Ir al contenido principal

Reversing(XII): Solución Reto Yoire "04_crackme_hard"

En este post la solución a otro de los retos de 'reversing' de la plataforma Yoire.

Este reto tiene el título "04_crackme_hard" y mi valoración sobre su dificultad es:  ☆☆.

Su enunciado dice lo siguiente:

Descarga y analiza el ejecutable (PE) suministrado, e indica la solución en el recuadro de texto mostrado más abajo.

Y nos dan un archivo ejecutable (04_crackme_hard.exe).

Solución: Abro el archivo en OllyDbg. Lo ejecuto en modo depuración y aparece el siguiente mensaje:
El programa detecta que se está ejecutando desde un depurador ('debugger') y muestra esta ventana con objeto de evitar el análisis.

Intento averiguar qué técnica 'anti-debugging' está utilizando para ver si puedo evitar esa protección. Para ello, reinicio la ejecución en modo depuración y busco todas las llamadas con destino fuera del módulo actual realizadas en el programa (en la parte superior izquierda de la ventana principal: clic botón derecho, 'Search for' > 'All intermodular calls'):
Y obtengo lo siguiente:
En la figura anterior se ve la llamada a la función IsDebuggerPresent, una función de la librería Kernel32.dll que devuelve un valor distinto de 0 si el programa está siendo 'debuggeado' y 0 en caso contrario.

Se trata de una técnica 'anti-debugging' muy fácil de implementar, ya que basta con realizar la llamada a la función y comprobar el valor que devuelve, pero también es muy fácil de evitar.

Hago doble clic sobre esa llamada y voy a la parte del código donde se encuentra:
Como se observa en la figura anterior, justo después de la llamada a esta función, se comprueba el valor del registro EAX y si éste es cero (el programa no está siendo 'debuggeado') se produce un salto a la dirección 0x40102D

Pongo un punto de interrupción en la instrucción de salto condicional (JZ) y ejecuto el programa en modo depuración:
Como se observa en las figuras anteriores, el valor de EAX es diferente de cero (el programa está siendo 'debuggeado') y, por tanto, no se producirá el salto y el programa continuará para mostrar la ventana en la que se indica que se aborta la ejecución.

Para saltarnos esta protección simplemente cambiamos la instrucción JZ por su contraria (JNZ):
Y como se ve en la figura anterior, ahora el salto se produce y el programa se comportará como si no estuviera siendo 'debuggeado', y se me pide que introduzca un número de serie. Incluyo una cadena cualquiera de caracteres y dígitos, por ejemplo: "abc123", y, tras pulsar 'Check serial', se muestra un mensaje de error:
Reinicio la ejecución en modo depuración y, como siempre suelo hacer cuando utilizo OllyDbg, empiezo el análisis buscando todas las cadenas de texto o 'strings' utilizadas en el programa (en la parte superior izquierda de la ventana principal: clic botón derecho, 'Search for' > 'All referenced strings'):
Y obtengo lo siguiente:
Como se observa en la figura anterior, entre las cadenas de texto está el mensaje de error que me ha aparecido al ejecutar el programa: "Sorry, the serial is invalid :("y también el mensaje que supuestamente aparecerá si introduzco el número de serie correcto"Your serial is valid :)". Si hago doble clic sobre este último voy a la parte del código donde se encuentra esta cadena de texto:
Como se ve en la figura anterior, hay 11 comparaciones de caracteres predeterminados con el contenido de ciertos Bytes de memoria en los que se incluyen los caracteres que se introducen como número de serie. Por tanto, el número de serie correcto tiene 11 caracteres de longitud.

Tras cada una de las comparaciones, si los dos caracteres son iguales se continuará con la siguiente comparación, mientras que si son distintos se produce un salto a la dirección 0x00401204 y el programa mostrará el mensaje de error. Si los caracteres en todas las comparaciones son iguales se mostrará el mensaje de éxito.

Para verlo exactamente pongo un punto de interrupción en la primera comparación de caracteres. Ejecuto el programa en modo depuración, me salto la protección 'anti-debugging' como ya he explicado anteriormente, introduzco como número de serie "123456789ab" y el programa se parará en el punto de interrupción que he puesto en la primera comparación. Voy ejecutando una detrás de otra (tras cada una de ellas si los dos caracteres comparados son distintos habrá que cambiar la instrucción JNE que le sigue por su contraria - JE -, para que se continúe con la siguiente comparación) y veo lo siguiente (el primer carácter que se indica es fijo, mientras que el segundo se corresponde con el valor de un Byte de memoria que contiene uno de los caracteres introducidos como número de serie):

- En la primera comparación se compara 'b' (código ASCII 62 en hexadecimal) con 'a' (código ASCII 61 en hexadecimal). El carácter 'a' es el que ocupa la posición 10 entre los caracteres introducidos como número de serie, por lo que 'b' es el décimo carácter del número de serie correcto.

- En la segunda comparación se compara 'y' (código ASCII 79 en hexadecimal) con '8' (código ASCII 38 en hexadecimal). El carácter '8' es el que ocupa la posición 8 entre los caracteres introducidos como número de serie, por lo que 'y' es el octavo carácter del número de serie correcto.

- En la tercera comparación se compara 'l' (código ASCII 6C en hexadecimal) con '6' (código ASCII 36 en hexadecimal). El carácter '6' es el que ocupa la posición 6 entre los caracteres introducidos como número de serie, por lo que 'l' es el sexto carácter del número de serie correcto.

- En la cuarta comparación se compara 'e' (código ASCII 65 en hexadecimal) con '4' (código ASCII 34 en hexadecimal). El carácter '4' es el que ocupa la posición 4 entre los caracteres introducidos como número de serie, por lo que 'e' es el cuarto carácter del número de serie correcto.

- En la quinta comparación se compara 'i' (código ASCII 69 en hexadecimal) con '2' (código ASCII 32 en hexadecimal). El carácter '2' es el que ocupa la posición 2 entre los caracteres introducidos como número de serie, por lo que 'i' es el segundo carácter del número de serie correcto.

- En la sexta comparación se compara 'l' (código ASCII 6C en hexadecimal) con '1' (código ASCII 31 en hexadecimal). El carácter '1' es el que ocupa la posición 1 entre los caracteres introducidos como número de serie, por lo que 'l' es el primer carácter del número de serie correcto.

- En la séptima comparación se compara 'k' (código ASCII 6B en hexadecimal) con '3' (código ASCII 33 en hexadecimal). El carácter '3' es el que ocupa la posición 3 entre los caracteres introducidos como número de serie, por lo que 'k' es el tercer carácter del número de serie correcto.

- En la octava comparación se compara 'o' (código ASCII 6F en hexadecimal) con '5' (código ASCII 35 en hexadecimal). El carácter '5' es el que ocupa la posición 5 entre los caracteres introducidos como número de serie, por lo que 'o' es el quinto carácter del número de serie correcto.

- En la novena comparación se compara 'l' (código ASCII 6C en hexadecimal) con '7' (código ASCII 37 en hexadecimal). El carácter '7' es el que ocupa la posición 7 entre los caracteres introducidos como número de serie, por lo que 'l' es el séptimo carácter del número de serie correcto.

- En la décima comparación se compara 'd' (código ASCII 64 en hexadecimal) con '9' (código ASCII 39 en hexadecimal). El carácter '9' es el que ocupa la posición 9 entre los caracteres introducidos como número de serie, por lo que 'd' es el noveno carácter del número de serie correcto.

- En la undécima comparación se compara 'g' (código ASCII 67 en hexadecimal) con 'b' (código ASCII 62 en hexadecimal). El carácter 'b' es el que ocupa la posición 11 entre los caracteres introducidos como número de serie, por lo que 'g' es el undécimo carácter del número de serie correcto.

Por tanto, el número de serie correctos es: "likeollydbg".

Para comprobar si lo he hecho bien ejecuto el programa e introduzco "likeollydbg" como número de serie:
Pulso 'Check serial' y se muestra el mensaje de éxito:
Y lo único que me falta para superar este reto es introducir el número de serie correcto en la plataforma:

Comentarios

Entradas populares de este blog

Criptografía (I): cifrado Vigenère y criptoanálisis Kasiski

Hace unos días mi amigo Iñaki Regidor ( @Inaki_Regidor ), a quien dedico esta entrada :), compartió en las redes sociales un post titulado "Criptografía: el arte de esconder mensajes"  publicado en uno de los blogs de EiTB . En ese post se explican ciertos métodos clásicos para cifrar mensajes , entre ellos el cifrado de Vigenère , y , al final del mismo, se propone un reto consistente en descifrar un mensaje , lo que me ha animado a escribir este post sobre el método Kasiski  para atacar un cifrado polialfabético ( conociendo la clave descifrar el mensaje es muy fácil, pero lo que contaré en este post es la forma de hacerlo sin saberla ). El mensaje a descifrar es el siguiente: LNUDVMUYRMUDVLLPXAFZUEFAIOVWVMUOVMUEVMUEZCUDVSYWCIVCFGUCUNYCGALLGRCYTIJTRNNPJQOPJEMZITYLIAYYKRYEFDUDCAMAVRMZEAMBLEXPJCCQIEHPJTYXVNMLAEZTIMUOFRUFC Como ya he dicho el método de Vigenère es un sistema de sustitución polialfabético , lo que significa que, al contrario que en un sistema de

Criptografía (XXIII): cifrado de Hill (I)

En este post me propongo explicar de forma comprensible lo que he entendido sobre el cifrado de Hill , propuesto por el matemático Lester S. Hill , en 1929, y que se basa en emplear una matriz como clave  para cifrar un texto en claro y su inversa para descifrar el criptograma correspondiente . Hay tres cosas que me gustan de la criptografía clásica, además de que considero que ésta es muy didáctica a la hora de comprender los sistemas criptográficos modernos: la primera de ellas es que me "obliga" a repasar conceptos de matemáticas aprendidos hace mucho tiempo y, desgraciadamente, olvidados también hace demasiado tiempo, y, por consiguiente, que, como dice  Dani , amigo y coautor de este blog, me "obliga" a hacer "gimnasia mental"; la segunda es que, en la mayoría de las ocasiones, pueden cifrarse y descifrase los mensajes, e incluso realizarse el criptoanálisis de los criptogramas, sin más que un simple lápiz y papel, es decir, para mi es como un pasat

¿Qué significa el emblema de la profesión informática? (I)

Todas o muchas profesiones tienen un emblema que las representa simbólicamente y en el caso de la  informática: " es el establecido en la resolución de 11 de noviembre de 1977  para las titulaciones universitarias superiores de informática, y  está constituido por una figura representando en su parte central  un  núcleo toroidal de ferrita , atravesado por  hilos de lectura,  escritura e inhibición . El núcleo está rodeado por  dos ramas : una  de  laurel , como símbolo de recompensa, y la otra, de  olivo , como  símbolo de sabiduría. La  corona  será la  de la casa real  española,  y bajo el escudo se inscribirá el acrónimo de la organización. ". Veamos los diferentes elementos tomando como ejemplo el emblema del COIIE/EIIEO (Colegio Oficial de Ingenieros en Informática del País Vasco/ Euskadiko Informatikako Ingeniarien Elkargo Ofiziala ) . Pero no sólo el COIIE/EIIEO adopta el emblema establecido en dicha resolución, sino que éste se adopta también como im