TORN@DO presents: cRACKER's n0TES
Sistemas de Protección comerciales: SecuROM



Crackeando SecuROM (Pedro))
Primero, una explicación simple sobre SecuROM
SecuROM es una protección del CD-ROM que no puede copiarse cuando duplicas un CD. Es usado por muchos juegos, con el propósito de este tutorial yo probé Conflict Freespace (versión inglesa), Grim Fandango (versión italiana) y Might and Magic VI (versión italiana). Este es el primer tutorial que yo escribo, así que me perdonas si no estoy claro o si mi inglés es malo. Decidí escribir este tutorial porque el crack genérico para SecuROM de Laxity no funciona en los juegos que yo probé. También encontré que parte del código de SecuROM está encriptada, y es descifrada por una lectura de la clave del CD. Mi objetivo es permitir a la protección descifrarse, entonces poner el código descifrado en el ejecutable y quitar la comprobación del CD-ROM por SecuROM.

Necesitas SoftICE, Adump 1.0, ProcDump32 1.1 y el gratuito & grandioso
DJGPP32 C++ - Compilador para usar este tutorial.


Primero, miremos al ejecutable principal. Conflict Freespace y Might and Magic VI no están empaquetados, mientras que Grim Fandango está empaquetado con Petite. Así que la primera cosa que nosotros tenemos que hacer es desempaquetar el ejecutable de Grim Fandango. Por suerte es bastante fácil si nosotros usamos ProcDump32, este tiene apoyo para desempaquetar los programas comprimidos por Petite.

Ok, empecemos con el cracking real ;-)

Cuando arrancamos estos juegos, vemos que cargan algo del disco y que simplemente terminan (porque pusimos una copia, no el original dentro del lector :-) Bien,podemos intentar un breakpoint en la llamada usual a SendDriverMessage, pero no pasa nada.

Hmm, parece que SecuROM no usa el Windows API para acceder al CD-ROM. Te ahorro el esfuerzo de encontrar cómo el programa accede al CD-ROM: Usa INT 31 con AH=03 (DPMI 0.9+ - SIMÚLATE REAL MODE INTERRUPT) para llamar a la interrupción de MSCDEX

andemos un poco después del breakpoint, entramos en CMS32_95.DLL eso es parte de la protección, entonces alcanzamos el ejecutable principal. ¡Ahora, si buscamos algunos de los bytes del código que nosotros vemos, no podemos encontrarlos en el archivo ejecutable principal! Partes del código están encriptadas, y ellas se descifran cuando el programa se ejecuta. ¿Cómo puede modificarse el programa durante la ejecución?

Llamando a WriteProcessMemory. Así que ponemos un breakpoint en esta llamada. Vemos que todos éstos juegos lo llaman tres veces por lo menos, aun cuando no pusimos el CD-ROM en el lector. Así que este descifrado no depende de los datos en el CD-ROM original. Esto es simplemente el código que hace el último descifrado. De hecho si nosotros pusiéramos el CD-ROM original en el lector, el API es llamado una vez más, y el código descifrado es correcto, mientras si nosotros pusiéramos una copia en el lector, o bien WriteProcessMemory no es llamado la cuarta vez (copia mala, así que la protección comprende que es falso) o es llamado pero el código descifrado es basura y el programa comprende que es erróneo y sale.

Así que el cuarto descifrado depende de la lectura de los datos del CD-ROM original.

Si miramos la referencia de API que vemos cuando el breakpoint es activado en WriteProcessMemory tenemos:

ESP+08: dirección del destino
ESP+0C: dirección de la fuente
ESP+10: longitud de área a copiar

Así que, nosotros podríamos descargar los bytes del código después del descifrado y podríamos sustituirlos en el archivo ejecutable principal.

Primero hacemos una copia del ejecutable principal llamado MM6_2.EXE (para este propósito yo uso Might and Magic VI, pero los otros funcionan de la misma manera). Es importante usar nombres de archivo cortos, de otra manera supcomp y supwrite no funcionarán. La regla es: ejecutamos el original MM6.EXE para descifrar el código y parcheamos MM6_2.exe (no ejecutar MM6_2.EXE antes de que sea parcheado completamente o se colgará).

Ejecutemos Adump. Con el comando ' R' veo que el comienzo del área de memoria para descargar es 0x83651000.

Ahora ejecutemos MM6.EXE con breakpoint en WriteProcessMemory. Ok, veo que 0x5000 bytes serán escritos, la dirección de la fuente está en 0xe80078 mientras la destino dirección está en 0x4ae000. Así que copio las dos áreas (fuente y destino) en dos áreas diferentes de descarga de memoria::

M 4AE000 L 5000 83651000 (código original)
M E80078 L 5000 83661000 (código desencriptado)

Dejó al proceso acabar, voy al "dumpeador" y escribo las dos áreas de memoria a dos archivos.

W C:\ORIG1.DAT 5000 83651000
W C:\MODIF1.DAT 5000 83661000

Ahora abro ORIG1.DAT con un editor hexadecimal y tomo los primeros 16 bytes. Busco esos bytes en MM6_2.EXE. Los encuentro en offset 0xAD400. Veamos si todos los 0x5000 bytes son idénticos. Abro una ventana de DOS y ejecuto:

supcomp C:\ORIG1.DAT MM6_2.EXE 0 0xAD400 0x5000

Ok, ninguna diferencia, así que podemos parchearlos.

supwrite C:\MODIF1.DAT MM6_2.EXE 0 0xAD400 0x5000

Pero ahora si nosotros ejecutamos MM6_2.EXE se cuelga porque intenta descifrar datos ya descifrado y consigue basura. Así que ejecutemos MM6.EXE de nuevo, y cuando localizamos el breakpoint, escribimos ' u @esp ' y subimos algunas líneas:


       :008CC2FE  8D8D64FEFFFF        LEA     ECX,[EBP-019C] 
       :008CC304  51                  PUSH    ECX 
       :008CC305  8B95C4FEFFFF        MOV     EDX,[EBP-013C] 
       :008CC30B  52                  PUSH    EDX              ; longitud 
       :008CC30C  8B85E4FEFFFF        MOV     EAX,[EBP-011C] 
       :008CC312  50                  PUSH    EAX              ; fuente 
       :008CC313  8B8DBCFEFFFF        MOV     ECX,[EBP-0144]  
       :008CC319  2B8DB4FEFFFF        SUB     ECX,[EBP-014C] 
       :008CC31F  51                  PUSH    ECX              ; destino 
       :008CC320  8B15B87D9F00        MOV     EDX,[009F7DB8] 
       :008CC326  52                  PUSH    EDX              ; manipulador 
       :008CC327  FF15B8839F00        CALL    [KERNEL32!WriteProcessMemory]
    

Debemos poner longitud a 0 así que cambiamos:


       MOV EDX,[EBP-13C] 
       PUSH EDX
    

a:


       XOR EDX,EDX 
       NOP 
       NOP 
       NOP 
       NOP 
       PUSH EDX
    

Es decir, nosotros buscamos los bytes (en MM6_2.EXE):
8B 95 C4 FE FF FF 52 8B 85 E4 FE FF FF 50 8B 8D BC FE FF FF 2B 8D B4 FE FF FF 51 8B 15 B8 7D 9F 00 52 FF 15 B8 83 9F 00

y cambiamos los primeros 6 bytes a:

33 D2 90 90 90 90

(es mejor buscar varios bytes, porque hay partes similares de código, y tenemos que asegurarnos que hemos encontrado el lugar exacto).

Tienes que trabajar de la misma manera para los otros dos breakpoints (cambia el código cifrado por el código descifrado y pon a cero la longitud para WriteProcessMemory). Alguien podrían preguntarse por qué no escribí un programa para hacer todo esto automáticamente.

Bien, el problema es, el código es similar pero no es el mismo para todos los juegos que probé (por ejemplo Grim Fandango usa ECX como el registro para empujar el parámetro de longitud).

Ahora nosotros realmente necesitamos el CD-ROM original (¿lo compraste?,¿ no lo tienes? :-) para descifrar el código correctamente. Todavía debemos repetir el procedimiento anterior para descifrar y poner la longitud a cero cuando localiza el cuarto WriteProcessMemory (esta vez EDX es "XOReado" amablemente para nosotros, así que nosotros apenas necesitamos ' NOPear' la siguiente instrucción que carga EDX). También debemos crackear la parte de código donde verifica el CD-ROM original y sale sin ejecutar nuestro código parcheado (esto está en la parte del código que desciframos antes, así que si no lo hubiéramos descifrado, no podríamos encontrarlo fácilmente el archivo ejecutable).

¡De hecho si nosotros intentamos ejecutar el programa después de cuarto descifrado pero antes del último crack, no funcionará, incluso con el CD-ROM original en el lector!

La última parte del crack es un poco más difícil porque no puedes caminar en el código del programa(F8 o F10 no funcionarán). Es más, si el programa descubre que estás intentando caminar en él, la próxima vez ni siquiera se cargará hasta que reinícies Windows, así que no debes poner breakpoints excepto lo que yo te diga. Te ahorraré el tiempo que yo gasté para entender lo que el hace programa. Primero puedes poner un breakpoint en GetDriveTypeA que es usado para encontrar el CD-ROM. Con F11 vuelves al código del programa. Si te desplazas en la ventana del código algunas páginas abajo, encontrarás una serie de POPs y un RET seguida por unos INT 03. Pon un breakpoint en el RET.

Ejecuta el original MM6.EXE con el CD original.

Hmm, no alcanza el RET. Quita el CD del lector y ejecútalo de nuevo. Ah, ahora alcanza el RET con EAX=2. Pon el CD-ROM original de nuevo en el lector pero ejecuta MM6_2.EXE (debes de haberlo descifrado y lo debes de haber remendado TODO las cuatro veces). Alcanza el RET con EAX=7. Si pones una copia en el lector también consigues EAX=7. Así que es fácil entender que EAX contiene un código de error cuando algo sale mal, y el RET nunca es alcanzado cuando todo va correctos. Ahora debes ejecutar el MM6_2.EXE modificado después de poner el cd original en el lector y poner un breakpoint en GetDriveTypeA y en RET. Aprieta F11 para conseguir el código cuando alcance GetDriveTypeA. Recuerda, debes conseguir el código de error 7 de modo que desplázate abajo hasta que encuentres:


       TEST EDX,EDX ; ¿error? 
       JNZ ........ ; si salta => no error 
       CALL [.....] ; comienzo de rutina de error 
       PUSH 07 
       CALL ....... 
       MOV EAX,7    ; código de error 
       JMP ........ ; salta a los POPs y RET
 

Así que el primer jnz debe cambiarse a jmp. Buscamos los siguientes bytes:

75 17 FF 15 B0 83 9F 00 6A 07
Dentro de MM6_2.EXE y cambiamos 75 a EB. Ejecútalo. Otro error, con retorno de código 8. En el código encontramos:


       TEST EDX,EDX ; ¿error? 
       JNZ ........ ; si salta => no error 
       CALL [.....] ; comienzo de rutina de error 
       PUSH 08 
       CALL ....... 
       MOV EAX,8    ; código de error 
       JMP ........ ; salta a los POPs y RET
 

Busca:

75 17 FF 15 B0 83 9F 00 6A 08
Y cambia 75 a EB. Esta vez si lo ejecutas, consigues error código 0. Encuentras este código cerca del RET:


       JNZ ........ ; salta si error 
       PUSH 2C      ; ¡todos los controles pasados! 
       CALL ....... 
       JMP ........ ; corre, baby, corre :-)
 

Así que simplemente debes cambiar jnz -> nop nop. La secuencia a buscar es 75 09 6A 2C y cambia 75 09 con 90 90.

Por fin el ejecutable modificado corre de nuevo con el original. ¿Pero qué pasa con la copia, oigo que preguntas? ¡Hurra, también funciona porque quitaste los códigos de error 7, 8 y 0 que también producía la copia! Por supuesto la copia debe tener el nombre de volumen correcto, de otro modo conseguirás el mensaje 'Wrong disc'
(n.del t.: disco incorrecto)
Bien, yo no sé si esto es la manera más simple de crackear SecuROM: Yo escribí todo esto especialmente con propósitos didácticos. Debe funcionar en cualquier juego protegido con SecuROM. De modo que bye, bye SecuROM, nosotros no te extrañaremos :-)


    ****************** código fuente para supcomp **************************** 
      
    #include <stdio.h> 
    #include <conio.h> 
    #include <stdlib.h> 
    #include <mem.h> 
    #define AREA 32768 
      
    FILE *f,*g; 
    unsigned char *b1,*b2; 
    char notfound[]="Can't open: %s\n"; 
    char seekerror[]="Seek error: %s\n"; 
    char readerror[]="Read error or end of file: %s\nAborting\n"; 
    long l,cont,ofsrc,ofdest; 
      
    void uscita(void) 
    { 
    if (b1) free(b1); 
    if (b2) free(b2); 
    if (f) fclose(f); 
    if (g) fclose(g); 
    } 
      
    void main(int argc, char *argv[]) 
    { 
    if (atexit(uscita)) 
    { 
    printf("Atexit error\n"); 
    exit(EXIT_FAILURE); 
    } 
    if (argc!=6) 
    { 
    printf("Supcomp v1.0 by Pedro '98\n\n" 
    "Usage: supcomp <src> <dest> <offset src> <offset dest> <length>\n" 
    "Números deben estar en hex si precedidos por 0x\n\n" 
    "El programa compara <length> bytes de <src> con el correspondiente\n" 
    "bytes en <dest> comienzan desde el especificado offsets\n" 
    "Solo las diferencias son escritas en el output\n"); 
    exit(EXIT_FAILURE); 
    } 
    if ((b1=(char *)malloc(AREA))==NULL) exit(EXIT_FAILURE); 
    if ((b2=(char *)malloc(AREA))==NULL) exit(EXIT_FAILURE); 
    if ((f=fopen(argv[1],"rb"))==NULL) 
    { 
    printf(notfound,argv[1]); 
    exit(EXIT_FAILURE); 
    } 
    if ((g=fopen(argv[2],"rb"))==NULL) 
    { 
    printf(notfound,argv[2]); 
    exit(EXIT_FAILURE); 
    } 
    ofsrc=strtol(argv[3],NULL,0); 
    ofdest=strtol(argv[4],NULL,0); 
    if (fseek(f,ofsrc,SEEK_SET)) 
    { 
    printf(seekerror,argv[1]); 
    exit(EXIT_FAILURE); 
    } 
    if (fseek(g,ofdest,SEEK_SET)) 
    { 
    printf(seekerror,argv[2]); 
    exit(EXIT_FAILURE); 
    } 
    if ((l=strtol(argv[5],NULL,0))==0) 
    { 
    printf("Wrong length\n"); 
    exit(EXIT_FAILURE); 
    } 
    while (l) 
    { 
    long letti,i; 
      
    if (l>=AREA) letti=AREA; 
    else letti=l; 
    if (fread(b1,1,letti,f)!=letti) 
    { 
    printf(readerror,argv[1]); 
    exit(EXIT_FAILURE); 
    } 
    if (fread(b2,1,letti,g)!=letti) 
    { 
    printf(readerror,argv[2]); 
    exit(EXIT_FAILURE); 
    } 
    for (i=0;i<letti;i++) 
    { 
    if (b1[i]!=b2[i]) 
    { 
    printf("%.8lx %.2x - %.8lx %.2x\n",cont+ofsrc+i, (unsigned
    int)b1[i],cont+ofdest+i,(unsigned int)b2[i]); 
    } 
    } 
    l-=letti; 
    cont+=letti; 
    } 
    exit(EXIT_SUCCESS); 
    } 
      
      
      
      
    ****************** código fuente para supwrite ****************************   
    #include <stdio.h> 
    #include <conio.h> 
    #include <stdlib.h> 
    #include <mem.h> 
    #define AREA 32768 
      
    FILE *f,*g; 
    unsigned char *b1; 
    char notfound[]="Can't open: %s\n"; 
    char seekerror[]="Seek error: %s\n"; 
    char readerror[]="Read error or end of file: %s\nAborting\n"; 
    char writeerror[]="Write error: %s\n"; 
    long l,ofsrc,ofdest; 
      
    void uscita(void) 
    { 
    if (b1) free(b1); 
    if (f) fclose(f); 
    if (g) fclose(g); 
    } 
      
    void main(int argc, char *argv[]) 
    { 
    if (atexit(uscita)) 
    { 
    printf("Atexit error\n"); 
    exit(EXIT_FAILURE); 
    } 
    if (argc!=6) 
    { 
    printf("Supwrite v1.0 by Pedro '98\n\n" 
    "Usage: supwrite <src> <dest> <offset src> <offset dest> <length>\n" 
    "Números deben estar en hex si precedidos por 0x\n\n" 
    "El programa escribe <length> bytes de <src> al correspondiente\n" 
    "bytes en <dest> comienzan desde el correspondiente offsets\n"); 
    exit(EXIT_FAILURE); 
    } 
    if ((b1=(char *)malloc(AREA))==NULL) exit(EXIT_FAILURE); 
    if ((f=fopen(argv[1],"rb"))==NULL) 
    { 
    printf(notfound,argv[1]); 
    exit(EXIT_FAILURE); 
    } 
    if ((g=fopen(argv[2],"rb+"))==NULL) 
    { 
    printf(notfound,argv[2]); 
    exit(EXIT_FAILURE); 
    } 
    ofsrc=strtol(argv[3],NULL,0); 
    ofdest=strtol(argv[4],NULL,0); 
    if (fseek(f,ofsrc,SEEK_SET)) 
    { 
    printf(seekerror,argv[1]); 
    exit(EXIT_FAILURE); 
    } 
    if (fseek(g,ofdest,SEEK_SET)) 
    { 
    printf(seekerror,argv[2]); 
    exit(EXIT_FAILURE); 
    } 
    if ((l=strtol(argv[5],NULL,0))==0) 
    { 
    printf("Wrong length\n"); 
    exit(EXIT_FAILURE); 
    } 
    while (l) 
    { 
    long letti; 
      
    if (l>=AREA) letti=AREA; 
    else letti=l; 
    if (fread(b1,1,letti,f)!=letti) 
    { 
    printf(readerror,argv[1]); 
    exit(EXIT_FAILURE); 
    } 
    if (fwrite(b1,1,letti,g)!=letti) 
    { 
    printf(writeerror,argv[2]); 
    exit(EXIT_FAILURE); 
    } 
    l-=letti; 
    } 
    exit(EXIT_SUCCESS); 
    }
    




Apéndice de +Xoanon



 ------------------------------------------------------------------------------
                                    SecuROM
                            Apéndice al crack de Pedro
                              por xOANINO [UCF/CLASS]
 ------------------------------------------------------------------------------

Precisamente he leído el ensayo de Pedro para SecuROM, un ensayo muy bueno.... Pero como todas las cosas italianas... no es un trabajo completo. Como nuestros increíbles políticos, él hizo cosas fáciles más difíciles de lo que realmente son como te mostraré en este pequeño 'apéndice' (Yo no puedo escribir un ensayo completo, como siempre tengo chicas que me esperan... ya sabes :))
(n.del t.: No sé que tiene éste muchacho contra los italianos, a mí personalmente me caen bastante bien, aunque como es normal me gustan más las italianas ;oÞ)

Sin embargo, un trabajo muy bueno Pedro... Aun cuando tu trabajo no está al 100% completo, funciona... y es bueno ver que también Italia tiene (de hecho) algo de valor para mostrar en la escena del cracking!!

Bien... Aquí está el problema: Como todos pueden leer anteriormente en el ensayo de Pedro, él descifra correctamente todo el material en la sección .text e .idata y parchea el .exe. Ok, así es cómo SecuROM debe ser crackeado.

Así... ¿qué está equivocado en el ensayo de Pedro? Bien, intenta usar su método con (por ejemplo) un juego que quieres rasgar y usar sin el CD. No funcionará. ¿Por qué? Bien, el EXE producido por Pedro no esta reconstruido al 100%. Todavía depende de las DLLs de SecuROM, y si no encuentra un CD en la unidad con el nombre y material correcto, el programa no correrá.

Y así que, aquí viene tu mega-ocupado, con chicas, estudios, codificando xOANINO al rescate para producir un ejecutable completamente reconstruido trabajando al 100% :)

Simplemente sigue estos 6 pasos:


1) Sigue el ensayo de Pedro hasta el BPX GetdrivetypeA / BPX en el RET algunas páginas abajo.

2) Como puedes notar, algunas líneas sobre el ret (donde Pedro remienda el último JNZ) allí hay un JMP EAX. Ahora... ¿qué es este JMP? Es el salto al entrypoint del programa correcto, cuyo código ya está descifrado siguiendo el ensayo de Pedro.

3) Apunta el valor de EAX, y simplemente escribe este valor al campo entrypoint de la cabecera de PE (PE+28h. debe estar en offset A8h en cada archivo PE). Considera que debes restar de EAX el valor del imagebase:

  Ejemplo:
  EAX = 418DB4h (Omnia99 entrypoint)

  Imagebase = 400000h
  valor a escribir = 418DB4-400000 = 018DB4h (revertido, por supuesto)

4) Ahora también puedes eliminar las secciones no necesitadas... ¡como la sección .CMS_D y la sección .PETITE!! (usa procdump para esto, o hazlo a mano)

5) Wow, también puedes suprimir el CMSxx.DLL !

6) ri-Wow, el EXE corre sin más problemas !!!!


Eso es todo... es solamente un ' apéndice':) ¡Pedro hizo un trabajo muy bueno de cualquier modo!





Apéndice de GrimFandango (Pedro)


Hace algunos días yo encontré un pequeño cambio en la protección de SecuROM que fue hecho por Sony en un reciente juego, así que decidí escribir de nuevo sobre esto. El ensayo anterior todavía es válido, pero, como nosotros veremos, hay un poco más de trabajo que hacer para crackear el nuevo SecuROM. En primer lugar, me gustaría agradecer a +Xoanon por escribir su ' apéndice'. Yo realmente había hecho las cosas más difíciles de lo que eran. Con su idea simple, nosotros no necesitamos ya poner la longitud de WriteProcessMemory a cero, ni tenemos que crackear los códigos de error antes del RET, porque simplemente saltamos todo el código de SecuROM y nos vamos directamente al punto de entrada real. Tengo todavía mucho que aprender ... :-)

Pero hay algo más que decir sobre SecuROM.

Bien, en mi ensayo yo era un poco impreciso. Recuerdas que yo crackeé Might and Magic VI como un ejemplo, y por supuesto eso funcionó (yo leí el FAQ de Fravia+ y no quiero escribirle diciendo ' Mi invalido crack no funciona' después de que ha publicado mi trabajo :-). También dije que Conflict Freespace y Grim Fandango eran lo mismo. Es aquí, donde yo he sido impreciso. De hecho yo sólo tenía una copia no-funcional de esos dos juegos, pero vi que había el mismo descifrado multi-pasos, así que yo asumí que la protección entera era la misma.

Después algunos días yo conseguí el original de Grim Fandango y me sentí defraudado cuando vi que Sony dejaba el descifrado multi-pasos, pero se agregó algo más a la protección. Así que yo quiero comportarme mejor que mis aborrecidos políticos italianos y yo no quiero permitir que este crack sea otra cosa italiana inacabada :-)

En primer lugar, tienes que hacer la copia usual del ejecutable original descomprimido llamado GRIM2.EXE. Entonces debes parchear las cuatro partes del código como describí en mi primer ensayo. Puedes saltar la parte en donde puse a cero longitud para WriteProcessMemory o donde crackeé los códigos de error, porque ya no necesitaremos esa parte del código de SecuROM. También, debes poner un breakpoint en ' jmp eax' como +Xoanon señaló, para conseguir el punto de entrada real, y cambiarlo en la cabecera de PE. Pero si lo ejecutas, no funciona. ¿Por qué? Sígueme y lo descubrirás.

Ahora deja un breakpoint de nuevo en WriteProcessMemory y ejecuta el original GrimFandango.exe (con la copia original en el lector). Vemos que allí está el mismo descifrado de las cuatro partes, pero después de eso, WriteProcessMemory es llamado muchas más veces durante la ejecución del juego, y sólo son parcheados 4 bytes cada vez. Cuando estamos dentro del breakpoint si escribimos ' u (@esp+8)-2 ' para ver donde los datos están siendo escritos, siempre vemos la misma LLAMADA:

CALL [008D6218] (por supuesto esto cambia de juego a juego)

A propósito, esto es justamente el punto desde donde se llamó el procedimiento de SecuROM en [008D6218], y es este procedimiento el que está llamando a WriteProcessMemory ahora. Si apretamos F11 podemos ver lo que pasa. Esa llamada se ha cambiado a:

CALL [KERNEL32!GetVersion]

(esto es simplemente un ejemplo, cada llamada es cambiada a su valor original, es decir el valor que estaba en el juego sin protección antes de que Sony se entretuviera con él :-)

Nosotros lo hemos entendido ahora. Todo el tiempo el juego desprotegido tenía que llamar una rutina del sistema, o incluso a una de sus propias rutinas, Sony guardó la dirección de la LLAMADA en una tabla, y hizo a la llamada apuntar a una rutina de SecuROM. Cuando esta rutina es ejecutado, esto puede entender desde donde se llamó mirando el valor de retorno en la pila, entonces parchea el código y así la próxima vez la llamada se hará directamente. Al final debe dar el control a la rutina que sería llamada, y logra esto con un ' jmp eax' (en nuestro ejemplo eax contendrá la dirección de GetVersion). Desgraciadamente esto sigue durante la ejecución entera del programa. Pero no nos gusta mantener a semejante aburrido vecino como una parte del código de SecuROM, nosotros queremos eliminarlo completamente.

En primer lugar debemos ver lo que es la dirección real de esta rutina de SecuROM:
en la localización [8D6218] nos encontramos la dirección 8CB050.

Ahora tomemos Wdasm y desensambla GRIM2.exe (así el código en 8CB050 ya estará descifrado) . Bien realmente no necesitas desensamblarlo para hacer el crack, porque yo explicaré todos los pasos para hacerlo después, pero es útil aprender, porque esa es la razón real de por que estás estudiando reversing y para lo que estás leyendo esto, no simplemente para copiar algunos juegos tontos, ¿o tu sí? :-)

Puedes ver simplemente el código con SoftICE cuando estás dentro del procedimiento. Vamos a 8CB050. Aquí nosotros vemos muchas referencias como éstas:


       :008CB069 8B0DBCDF8E00            MOV ECX, DWORD PTR [008EDFBC] 
        ...... 
       :008CB072 890DBCDF8E00            MOV DWORD PTR [008EDFBC], ECX 
        ...... 
       :008CB0AA 8A8240FC8E00            MOV AL, BYTE PTR [EDX+008EFC40] 
        ......
  

Así que ahí debe estar la tabla para descifrar todas las llamadas. Nota que no nos preocupamos de cómo esta tabla está hecha. Apenas necesitamos reconstruir el ejecutable de la misma manera que hicimos con los cuatro parches. La rutina termina así:


       :008CB385 FF1518E78E00            CALL DWORD PTR [008EE718] 
                                         ; llama a WriteProcessMemory 
      
       :008CB38B 61                      POPAD 
       :008CB38C 8B45F8                  MOV EAX, DWORD PTR [EBP-08] 
       :008CB38F 8BF0                    MOV ESI, EAX 
       :008CB391 8B06                    MOV eax, DWORD PTR [ESI] 
       :008CB393 5F                      POP EDI 
       :008CB394 5E                      POP ESI 
       :008CB395 5B                      POP EBX 
       :008CB396 8BE5                    MOV esp, EBP 
       :008CB398 5D                      POP EBP 
      
       :008CB399 FFE0                    JMP EAX       ; aquí hace la llamada 
                                                       ; original del juego 
      
       :008CB39B 5F                      POP EDI 
       :008CB39C 5E                      POP ESI 
       :008CB39D 5B                      POP EBX 
       :008CB39E 8BE5                    MOV ESP, EBP 
       :008CB3A0 5D                      POP EBP 
       :008CB3A1 C3                      RET
 

Hmm, ahora una idea interesante me viene a la mente. En primer lugar la rutina no usa EBX, así que nosotros podemos utilizarlo para conseguir el control después de llamar a la rutina. Entonces nosotros podemos ' simular' las llamadas del programa usando el siguiente pequeño programa en ensamblador que puede ensamblarse en SoftICE en una zona sin usar de Adump (pobre Adump, lo estamos cargando excesivamente :-):

  
       :00000100 B9FA0F4F00              MOV ECX, 004F0FFA 
                                    ; esto es (longitud - 6 bytes) de sección .text 
                                    ; por supuesto tendrás que cambiarlo con 
                                    ; los diferentes juegos 
      
       :00000105 BA00104000              MOV EDX, 00401000 
                                    ; esto es dirección de comienzo de sección .text 
      
       :0000010A 803AFF                  CMP BYTE PTR [EDX], FF 
                                    ; FF 15 18 62 8D 00 es la secuencia que 
                                    ; corresponde para call [008d6218], y 
                                    ; tendrás que cambiarlo según 
                                    ; el juego que estés crackeando. 
                                    ; Estamos buscando esta secuencia en 
                                    ; el código 
      
       :0000010D 7530                    JNE 0000013F 
                                    ; no encontrada, continúa buscando 
      
       :0000010F 807A0115                CMP byte ptr [edx+01], 15 
       :00000113 752A                    JNE 0000013F 
       :00000115 807A0218                CMP byte ptr [edx+02], 18 
       :00000119 7524                    JNE 0000013F 
       :0000011B 807A0362                CMP byte ptr [edx+03], 62 
       :0000011F 751E                    JNE 0000013F 
       :00000121 807A048D                CMP byte ptr [edx+04], 8D 
       :00000125 7518                    JNE 0000013F 
       :00000127 807A0500                CPM byte ptr [edx+05], 00 
       :0000012B 7512                    JNE 0000013F 
      
       :0000012D 8D4206                  LEA EAX, DWORD PTR [EDX+06] 
                                    ; ¡encontrada! Ahora 'simulamos' la 
                                    ; llamada: ponemos 
                                    ; la dirección de retorno en la pila como 
                                    ; la llamada que fue hecha por el programa  
      
       :00000130 60                      PUSHAD 
                                    ; ...pero primero mejor guardamos nuestros 
                                    ; preciosos registros 
      
       :00000131 50                      PUSH EAX 
                                    ; ah, ahora la dirección de retorno 
                                    ; correcta está en la pila
                                    
      
       :00000132 BB3D010000              MOV EBX, 0000013D 
                                    ; cargamos ebx con la dirección de la siguiente: 
                                    ; instrucción de 'pop eax', así recobraremos 
                                    ; el control después de parchear. Cambia este valor 
                                    ; según tu offset in Adump 
      
       :00000137 FF2518628D00            JMP DWORD PTR [008D6218] 
                                    ; y ahora damas y caballeros, infrinjamos las reglas 
                                    ; SecuROM (como siempre, cambia 008d6218 según 
                                    ; el juego que estés crackeando) 
      
       :0000013D 58                      POP EAX 
       :0000013E 61                      POPAD 
      
       :0000013F 42                      INC EDX 
      
       :00000140 E2C8                    LOOP 0000010A 
                                    ; la búsqueda seguirá en... 
      
       :00000142 CC                      INT 03 
                                    ; terminado, atrás a SoftICE
   

Ejecutemos GrimFandango.exe con el breakpoint de +Xoanon sobre ' jmp eax'. Ahora nosotros estamos a punto de entrar en el programa (recuerdas, nosotros siempre estamos ejecutando GrimFandango.exe porque GRIM2.EXE no funciona). Con ' u 8cb050 ' nosotros vemos nuestra rutina principalmente odiada :-).

Desplazando algunas páginas abajo vemos el ' jmp eax' sobre el que yo estaba hablándote. Esto debe cambiarse a ' jmp ebx', para permitir a nuestro diminuto (diminuto pero eficaz :-) programa en ensamblador recobrar el control. Entonces apuntamos el eip actual, ponemos ' i3here on' y ponemos eip al principio de nuestro código en ensamblador. F5, entonces nosotros esperamos un poco (si ni tu ni yo hemos cometido ningún error, de otra manera podrías esperar para siempre por Windows para resucitar :-) Wow, está terminado. ¿Así que qué pasó? Bien, todas las ' call [008d6218] ' se deben de haber reemplazado con su colega original correcto. Para decir la verdad es posible (pero muy improbablemente) que una secuencia falsa FF 15 18 62 8D 00 que no representa a la antedicha llamada se haya cambiado incorrectamente. Es improbablemente, no obstante, porque 6 bytes son un modelo muy específico. Así que simplemente probémoslo primero, si todo choca -o algo peor - simplemente investigaremos aburridamente todas las localizaciones reemplazadas.

Debemos descargar ahora desde 401000 al final de la sección .text la que puede verse con 'map32' (comienzo=401000, longitud=4f1000 => fin=8f2000). El problema es ahora que algunas páginas no están cargadas en memoria, así cuando nosotros escribimos el comando "m" conseguimos un error. Lo que sigue es una idea para descargar aun cuando algunas páginas no están cargadas en la memoria: supón que la zona de descarga de Adump empieza en 'pippo' (con una imaginación italiana increíble :-). Debemos ensamblar este pequeño programa con SoftICE cerca del final de la zona de Adump, pon pippo+4ff000 (ah, recuerda aumentar el área de Adump por supuesto, si lo necesitas, como en este caso que debe ser por lo menos 0x500000 bytes):


    PUSHAD 
    PUSHF 
    CLD 
    REP 
    MOVSB 
    POPF 
    POPAD 
  

Ok, cuando necesitamos descargar apuntamos el eip actual, entonces cambiamos eip a pippo+4ff000, caminamos sobre pushad y pushf, entonces cargamos ecx manualmente con la longitud de la descarga (en este caso 4f1000), esi con el offset (401000) del comienzo, y edi con el offset (pippo) de destino y caminamos sobre las instrucciones restantes.

¡Cuando hemos terminado de descargar nosotros podemos restaurar el eip que antes apuntamos, y GrimFandango continuará apaciblemente incluso sin saber que nos lo hemos vuelto del revés! : -) Ah, sólo una nota de advertencia: antes de descargar o llamar a mi rutina en ensamblador, quita TODOS los breakpoints, de lo contrario tendrás ' int 3 ' no deseados en la descarga (como yo hice :-).

La última parte es muy fácil: mira donde empieza la zona descargada en el ejecutable y reemplázalo con supwrite (bien, mi conocimiento de ejecutables PE es limitado, pero yo pienso que es ok para reemplazarlo todos. Por otra parte puedes escribir un pequeño programa en C para reemplazar sólo las FF 15 18 62 8D 00 secuencias con lo correcto desde la descarga). Si el reemplazando completo es correcto, ni siquiera necesitas los primeros cuatro pasos: con este único descarga y el punto de entrada correcto lo consigues todos.

Que cosa tan bonita: ¡nuestro GrimFandango no-funcional está vivo de nuevo! No está tan mal para un esqueleto :-)).





Outcast Apéndice (R!SC)


Herramientas
* HexEditor (Hacker's View)
* SoftICE 3.2x + Memory Dumper (IceDUMP)
* ProcDump
* RPP 1.2i
* TASM 5.0


Mi objetivo, LOADER.EXE, comprimido con ' Petite' del juego ' Outcast' de Appeal/Infogrames (bonito objetivo, porque 50% del tiempo no quiere correr aun cuando tengas el CD correcto).


Yo he estado jugando con SecuROM... Me encanta el tutorial de Pedro sobre él (
http://crknotez.cjb.net), y esto me ayudó a que crackeara algunos juegos de SecuROM, pero, ¡ay!, pienso que Sony ha puesto al día SecuROM, así que el tutorial de Pedro no ayuda mucho ahora... ¿Recuerdas cómo ello parecía que supiera que habías estado corrigiéndolo, como y se negó ya a correr, hasta un reseteo ? Bien, chúpate esto , y antes había unos breakpoints seguros que podrías usar, bpx writeprocessmemory, bpx getdrivetypea, erm, bien, ahora los conoce, y también se niega a correr... ¡ay!, nos encontramos con algunos problemas.. :D

¿bien, eres un cracker o un ratón?? he, he, nosotros no nos asustamos de NINGUN SecuROM ...

Digamos que quiero poner un bpx en writeprocessmemory, para averiguar donde descifra los datos en el código de los programas, consigue una interrupción, la primera donde descifra algún código de SecuROM, entonces ninguna más, el programa corre en un loop continuo, ctrl-alt-del para eliminarlo, entonces él habitualmente correrá de nuevo... digamos que quiero evitar la parte de descifrado del código de él, y romper en GetDriveTypea, no no no, si tienes cualquier punto de ruptura puesto, él simplemente correrá, y después de quitarlos, seguirá sin correr ...

Yo noté una cosa, CMS16.DLL, CMS32_95.DLL & CMS32_NT.DLL están dentro del programa, y son escritos al disco cuando es ejecutado... probablemente para evitar que los manoseemos.. :D si sabe que has estado corrigiéndolo, sale sin cerrar el manipulador del archivo para CMS16.DLL. Prueba a suprimirlo, consigues un bonito error, 'Cannot delete CMS16: The specified file is being used by Windows'.

Bien, esto es una pista, quizá... quita todos los breakpoints, bpx createfilea ... ejecuta el juego protegido por SecuROM: algunas de las primeras interrupciones no son importantes... Windows cargando el archivo, entonces una pausa corta, dónde se descomprime, entonces éstos son los únicos que queremos, el primero se abre, ¿el segundo?

CMS16.DLL? el tercero, CMS16.DLL ... espera, echa una mirada a este código ...

0137:005A1298  50                  PUSH    EAX                      <-- ptr para x:\xx\cms16.dll
0137:005A1299  FF1534685C00        CALL    [KERNEL32!CreateFileA]
0137:005A129F  8945DC              MOV     [EBP-24],EAX
0137:005A12A2  837DDCFF            CMP     DWORD PTR [EBP-24],-01   <-- él ya está allí, y 
0137:005A12A6  753B                JNZ     005A12E3                   - no puede ser abierto de nuevo..
0137:005A12A8  C70580645C0000000000MOV     DWORD PTR [005C6480],00000000
0137:005A12B2  6A00                PUSH    00
0137:005A12B4  6A00                PUSH    00
0137:005A12B6  6A03                PUSH    03
0137:005A12B8  6A00                PUSH    00
0137:005A12BA  6A00                PUSH    00
0137:005A12BC  6800000080          PUSH    80000000
0137:005A12C1  8D8D38FFFFFF        LEA     ECX,[EBP-00C8]
0137:005A12C7  51                  PUSH    ECX                      <-- mismo ptr para cms16.dll
0137:005A12C8  FF1534685C00        CALL    [KERNEL32!CreateFileA]
0137:005A12CE  8945DC              MOV     [EBP-24],EAX
0137:005A12D1  837DDCFF            CMP     DWORD PTR [EBP-24],-01   <-- oh mierda, todavía está a -1
0137:005A12D5  750A                JNZ     005A12E1                   - pero forzando este salto
0137:005A12D7  6A00                PUSH    00                         - correrá de nuevo :D    
0137:005A12D9  E8022C0000          CALL    005A3EE0
0137:005A12DE  83C404              ADD     ESP,04
0137:005A12E1  EB0A                JMP     005A12ED
0137:005A12E3  C70580645C0001000000MOV     DWORD PTR [005C6480],00000001
0137:005A12ED  8B15C4675C00        MOV     EDX,[005C67C4]

 

Bien, mira, intenta crear este archivo, y si falla, devuelve el código FFFFFFFF, y sale... si nosotros lo engañamos, haciéndolo pensar que puede crear este archivo, sólo forzando cualquiera de estos saltos, corre de nuevo :D

Así no todo está perdido.. oops, nosotros todavía no podemos bpx writeprocessmemory, o bpx getdrivetypea, así que las cosas son más complicadas, pero no imposible ...

Lo que noté sobre las versiones más viejas de SecuROM, es que descifra 20 KB de código del programa, alrededor del punto de entrada original, entonces verifica el disco, y si el correcto está dentro, descifra 200h bytes más de código en el punto de entrada original... el otro código descifrado no era tan importante, como lo era éste código de SecuROM... teoría, rastrea Petite hasta que haya desempaquetado el programa, descarga la memoria, bpx en el punto de salida del código de SecuROM, y cuando lo alcances, descargas la memoria de nuevo, y simplemente haces una comparación del archivo, debes encontrar un bonito bloque de 20 KB de código descifrado en el segundo volcado... arrgh! ¿cómo hacemos para el bpx en el punto de salida del código de SecuROM?? eh, no hagas ph34r, es fácil :D

Yo espero que tengas ya jodido al programa, así que ya no correrá, y tenemos que hacerle correr cambiando uno de los saltos después de la llamada a CreateFileA, ' CMS16.DLL '... good ... Yo utilicé mi arriesgado parcheador de procesos para hacer un loader que arregló esto para mí ...

T=10000:
F=loader.exe:
O=securomfix_cc.exe:
P=5A12A6/75/CC: ; 0137:005A12A6 753B JNZ 005A12E3
$

Cambiar esto a un EB le hace correr todo el tiempo, pero Yo quise romper aquí, así que lo cambie a CC, INT 03, entonces en SoftICE, bpint 03, X. ejecuta el loader... eh, cuando rompa, no te olvides de cambiar el CC a un EB... e eip eb ... bien, cuando rompa, y hayas cambiado tu INT 03 a un JMP, simplemente haz tu ventana de código grande y bonita, y desplázate, ctrl-page-down.

Aquí es donde nosotros normalmente podríamos romper, pero bpx getdrivetypea o simplemente bpx 5a25a2, el los conoce y detiene la ejecución... malo, sigue desplazándote


0137:005A259B  52                  PUSH    EDX
0137:005A259C  FF15E04F5C00        CALL    [KERNEL32!GetDiskFreeSpaceA]
0137:005A25A2  8D8548FCFFFF        LEA     EAX,[EBP-03B8]
0137:005A25A8  50                  PUSH    EAX
0137:005A25A9  FF15004B5C00        CALL    [KERNEL32!GetDriveTypeA]
0137:005A25AF  83F805              CMP     EAX,05

 

Mira, otro lugar donde normalmente podríamos romper, pero, ¡ay!, no podemos nunca más... sigue desplazándote ...


0137:005A28E0  8D9548FCFFFF        LEA     EDX,[EBP-03B8]
0137:005A28E6  52                  PUSH    EDX
0137:005A28E7  FF15E04F5C00        CALL    [KERNEL32!GetDiskFreeSpaceA]
0137:005A28ED  8D8548FCFFFF        LEA     EAX,[EBP-03B8]
0137:005A28F3  50                  PUSH    EAX
0137:005A28F4  FF15004B5C00        CALL    [KERNEL32!GetDriveTypeA]
0137:005A28FA  83F805              CMP     EAX,05

 

Yippee!! este es otro lugar donde nosotros romperíamos, muchas muchas páginas de código han pasado ante nosotros, y lo sabemos, aquí es donde el código del securom termina, y salta al programa apropiado :D


0137:005A31A8  B8A1535000          MOV     EAX,005053A1
0137:005A31AD  90                  NOP
0137:005A31AE  90                  NOP
0137:005A31AF  50                  PUSH    EAX
0137:005A31B0  EB03                JMP     005A31B5
0137:005A31B2  58                  POP     EAX
0137:005A31B3  FFE0                JMP     EAX

  

Hmm, buenas noticias, podemos bpx aquí 0137:005A31B3 FFE0 JMP EAX, y todo estará bien... el programa todavía funciona bien :D yah... ¡¡Bien!!

Aquí hay otro loader para ayudarnos en nuestra tarea ...

T=10000:
F=loader.exe:
O=securom.cc.jmp.eax.exe:
;P=5A12A6/75/EB: ; eh, mi pc chocó por alguna razón, así que esto no es necesario todavía :)
P=5A31B3/FF/CC: ; Solamente quiero romper en el punto de salida de securom, el jmp eax ...
$

Bonito R!SC, casi es el momento para ser destructivo :D


Ahora, usando este loader, cuándo el softice rompe en el int 03, nosotros podemos conseguir nuestro código descifrado, ¿qué sobre nuestras arriesgadas llamadas? ¿recuerdas al viejo securom? ¿call dword ptr [securom] para cada importación? ¿y si remontaras encima de él, el bonito código del securom reemplazó [securom] con la dirección real de la importación a fuera IAT en alguna parte en memoria? he, he, bien, jodido si esto trabaja ahora :( Mira aquí ...

Esto es mi punto de entrada de programa original, mira 005053C7.. eso es donde la api llama a GetVersion, pero llama al código de securom, que a un tiempo, jmp a GetVersion, remonta en una de las llamadas, entonces desplaza la ventana del código hasta un jmp eax... pon un breakpoint en este ... y ejecútalo ...


0137:005053A1  55                  PUSH    EBP
0137:005053A2  8BEC                MOV     EBP,ESP
0137:005053A4  6AFF                PUSH    FF
0137:005053A6  6810EB5100          PUSH    0051EB10
0137:005053AB  68C0525000          PUSH    005052C0
0137:005053B0  64A100000000        MOV     EAX,FS:[00000000]
0137:005053B6  50                  PUSH    EAX
0137:005053B7  64892500000000      MOV     FS:[00000000],ESP
0137:005053BE  83EC58              SUB     ESP,58
0137:005053C1  53                  PUSH    EBX
0137:005053C2  56                  PUSH    ESI
0137:005053C3  57                  PUSH    EDI
0137:005053C4  8965E8              MOV     [EBP-18],ESP
0137:005053C7  FF1528C25A00        CALL    [005AC228]       <-- llamada [securom] ...
0137:005053CD  33D2                XOR     EDX,EDX
0137:005053CF  8AD4                MOV     DL,AH
0137:005053D1  891594585900        MOV     [00595894],EDX
0137:005053D7  8BC8                MOV     ECX,EAX
0137:005053D9  81E1FF000000        AND     ECX,000000FF
0137:005053DF  890D90585900        MOV     [00595890],ECX

  

mi 'jmp eax' estaba en 59F16F

Rompe debido a BPX #0137:0059F16F (ET=286.97 microsegundos)
:?eax
BFF9137C 3220771708 (-1074195588) "¿ù|"
:¿qué eax?
El valor BFF9137C es (a) KERNEL32!GetVersion <-- ha

Ahora, teoría, el petite desempaqueta el código, y desempaqueta una tabla de dirección de importación real :D, nosotros apenas tenemos que encontrar el IAT real en memoria, buscamos las importaciones correctas para nuestras llamadas, y arreglamos las llamadas para llamar nuestra tabla de importación en lugar del código del securom ...

:s 400000 l ffffffff 7c 13 f9 bf
modelo encontrado en 0137:0051B110 (0011B110)
:s
modelo encontrado en 0137:005C6530 (001C6530)
:s
modelo encontrado en 0137:005CA3E8 (001CA3E8)
:s
modelo encontrado en 0137:0095067C (0055067C)

Bien, nosotros conseguimos cuatro opciones por el momento, Yo rastreé el código desempaquetado, y simplemente se detiene antes de que el código de securom se ejecuta... entonces busca de nuevo ...

:s 400000 l ffffffff 7c 13 f9 bf
modelo encontrado en 0137:005CA3E8 (001CA3E8)

Yippee, sólo encuentra uno... así si cambio esta línea ...


0137:005053C7 FF1528C25A00 CALL [005AC228]
a

0137:005053C7 FF15E8A35C00 CALL [KERNEL32!GetVersion] ; llamada [005CA3E8]

Eso es una llamada arreglada, sólo deja aproximadamente 300 para irse:) deja algo de código ...

WHOOPS, Yo codifiqué algunas cosas, arreglé todo, descargué la memoria, lo copié y lo pegué en mi anterior volcado, y funcionó ok... pero ... no funcionó en Win95 (Yo trabajo con Win98) ...

Más allá el debugging reveló algún código así ...


015F:00508FE0  55                  PUSH    EBP
015F:00508FE1  8B2D68B15100        MOV     EBP,[KERNEL32!CloseProfileUserMapping]
015F:00508FE7  56                  PUSH    ESI
015F:00508FE8  57                  PUSH    EDI
015F:00508FE9  33DB                XOR     EBX,EBX
015F:00508FEB  33F6                XOR     ESI,ESI
015F:00508FED  33FF                XOR     EDI,EDI
015F:00508FEF  3BC3                CMP     EAX,EBX
015F:00508FF1  7533                JNZ     00509026
015F:00508FF3  FFD5                CALL    EBP

  Mira esta línea :
  

015F:00508FE1  8B2D68B15100      MOV     EBP,[KERNEL32!CloseProfileUserMapping]


  

Es realmente MOV EBX, DWORD PTR [0051B168], moviendo una dirección del api desde el primer IAT nosotros encontramos... lo único que no es suyo cuando es desempaquetado... no estropearon securom con esto, porque no es una llamada directa al IAT.. bien, desempaqueté el ejecutable con ProcDump... lo ejecuté con LOADER32, y comprobé la memoria en 51B168, contenía 72981200... obviamente, como esto es reemplazado con la dirección lineal de la función del api, esto era mi primera cosa 'rota'.. Yo busqué en el exe desempaquetado por 72981200, y encontré dos lugares, uno justo antes de todos los nombres de las funciones importadas, y el otro, uno que ya había encontrado antes, además estudiando el exe con mi editor hex, localicé el comienzo de la tabla de importación.. la lista de mi image_import_descriptors, 8 de ellos, seguidos por 14h bytes nulos... terminando el descriptor :D yippee!! simplemente usa ProcDumps PE Editor, edita la estructura del directorio, dirige la tabla de importación al real... para este programa, era 528ed8, - la imagebase hace 128ed8 ...

Bien, ejecutándolo de nuevo con LOADER32, comprueba la dirección 51b168, sí, está escrito encima con la dirección lineal de la función del api correcta... grande... a medio camino de el ...


Algo de código de nuevo ...


;------------------------------------------------------------------------------
; R!SC's dodgy call fixer for 'newer' SecuROM
; (c) august 27th 1999 risc@notme.com
;
; tasm32 /mx /m3 /z /q call_fix
; tlink32 -x /Tpe /aa /c call_fix,call_fix
;
; copia y pega el código dentro del ejecutable comprimido de securom.. 
;Yo prefiero la cabecera de pe ...   
; Rompe en jmp eax (en el código de securom, jmp orig_entry_point)  
; recodifica el 'jmp eax' en el código de la llamada [securom] a jmp ebx  
; i3here on, faults on  
; copia el código a una zona de memoria vacía.. m 400300 l 60 530000, r eip 530000, ejecútalo :0
;------------------------------------------------------------------------------

.486P
.Model Flat

.code
main:
    call    @1  ; por favor excusa mi primer esfuerzo del tipo un código reubicable
@1:
    pop ebx
    mov esi, ebx
    add ebx, offset here-offset @1  ; devuelve dirección desde jmp [5ac228]
    add esi, offset boring-offset @1
    mov edx, 401000h
    mov ecx, 51b000h-401000h    ; mi iat empieza en 51b000, así que el código termina ,espero, antes de él
search_loop:
    cmp [edx], 0c22815ffh   ; busca modelo para llamada [005AC228]
    jne try_again
    cmp word ptr [edx+4],005ah  ; -
    jne try_again
    
    lea eax, [edx+6]        ; consigue la dirección que será empujada a la pila
    pushad
    push eax
    ;jmp dword ptr [5ac228h]
    db 0ffh,25h,28h,0c2h,5ah,0  ; jmp blah..

here:                   ; k, retornamos aquí desde el código de securom, la dirección del api está en EAX
    mov edx, 51b000h    ; comienzo de la dirección de mi *real* IAT, primer tronco..
search_iat:
    cmp [edx],eax
    jz  got_match
    inc edx
    cmp edx, 51b2a0h
    jne search_iat
    pop eax         ; seguridad, si no puede encontrar una pareja para lo que está en EAX en nuestro IAT
    popad
    int 03          ; la pareja no fue encontrada, rompe en int 03, apunta la dirección en EDX
    jmp try_again   ; y arréglalo a mano..
got_match:
    mov [esi+4],edx ; guardando la direc de la importación de la dirección conseguimos una pareja para
    pop eax
    popad
    mov eax, [esi+4]    ; recupera la dirección de la importación en nuestro IAT
    mov [edx+2], eax    ; pégalo encima de 005ac228 en la llamada [securom]
try_again:
    inc edx
    mov [esi],edx   ; guarda la última dirección que estaba en EDX.. (en caso de algún problema..)
    dec ecx
    jne search_loop
    int 03
    nop
boring:
end main
;------------------------------------------------------------------------------

  
  

Correcto, compílalo, edítalo en hex y edita en hex el exe de SecuROM comprimido, corta y pega el código en alguna parte del fixer de la llamada en el ejecutable securom.. Yo escogí el offset 300h del archivo, en la cabecera del pe ...

Ejecuta tu loader que rompe en el punto de salida de securom. mueve el código desde la cabecera del pe a alguna otra parte si no.. m 400300 l 100 530000 , r eip 530000 ...

Pon un bpx en JMP [005AC228], y ejecútalo. cuando consigas una interrupción, remonta en el jmp, y desplaza tu ventana del código hasta que veas algún código así ...


015F:0059F15E  83C408              ADD     ESP,08
015F:0059F161  61                  POPAD
015F:0059F162  8B45F4              MOV     EAX,[EBP-0C]
015F:0059F165  8BF0                MOV     ESI,EAX
015F:0059F167  8B06                MOV     EAX,[ESI]
015F:0059F169  5F                  POP     EDI
015F:0059F16A  5E                  POP     ESI
015F:0059F16B  5B                  POP     EBX
015F:0059F16C  8BE5                MOV     ESP,EBP
015F:0059F16E  5D                  POP     EBP
015F:0059F16F  FFE0                JMP     EAX

  

Entonces cambia el jmp eax que sería JMP a la llamada de API, a JMP EBX... para saltar atrás a nuestra rutina de llamada amañada

:a 59f16f
0137:0059F16F jmp ebx

bc*, i3here on, faults on, a causa de que queremos atrapar cualquier error, y softice romperá si golpea cualquiera de nuestras int 03's ...

Bien, de cualquier modo, ejecuta el código, y cruza tus dedos... Yo conseguí algunos errores, tres llamadas devolvieron direcciones erróneas, así que no podría encontrarlos en mi IAT, y dos llamadas causaron una caída... con faults on, softice cogió la caída, y todo lo que tuve que hacer fue mirar en la dirección de memoria al final de mi código, donde se almacena el contador de dirección, para ver qué llamada lo provocó ...

502bdd lo provocó, y después de arreglar eso, 50ce1c lo provocó, así que cuando lo ejecuté de nuevo, revisé aquéllas situaciones de memoria, reemplazando el FF 15 con CC 15 que detuvo el código encontrando el modelo de byte correcto, así deteniendo la caída, e investigando esas llamadas a mano ...

También rompió en este int 03 tres veces ...

int 03 ; la pareja no fue encontrada, rompe en el int 03, apunta la dirección en EDX jmp try_again ; y arréglalo a mano ...
Simplemente apunta la dirección en edx, y continúa, nosotros podemos investigar esas llamadas a mano también ...

Las llamadas malas eran 507c39, 50a324 50e0be, así que ejecuta el programa con tu interrupción en el punto de salida de securom, edita el eip para apuntar a una de esas llamadas arriesgadas, y remonta, rompe en el jmp eax... y busca la dirección del api en tu IAT a mano :D, después de que todas las llamadas estén arregladas, vuelca la memoria, pagein 400000 11b000 c:\callsfixed.dat .. copia y pega esto dentro del archivo que desempaquetaste con ProcDump, y arregla la dirección del IAT en la cabecera del pe ...

Cruza tus dedos, ejecútalo :D hey, funciona :P

¡Eso es! SecuROM es un poco más divertido esta vez por todas partes, pero si no fuera por Pedro y +Xoanon, yo dudo que este tutorial hubiera sido posible. En los tres días o así que este crack me llevó, yo aprendí mucho, y espero que, tú, aprendas algo de él también ...

R!SC 27th August '99





 

The cRACKER's n0tES esta dividido dentro de 12 partes principales:
 TX. Notas del Traductor
 00. INDICE
 01. Ensamblador para Cracker (CoRN2)
 02. SoftICE (Menú de arranque , Configuración, Comandos)
       
 1 Menú de arranque
       
 2 Configuración
       
 3 Comandos
 03. Breakpoints & Detalles de API de Windows
       
 1 Programas restringidos
       
 2 Cajas de diálogo
       
 3 Verificando el Tipo de unidad
       
 4 Acceso a archivos
       
 5 Acceso al Registro
       
 6 Cogiendo números de serie
       
 7 Accediendo a Tiempo & Fecha
       
 8 Generando ventanas
 04. Instrucciones de salto
 05. Instrucciones SET
 06. Tips & Trucos para Crackear
       
 1 Programas restringidos
       
 2 Dongles
       
 3 General
       
 4 Configuración de InstallSHIELD
       
 5 Protecciones con Archivo llave
       
 6 Pantallas molestas
       
 7 Límites de Runtime
       
 8 Serials
       
 9 Limites de Tiempo
       
10 Programas Visual BASIC
 07. Ventanas de Mensajes Para los Cracker
 08. Identificando funciones, Argumentos, y Variables (Rhayader)
 09. Los Sistemas de Protecciones de comerciales
       
 1 Armadillo
       
 2 C-Dilla SafeDISC
       
 3 SalesAgent
       
 4 SecuROM
       
 5 softSENTRY
       
 6 TimeLOCK
       
 7 VBox
 10. Bitmanipulation (Cruehead)
 11. Teoría general de Cracking
 12. FAQ

 +A. Cómo contactar conmigo
 +B. ¿Que es lo Nuevo?


 



The cRACKER's n0TES are Copyright 1998-2000 by TORN@DO of ID.
Todo los Derechos Reservados.
Traducido por
Revisado por X-Grimator.