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.