lunes, 5 de marzo de 2012

Introducción a la ingeniería inversa x86 (Parte V)

Hoy, para finalizar la serie de entregas de introducción a la ingeniería inversa realizaremos un sencillo ejercicio o crackme, en el cual podremos aplicar los conocimientos adquiridos en las anteriores entregas y así poder resolver el ejercicio.

Os dejo las cuatro entradas anteriores de la serie por si queréis repasarlas:

- Introducción a la ingeniería inversa x86 (Parte I)
- Introducción a la ingeniería inversa x86 (Parte II)
- Introducción a la ingeniería inversa x86 (Parte III)
- Introducción a la ingeniería inversa x86 (Parte IV)

El fichero que pretendemos analizar se encuentra disponible en las siguiente url: Ejercicio ingeniería inversa

MD5 (fichero .exe): c12ca49829f6a340e944936ffb1f2cde
SHA1 (fichero .exe): d3f9b9a2c0e8624aae672c3e9a4f1a00e740659b

Una vez descargado el binario lo ejecutamos y visualizamos como nos pide un password de instalación, el cual mediante ingeniería inversa tendremos que averiguar. (Recalco averiguar porque obviaremos la parte de modificar el ejecutable para saltarnos la comprobación)

image

Si desensamblamos el binario nos encontrarnos dos funciones importantes (sub_4013C0 y sub_401424), que serán las encargadas de realizar los cálculos y de informar de si el password es el correcto respectivamente.

Analizaremos cada una de las funciones en busca como se genera el password, detallando las instrucciones más importantes y las que nos llevarán a solucionar el reto.

Función sub_4013C0: (Voy a dividir en dos la función para facilitar su visualización)

image

- 0x004013CE: Se almacena en la dirección [esp+31] el valor hexadecimal 64 correspondiente a la letra “d” del abecedario.
- 0x004013D3: Se almacena en la dirección [esp+24] el valor entero “5”.
- 0x004013E2: Se llama a la función printf con el texto “Installation password: “ en ESP.
- 0x004013E7: La función getchar() almacena en AL (los primero 8 bits del registro EAX) el carácter introducido por teclado. Esto ya nos da una pista de que datos se están guardando para posteriormente trabajar con ellos. En este caso se almacena el primer byte introducido por teclado, el cual se puede asociar al primer número, carácter o símbolo introducido. Por lo que si asignamos como password “hola” la función getchar() únicamente se quedará con el carácter “h”.
- 0x004013F0: Se almacena el valor introducido por teclado en AL (EAX).
- 0x004013F4: Se almacena el inicializado anteriormente “d” en DL (EDX).

image

- 0x004013F8: Se realiza la operación lógica XOR sobre EAX y EDX.
- 0x00401410: Se almacena el resultado del XOR en ESP+4
- 0x00401418: Se almacena la variable inicializada anteriormente “5” en ESP.
- 0x0040141B: Esta instrucción es la última “útil” de la función, en la cual se realiza una llamada a una nueva función, hay que tener en cuenta que en las funciones anteriores se han almacenado valores en la ESP para utilizarlos en esta función.

Hasta aquí ya sabemos que:

- Se almacena el primer byte introducido por teclado
- Se almacena el valor “d”
- Se realiza un XOR de los valores anteriores
- Se llama a la función sub_401424 pasándole el valor resultante del XOR y el valor “5”.

Función sub_401424:

image

- 0x0040142A y 0x0040142D: Se almacenan los valores pasados anteriormente en EAX y EDX.
- 0x0040141B: Sumamos EAX y EDX y lo almacenamos en EAX.
- 0x00401433: Comparamos el resultado (EAX) con el valor hexadecimal 1B, en decimal 27.
- 0x00401436: Se realiza un salto JNZ a una dirección (mensaje “sorry, try again!!”) si la comparación es falsa. Como habréis podido imaginar es justamente en esta comprobación donde nos interesa que la comparación sea cierta.

Hasta aquí sabemos:

- Los valores pasados a esta función sumados deben dar 27 para poder resolver el reto.

Con todo lo recopilado hasta ahora podemos decir que: debemos encontrar un carácter, número o símbolo que al realizar un XOR con el carácter “d” y sumándole el valor 5 el resultado sea 27.

Resumido en una fórmula:

image

Si os fijáis, es necesario trabajar en binario para poder identificar el valor correcto. Al tener un único valor al otro lado de la igualdad, es posible realizar la operación XOR entre los dos valores conocidos “22” y “d” de este modo obtendremos el valor correcto.

image

Y el valor en binario “0 1 1 1 0 0 1 0” corresponde con el valor hexadecimal 72 que a su vez corresponde a la letra “r” del abecedario, la cual será la solución a nuestro retro.

Si realizamos la prueba sobre el ejecutable conseguimos que se nos muestre el mensaje “Well Done!!”

image

Aquí finaliza la serie de entradas sobre la introducción a la ingeniería inversa en x86, seguiremos añadiendo nuevos contenidos al blog en poco tiempo.

*Os podéis descargar el código en C del reto desde el siguiente enlace: Código_C_reto

Un Saludo!!

8 comentarios:

  1. Muy guapo y bien maquetado :D

    Daleee

    ResponderEliminar
  2. Te has pegado un buen trabajo, así que me obligo a leerlo completo con calma.

    ResponderEliminar
  3. Voy a sacar el recopilatorio de las entradas en formato PDF para poder tenerlo descargado ;)

    Un Saludo.

    ResponderEliminar
  4. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  5. Me encanto :)

    No solo eso, sino que por modificando alguna parte logres hacer una bifurcación directamente a la zona buena :).

    Gracias ! :D

    ResponderEliminar
  6. Enhorabuena por los artículos, como introducción son perfectos, ahora logré entender éste mundillo tan interesante, gracias.

    ResponderEliminar