|
|
 |
ESTUDIO COLECTIVO DE DESPROTECCIONES
Última Actualizacion:
25/10/2001
|
 |
|
Programa |
Messiah |
W95 / W98 / NT |
Descripción |
Juego en 3D |
Tipo |
Protección anticopia de CD's |
Tipo de Tutorial |
[X]Original, []Adaptación, []Aplicación, []Traducción |
Url |
NO DISPONIBLE |
Protección |
LaserLok 5 |
Dificultad |
1) Principiante, 2) Amateur, 3)
Aficionado, 4) Profesional, 5) Especialista |
Herramientas |
SoftIce 4.01, IceDump 6.020,
Hiew 6.55, ADump, Hex WorkShop |
Objetivo |
Eliminar LaserLok |
Cracker |
Mr.Ocean & Mr.Snow [WkT!] |
Grupo |
http://www.whiskeykontekila.org |
Fecha |
24 de Mayo de 2001 |
INTRODUCCION
|
Hola amigos! Tras unos meses de farras, estudios y
demás proyectos, vamos a eliminar una vieja cuenta pendiente: el
LaserLock
Primero de todo vamos a hacer un breve resumen de las características
de esta protección:
- No encripta ninguna sección del ejecutable protegido
- No lleva antidebug
- No aumenta el tamaño del ejecutable, la protección se basa en una
DLL la cual no tiene nombre fijo (en este juego se llama
'Mes3ddll.dll'). El nombre de ésta lo podéis averiguar con un editor
PE y es el primer IMAGE_IMPORT_DESCRIPTOR. Esta librería siempre tiene
una función que es 'CallDLL'.
- REDIRECCIONA las llamadas a las API'S
Así pues si corregimos las llamadas a las API'S tendremos nuestro
juego libre de LaserLock ;) Vamos a ver 2 métodos de hacerlo. La elección
final, queda en vuestras manos
Pero primero vamos a estudiar un poco por encima la protección.
Si cargamos MESSIAHD3D.EXE con el Loader del Sice vemos lo siguiente:
:004DD7C0 PUSH EBP <---
Entry Point
:004DD7C1 MOV EBP,ESP
:004DD7C3 PUSH FF
:004DD7C5 PUSH 004E7430
:004DD7CA PUSH 004E12E8
:004DD7CF MOV EAX,FS:[00000000]
:004DD7D5 PUSH EAX
:004DD7D6 MOV FS:[00000000],ESP
:004DD7DD SUB ESP,58
:004DD7E0 PUSH EBX
:004DD7E1 PUSH ESI
:004DD7E2 PUSH EDI
:004DD7E3 MOV [EBP-18],ESP
:004DD7E6 CALL [004E8868]
<--- Llamada
a LaserLock
:004DD7EC XOR EDX,EDX <---
Dirección de retorno
Si trazamos un poco en la llamada a LaserLock encontramos esto:
:10001D4B PUSH EAX
:10001D4C PUSH EBP
:10001D4D MOV EBP,ESP
:10001D4F PUSH EAX
:10001D50 PUSH EBX
:10001D51 PUSH ECX
:10001D52 PUSH EDX
:10001D53 PUSH ESI
:10001D54 PUSH EDI
:10001D55 MOV EAX,SS:[EBP+08] <-------------
(0)
:10001D59 PUSH EAX
:10001D5A CALL 100018E1 <-----------------------
(1)
:10001D5F ADD SP,04
<------------------------------
(2)
:10001D63 MOV EAX,DS:[EAX]
<----------------- (3)
:10001D66 CMP BYTE PTR
[100168EC],01 <--- (4)
:10001D6D JZ 10001D7F
:10001D73 MOV SS:[EBP+04],EAX
:10001D77 POP EDI
:10001D78 POP ESI
:10001D79 POP EDX
:10001D7A POP ECX
:10001D7B POP EBX
:10001D7C POP EAX
:10001D7D POP EBP
:10001D7E RET
:10001D7F MOV SS:[EBP+08],EAX
:10001D83 POP EDI
:10001D84 POP ESI
:10001D85 POP EDX
:10001D86 POP ECX
:10001D87 POP EBX
:10001D88 POP EAX
:10001D89 POP EBP
:10001D8A ADD ESP,04
:10001D8D RET
(0) Aquí EAX=004DD7EC
(dirección desde donde hemos sido llamados+6)
(1) Esta es la gran llamada a
LaserLock. Esta rutina se encarga de todo: de mostrar el LOGO,
de pedir el CD, pero sobretodo de devolver la API correcta. La primera
vez que se pasa por la rutina se muestra el LOGO del juego (no en todos
los juegos) y llama a la primera API (normalmente GetVersion). La
segunda vez que pasa comprueba que esté insertado el CD original
(atentos a este dato que como veremos más adelante es importantísimo)
y llama a la siguiente API. Las sucesivas veces solo devuelve la API
correcta
(2) EAX=004E7130
:what eax
The value 4E7130 is (a) MESSIAH!.rdata+0130
:d eax
0177:004E7130 FD 33 F8 BF F6 E1 F6 BF-85 77 F6
BF 5E CA F7 BF .3.......w..^...
:what *eax
The value BFF833FD is (a) KERNEL32!GetVersion
(3) EAX pasa a valer BFF833FD
(GetVersion). Aquí o en el punto 2 PODRÍAMOS llamar a nuestra
rutina correctora de API'S, ya que en EAX tenemos la dirección de
.rdata que queremos y
en [EBP+04] desde donde hemos sido llamados. Pero todo se nos jode por
el punto (4)
(4) si BYTE PTR [100168EC]=1
salta a 10001D7F. Esto es debido a LaserLock también redirige
"los saltos" a las API'S. Os hago un ejemplo con GetVersion:
Una llamada "normal" sería:
004DD7E6 FF1530714E00 call
KERNEL32!GetVersion
pero si BYTE PTR [100168EC]=1 sería:
004DD7E6 FF2530714E00 jmp
KERNEL32!GetVersion
Fíjaos bien en el FF25, porque nuestra rutina tendrá que cambiar FF15
por FF25 si se da este caso
|
AL ATAQUE
|
MÉTODO Mr.Ocean
|
Bien con toda esta información ya podemos
escribir nuestra rutina correctora. Primero de todo hemos de
parchear el código del LaserLock para que salte a nuestra rutina:
:10001D59 PUSH
EAX
:10001D5A CALL 100018E1
:10001D5F ADD SP,04
:10001D63 MOV EAX,DS:[EAX] <---
Lo cambiamos a JMP ADump_Adress
Y la rutina es la siguiente:
ADUMP_ADRESS:
mov ecx,00401000
; Inicio de .text
mov
edx,004E7000 ; Fin de
.text
LOOP_BUSCA:
cmp word ptr [ecx],15ffh
; FF15 son los opcodes de "call
[xxxxxxxx]"
jnz SIGUE_BUSCANDO
push ecx
; Metemos en la pila la siguiente
llamada a LaserLock
jmp ecx
; Saltamos a la llamada
SIGUE_BUSCANDO:
inc ecx
cmp ecx,edx
; Hemos llegado al final de .text ???
jnz LOOP_BUSCA
; Si no es así, sigue buscando
int 3
; Cuando rompamos aquí ---> todo OK
CORRIGE:
pop ecx
mov ebx,[esp+8]
; EBX = dirección de "Call
[LaserLock]"
mov dword
ptr[ebx+2],eax
cmp byte ptr[100168ec],1
; Miramos si era salto o call
jnz ADUMP_ADRESS
; Si es call no hay que corregir nada
mov dword
ptr[ebx+1],25h ;
Lo convertimos a JMP API
jmp ADUMP_ADRESS
; Vamos a por la siguiente llamada
Ahora:
"r eip ADump_Adress"
"BPINT 3"
Le damos al F5 y en cuestión de segundos aparecemos en el INT
3. Volcamos la sección .text y la sobreescribimos en el fichero.
Ejecutamos y ZASH! Obtenemos un bonito fallo de protección
general. Si investigamos el tema, nos damos cuenta de que
LaserLock comprueba el CRC de su código:
BPM 10001D5F R
Y aparecemos en la rutina de chequeo del CRC. Para los
interesados, aquí
podeis ver la rutina.
Tras dos F12, vemos lo siguiente:
:10008CC0 CALL 10008AB8
:10008CC5 ADD ESP,04
:10008CC8 MOVZX EAX,AX
:10008CCB MOV ECX,[EBP-08] ;
[EBP-08] contiene el valor del CRC
:10008CCE AND ECX,0000FFFF
:10008CD4 XOR EAX,ECX ;
se XORea el valor de EAX con el valor del CRC (ECX)
Como podéis comprobar el valor del CRC
en ningún momento se compara, lo xorea directamente con el valor
de EAX. Además el chequeo se va haciendo por partes, con lo cual
las posibilidades de "trapichear" con el CRC son
escasas. Pero entonces......cómo redirigimos el código a nuestra
rutina? Fácil, con un BPM y una pequeña "macro":
BPM 10001D63 X do "r eip
CORRIGE;g;"
"CORRIGE" es pues eso, la dirección de memoria de
"CORRIGE:" de
nuestra rutina correctora. Bueno, pues otra vez ponemos el EIP en
ADump_Adress, BPINT 3 y F5. Tras unos 3-5 minutillos llegamos otra
vez al INT 3. (NOTA:
es normal que parezca que el Sice se vuelva loco). Volcamos,
pegamos, ejecutamos y....ZASH! otra vez!!! Bueno......antes que
meterle dos patadas a nuestro querido ordena, decidimos irnos a la
cama, mañana será otro día...
Sip. Con un poco más de calma, nos ponemos a investigar el
tema.....a ver....problema de CRC no es porque no escribimos en su
código (los BPM's al contrario que los BPX's no parchean en el código).
Hacemos un rutina que deje la pila "intacta" y tampoco.
Tras otro ratito más calentándonos la cabeza, damos con la
solución: el muy cabrón comprueba si hemos corregido la anterior
llamada!!! De nuevo para los interesados, aquí
tenéis el código que se encarga de ello.
Tenemos dos opciones. La primera: LaserLock sólo
comprueba si hemos parcheado la anterior, por tanto si hacemos que
nuestra rutinilla vaya parcheando posteriormente asunto
solucionado.
La segunda se aprovecha de una gran "puerta abierta".
Quiero pensar que lo han hecho para ganar velocidad porque
sino....Os explico. LaserLock usa un contador para saber el número
de veces que ha sido
:10001C8B CMP
DWORD PTR [100168F8],32
;
¿ Hemos pasado 32 veces ?
:10001C92
JLE 10001CD0
; Si hemos pasado 32 o menos se
va sin corregir
:10001C98
MOV EAX,[1001690C]
:10001C9D ADD [EBP+08],EAX
:10001CA0 MOV EAX,[EBP+08]
:10001CA3 SUB EAX,05
:10001CA6 MOV [EBP-1C],EAX
:10001CA9 XOR EAX,EAX
:10001CAB MOV AL,[100168EC]
:10001CB0 CMP
EAX,01
<---
0=CALL; 1=SALTO
:10001CB3 JNZ
10001CBF
:10001CB9 MOV EAX,[EBP-1C]
:10001CBC MOV BYTE PTR [EAX],25
<---
Corrige el FF25 (si es
salto)
:10001CBF MOV
EAX,[EBP+08]
:10001CC2 SUB EAX,04
:10001CC5 MOV [EBP-18],EAX
:10001CC8 MOV EAX,[EBP-04]
:10001CCB MOV ECX,[EBP-18]
:10001CCE MOV [ECX],EAX
<---
Corrige la llamada a la API
:10001CD0 MOV
EAX,[EBP-04]
:10001CD3 JMP 10001CD8
:10001CD8 POP EDI
:10001CD9 POP ESI
:10001CDA POP EBX
:10001CDB LEAVE
:10001CDC RET
Alguien puede pensar que si NOPeamos el
salto en 10001C92 asunto resuelto, pero NO. Recordad que no
podemos parchear...pero tranquilos que esta vez la solución es fácil.
Haremos que nuestra rutina ponga a 33 el contador del LaserLock
(mov dword ptr[100168F8], 33h) o con el propio Sice ("e
100168F8 33"). Y aquí viene el gran
"BackDoor" del que os hablaba:
:100019ED CMP DWORD PTR
[100168F8],00
:100019F4 JNZ 10001A13
:100019FA CALL 100013AA
:100019FF MOV EAX,[10014594]
:10001A04 PUSH EAX
:10001A05 CALL 1000337A
<---
Muestra el LOGO
:10001A0A ADD ESP,04
:10001A0D ADD [10016914],EAX
:10001A13 CMP DWORD PTR [100168F8],01
:10001A1A JNZ 10001A3D
:10001A20 CALL 100057E2
<--- Comprueba el CD
:10001A25 ADD
[10016914],EAX
:10001A2B CMP DWORD PTR [100145AC],01
:10001A32 JNZ 10001A3D
:10001A38 CALL 10001340
:10001A3D CMP DWORD PTR [100168F8],02
:10001A44 JNZ 10001A55
:10001A4A CALL 10008393
:10001A4F ADD [10016914],EAX
:10001A55 CMP DWORD PTR [100168F8],02
:10001A5C JLE 10001A8E
:10001A62 CMP DWORD PTR [100168F8],32
:10001A69 JGE 10001A8E
:10001A6F CALL 100086A2
<---
Se asegura de que ha comprobado el CD
:10001A74 ADD
[10016914],EAX
:10001A7A XOR EBX,EBX
:10001A7C CALL 10008590
:10001A81 LEA EAX,[EAX*2+EAX]
:10001A84 SUB EBX,EAX
:10001A86 NEG EBX
:10001A88 SUB [10016914],EBX
:10001A8E CMP DWORD PTR [100168F8],32
:10001A95 JNZ 10001AD3
:10001A9B XOR EAX,EAX
Comprobadlo vosotros mismos....pone
el dword 100168F8 a 33h....pasáis en algún momento por las
comprobaciones del CD??? :d
Bien, por mi parte esto es todo.
|
MÉTODO Mr.Snow
|
Buenas a todos ....
Como veis Mr.Ocean a explicado detalladamente
esta protección, con lo que pensando un poco y recopilando datos
podemos usar este método...
Primero recopilemos datos:
Como dice Mr.Ocean esta protección tiene
crc´s y checkeos
para saber si el código del programa ha sido
alterado (por
lo menos mientras dependa de la dll), aunque como veremos estos
checkeos se puede decir que son INÚTILES ....
Ya que todo depende de la forma en la que
planteemos el problema.
Así pues mi planteamiento es el siguiente:
-
Desviar el EP del programa a una rutina en memoria la cual
se encargue de reconstruir y almacenar las apis.
Pues entonces echemos un vistazo dentro de la
rutina de laserlock:
:10001D4B
PUSH EAX
:10001D4C PUSH EBP
:10001D4D MOV EBP,ESP
:10001D4F PUSH EAX
:10001D50 PUSH EBX
:10001D51 PUSH ECX
:10001D52 PUSH EDX
:10001D53 PUSH ESI
:10001D54 PUSH EDI
:10001D55 MOV EAX,SS:[EBP+08]
:10001D59
PUSH EAX
:10001D5A CALL 100018E1 <-----------------------
(1)
:10001D5F ADD SP,04
:10001D63
MOV EAX,DS:[EAX]
:10001D66
CMP BYTE PTR [100168EC],01 <---
(2)
(1)
Es la rutina encargada de devolvernos la api correcta (mas
bien el puntero a la api correcta)
(2)
Es la comprobación que indica si es JMP o
CALL
Bien
pues con estos 2 datos, el inicio y tamaño de text tenemos mas
que suficiente para reconstruir todas las llamadas a las apis.
Este seria el código de reconstrucción:
mov ecx,InicioDeTExt
mov eax,TextFin
xor edi,edi
repite:
cmp word ptr[ecx],15ffh
jnz incre
pushad
add ecx,6
call Corrige
popad
add edi,5
inc ebx ; ebx se incrementa cada vez que corregimos
incre:
inc ecx
cmp ecx,eax
; se comprueba si hemos llegado al final
jnz repite
Int 3
; pararemos aquí si todo va bien.
;----------------------------------------------------------------------------
; Procedimiento: Corrige
; Descripción: Obtiene la llamada correcta y la deposita en la zona de
; almacenamiento. jeje estamos de suerte y esta rutina nos
; devuelve la dirección de la api en .rdata
; Entrada: ECX = Offset a pushear para que devuelva el valor correcto
; EDI = Puntero A la zona donde guardamos la api corregida;
; Salida:
;----------------------------------------------------------------------------
Corrige:
push edi ; guardamos edi y ebp ya ke la dll se
push ebp ; lo ventila
push ecx ; pusheamos el offset que hemos obtenido
call dll_corrige(1) ; se llama a la rutina que corrige las apis
pop ecx ; corregimos la pila porque se queda
; insertado el Push ECX
pop ebp ; restauramos ebp
pop edi ; restauramos edi
mov ecx,Codigo_Mem_fin ; cargamos en ECX el puntero al final del
; código de memoria que será a partir de
; donde depositaremos las apis add ecx,edi
; lo sumamos en ecx y ecx será nuestro
; puntero a la zona de almacenamiento
mov [ecx],eax ; guardamos en [ecx] el puntero a
; rdata hacia la api correcta.
mov eax,SaltoCall ; cargamos en eax la variable que indica si
; es salto o call
cmp byte ptr [eax],1
jz zero mov
byte ptr[ecx+4],0 ; colocamos 0 si es call
jmp
fuera
zero:
mov byte ptr[ecx+4],1 ; o 1 si es JMP
fuera:
ret
db "[APIS BOLCADAS]"Codigo_Mem_fin:
(este código ha
sido sacado de Delaserlock v1.0)
Con este código ensamblado en la
memoria que reserva Adump ,y simplemente desviando el EP del
ejecutable a esta zona de memoria , tendremos una lista de las
apis correctas.
Con lo que solo nos queda volcar las apis
reconstruidas a un fichero e inyectarlas en frío en el ejecutable
protegido, para ello cuando paremos en la INT 3 solo tendremos que
ver el numero de apis corregidas multiplicarlo por 5 (que es 1
dword para la api correcta + 1 byte para determinar si es salto o
call) y volcar a partir de Codigo_Mem_fin con el resultado
obtenido (/dump codigo_mem_fin ebx*5
c:\listaapis.bin)
Ahora simplemente tenemos que inyectar
las apis obtenidas, en el fichero original teniendo en cuenta que
si el 4 byte de la apis recontruidas es 1 significa que hemos de
cambiar el call por un salto el código sería algo así:
Ecx= Inicio de text
Ebx= rutina de laserlock
xor
edx,edx
bucle:
cmp word ptr[ecx],15ffh
jnz inc_b
cmp dword ptr[ecx+2],ebx
jnz inc_b
mov edi,Inicio_Apis_Recontruidas
add edi,edx
cmp byte ptr[edi+4],0
jz es_call
mov byte ptr[ecx+1],25h
es_call:
mov edi,dword ptr[edi]
mov dword ptr[ecx+2],edi
add edx,5
inc conta
inc_b:
inc ecx
cmp eax,ecx
jnz bucle
Pues como veis haciendo estas cositas también
obtenemos un archivo reconstruido que no necesita del CD original
para funcionar.
Y ajustando un poco mas la rutina de
reconstrucción teniendo en cuenta lo que dice Mr.Ocean, no habría
problema para prescindir del cd original o incluso de este ultimo
código encargado de inyectar las apis correctas en su sitio. Os
preguntareis: ¿y porqué no lo has hecho así ....? pues
mu sencillo , como he dicho el código de reconstrucción lo he
sacado de Delaserlock v 1.0, que es una utilidad de cosecha propia
J
y ya que tengo el código a mano, ¿porque no usarlo? Jeje, además
si os lo damos todo hecho no tendríais el placer de experimentar
y disfrutar. ¿se anima alguien ha hacer un Delaserlock? Es muy
sencillito y no necesitareis el Cd original ....
Enga Salu2
y
Punk Not Dead ....
|
REMATANDO LA
FAENA
|
Nuestro
crack funciona perfectamente, pero nosotros, que somos unos tíos
elegantes, no vemos necesidad que nuestro crack dependa de la DLL
de LaserLock. Así que vamos a eliminar esta dependencia de la
IAT. Con PEditor 1.7 vemos lo siguiente:

Vemos que la siguiente librería a la del Laser es
'DINPUT.dll'. Fácil. Abrimos el fichero con el HexWorkShop
y buscamos la cadena 'DINPUT.dll'. La encontramos en dos
offsets....aplicando un poco de ZEN deducimos que es la segunda
(alrededor de la primera hay strings ;) que está en el
offset 000E7CF6h. Invertimos los bytes de ese offset ( F67C0E00) y
buscamos esos valores. De nuevo nos salen dos offsets, cualquiera
de los dos nos vale. Yo para explicároslo cogeré el del offset
000E799Ch

Conociendo la estructura IMAGE
IMPORT DESCRIPTOR sabemos que:
-1- |
-2- |
-3- |
-4- |
-5- |
Original First Thunk |
TimeDateStamp |
ForwardChain |
Name |
First Thunk |
607A
0E00 |
0000
0000 |
0000
0000 |
F67C
0E00 |
1C70
0E00 |
Pues ya lo tenemos: el 000E7990h es el RVA de
nuestra tabla de importación. Lo corregimos con PEditor,
ejecutamos y.......FUNCIONA!!! ;)
|
PALABRAS
FINALES |
El
continuo retraso de la salida de este tutorial ha propiciado que
saliese una nueva versión de LaserLock. Sabiendo crackear ésta
no deberíais tener excesivos problemas con la nueva. De todas
formas ya sabéis dónde encontrarnos: en el canal #cdcracking del
IRC Hispano ;)
Esto es todo, un saludito para los amigos de K-FOR, [WkT!], EiThel
y MYTH
Mr.Ocean & Mr.Snow [WkT!]
|
|
[ Entrada | Documentos Genéricos | WkT! Web Site ]
|
[ Todo el ECD | x Tipo de Protección | x Fecha de Publicación | x Orden Alfabético ]
|
|
(c)
Whiskey Kon Tekila [WkT!] - The Original Spanish Reversers.
Si necesitas contactar con
nosotros
, lee
esto
antes e infórmate de cómo puedes
ayudarnos |
|
|
|
|
|