| ESTUDIO COLECTIVO DE DESPROTECCIONES Última Actualizacion: 25/10/2001 |
Programa | Paint Shop Pro v6.02 | W95 / W98 / NT
Descripción | Utilidad edición gráfica
Tipo | Nag/Trial de 60 dias
Tipo de Tutorial | [X]Original, []Adaptación, []Aplicación, []Traducción
Url | http://www.jasc.com
Protección | Nag Screen. Time Limit 60 Dias
Dificultad | 1) Principiante, 2) Amateur, 3) Aficionado, 4) Profesional, 5) Especialista
Herramientas | SoftIce v4.05, Exescope v6.0
Objetivo | Eliminar Nag Screen y límite de tiempo.
Cracker | Mr.YelloW
Grupo | Whiskey Kon Tekila
Fecha | 30 de Julio de 2000
INTRODUCCION
Paint Shop Pro es un conocido programa de edición gráfica, el cuál siempre se ha distinguido por utilizar en sus versiones de evaluación un Nag Screen. Este tutorial pretende explicar otra forma de eliminar este odioso Nag a través de los mensajes de windows.
AL ATAQUE
La principal peculiaridad de la protección de este programa es que no es tan sencillo como eliminar la llamada a la creación del dialogo y seguir "palante". Esto se deba pobablemente a que después de pulsar el botón OK del Nag, se ejecutan algunas determinadas funciones vitales para el buen funcionamiento del programa. Sin embargo, hay un pequeño problema, dicho botón no existe, solo es un dibujo. Lo que el programa realmente hace es verificar que la pulsación del ratón se hizo en un area determida. Entonces, sino tenemos más pelotas que pulsar el dichoso botoncito, dejemos que el programa lo haga por nosotros ;) Os preguntareis como es posible esto. Pues muy sencillo, toda la comunicación entre el sistema operativo y los dialogos se realiza a través de mensajes. Cada dialogo tiene su propia pila de mensajes que atenderá a medida que los vaya recibiendo. De esto se encarga la función de dialogo que tiene asociada toda ventana. Por ejemplo, cuando se pulsa una tecla, windows le comunica al dialogo que se ha pulsado una tecla, y el código del programa actuará en consecuencia. De modo que basándonos en este funcionamiento, podemos generar un mensaje de pulsación del botón izquierdo del ratón sobre una determinada ventana en una determinada coordenada, sencillo verdad? ;) Analicemos que funciones del núcleo nos permiten hacer esto. Por un lado tenemos la función SendMessage y por el otro PostMessage. La principal diferencia entre estas dos funciones es que la primera funciona de forma síncrona y la otra de forma asíncrona. Ahora en cristiano, la primera no devuelve el control hasta que no se tenga la certeza de que el mensaje ha llegado y se ha procesado correctamente. Sin embargo, PostMessage envía el mensaje, pero no hay ningun tipo de garantía de que la ventana lo reciba y lo procese. En este caso voy a utlizar la función PostMessage, pero mas adelante explicaré mis razones. Los prototipos de ambas funciones son iguales, de modo que la siguiente explicación sirve para las dos. LRESULT WINAPI SendMessageA (HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); BOOL WINAPI PostMessageA (HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); El primer parámetro corresponde al manejador de la ventana al que se quiere enviar el mensaje, en este caso sería el manejador de la ventana del Nag. El segundo parámetro se refiere al tipo de mensaje que se quiere enviar. Una muy pequeña lista de los mensajes mas usados sería : WM_CHAR, WM_COMMAND, WM_CREATE, WM_DESTROY, WM_LBUTTONDOWN, WM_PAINT, WM_QUIT, WM_SIZE, WM_TIMER, ........... En nuestro caso, el mensaje que debemos enviar será el de WM_LBUTTONDOWN. El resto de parámetros son utilizados como parámetros, valga la redundancia, por los mensajes. Es decir, estas variables pueden contener los caracteres de la teclas pulsadas, las coordenadas del ratón, los keycodes, .... su contenido varía en función del tipo de mensaje. Aqui deberiamos poner las coordenadas de la posición del botón OK para que el programa reconozca que se ha pulsado sobre este botón. El código del mensaje WM_LBUTTONDOWN es 201h. Esto se puede ver en cualquier compilador para windows, o incluso en el propio softice escribiendo: ?WM_LBUTTONDOWN . Las coordenadas se pasan a través del parámetro lParam, donde las coordenadas X e Y estan en la parte baja y alta respectivamente de la variable de 32 bits. Bien, ahora que esta presentada la teoría, vayamos al tema. Hay tres grandes preguntas que deberiamos hacernos antes de empezar. ¿Cuando debemos mandar el mensaje? ¿Cual es el handle de la ventana? ¿Cuales son las coordenadas del botón? A la primera pregunta podría contestar que inmediatamente despues de la creacion de la ventana. Pero aqui viene el dilema entre utilizar una llamada síncrona o asíncrona. Si enviamos un mensaje síncrono, recibirá el mensaje inmediatamente, pero tendrá el resultado que nosotros deseamos? Quizas deberiamos esperar un poco más antes de enviarlo para que pueda ejecutar otra serie funciones. Con las puebas que yo realicé llegué a la conclusión de que este sistema no funcionaba correctamente, de modo que opté por los mensajes asíncronos, dando así un margen para que atienda el mensaje. Para buscar la función donde se crea el Nag podriamos empezar poniendo un breakpoint en la API SetTimer, ya que si nos fijamos, hay una temporización de unos segundos. Si hacemos esto, el programa se interrumpe justo depues de aparecer el Nag, en 770F1Fh. Si continuamos la ejecucion paso a paso, y llegamos a una instruccion RET, salimos a la direccion 653814h. * Reference To: MFC42.Ordinal:09BE, Ord:09BEh | :00653802 E89B771E00 Call 0083AFA2 :00653807 8BCE mov ecx, esi :00653809 E8E71EDBFF call 004056F5 :0065380E 56 push esi :0065380F E87D32DBFF call 00406A91 :00653814 83C404 add esp, 00000004 <-- Estamos aqui * Reference To: MFC42.Ordinal:1926, Ord:1926h | :00653817 E8207A1E00 Call 0083B23C Ahora hagamos la prueba de ejecutar los call de más arriba a ver que pasa. Y bingo!! hemos dado con la función que genera el Nag en la dirección 65380Fh. Ahora solo nos queda examinarla mas detenidamente. Traceamos el interior del call hasta llegar a la función que carga la imagen y crea el Nag Screen. Esto se realiza en el siguiente codigo. :00770EC8 E8A534C9FF call 00404372 ;Aqui se carga la imagen y crea la ventana. :00770ECD 85C0 test eax, eax ;Si es diferente de cero continua normalmente. :00770ECF 7519 jne 00770EEA :00770ED1 8B0DD48C9300 mov ecx, dword ptr [00938CD4] :00770ED7 3BCF cmp ecx, edi :00770ED9 7407 je 00770EE2 :00770EDB 8B11 mov edx, dword ptr [ecx] :00770EDD 6A01 push 00000001 :00770EDF FF5204 call [edx+04] * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00770ED9(C) | :00770EE2 893DD48C9300 mov dword ptr [00938CD4], edi :00770EE8 EB0F jmp 00770EF9 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00770ECF(C) | :00770EEA A1D48C9300 mov eax, dword ptr [00938CD4] :00770EEF 8B4820 mov ecx, dword ptr [eax+20] :00770EF2 51 push ecx ;Aqui se obtiene el manejador de la ventana. * Reference To: USER32.UpdateWindow, Ord:0291h | :00770EF3 FF1524359900 Call dword ptr [00993524] El mensaje se puede enviar al final del código de esta función, ya que precisamente hay un hueco vacio, en la dirección lineal 770F4Fh. Ya sabemos cuando mandar el mensaje, y cual es el handle de la ventana. Ahora nos queda saber las coordenadas correctas del cursor del ratón dentro del dialogo para que la pulsación sea correcta. Para ello debemos encontrar el código que trata las pulsaciones. Si nos fijamos en el cursor cuando se coloca sobre el botón, este se convierte en un reloj impidiendo que pulsemos sobre este. Esta rutina tiene que estar ligada de alguna manera con algun temporizador. De modo que vamos a colocar un breakpoint sobre la función KillTimer. Esto nos lleva a este código: :00772220 8B442404 mov eax, dword ptr [esp+04] :00772224 56 push esi :00772225 83F807 cmp eax, 00000007 :00772228 8BF1 mov esi, ecx :0077222A 0F8588000000 jne 007722B8 :00772230 A1D48C9300 mov eax, dword ptr [00938CD4] :00772235 8B5620 mov edx, dword ptr [esi+20] :00772238 8B4874 mov ecx, dword ptr [eax+74] :0077223B 51 push ecx :0077223C 52 push edx * Reference To: USER32.KillTimer, Ord:0195h | :0077223D FF15C8349900 Call dword ptr [009934C8] ;Aqui se mata el temporizador. :00772243 A1CC8C9300 mov eax, dword ptr [00938CCC] ;Prestar atencion a esta variable. :00772248 85C0 test eax, eax :0077224A 7553 jne 0077229F ; En caso de que valga cero se pone a 1. :0077224C 57 push edi * Possible StringData Ref from Data Obj ->"5000" | :0077224D 6800B79200 push 0092B700 :00772252 C705CC8C930001000000 mov dword ptr [00938CCC], 00000001 La variable de la direccion 938CCCh indica si estamos dentro o no del tiempo de espera antes de poder pulsar sobre el botón. Para ver la relación entre esta variable y la rutina que verifica la posición del cursor dentro del dialogo, vamos a poner un breakpoint sobre esta variable. :bpm 938CCC R Ahora pulsamos sobre el dialogo. Existen dos rutinas. Una se ejecuta cada vez que se mueve el raton. La cual se utiliza para determinar que icono debe mostrar, por ejemplo durante el tiempo de espera. * Reference To: USER32.ScreenToClient, Ord:020Ah | :00772365 FF1508359900 Call dword ptr [00993508] :0077236B A1CC8C9300 mov eax, dword ptr [00938CCC] <------- Interrupcion :00772370 5E pop esi :00772371 85C0 test eax, eax :00772373 7525 jne 0077239A :00772375 8B542408 mov edx, dword ptr [esp+08] :00772379 8B442404 mov eax, dword ptr [esp+04] :0077237D 52 push edx :0077237E 8D4C2410 lea ecx, dword ptr [esp+10] :00772382 50 push eax :00772383 51 push ecx * Reference To: USER32.PtInRect, Ord:01EAh | :00772384 FF15F8349900 Call dword ptr [009934F8] ................................... ................................... ................................... La otra interrupcion solamente se produce cuando el cursor esta dentro del boton OK. Esto significa algo, vamos a analizar el codigo. :0077129E 56 push esi ; Coordenada Y :0077129F 8D54242C lea edx, dword ptr [esp+2C] :007712A3 57 push edi ; Coordenada X :007712A4 52 push edx :007712A5 FFD5 call ebp :007712A7 85C0 test eax, eax :007712A9 0F84C0000000 je 0077136F ;Este salto provoca la salida de la funcion :007712AF A1CC8C9300 mov eax, dword ptr [00938CCC] <------- Interrupcion :007712B4 85C0 test eax, eax :007712B6 0F848B000000 je 00771347 ;Este salto provoca la salida de la funcion :007712BC 8B35D48C9300 mov esi, dword ptr [00938CD4] De modo que esto verifica nuestra teoría, una de las condiciones es que la variable 938CCCh tiene que valer uno. Ahora hay que analizar la otra condicion. Si colocamos un breakpoint en 77129Eh, el programa pasa por aqui cada vez que se pulsa el botón izquierdo en cualquier parte de la ventana. Pero el resultado de la llamada a la funcion en 7712A5h es uno unicamente cuando el cursor esta sobre el botón. Debemos analizar los parametros que recibe esta funcion. Los registros ESI y EDI contienen las coordenadas de la pulsación sobre el botón OK. Ahora todo lo que deberiamos hacer es quedarnos con unas coordenadas correctas. Ya tenemos contestadas las TRES preguntas cruciales. Ahora solo queda meter el código que genera el mensaje. Como se ha dicho antes, esto lo vamos a hacer en la dirección 770F4Fh. :00770F4F 56 push esi :00770F50 8B35D48C9300 mov esi, dword ptr [00938CD4] :00770F56 8B7620 mov esi, dword ptr [esi+20] ;Cogemos el handle de la ventana. :00770F59 68C8005C01 push 015C00C8 ;Coordenadas Y | X (LPARAM) :00770F5E 6AFF push FFFFFFFF ;Este dato no afecta (WPARAM) :00770F60 6801020000 push 00000201 ;Mensaje WM_LBUTTONDOWN :00770F65 56 push esi ;Manejador ventana * Reference To: USER32.PostMessageA, Ord:01DEh | :00770F66 FF15DC349900 Call dword ptr [009934DC] :00770F6C 5E pop esi :00770F6D C705CC8C930001000000 mov dword ptr [00938CCC], 00000001 ;Anulamos el temporizador :00770F77 C3 ret Con esto seria suficiente para saltarnos el Nag. El mensaje es enviado, y el programa se lo traga inocentemente. }:-) Queda explicar un pequeño detalle acerca de este código: La llamada a la función PostMessageA. El codigo de las dll's se ubica en diferentes zonas de memoria dependiendo del S.O. u otro tipo de causas. De modo que no podemos hacer una llamada directa a la función. Tenemos dos soluciones: La primera consiste en llamar a las funciones GetModuleHandle y GetProcAddress para obtener la dirección de la función PostMessageA. O por otro lado, si el programa tiene la función PostMessageA en la lista de importaciones, podemos utilizar la dirección de la función en esta tabla de importaciones. En este caso el programa utiliza la función, de modo que va a ser mas sencillo. Ahora de lo que se trataría es de averigüar el puntero donde se guarda la dirección de la función PostMessageA. Yo lo he hecho al método tradicional, cogiendo un editor hexadecimal y entrando en la estructura de los descriptores de importación. Pero esto lo dejo como ejecicio para el lector ;) , aunque para no dejarlo muy tirado, voy a decir las direcciones donde esta la información más relevante. Sección .import: 98F000h Descriptor USER32.dll: 98F0B4h Puntero PostMessage: 9934DCh Bueno, ahora queda la parte mas mundana, quitar la limitación de tiempo y cambiar el dibujo de ese feo Nag Screen. Para quitar la limitación de tiempo colocamos un breakpoint sobre la función GetSystemTime. Esto nos lleva hasta la dirección 771CC0h donde se compara un número que presumiblemente podría ser el número de días que se esta utilizando el programa y el límite, que son 30 dias. cmp ESI,1E jle 771D0Ch Esto podria ser sustitudo por: mov ESI,1 jmp 771D0Ch Ya nos hemos quitado la limitación de tiempo, ahora solo queda cambiar la pantallita inicial. Si recordaís, había un sitio donde se cargaba la imagen del Nag de los recursos del programa. El código es el siguiente: :007714AA 68DC219200 push 009221DC :007714AF 687F010000 push 00000181 ; Identificador del recurso a buscar :007714B4 50 push eax * Reference To: KERNEL32.FindResourceA, Ord:00A3h | :007714B5 FF15341A9900 Call dword ptr [00991A34] :007714BB 8BF0 mov esi, eax :007714BD 85F6 test esi, esi :007714BF 7507 jne 007714C8 :007714C1 8B07 mov eax, dword ptr [edi] :007714C3 8BCF mov ecx, edi :007714C5 FF5070 call [eax+70] :007714C8 55 push ebp :007714C9 E8A28D0C00 Call 0083A270 :007714CE 8B4008 mov eax, dword ptr [eax+08] :007714D1 56 push esi :007714D2 50 push eax :007714D3 FF152C1A9900 Call dword ptr [00991A2C] :007714D9 8BF8 mov edi, eax :007714DB E8908D0C00 Call 0083A270 :007714E0 8B4008 mov eax, dword ptr [eax+08] :007714E3 56 push esi :007714E4 50 push eax * Reference To: KERNEL32.LoadResource, Ord:01C7h | :007714E5 FF153C1A9900 Call dword ptr [00991A3C] ; Carga del recurso Si utilizamos el Exescope para hurgar dentro de las tripas del programa, y nos adentramos en la sección de recursos, llegamos hasta una serie de mapas de bits en formato DIB. Entre ellas hay perro muy majo deborando un gato (que sádicos), el Nag Screen (181h) y la presentación sin botones (179h). De lo que se trata es de cambiar el numerito 181h por 179h, y todo esta arreglado. Como podeis comprobar no ha sido tan dificil. Simplemente es tener las ideas un poco claras, y yo no soy precisamente un buen ejemplo con mi lógica borrosa ;) Bueno, pues esto ha sido todo. Hasta el próximo tutorial, que no tengo ni idea cuando será. Gero arte.
[ 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