Mayo 1998

"JavaScript Scrambler V1.11" ( Usando el crack del eco en la memoria )

PROGRAMA Win '95 Win Code Reversing  

  

por The Sandman 

 

 

Code Reversing Para Principiantes 

   

 

  Detalles del Programa Nombre del Programa: Scram111.zip Tipo de Programa: Protección de Código Javascript  Localización del Programa: Aquí o  Aquí Tamaño del Programa: 136K 

 

 
 

    Herramientas Utilizadas: Softice 3.2 – Depurador W32Dasm V8.9- Desensamblador  

 

Calificación

Fácil ( X )  Medio (   )  Difícil (    )  Profesional (    ) 

Hay una grieta, una grieta en todo . Así es como la luz penetra.

   


  JavaScript Scrambler V1.11 ( Usando el crack del eco en la memoria ) Escrito por The Sandman

 
 
 
 

Introducción

 
Al autor de esta utilidad se le puede localizar en:  http://members.tripod.com/~tier
 
El autor dice:

"Una utilidad para todos los programadores de JavaScript que están hartos del hecho de que su código pueda ser robado y sencillamente modificado. JavaScript Scrambler codificará cualquier script de código fuente hasta que resulte de casi imposible comprensión para otros."
 
 

Acerca de este sistema de protección

 
Se registra seleccionando la pestaña 'Register' .. Aquí se nos pedirá introducir:

(Nombre)          Name          :
(Nº de Serie)    Serial No    :

El código de registro está basado en lo que se tecleó para el nombre/identificador. También varía en tamaño (número total de caracteres alfanuméricos) pero normalmente toma la forma: 1234-567-89
 
Una vez registrado, el programa guarda el nombre y código de registro en:
 
C:\Windows\JSScrambler.ini y adopta la forma:

[JavaScript Scrambler]
Name=The Sandman
Serial Number=1936-957-76

No os aprovechéis y uséis mi clave de registro, sino una propia vuestra.
     
 

El ensayo 

     
Estaba yo leyendo una de los tutoriales de +ORC  hace unos días, cuando una de las partes me resultó especialmente interesante. +ORC explicaba brevemente los "Ecos en la Memoria" y los "Volcados de Memoria" en los que se podía acceder fácilmente a las contraseñas válidas (al ser generadas por el propio programa víctima) con tal de saber dónde hallarlas. Como la mayoría de los newbies, leí esa sección y seguí leyendo el resto del tutorial, sin darme apenas cuenta de que pocos días después iba a "descubrir" esta técnica por mí mismo y a usarla con éxito para hacer un crack muy interesante. Yo no había planeado usar esta misma técnica; tan solo se reveló como el "mejor" método para realizar este crack. En primer lugar, he aquí la sección del texto que leí en el tutorial de +Orc :-

"Dentro de casi todas las rutinas de protección, como ya habéis aprendido, hay un momento en que aparece en la pila el ECO de la auténtica, "correcta" contraseña o número. La localización de este ECO varía, pero la mayoría de las veces estará en una extensión +- 0x90 bytes de una de las direcciones donde residen los datos introducidos por el usuario. Esto se debe al volcado de datos que windows limita dentro de las herramientas que usan los proteccionistas... pero esta práctica está llamada a disminuir... especialmente tras esta lección :=)

El truco de esta lección: [constricción de datos], o "proximidad de la contraseña", se basa en la necesidad del proteccionista de no perder de vista la protección "trabajando" cuando él la ensambla. Él debe "ver" las relaciones entre los DATOS INTRODUCIDOS POR EL USUARIO, DATOS DEL USUARIO TRANSFORMADOS y la RESPUESTA NUMÉRICA CORRECTA ( en nuestra jerga el "Bingo")
 
Estas relaciones deben ser constantemente verifcadas para depurar el código de protección. La mayoría de las ocasiones residirán JUNTAS dentro de una pequeña área de la pila, permitiéndoles ser "vistas" en la MISMA ventana de observación. Casi siempre, por tanto, el ECO se "materializará" brevemente no muy lejos de una de las localizaciones de los DATOS INTRODUCIDOS POR EL USUARIO."
 
Para algunos de vosotros el texto señalado resultará un tanto incomprensible, porque nuestro conocimiento del Lenguaje Ensamblador puede ser aún escaso, por lo que permitidme que intente explicar lo que +ORC dice aquí y elaborarlo en cierta medida, a la vez.
 
Probablemente ya sabéis que los programas que usan una contraseña ('Password') o Número de Registro ('Registration Key') DEBEN ser capaces de comparar el introducido por nosotros con el que ÉL espera que hayamos introducido.  Bien, para hacer eso este programa-víctima (aquel que queremos crackear) o tiene el password correcto a mano (escondido dentro del propio programa), o debe generar uno él mismo, a fin de contrastarlo con el password/Clave de Registro que hemos introducido. ¿Está claro hasta aquí?

Aquí es donde se pone interesante...
 
Cuando se llega a la verificación de las Passwords/Claves de registro, normalmente el programa debe colocarlas ambas muy cerca en la memoria del ordenador y entonces efectúa la comprobación. En este punto NO nos importa el modo en que el programa-víctima crea o verifica estas Passwords/Claves de registro. Lo que importa es que si el programa puede "ver" ambas Passwords/Claves de registro, entonces nosotros podemos aprovechar este hecho y hacer que el programa NOS MUESTRE la Password/Clave de registro correcta, en lugar de decirnos que nuestra Password/Clave de registro era inválida.

Hasta ahora yo siempre he optado por el método 'Comparación y Salto' para quebrar programas, lo que significaba que siempre he hecho mis cracks después de que la víctima hubiera realizado el chequeo de validación para la Password/Clave de registro. Sería aquí donde yo "Nop"aría (90h) o cambiaría el salto condicional (p.e. Jnz) por otro forzoso ( ejemplo: Jmp).

Uno de los métodos de crackeo más populares para programas con Clave de Registro/Número de serie parece ser la realización de "Generadores de Claves" ( 'Key Generators' ), en los que el cracker crea un pequeño programa. Cuando el Usuario introduce un nombre en él, este programa genera una clave de registro válida que el Usuario puede utilizar posteriormente para registrar su programa-víctima.  Pero esto supone necesariamente entender cómo trabaja el programa-víctima; más en concreto, el algoritmo que usa para crear estos números de serie/registro. Como principiantes, esto puede parecer demasiado difícil, pero ¿y si hubiera un modo mucho "mejor" de hacer el mismo trabajo que estas Key Generators y requiriera muy poco conocimiento de Lenguaje Ensamblador?

Sigamos quebrando JavaScript Scrambler e incorporemos nuestro nuevo método de crackeo en la labor.

En primer lugar, hice un Listado de Desensamblado ( 'Dead Listing' ) de la víctima usando W32Dasm. Luego busqué en los Recursos de Cadenas de Datos (String Data Resources) por si aparecía algún 'Serial number', que no fue el caso. Pero encontré una curiosa referencia a la cadena "HEGRTZUINQYAXLPSWBMFOCDJKV,.- " que tiene aspecto de número de serie y que ahora sé positivamente que es usada por el programa durante el proceso de creación de números de serie válidos.

Como normalmente uso el método de crackeo 'Comparación y luego Salto' cuando el programa decide saltar bien a la rutina 'Beggar off' (expresión con la que nos referimos al mensaje que aparece cuando no conseguimos registrar el programa) o a la rutina 'Thank you for purchasing....' (Gracias por comprar...) hice doble click en la referencia a la cadena: "The serial number you entered, (El número de serie que ha introducido...)"

Esto me trajo entonces a este interesante bloque de código (explicaré brevemente por qué):-

* Referenced by a (C)onditional Jump at Addresses:00433F82(C),:00433FA0(C)
 
:0043406D B8A0414300          mov eax, 004341A0 ;"El número de serie
                                                ; que ha introducido era incorrecto"
:00434072 E86DB1FFFF          call 0042F1E4
:00434077 33D2                xor edx, edx
:00434079 8B832C020000        mov eax, dword ptr [ebx+0000022C]

Mirad. Hay dos sitios en la víctima (:00433f82 y :00433FA0 ) que deciden si el número de serie que pusimos es incorrecto, asi que vayamos a hallarlos. Por la localización de sus offsets están muy cerca el uno del otro..:)

¡ECHAD UN VISTAZO A ESTO!.  El proteccionista (término con el que se refiere al encargado de implementar las rutinas de protección del programa) ha mantenido todo su código junto; eso era más sencillo para él a la hora de probarlo y depurarlo, y, ciertamente, también hace más fácil nuestro "trabajo".

Lo que tenemos aquí son nuestros dos saltos condicionales a las rutinas 'Beggar off Cracker' . También tenemos la rutina que genera el archivo JSScramble.ini file para que cuando se determine que nuestro número de serie es correcto lo coloque allí junto con el Nombre de Usuario que introdujimos.

:00433F82 0F8EE5000000        jle 0043406D                ; Nos manda al mensaje Beggar off
:00433F88 8D4DF4              lea ecx, dword ptr [ebp-0C]
:00433F8B 8B55FC              mov edx, dword ptr [ebp-04] ; Localización de nuestro Nombre
                                                          ; de Usuario

:00433F8E 8BC3                mov eax, ebx
:00433F90 E81BFAFFFF          call 004339B0                             ; Genera nuestro Nº de Serie  
:00433F95 8B45F4              mov eax, dword ptr [ebp-0C]; apunta al nº de serie 'real'  
:00433F98 8B55F8              mov edx, dword ptr [ebp-08]
:00433F9B E8A0FBFCFF          call 00403B40
:00433FA0 0F85C7000000        jne 0043406D     ; Nos manda al mensaje Beggar off
                                               ; si el nº de serie es incorrecto. 
                                               ; Si no, crea un archivo .ini
                                               ; y guarda el Nombre de Usuario
                                               ; y Nº de serie en él.
 
:00433FA6 C6054859430001      mov byte ptr [00435948], 01
                                    |
:00433FAD B9D4404300          mov ecx, 004340D4 ; El nombre de nuestro archivo .ini
                                                ; es JSScramble.ini
:00433FB2 B201                mov dl, 01
:00433FB4 A1D4F34200          mov eax, dword ptr [0042F3D4]
:00433FB9 E872B4FFFF          call 0042F430     ; Crea el archivo .ini
:00433FBE 8BF0                mov esi, eax
:00433FC0 8B45FC              mov eax, dword ptr [ebp-04]
:00433FC3 50                  push eax
 
:00433FC4 B9EC404300          mov ecx, 004340EC ; Guarda "Name=" en el
                                                ; archivo .ini
 
:00433FC9 BAFC404300          mov edx, 004340FC
:00433FCE 8BC6                mov eax, esi
:00433FD0 E8EFB4FFFF          call 0042F4C4     ; Guarda en el archivo .ini nuestro
                                                ; Nombre/identificador de Usuario

:00433FD5 8B45F8              mov eax, dword ptr [ebp-08]
:00433FD8 50                  push eax
 
:00433FD9 B91C414300          mov ecx, 0043411C ; Guarda "Serial Number="
                                                ; en el archivo .ini
 
:00433FDE BAFC404300          mov edx, 004340FC
:00433FE3 8BC6                mov eax, esi
:00433FE5 E8DAB4FFFF          call 0042F4C4     ; Guarda en el archivo .ini
                                                ; nuestro Nº de serie
:00433FEA 8BC6                mov eax, esi
:00433FEC E85FEDFCFF          call 00402D50
 
:00433FF1 B834414300          mov eax, 00434134 ; Muestra el mensaje'Thank you...'
:00433FF6 E8E9B1FFFF          call 0042F1E4
 

Si, como yo, "nopeáis" (90h) los dos saltos condicionales en las direcciones de memoria:-
 
:00433FA0     0F85C7000000        jne 0043406D
:00433F82     0F8EE5000000        jle  0043406D

entonces cuando metáis vuestro falso Nº de serie, el programa lo aceptará y procederá a crear el archivo SScramble.ini con vuestro nombre/identificador, junto con vuestro nº de serie falso. Me apresuro a añadir aquí que esto NO hace que el programa quede registrado, ya que cuando se ejecuta el programa de nuevo, carga el Nº de serie desde el archivo .ini y lo comprueba para ver si, en efecto, el número es correcto, cosa que no es así, por lo que considera que aún está no-registrado. Buen intento, no obstante. De hecho, algunos programas guardan el Nº de serie "bueno" en el archivo .ini, en lugar del falso, pero no es este el caso..:(  Volvemos a la casilla de salida.

Si fuéramos a continuar con este plan de ataque, ahora tendríamos que buscar en la víctima y desactivar la comprobación que hace de nuestro número falso cuando el programa comienza a ejecutarse, pero ¿no se está complicando esto un poco? Al fin y al cabo hay modos mucho mejores de enfrentarse a este programa.

Fue en ESTE momento cuando lo que decía +ORC sobre "Ecos en la Memoria" de pronto empezó a cobrar sentido. Sentía algo diferente acerca de este programa, lo cual me hizo pensar de nuevo en mi plan de ataque a este sistema de protección.
 
En Softice fui paso a paso recorriendo el código de arriba, observando qué sucedía con mi falso número, mientras todavía podía ver el número "bueno" formándose carácter a carácter. Allí estaba yo observándolos a los dos al mismo tiempo en una pequeña pantalla de softice.

Echemos otro vistazo a aquella rutina 'Beggar off cracker' :-
 
* Referenced by a (C)onditional Jump at Addresses:00433F82(C),:00433FA0(C)
 
:0043406D B8A0414300          mov eax, 004341A0 ; "El Número de serie
                                                ; que ha introducido es incorrecto"
:00434072 E86DB1FFFF          call 0042F1E4
:00434077 33D2                xor edx, edx
:00434079 8B832C020000        mov eax, dword ptr [ebx+0000022C]
:0043407F E86868FEFF          call 0041A8EC     ; Crea una messagebox
:00434084 33D2                xor edx, edx
:00434086 8B8330020000        mov eax, dword ptr [ebx+00000230]

Está creando un cuadro de diálogo(messagebox) en la pantalla, que nos dice que nuestro número de serie es incorrecto, y si miráis este mensaje en la memoria, veréis que termina con un byte '0', lo que significa para la rutina del messagebox que es el final del mensaje. Si miráis al número de serie "bueno" en la memoria, veréis que ese también termina con este byte '0'. ¿Podéis sentirlo ya?

El número de serie bueno que está guardado en la memoria es para el ordenador como el texto del mensaje 'beggar off cracker', de modo que ¿por qué no hacer que la rutina de este mensaje 'Beggar off cracker' muestre el número de serie bueno en lugar de mandarnos a paseo?

Todo lo que necesitamos hacer es cargar la dirección de memoria del Nº de serie bueno, en lugar del mensaje 'Beggar off'. Así que mi primer intento consistió en cambiar la dirección de memoria del mensaje 'beggar off' para que "apuntase" a la dirección del Nº de serie bueno. Esto se logró cambiando:

:0043406D          mov eax, 004341A0 ; ==>Localización del mensaje 'beggar off'.
 
POR

:0043406D          mov eax, 007A8594 ; Ahora apunta al Nº de serie bueno.
 
Esto funcionó una vez y el Nº de serie bueno se mostró en lugar del texto del mensaje 'Beggar off' , pero al ejecutar el programa otra vez, tan solo apareció basura en su lugar.

Al ejecutar Softice me di cuenta de que la dirección de memoria del número bueno así como el introducido por mí eran guardados esta vez ¡en una dirección de memoria diferente! ¿Qué pasa? Luego pensé: "Bien, si esto sucede ¿cómo sabe entonces el programa dónde tiene que ir a buscar el nº de serie bueno, si su dirección de memoria cambia siempre porque hay otros programas en ese momento ocupando memoria?"

Examinando otra vez esta sección del código desde Softice, de repente apareció la respuesta que buscaba.
:00433F82 0F8EE5000000        jle 0043406D     ; Nos manda al mensaje Beggar off
:00433F88 8D4DF4              lea ecx, dword ptr [ebp-0C]
:00433F8B 8B55FC              mov edx, dword ptr [ebp-04]
:00433F8E 8BC3                mov eax, ebx
:00433F90 E81BFAFFFF          call 004339B0
 
:00433F95 8B45F4              mov eax, dword ptr [ebp-0C]    ; ¡Esta instrucción
                                                             ; señala SIEMPRE a la
                                                             ; dirección de memoria
                                                             ; del nº de serie bueno!
                                                         
:00433F98 8B55F8              mov edx, dword ptr [ebp-08]
:00433F9B E8A0FBFCFF          call 00403B40
 

Por tanto, si la instrucción mov eax, dword ptr [ebp-0C] sabe siempre en qué lugar de la memoria está el número "bueno", ¡por qué no usarla en lugar de mov eax, 007A8594 y rellenar ahora con NOPs (90h) los espacio libres que se han creado al usar una instrucción que precisa unos cuantos bytes menos que la que acabamos de reemplazar!

 
Así que eso fue lo que hice y ¡funcionaba!. Por lo tanto, ahora si se mete un número de serie incorrecto el programa os dice lo que deberíais haber escrito. ¡Mucho mejor que nuestro viejo mensaje ‘beggar off’..:)! Ahora tenemos el programa no solo crackeado sino que también lo hemos convertido en nuestro propio 'Serial Key Generator'.
 
Misión Cumplida.....
 
 

El 'Crack' 

 
Cargad jsscram.exe en vuestro editor hexadecimal y
SEARCH (BUSCAD) la siguiente cadena hexadecimal: "EB35B8A0414300"

00033450 83F80100 008B10FF 52508B93 EC010000 ........RP......
00033460 8B83E801 0000E845 D2FFFFEB 35B8A041 .......E....5..A
00033470 4300E86D B1FFFF33 D28B832C 020000E8 C..m...3...,....

Ahora REPLACE (SUSTITUID) los siguientes bytes RESALTADOS:

00033450 83F80100 008B10FF 52508B93 EC010000 ........RP......
00033460 8B83E801 0000E845 D2FFFFEB 358B45F4 .......E....5.E.
00033470 9090E86D B1FFFF33 D28B832C 020000E8 ...m...3...,....
 

O, si lo preferís, podéis usar este "crack loader" (cargador), que he hecho usando PATCH ENGiNE V2.0 – de RTD. Gracias, muchachos..:)
 
code            segment byte public
  assume cs:code, ds:code

  org 100h
start:
                mov     dx,offset logo    ; Mostrar vuestro logo
                call    write             ; Escribir el mensaje

                call    open_file         ; Adivinadlo...
                mov filehandle,ax         ; Poner el nombre del archivo en "filehandle"
                mov     dx,offset fsize
                call    write             ; Escribir el mensaje
                call    check_size        ; Comprobar el tamaño real del archivo
                mov     di,offset data    ; Apuntar di a la tabla de datos
                mov     si,offset ofs     ; Apuntar si a la tabla de desplazamientos
                mov cx,5                  ; Bucle de 5 repeticiones para cada byte cambiado
                mov     dx,offset crackfile
                call    write             ; Escribir el mensaje
 

crackit:
                push cx   ; Guardar cx
                call    seek_file         ; Buscar en el archivo
                call    read_file         ; Leer un byte y comparar
                call    seek_file         ; Buscar de nuevo (atrás)
                call    write_file        ; Escribir el byte
                add     si,4              ; Añadir 4 a si 2*sizeof(word)
                add     di,2              ; Añadir 2 a di 2*sizeof(byte)
                pop cx                    ; Recuperar cx
                loop crackit              ; Bucle Crackit
                mov     dx,offset cracksucc
                jmp     short goback
already_patched:
                mov     dx,offset alreadycrk
                jmp     short goback
size_mismatch:
                mov     dx,offset sizemismtch
                jmp     short goback
error:
                mov     dx,offset erroropen
goback:
                call    write             ; Escribir el mensaje
                call     close_file       ; Cerrar el archivo
                mov     ah,4Ch            ; Saltar de nuevo al sistema operativo
                int     21h
Write           proc    near
                push ax
                mov     ah,9
                int     21h               ; Mostrar la cadena
                pop ax
                retn
Write           endp
open_file       proc    near
                mov     ah,3Dh
                mov     al,2              ; abrir la función de archivo 3Dh
                mov     dx,offset filenaam
                int     21h
                jb      error
                retn
open_file       endp
 
close_file      proc near
                mov     ah,3Eh             ; cerrar la función de archivo 3Eh
                mov     bx,filehandle
                int     21h
                retn
close_file      endp

check_size      proc near
                mov     bx,ax
                mov     ax,4202h
                xor     cx,cx               ; Comprobar filelength longitud del archivo)
                xor     dx,dx
                int     21h
                jb      error
                cmp     ax, lowsize         ; (Lowbyte)
                jne     size_mismatch
                cmp     dx, highsize        ; (Highbyte)
                jne     size_mismatch
                retn
check_size      endp

read_file       proc near
                mov     ah,3fh
                mov     bx,filehandle        ; Leer la funcción de archivo 3Fh
                mov     cx,1
                mov     dx,offset readbyte
                int     21h
                mov ah,readbyte
                cmp     [di],ah              ; Comparar los bytes parcheados
                jne     already_patched
                jb error
                retn
read_file       endp

write_file      proc near
                mov     ah,40h
                mov     bx,filehandle
                mov     cx,1                  ; Escribir la función de archivo 40h
                mov     dx,di
                inc dx
                int     21h
                jb  error
                retn
write_file      endp

seek_file       proc    near
                mov     ah,42h
                mov     al,0
                mov     bx,filehandle          ; Mover el archivo al puntero de la funcíon 42h
                mov     dx,[si]
                mov cx,[si+2]
                int     21h
                jnc  here
                jmp error
here:
                retn
seek_file       endp
 

filenaam        db      'JSSCRAM.EXE', 0
filehandle dw 0
lowsize         dw      62976
highsize        dw      3
readbyte        db      0

logo            db '[PATCH FOR [FILEIN] GENERATED BY THE SANDMAN', 0Dh, 0Ah
                db      'þ OPENiNG FiLE : ','$'
fsize           db      'OK!',0Dh,0Ah,'þ CHECKiNG FiLESiZE : $'
crackfile       db      'OK!',0Dh,0Ah,'þ CRACKiNG FiLE : $'
cracksucc       db      'OK!',0Dh,0Ah,'þ PATCH SUCCESSFULL!',0Dh,0Ah,'$'
alreadycrk      db      'SJiT!',0Dh,0Ah,'þ FiLE ALREADY PATCHED OR'
                db      ' DiFFERENT!',0Dh,0Ah,'$'
sizemismtch     db      'SJiT!',0Dh,0Ah,'þ FiLE iS PACKED OR WRONG'
                db      ' VERSiON!',0Dh,0Ah,'$'
erroropen       db      'SJiT!',0Dh,0Ah,'þ CAN', 027h,'T OPEN FiLE'
                db      '!!',0Dh,0Ah,'$'

ofs             dw 13421 , 3 , 13422 , 3 , 13423 , 3 , 13424 , 3
                dw  13425 , 3

data            db 184, 139 , 160, 69 , 65, 244 , 67, 144
                db  0, 144

code  ends

  end start
 
 
 

Notas Finales 

 
Puede que este programa esté entre los básicos, pero yo aprendí una barbaridad sobre crackear programas que se registran con una clave y, lo que es más importante, sobre el eco en la memoria de las passwords/números de serie, del que podemos obtener muchas ventajas.

 
Una vez hube localizado la dirección de memoria donde el programa genera el número correcto, lo comprobé poniendo un punto de interrupción con Softice: bpm (break point on memory access RW) en este área para confirmar que esta era el área que el programa usa y no una que pudiera ser usada para confundirnos. Rápidamente me di cuenta de que era después del mensaje 'Beggar off cracker' cuando el programa borra la password de la memoria. Luego, todo lo que tenía hacer era verificar que el programa no alteraba la dirección base del registro ebp antes de tener la oportunidad de usar la instrucción  mov eax, dword ptr [ebp-0C]. No lo hizo, por lo que era seguro continuar y usar esa nueva instrucción.

No es necesario tener ningún conocimiento de ‘Direccionamientos de memoria directos o indirectos’ para descubrir por qué una instrucción se diferencia de otra, o que el registro ebp es usado por el programa como una regleta deslizante, donde simplemente determinando un desplazamiento desde la dirección base del registro ebp podemos especificar direcciones de memoria por encima y por debajo del mismo. El parcheado que hicimos, sustituyendo una instrucción de direccionamiento directo de memoria por una de direccionamiento indirecto, puede ciertamente marcar la diferencia en un crack.

Mis agradecimientos van para:

Fravia+ por proporcionar posiblemente los mayores recursos de conocimientos de Ingeniería Inversa en la Red.
 
+ORC por mostrame la luz al final del túnel.
 

Ob Duh 

 

 
Debo recordaros a todos/as que comprando y NO robando el software que usáis, conseguiréis que las compañías de software sigan produciendo un "mejor" software para el uso de todos/as y, lo que es más importante, sigan proporcionando mejores desafíos para quebrar sus a menudo débiles sistemas de protección. 
Si estáis buscando cracks o números de serie en estas páginas, estáis perdiendo el tiempo; intentad buscarlas en otros puntos de la Red, en Warez, Cracks, etc.


 

 Siguiente  Volver al Indice de Ensayos   Anterior 

 



 
Ensayo por:          The Sandman
Página Creada el 27 de mayo de 1998
Traducido por:     frantic  en junio de 2000
 

www.000webhost.com