CRACKEAR ARCHIVOS PE EMPAQUETADOS ( I )

por  n u M I T_o r   [kUT]


Target:                  API32 v2.4

Herramientas:     Snippet Creator v1.5
                              HexWorkShop
                              SoftIce
                             TASM v5.0
Puedes conseguir estas herramientas en http://members.xoom.com/crk10/archivos
                                                            http://welcome.to/karpoff

Autor:                    n u M I T_o r     


 

I n t r o

Ya he escrito un tutorial sobre Snippet Creator donde trato el tema de quebrar protecciones en archivos ejecutables PE enpacados. Me he dado cuenta que era un escrito muy duro para principiantes y he reorganizado un material que pudiera ser seguido mejor y con más facilidad.

Sin embargo, para poder seguir este tutorial se requiere una experiencia mínima en lenguaje ensamblador orientado al sistema operativo Windows a 32 bits, conocimiento de las estrategias clásicas de desprotección de programas (las comunes), algunas nociones sobre la estructura de los archivos con formato PE. De alguna manera supongo también conocimietos sobre desempacado manual de archivos con ProcDump.

 

 

E l   C a m i n o

El método clásico de crackear archivos PE empaquetados consiste en usar un parcheador de procesos (process patcher) y hacer el parche estratégico en tiempo de ejecución. Se trata de esperar hasta que el archivo sea desempacado en la memoria para su ejecución y entonces parcharlo. Para hacer esto, tenemos que tener el manejador del proceso.

Tenemos entonces que un parchador de un proceso se puede dividir en dos partes:

      un cargador: una rutina que carga el proceso objeto generalmente en modo de depuración.

      un parchador: una rutina que intercepta el proceso, toma el control y escribe el parche en el proceso.

Yo nunca he usado este método. Uso otro, también clásico: injertar un recorte de código que tome el control del programa cuando éste se ejecuta, sobre-escriba el archivo objeto en tiempo de ejecución y haga los parches necesarios en puntos estratégicos. Estos puntos estratégicos son direcciones virtuales del proceso o desplazamientos dentro del archivo:

1. Final de la rutina que desempaca el archivo : Desplazamiento 1 - VA1 (Virtual Address 1)
    Todo archivo ejecutable necesita ser desempacado para correr. El código con que comienza el programa que contiene este archivo es un "cargador" [ loader ] que desempaca el archivo en memoria. Cuando la rutina termina, el archivo objeto es desempacado en memoria, y podemos parcharlo en este momento. Una vez alcanzado el final del "cargador" del archivo empacado, el archivo ya debería estar desempacado en la memoria, así que a partir de la dirección de las últimas instrucciones del cargador escribimos unas nuevas instrucciones que hacen que el programa pase el control a un recorte de código que hemos insertado estratégicamente dentro del archivo empacado. Este recorte parchará entonces el archivo de manera que quedan rotas las protecciones que impiden su disfrute. A la dirección dónde termina de ejecutarse el cargador del empacado la llamamos VA1.

2. Un lugar para el recorte. Desplazamiento 1 - VA2 (Virtual Address 2)
    Tenemos que especificar dónde colocaremos el recorte de código parchador que romperá la protección del programa. Este código ha de recibir el control desde el cargador que desempaca el programa cuando éste es ejecutado. Cuando el recorte se ejecuta, re-escribe algunas instrucciones que eliminan las protecciones y restaura las instrucciones que le entregaron el control para que el programa siga su curso y devuelve el control al programa. Para hacer el parche, la sección del archivo PE a parchar debe ser "escribible" (writeable), de lo contrario se producirá un error de protección. A la dirección donde colacamos el recorte la llamamos VA2.

3. La dirección de la instrucción a parchar: VA3 (Virtual Address 3)
    Todavía tenemos que romper la protección del archivo. Esto no lo podemos hacer a la manera clásica, directamente sobre los desplazamientos característicos con un editor hexadecimal porque el archivo objeto está empaquetado. Podemos localizar las instrucciones a parchar y sus direcciones con un depurador (debugger) como SoftIce y luego proceder a parchar el archivo con código que podemos introducir en un punto estratégico del ejecutable empaquetado. El problema es que generalmente los empacadores al empacar un archivo ejecutable PE, cambia las características de sus secciones, evitando que SoftIce, y otros desensambladores, se detengan en ciertos del programa. Para que SoftIce pueda revisar un programa de estos, debemos revisar las características de las secciones del archivo ejecutable para asegurarnos que las secciones de código tengan las características típicas que les convienen.

4. Escribir y ensamblar el recorte.
    Si tenemos éxito en el intento de romper la protección que nos mortifica, debemos proceder a escribir un recorte de código enensanblador (es lo más pequeño y rápido), ensamblarlo y pegarlo en el archivo objeto donde hemos establecido.

 

¿ E s  e l  c a m i n o ?

A veces encontramos que las instrucciones finales del cargador del archivo empaquetado también están empacadas. Así que tenemos que esperar que estas últimas instrucciones sean desempacadas antes de parcharlas para que entreguen el código al recorte. Para resolver esto, podemos pasar el control a nuestro recorte parchador antes de que la rutina cargadora llegue al final. ¿Cuándo? cuando las instrucciones finales del cargador hayan sido desempacadas. Entonces tenemos que agregar algunas instrucciones adicionales al recorte para que éste parche primero las últimas instrucciones del cargador y éste pueda entregar de nuevo, por segunda vez, el control al recorte. La segunda vez que el recorte tiene el control, parchará el código original del programa y eliminará sus protecciones.

5. Dirección de la primera llamada al recorte: VA0.
    Bien, el recorte recibirá entonces el control dos veces. La primera vez, parchará las últimas instrucciones de la sección del archivo encargada de desempacar el programa; este parche consiste en un par de instrucciones que entregarán el control al recorte por segunda vez. En esta última ocasión, el recorte ejecutará una nueva rutina que parchará el programa en memoria y lo desprotegerá. A la dirección que entrega el control por primera vez al recorte lo llamamos VA0.

 

<< O n    t h e    w a y >> ( D o   y o u   r e m e m b e r   J a c k   K e r o u a c k ? )

Crackear un archivo empacado empleando este método es sencillo con Snippet Creator, una herramienta hecha para injertar código nuevo en archivos ejecutables con formato PE. Así que consigamos este programa, corrámoslo y creemos un proyecto nuevo: File\New project. Este comando desplegará una ventana donde podrás seleccionar el archivo que deseas cambiar o desproteger y dar un nombre al proyecto. Cuando creas un programa, Snippet Creator crea un subdirectorio con el nombre que tú eliges y un archivo .INI que salva la información y permite reabrir el proyecto.

1. Final de la rutina desempacadora: Desplazamiento 1 - VA1 (Virtual Address 1)

Nuestro objetivo será api32 v2.4. Para registrar este programa y obtener todas sus funciones podemos buscar y calcular su serial. Pero he visto que esto puede resultar un trabajo largo y arduo. A veces es preferible (menos trabajo - mejor resultado, +ORC) parchar el archivo ejecutable cuando se pueda. Tomaremos este camino.

Primero tenemos que ubicar el final de la rutina que desempaca el archivo. Cargamos el programa con SoftIce y bajamos de alguna manera (usando la tecla F10, y ocasionalmente F5 y F9 para evitar los bicles [ loops ] ) hasta 00 41 B5 D2.       

Esta instrucción es un salto [ jump ] al punto de entrada original del programa en la sección .text:

:0041B5BD       8B 64 24 14               mov esp, dword ptr [esp+14]
:0041B5C1       5E                               pop esi
:0041B5C2       8B FE                         mov edi, esi
:0041B5C4       81 C6 D7 15 00 00    add esi, 000015D7h
:0041B5CA      6A 05                         push 00000005h
:0041B5CC       59                              pop ecx
:0041B5CD       F3                              repz
:0041B5CE       A4                              movsb
:0041B5CF       61                              popad
:0041B5D0       66 9D                         popf
:0041B5D2       E9 E9 9F FE FF         jmp 004055C0h ; <- Salto al punto de entrada original

La instrucción en la dirección 00 41 B5 D2 es donde termina el cargador interno del programa empaquetado. Llamamos a esta dirección VA1.

En esta dirección tendremos que escribir una instrucción de seis bytes que tiene la forma:

1:     push   address_of_snippet
2:     ret

Estas instructiones entregarán el control al recorte. Un código con esta forma tiene un tamaño de seis bytes. En octal:

1:     68 zz yy xx 00
2:     C3

El código octal 68h es la instrucción empujar a la pila [ push ] un dato dword. El resto de la instrucción es un número hexadecimal de 32 bits que será empujado a la pila: 00 xx yy zz h; este número es la dirección a la que saltará el programa con la siguiente instrucción. Así que la instrucción 1 será en ensamblador:

push   00 xx yy zz h

El código octal C3h corresponde a la instrucción en ensamblador 'RET'. Esta instrucción hace que el programa salte a la dirección a la que apunte el registro SP o ESP (el puntero de pila). En este caso es la dirección 00 xx yy zz h en la memoria virtual del proceso y que antes metimos en la pila.

Pero todavía hay un problema. La instrucción original en VA1 también está empacada; entonces tenemos que esperar hasta que esta instrucción sea cargada para escribir un primer salto [ jump ] al recorte: tendremos que localizar otra dirección VA0 anterior a VA1 que entregue una primera vez el control al recorte: en esta primera ocación, el recorte sobre-escribirá la instrucción en la dirección VA1 para que en VA1 el programa entregue nuevamente el control al recorte. La segunda vez que el recorte recibe el control, parchará el programa y lo desprotegerá. Por último restaurará las instrucciones originales que reescribió antes.

Una buena dirección para dar el control al recorte por vez primera es:

:0041A110       0F 84 A7 14 00 00         je 0041B5BDh

Llamamos a esta instrucción VA0. ¿Cómo conseguirla?

Cargo el programa con el loader de SoftIce. Cuando se despliega la ventana de SoftIce, ejecuto el comando "D   41B5D2". Luego voy trazando las diversas instrucciones del programa con la tecla F10 hasta ver como se realiza un cambio en la dirección 41B5D2 en la ventana de datos. Seguro aparecerá algo como " FE 9F E9 E9     FF FE B5 BB ", que son los valors octales de las instrucciones siguientes, pero invertidas:

:0041B5D2       E9 E9 9F FE FF            jmp 004055C0h ; <- Jump to the original entry point
:0041B5D7       E9 BB B5 FE FF           jmp 00406B97h

Entonces, cuando el programa llega a 00 41 A1 10 h, las instrucciones en la dirección 00 41 B5 D2 h estarán desempacadas y podrán ser parchadas.

 

2. Un lugar para el recorte. Desplazamiento 1 - VA2 (Virtual Address 2)

Para ubicar un lugar para el recorte podemos emplear un método bastante empírico pero que funciona. Abrimos el programa con un editor hexadecimal como HexWorkshop y buscamos un sitio sin código, lleno de ceros. Estos espacios amplios genertalmente podemos encontrarlo al final de las diversas secciones. Así que podemos encontrar un espacio amplio al final de la sección .rsrc, en el desplazamiento 00 D3 20 h.

Podemos elegir este espacio. Tenemos el desplazamiento dentro del archivo, pero necesitamos su dirección virtual. Esta dirección la podemos calcular con esta fórmula:

(Desplazamiento del recorte - Desplazamiento del inicio de la sección) + VA de la Sección

A esta dirección la llamamos VA2.

Ya hemos determinado la sección donde pondremos el recorte .rsrc. Para hacerlo ejecutamos en Snippet Creator PE Info\View Section Info. Podemos ver que este desplazamiento está en la sección .rsrc, antes de la sección "madmat". El desplazamiento de inicio de la sección [ Raw Offset of the section ] es 4A 00h.

La dirección virtual de la sección [ VA of Section ] es: Dirección de la base de la imagen [ Image Base Address ] + Desplazamiento virtual de la sección [ VA offset of the section ]:

00 40 00 00h + 00 01 00 00 h = 00 41 00 00 h

Ahora calculamos:

VA2 = (00 D3 20h - 00 4A 00h) + 00 41 00 00h = 00 41 99 20h

Esta es la dirección VA2.

 

3. La dirección a parchar: VA3 (Virtual Address 3)

Ahora vamos a desproteger el programa. Por razones de brevedad, considerando que el lector de este tutorial no es propiamente un principiante, no detallaré el proceso para ubicar el punto a parchar. Simplemente lo diré. Para que el programa corra como si estuviera registrado, con todas sus funciones, debemos cambiar en el siguiente código:

:00404815          03EA               add ebp, edx
:00404817          41          
         inc ecx
:00404818          4E          
         dec esi
:00404819          75DA          
    jne 004047F5
:0040481B          33C0          
    xor eax, eax
:0040481D          5F          
        pop edi
:0040481E          85ED          
    test ebp, ebp
:00404820          5E          
         pop esi
:00404821          5D          
         pop ebp
:00404822          0F94C0          
sete al
:00404825          5B          
         pop ebx
:00404826          59          
         pop ecx
:00404827          C3          
        ret

La instrucción:

:00404822          0F94C0           sete al

Es donde el programa coloca una bandera en el registro al para indicar si el programa está registrado o no. Si esta instrucción pone 1 en al, el programa está registrado. Entonces podemos cambiar esa instrucción de tres bytes por

:00404822          FEC0     inc eax
:00404824          90
         nop

Esta instrucción hará a al diferente de cero. Cuando el programa revise la bandera, actuará como si el programa hubiera sido registrado y actuará como tal.

Aunque esto sería suficiente para registrar el programa, todavía necesitamos introducir nuestro nombre de ususario y el serial. El programa revisa el número de caracteres en el nombre de usuario (debe ser mayor que cinco) y el de la clave (debe ser 16 o más).

Bien. ya tenemos la dirección de los parches.

 

4. Escribir y ensamblar el recorte.

Tenemos que crear el proyecto en Snippset Creator: File\New project. Lo llamamos api32.

Luego configuramos las opciones del proyecto:

Snippet VA = VA2 = 41 99 20
Patch Options =
Patch into Existing Section
Address to Redirect Control To the Snippet =
Redirect Control From Code Section
VA1 = 00 40 17 75
Return Control to the program =
Don't Return Control To Program

Estas opciones eligen:

· la dirección virtual donde el recorte será injertado (VA2)
· el recorte será injertado dentro de una sección existente (.rsrc)
· la dirección virtual donde el programa dará el control al recorte (VA1)
· el recorte no regresará el control al programa; tenemos que hacerlo nosotros y escribirlo en el recorte.
· Snippet Creator no restaurará las instrucciones originales del programa. Tenemos que hacerlo nosotros.

Luego escribimos el recorte y lo ensamblamos. A continuación está el código del recorte para TASM v5.0. Antes de ensamblar el recorte debemos elegir y configurar el ensamblado que usemos. Ejecutamos en Snippet Creator Action\Options para desplegar la ventana "General Options". Escogemos el ensamblador (TASM o MASM según sea el caso) y establecemos los comandos y parámetros correspondientes. En mi caso particular, que he empleado TASM v5.0, y tengo a Snippet Creator en el directorio C:\ASM\ICZ\, los valores y comandos son:

Assembler
TASM

Locations
Assembler:                TASM32 /ml %1
Linker:                      TLINK32 /Tpe /c /aa /V4.0 %1,,,C:\TA\LIB\import32.lib
Project Directory:    C:\ASM\ICZ\

Estos comandos suponen que el directorio donde tengo TASM32.EXE y TLINK32.EXE, está en entorno; es decir, cuando inicio la sección en Windows, el archivo por lotes "autoexec.bat" tenía la siguiente línea:

PATH     C:\TASM\BIN;C:\TASM\LIB;C:\TASM\INCLUDE;%PATH%

A contiuación el código del recorte:

; ---------------------------------------- code snippet ------------------------------------------

jmp init

oldinst1 db 00Fh,084h,0A7h,014h,000h,000h
oldinst2 db 0E9h,0E9h,09Fh,0FEh,0FFh,09Eh
newinst1 db 068h, 020h,099h,041h,000h, 0C3h
newinst2 db 0FEh,0C0h,090h
counter db 0

init:
pushad
cmp counter,0
jne time2

; Restaurar la instrucción 1
inc counter
mov edi,41A110h               ; dirección de la instrucción original 1 en VA0
lea esi,oldinst1                    ; instrucción a restaurar
mov ecx,6 push ecx            ; tamaño de la instrucción original
rep movsb                          ; restaurar la dirección original

; Escribir la nueva instrucción en VA1: segundo salto al recorte
mov edi,41B5D2h              ; dirección donde se volverá a entregar el control al recorte: VA1
lea esi,newinst1                  ; instrucción a escribir
pop ecx                             ; tamaño de las instrucciones
rep movsb

; Retorno 1
popad
push 41A110h
ret

time2:
; Restauar intrucción 2
mov edi,41B5D2h               ; dirección de la instrucción original 2 en: VA1
lea esi,oldinst2                     ; instrucción a restaurar
mov ecx,6
rep movsb

; Write new instruction 2: patch 2
mov edi,404822h               ; dirección de la instrucción original 2 en : VA2
lea esi,newinst2                  ; instrucción a escribir
mov ecx,3                          ; tamaño de las instrucciones
rep movsb                          ; escribirlas

; Retorno 2
popad
push 41B5D2h
ret

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

 

Después de escribir estas lineas en la ventana de edición de Snippet Creator, presionamos el botón "Assemble" y esperamos. Si no hay error, el recorte de código ha sido ensamblado y enlazado.

Ahora podemos "exportar" el binario correspondiente al recorte (File\Export) y salvamos api32.bin.

Abrimos el archivo api32.exe con HexWorkshop (conviene más emplear este editor que HIEW, ya que necesitamos tener dos vistas desplegadas al mismo tiempo, una del archivo api32.exe y otra del recorte api32.bin). Vamos al desplazamiento 00D320 h ( Edit/Goto ). Es el desplazamiento donde colocaremos el recorte de código.

Ahora abrinos el archivo api32.bin que hemos exportado. Lo marcamos totalmente con el ratón y lo copiamos (CTRL+C). Luego desplegamos la vista de api32.exe y vamos al desplazamiento 00D320h y marcamos desde 00D320 hasta 00D39Eh. Ahora pegamos el recorte (CTRL+V). Para terminar, ponemos en el desplazamiento 00D510h (correspondiente a la dirección virtual VA0) la instrucción que entrega el control al recorte por primera vez: 68 20 99 41 00 C3. Esto significa:

:0041A110            68 20 99 41 00            push 00419920
:0041A115             C3                               ret

Recordar que el recorte ha sido colocado en la sección .rsrc. Como sobrescribimos esta sección con alguna instrucción debemos asegurarnos que soporte escritura. Revisemos las características de la sección .rsrc: PE Info\View Section Info. Las características son: 40 00 00 40 h. Esto significa:

Datos Inicializados: 00 00 00 40 h
Lectura:                 40 00 00 00 h
                             40 00 00 40 h

La sección no soporta escritura, así que tendremos que editar las características. Para hacer esto hacemos click con el botón derecho del ratón sobre la cadena .rsrc que aparece en el cuadro de diálogo "Section Information". Seleccionamos "Edit Section" en el menú emergente: esto despliega el vuadro de diálogo "Modify Section Values". Pulsamos el botón "..." al lado del campo "Characteristics". Esto despliega el cuadro de diálogo "Section Charactheristics". Seleccionamos la caja de chequeo IMAGE_SCN_MEM_WRITE y salvamos ( save ). Ahora las características de la sección serán: C0 00 00 40 h:

Datos Inicializados:  00 00 00 40 h
Lectura:                  40 00 00 00 h
Escribible:               80 00 00 00h
                              C0 00 00 40 h

Esto mismo lo tenemos que hacer para todas aquellas secciones que serán escritas durante el proceso, como el cargador del empacado, que es la sección con que inicia un ejecutable empaquetaso. Eso es todo.

 

R e g i s t r a n d o

Ahora corremos el programa y pulsamos el botón 'register'. Escribimos un nombre con más de cinco caracteres:

Mi_Nombre

y un código serial con más de dieciseis caracteres:

FREE-FREE-FREE-FREE

Hacemos click sobre OK, y listo...


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