Desempacar PeiD 0.95 (Parte III)
Curioso error
El error, mejor dicho la ventana de error que nos apareció en el anterior artículo puede despistar bastante y nos induce a pensar que el dumpeado que hemos realizado no es correcto. Como dije al principio, el mismo UPX ya nos avisó que el programa había sido modificado tras su compresión, por lo tanto, el error no me llama excesivamente la atención, era de esperar.
¿Por qué aparece?
Como vimos, si ejecutas dump_.exe y seleccionas una opción que pone Entropy o alguna otra, verás que salta esta ventana:
Vamos a intentar ver por qué aparece. La explicación será un poco más ligera que las anteriores. Si has seguido los otros dos tutoriales es posible que tengas programas abiertos, así que cierra todos. Carga dump_.exe en OllyDBG 2 y ejecútalo pulsando en OllyDBG F9. Llega al error de la ventana anterior y pulsa pause (F12). Ahora vamos a centrarnos en la pila, y observa los retornos a dump_.exe. Yo me fijo en la pila en esta zona:
...
0012EA78 0012ED28
0012EA7C 00479816 ; RETURN from dump_.00476861 to dump_.00479816
0012EA80 00000002
0012EA84 0047598F ; RETURN to dump_.0047598F
0012EA88 0012EAB0
0012EA8C 0012EB1C
...
¿Y por qué me fijo en ese retorno a 0047598F? Pues porque ya he probado otros. Voy a esa dirección en la ventana de desensamblado y observo este código:
...
0047598D call eax
0047598F mov edi,dword ptr ss:[ebp-210]
...
Como puedes ver hay una call eax que es la que nos ha enviado al mensaje de error. Voy a hacer una cosa: voy a parar ahí (en 0047598D) con dump_.exe y después con peid.exe y voy a ver el valor de eax en cada uno de ellos. Hago esto comentado y observo que en:
- dump_.exe el valor de eax = 0047980F
- peid.exe el valor de eax = 00472B2B
¿Curioso verdad? Pues aquí está el problema, ya tenemos por dónde "meter mano". Observa en el código que he puesto, voy a añadir dos lineas más de código y verás una call interesante:
...
00475981 push dword ptr ds:[40A7F0]
00475987 call 0046FFAB
0047598C pop ecx
0047598D call eax
...
Si entras en ese call 0046FFAB comprobarás que la dirección mala (0047980F) se forma tras una función "DecodePointer" pero lo que quiero que aprecies es que el valor que se le pasa a esa función, es este: 00475981 push dword ptr ds:[40A7F0]. Mira el código antes de este párrafo para que lo entiendas. Con esto vemos que el problema está en quién pone el valor en [40A7F0].
Por esto explicado, pongo un Hardware Breakpoint on write dword en [40A7F0] y reinicio OllyDBG 2. Pulso F9 y la primera vez se detiene aquí:
...
00472BEC pop ecx
00472BED mov dword ptr ds:[esi],eax
00472BEF cmp edi,28
00472BF2 jb short 00472BDC
00472BF4 pop edi
00472BF5 pop esi
00472BF6 retn
Llego traceando hasta el retn y veo el código donde estoy ahora después del retorno es este:
...
0047692E push 004398FC
00476933 call 004765A0
00476938 pop ecx
00476939 test eax,eax
0047693B je short 00476947
0047693D push dword ptr ss:[ebp+8]
00476940 call dword ptr ds:[4398FC]
00476946 pop ecx
00476947 call 00472BD6
0047694C push 00408424
...
Aquí está todo el quid de la cuestión. Si analizas el programa original y dump_.exe podrás ver que todo el problema viene porque el original en el je no salta mientras que el desempacado sí salta. Lo que ocurre es que en el desempacado no se ejecuta 00476940 call dword ptr ds:[4398FC] y este es el problema. Esta última call es la que rellena correctamente las direcciones correctas de determinadas rutinas. Examina tú mismo lo que hace esa call y dentro de esa la primera call y verás lo que digo.
Bueno, y ¿por qué en el desempacado el je salta? El salto se produce por una comparación de eax (00476939 test eax,eax), así que tenemos que observar la call anterior al salto: 00476933 call 004765A0, y comprobar el porqué del valor de eax:
Yo creo que lo he dejado todo muy bien explicado en la imagen. Es decir, todo el problema viene porque el programa obtiene el flag de la primera sección y hace tres cálculos sencillos. En el dump_.exe, si te fijas con un visor de PE en la primera sección verás esto:
Name Virtual Offset Virtual Size Raw Offset Raw Size Flags
snk0 00001000 00063000 00001000 00063000 E0000080
Como puedes ver el flag de la primera sección es E0000080, por lo tanto las operaciones:
- mov eax, dword ptr ds:[eax+24] ;eax = E0000080
- shr eax, 1F ;eax = 1
- not eax ;eax = FFFFFFFE
- and eax, 00000001 ;eax = 0
Darán como resultado eax = 0, como puedes ver en la imagen. Sin embargo, en el original el flag de la sección es 60000080. Esta es una curiosidad que suele hacer UPX, tras desempacarse bloquea la sección de código contra escritura y en este caso se ha aprovechado esta característica.
Solución
Pues tiene muy fácil solución, pero lo que no quiero que hagas es modificar el je por un jne. Tampoco puedes cambiar el flag de la sección porque si no el loader de Windows no podrá, por ejemplo, poner la IAT. En vez de cambiar el je por un jne vamos a pensar un poco más. Si en cualquier momento el programa accediera de nuevo a esa call, obtendría que otra vez eax = 0 y tendrías que volver a modificar otro posible je. Vamos a modificar el código que he encerrado en un círculo rojo en la imagen para que siempre eax sea 1. Muy sencillo, este es el código original:
... 00476607 mov eax,dword ptr ds:[eax+24] 0047660A shr eax,1F 0047660D not eax 0047660F and eax,00000001 ...
Y voy a modificarlo tal que así:
... 00476607 mov eax,dword ptr ds:[eax+24] 0047660A shr eax,1F 0047660D not eax 0047660F xor eax,eax 00476611 inc eax ...
Y ahora desde OllyDBG 2 a guardarlo: botón derecho del ratón -> Edit -> Copy to executable. Si es la primera vez te saldrá una ventana de información que debes aceptar y si quieres, tildar para que no se vuelva a mostrar en el futuro. Y en la siguiente ventana (tendrá un icono de una D) pulsas el botón derecho del ratón -> Save file. Aparecerá una nueva ventana de información. Pulsas Sí y guardar el archivo con el nombre que quieras, yo lo he llamado dump_1.exe.
Dejo el video para que aprendas a desempacarlo en directo:
Si lo ejecutas verás que ya funciona correctamente. Aunque verás que para agregarle ahora una imagen tendremos un pequeño problema que explicaré en el siguiente artículo. Veremos cómo añadir una imagen propia a PeiD 0.95.