Documentos de Académico
Documentos de Profesional
Documentos de Cultura
INTRODUCCION AL CRACKING CON OLLYDBG PARTES 11 A 20 PDF
INTRODUCCION AL CRACKING CON OLLYDBG PARTES 11 A 20 PDF
Bueno, ya nos queda ver los hardware breakpoints, los condicionales y los message breakpoints, para
terminar con los tipos de breakpoints.
HARDWARE BREAKPOINTS
Los HARDWARE BREAKPOINTS o (HBP) son una propiedad física del procesador, realmente yo no
conozco la arquitectura de los mismos para explicarla, pero es como si tuviera varias entradas en las
cuales vos le podes poner las direcciones en las cuales querés que el programa se detenga y el al ir
ejecutando compara y al hallar la dirección parara.
Tenemos la posibilidad de poner cuatro HBP, a la vez al poner el quinto OLLYDBG nos pedirá que
elijamos cual de los 4 existentes queremos borrar.
Existen HBP ON EXECUTION, ON WRITE y ON ACCESS son las tres posibilidades existentes.
Poner un HB ON EXECUTION cumple la misma función que poner un BPX en una dirección, salvo que
el HBP no cambia código y es mas difícil que sea detectado, eso si hay programas que tienen trucos que
nos borran los HBP, esos trucos y la forma de contrarrestarlos los veremos en próximas entregas.
Si quiero poner un HBP EXECUTION en 401013, marco la línea, hago click derecho y elijo
BREAKPOINT-HARDWARE ON EXECUTION
Allí tenemos la ventana de los HBP, si apretamos FOLLOW nos mostrara en el listado donde esta
colocado el mismo, y con DELETE podremos borrarlo.
Y para en 401013
Como vemos se comporta como un BPX común, si realizamos la misma prueba que hicimos con el BPX
de escribir MOV EAX, DWORD PTR DS:[401013] y lo ejecutamos vemos que el código no ha sido
cambiado.
Cambio EIP a 401000 con NEW ORIGIN HERE y apreto F7
Vemos que los bytes son E8 A6 04 00, los lee al revés y nos muestra 00004A6E8, sin cambios, así que
verificamos que no hay cambios de código.
Lo borramos y colocamos uno en MessageBoxA como hicimos con el BPX directo en la api
No repetiremos lo mismo pero sabemos que si corremos el programa y le colocamos un user y pass, y lo
aceptamos, parara en la api MessageBoxA de la misma forma que lo hemos hecho antes con BPX
comunes.
Los HBP ON ACCESS y ON WRITE solo pueden abarcar 1, 2 o 4 bytes de largo, por mas que
marquemos zonas en el dump mas largas, solo tomara como máximo los primeros 4 bytes de la misma
veamos el ejemplo.
Reinicio y borro todos los HBP que quedaron, y tratare de colocar un HBP ON ACCESS en la dirección
4020CA
Veo que haya marcado la zona que haya marcado, me aparece solo en este caso la opción de colocarlo en
un solo byte a partir de 4020CA o dos bytes (WORD), la opción de 4 bytes va de cuatro en cuatro así que
si uno de casualidad elije una dirección intermedia no aparecerá, como en este caso,
Vemos que si hago click derecho en el byte siguiente y elijo HARDWARE ON ACCESS, solo aparece la
opción BYTE
Y en el siguiente ya me aparece nuevamente la opción DWORD o sea que abarque cuatro bytes.
El tema es que si yo quiero que pare cuando guarda o lee en 4020CA, con que haya un HBP en un solo
byte es suficiente pues al intentar guardar o leer en la dirección parara igual.
Doy RUN
Allí nos dice OLLY que paro por el HBP 1 o sea el primero de la lista de los HBP.
Veo que para en la línea siguiente a donde guarda o lee, eso ocurre con los HBP ON ACCESS y ON
WRITE siempre debemos recordar que se pasan una instrucción y paran en la instrucción siguiente.
Y para justo después de guardar, a diferencia del MEMORY BREAKPOINT que hubiera parado en
401007, justo en la instrucción que lo activa.
Bueno lo mismo se puede realizar con los HBP ON WRITE, en ese caso solo parara cuando guarda no
cuando lea, y en la instrucción siguiente a la que lo activa.
BREAKPOINT CONDICIONALES
Son en realidad una variante de los BPX comunes, solo que al activarse OLLYDBG chequera si alguna
condición que le colocamos se cumple y en ese caso parara, si no se cumple seguirá corriendo como si no
existiera.
Veamos un ejemplo
Reiniciamos el OLLY y borramos todos los HBP si quedo alguno del ejemplo anterior y colocare un BPX
CONDICIONAL o BREAKPOINT CONDICIONAL en 40100E, para ello marco la línea, hago click
derecho y elijo BREAKPOINT CONDICIONAL.
En la ayuda del OLLYDBG nos muestra los símbolos que podemos utilizar, en este caso el igual, se
representa por dos símbolos igual consecutivos.
Si vemos EAX vemos que vale 400000, lo cual fue la condición para que se detuviese
Si reinicio y borro el BPX CONDICIONAL y ahora coloco otro pero que pare si EAX==500000 por
ejemplo
Y doy RUN
Vemos que el crackme se ejecuta y no para en el BREAKPOINT ya que siempre al pasar por allí, vale
EAX=400000 y la condición no es cumplida, por lo tanto no se detiene.
Si vamos a HELP-CONTENTS
Es un BPX condicional igual que el anterior, solo que en este caso podemos activar que nos loguee o nos
guarde ciertos valores al pasar por el BPX CONDICIONAL, en este caso las opciones son muchísimas,
probaremos en el caso de una API que tiene varios accesos y queremos que loguee o nos guarde ciertos
datos al pasar por ella.
Usamos el ejemplo de la api pero puede ser colocado un BPX CONDICIONAL LOG en cualquier
dirección sea api o no, reiniciemos el OLLY.
En este caso no haremos que pare en la api, solo que nos loguee ciertos datos de interés.
Como no queremos que pare no colocamos ninguna CONDICIÓN y en la opción PAUSE PROGRAM
elegimos que no pare nunca o sea ponemos la marca en NEVER.
Luego en LOG VALUE OF EXPRESIÓN ponemos que nos guarde el valor de [esp] que escribimos en el
renglón EXPRESSION, que como sabemos será la dirección de retorno al programa desde la api, ya que
es el valor superior del stack, por lo tanto en la segunda opción LOG VALUE OF EXPRESIÓN elegimos
ALWAYS para que la LOGUEE siempre, y en el tercer renglón nos da la opción si queremos LOGUEAR
los argumentos o parámetros de la función o api, pues no estará de mas, ponemos ALWAYS tambien.
Y limpiamos la misma para ver claro lo que guarde el programa a partir de aquí con CLICK DERECHO-
CLEAR WINDOW.
Vemos que también allí esta la opción de guardar lo logueado, en una fila de texto, si lo necesitamos lo
podemos activar allí.
Ahora doy RUN con f9
Llego a la ventana del crackme y aun no hay en el LOG nada sobre nuestra api pues aun no paso por la
misma.
Al apretar OK
Vemos allí que nos muestra aun sin haberse detenido el OLLY, la info de la MessageBoxA, primero el
valor superior del stack que es 40137D o sea la dirección de retorno de la api, y luego los parámetros de
la misma, en este caso que es un call desde 401378, el texto, el titulo etc.
En este caso nos muestra solo una información pero que tal si una api se ejecuta 100 veces por ejemplo,
podemos loguear todas a una fila de texto, pero si queremos que pare en una sola determinada de toas
esas veces en ese caso, debemos usar la CONDICION.
Si tuviera aquí una lista con la info de 100 veces diferentes que paro el programa en esa api, puedo
colocarle algún dato que me da la info en la condición, por ejemplo la dirección de retorno en este caso, la
puedo usar como condición y de esa forma solo parara de las 100, en la que regrese a 40137d, las que son
llamadas de otras direcciones del programa no parara.
Para ello reinicio el OLLY y voy nuevamente a la api y ahora pongo un BPX CONDICIONAL LOG así.
Cambio la tilde para que solo pare cuando se cumpla la condición (ON CONDITION) y escribo la
condición o sea que solo pare cuando [esp] sea igual a 40137D.
En esta forma solo parara cuando pase por la api y sea el valor superior del stack 40137d el cual es la
dirección de retorno de la api y me asegura que solo parara en esa.
Corramos el programa pero ahora cuando vayamos a REGISTER coloquemos un nombre con números
como ricnar456 y password 989898
Recordamos que cuando poníamos un nombre que tenia números, paraba 2 veces en la api messageboxa,
apretemos OK
Vemos que salio la primera MessageBoxA pero no paro OLLY en ella, vemos en el log la dirección de
retorno es 4013C1 y no se activa la condición por ello no paro.
Al apretar aceptar
Vemos que en la parte superior del stack esta el valor 40137d que fue el que activo el BPX
CONDICIONAL LOG.
Ahí se ve claro que la segunda vez la dirección de retorno fue 40137D y nos muestra en el mismo LOG
que la segunda vez se detuvo.
Bueno creo que con esto tienen para practicar un rato, aun quedan los MESSAGE BREAKPOINTS pero
no quiero matarlos, lo dejamos para la parte 12 y luego de los MESSAGE BPX le prometo seguir
crackeando un poco para no aburrirlos, pero esto deben saberlo antes de continuar.
Hasta la parte 12
Ricardo Narvaja
27 de noviembre de 2005
INTRODUCCIÓN AL CRACKING CON OLLYDBG parte 12
Tengo esta cita que define un poco que son los mensajes en WINDOWS
Los mensajes en Windows son usados para comunicar la mayoría de los sucesos, al menos en los niveles
básicos. Si quieres que una ventana o control (el cual es una ventana especializada) haga algo, debes
enviarle un mensaje. Si otra ventana quiere que vos hagas algo, entonces te envía un mensaje. Si ocurre
un evento, como cuando el usuario mueve el mouse, presiona el teclado, etc... entonces el sistema la envía
un mensaje a la ventana afectada. Dicha ventana recibe el mensaje y actúa adecuadamente.
O sea que como ya sabemos, podemos en OLLYDBG trabajar poniendo BPX en las apis que realizan la
mayoría de las funciones del programa, pero muchas veces resulta mas directo poner Breakpoints en estos
mensajes que el programa envía directo al sistema llamados MESSAGE BREAKPOINTS o BMSG por la
sigla que se utilizaba en SOFTICE para poder tipearlos.
Existe un Bucle de mensajes en todo programa compuesto por varias apis, que no profundizaremos aquí,
dichas apis se ocupan del tratamiento de los mensajes, el que quiera profundizar el tema, este es un
tutorial bastante completo de cómo funcionan, aunque para el cracking no es necesario, profundizar tanto,
mas vale saber que dichos mensajes existen y son procesados y en cual colocar BMSG para obtener un
buen resultado.
http://winprog.org/tutorial/es/message_loop.html
Veremos como ejemplo el caso siguiente: para hallar seriales queremos que el programa rompa al apretar
en el botón que ingresa nuestro nombre y serial, para luego analizar que operaciones realiza con ellos.
Si abrimos el Crackme de Cruehead en OLLYDBG.
Vamos a ver primero el método con las apis, para ello miramos las apis que importa el programa, a ver
cual es la encargada de realizar el trabajo de traer el texto que tipeamos para su procesamiento y futura
comparación.
Vemos que usa la api GetDlgItemTextA por lo cual seguro la utilizara para ingresar el texto
Bueno una vez colocado el BPX en la api corremos el programa y vamos a ingresar nuestro user y pass
Al apretar OK para en nuestro BREAKPOINT
Si miramos el stack
Vemos que uno de lo parámetros de la api es el buffer, allí guardara el texto que estamos ingresando.
Veamos el BUFFER en el DUMP con FOLLOW IN DUMP o yendo al DUMP y haciendo GOTO
EXPRESSION=40218E
Allí lo vemos vacío pues aun no se ejecuto la api
Así que ejecutemos la api hasta el RET con DEBUG- EXECUTE TILL RETURN
Y ingresa mi serial.
Ya comprendemos que para la búsqueda de seriales correctos, debemos detenernos en donde ingresa
nuestro nombre y serial o los datos que se nos pidan, mas adelante veremos como seguir hasta hallar el
serial correcto.
Bueno hemos parado en el punto en que ingresa nuestro user y serial con apis, ahora veamos como
hacerlo con BMSG, ya que muchos programadores sabedores de que para obtener el serial debemos
detenernos aquí, para complicar las cosas, no utilizan apis para ingresar el texto si no que lo hacen
mediante mensajes de Windows.
Quitemos los BREAKPOINTS que colocamos yendo a la ventana B y borrando todos con REMOVE
Para colocar el BMSG vamos a la ventana W o WINDOWS sin pausar el programa que continua
RUNNING.
Buscamos el BOTÓN, allí vemos marcada la línea en CLASS dice BUTTON y el titulo es OK como en
nuestro BOTON.
Vemos que hay BMSG genérico para texto, Mouse, portapapeles, botones, cuando uno no sabe bien cual
es el mensaje que se ultiliza el programa, puede intentar usar las opciones genéricas, pero en mi caso,
usare el BMSG exacto, sigo bajando en el menú desplegable, ya que los años me han enseñado que
cuando se hace click en un botón, se envía un mensaje WM_LBUTTONDOWN, primero cuando
apretamos con el botón izquierdo por eso la L de LEFT y luego WM_LBUTTONUP cuando soltamos el
botón izquierdo, así que pondremos el BMSG en este ultimo evento al soltar el botón, que es el 202.
Quedaría así
Elegido el tipo de mensaje 202 WM_LBUTTONUP, ponemos la marca en BREAK ON ANY WINDOW,
y en PAUSE PROGRAM, que pare ON MESSAGE o sea cuando se ejecute el mensaje que elegimos, y
abajo LOG WINPROC ARGUMENTS, ya que nunca viene mal que loguee los argumentos de algo.
Vemos que como elegimos en cualquier ventana lo coloco en los dos botones que hay OK y CANCEL, no
hay problema, ahora apretemos OK.
Aquí es donde se pierden muchos porque dicen que parando con este método, quedan en el medio de la
nada ya que la dirección de retorno, no pertenece al programa pero retornar es muy sencillo.
Sabemos que el programa se ejecuta en la sección que comienza en 401000, así que pongo un BPM ON
ACCESS en dicha sección para que pare cuando ejecute algo allí.
Vemos que enseguida luego de ejecutar dos veces hasta el RET caemos en las llamadas a
GetDlgItemTextA que leen el user y serial que tipeamos, de forma que llegamos al mismo lugar sin haber
utilizado BPX en las apis en este caso.
Si el programa no hubiera utilizado apis para entrar el texto, hubiéramos llegado con los BMSG al mismo
punto donde ingresara el texto y podremos empezar a trabajar la rutina del serial lo cual veremos en
próximas partes.
En el caso que quisiéramos parar al apretar una tecla, podemos intentarlo también borramos el BPM ON
ACCESS haciendo CLICK DERECHO-REMOVE MEMORY BREAKPOINT en cualquier parte del
listado.
Y vamos a la ventana B y borramos los BMSG anteriores con REMOVE
Ponemos el programa a correr nuevamente y llegamos a la ventana de ingresar el user y serial pero esta
vez no ingresamos nada.
Vamos a la ventana W
Apretamos una tecla para escribir el nombre en la ventana de user y serial y vemos que en este caso no
para, porque el programa no procesa los mensajes de la presión tecla por tecla, pero es bueno saberlo
porque hay programas que si lo hacen, y comparan carácter por carácter a medida que tipeamos, y por eso
hay que tener en cuenta para esos casos esa opción.
Ahora esto trae otros interrogantes, podemos hacer que OLLY nos liste los mensajes que utiliza el
programa sin parar, de forma de luego poder utilizar el BMSG que sabemos que funcionara, pues es
utilizado?
Pues es sencillo, lo que tenemos que hacer es utilizar un BMSG que sabemos que funciona, como en este
caso el 202 y poner un BMSG en el y que se detenga como hicimos en el primer caso, quitamos todos los
BPX en la ventana B y repetimos hasta que pare al apretar el botón OK por BMSG 202
WM_LBUTTONUP
Lo colocamos y apretamos OK en la ventana de ingresar el serial.
Vemos que allí paro ahora modificaremos las cosas para que loguee todos los mensajes utilizados por los
botones.
Vamos a la ventana B
Bueno la cuestión es que en [esp+8] esta el numero del BMSG que necesitamos saber asi que cambiamos
en la ventana del BREAKPOINT.
Para que loguee el valor que se encuentra en EXPRESSION en este caso [esp + 8], que no pare o sea en
PAUSE PROGRAM ponemos NEVER y LOG VALUE OF EXPRESSION y LOG FUNCTION
ARGUMENTS pues no esta demás en ambos que los loguee ALWAYS o sea SIEMPRE.
Aceptamos y vamos a colocar nuestro nombre y serial nuevamente al apretar OK miramos el LOG y
vemos la lista de mensajes que usa el programa en los botones con sus nombres y números.
Allí vemos como dije que utiliza el 201 WM_LBUTTONDOWN y luego 202 WM_LBUTTONUP, y que
no utiliza los de tecla WM_KEYUP o WM_KEYDOWN jeje.
Para hacer un logueador genérico para todo el programa (botones, ventanas etc) se deben hacer
condicional breakpoints en las apis que manejan mensajes. Podemos utilizar las apis TranslateMessage y
DefWindowProcA que se complementan en su logueo.
Si quieren un reporte completo pueden poner un breakpoint condicional en las dos apis, veamos como se
hace eso.
Y
Con eso ponemos dos BPX en las apis ahora los transformaremos en condicionales vamos a la ventana B
y hacemos click en el primero FOLLOW IN DISSASSEMBLER.
Poniendo como expresión a loguear MSG que es el valor del tipo de BMSG por ejemplo en
WM_LBUTTONUP era 202 en ese caso MSG=202
Ponemos que no pare nunca y que loguee siempre y realizamos el mismo trabajo en la otra api.
Ya tenemos convertidos los BPX en CONDICIONALES
y si queremos que ya que los resultados serán muchos se loguee a una fila txt en el LOG.
Y elegimos el nombre del archivo de texto que lo guardara, ahora damos RUN.
Vemos el resultado del LOGUEO completo de todos los mensajes, los cuales se guardan en una fila txt, la
cual luego podemos mirar con detenimiento para ver cual BMSG nos conviene mas colocar y en donde ya
que el listado nos muestra cada mensaje en que ventana, boton, etc se aplica.
Sabiendo manejar correctamente los BMSG puede ser una gran ayuda ya lo veremos en casos de NAGS
que se utiliza el WM_CLOSE para que pare cuando se cierra la msima y mil usos mas hay mensajes para
casi todos los eventos que pueden ocurrir en una ventana.
Espero que lo hayan entendido y les sirva, en la próxima parte terminaremos de hallar el serial valido para
el CRACKME DE CRUEHEAD
Hasta la parte 13
Ricardo Narvaja
30 de noviembre de 2005
INTRODUCCION AL CRACKING CON OLLYDBG PARTE 13
Creo que una de los temas mas candentes de hoy en día es el tema de hallar seriales, sobre todo luego de
que existen fuertes encriptaciones que pueden llegar a complicar la cosa, igual iremos paso a paso desde
el caso mas simple al mas complejo, tratando de practicar bastante para poder afianzar los conceptos de
trabajar con seriales.
Bueno esta primera parte del trabajo con seriales lo dedicaremos a los HARDCODED, que son los
seriales que no son calculados a partir de un nombre, o sea es un serial fijo que puede ser un texto, un
numero pero es siempre el mismo y muchas veces son sencillos otras no tanto, se tiene el concepto que
son los mas fáciles de hallar jeje, por eso empezamos por este tipo, pero hay de todo fáciles y mas
difíciles ya verán los ejemplos en esta parte.
Tenemos cuatro ejemplos para practicar, dos haremos en esta parte 13 y los dos mas difíciles en la parte
14.
El primero de los cuatro que veremos es el llamado LECCION 13 HARDCODED 1, que se encuentra
adjunto con la teoría es el caso mas simple, abrámoslo en OLLYDBG.
Allí esta en el inicio, el caso mas simple de los HARDCODED es el que aparece la clave correcta en las
STRINGS o CADENAS DE TEXTO que utiliza el programa, miremos si aquí aparece.
Para hallar las cadenas de texto o strings, hacemos click derecho SEARCH FOR – ALL REFERENCED
TEXT STRINGS.
Los resultados son
Pues allí se ve la palabra FIACA que puede ser la clave, si no tenemos ganas de trabajar podemos probar
algunas strings que salen en la lista y por ahí acertamos, pero este método no es aconsejable, por las
siguientes causas:
1)En este caso hay 2 strings, pero hay programas que tienen miles de strings, y probar una por una puede
llevar a la locura total, así que aunque vemos allí el posible serial correcto, haremos como que hay mil
strings y que no sabemos cual es.
2) Hay programas que ponen strings tramposas en la lista que no son la clave y que al tipearlas al ingresar
un serial provocan algún perjuicio ya que son trampas para crackers, así que lo mejor es asegurarse y
verificar que es el serial correcto llegando hasta la comparación entre lo que tipeas y la string correcta.
Lo primero es mirar las apis que utiliza con click derecho-SEARCH FOR- NAME (LABEL) IN
CURRENT MODULE
Ahí salen las apis utilizadas por el programa, veamos si hay alguna conocida
Allí vemos que utiliza GetDlgItemTextA, seguro la usara para ingresar el serial que nosotros tipeamos y
MessageBoxA para sacar los mensajes de si es correcto o incorrecto nuestro serial, pongamos un BPX en
cada una de dichas apis.
Allí sale la ventana para tipear el serial, pongamos un nombre cualquiera por ejemplo narvajita jeje
Apretemos Verificar y vemos que para en el OLLYDBG en uno de los BPX que colocamos
Si miramos el stack, vemos que paro en la api GetDlgItemTextA para ingresar el serial, allí en los
parámetros de la api, vemos la dirección del BUFFER donde guardara el serial que ingresa, en este caso
es 403010.
Así que veamos esa dirección en el DUMP haciendo click derecho – FOLLOW IN DUMP en la misma
Allí esta visible el BUFFER, y esta vacío pues aun no se ha ejecutado la api
Ya vemos viendo que estamos llegando a la comparación y al salto condicional que según salte o no me
llevara a los MessageBoxA de “Mal Muy MAL” o “Muy BIEN” obviamente si ese salto condicional lo
cambio por un JMP 401087, lo obligo siempre a saltar al cartel de MUY BIEN y programa parcheado y
resuelto, pero aquí yo quiero hallar el serial, así que veamos que compara.
En 401066 moverá a EBX el contenido de la memoria 403010 como es un DWORD solo moverá los 4
bytes pero es suficiente, veamos que hay en 403010 en el dump.
Marco la linea y hago click derecho FOLLOW IN DUMP-MEMORY ADDRESS y vere que esta leyendo
En la aclaración veo que esta leyendo 7672616E que son los 4 bytes que se encuentran en el contenido de
403010 leídos al revés como vimos, y son los primeros 4 bytes del serial falso que yo tipee los cuales
mueve a EBX.
Aquí vemos que compara EBX que como recordaran son los primeros 4 bytes de mi serial falso, con el
contenido de la dirección 403008, veamos que hay allí en el dump, de la misma forma que hicimos en la
línea anterior.
Vemos que esta leyendo los 4 primeros bytes de la palabra FIACA, comparándolos con los primeros
cuatro bytes que tipee, por lo cual deduzco que si ambos fueran iguales en esta comparación, se activaría
el flag Z, al ser la diferencia entre ambos cero, y el JE saltaría, mandándome el cartel de MUY BIEN, por
ahora como no son iguales recibiré el escarmiento jeje,
Como no fueron iguales no salta y va directo al cartel MAL MUY MAL, pues apretemos F9
Y ya vemos que nos va a decir MAL MUY MAL en los parámetros de la api.
Demos run o F9
Como vemos salio el cartel malo, aceptémoslo y escribamos la clave correcta FIACA.
Apreto VERIFICAR y repito el proceso anterior hasta llegar a la comparación
Ya la aclaración nos muestra que son iguales, por lo cual se restaran y dará cero el resultado el flag Z se
activara al ejecutar la comparación con f7
Vemos como en este caso saltara al MessageBoxA de MUY BIEN veamos con F9
Allí veo en el stack cuando para en la api, que va a salir el cartel bueno
Bueno aunque olvidamos cambiarle el titulo a la ventana pero no importa hallamos el serial correcto de
nuestro primer y mas sencillo hardcoded.
El siguiente es el mismo crackme que me facilito mi amigo REDHAWK, este segundo es el original que
me hizo, el anterior lo modifique un poco yo jeje (por eso por vagancia no le cambie el titulo del
MessageBoxA correcto jejeje)
Como ven es muy similar pero en las strings no aparece la clave correcta.
No se ve FIACA, ni ninguna otra posible por ahí jeje
Apreto VERIFICAR
Y para en el BPX veremos que compara en este caso, esta pasando a EBX el contenido de la memoria
40300C, veámosla en el DUMP.
Allí vemos que al ejecutar la línea, moverá los 4 bytes a EBX, siempre invirtiéndolos ya vimos que
cuando lee de la memoria y pasa el contenido a un registro se invertirán.
Apreto F7 y allí están en EBX , al ser un MOV EBX, DWORD PTR DS: [40300C] se mueven solo
cuatro bytes (DWORD)
En este caso vario apenas la cosa, pasara a EDX el contenido de 40204B, veamos que hay allí.
Esta pasando los cuatro bytes que corresponden a la string 9898 que en este caso es el serial correcto ya
que compara estos 4 bytes con los 4 primeros de LUCKY y si son iguales verificamos que salta a la zona
de MUY BIEN, en este caso no saltara, pero si llegamos hasta poder volver a ingresar la clave y tipeamos
9898.
Apreto VERIFICAR
En la comparación de EBX y EDX ambos son iguales son 38393839 que son los bytes correspondientes a
la cadena 9898 que ingresamos y por supuesto saltara al cartel MUY BIEN.
Vemos que en este que hizo mi amigo si sale el titulo BRAVO, jeje ya que no estaba vago como yo, jua
jua, la cuestión que sacamos el serial correcto también, que en este caso es 9898.
Ahora iremos incrementando la dificultad tenemos dos hardcoded mas difíciles ya no tan directos, el
ultimo no apto para cardiacos pero bueno pueden ir viendo en ellos, como se aplican las técnicas de
crackeo para casos mas difíciles.
Como ustedes pensaron que yo solo iba a trabajar y ustedes nada, pues no, aquí trabajamos todos, hay un
tercer crackme que harán ustedes (mielecrackme1.zip), que queda como tarea para la próxima parte 14, en
la cual estará resuelto y explicado por mi, al igual que los otros dos que tenemos pendientes, lo que si les
aconsejo hacerlo pues la parte 14 vendrá en un rar con password y el password para abrirlo, será el serial
correcto de este crackme, jeje así que deben trabajar si o si (Que malvado jeje)
Como ayuda les digo que la api lstrcmpA que utiliza este crackme, es una api que se utiliza directamente
para comparar strings, cuando lleguen a esa api, verán en los parámetros en el stack, las dos strings
comparadas por la misma.
En la parte 14 les mostrare bien como funciona y seguiremos con los dos hardcoded, mas difíciles, pero
antes deben practicar con algo sencillo, por eso el crackme que agregue aquí y que es obligatorio para
seguir adelante jeje. (malo, malo eres jeje)
Hasta la parte 14
Ricardo Narvaja
03 de diciembre de 2005
INTRODUCCIÓN AL CRACKING CON OLLYDBG PARTE 14
Bueno antes que nada vamos a explicar como se soluciona el crackme que deje como tarea en la parte 13.
Allí esta el mielecrackme abierto en OLLYDBG, y detenido en el ENTRY POINT, veamos las apis que
utiliza con SEARCH FOR-NAME (LABEL) IN CURRENT MODULE.
Allí están las apis que son importantes, GetWindowTextA para ingresar el serial que tipeamos, lstrcmpA
como les anticipe en la parte anterior para comparar strings y MessageBoxA para mostrar el mensaje de si
colocamos el serial correcto o no.
Podemos poner un BPX en esas apis, para parar cuando ingresa nuestro serial falso, pero en este caso que
es bien sencillo, podemos hacer mas rápido si miramos las STRINGS que utiliza el programa.
Haciendo SEARCH FOR – ALL REFERENCED TEXT STRINGS sale la lista de STRINGS o
CADENAS DE TEXTO usadas por el programa veamos.
Allí vemos las strings de que acertamos y las que muestra cuando fallamos, si hacemos doble click en
alguna de ellas, nos llevara a la zona de los MessageBoxA, probemos haciendo doble click en YOU
ENTERED THE RIGHT PASSWORD (has ingresado el password correcto)
Primero GetWindowTextA como dijimos para ingresar el serial que tipeamos, luego lstrcmpA para
comparar con el serial correcto, y luego según si son iguales continua al MessageBoxA, con la leyenda
YOU ENTERED THE RIGHT PASSWORD, y si no son iguales salta al otro MessageBoxA, MAYBE,
YOU SHOULD TRY AGAIN, IT´S SO EASY, que intentemos de nuevo que es fácil.
Así que pondremos un BPX, allí en el CALL a la api lstrcmpA, para ver que compara.
Sale la ventana para ingresar el serial y ponemos uno cualquiera por ejemplo 989898.
Vemos que OLLY nos aclara los parámetros, los cuales son las dos STRINGS que comparara, en este
caso vemos que compara la que tipee “989898”, con la palabra “cannabis.
El resultado dicha api lo muestra en EAX, si es FFFFFFFF o sea -1, es que las strings no son iguales.
Como el resultado de la comparación no es cero, no se activa el FLAG Z, y el JNZ salta ya que el FLAG
Z es cero. (Recordar que JNZ salta si el FLAG Z es cero porque es el inverso de JZ que salta cuando el
FLAG Z esta activo o 1)
Pues allí salta y va al cartel de error, así que ya sabemos que compara con la palabra cannabis, o sea que
este es el serial correcto doy RUN nuevamente, acepto el cartel malo.
Y vuelvo a la ventana para ingresar el serial esta vez tipeo el serial correcto, cannabis.
Veo que va a comparar ambas strings y estas son iguales, apreto F8 para ejecutar el CALL de la api.
Ahora al ser ambas strings iguales el resultado de la api que guarda en EAX es cero, por lo cual se activa
el FLAG Z.
Y el JNZ en este caso no salta al estar el FLAG Z activo.
Pues esta es la solución del crackme que deje como tarea de la parte 13, jeje, el serial es la palabra
“cannabis”
Sigamos ahora avanzando con HARDCODED SERIALS mas difíciles nos quedan para ver dos.
El caso siguiente es un paso mas, en este ya no compara directamente el serial que tipeamos sino que
realiza algunas operaciones antes de comparar veamos el ejemplo, este es el crackmeeasy, abrámoslo en
OLLYDBG.
Ya sabemos como ver las apis que utiliza, así que en la lista vemos GetDlgItemTextA, pongámosle un
BPX en dicha api.
En la commandbar tipeo
Allí esta el buffer vacío, porque aun no se ejecuto la api, así que hago DEBUG-EXECUTE TILL
RETURN
Allí mueve 401222 a EAX y en el registro EAX vemos que dicha dirección apunta a la string del numero
constante.
En realidad es similar a
En la aclaración del OLLY se ve bien que son los 4 primeros bytes del numero 10445678951
Al ejecutar la línea con F7 se mueven a EDX (siempre se moverán al revés al mover de la memoria a un
registro)
La siguiente línea esos bytes que están en EDX los mueve a [EBP-30]
En la aclaración del OLLY vemos que [EBP-30] es en mi maquina 240f9e4, lo busco en el DUMP
Luego
Mueve a EDX los siguientes cuatro bytes del número constante
La aclaración del OLLY lo muestra, en este caso [eax+4] es en este caso el contenido de 401226 y al
ejecutar con F7 mueve los 4 bytes siguientes a EDX.
En realidad lo que esta haciendo es copiar ese numero de a 4 bytes a otra parte de la memoria
Allí vemos que un poco mas abajo se acerca a una llamada a la api memset, allí vemos los parámetros en
OLLYDBG
s es la dirección de inicio
n que es la cantidad de bytes que van a llenar
c es el valor con el cual se va a llenar esa zona
En el stack se ven mejor en este caso los parámetros, o sea que llenara con ceros (c ), 8 bytes (n) a partir
de s (240f9f0).
Al ejecutar la api con F8, allí vemos que lleno de ceros, los 8 bytes a partir de 240f9f0 que es la dirección
de inicio s.
Mas abajo vemos una llamada a lstrlen, que es una api que calcula el largo de una string lleguemos hasta
el call a la misma.
O sea nos dará el largo de la string que comienza en 240f9E4, que es el numero constante famoso jeje.
Al pasar con F8 el call a dicha api en EAX nos devuelve el largo de la string
Vemos que el largo es 0B que es 11 decimal, que es el largo del número constante.
Allí le resta uno a EAX o sea 0B-1 y como es LEA mueve ese valor directo a EDX o sea que EDX vale
0A.
En la siguiente línea compara EDX que vale 0A con el contenido de [EBX-10] que es cero.
Pues como cero es mas bajo que 0A en la comparación, salta y va a 40135C.
En la próxima línea mueve a EAX el puntero a nuestro serial falso, allí vemos que luego de ejecutar con
F7, EAX apunta a nuestro serial falso 98989898
En la siguiente línea
Como EAX apunta al inicio de nuestro serial falso, le suma en este caso EDX que vale cero posiblemente
para hacer un LOOP que se ira actualizando incrementando EDX a 1, 2 etc y recorrer de esa forma todos
los bytes de nuestro serial falso uno a uno en dicho LOOP.
Como ya sabemos que MOVSX en el caso de números positivos mueve el byte a EDX y si es positivo
llenara el resto con ceros, y si es negativo con efes jeje.
En este caso no hay problema mueve el primer byte de mi serial falso el 39 a EDX al ejecutar la línea
vemos que EDX vale 39.
Y como EDX vale 39, le resta 14 y como es un LEA mueve el resultado directo a EAX.
O sea que la operación que realizo es tomar 39 que es el valor hexa del primer carácter de mi serial, y le
resto 14 y quedo por ahora en 25, el cual esta en EAX.
La siguiente línea mueve el valor EBP-30 que en mi maquina es 240f9E4 que apunta al inicio del numero
constante guardado a EDX.
Al apretar F7
Queda EDX apuntando al inicio del número constante.
Aquí vemos que mueve a ECX el valor cero y en cada pasada que haga en el LOOP se incrementará,
permitiendo a ECX+EDX apuntar a los distintos bytes del numero constante.
Ahí vemos como ECX por ahora vale cero y EDX apunta al inicio del numero, moverá a EDX en este
primer paso por esta línea, el primer byte del numero vemos en la aclaración del OLLYDBG.
Que mueve el byte 31 que corresponde al 1 en ASCII, es la primera cifra del número constante.
En EAX esta el valor del primer byte de mi serial falso 39 al cual le resto 14, quedando en EAX el valor
25, y en EDX el primer byte del numero constante o sea 31
CMP EAX,EDX
En realidad es
CMP (PRIMER BYTE DE MI SERIAL FALSO – 14), PRIMER BYTE DEL NUMERO CONSTANTE
CMP 25,31
Y al ser la diferencia entre ambos miembros diferente de cero, no se activa el FLAG Z y salta el JNZ.
Como estoy utilizando el serial falso, la comparación no es igual, solo serán iguales ambos miembros
cuando usemos el serial correcto ya que es el valor que hace que la comparación llegue a ser una
igualdad.
PRIMER BYTE DEL SERIAL CORRECTO-14= PRIMER BYTE DEL NUMERO CONSTANTE
Por lo tanto
PRIMER BYTE DEL SERIAL CORRECTO= PRIMER BYTE DEL NUMERO CONSTANTE +14
PRIMER BYTE DEL SERIAL CORRECTO= PRIMER BYTE DEL NUMERO CONSTANTE +14
SEGUNDO BYTE DEL SERIAL CORRECTO= SEGUNDO BYTE DEL NUMERO CONSTANTE +14
TERCER BYTE DEL SERIAL CORRECTO= TERCER BYTE DEL NUMERO CONSTANTE +14
Y así sucesivamente
Siguiendo la misma lógica, a cada byte del numero constante, le sumamos 14 y obtenemos el valor del
byte correspondiente a nuestro serial correcto.
31 30 34 34 35 36 37 38 10445678
39 35 31 00 00 00 00 00 951.....
36 + 14 = 4A es la letra J en ASCII
38 + 14 = 4C es la letra L en ASCII
39 + 14 = 4D es la letra M en ASCII
35 + 14= 48 es la letra I en ASCII
EDHHIJKLMIE
Apretemos Check
Les dejo como tarea recorrer el loop completo, ver como va actualizando los contadores y como va
incrementando los bytes del numero constante y del serial falso, y como llega al cartel de correct o de
incorrect.
No es tan easy el crackme jeje ya que recién están empezando, pero creo que si lo practican pueden
sacarle buen jugo.
Bueno aquí tienen la tarea sencilla para la parte 15 es otro crackme llamado SPLISH, solo tienen que
hallar en la parte de HARDCODED el serial correcto y con el serial abrirán la parte 15 jeje sigo
malísimo, pero les digo que este crackme no se parece en nada a este anterior que hice, es bien sencillo,
ya iremos practicando mas difíciles de a poco.
Ricardo Narvaja
05 de diciembre de 2005
INTRODUCCIÓN AL CRACKING CON OLLYDBG PARTE 15
Bueno antes de seguir con el ultimo hardcoded, mostraremos la solución del que quedo pendiente como
tarea, el SPLISH que es bien sencillo.
Abrámoslo en OLLYDBG.
Si vemos las apis que utiliza con click derecho SEARCH FOR-NAME (LABEL) IN CURRENT
MODULE
Allí vemos el texto del cartel de Congratulaciones, que nos muestra cuando colocamos el serial correcto,
por lo tanto hagamos doble click allí, a ver donde usa ese texto, así estaremos en la zona caliente o cerca.
Vemos la entrada de texto con la api GetWindowTextA y los MessageBoxA con sus respectivos textos de
si acertamos o no.
Pues pongamos un BPX alli, en el call a la api GetWindowTextA para comenzar desde donde se
introduce el serial que tipeamos.
Como solo pedimos por ahora solucionar la parte de HARDCODED, tipearemos un serial falso, allí en la
parte superior y apretamos el botón CHECK HARDCODED.
Allí vemos tanto en el stack como en las ayudas que nos muestra el OLLY que el BUFFER donde
guardara el serial que tipeamos, esta en 403215.
Así que vayamos al dump a ver el buffer.
Allí esta el buffer donde guardara el serial que tipeamos, apretemos F8 para ejecutar el CALL a la api.
Como al ejecutar con F8, ejecuta todo el call con la api incluida, pues ya tenemos el serial falso guardado
en el BUFFER.
Bueno la próxima línea moverá 401353 a EAX, (recordar que los LEA no mueven el contenido de la
dirección de memoria, si no solo el resultado de lo que hay entre corchetes, en este caso moverá 401353)
Veamos en el DUMP dicha dirección, en la línea hacemos click derecho FOLLOW IN DUMP-
MEMORY ADDRESS lo que nos muestra en el DUMP la dirección de memoria 401353.
Pues 401353 apunta a la string “HARDCODED”, apretemos F7 para que se ejecute el LEA.
Al ejecutar queda EAX con el valor 401353 y al lado nos aparece la aclaración de que dicha dirección
apunta a una string en este caso “HARDCODED”
Y OLLYDBG nos muestra a la derecha, que esa dirección apunta a la string “98989898”, que es mi serial
falso y que se ve en el dump si hago como en la instrucción anterior.
La siguiente linea compara si el primer BYTE del contenido de EAX es cero, como EAX vale 401353
Sabemos porque lo vimos en el DUMP que el contenido son los bytes de la cadena HARDCODED.
Allí esta el primer Byte es 48, en la aclaración OLLYDBG también nos dice que esta leyendo el 48 que
corresponde a la H en ASCII de la primera letra de la palabra HARDCODED, ve si es cero, como no es
cero continuara.
Como la comparación no activo el FLAG Z al no ser ambos miembros iguales, pues el JE siguiente no
saltara, recordar que JE solo salta al estar activado el FLAG Z.
Aquí vemos con una visión mas ampliada, que ahora moverá el primer byte de [EAX] que es el 48 que
corresponde a la palabra HARDCODED y en la siguiente línea moverá [EBX] que corresponde al primer
byte de mi serial falso y los comparara si no son iguales salta a 4013D2 que es el cartel de SORRY,
PLEASE TRY AGAIN.
La aclaración del OLLYDBG no deja dudas, compara el 39 que es el 9 de la primera cifra de mi serial
falso con H que es la primera cifra de HARDCODED.
Vemos que al no ser iguales salta al cartel de error, si fueran iguales y no saltara lo cual podemos hacer
fácil cambiando el FLAG Z con doble click.
Ahora Z vale 1 como si en la comparación ambos bytes fueron iguales y la resta entre ambos dio cero y
activo el FLAG Z o cero.
Vemos que en este caso INCREMENTA EAX y EBX y salta con un JMP al inicio del LOOP
Ahora EAX apunta al segundo byte de HARDCODED y vemos que el loop se repetirá comparando byte a
byte, hasta que sea cero el contenido de EAX o sea cuanto se terminen los bytes de la palabra
HARDCODED ya que en una string, luego de su ultimo carácter, hay un cero.
Pues entonces al incrementar EAX y EBX ira leyendo y comparando los segundos bytes, si son iguales,
repetira el loop y hará lo mismo con los terceros y asi, una vez que se completo la palabra HARDCODED
si todos los bytes en la comparación CL con DL han sido iguales, no saltará a mostrar el mensaje de
SORRY y llego aquí
Como EAX ya termino de apuntar a todos los bytes de la palabra HARDCODED pues llego al cero del
final de la string veamos.
Allí EAX apunta a 40135C que en el DUMP vemos que es el cero al final de la string entonces al ser la
comparación ambos miembros iguales
Por supuesto yo lo hice invirtiendo en cada comparación de CL con DL el flag Z, para que el programa
crea que son iguales si no saltará al cartel malo y no llegaré aqui, pero de todas formas ya sabemos
entonces que el serial correcto es la palabra HardCoded respetando mayúsculas y minúsculas porque
tienen diferente valor ASCII.
Quito todos los BPX y tipeo el serial que halle, y al apretar CHECK HARDCODED
Otro vencido, si ustedes están leyendo esto pues, felicitaciones también para ustedes pues lo han vencido
también, si no no podrían leer esta lección y si el password del rar se los paso un amigo, mejor releer todo
y practicar que haciendo trampa no se aprende, jeje.
Bueno pues vamos con el ultimo HARDCODED y terminamos ya con esto, para pasar el siguiente tema
en la parte 16.
Bueno el siguiente crackme es algo diferente a los anteriores es al llamado SAMBO y lo arrancamos en
OLLYDBG.
Nos sale este cartelito de OLLYDBG que nos avisa que algo pasa, alli dice que la fila se auto-
descomprime o se auto modifica, lo que en la jerga del cracking se llama una fila empacada, comprimida
o empaquetada, lo cual estudiaremos en profundidad mas adelante, pero igual podemos a pesar de que
este empacada, correrla en OLLYDBG y tratar de hallar el hardcoded serial.
Otro avisito en este caso antes de analizar OLLYDBG nos avisa que es un programa empacado,
comprimido, encriptado y que analizar eso es mas inútil que cenicero de moto, jeje, pues el programa se
ira desempacando mientras corre, por lo cual, elegimos NO, para que no lo analice por ahora.
Pues si alli estamos en las primeras líneas del crackme, vemos como curiosidad que el crackme no esta
ejecutando como los desempacados la primera sección después del header que comienza en 401000
Vamos a ver que sección esta ejecutando, así que voy a VIEW-MEMORY o apreto el botón M.
Vemos que el programa se esta ejecutando en la sección que comienza en 4D4000 y su largo es 2000,
pues 4d4001, es una dirección de memoria perteneciente a esa seccion.
Pues eso era lo que avisaba OLLYDBG que el ENTRY POINT esta fuera de la sección code
La sección CODE empieza en 401000, allí vemos resaltada la palabra CODE y nosotros estamos
ejecutando la dirección 4D4001 que pertenece a otra sección, OLLYDBG nos aviso de esto que es una
característica de muchos programas empacados.
La sección en la cual esta el ENTRY POINT corresponde al desempacador y una vez que se ejecuta y
realiza su trabajo, salta a la sección code donde se ejecuta el programa en si.
Al aparecer la ventana del crackme, para ingresar el serial, sabemos que el programa ya esta desempacado
en memoria y esta ejecutándose ahora en la sección code, por lo cual podemos poner un BPM ON
ACCESS en dicha sección, para que pare allí cuando ejecute alguna línea de la misma.
Al tratar de volver a la ventana del crackme, para OLLYDBG en la sección code o primera sección
después del header.
Veo que ahora que esta descomprimido el programa en memoria, puedo analizarlo entonces, en el listado
hago click derecho
Ahora que estamos en la sección code, podemos ver que apis usa el programa, esto no lo podíamos hacer
en el inicio, pues en ese momento solo nos mostraría las apis que usa el desempacador, y no las que usa el
programa, ahora no hay problema.
Ughh que mal trago una terrible lista y ninguna conocida, veamos la lista de strings, aclaramos que esto
tampoco se podía hacer en el inicio pues estábamos en otra sección y además las strings estaban
empacadas junto con el programa así que no veríamos nada.
Bueno hay una comparación y un salto vemos strings de felicitación y de error aunque no hay
MessageBoxA por aquí.
Pongamos un BPX en el salto condicional para verificar si es el salto decisivo, quitemos el BPM ON
ACCESS con click derecho
Y demos RUN
Invirtamos el salto a ver si sale el cartel de felicitaciones, para ver si es esto verdaderamente lo que
decide.
Y sale el cartel de felicitación, así que por aquí es donde decide las cosas, veamos la comparación antes
del salto.
Es un TEST CL,CL que solo testea si CL es cero o uno, así que la comparación se realiza antes,
posiblemente en el CALL que esta justo antes pongamos un BPX alli.
Demos RUN y volvamos a la ventana y apretemos nuevamente el botón Test para que pare ahora en el
CALL.
Una vez que paro como soy curioso miro un poco alrededor jeje
Si miro en el stack veo mi serial falso allí, veamos en el DUMP haciendo FOLLOW IN DUMP en el
mismo.
Mi ojo de cracker ve por ahí una string con forma de posible serial correcto, podría probar a ver si es pero
por ahora seguiré con el método de buscarlo a fondo sin intentar.
Si alguna vez comparara o operara con mi serial falso dentro del CALL, pues poniendo un BPX ON
ACCESS en el mismo, parara cuando el programa quiera hacer algo con el, o sea al acceder al mismo
para cualquiera operación o comparación que desee realizar.
Apreto F9
Vemos que no para, quizás la comparación sea antes, así que o bien podemos ir poniendo BPX en los
calles que están mas arriba de este y repetir el método o bien empleamos el método de parar justo cuando
el programa ingresa el serial, aquí no utiliza la api GetWindowTextA pero tenemos nuestros Mensajes de
Windows los cuales seguro nos servirán.
Y doy RUN
Y ponemos las tildes para que pare ON CONDITION y que loguee siempre todo.
Llego a la ventana del crackme y para evitar confusiones cambio el serial por si quedo el anterior en la
memoria.
y al apretar el botón para en mi BPX CONDICIONAL
Aquí se me abren dos posibilidades poner un BPM ON ACCESS en la primera sección para con f9 ir
saltando y ver cuando llega a la rutina de comparación del serial, lo cual me parece un poco complejo
porque aquí ya vi que la rutina del serial es bastante larga y me pasare saltando jeje.
La otra posibilidad es ver si el serial que tipee ya ingreso en la memoria, como es un serial nuevo pues si
esta en la memoria, no es porque quedo de antes si no que ya ingreso, así que voy a la ventana M.
Que además de permitirme ver las secciones me permite buscar una cadena en toda la memoria, así que
hago click derecho SEARCH
Y en la ventana que aparece, en la parte ASCII tipeo mi serial falso.
Pues la primera ocurrencia es aquí puedo repetir con CTRL+L y no hallara mas ocurrencias, ni en la
sección que se abrió ni en el resto de la memoria.
Pues pongo un BPM ON ACCESS en mi serial falso pues en algún momento accederá a el para leer,
operar o comparar.
Y apreto F9
Para aquí donde lo copiara a su ubicación la que habíamos visto en el ultimo CALL
Sabemos que el REP MOVS copiara el contenido de ESI a EDI, así que veamos EDI en el DUMP,
haciendo click derecho en EDI-FOLLOW IN DUMP.
Al llegar con F8 al RET lo habrá copiado entero, y pongo ahora el BPM ON ACCESS en mi serial falso
aquí
Ahora para intentar pues no hemos visto aun el tema, por lo cual la siguiente lección no estará con
password, si no para intentar y divertirse, el que quiere intentar el crackme de cruehead hallar un serial
para su nombre pues puede hacerlo, o sea en user pone su nombre y halla el serial correcto, en la próxima
parte empezaremos con crackmes USER y SERIAL y el primero que resolveremos será ese, así que a no
frustrarse si no pueden, que es un tema no visto aun, así que tómenlo como diversión si pueden con el ,
pues felicitaciones, si no pueden, lo aprenden en la próxima parte.
Hasta la parte 16
Ricardo Narvaja
08 de diciembre de 2005
INTRODUCCIÓN AL CRACKING CON OLLYDBG PARTE 16
Comenzaremos en esta parte con los crackmes que a diferencia de los hardcoded como hasta ahora, el
serial es variable y depende del nombre que ingresamos, y es calculado a partir de el.
El mecanismo para solucionarlos es muy similar, pero veremos algunos ejemplos para que quede claro.
En la parte anterior los anime a que intenten hallar para su propio nombre, el serial correcto para el
CRACKME DE CRUEHEAD y bueno, ese será el primero que haremos, así ven como se soluciona y si
estaban en el buen camino, y si lo solucionaron pues mis mas gratas felicitaciones.
Veamos las apis que utiliza para ingresar el texto del serial que tipeamos
Probamos colocando un BP en dicha api a ver si se detiene cuando ingresa el nombre y serial correcto
Damos RUN
Allí esta, aun vacío porque no se ejecuto la api, así que hagamos DEBUG- EXECUTE TILL RETURN y
como estamos en el RET de la api hago F7 para volver al programa.
Vemos que en el buffer guardo mi nombre a partir del cual realizara operaciones y creara la clave correcta
para el mismo, si quisiéramos hacer un keygen, deberíamos estudiar a partir de aquí las operaciones que
realiza el programa para desde un nombre cualquiera, calcular la clave correcta, pero como este no es el
caso, dejaremos que el programa genere la clave correcta y trataremos de ver si compara con el serial que
tipeamos damos RUN nuevamente.
Para por segunda vez en la api, el nuevo BUFFER para la entrada del serial que tipee es 40217E, así que
lo busco en el dump.
Allí esta justo arriba del otro, ejecuto la api con EXECUTE TILL RETURN y para volver al programa
desde el RET apreto F7.
Allí ingreso nuestro serial falso, a partir de este punto el programa comparara el serial falso con el
correcto que calculo a partir de mi nombre, así que podemos colocar un BPM ON ACCESS en este serial
falso para ver que hace el programa con el.
Marco los bytes y hago click derecho – BREAKPOINT –MEMORY ON ACCESS y doy RUN
Vemos que para allí cuando el programa lee el primer byte de mi serial falso y lo mueve a BL si apreto
F7.
Allí esta en BL el valor 39 de mi primer byte, debemos perseguir lo que el programa realiza con el, y en
lo posible ir anotando para no perdernos si realiza operaciones matemáticas con el mismo.
Allí testea si es cero, para salir del loop al encontrar el final de la string, sigamos con f7
Dichos valores estaban inicializados EAX en 0A justo al inicio de la rutina y EDI antes de entrar al loop
se coloco a cero con XOR EDI,EDI
Allí esta de donde surgen ambos valores, al apretar f7 si recordamos la definición de IMUL con dos
operandos, en dicho caso multiplica ambos considerando el signo, y guarda el resultado en el primer
operando o sea EDI en este caso.
Quedando el EDI el valor 9, a no desesperar que esto parece difícil pero ya verán que no lo es en la
próxima línea INC ESI, incrementa ESI para retornar al inicio del LOOP con el JMP y poder leer el
siguiente byte de mi serial falso.
Luego de volver a colocar en AL el valor 0A, ahora lee el segundo byte de mi serial falso, ahí vemos que
moverá a BL el valor 38 al igual que antes, testeara si es cero, le restara 30, y llegamos a la IMUL.
Vemos que multiplica EDI que tiene el valor que arrastra de la pasada anterior con 0A y el resultado lo
guardara en EDI veamos.
EDI queda en 5A en la siguiente línea le suma EBX
O sea que va realizando operaciones y va juntando el resultado en EDI, para los que son ya asiduos al
cracking ya sabrán que hace aquí, lo explicaremos.
Lo mas sencillo es poner un BP en la salida del loop apretemos F9 y cuando se detiene veo que EDI vale
98989898 lo primero transformo esto en el número decimal 98989898 y luego lo transformo a hexa
quedando 5E6774A.
Vemos que al volver del ret llega a la comparación EAX con EBX, lleguemos allí, ese era el salto que
decidía si era correcto o no así que estamos bien,
Al llegar vemos que compara el valor que calculó que esta en EBX con EAX que vale 547B
Como EAX es un valor determinado del programa y EBX es calculado a partir de mi serial falso el cual
es incorrecto obviamente, aquí no hay igualdad.
Si EBX fuera igual a EAX el programa saltaría a CORRECTO, por lo tanto debemos analizar como llegar
a que allí haya una igualdad.
Como yo quiero que EBX sea igual que EAX, en dicho caso se verificara la igualdad y estaremos en el
caso correcto
Si EAX=EBX
Y ya no es más serial falso porque el serial que hace que EBX y EAX sean iguales es el serial correcto.
Despejo
Si soluciono el XOR
Si 464F es el valor correcto hexadecimal, si lo paso a decimal tendré mi serial para tipear
Apreto decimal
Ese es el serial correcto para narvaja quitemos todos los BPM y BPs
Apreto OK
Esta es una forma de solucionarlo, otra forma de pensarlo que se llega a la misma soluciones es esta
Si a mi serial falso le hace operaciones y lo transforma a esas operaciones las llamamos función F
O sea que a mi serial falso le realiza ciertas operaciones llamadas F y lo convierte en EBX el cual
comparará.
Aplicando las mismas operaciones al serial verdadero en este caso llego al valor de EAX, por lo tanto si
tengo EAX ya que es un dato de la comparación y tengo las operaciones realizadas.
Para hallar el serial verdadero deberé a EAX realizarle las operaciones opuestas para hallar el serial
verdadero.
O sea si fuera que a mi serial falso se le sumo un valor para llegar a la comparación, este se lo deberé
restar a EAX y así siempre debo realizarle las mismas operaciones pero opuestas.
En este caso la operación opuesta de XOR es la misma XOR ya que es una operación inversible
Por lo cual
XOR EAX será realizar la función opuesta de F y me dará el valor hexa de mi serial correcto, a partir del
cual, pasándolo a decimal obtendré el serial verdadero.
Esto que parece mucho palabrerío no lo es tanto, de ambas formas despejando o realizando las
operaciones opuestas normalmente se puede llegar al serial correcto, salvo que se use una operación que
no tiene opuesta, ya veremos esos casos.
Veamos otro caso el del ya visto SPLISH pero en el modo USER-NAME ya que la parte HARDCODED
ya la hemos hecho.
Allí está vacío aun, hagamos EXECUTE TILL RETURN para llegar al RET y luego F7 para volver al
programa.
Vemos que en este caso ingreso primero el serial falso, así que marcamos el mismo y ponemos un BPM
ON ACCESS.
Damos RUN
Para de nuevo en la api para ingresar el nombre, como esto por ahora no nos interesa damos RUN
nuevamente.
La primera línea mueve nuestro primer byte del serial falso si ejecutamos
Luego tenemos la siguiente instrucción CDQ, ya que no la explicamos veamos que dice nuestro amigo
GOOGLE, el puede ayudar tipeamos en el buscador de GOOGLE CDQ ENSAMBLADOR.
En este caso igual no es necesario ya que EDX es cero y esta preparado para obtener el resto de la
división pero como es un loop por si acaso siempre mejor antes de una IDIV usar el comando CDQ para
preparar los registros EDX y EAX para la misma.
Pues dividirá EDX:EAX por ECX y el resultado va a EAX y el resto a EDX bueno este es todo el truco
vemos que el byte nuestro vale 39 y lo dividirá por ECX que es 0A
Vemos que en la próxima línea guarda el resto de la división en 40324D veámoslo en el DUMP
Allí lo guardara ejecuto con f7
Vemos que EBX que era cero es incrementado y comparado con 6 para salir del loop por ahora no son
iguales por lo tanto repite.
Bueno vemos que no hay variación realiza la misma operación en todos los bytes.
Y sale del loop al no saltar el JNZ que nos retornaba al inicio del mismo.
Llegamos allí y vemos los mensajes de correcto o incorrecto por lo cual ya sabemos que estamos cerca.
Luego hay dos LEA que mueven direcciones a ESI y EDI
ESI apunta a donde guardo los restos y EDI apunta a algo interesante jeje?
Sigamos
A EAX moverá el primer byte que apunta EDI que es 02 y a ECX mueve el primer byte de mis restos o
sea 7.
Y si vemos que si el resto del primer byte hubiera sido 02 la comparación seria exitosa.
39= 5 .0A + 7
Ya que el resultado de 39 dividido 0a daba 5 con resto 7, eso quiere decir que al multiplicar 0a por 5 me
da 32 y al sumarle 7 me da 39 lo cual se ve reflejado en esa formula
39= 5 x 0A + 7
Como el resto correcto debería ser dos para el caso del serial correcto
BYTE CORRECTO= 5 x 0A + 2
BYTE CORRECTO= 32 +2 = 34
BYTE CORRECTO= 5 x 0A + 2
Al realizar 5 x 0A + 2 se pasa de los números posibles de una cifra (de 30 a 39) en ese caso es porque el
resultado de la división no era cinco sino 4 por lo cual disminuimos y intentamos nuevamente con
Vemos los otros bytes correctos que va a comparar con mis restos.
Con 02 ya calculamos
Sigamos con 08
BYTE CORRECTO= 5 x 0A + 8
BYTE CORRECTO= 32 + 8
En este caso da 40 se pasa del máximo numero decimal que es 39 ( 9 en ASCII) así que disminuyamos a
BYTE CORRECTO= 4 x 0A + 8
El siguiente es 03
BYTE CORRECTO= 5 x 0A + 3
El siguiente es el 05
BYTE CORRECTO= 5 x 0A + 5
Por lo cual el serial correcto para narvaja seria 4005775 quitando todos los BPM y BPX y dando RUN
El crackme para practicar por ahora será uno de solo serial hardcoded de a poco iremos aumentando por
supuesto con el serial correcto se activa la parte 17, así que a buscar que este es muy fácil, el crackme es
el MEXCRK1.ZIP y esta adjunto con la lección.
Ricardo Narvaja
11 de diciembre de 2005
INTRODUCCION AL CRACKING CON OLLYDBG PARTE 17
Bueno antes que nada, vamos a solucionar el crackme MEXCRK1.ZIP pendiente que es muy
sencillo.
Abrámoslo en OLLYDBG y por supuesto para en el Entry Point
Veamos las strings referentes que utiliza el programa, haciendo click derecho
Vemos allí la zona caliente, un Call y dentro se decide ya que a la vuelta del mismo hay un JE
que salta a WRONG CODE DUDE o a THANKS YOU MADE IT, o sea que es el salto decisivo.
Pongo un BPX un poco antes del CALL en 42d534, y doy RUN
Allí tipeo mi serial falso, en la parte superior donde dice ENTER SERIAL #
Si entro traceando dentro del CALL veo que compara mi serial falso Narvajita, con la string
Benadryl.
Bueno ya llegamos a la comparación, así que el serial correcto es la palabra Benadryl si damos
RUN nuevamente quitando todos los BPXs
Allí vemos como nos felicita por haber hallado el serial correcto y felicitaciones porque si
llegaron aquí también lo han sacado ustedes.
Bueno vamos a hacer el ultimo user, name ya que en la próxima parte comenzaremos con un
nuevo tema.
Uno de los lectores de este curso, tuvo problemas con un programita que en realidad es un juego
que se llama canasta 5.0 y que ira adjunto al tutorial.
El me comentaba que se le quemaron los papeles porque siempre, en los tutes vemos casos de
user y name que se ingresan apretando un botón y en este caso, solo hay que tipear y si lo que tipeas es
correcto, el botón OK se habilita pues esta deshabilitado.
Allí dice que el botón OK se habilitara cuando se coloque la combinación correcta jeje.
Arranquémoslo en OLLYDBG.
Ahora apreto la M
Luego de que para dos o tres veces en palabras que comienzan con WM, y que sigo buscando con
CTRL+L y si termina una sección salgo y sigo buscando mas abajo en la ventana M, llego a esta
ocurrencia que muestra WM en mayúscula y solo, y además abajo esta el texto que muestra de que se
habilitara el botón OK cuando apretemos el serial correcto.
Recordemos que a las direcciones que comienzan con letra, como en este caso la C debemos ponerle un
cero delante si no el OLLYDBG no las reconocerá.
Para estar seguros que esta es la zona donde va guardando el serial, escribamos el siguiente carácter del
serial WMYXSZ, o sea tipeo la Y.
Al tipearla, veo en el dump que se agrego y que halle la zona donde va guardando el serial, por lo tanto,
pongamos allí un BREAKPOINT MEMORY ON ACCESS que abarque 6 cifras ya que sabemos que son
6.
Luego para nuevamente cuando copia al stack, los cuatro bytes que entramos hasta ahora.
Antes justo del nombre esta 0E que es el largo del mismo, y lo compara con cero
Y podemos probar si es el serial correcto quitando todos los BPM y BPX y HARDWARE BPX
Al colocarlo se habilito el botón y al apretarlo estamos registrados jeje, otra opción que no voy a
detenerme a explicar aquí, pero no es muy difícil, es usar WM_KEYUP cosa de que cada vez que
apretamos una tecla pare OLLYDBG y podamos seguir el valor del byte que tipeamos, aunque
lógicamente es mas engorroso, este método si nos funciona es mucho mas sencillo.
Bueno los dejo descansar un poco, la próxima parte ya veremos un poco mas de teoría, acompañada de
ejemplos para poder ir avanzando mas en conocimientos lo cual derivara en programas mas complejos
resueltos.
Hasta la parte 18
Ricardo Narvaja
15 de diciembre de 2005
INTRODUCCIÓN AL CRACKING CON OLLYDBG PARTE 18
Bueno, en la parte anterior había comentado que iba aquí a empezar otro tema que seria el tema de la
detección del OLLYDBG, por los programas que ejecutamos en el, lo que comúnmente se llama
antidebugging, como evitarlo manualmente, y con los plugins disponibles en cada caso y con ejemplos.
Pero eso con ese tema comenzare en la parte 19, ya que surgió entre varios seguidores del curso que me
escribieron al mail, el pedido de que haga un ejemplo mas de crackme sin botones, como el de la parte
anterior, y si es posible usando la otra técnica la de WM_KEYUP .
Bueno así que usaremos un crackme que me facilito Stzwei, gracias por el mismo, llamado
crackme_4stz.exe y que por supuesto estará adjunto con este tutorial.
Allí esta parado en el Entry Point, veamos las strings referentes ya que no esta empacado.
Vemos que no hay botón de registro, así que tipeo un nombre completo
Si alguien no se acuerda el valor correspondiente al WM que vamos a usar, pues vamos a la ventana W,
que nos muestra las ventanas del programa.
Y nos aparece la lista de ventanas, en cualquiera, total es solo para averiguar el valor numérico, hacemos
click derecho
Y nos aparece la ventana de los MESSAGE BREAKPOINTS con el menú desplegable de los WM
Buscamos en la lista WM_KEYUP
Vemos que es 101, así que cancelamos todo esto que fue solo para averiguar ese valor numérico y
volvemos al BREAKPOINT CONDICIONAL LOG en TranslateMessage.
Y allí coloco MSG==101 (recordar el doble signo igual), también podía haber escrito allí si no encuentro
el valor, MSG==WM_KEYUP y funcionara, pero a mi me gusta mas usar valores numéricos, cada uno
puede hacer como quiera en ese punto.
Bueno allí quedo nuestro BPX transformado en CONDICIONAL LOG (color rosa)
Vemos allí los parámetros de la api, en 12ff78 hay una estructura que guarda los valores del la tecla que
aprete en este caso 39, que corresponde al numero 9.
Veamos en el DUMP dicha posición de memoria, haciendo click derecho en dicha dirección y eligiendo
FOLLOW IN DUMP.
Vemos que conseguimos parar y identificar cuando ingresa el byte el problema es que es un programa en
DELPHI lo cual veremos mas adelante y si pongo un BPM ON ACCESS en ese byte, dará mil vueltas
antes de llegar a la comparación, por lo cual, el método que vimos la vez anterior se aplica mucho mejor
aquí y antes de enloquecer pues lo usaremos, de cualquier forma ya saben como parar el programa cuando
ingresa por teclado, y como localizar el byte, seguramente en otro crackme que no sea en DELPHI, se
podrá seguir mas fácilmente con un BPM ON ACCESS en el mismo, hasta la comparación.
Y doy RUN
La primera ocurrencia es en el stack apreto CTRL + L varias veces a ver cuantas aparece en el mismo.
Una zona vez ya que nos aparece en amarillo la palabra ITEM NOT FOUND debajo, salgamos de esta
sección y volvamos a la ventana M
Llego hasta aquí buscando, así que sigamos para abajo con CTRL + L
Allí aparece por primera vez en esta sección hagamos CTRL + L para ver si aparece de nuevo
Doy RUN
Lo que vemos que cada vez que tipeo va copiando de nuevo mas abajo mi serial falso y cada vez lo va
machacando con mi nombre, y con el carácter siguiente vuelve a copiar el serial bueno mas abajo y asi
hasta que tipeo los 6 caracteres del serial falso y ahí si cuando están los 6 caracteres a la vista poniendo un
BPM en ellos.
Los cuales son comparados de a 4 bytes en ese loop, probemos si el serial hallado es el correcto
Vemos que a pesar de todo es un crackme difícil ya que es un momento justo, que hay que agarrarlo ya
que va variando la posición del serial falso y hay que agarrarlo con el BPM justo cuando recién lo escribe
en su nueva posición, para poder parar en la comparación.
Pues voy poniendo BPM ON WRITE en la zona justo abajo, donde va a escribir cuando ingrese el
próximo carácter
Seguro cuando ingrese el próximo carácter, lo escribirá aquí, así que doy RUN
Allí escribio primero el posible serial bueno
Damos RUN
Y luego para cuando copia el serial falso, ahora si que paro apenas se copio, puedo ponerle un BPM on
ACCESS al serial falso y al dar RUN para justo en la comparación, nuevamente.
Bueno creo que este fue un caso difícil para cualquier método por lo movedizo de la zona donde guarda el
serial.
Bueno les dejare un ejercicio, este será hallar el serial del CRACKME DE CRUEHEAD 2, esto será el fin
del primer capitulo de la INTRODUCCIÓN a partir de la parte 19 empezaremos con nuevos temas, y el
resolver este sencillo crackme será como la graduación del primer capitulo, recuerden que para abrir el rar
de la parte 19 necesitaran del serial verdadero del crackme de cruehead 2 es bien sencillo.
Hasta la parte 19
Ricardo Narvaja
19 de diciembre de 2005
INTRODUCCION AL CRACKING EN OLLYDBG parte 19
Como dijimos la parte anterior, nos concentraremos en la forma de evitar manualmente y por
medio de plugins la detección de OLLYDBG por medio del programa que esta siendo debuggeado, de
forma tal de poder trabajarlo tranquilamente ya que la mayoría de los programas, cuando detectan que hay
un debugger trabajando sobre ellos, se cierran o comienzan a funcionar en forma diferente por lo cual
hay que lograr evitar por todos los medios la detección de OLLYDBG por parte del programa victima.
Esta primera parte tratara sobre la detección por medio de la api IsDebuggerPresent, la cual es la
mas comun de todas.
Para ello utilizaremos el Crackme1.exe que esta adjunto a esta leccion, lo arrancamos en
OLLYDBG.
Recordemos que mi OLLYDBG por ahora solo tiene el plugin COMMAND BAR, por lo cual,
no tiene cargado ningún plugin que pueda evitar la detección por medio de la api IsDebuggerPresent, pero
como funciona dicha detección?
Si corremos el crackme con F9 vemos que no solo no abre la ventana del crackme si no que se
cierra el programa.
OLLYDBG nos indica en la parte inferior que el programa termino, y ni siquiera vimos la
ventana del crackme, jeje, que ocurre aquí, muy sencillo el crackme utiliza el método mas conocido para
detectar que esta siendo debuggeado que es llamar a la api IsDebuggerPresent.
Reiniciemos el crackme y veamos si la susodicha esta en la lista de las apis que utiliza la victima,
haciendo click derecho en el listado y eligiendo ..
Vemos la lista de apis usadas
http://www.ricnar456.dyndns.org
user:hola
pass:hola
http://www.ricnar456.dyndns.org/HERRAMIENTAS/V-W-X-Y-Z/winapi32%20NEW.rar
user:hola
pass:hola
El archivo zip, contiene un archivo de extensión HLP que es el que nos interesa lo ejecutamos.
Allí en la barra a medida que vamos tipeando el nombre de la api, va buscando las que coinciden
con la letra que tipeamos
La api IsDebuggerPresent indica cuando el proceso que la llamo, esta bajo el contexto de un
debugger o sea siendo debuggeado.
Luego dice que esta api o función es exportada por la KERNEL32.dll, que no tiene parámetros
como vimos, y en RETURN VALUES o sea en valores de retorno, dice que si el programa esta siendo
debuggeado el retorno es un valor distinto de cero, y si no lo esta es cero.
Bueno esa información es muy importante, ejecutemos la api hasta el RET a ver donde devuelve
la información.
Probemos que ocurre si lo cambiamos a mano y ponemos EAX=0 o sea que no esta siendo
debuggeado.
Vemos que vuelve a parar en la api, así que llegamos al ret nuevamente y cambiamos EAX a
cero.
Vemos que el programa arranca, o sea que toda su detección se basa en dicha api, reiniciémoslo
y cuando pare en IsDebuggerPresent, veamos que hace con el valor que le devuelve la api.
Allí paro nuevamente lleguemos hasta el ret, podemos tracear con f8 pues la api es cortita.
Allí esta, al llegar al RET, vale EAX=1, volvamos al programa con f8 nuevamente.
Vemos que la primera vez no es llamado desde el mismo ejecutable si no de una dll que es
uxtheme, demos RUN a ver la segunda vez que para en la api.
Ahí paro la segunda vez, llego hasta el RET, y vuelvo al programa traceando con f8.
Llega aquí, y allí hay un JE que testea si EAX se cero o no, veamos.
Vemos que el JE al ser EAX diferente de cero no salta, observamos también que si saltara
continua la ejecución del programa con GetDlgItem leyendo de la ventana del crackme.
Como no salta continua al JMP, el cual no es evitado, y aquí si se puede aplicar bien la palabra el
crackme me tiro fuera, vemos que el JMP nos lleva bien lejos, posiblemente a cerrar el programa.
Y si tenemos paciencia de tracear bastante mientras va cerrando todo, observaremos que llegara
a la api ExitProcess que es la que cierra el proceso.(si no tienen paciencia le ponen un BP ExitProcess y
parara en ella)
Así que ya vimos que el salto que esta al volver de la api IsDebuggerPresent es el que toma la
decisión de si corre o se cierra, una solución podría ser parchearlo, reiniciemos el programa y lleguemos
al salto decisivo.
Allí esta y como habíamos visto tenia que saltar siempre, por lo cual lo cambiamos a JMP,
tecleando la barra espaciadora y escribiendo JMP 4011b2.
Allí esta, vemos que ahora evita el JMP que va a cerrar el programa y el mismo continua
funcionando.
Guardemos los cambios en un archivo con otro nombre, hagamos click derecho
Ahora abramos el parcheado en OLLYDBG para ver si corre en el mismo, sin poner ningún BP
ni nada
Corre perfectamente, así que ya sabemos hacer correr un programa cambiando EAX al volver de
IsDebuggerPresent, también sabemos parchear para que corra y no tengamos que tomarnos el trabajo de
hacerlo a mano.
Con este crackme no tendremos problema, para parchearlo y que corra, aunque por supuesto hay
métodos mas sencillos usando plugins que nos evitan realizar todo este trabajo, pero es bueno conocer
como funcionan las cosas.
Ahora la pregunta que alguien se podría hacer es la siguiente volvamos al original y miremos la
api.
Son tres tristes MOV y con eso la api determina si esta siendo debuggeado el programa o no.
Lo primero que se me viene a la cabeza es, porque el programa no podría ejecutar estas tres
líneas mezcladas entre su código, las cuales le devolverían en EAX el valor 1 si esta siendo debuggeado,
probemos reiniciemos el crackme original y en el entry point escribamos.
Vemos que cuando paso la ultima instrucción, EAX se puso a 1 en la misma forma que lo hace
en la api.
Y obviamente nunca el programa parara en la api IsDebuggerPresent, pues nunca fue llamada, e
igual detecto que esta siendo debuggeado.
Por ello es muy importante determinar que es lo que lee la api o mejor dicho esas tres líneas
famosas.
Como podemos localizarlo al byte?, pues vayamos nuevamente a la primera línea de estas tres y
miremos paso a paso lo que hace.
La primera línea es
Pues aquí explicaremos lo más sencillo posible algo de teoría, en el OLLYDBG vemos aquí
En la ventana de los registros un valor muy importante, no quiero dar nombres difíciles pero ese
valor apunta a una estructura que guarda información muy importante sobre el programa que arranco,
vayamos a ver en el DUMP dicha dirección (en su maquina puede estar en otra dirección solo vayan a la
dirección que les indica olly allí)
Esta estructura se llama TEB O TIB y guarda buena información que si consultamos nos puede
ayudar muchísimo con el programa, en la TIB podemos ver por ejemplo donde comienza y donde termina
el stack del programa.
Si vemos en M la sección del stack
Vemos que comienza en 12d000 y termina justo antes de donde se inicia la sección siguiente en
130000.
Hay muchos otros valores interesantes como el primero, que veremos mas detalladamente
cuando estudiemos las excepciones, pero como adelanto si miramos en el stack ese valor 12ffE0 en mi
maquina.
Lo busco en el stack
Vemos que esta marcado como END OF SEH CHAIN, por ahora no diremos mas de el, pero si
que esta relacionado con las excepciones.
Una cosa interesante de este TIB es que existe una nomenclatura para acceder al cualquier valor
del mismo, por ejemplo este valor que marque antes seria Fs: [0] .
Ese seria Fs: [0], si en la command bar buscamos el valor de fs: [1], ese seria
Por lo tanto:
Es ese valor, o sea que el valor que guarda el TIB en FS : [18] es el valor que OLLYDBG nos
mostraba en los registros el puntero al inicio del TIB, que lo almacena allí.
O sea que en la primera línea, solo muevea EAX el puntero al inicio del TIB, para enterarse
donde esta ubicado en tu maquina, y eso esta en fs: [18] por lo tanto si ejecuto la línea con f8, moverá ese
valor a EAX.
7FFDC000 + 2= 7FFDC002
Y mueve el byte que contiene esa dirección a EAX y dicho byte es el byte buscado,y ya lo
hallamos manualmente es en mi maquina el que esta en la dirección 7FFDC002 (en su maquina puede
cambiar la dirección realizar el mismo proceso para hallarlo)
Allí el sistema guardo el byte 1 que lee la api, inclusive en su misma maquina puede variar de
posición al reiniciar, pero siempre lo pueden hallar rápidamente con este método, reiniciemos el crackme.
Esta vez no escribimos nada a ver si localizamos el byte a mano y si lo ponemos a cero a mano,
y veremos si el programa corre, pues la api leerá dicho byte y si esta a cero, pues devolverá cero, jeje.
Busco fs: [30] o sea le sumo 30 al inicio del TIB y hallo su contenido
Y le sumo 2 y allí esta el byte (muchos dirán para que tamaña explicación si los programas
cuando arrancan en EBX, esta siempre el puntero a esta zona, jeje o sea EBX= fs:[30], jeje)
Bueno pero es bueno saber el método entero, porque por ahí uno no esta al inicio del programa y
quiere hallar el byte a mano y no sabe que valor tenia EBX en el arranque, pero bueno este es el método
completo, ahora pongamos a cero el byte.
Obviamente hay muchos plugins que hacen este trabajo, uno de ellos es el plugin HideDebbuger
1.23f que pueden descargar desde mi http aquí
http://www.ricnar456.dyndns.org/HERRAMIENTAS/L-M-N-%D1-O-
P/Plugins_Olly/HideDebugger123f.zip
COPIANDO jeje
Viene ya marcado para evitar que detecte por el byte de IsDebuggerPresent o sea hace el trabajo
que nosotros hicimos a mano lo pone a cero siempre, apretamos SAVE y las otras opciones por ahora las
dejamos deshabilitadas, a medida que las vayamos estudiando, las veremos.
Arranco de nuevo el crackme y me fijo ya que EBX apunta a la zona del byte
El siguiente truco ANTIOLLYDBG que veremos en esta oportunidad es la detección del mismo, por el
nombre del proceso del OLLYDBG, pero antes de todo les diré una configuración del OLLYDBG que
aun no hemos tocado y que es muy importante en este caso.
Allí lo mejor es poner las tres tildes y que cargue siempre la información, verán que con las tres tildes
puestas cuando pongan BPX en una api y reinicien el OLLYDBG, el BPX continuara puesto, lo cual evita
tener que repetir el proceso de ponerlos uno a uno cada vez que reiniciamos.
Estrictamente no conozco el funcionamiento interno completo del OLLYDBG pero en la practica lo que
sucede es eso con las tres tildes, los BPX en las apis se mantienen luego de reiniciarlo.
Así esta mejor para mi gusto, es menos molesto, ahora si, comenzamos con el tema de antidebugging por
el nombre del proceso.
Cuando corremos el OLLYDBG si miramos la lista de procesos con CTRL + ALT + SUPR
Vemos que el nombre del proceso esta allí muy claro en la lista de los mismos, que le impide a un
programa revisar todos los procesos y si encuentra alguno que se llame OLLYDBG, cerrarlo, pues nada,
jeje.
Usaremos un crackme que no resolveremos por ahora porque es un nivel levemente superior al actual, así
que lo veremos mas adelante, pero estudiaremos en el la técnica de cómo detectan los programas a
OLLYDBG por el nombre del proceso, como evitarlo manualmente y como evitarlo definitivamente jeje.
El crackme que adjunto es el DAXXOR el cual si dejamos un OLLYDBG corriendo vacío y corremos
fuera de OLLY el famoso DAXXOR, veremos que el crackme corre pero cierra el OLLYDBG, lo mismo
que si lo corremos en OLLYDBG, también lo cierra y por supuesto se acaba todo.
Bueno hay unas cuantas, pero aquí hay otra protección agregada y es que el crackme no tiene cargadas en
el inicio las apis que usara para detectar al OLLYDBG, y las cargara a medida que corra, de paso
explicaremos también este método de protección que en si, no te permite ver todas las apis que usara, en
la lista de NAMES, pero por otra lado tiene como contrapartida que el que se da cuenta del truco y
descubre las apis que va cargando el programa a medida que corre, sabrá a ciencia cierta que esas apis son
las IMPORTANTES, pues por algo el programa las oculta para que no aparezcan en la lista.
Esto casi siempre es evidente cuando un programa que no esta empacado como en este caso, hace uso de
la api GetProcAddress
GetProcAddress se utiliza, para que el programa cargue nuevas apis, que no están en la lista para poder
usarlas, ya veremos un uso intensivo y mas detallado de esta api en el capitulo de desempacado, pero por
ahora pongamos un BP en dicha api.
Y demos RUN
Cada vez que para vemos que esta pidiendo por medio de la api GetProcAddress, la dirección en nuestra
maquina de una determinada api la primera que pide es en este caso, __CPPdebugHook que no pertenece
al truco que estamos estudiando por lo cual damos RUN nuevamente.
Así vamos pasando con F9 hasta que encontremos apis relacionadas con el truco, aquí vemos la api
EnumProcesses que es usada, así que lo que hacemos es llegar hasta el RET de GetProcAddress la cual
nos devuelve en EAX la dirección de la api solicitada en nuestra maquina y allí le ponemos un BPX,
veamos, lleguemos al RET con EXECUTE TILL RETURN.
Allí en EAX devuelve la dirección en mi maquina de la api solicitada, en mi caso es 76BB3A9A en sus
maquinas puede variar.
Por otro lado veo que OLLYDBG no identifica la api que no esta en la lista de NAMES, por lo cual no se
puede poner BP directos al nombre de la api, si no que hay que poner el BP en la dirección.
Ahora si lo toma
Ya tenemos puesto el BP en la api sospechosa, sigamos corriendo OLLYDBG, para ver si carga mas apis.
Hmm enumera los módulos de un proceso, hmm repito el procedimiento anterior llego al RET y le pongo
un BPX a la dirección que me muestra EAX.
Que me servirá para colocarle BPX a todas las apis cuando este en el RET .
Otra sospechosa le pongo BP de la misma forma que a las anteriores, y doy RUN y para en
EnumProcesses
El comentario a la derecha con el nombre de la api se lo agregue yo, haciendo doble click en esa zona nos
permite agregar un comentario.
Esto lo realizo en todas las apis que el programa va cargando y veo sospechosas cuando le pongo un
BPX cosa de que cuando pare, sepa que api era, pues el OLLYDBG no me aclarara nada al no ser una api
de las de la lista.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/perfmon/base/enumprocesses.asp
Bueno aquí dice que la susodicha api, nos devolverá el PROCESS IDENTIFIER o PID de cada proceso
que esta corriendo, pues bien veamos antes que es el PID ese, jeje.
Cada proceso que corre esta identificado con un número que varia cada vez que se arranca un proceso, si
vemos en la lista de procesos
Vemos que el OLLYDBG en este caso tiene un PID de 724 decimal ya que esta utilidad trabaja con
números decimales, pero bueno si queremos saber el PID del OLLYDBG en hexa con la calculadora de
Windows.
2D4 será el PID del OLLYDBG, pueden verificar que si lo cierran al OLLYDBG y lo vuelven a abrir el
PID variara, pues cada proceso al reiniciarse recibirá otro PID.
Tampoco tendremos la suerte en este caso de que OLLYDBG nos muestre los parámetros de la api pues
para OLLYDBG no existe la misma.
Sabemos por la pagina de Microsoft que los tres parámetros son estos
O sea que en 12eDe4 guardara la lista de PIDs de todos los procesos que corren en mi maquina, hagamos
execute till return para llegar al ret de la api y ver en el dump si los guarda alli.
Que diferencia hay entre el PID y el handle, muy sencillo, el PID es un identificador genérico, en toda tu
maquina, en cualquier proceso el PID del OLLYDBG será el mismo mientras no se reinicie, en mi caso
será 2d4, ahora el handle, como su nombre lo indica es un manejador, o sea que es un numero que te
devuelve el sistema para que tu programa pueda manejar ese proceso, y el numero puede variar para cada
programa, es como una solicitud para controlarlo, si no la pedís no tendrás el numerito y no lo podrás
controlar, si lo pedís el sistema te devolverá el manejador y lo podrás manejar y hacerle guarradas jeje.
O sea devolverá el manejador del proceso que esta corriendo, en resumidas cuentas es lo que el programa
quiere saber en este caso.
El mismo OLLYDBG nos muestra los HANDLES con los cuales esta trabajando el programa en la
ventana H.
Vemos que allí aparece el 58 y el TYPE o tipo es PROCESS o PROCESO, así que el programa maneja el
handle 58 que pertenece a un proceso en este caso al OLLYDBG.
Si otro proceso usara EnumProcess para hallar el PID en este momento seria el mismo 2d4 mientras no se
termine el proceso OLLYDBG, ahora si pide al sistema un handle o manejador para dicho proceso, será
cualquier otro numero pues, los handles son particulares de cada proceso.
En este caso el peligro para nuestro OLLYDBG es que el programa ya tiene un manejador, con ello puede
hacer lo que quiere, lo que si aun no sabe que pertenece a OLLYDBG solo que es un proceso y que esta
corriendo, ahora debe verificar el nombre del mismo para determinar si este proceso es OLLYDBG,
obviamente esto lo realiza con cada PID que obtiene de la lista de procesos, nosotros salteamos todos y
llegamos hasta cuando trabaja con el OLLYDBG al haber puesto un BPM ON ACCESS en su PID.
Vemos que allí llega a la otra api que nos quiso ocultar en este caso EnumProcessModules, en la misma
pagina de MICROSOFT vemos el detalle de esta api.
O sea que ahora va a buscar de este proceso que esta investigando, la lista de handles de los módulos que
usa, lleguemos con f7 hasta la api.
Aquí hay una cosita que aclarar, cuando pedimos handle de los módulos el sistema nos devuelve la
dirección base o donde comienza dicho proceso en la memoria, en este caso nos devuelve 400000 ya que
el proceso OLLYDBG comienza allí.
GetModuleBaseNameA
O sea que con esto quiere hallar el nombre del modulo, ya que esta api, en el parámetro lpBaseName,
abre un buffer para guardar el nombre del modulo que corresponde a esa base que averiguo antes, veamos
lleguemos hasta la api.
En el stack los parámetros son:
El 58 que es el handle del OLLYDBG, el 400000 que es la base del modulo principal, y el buffer estará
guardado en 12ECE0, asi que veamos esa zona en el dump.
Jeje ya tiene ahora que llega hasta el RET el nombre del proceso y realiza esto con cada uno de los
procesos que corren en tu maquina, pues ahora comparara el nombre a ver si es OLLYDBG.exe si en este
caso hubiera sido OPERA.EXE por ejemplo, pues lo dejara tranquilo seguramente jeje.
Ahora llega a CloseHandle donde cierra el manejador o sea que el 58 desaparecerá de la lista de handles.
Pues si, por ahora no podrá hacerle trastadas pues no tiene el handle abierto, pero no nos confiemos
sigamos adelante.
Vemos que llega a un CALL entremos a el con F7
Allí lee la primera letra de OLLYDBG (4F) y la pone en el stack con PUSH y entra a otro CALL
entremos también.
Vemos que en este call no realiza nada demasiado importante salimos y llegamos al segundo.
Entramos en el
Ahh acá si esta comparando el nombre del proceso que obtuvo, con el nombre OLLYDBG.exe y si son
iguales ir a a kaput, jeje en este caso eran iguales veremos que hace, lleguemos al RET
Allí si no son iguales, EAX será diferente de cero y saltara y no pasara nada pero si EAX es igual a cero
como en nuestro caso.
Como vemos llega a la api TerminateProcess auxilio esta por morir mi OLLYDBG a la cual le pasa el
handle 58.
Y al apretar f8, adiós OLLYDBG se cerro todo, con eso investigamos como funciona la detección por
nombre.
Con eso, la api siempre devolverá cero quitemos todos los Bps, y debemos ya que el programa genera
muchas excepciones y aun no hemos visto el tema excepciones, para que corra poner las tildes en
DEBUGGING OPTIONS- EXCEPTION de esta forma.
Por ahora coloquen las tildes de esta forma para que el programa salte solo las excepciones ya que son
muchísimas y vivirán haciendo SHIFT +f9 para pasarlas, de esta forma las que están tildadas las pasara
automático el OLLYDBG sin parar, demos RUN.
El programa arranca y muestra la ventana veamos que pasa cuando apreto TRY
Sale el cartel de error perfectamente eso quiere decir que la protección ANTIDEBUGGER ha sido
vencida.
De cualquier manera esto no es lo que se hace habitualmente para vencer esta protección, simplemente
copiando el ejecutable OLLYDBG.exe a otra carpeta y cambiándole el nombre por ejemplo a
PIRULO.exe y volviéndolo a su carpeta original, de forma que queden ambos el OLLYDBG.exe original
y el PIRULO.exe y usando este ultimo, el programa al comparar nunca encontrara el nombre de ningún
proceso llamado OLLYDBG, ya que ahora se llamara proceso PIRULO y con eso es vencida esta
protección completamente, de cualquier forma creo que es bueno que sepan como funciona por eso la
explicación.
Es importante recordar que aunque usemos un OLLYDBG renombrado, debemos dejar el original en la
misma carpeta si no habrá problemas con los plugins.
Hay una parte que el programa posiblemente acceda cuando colocamos un serial bueno, que llama a
nuevas apis para una detección diferente, dicha detección la veremos en próximas partes detalladamente.
Hasta la próxima parte 21
Ricardo Narvaja
24 de diciembre de 2005
FELIZ NAVIDAD