ESTUDIO COLECTIVO DE DESPROTECCIONES
Última Actualizacion: 25/10/2001

Programa TrickStyle W95 / W98 / NT
Descripción Juego futurista de carreras sobre aerotablas
Tipo Protección comercial anticopia de CD's
Tipo de Tutorial [X]Original, []Adaptación, []Aplicación, []Traducción
Url NO DISPONIBLE
Protección SECUROM
Dificultad 1) Principiante, 2) Amateur, 3) Aficionado, 4) Profesional, 5) Especialista
Herramientas SoftIce 4,Adump,ProcDump,IceDump 6.020,Hex WorkShop
Objetivo Eliminar Securom
Cracker Mr.Ocean [WkT!]
Grupo http://www.whiskeykontekila.org
Fecha 27 de Febrero de 2001

INTRODUCCION
Lo primero de todo qué es Securom:

SecuROM es una protección anticopia para CD-ROM´s de Sony DADC que identifica el CD "original" por un mecanismo de autenticación especial. En el proceso se graba una huella digital electrónica que asigna un número único a cada título de CD-ROM.

¿Cómo detectarlo? Hasta la versión V4 en el directorio raíz del CD se hallan los archivos CMS16.DLL, CMS_95.DLL y CMS_NT.DLL. En las nuevas versiones (como el juego del presente tutorial) estos archivos se encuentran dentro del ejecutable principal. Si lo editas con un editor PE (ProcDump, PEditor) verás que hay dos secciones llamadas ".cms_t" y ".cms_d".


 Este no es un tutorial precisamente fácil. Yo asumiré que tú tienes unos conocimientos básicos sobre archivos PE, SoftIce, volcados de memoria, etc. También asumo que has leído antes los tutoriales de Securom de Pedro, R!SC y +Xoanon. De todas formas intentaré explicar las posibles dudas-problemas que vayan surgiendo.

 

AL ATAQUE
Vamos a lío !!!!!

Si leíste el tutorial de Pedro puedes ver cómo él pone breakpoints en WriteProcessmemory, GetDriveTypeA, etc...pero Sony ha mejorado Securom y ahora es capaz de detectar estos breakpoints. Hiuston !!!!! Tenemos un problema !!!!

Bueno lo primero que vamos  a hacer es recopilar información del ejecutable (TS_D3D.exe):

Entry Point --> 00553E90 (situado en la sección ".cms_t")

Como podréis comprobar el código de Securom ahora se encuentra dentro del ejecutable  principal, en las secciones ".cms_t" (cms_text) y ".cms_d" (cms_data). 

Tenemos que hallar el punto de entrada original del ejecutable (el que tenía antes de pasar por Securom)

Cómo +Xoanon explica en su tute, tenemos que buscar el "JMP EAX" que nos lleva al Entry Point original. Oppsss !!!! pero no podemos tracear ni poner breakpoints en WriteProcessMemory o GetDriveTypeA. 

Bueno es el momento de ver algo de teoría:

Para establecer un breakpoint con SoftIce (y cualquier otro debugger) lo que hace éste es cambiar el primer byte del código donde hemos puesto el punto de ruptura por CCh, que es el opcode de Int 3 (que hace saltar al debugger). Lo que pasa que éste es un proceso transparente para el cracker ya que el SoftIce en pantalla muestra el byte original y no "CC". Y es aquí dónde se basa Securom (y muchas otras protecciones) para detectar los breakpoints. Haced lo siguiente:

u GetDriveTypeA

KERNEL32!GetDriveTypeA 
016F:BFF678EF     57         PUSH EDI  <--- Securom comprueba el breakpoint aquí
016F:BFF678F0     6A21     PUSH 21    <--- Qué tal si lo ponemos aquí? ;)
016F:BFF678F2     2BD2    SUB EDX,EDX 

El SoftIce parcheará el byte siguiente a GetDriveTypeA y Securom no nos detectará el breakpoint. 

Mucha gente me preguntó si no es más fácil poner un BPM? Quizás sí, pero el Securom no nos permite tener BPM´s, se niega a correr cuando se encuentra con alguno, entre otras cosas porque como veréis un poco más abajo el propio Securom maneja sus propios BPM´s.

BPX getdrivetypea+1

F12 y aparecemos aquí:

016F:00551E21    51                           PUSH ECX 
016F:00551E22    FF151C505700      CALL [KERNEL32!GetDriveTypeA] 
016F:00551E28    83F805                   CMP EAX,05 
016F:00551E2B    7421                       JZ 00551E4E 

Ahora tendríamos que trazar hasta encontrar el Entry Point original, pero si pulsas F8 o F10 simplemente no pasa nada...nos han mutilado el SoftIce!!! Cómo se lo han montado? Aquí tenéis la solución "by Ni2":

"El F8 no funciona (o parece q no funciona) porque el SECUROM pone un breakpoint por hardware (BPM en DR0) en la dirección donde no funciona el F8. Como estamos bajo el SICE, no se produce excepción tras una INT 1 (la INT 1 la genera el BPM que ha puesto el SECUROM). El SECUROM, lo que hace es instalar un SEH que se encarga de manejar la excepcion (INT 1) tras el breakpoint que ha puesto"

Encontrar y jugar con las SEH que instala Securom puede llevar mucho tiempo y requeriría un estudio mucho más a fondo de la protección (jeje, como si no nos la hubiésemos estudiado para el UnSecurom ;) Hi Ni2! Hi SkUaTeR!) Habrá que buscar pues otra solución. Es ésta: Pulsa 'Control+Av.Pág' hasta encontrar el siguiente código:

016F:00553054    58                     POP EAX 
016F:00553055    FFE0                JMP EAX 
016F:00553057    A3286E5700    MOV [00576E28],EAX 

Y haz lo siguiente:

- BPX 553055 

- Borra (o desactiva) el breakpoint de Getdrivetypea

- Pulsa F5 y espera que salte el SoftIce

Aparecemos en  :00553055, miramos el valor de EAX y vemos que es 004EBBA4. Bien este es el punto de entrada original sin Securom. Pero todavía no es el momento de cantar victoria, tan sólo hemos ganado la primera batalla.....si volcamos el archivo y lo ejecutamos nos peta en las narices  porque las llamadas a las APIS todavía dependen de Securom. Vamos a ver que hacemos para subsanar este problemilla:

016F:004EBBA4    55                            PUSH EBP            <-- Entry Point original
016F:004EBBA5    8BEC                       MOV EBP,ESP 
016F:004EBBA7    6AFF                       PUSH FF 
016F:004EBBA9    6808AF5000           PUSH 0050AF08 
016F:004EBBAE    68A8114F00           PUSH 004F11A8 
016F:004EBBB3    64A100000000        MOV EAX,FS:[00000000] 
016F:004EBBB9    50                             PUSH EAX 
016F:004EBBBA    64892500000000    MOV FS:[00000000],ESP 
016F:004EBBC1    83EC58                    SUB ESP,58 
016F:004EBBC4    53                             PUSH EBX 
016F:004EBBC5    56                             PUSH ESI 
016F:004EBBC6    57                             PUSH EDI 
016F:004EBBC7    8965E8                     MOV [EBP-18],ESP 
016F:004EBBCA    FF1528C25500       CALL [0055C228]
  <-- Llama a la rutina de Securom encargada
016F:004EBBD0    33D2                        XOR EDX,EDX             de las APIS 

Bueno al menos ahora podemos tracear con F8 y F10. Nos aprovechamos de eso y trazamos esa llamada con F8. Aparecemos aquí:

016F:0054D040   55             PUSH EBP  
016F:0054D041   8BEC       MOV EBP,ESP 
016F:0054D043   83EC28    SUB ESP,28 

De nuevo con 'Control+Av.Pág' vemos que lo que hace la rutina es sacar de una tabla la llamada correcta a la API, almacena el valor correcto en EAX y salta a ella. Busca el siguiente código:

016F:0054D5B7    5D       POP EBP 
016F:0054D5B8    FFE0   JMP EAX 
016F:0054D5BA    5F       POP EDI 

 

Pon un breakpoint en 0054D5B8. Le damos al F5 y esperamos que salte el Sice. Ahora poned:

 
:what eax                                                                       
The value BFF833FD is (a) KERNEL32!GetVersion                                   

Osea que ese 'JMP EAX' en realidad es el salto a la llamada correcta. Podríamos codificar un pequeño programilla que nos arreglase las llamadas a las APIS tal que:

:0054D5B7      Aquí EAX contiene la llamada correcta
:0054D5B8      JMP a Nuestra rutina
:mi rutina          Cambia CALL [0055C228] a CALL valor de EAX

Si lo hacemos, funciona perfectamente, pero sólo lo haría en nuestro sistema operativo (en mi caso WindowsME). La solución está en hacer una llamada directa a la tabla de importación. Buscamos 'BFF833FD' en la memoria y:

 
:s 400000 l ffffffff FD 33 F8 BF                                                
Pattern found at 0030:004FB0CC (000FB0CC)                                       

Si en 004EBBCA cambiamos 

CALL [0055C228]

           por 

CALL [004FB0CC] 

vemos que llamamos a GetVersion sin pasar por la rutina de Securom, prueba superada !!! 

Si estudiamos un poco más la rutina que devuelve la llamada correcta, vemos que Securom coge la dirección desde donde ha sido llamada y en función de eso saca de una tabla la correcta. Pero todo esto nos supondría un trabajo enorme si tuviésemos que corregir a mano todas llamadas a las APIS. Por eso codificaremos en SoftIce un programilla como éste que nos haga la faena sucia: 

; Securom Call FiXeR
; Ejecuta Adump. Ejecuta el comando "r" , STARTOFFS es la dirección ADUMP
; en 0054D5B8 cambia 
; JMP EAX 
;        a 
; JMP dirección ADUMP;
; Y en la dirección ADUMP ensambla esto:

         

          mov ebx,eax                 ; Guardamos en EBX la API llamada
          pop eax                        ; Obtenemos la dirección de retorno después de la llamada
          mov edx, ebx                ; Guardamos EBX en EDX como precaución         
          mov ecx,004FB000h    ; 004FB000=Inico sección ".rdata"
BUSCAIAT:
          cmp dword ptr[ecx],ebx   ; Busca la API en la sección ".rdata"
          jnz   SIGUEBUSCANDO1
          mov dword ptr[eax-4],ecx  ; Modifica "CALL [0055C228]" por "CALL [API correcta]"
          mov ecx,00401000             ; 00401000= inicio de la sección ".text"      
BUSCALLAMADA: 
          cmp word ptr [ecx],15FFh     ; Busca la siguiente llamada a Securom en la sección ".text"
          jnz   SIGUEBUSCANDO2                          ;  FF 15 28 C2 55 00 son los bytes de
          cmp dword ptr [ecx+2], 0055C228h   ;  CALL [0055C228] y cambian en función
          jnz   SIGUEBUSCANDO2                           ;  del juego que estés crackeando
          jmp ecx                       ; Salta a la llamada siguiente para que Securom nos devuelva la correcta
SIGUEBUSCANDO1:                                    
          inc ecx 
          cmp ecx,0050D000h      ; Es fin de sección ".rdata"???
          jnz   BUSCAIAT                 ; Si no lo es, sigue buscando
          int 3                                ; Si algo va mal romperemos aquí
SIGUEBUSCANDO2:  
          inc ecx 
          cmp ecx,004F9000h    ; Es fin de sección ".text"??
          jnz   BUSCALLAMADA    ; Si no lo es, sigue buscando
          int 3                              ; Cuando todas las llamadas estén corregidas romperemos aquí

Ahora pon "BPINT 3", desactiva todos los breakpoints, cruza los dedos y pulsa F5. Arrrrrrgggggghhhh!!!! Falla!!! Puto Securom de los....tranquilos no os desaniméis. Esto sucede porque Securom comprueba el CRC de su rutina. Si el CRC llama a una API errónea y peta. Pero....cómo nos enfrentamos a un CRC si los BPM´s están inutilizados? Pues gracias a este magnífico programilla de EliCZ: "SuperBPM". Pero no podemos cargarlo desde el principio, porque sino el Securom se niega a correr. Debemos ejecutar el juego y cuando rompamos en el verdadero Entry Point, parar el proceso y ya sí, cargar el SuperBPM. Jeje qué lioso, no?   Con el SuperBPM, un poco de vista e intuición (jeje y algo más quizás, SkUaTeR y Ni2 ya saben a lo que me refiero ;) ) unas páginas más arriba del JMP EAX encontramos el siguiente código:

:0054D28A  8B0A   mov ecx, dword ptr [edx]
:0054D28C  3B08    cmp ecx, dword ptr [eax] <--- Comprueba el "checksum"
:0054D28E   7409    jz  0054D299    <--- Hay que hacer incondicional este salto

Sí, si forzamos ese salto diremos adiós a las caídas de sistema. Para mentes retorcidas: Os podéis imaginar lo cabrón que podía haber sido el Securom si hubiese utilizado directamente el CRC para desencriptar las APIS? Pues ésto (y más) lo podréis comprobar en el tute de LaserLok. 

Bueno, cuando todas las llamadas estén corregidas vuelca la sección ".text". Divide "TS_D3D.exe" en secciones y reconstruye el fichero con la nueva sección ".text". Con un editor PE cambia el Entry Point por el nuevo. En teoría ya tenemos finalizado nuestro crack, pero si ejecutamos el juego provocamos un bonito fallo de protección general. ¿A qué es debido? Pues a que Securom todavía no ha dicho la última palabra. La dirección  a la que apunta la tabla de importación en la cabecera PE no es la correcta (esta técnica es usada por muchos otros protectores). Pero... ¿cómo  podemos encontrar la verdadera tabla de importación? Muy sencillo. Con un editor hexadecimal (para esta tarea os recomiendo Hex WorkShop) buscamos la cadena 'Kernel32.dll' (que es la primera importación). La encontramos en el offset 10C11C, invertimos bytes y nos queda 1CC110. Buscamos (generalmente hacía arriba) '1CC110', encontramos lo siguiente:

IMAGE IMPORT DESCRIPTOR:

 
-1- -2- -3- -4- -5-
  Original First Thunk   TimeDateStamp   ForwardChain   Name   First Thunk
E4BD 1000 0000 0000 0000 0000 1CC1 1000 5CB0 0F00

 Estamos indudablemente en el inicio de nuestra tabla de importación. Vamos a nuestro editor PE y en 'Directory' cambiamos el RVA de 'Import Table' a 0010BC98. Ejecutamos el juego y....funciooonaaaaa!!!!!! Este juego no tiene CD-Check secundario, por tanto ya tenemos TrickStyle 100% crackeado. Tampoco tiene videos o músicas que poder ripear. Queda por tanto pendiente para un futuro tute, enseñaros el arte de ripear.

 

VARIANTES DE SECUROM

Durante el desarrollo del UnSecurom nos topamos con dos pequeñas variantes de esta versión:

- La primera en juegos como el ShadowMan, Revolt y Rally Championship. El proceso de crackeo es algo más sencillo. Sólo debéis llegar al verdadero EntryPoint y volcar la sección ".text". En esta variante las APIS no están redirigidas con lo cual nos olvidamos de la parte más engorrosa de Securom. Y con editor PE veréis que el ejecutable tiene 2 secciones ".idata", la primera es la buena. Así pues, una vez reconstruido el fichero tenéis que corregir la IAT al inicio de esa sección.

- La segunda me la encontré en el FreeStyleBMX. También tiene 2 secciones ".idata", pero aquí sí que están redirigidas las APIS. No existe copia de la tabla de importación en la sección ".rdata" y la rutina de corrección de APIS tiene que buscar en la primera ".idata". La IAT también es el inicio de la primera ".idata".

 

PALABRAS FINALES

Salvo que Sony dé un gran giro  (y hace mucho que no lo da) en su protección no deberíais tener ningún problema al crackear cualquier nueva versión. De echo la única gran dificultad de esta versión en realidad es corregir las llamadas a las API'S. Pero ahora el problema ya está resuelto, no?

Saludos y agradecimientos:

- A SkUaTeR y Ni2. Qué locos que estamos!!! 
- A AlCaLiNo y GAMESPACK, por su amistad y soporte técnico
- A Alexia y a Sir_Death por los buenos ratos en el chat
- A R!sc, +Xoanon y Pedro por sus tutoriales (y en general a todos los que crackean juegos)
- A Karpoff simplemente por TODO
- Y a toda la gente de BCN y Cádiz que me dejo :)

Dudas, erratas y demás a:

mrocean@whiskeykontekila.org

 
[ 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