3.2 ¿Dónde se crea la ventana?
El problema es que
no sabemos a dónde queremos que el programa salte. Tenemos la pista del nombre
de la ventana “test_app”. También sabemos que seguramente debamos saltar a una
función que no sea referenciada por otra (ahí está la gracia del reto). Debemos
suponer que primero el binario deberá hacer una llamada para crear la ventana y
después otra para pintar el cuadrado (o lo que sea que sea eso).
Otra forma de
resolver el reto es ver que hacen cada una de esas tres funciones que he
mostrado antes y ver quien las está llamando. Yo opté por una mezcla de esta
última opción con la anterior.
Veamos primero la
función llamada por IDA sub_4020B0. En un bloque de la función vemos:
¡Vaya! Si tenemos
una llamada a la API “CreateWindowExA”.
Qué suerte la nuestra que hemos encontrado precisamente lo que buscábamos.
Siguiente paso es saber quien está llamando a esta función.
Veamos que trozos
del código no son referenciados por el flujo de código que estamos siguiendo
simplemente pulsando la letra “x” en IDA al principio de la función. Si nadie
referencia a esta función ya sabremos a donde debemos hacer que se produzca el
CALL EAX:
Vemos que la dirección
402012(402000+12) está haciendo un CALL a la función que crea la ventana donde
más tarde se debe pintar el susodicho cuadrado. Vayamos allí a ver que vemos:
¡Perfecto! Parece
que está llamando a nuestra función create_window (así la he llamado yo pero es
la antigua sub_4020B0) y en caso de que la respuesta de la misma sea 0 (error)
nos mostrará un mensaje con el texto “error”.
Veamos ahora si
alguna parte del código está llamando a la dirección 402000.
¡Ya tenemos nuestra
dirección deseada del CALL para crear la ventana!
Otra forma de encontrar la función “huérfana” a la que debemos saltar es abrir la vista de IDA que pinta el “CALL flow” del programa (Ctrl+F12):
Como podemos ver todas las funciones son referenciadas excepto dos de ellas: sub_4022E0 y sub_402000. Si recordamos del
punto 3.1, el programa cogía los 4 primeros bytes del fichero “key.txt” y los
sumaba al valor 7A40B660.
Por tanto: X+7A40B660=402000
=> X=402000-7A40B660. Usamos la misma calculadora de Windows para calcular
nuestra X y obtenemos: 85FF69A0. Estos deberán ser los primeros 4 bytes del
fichero “key.txt”. Recordemos que estamos bajo una arquitectura Little Endian
por lo que el orden de los bytes es de derecha a izquierda (inverso a la
escritura occidental) y por tanto los cuatro primeros bytes serán: A069FF85.
Debugueamos la
aplicación con IDA y vemos como el CALL EAX se produce con el valor de
EAX=402000 y podemos observar como se ha creado una nueva ventana con el nombre
“test_app”. ¡Perfecto!
3.3 Pintar el cuadrado
Ahora solo nos
falta que se pinte el cuadrado en la ventana creada. Para ello deberemos de
saltar en algún momento a alguna parte del código que se encargue de pintar
dicho cuadrado. Intentemos identificar las opciones que tenemos para saltar a
una zona que nosotros queramos como hicimos anteriormente:
Como vemos solo
tenemos dos opciones que a priori no parecen muy prometedoras:
- CALL [EBP+4]: En ningún momento llegamos a controlar EBP por lo que no podemos contar con ello para dirigir el flujo de ejecución a donde queramos.
- JMP loc_402360: En principio parece que la dirección a la que salta es estática y no depende de ningún registro (y lo es), sin embargo si nos fijamos en las instrucciones desde el CALL EAX hasta el PUSH previo al siguiente CALL podemos observar lo siguiente:
Vemos que tenemos el control de EDI y que en EDI se escriben ciertos
bytes de los cuales también tenemos nosotros el control. Por tanto, lo que
podemos hacer es modificar a donde debe el JMP pegar el salto para hacer que
ese salto sea al trozo de código que se encargue de pintar el cuadrado y solucionar
el reto. Por tantoEntonces
deberemos hacer que se modifiquen los bytes de la dirección del JMP (4010BD).
Del byte 4 al byte
8 (Teniendo en cuenta que el primer byte es el 0) de nuestro “key.txt” es
sumado a “0D1BE0114C” y almacenado en EDI. Luego el byte 8 del fichero es
almacenado en BL. Por último del byte 9 al 13 del fichero se mueven a EAX.
Los siguientes dos
MOV modificarán la zona de memoria a donde apunta EDI (y que nosotros
controlamos):
- El primer MOV mueve a donde apunte EDI el byte octavo de nuestro “key.txt”.
- El segundo MOV mueve EAX (los bytes de “key.txt” de la posición 9 a la 13) a donde apunte EDI+1.
Como queremos
modificar la zona de memoria del JMP (4010BD) tendremos que hacer que esta sea
igual a la suma de “0D1BE014C” (harcodeado por el programador) con los bytes
del 4º al 8º de nuestro “key.txt. Por tanto:
0D1BE014C + X =
4110BD => X = 2E830F71 (710F831E en Little Endian).
3.4 Dónde saltar para pintar el cuadrado
¡Perfecto! Ahora
que podemos modificar a donde salta el JMP solo nos queda saber a qué dirección
queremos que dé el salto. Debemos hacer que salte a alguna zona de código que
se encargue de pintar el cuadrado en la ventana que ya hemos creado.
Para encontrar
dicha zona echemos un vistazo a las otras dos funciones que nos enseñaba IDA
(sub_402040 y sub_4023A0):
- sub_402040: Parece que lo que hace es eliminar la ventana creada por lo que no debe ser la encargada de pintar el cuadrado.
Además si vemos que partes de código la llaman nos encontramos con que se llama justo antes de mostrar un mensaje con el string “error”.
Por esta información podemos decir que esta llamada es el destructor de la ventana.
- sub_4023A0: Solamente viendo las APIs que está utilizando podemos darnos cuenta de que está función se encarga de crear una figura geométrica a la cual le establece ciertos colores:
Veamos quien llama
a esta función:
Vemos que la
dirección 402324 está llamando a dicha función. Si miramos por encima la
estructura del código anterior y posterior veremos que es un bucle:
Podemos ver
(resaltado en naranja) como se almacena en EDI, EBP y EBX las direcciones de
tres funciones (“PeekMessageA”, “DispatchMessageA” y “SwapBuffers”) que más
tarde son usadas en el bucle y también la
típica estructura de prólogo de una función reservando 28 bytes (1Ch) de
espacio en la pila: SUB ESP,1Ch.
Yo cree una función
en la dirección 4022FC en IDA presionando la letra “P” para poder verlo
gráficamente más fácilmente:
Como podemos ver
ninguna parte del código accede a este bucle (que
pinta el dichoso cuadrado en la ventana) y por
tanto, debemos hacer que nuestro flujo de
instrucciones salte a la dirección 4022E0.
Ya tenemos donde
queremos saltar para pintar el cuadrado.
1 comments :
Disculpad la errata, ¡gracias por la aclaración Nacho!
Publicar un comentario