CRACKEAR ARCHIVOS PE EMPAQUETADOS ( III )

Usando memoria virtual

por  n u M I T_o r   [ kUT ]


Target: Star Strider v1.5 (http://www.fmjsoft.com)

Tools:   SnippetCreator v1.5
             Soft Ice
             HexWorkShop
             TASM v5.0
Note: Puedes encontrar estas herramientas en: http://members.xoom.com/crk10/archivos

Author:  n u M I T_o r 


 

I n t r o

Bien amigos, seguro que alguna vez han encontrado programas fácil de desproteger pero que presentan el problema de estar empacados y no es tan fácil parcharlos. Algunos crackers han superado este obstáculo empleando parcheadores de procesos (process partchers). Recientemente, y podemos constatarlo en los fabulosos tutoriale de R!SC, otros crackers detectan con un depurador -debugger- como Soft Ice los puntos donde colocar en archivo ejecutable los parches y en un breve análisis del ejecutable mismo ubica dónde insertar un recorte -snippet- que parche el programa cuando se despliega en memoria para su ejecución. A veces esto es relativamente sencillo, pero otras veces no tanto. Yo he implementado el uso de DLLs cuando el recorte es muy grande [ver CRACKEAR ARCHIVOS PE EMPAQUETADOS ( I I )] y el tamaño es un parámetro crítico. Ahora implementaré otro método para esto que me ha parecido más sencillo y mejor porque no requiere archivos adicionales: aprovechar las APIs del manejo de memoria virtual de Windows.

¿Cuándo usar este método?

Cuando el espacio donde se ubica el recorte es limpiado y barrido por el programa en el momente que el archivo ejecutable es desempacado y no queremos usar una DLL para evitar esto.

Esta técnica consiste en escribir el recorte de código y moverlo a un lugar seguro en la misma memoria del proceso, pero lejos del área de despliegue del ejecutable. De esta manera cuando se despliegue el programa no podrá alcanzar el recorte y destruirlo. Entonces el programa pasará el control al recorte en memoria para que el recorte de código parche el programa y lo desprotega (si éste es nuestro objetivo).

 

A t A k E e e . . .   j e - j É e

Si cargamos el archivo StarStrider.exe con SoftIce e intetamos desplegar su contenido, no se disparará la ventana del depurador porque el programa está empaquetado y se han cambiado los atributos de las secciones.

A esta altura ya deberíamos tener una idea de cómo desplegar el programa de un archivo empacado en Soft Ice. Abrimos el archivo con un editor de archivos PE (ProcDump o SnippetCreator) y cambiamos las características de la sección de código. Con SnippetCreator procedemos así:

Creamos en SnippetCreator un nuevo proyecto (File/New Project) y llamémosle SS, cuyo target sería StarStrider.exe. Recabamos información sobre el encabezado del archivo (PE Info\View PE Header):

Address Entry Point: 00 06 E0 00 h

Ahora cambiamos las características de la sección de código (por lo general .text o .code). Ejecutamos PE Info\View Section Info. Vemos que el punto de entrada coincide con la dirección de inicio de la sección .aspack. Anotemos de una vez los siguientes valores de .aspack:

V. Offset:      0006E000h
Raw Offset:  00025400h

Así que hacemos click con el botón derecho del ratón sobre .text (la sección de código) y elegimos Edit Section en el menú emergente; pulsamos el botón "..." de "Characteristics", elegimos IMAGE_SCN_CNT_CODE y IMAGE_SCN_CNT_EXECUTE y pulsamos el botón "Save". Ahora en en el campo "Characteristics" aparece E0 00 00 60h.

Después de realizar esta operación con StartStrider.exe, carguémoslo con el "loader" de SoftIce y empleando F10, F9 y F5 estratégicamente busquemos el final del la rutina que desempaca el archivo:

0157:0046E5B1     50                          PUSH EAX
0157:0046E5B2     0385A8304400      ADD EAX,[EBP+004430A8]
0157:0046E5B8     5B                          POP EBX
0157:0046E5B9     0BDB                     OR EBX,EBX
0157:0046E5BB     8985E12E4400      MOV [EBP+00442EE1],EAX
0157:0046E5C1     61                          POPAD
0157:0046E5C2     7508                      JNZ 0046E5CC
0157:0046E5CC     68305E4200        
PUSH 00425E30
0157:0046E5D1     C3                          RET

Vamos a necesitar un espacio de seis bytes para la nueva instrucción, así que escogemos:

0157:0046E5BB     8985E12E4400      MOV [EBP+00442EE1],EAX

Como antes, llamamos a esta dirección RVA1: es la dirección que entrega el control a nuestro recorte parchador.

Como en otros casos que he analizado, esta instrucción también está empaquetada, así que para parcharla y reescribir en ella las instrucciones que entregan el control al recorte tenemos que esperar hasta que la instrucción misma sea desempacada porque si no, cuando la instrucción se despkliegue corroerá nuestro parche. Esto nos obliga a encontrar un punto anterior para dar el controla nuestro de código. Para esto ejecutamos en SoftIce el comando: D RVA1 = D 0046E5BB. En la ventana de datos podemos ir revisando hasta que en ella aparezca el código octal correspondiente a las instrucciones que queremos localizar.

Cargamos StarStrider.exe con el "loader" de SoftIce, ejecutamos el comando D 0046E5BB y vamos trazando el programa con la tecla F10 hasta ver en la ventana de datos:

0030:0046E5BB    2EE18589 75610044 00

Es la representación en octal en reverso y ordenada en valores dword de:

8985E12E4400      MOV [EBP+00442EE1],EAX

La instrucción que buscamos se despliega cuando se ejecuta la instrucción 0157:0046E0E7:

0157:0046E0E7     F3A4                      REPZ  MOVSB ; <-
0157:0046E0E9     8B8541294400      MOV  EAX,[EBP+00442941] ; <- VA0
0157:0046E0EF     6800800000          PUSH  00008000
0157:0046E0F4     6A00                     PUSH  00
0157:0046E0F6     50                          PUSH  EAX
0157:0046E0F7     FF9549294400     CALL [EBP+00442949]
0157:0046E0FD     8D851D2C4400   LEA  EAX,[EBP+00442C1D]
0157:0046E103     50                          PUSH  EAX
0157:0046E104     C3                         RET

Así que podemos elegir la instrucción 0046E0E9, una instrucción de seis bytes y que se realiza cuando la instrucción VA1 ya está desplegada. Llamamos a esta instrucción VA0.

Ahora tenemos que localizar un espacio para nuestro recorte de código. Podemos hacer esto con el editor hexadecimal y sin mucho tecnisismo. Abrimos StarStrider.exe con HexWorkshop y buscamos "manualmente" un espacio con gran cantidad de ceros. Hay varios, pero elegimos el espacio que comienza en el desplazamiento del archivo 00 01 DC 00 h. ¿Por qué? por intuición: a la vista parece suficiente.

Para realizar nuestro trabajo tenemos que convertir el desplazamiento en el archivo a dirección virtual. Para eso aplicamos la siguiente fórmula:

VA del recorte = (Desplazamiento del recorte - RawOffset de la Sección) + (ImageBase + VirtualOffset de la sección)

Tenemos que ubicar en qué sección está el espacio para el recorte y especificar dónde comienza esa sección.

Vemos que el recorte está entre, es decir, en la sección .rsrc, que inicia en la dirección virtual (VA) 00 04 00 00 h y cuyo desplazamiento en el archivo es 01 DC 00 h .

Aplicando la fórmula tenemos:

(00025260h - 0001DC00h) + (00400000h + 00040000h) = 00447660h

Sólo nos queda ubicar las instrucciones que necesitamos cambiar para que el programa tenga el comportamiento de un programa registrado.

Como supongo que el lector de este escrito ya debe tener cieta destreza ubicando los puntos frágiles de un programa, no explicaré como encontrarlo. Además ese no es el objeto de este escrito sino el aprender una estrategia para parchar archivos empaquetados. Así que de una vez indico que la instrucción a cambiar es:

0157:0042FBA3     51                          PUSH ECX
0157:0042FBA4     52                          PUSH EDX
0157:0042FBA5     E8D6000000         CALL 0042FC80
0157:0042FBAA     85C0                    TEST EAX,EAX
0157:0042FBAC     7540                     JNZ 0042FBEE
0157:0042FBEE     BB88080000         MOV EBX,00000888
0157:0042FBF3     8BC3                     MOV EAX,EBX
0157:0042FBF5     5B                          POP EBX
0157:0042FBF6     5E                          POP ESI
0157:0042FBF7     81C4D0000000     ADD ESP,000000D0
0157:0042FBFD     C21400                 RET 0014

Es muy simple lo que tenemos que hacer. Reemplazar la instrucción

0157:0042FBAA     85C0                 TEST EAX,EAX

por:

0157:0042FBAA     EB2B                 JMP 0042FBD7

Con esta instrucción saltamos todas las pruebas que comprueban si el programa ha sido registrado hasta la dirección 0042FBD7, que es la dirección a donde debería llegar el programa si estuviera registrado.

E l   R e c o r t e

Ahora lo decisivo: escribir el recorte. Corremos Snippet Creator y abrimos el proyecto SS que creamos al principio.

Establecemos las opciones del proyecto:

He descubierto que (aunque no sé porqué motivo) algunas acciones hechas por Snippet Creator sobre archivo PE empaquetados deterioran el archivo. Así que muchas opciones de Snippet Creator que podrían ahorrarnos trabajo no se pueden emplar cuando injertamos código nuevo en ejecutables. Así que nos conformaremos con las siguientes opciones (ejecutamos Action\Project Options para desplegar el diálogo Project Options):

Snippet VA: 477660
Patch Options: Patch Into Existing Section
Address to Redirect Control to the Snippet: No Redirection
Return Control To Program: Don't Return Control To Program

Otras opciones que no hemos podico elegir tendremos que realizarlas nosotros mismos "manualmente". No es difícil hacerlo.

Este es el recorte de código:

; ------------------------------------------------------------------------------------------------

extrn LoadLibraryA:near
extrn GetProcAddress:near

jmp numit1

l1 db 'kernel32.dll',0
f1 db 'VirtualAlloc',0
OldInstruction db 08Bh,085h,041h,029h,044h,000h
NewInstruction db 068h,000h,000h,000h,000h,0C3h

numit1:
; Restaurar antigua instrucción
pushad mov esi,offset OldInstruction
mov edi,46E0E9h
mov ecx,6
rep movsb

; Obtiene la dirección de la función VirtualAlloc en la memoria del proceso
push offset l1
call [LoadLibraryA]
push offset f1
push eax
call [GetProcAddress]

; Reservar espacio en memoria para el recorte
mov esi,(final - init)
push esi
call eax,0,esi,1000h,40h

; Mover el código a la memoria
mov edi,eax
lea esi,init
pop ecx
rep movsb

; Escribir el salto al código en memoria
mov edi,46E5BBh
lea esi,NewInstruction
mov dword ptr [esi+1],eax
mov ecx,6 rep movsb

; Regresar
popad
push 46E0E9h
ret

init:
pushad

; Restaurar instrucción original
mov edi,46E5BBh
mov dword ptr [edi],02EE18589h
mov word ptr [edi+4],0044h

; Escribir el parche
mov edi,42FBAAh
mov word ptr [edi],2BEBh

; Regresar
popad
push 46E5BBh
ret
final:

; ------------------------------------------------------------------------------------------------

Puedes ver que este código, cuando toma el control por vez primera:

    · Restaura la instrucción original en VA0 = 46E0E9h
    · Obtiene la dirección de las funciones VirtualAlloc y VirtualFree.
    · Compromete memoria física con la función VirtualAlloc.
    · Mueve el recorte de código parchador a la región de memoria comprometida.
    · Cambia la instrucción en la dirección 46E5BBh para que en una segunda ocasión devuelva una váz más el control al recorte, ahora en el área de memoria comprometida.
    · Devuelve el control al programa en la dirección VA0.

Cuando el programa vuelve a tomar el control y alcanza la dirección VA, devuelve por segunda vez el control al recorte, ahora ubicado en una región de memoria que previamente comprometimos para él. En esta segunda ocasión el código de recorte:

    · Restaura la instrucción original en VA1 = 46E5BBh
    · Parcha el proceso en VA2 = 42FBAAh
    · Retorna el control al programa.

La parte interesante del recorte es:

; --------------------------------------------------------------------------------------------------

; Obtiene la dirección de la función VirtualAlloc en la memoria del proceso
push offset l1
call [LoadLibraryA]
push offset f1
push eax
call [GetProcAddress] ; Devuelve en eax la dirección de VirtualAlloc, en este caso.

; Reservar espacio en memoria para el recorte
mov esi,(final - init) ; Tamaño del recorte
push esi
call eax,0,esi,1000h,40h .

; Mover el código a la memoria
mov edi,eax ; Dirección dónde se halla el recorte
lea esi,init     ; Dirección del recorte en el código fuente
pop ecx       ; Tamaño del recorte
rep movsb   ; Mover el recorte

; --------------------------------------------------------------------------------------------------

Este código es lo que permite no tener que usar DLLs ni loaders, y evita tener que aumentar el tamaño del ejecutable PE que estamos tratando.

Ahora ensamblamos el recorte (click sobre el botón "Assemble"), exportamos el binario y lo llamamos SS.BIN

P a t c h i n g

Abrimos una vista de nuestro target y otra del binario SS.BIN que hemos exprotado. Marcamos con el ratón toda el área correspondiente al código de nuestro binario SS.BIN y lo copiamos (CTRL+C). Luego marcamos el área del ejecutable StarStrider.exe correspondiente al espacio donde insertaremos el recorte: desde 025260h hasta 025326h y pegamos el binario que copiamos antes (CTRL+V). Repito una vez más que esta es la operación más delicada del proceso: copiar un byte de más o de menos daña por completo el archivo empacado.

Lo último que nos queda es escribir en el ejecutable StarStrider.exe la instrucción en VA0 = 46E0E9h que entregará por vez primera el control al recorte. Calculemos el desplazamiento:

Desplazamiento en el Archivo = ( VA0 - VA de la sección ) + RawOffset de la Sección

El salto está en la sección .aspack cuya (VA) es 46E000h y cuyo desplazamiento en el archivo es

( 46E0E9h - 46E000h ) +  00025400h = 254E9h

Nos movemos ahora en el editor hexadecinal (HexWorkshop) hasta 254E9h (Edit\Goto) y escribimos:

68 60 76 44 00 C3

Es el código en octal que corresponde a las instrucciones

  68 60 76 44 00    push    00447660         ; VA2
  C3                       ret

Son las instrucciones que entregan por vez primera el control al recorte.

Con esto el programa casi parecerá registrado. Sólo queda colocar nuestro nombre de usuario y la clave en la subclave correspondiente del registro de Windows. ¿Cómo encontramos esa subclave? Podemos trazarla con una trampa en Soft Ice sobre la función RegQueryValueExA o con un monitor de las llamadas al registro de Windows como Registry Monitor de Mark Rusinovich.

Yo encontré que era:

HKCU\Software\FMJ-Software\StarStrider\

Hay que crear una clave llamada "Username" cuyo dato sería una cadena con el nombre del usuario.

 

P a r a   T e r m i n a r

Bueno. Con esto termino esta serie en tres partes sobre desprotecciones de archivos PE empaquetados. Yo encuentro este último procedimiento más conveniente que el implementado con las DLLs para crackear archivos empaquetados. Pero en algunos respectos prácticos el método de las DLLs podría resultar más atractivo.

 


Gracias a Iczelion - Stone - _mammon, por sus extraordinarios conocimientos y herramientas. Trato de pagar la deuda con ellos compartiendo libremente lo que he aprendido y cada día descubro.

Comentarios y correcciones: nuMIT_or@iname.com
Mi página de programación: n u M I T_o r's   P r o g r a m m i n g   P a g e

www.000webhost.com