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:
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 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
Publicar un comentario