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

Programa ACDSee 32 v2.41 W95 / W98 / NT 
Descripción Visor rápido y fácil de usar que soporta multitud de formatos 
Tipo Shareware de 30 días
Tipo de Tutorial [X]Original, []Adaptación, []Aplicación, []Traducción
Url http://www.acdsystems.com/es/products/acdsee
Protección Nag Screen
Dificultad 1) Principiante, 2) Amateur, 3) Aficionado, 4) Profesional, 5) Especialista 
Herramientas SoftIce v3.25, W32dasm v8.9, Hiew v6.04 
Objetivo Simular estar registrados.
Cracker SpOeK! 
Fecha 7 de Noviembre de 1.999 


INTRODUCCION

El programa funciona sin ningún contratiempo, salvo que al ver X imágenes sale una nag screen pidiéndonos que nos registremos pagando 40$ --> 6.000 ptas :( 
Pide un serial en función del Nombre introducido, así que vamos allá
AL ATAQUE
Bien, arrancamos el ACDSee32 en modo Explorador y al pinchar en Ayuda | Acerca de ACDSee... aparece un mensaje con la opción de registrarnos. Aparecen dos edit: en el primera se nos pide el nombre y en el otro el serial. Vamos a ver, ponemos cualquier cosa en el nombre y un serial. Aceptamos y ... sale una ventana con el texto: "Su nombre y código de registro no coinciden. Favor de checar (bonito palabro!) su nombre y código, e intente de nuevo. ¡Vaya!, que será? me huele que es la función MessageBoxA, pues nada, vamos a ver. Arrancamos con el SoftICE y ejecutamos el ACDSee32, nos vamos a la ventana de registro, volvemos a poner los datos y antes de dar a OK, entramos al SICE y ponemos un "bpx messageboxa". Salimos del SICE y damos a OK.
 
 
:0044A4D2 6800010000              push 00000100  ; Tamaño máximo del buffer
:0044A4D7 51                      push ecx  ; Dirección del buffer destino
:0044A4D8 52                      push edx  ; Identificador de la cadena
:0044A4D9 50                      push eax  ; Handle de la cadena

* Reference To: USER32.LoadStringA, Ord:01ABh
                                  |
:0044A4DA FF1584F54D00            Call dword ptr [004DF584]
:0044A4E0 8B8C2418010000          mov ecx, dword ptr [esp+00000118]
:0044A4E7 8B942414010000          mov edx, dword ptr [esp+00000114]
:0044A4EE 51                      push ecx ; Tipo de mensaje --> MB_OK
:0044A4EF 8B8C2410010000          mov ecx, dword ptr [esp+00000110]
:0044A4F6 8D442408                lea eax, dword ptr [esp+08]
:0044A4FA 52                      push edx  ; Titulo del mensaje
:0044A4FB 50                      push eax  ; Dirección de la cadena de texto
                                              cargada por LoadStringA
:0044A4FC 51                      push ecx  ; Handle de la ventana

* Reference To: USER32.MessageBoxA, Ord:01BEh
                                  |
:0044A4FD FF153CF64D00            Call dword ptr [004DF63C]
:0044A503 5F                      pop edi       ; Salimos aquí con F11
:0044A504 81C400010000            add esp, 00000100     ; Arregla la pila
:0044A50A C3                      ret           ; Salimos de la subrutina

 

 

Nos encontramos en el SICE, damos al F11 (Aparecemos en :44A503), miramos un poco el código hacia arriba y vemos que se llama a MessageBoxA y después se ha llamado a la función LoadStringA y un poco más arriba se ven varios NOP y un RET y ningún salto condicional. Bien, todos esos NOP están ahí para separar el espacio que queda entre varias rutinas. Vemos tres líneas más abajo de donde estamos un RET, esto nos hace suponer que estamos en una subrutina empleada para mostrar sólo que no hemos introducido el serial correcto. Entonces, vayamos al lugar desde donde se llama a la función en la que estamos, hay dos formas: avanzamos con el F10 hasta el RET o damos a F12 para salir de la rutina. Volvamos a la sección principal de código ;)

Por si a alguien le interesa, la estructura de la función LoadStringA es la siguiente:
 

int LoadString(
    HINSTANCE hInstance,        // handle of module containing string resource 
    UINT uID,                   // resource identifier 
    LPTSTR lpBuffer,            // address of buffer for resource 
    int nBufferMax              // size of buffer 
    );  

Claramente, lo que hace la función es cargar la cadena de texto con el mensaje de error desde el ejecutable, copiarla al buffer y añadirle el caracter nulo para que pueda ser pasada como parámetro.

Ahora nos hallamos en :4591B6. Ha llegado el momento de usar el buen W32dasm v8.9 ;)
 
 

SEGUIMIENTO ESTÁTICO Y ZEN CRACK
Bien, abrimos el W32dasm y le ponemos a desensamblar en ejecutable, como parece que tarda un poco puedes ir al baño :) 
Nos desplazamos hasta la posición :4591B6 y miramos el código que hay antes de llegar hasta ahí. Hummm, ta curioso }:) 
 
:00459198 EB1F                    jmp 004591B9

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00459171(C)
|
:0045919A A1B4035000              mov eax, dword ptr [005003B4]
:0045919F 8B0D78045000            mov ecx, dword ptr [00500478]
:004591A5 8B15B0035000            mov edx, dword ptr [005003B0]
:004591AB 6A00                    push 00000000
:004591AD 50                      push eax
:004591AE 51                      push ecx
:004591AF 56                      push esi
:004591B0 52                      push edx
:004591B1 E8EA12FFFF              call 0044A4A0 ; Nos dice que no es correcto
                                                  el serial
:004591B6 83C414                  add esp, 00000014


Subiendo desde :4591B6 vemos un CALL a 0044A4A0, que nos lleva a la rutina que nos dice que no es el serial válido. Siguiendo hacia arriba se ven varios parámetros pasados a la función mediante la pila y vemos que se llega a :45919A mediante un salto condicional y que no podemos haber venido por :459198 puesto que es un salto incondicional a otra parte del código. 
Vamos pues hacia :459171 
 

:0045916C EB4B                    jmp 004591B9

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00459129(C)
|
:0045916E 83F8FF                  cmp eax, FFFFFFFF  ; Compara eax con -1
:00459171 7527                    jne 0045919A  ; Si no son iguales salta a
                                                 serial incorrecto
:00459173 6AFA                    push FFFFFFFA  ; El serial es correcto
:00459175 56                      push esi  ; pero es antiguo


Vaya, vaya, seguro que si en :459171 cambiamos el "jne" por un "je" vamos a hacer maravillas, jejeje. Bueno, pues entonces ponemos un "bpx 459171" e intentamos registrarnos otra vez. Al pararse ahí el SICE hacemos "r fl z" con lo que el flag Zero pasa a ser el opuesto al de ahora y además ahora dice que no salta, perfecto. Salimos del SICE y dejamos que continue la ejecución del programa. A ver, a ver, ... Eh? cómo? qué dice? Cree que hemos introducido el código de una versión anterior del ACDSee32 y nos dice que mandemos un mail con nuestros datos a la casa de ACDSee32, y que entonces nos darán el nuevo serial. Pues que esperen!
 

Creo que ya me lo estoy imaginando: al comprobar el serial, el programa tiene dos opciones, si el serial es correcto se termina todo y nos lo agradece, sino es así, llega hasta :459171 y ahí decide si el serial que hemos metido es erróneo o si es correcto pero es para una versión anterior del programa. 
De acuerdo con esto, debe haber otro salto condicional anterior a este, que es el que hay que parchear. Al igual que antes, el salto tiene que hallarse en donde indica el W32dasm, en :459129. No puede ser :45916C puesto que es un salto incondicional, luego veamos que se esconde en :459129
 
 

SUBRUTINAS RECURRIDAS
Bien, entonces ya estamos bastante más cerca. Pongo aquí el trozo de código de :459129 para poder observarlo detenidamente ;) 
 
:00459121 E8FAEFFFFF              call 00458120  ; Comprueba el serial
:00459126 83F801                  cmp eax, 00000001 ; Es correcto?
:00459129 7543                    jne 0045916E  ; Si no lo es, salta a 45916E


Como sabemos, :459129 es un salto condicional pero lo curioso es lo que hay antes: UNA COMPARACIÓN CON 1. Joder, creo que esto está al rojo vivo. Normalmente, la lógica booleana que siguen en programación es algo tan sencillo como esto:
TRUE = 0x00000001
FALSE = 0x00000000

(No siempre, a veces es lógica inversa, o sea, todo lo contrario. Incluso puede que el programador sea un 0,0001% más avispado que sus colegas y diga que TRUE = 0x12345678 y FALSE = 0x90010203, o ponga las medidas de su novia o cualquier parida que se le ocurra, pero de estos suele haber pocos ;)

Entonces, vamos a poner un "bpx 459126" y vamos a intentar registrarnos de nuevo. Al hacerlo, aparecemos aquí con lo que hacemos un "r fl z" en :459129 y no llegamos a saltar hacia :45916E. Enhorabuena, estás registrado y sin soltar un puto duro, pero ... por qué sigue el mensaje de [No registrado] ahí arriba?

A ver, tranquilidad ante todo. Lo mejor es profundizar en el CALL 458120 de :459121. Así que vamos a investigar de dónde sale el valor de eax y que a nosotros nos sale con el valor 0x00000000. 

Para ello, lo mejor es ver el valor de retorno justo cuando vaya a alcanzar el RET y así ver donde se pone eax a 0. Ponemos un "bpx 459121" y cuando estemos sobre el CALL, F8, y luego ponemos un "bpr ss:esp ss:esp+3 R". Esto lo hago para que cuando vaya a leer la dirección de retorno se active el SICE (esto a veces puede no funcionar porque la rutina puede variar el valor de retorno dependiendo del resultado que haya obtenido, pero en este caso sabemos que tiene que volver por narices a :459126)
 

:0045813C 750C                    jne 0045814A  ; Salta a otra parte del 
                                                código

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00458194(C)
|
:0045813E 5F                      pop edi
:0045813F 5E                      pop esi
:00458140 5D                      pop ebp
:00458141 33C0                    xor eax, eax  ; Aquí hace eax = 0x00000000
:00458143 5B                      pop ebx
:00458144 83C424                  add esp, 00000024  ; Arregla la pila
:00458147 C20C00                  ret 000C  ; Retorno a 459126
SICE se para en :458147 dispuesto a leer la dirección de retorno. Poniendo un "bpx 45813C" vemos que la ejecución salta a :45814A, bien pues vamos a seguir el código un rato. Vamos traceando con F10 y fijándonos en donde se hace eax = 0x00000000, ..., hasta llegar a la siguiente porción de código: 



:00458172 E8391C0000              call 00459DB0  ; Comprueba el serial
:00458177 83C410                  add esp, 00000010
:0045817A 85C0                    test eax, eax  ; And entre eax, eax
:0045817C 740F                    je 0045818D  ; Salta si eax = 0
:0045817E 5F                      pop edi
:0045817F 5E                      pop esi
:00458180 5D                      pop ebp
:00458181 B801000000              mov eax, 00000001 ; Pon eax a 1!!!
:00458186 5B                      pop ebx
:00458187 83C424                  add esp, 00000024
:0045818A C20C00                  ret 000C  ; Vuelve :459126


Llegamos a :458172 donde seguramente se comprueba el serial, pero vemos que si en :45817C no saltasemos hacia :45818D como nos ocurre, veríamos que el ejecutable pone a 1 eax y retorna a :459126. Que curioso!, vale, vamos a comprobarlo: ponemos un "bpx 45817C" y al llegar ahí "r fl z" de forma que no saltemos.

Entonces vemos ¡que nos acepta la clave! y estamos registrados, pero ... joder, seguimos con lo de [No registrado]. Anda, resulta que si cierras el ACDSee32 y vuelves a ponerlo se para en :45817C al arrancar y varias veces, y si además haces que nunca salte desaparecen las nags screen al completo. Sólo hay una forma probarlo en serio. 
 
 

CRACKEANDO QUE ES GERUNDIO
Nos situamos en la línea de código :45817C en W32dasm y vemos en la barra de abajo que el Offset en el ejecutable es: 0x0005817C. Vale, abrimos el programa con el Hiew y nos desplazamos hasta la posición indicada y sustituimos:
75 por 74
Cerramos el Hiew y ejecutamos el ACDSee32 y ... ahora sí, perfecto. No aparece nada de [No registrado] y si vas a Ayuda | Acerca de ... verás que apareces con tu nombre, jejeje, si quisieras cambiarlo nada más fácil que trastear en el registro en:
[HKEY_LOCAL_MACHINE\Software\ACD Systems\ACDSee32S]
Y ahi en "Name" pones lo que te de la gana.
Como habrás supuesto, siempre que comprueba el serial pasa por nuestro crack. Usa todo el tiempo la misma subrutina ;)

sPOEK

[ 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, leeestoantes e infórmate de cómo puedes ayudarnos