Análisis packer 01 - parte VII

Tamaño de letra:

Primer error en el dumpeado

Después de todo este trabajo que hemos hecho hasta ahora, parecía que lo siguiente sería reparar código ofuscado y emulado en una máquina virtual y que sería sencillo, sin embargo, después de crear el dumpeado  (dumpe_05.exe) con todo reparado, lo voy a intentar ejecutar en un debugger. Así que lo cargo en OllyDBG, pulso F9 y me encuentro con el siguiente error:

OllyDBG error al leer dirección

En un primer momento puede parecer sencillo, pero no lo es tanto. Se produce porque en el dumpeado no existe la dirección 16DF08, la puedes crear y solucionas el problema pero a mi siempre me gusta analizar todo bien y mi intención es saber por qué se produce eso y después ya resolveremos el problema.

En este momento analicé detenidamente el packer, el dumpeado y busqué programas en Delphi 7 para comparar. Es muy curioso porque el código da por hecho que en 16DF08 hay "algo", no se ve ningún je que salte... Después de mucho analizar encontré cómo se inicializa esa dirección en el programa protegido y se inicializa con el siguiente código pero como verás no se ejecuta nunca en el dumpeado:

OllyDBG inicializa dirección 16DF08

Es muy sencillo y observa que la dirección 16DF08 se obtiene de LocalAlloc y reserva 0FF8 bytes. Bien ¿Y por qué en el dumpeado el código no pasa por aquí para reservar esa memoria? Curiosamente el packer ejecuta esa parte de código antes de llegar al OEP. Has oído bien, el packer ejecuta parte de código antes del OEP, por eso el dumpeado nos indica direcciones como 16DF08 que no existen. La subrutina por la que pasa antes del OEP es esta:

00729AF8    55                push ebp
00729AF9    8BEC              mov ebp,esp
00729AFB    33C9              xor ecx,ecx
00729AFD    51                push ecx
00729AFE    51                push ecx
00729AFF    51                push ecx
00729B00    51                push ecx
00729B01    51                push ecx
...

Traceo un poco y llego hasta aquí (parado en el color verde):

00402EA0 >/$  53              push ebx
00402EA1  |.  51              push ecx
00402EA2  |.  8BD8            mov ebx,eax
00402EA4  |.  85DB            test ebx,ebx
00402EA6  |.  7E 1A           jle short 00402EC2              ; <loc_402EC2>
00402EA8  |.  8BC3            mov eax,ebx
00402EAA  |.  FF15 44D07400   call near dword ptr ds:[74D044] ; <System::SysGetMem(int)>

La call [74D044] es la que nos reserva la memoria. Fíjate en el dump ahí parado:

00766624  00000000

Y ahora pulso F8 para pasar la call [74D044]:

00766624  0016DF08

Como LocalAlloc se ha ejecutado satisfactoriamente, pone (algo normal) un uno en memoria:

00401D90   .  C605 C4657600 0>    mov byte ptr ds:[7665C4],1

 

00729AF8 en la INIT TABLE

Como podrás pensar, mi intención es ver por qué no puedo ejecutar la subrutina 00729AF8. Analizando esta subrutina, observo que es posible acceder a ella únicamente desde la INIT TABLE. Mira:

00729F20   .  832D 50C27600>  sub dword ptr ds:[76C250],1
00729F27   .  0F83 83000000   jnb 00729FB0       ; <locret_729FB0>
00729F2D   .  B8 749C7200     mov eax,729C74
00729F32   .  E8 81B3CDFF     call 004052B8      ; <System::__linkproc__ InitWideStrings(void)>
00729F37   .  E8 BCFBFFFF     call 00729AF8      ; <sub_729AF8>

Por aquí pasa tanto el programa protegido como el dumpeado pero se ejecuta después, es decir, que no tiene nada que ver.

 

Conclusiones de todo esto

Resumiendo de forma sencilla:

  • El packer reserva en memoria 0FF8 bytes en 16DF08 y lo hace antes del OEP.
  • Una vez reservada pone un 1 en [7665C4]. Típico cuando se usa LocalAlloc para usar posteriormente LocalFree

Por eso el dumpeado da ese error, porque no tiene memoria reservada. Ahora ya se entiende. Pero la pregunta que nos hacemos es:

¿Por qué el packer ejecuta ese código antes del OEP? -Sinceramente después de darle muchísimas vueltas, no lo tengo del todo claro. No creo que sea TLS en el original. Además puedes reservar esa memoria y el programa funciona, también puedes poner todo a cero y el programa también funciona... He estado tiempo analizando este tema y no he encontrado ninguna explicación clara, yo creo que es una protección más del packer.

 

Resolviendo el problema

Se te pueden ocurrir muchas soluciones:

  • Esta quizá sea la más plausible: intentar ejecutar la subrutina 00729AF8 directamente antes del OEP como hace el packer. Yo lo intenté pero empezaron a saltar excepciones y posiblemente por pereza, pasé al siguiente punto.
  • La solución más fácil para mi es crear con Add PE bytes 0FF8 bytes y cambiar la dirección 16DF08 por la de Add PE bytes, después copias los bytes y verás que la excepción se repara aunque no pueda después liberar esa zona de memoria con LocalFree.
  • Para solucionar el punto anterior puedes insertar código reservando memoria con LocalAlloc tal cual lo hace el programa y que te he puesto en una imagen anterior y después pegar ahí los 0FF8 bytes.
  • También puedes pensar resetear el byte [7665C4] para "decirle" que no hay memoria reservada y el programa se ejecuta correctamente pero como sabrás, no existirán esos 0FF8 bytes que tal vez puedan ser necesarios.

De estos modos se resuelve esta excepción y tras analizar el código parece que todo está correcto así que puedo continuar.... aunque la verdad: Me he quedado muy sorprendido de la ejecución de este código antes del OEP... Gran packer y difícil. A partir de aquí saltan excepciones pero que ya podíamos preveer. En el siguiente tutorial veremos cómo reparar de forma genérica las siguientes excepciones que ocurren.

Última actualización: Sábado, 27 Agosto 2011

No tiene privilegios para responder a los comentarios.


 
Visitas: 8567612