and the Immortal Descendants present
an UPX unpacker tutorial


 
 

Prologo:
Acid_Burn me envio un archivo que se empaqueto con UPX , no recuerdo ahora la version correcta,era un tema muy interesante y al principio no era capaz de desempacarlo. Algunos dias despues localice una nueva version de UPX 0.82 la descargue y estudie los Doc. Encontre que es una beta y podria tener aun algunos bugs , tengo que admitir que no encontre ningun comportamiento extraño en el programa. Para entender mejor el programa he codificado mi propio Programa- Test el cual consiste solo en un MessageBox (explicado mas abajo).Entonces ejecuto upx sobre el y comienzo a debuggearlo y en este punto comienza el tute (Tambien he incluido el fuente,je,je)

tutorial:
La primera cuestion es... que necesito para seguir este tute? , la respuesta es la siguiente:

1. UPX version 0.82 obtenido de protools.cbj.net

2. Hview

3. SoftIce por supuesto

4. ProcDump o cualquier otro volcador

5. Tasm5.0 o MASM 6. Un poco de conocimiento de Asembler

 
Primera Aproximacion (Obtrener el archivo volcado/desempacado)

Primero veamos el codigo de nuestro pequeño programa-test: Este fue el codigo-fuente que use:
 
.386P
jumps
locals

Model Flat, Stdcall

extrn ExitProcess :proc
extrn MessageBoxA :proc

.Data
_cap db "upx-killer",0
_text1 db "regged!",0
_text2 db "unregistered!",0
_flag dd ?

.Code
Start:

mov [_flag],00
mov eax,[_flag]
cmp eax, 00000000
jnz _reg

push 0
push offset _cap
push offset _text2
push 0
call MessageBoxA
jmp _exit
 

_reg:
push 0
push offset _cap
push offset _text1
push 0
call MessageBoxA

_exit:
Call ExitProcess

End Start

 

Salva el archivo(yo use upx1.asm) y compilalo con la ayuda de un Batch
 
tasm32 /mx /m3 /z /q upx1
tlink32 -x /Tpe /aa /c upx1,upx1,, import32.lib
del *.obj
del *.map

Ahora deberias tener un ejecutable PE. Usa procdump para cambiar las caracteristicas de la seccion a E0000060 ( aplicalo a las tres secciones UPX0,UPX1 y UPX2 para asegurar)Lo que significa que el archivo es un ejecutable y contiene codigo y datos,si no lo haces el simbol loader no saltara. ahora usa el loader y tracea el archivo ,veras que es pequeño. Es el momento de correr Upx sobre el y empacarlo por completo usa estos parametros: upx.exe -7 upx1.exe Upx envolvera tu archivo como un virus. Carga tu archivo en el simbol-loader y una vez a F-10 podras ver el siguiente codigo:

 
:004050A0 60                                   pushad
:004050A1 BE00504000                  mov esi, 00405000
:004050A6 8DBE00C0FFFF            lea edi, dword ptr [esi+FFFFC000]
:004050AC 57                                  push edi
:004050AD 83CDFF                        or ebp, FFFFFFFF
:004050B0 EB10                              jmp 004050C2

Podemos ver lo siguiente: pushad empuja todos los registros a la pila , el siguiente mueve 00405000 (el cual es el punto de entrada -80h) a ESI , asi que clase de codigo esta entre 00405000 y 00405080 ? He buscado en el hexeditor y encontrado que contiene la tabla de importacion y los strings usados en mi prog (upx1).de momento no necesitamos esto. 000405000+FFFFC000 = 00401000 Este es el Dword movido a EDI , si has investigado tu prog (como te dije antes) deberias ver que este es el punto de entrada original del archivo y tambien la localizacion de memoria donde la rutina desempacadora comienza a escribir nuestro empacado (desempacado) codigo.Asi el salto solo sobrepasa algunos NOP´s y entra en la rutina de desempacado.Lo siguiente que a menudo hago es buscar la rutina desempacadora y como desempaca mi codigo (no se por que , no me culpes) Bpm 00401000 es el breakpoint correcto , tras pulsar F-5 entraras en un loop (en realidad es un subloop) el loop de desempacado.Con la ventana de datos activa puedes seguir como el codigo es desempacado y escrito en memoria mientras vas pulsando F-10 , como te dije estas en un subloop lo que tomara un buen rato hasta salir de estos loops (Hasta 7 min.) Te dire que la siguiente instruccion importante es: 004051B4 lea eax,[esi+eax+00005000] Carga la tabla de importacion en EAX. Ahora estamos a punto de entrar en nuestro programa desempacado se cuidadoso y paso a paso F-10 hasta 0040521D Sabes que es esto? jmp 00401000 (si tu codigo es diferente al mio busca el salto al rededor de 0040521D) Ahora tenemos que provocar un loop infinito para volcar el programa , entonces pon en el Ice

a eip (enter)

jmp eip (enter)

y otra vez (enter)

Ok , ahora salimos del Sice (el programa permanece en un loop infinito en memoria) Abrimos Procdump en la ventana de tareas encontramos upx1.exe , clik boton derecho y seleccionamos dump(full) , Ahora abrimos el nuevo archivo volcado con PE-Editor y cambiamos el punto de entrada a 00001000 ,Listo para correr , pruebalo. Ahora puedes parchearlo , no deberia ser muy dificil , si no eres capaz no puedo imaginar que es lo que has entendido de lo que he explicado hasta ahora...
 
 
Segunda Aproximacion (Insertar nuestro codigo en el archivo empacado)

Creo que seria mejor explicar primero la teoria,He de decir que esta parte del tute no es para principiantes , Que es la redireccion del codigo? Para mi y para muchos en la escena de la redireccion del codigo significa insertar nuestro propio codigo en la rutina desempacada de forma que el programa ejecute nuestro codigo y que este parchee el exe.He de admitir que lo he hecho un poco mas complicado Primero necesitaremos algo de espacio para insertar nuestro codigo , asi que abrimos el archivo con el hexeditor y buscamos un trozo de codigo con muchos ceros (00 00 00 00 00 00) Para mi , un buen sitio esta en 00405230 (lleno de ceros) , lo siguiente es redirigir el codigo de la rutina desempacadora para que salte a nuestro codigo insertado en 00405230.

Explicacion:

Queremos que la rutina desempacadora primero desempaque el archivo y luego salte a nuestro codigo y parchee el archivo en memoria. Cometi una equivocacion la cual hace la cosa un poco mas complicada pero pienso que asi ejercitamos mas el cerebro.la equivocacion ocurrio mientras usaba el Hview y buscaba el punto de entrada real del prog. en 0040521D.Hview no muestra jmp 00401000 (punto de entrada real) Creo que la rutina desmpacadora calcula el punto de entrada real y sobreescribe 0040521D (espero que me sigas) Por lo tanto no deberia tener sentido cambiar 0040521D jmp 004FFBC0 (esto es lo que muestra hview) a jmp 00405230 ya que sera sobreescrito de todas formas.por lo tanto busque un sitio para fijar el salto y encontre lo siguiente:
 
:004050A0 60                                   pushad
:004050A1 BE00504000                  mov esi, 00405000
:004050A6 8DBE00C0FFFF            lea edi, dword ptr [esi+FFFFC000]
:004050AC 57                                  push edi
:004050AD 83CDFF                        or ebp, FFFFFFFF
:004050B0 EB10                              jmp 004050C2 -->here

Recuerdas este salto? Tambien lo encontre con hview y por lo tanto lo cambie a: jmp 00405230 Alguien podria gritar ahora ya que esto cambiaria el codigo siguiente pero UPX tiene una agradable caracteristica, despues ese salto sera un puñado de NOP´s . para facilitar el cambio de opcodes jmp 00405230 es E9 BF B1 BF FF Aplica estos cambios con la ayuda de hview.Mediante este codigo se llega a 004050B0 y sesalta a 00405230 Si , estas en lo cierto aqui no hay nada (de momento) solo algun mov[eax],al... lo que señala a nuestros 00 00 00 00´s Lo siguiente que hemos de cambiar es 0040521D jmp 00401000 por jmp 00405260 Preguntas por que? Bien , despues de desempacar debe saltar al punto de entrada real pero tenemos que correr primero nuestro parche por lo tanto no saltaremos a 00401000 sino a 00405260 (donde hemos añadido nuestro parche) cambiando el salto por jmp 00405260 cuyo opcode seria EB 41 Pero en 00405260 hay algo como EB 43 FF 32 BC lo cual parchearemos con EB 41 00 00 00 para sobreescribirlo totalmente. En Asm la rutina que sobreescribe seria como sigue:
 
00405230 66C7051D524000EB41     mov word ptr[0040521d], 41EB
00405239 66C7051F5240000000       mov word ptr[0040521f],  0000
00405242 C6052152400000                mov byte ptr[00405221], 00
00405249 E974FEFFFF                      jmp 004050C2

Ok espero que entiendas las tres primeras lineas (recuerda el orden inverso de la primera linea) Esto parchea el jmp00401000 por jmp 00405260 La ultima linea salta a 00405242 , mirando un poco mas arriba de la tabla amarilla 00405242 es el comienzo de la rutina desempacadora.
Sumario de todo lo hecho: Parcheamos un salto de jmp 00405242 a jmp 00405230

Insertamos nuestro codigo el cual parchea el prog. real de 00401000 a 00405260 Imagina el programa corriendo.. salta a nuestra primera rutina parchea el salto , vuelve a saltar a la rutina desempacadora y finalmente alcanza el salto en 0040521D saltando a 00405260

Ahora añadimos la segunda rutina que parchea el programa en memoria Vamos a 00405260 insertando:

 
00405260 C6051210400074       mov byte ptr[00401012],74
00405267 E974FEFFFF              jmp 00401000

La primera linea parchea el jnz por jz y la segunda salta al real prog. Ahora tienes un ejecutable empacado/desempacado pero este es el punto en que tienes el archivo parcheado Tras haberlo hecho temporalmente con Sice toma los opcodes marcados en azul e insertalos con la ayuda de Hview. Ahora seran permanentes.

Agradecimientos:

Volatility
Lord Soth
Lucifer 48
Tornado
Acid_Burn
Risc
Pain
ytc_
LaZaRuS
RevX
knotty
    Warezpup
...........and all i forgot :( sorry

 





www.000webhost.com