| ESTUDIO COLECTIVO DE DESPROTECCIONES Última Actualizacion: 25/10/2001 |
Programa | 3D Studio Max 3.0 | W95 / W98 / NT
Descripción | No me digas que no lo conoces!
Tipo | Programa de modelado 3D
Tipo de Tutorial | [X]Original, []Adaptación, []Aplicación, []Traducción
Url | http://www.autodesk.com
Protección | Mochila Sentinel con Temporizador
Dificultad | 1) Principiante, 2) Amateur, 3) Aficionado, 4) Profesional, 5) Especialista
Herramientas | SoftIce v4.0, IDA Pro, UltraEdit
Objetivo | Eliminar la necesidad de tener que usar la mochila xDDD
Cracker | Black Fenix
Grupo | http://kickme.to/wkt
Fecha | Septiembre del 2000
INTRODUCCION
E n este tutorial tratamos de nuevo las mochilas, el objetivo es el 3D Studio Max V3.0. He de decir que me ha defraudado bastante el sistema de protección, parece más una broma que no otra cosa. En menos de media hora puedes crackear el programa, es ridiculo, incluso he tardado mucho más en escribir este tutorial. Hasta se puede prescindir del SoftIce para crackear el programa, con sólo usar el IDA y un poco de inteligencia habriamos llegado al crack final. Me parece patético.He encontrado muchas aplicaciones shareware mejor protegidas y además sin que estas utilizen ningún tipo de mochila. Esto me lleva a pensar el dinero que gastán en mochilas, para luego proteger de esta manera, es extraño que tan preocupados que son ellos para el dinero, no se den cuenta de como lo están tirando. Me sentiría muy avergonzado si malgastara mi dinero en un software que está protegido de tal manera y además resulta tan caro. De nuevo se demuestra que no importa lo caro que sea un programa, la vagancia de los programadores (en este caso de Autodesk) se pone de nuevo de manifiesto. A veces intento dar una explicación al porqué de estas inofensivas protecciones,quizas son las prisas por sacar cuanto antes una nueva versión, o quizas no protegen mejor para que su software sea crackeado rápidamente y se convierta así en el más utilizado (curiosa técnica de marketing), no se, no entiendo el porqué... sólo se que alguien dijo: es una mala protección, entonces es un mal programa.
AL ATAQUE
- Bueno primero vamos a utilizar el metodo del trazado a lo retro, si no sabes de que va, mirate mi tutorial génerico sobre mochilas. Antes de comenzar sería bueno desensamblar el ejecutable , yo le he intentado desensamblar con el W32Dasm pero no funciona (el programa se ejecuta sólo antes de desensamblarse, como es posible? ), de todas maneras no importa ya que siempre disponemos del IDA, que en estos casos nunca falla :). Pues nada desensamblamos el archivo y guardamos el resultado para su posterior uso. Luego ejecutaremos el 3DMax, nos aparece la pantalla de inicio y posteriormente un mensaje de error que dice algo así: ' El bloqueo de hardware no está conectado o no es válido bla bla... ' Pulsa aceptar, bueno parece que no tenemos la mochila reglamentaria, pero esto tiene fácil solución, activamos el SoftIce y pones un breakpoint sobre la funcion MessageBoxA con: > BPX MessageBoxA - Ahora ejecutamos el 3DMax y veremos que el SoftIce se activa antes de mostrar el cuadro de error, pulsamos F12 para ir a la linea de código donde se llamó a MessageBoxA y veremos al así : 0046977C loc_46977C: ; CODE XREF: sub_469610+155j 0046977C call sub_5C3910 00469781 and eax, 0FFFFh 00469786 test eax, eax 00469788 jz short loc_4697FA 0046978A mov ecx, [esp+10h] 0046978E dec ecx 0046978F test ecx, ecx 00469791 mov [esp+10h], ecx 00469795 jg short loc_469742 00469797 test eax, eax 00469799 jz short loc_4697FA 0046979B mov eax, dword_5F3740 004697A0 test eax, eax 004697A2 jz short loc_4697B5 004697A4 push 1025h 004697A9 call sub_414DA0 004697AE push eax 004697AF call ds:KillTimer 004697B5 004697B5 loc_4697B5: ; CODE XREF: sub_4697A2 004697B5 xor ebx, ebx 004697B7 call edi 004697B9 mov eax, [eax] 004697BB push 0FFh 004697C0 lea ecx, [esp+18h] 004697C4 push ecx 004697C5 push 2 004697C7 push eax 004697C8 call esi 004697CA call edi 004697CC mov eax, [eax] 004697CE push 0FFh 004697D3 lea edx, [esp+118h] 004697DA push edx 004697DB push 0EA81h 004697E0 push eax 004697E1 call esi 004697E3 push 2010h 004697E8 lea eax, [esp+18h] 004697EC push eax 004697ED lea ecx, [esp+11Ch] 004697F4 push ecx 004697F5 push ebx 004697F6 call ebp -> Llama al cuadro de mensaje 004697F8 jmp short loc_4697FE -> y salta más abajo !! ESTAMOS AQUÍ !! 004697FA loc_4697FA: ; CODE XREF: sub_469788 y sub_469799 004697FA test ebx, ebx -> comprueba si EBX es 0 004697FC jnz short loc_46980B -> no, salta 004697FE 004697FE loc_4697FE: ; CODE XREF: sub_4697F8 004697FE call sub_403A00 -> llamada a una función 00469803 push 0 00469805 call ds:ExitProcess -> Sale del programa 0046980B -> el siguiente código sólo se ejecuta si se salta desde 4697FC 0046980B loc_46980B: ; CODE XREF: sub_4697FC 0046980B pop esi 0046980C pop ebp 0046980D pop edi 0046980E mov eax, ebx 00469810 pop ebx 00469811 add esp, 608h -> restaura la pila 00469817 retn -> y continua el programa 00469817 sub_469610 endp Bueno, examinando este código podemos comprobar como después de mostrar el mensaje de error, se nos desvia a mediante un salto incondicional a 4697FE, donde se termina la aplicación mediante la función del Kernel ExitProcess. Si miramos el código que nos ofrece el desensamblado del ejecutable, veremos que sólo hay dos maneras de esquivar la llamada a ExitProcess. La primera es pasar por el código en 4697FA, este código es referenciado por las líneas de código 469788 y 469799 tal y como nos indica el IDA. La segunda la encontramos por debajo del salto incondicional en la línea de código 46980B la cual es referenciada por la línea 4697FC.Esta última línea está por debajo de 4697FA, de lo cual se deduce que la única manera de esquivar el códigoque sale del programa es pasar por aquí. Como he dicho antes, la única manera de llegar aquí es mediante un salto en las lineas 469788 y 469799. Examinemos primero el salto en 469788 ya que es la primera referencia. 0046977C call sub_5C3910 00469781 and eax, 0FFFFh 00469786 test eax, eax 00469788 jz short loc_4697FA Parece sospechoso, se llama a una función y posteriormente se borra el word alto EAX mediante el AND, y se comprueba si EAX es igual a 0, si esto es así, se salta a la línea 4697FA, donde se encuentra nuestro test ebx,ebx. Probemos a invertir el salto y ver lo que sucede. Activemos el breakpoint a MessageBoxA, pulsamos g para seguir, el breakpoint surte efecto, pulsamos F12 y aceptamos, de nuevo estamos en SoftIce. Ponemos ahora un breakpoint sobre la linea 469788 con el siguiente comando del SoftIce: > bpx 469788 Desactivamos el bpx del MessageBoxA y pulsamos g para continuar el programa, este finalizará. Volvemos a ejecutarlo y estaremos de nuevo en SoftIce, delante de la linea 469788. Ahora la modificaremos con el siguiente comando: > a 469788 > jmp 4697FA > (pulsa enter y luego esc) Puedes ver com ha cambiado el código, ahora pulsa g para ver lo que sucede... Magia el programa funciona !! - Bueno, no te lo creas del todo, efectivamente el programa se inicia correctamente, puedes cargar y salvar archivos, pero...¿ Averigua lo que sucede después de que el programa este abierto durante cierto tiempo ? Pues lo que era de esperar, se comprueba de nuevo la mochila, y se nos informa con otro mensaje de error. Podriamos actuar de la misma manera que lo hemos hecho antes, pero se trata de variar un poco y aprender nuevas técnicas, o no? Si te fijas, veras que el programa siempre comprueba la mochila en el mismo intervalo de tiempo, vamos a medir este tiempo aproximadamente. Coge un cronometro y conometra hasta que aparezca el mensaje de error, no ejecutes ninguna orden, solo espera. Después de aproximadamente 5 minutos aparecerá el mensaje de error. Si lo compruebas varias veces verás que el intervalo de tiempo siempre es el mismo, aproximadamente 5 minutos. Por lo tanto es posible que el programa utilize un temporizador que se active cada cinco minutos y compruebe la mochila. !! Lo cual quiere decir que si pudieramos eliminar el temporizador, podriamos eliminar también la comprobación de la mochila e incluso hariamos que la aplicación se ejecutará más deprisa !! .Vamos a comprobarlo, primero necesitamos saber que funciones hay en windows para crear temporizadores. La única que yo conozco se llama SetTimer y tiene el siguiente formato: UINT SetTimer( HWND hWnd, // handle de la ventana donde se enviaran los mensajes del temporizador UINT nIDEvent, // Identificador del temporizador UINT uElapse, // tiempo de espera en milisegundos TIMERPROC lpTimerFunc // dirección del proceso que el temporizador ejecutará al alcanzar el tiempo de espera ); Bueno lo más importante aquí es el tiempo de espera (uElapse), este valor se pasa como seguno parámetro, por lo tanto lo encontraremos en la pila a partir de (esp->0xC), ya que los 2 argumentos + la dirección de retorno ocupan 4 bytes cada uno (4*3=0xC). Teniendo en cuenta esto, en vez de poner un simple bpx SetTimer, utilizaremos un breakpoint condicional que sólo se ejecutará cuando se intente crear un temporizador con el tiempo de espera que nosotros le especifiquemos. Como vamos a buscar un temporizador que se active a los cinco minutos, deberemos convertir los minutos a milisegundos (5 minutos son 60*5=300 segundos * 1000 = 300000) y el valor resultante a hexadecimal 3000000 en hexadecimal es 493E0. Por lo tanto el breakpoint quedará: > bpx SetTimer if (esp->C)==493E0 Pues nada, entra en el SoftIce y teclealo. Sal del SoftIce y ejecuta el 3DMax, modifica el salto como hicimos previamente y continua con pulsando g. Antes de que desaparezca la pantalla de inicio, veras que el breakpoint del SetTimer a surtido efecto, pulsa F12 para ver el lugar desde donde se llamó y verás lo siguiente: 004023A1 6A00 push 0 -> pasa NULL como función a ejecutar. 004023A3 68E0930400 push 493E0h -> Aquí estan los cinco minutos de espera !!! 004023A8 6825100000 push 1025h -> Identificador 004023AD 55 push ebp -> Handle de la ventana donde enviar mensajes 004023AE 896804 mov [eax+4], ebp -> guarda handle de la ventana 004023B1 FF1594755C00 call ds:SetTimer -> establece el temporizador 004023B7 8B0D40375F00 mov ecx, dword_5F3740 004023BD 8B4108 mov eax, [ecx+8] 004023C0 6800040000 push 400h 004023C5 6870795E00 push 5E7970h 004023CA 50 push eax 004023CB 8944241C mov [esp+1Ch], eax 004023CF E8EC280100 call sub_414CC0 004023D4 8B54241C mov edx, [esp+1Ch] Como puedes comprobar se trata sin duda alguna de nuestra función. Ahora solo debemos pensar como hacer para eliminar el temporizador. Podemos sustituir por NOPs la llamada a SetTimer, pero tambien deberiamos de eliminar los 4 PUSH previos para no alterar el estado de la pila y provocar un posible cuelgue. Bien entonces vamos a hacer un resumen de los cambios necesarios, primero el salto en 469788, para averiguar el offset usaremos el IDA, nos colocaremos en la dirección 469788 con el menu Navigate/jump to/Ask for Address e introduciremos 469788 luego iremos al menu Edit/Patch Program/Change Byte y allí se nos mostrará el offset del archivo que es 69788h (no cambies nada y pulsa cancel). Entonces en el offset 69788h encontraremos los bytes 7470 (que corresponden al salto jz short loc_4697FA) que cambiaremos por un salto incondicional (el opcode para un jmp es EB) por lo tanto quedará EB70. Y para el temporizador actuaremos de igual forma para los pushes y el call, quedando: Desde el offset 23A1h hasta el 23ADh sustituiremos todos los bytes por 90h (código del NOP) y desde el offset 23B1h hata el 23B6H sustituiremos todos los bytes por 90 (código del NOP). Resumen: Offset: / Bytes originales / Sustituir por: 23A1h / 6A 00 68 E0 93 04 00 68 25 10 00 00 55 / 90 90 90 90 90 90 90 90 90 90 90 90 90 23B1h / FF 15 94 75 5C 00 / 90 90 90 90 90 90 69788H / 74 70 / EB 70 Gracias a Alfredo10 por corregir un fallo tipográfico en el offset (parece ser que hay alguien que si lee esto, aunque sea por las malas :) ). Bueno esto es todo para los que busquen un crack rápido, pero nuestro propósito es aprender un poquito más.Lo siguente es sólo necesario para los que esten interesados en conocer algunos trucos más. Sabemos que el 3DMax utiliza una mochila tipo sentinel (mira en el CD y veras un archivo VXD con este nombre), vamos a utilizar otro de los metodos descritos en mi tutorial genérico sobre mochilas, el metodo 4 (anticiparse a la carga del VXD). Utilizaremos el EXE sin modificar, por lo que si ya has modifcado el EXE, deberás recuperarlo. Borramos todos los breakpoints que tengamos y establecemos un BPX condicional para capturar la carga del controlador sentinel.vxd con el SoftIce: > bpx CreateFileA if *(esp->4+4)=='SENT' el breakpoint surte efecto, estamos dentro de la función CreateFileA, comprobamos que efectivamente se va a cargar el driver sentinel.vxd con: > d *(esp+14) veremos SENTINEL.VXD en la ventana de datos del SoftIce.Pulsamos F12 para ejecutar la función y volver al código que llama a CreateFileA, veremos algo así: 005C3000 sub_5C3000 proc near ; C 005C3000 push 0 // prepara parametros para CreateFileA 005C3002 push 0 005C3004 push 3 005C3006 push 0 005C3008 push 0 005C300A push 0 005C300C push 5C2FE0h // dirección de la cadena "\\. \SENTINEL.VXD" 005C3011 call j_CreateFileA // llama a CreateFileA 005C3016 mov ecx, [esp+4] 005C301A cmp eax, 0FFFFFFFFh // comprueba que se devuelve un handle correcto, eax debe de ser <> a -1 005C301D mov [ecx], eax // guarda el handler en la posicon apuntada por ECX 005C301F jnz short loc_5C3028 // salta si el handle es válido 005C3021 mov ax, 1C0Bh // retorna un misterioso código de error 005C3025 retn 4 // y retorna 005C3028 005C3028 loc_5C3028: ; CODE XREF: sub_5C3000+1Fj 005C3028 mov ax, 1C00h // retorna otro misterioso código de error 005C302C retn 4 // y retorna 005C302C sub_5C3000 endp El código anterior intenta cargar el dispositivo virtual que controla la mochila. Según el funcionamiento de la función CreateFileA, si se pudo abrir el dispositivo, se retorna un valor diferente a INVALID_HANDLE_VALUE que es una constante del API de Windows que equivale a -1 (FFFFFFFFH). La rutina comprueba esta condicición en la línea 5C301A mediante la instrucción cmp eax,0FFFFFFFFh. Se guarda el handle, aúnque este no sea válido y se retorna el valor 1C0Bh si no se pudo abrir el dispositivo y 1C00h si se obtuvo un handle válido. Por lo tanto sabemos que esta función siempre devolverá uno de estos dos valores. Nuestro código de error que indica que todo va bien es el 1C00h. Si continuamos trazando hasta ejecutar el ret veremos algo así: 005C30B0 sub_5C30B0 proc near ; CODE XREF: sub_5C2D80+5p 005C30B0 sub esp, 4 005C30B3 push esi 005C30B4 mov esi, [esp+0Ch] 005C30B8 lea eax, [esp+4] 005C30BC push eax 005C30BD call sub_5C3000 -> Aquí se llama a la rutina anterior 005C30C2 mov [esi+6], ax -> guarda el código de error retornado 005C30C6 or al, al -> comprueba si AL = 0 005C30C8 jz short loc_5C30D9 -> salta si es 0 005C30CA or ah, ah -> comprueba si AH = 0 005C30CC jnz short loc_5C30FA -> salta si AH = 0 005C30CE or ax, 1C00h -> solo llegaráremos aquí en caso de que la llamada a 5C3000 retorne 1C0B, esto hace que AX valga 1C0B siempre 005C30D2 pop esi -> restaura la pila 005C30D3 add esp, 4 005C30D6 retn 4 -> y regresa con código de error 1C0Bh Si se pudo cargar el driver, se tomará el salto en 5C30C8 que nos llevará hasta aquí: 005C30D9 loc_5C30D9: ; CODE XREF: sub_5C30B0+18j 005C30D9 mov eax, [esp+4] -> carga Handle al dispositivo SENTINEL.VXD 005C30DD push esi -> empuja un parámetro que no sabemos aún que es 005C30DE push eax -> pasa handle de SENTINEL.VXD 005C30DF call sub_5C3030 -> llama a una función (ver más abajo) 005C30E4 mov eax, [esp+4] 005C30E8 push eax 005C30E9 call sub_5C3090 005C30EE mov ax, [esi+6] 005C30F2 or ah, ah 005C30F4 jnz short loc_5C30FA 005C30F6 or ax, 1C00h -> Otra vez el misterioso código de error 005C30FA loc_5C30FA: -> aquí sólo llegamos desde 5C30CC 005C30FA pop esi 005C30FB add esp, 4 005C30FE retn 4 Previamente se abrió el driver SENTINEL.VXD, por lo que es lógico pensar que este código enviará datos al driver y este a la mochila. La aplicación solo tiene una manera de comunicarse con el VXD y es mediante la función DeviceIOControl. La función DeviceIOControl tiene la siguiente forma: BOOL DeviceIoControl( HANDLE hDevice, // handle to device of interest DWORD dwIoControlCode, // control code of operation to perform LPVOID lpInBuffer, // pointer to buffer to supply input data DWORD nInBufferSize, // size of input buffer LPVOID lpOutBuffer, // pointer to buffer to receive output data DWORD nOutBufferSize, // size of output buffer LPDWORD lpBytesReturned, // pointer to variable to receive output byte count LPOVERLAPPED lpOverlapped // pointer to overlapped structure for asynchronous operation ); Si continuamos trazando dentro de las funciones veremos que nuestras predicciones se cumplen. Este es el código que verás al entrar en la función llamada en la linea 5C30DF: 005C3030 sub_5C3030 proc near ; CODE XREF: 5C30DF 005C3030 sub esp, 4 005C3033 push esi -> empuja ESI 005C3034 mov esi, [esp+10h] -> carga ESI de nuevo (esto no es necesario) 005C3038 push esi -> y lo vuelve a empujar a la pila 005C3039 mov word ptr [esi+6], 0FFFFh -> establece posición de memoria a FFFFh 005C303F call sub_5C2990 005C3044 lea eax, [esp+4] 005C3048 push 0 -> pasa NULL como puntero a una estructura para las operaciones asincronas 005C304A push eax -> pasa puntero a una variable que recibira el numero de bytes de salida en mi caso 9CF694 005C304B push 0 -> Tamaño del buffer de salida 0 005C304D xor eax, eax -> borra EAX 005C304F push 0 -> pasa NULL como buffer donde recibir datos 005C3051 mov ax, [esi+2] -> carga en AX el tamaño del buffer de entrada 005C3055 push eax -> tamaño del buffer de datos de entrada 005C3056 push esi -> Pasa el buffer con información 005C3057 mov eax, [esp+24h] -> Carga handler del VXD en EAX 005C305B push 1 -> código de operación 1 005C305D push eax -> pasa handle como primer argumento 005C305E call j_DeviceIoControl -> Envia comandos al dispositivo VXD, y retorna 1 si todo OK 005C3063 push esi -> pasa de nuevo el buffer de entrada 005C3064 call sub_5C2950 -> realiza muchos calculos sobre la estructura 005C3069 cmp word ptr [esi+6], 0FFFFh -> comprueba los datos del buffer de entrada 005C306F jnz short loc_5C3077 -> sino es igual salta 005C3071 mov word ptr [esi+6], 1C3Bh -> guarda 1C3B en el buffer de entrada 005C3077 loc_5C3077: ; CODE XREF: 5C306F 005C3077 mov ax, [esi+6] -> guarda en AX datos del buffer 005C307B pop esi -> restaura la pila 005C307C add esp, 4 005C307F retn 8 -> y retorna con código en AX = 400h 005C307F sub_5C3030 endp Como era de esperar este código prepara los argumentos para la función DeviceIOControl y posteriormente en la línea 5C3064 se llama a una función (5C2950) la cual realiza una serie de cálculos sobre la estructura pasada en ESI. No he incluido estos cálculos por ser muy extensos. Si continuamos trazando después de la llamada veremos que el programa toma el salto en 5C306F y retorna en AX el valor que habia en el buffer de entrada apuntado por [ESI+6]. Continuamos hasta ejecutar el ret y estaremos al principio: 005C30DF call sub_5C3030 -> venimos de aquí 005C30E4 mov eax, [esp+4] -> estamos aquí, carga en EAX en Handle del VXD 005C30E8 push eax -> Pasa handle 005C30E9 call sub_5C3090 -> llama a función que cierra el VXD con CloseHandle y retorna 1C00 en EAX 005C30EE mov ax, [esi+6] -> recuperamos el valor de retorno 005C30F2 or ah, ah -> comprueba si AH = 0 005C30F4 jnz short loc_5C30FA -> no, salta 005C30F6 or ax, 1C00h -> todo bien 005C30FA loc_5C30FA: -> aquí sólo llegamos desde 5C30CC 005C30FA ; y desde 5C30FA 005C30FA pop esi 005C30FB add esp, 4 005C30FE retn 4 Bueno por todo lo que tenemos hasta ahora parece que el programa utiliza códigos de error para comprobar el exíto de sus operaciones, por lo que podemos deducir, el código que indica que todo va bien es 1C00h y cualquier otra cosada un error. Aún así hemos comprobado que la comuncación con el VXD se cierra en cualquier caso, por lo que podemos sospechar que el programa volverá a abrir el VXD con CreateFileA y volverá a establecer comunicación con este. Reactivaremos nuestros breakpoints (si los habias borrado, vuelvelos a crear) y pulsaremos g en SoftIce para continuar. Veremos que de nuevo el SoftIce se activará, pulsamos F12 para ver desde donde se llamó a CreateFileA y veremos que ya habiamos pasado por aquí, estamos de nuevo en 5C3000. Esto nos da otra pista, parece que la función en 5C3000 se utiliza en más de un sitio, por lo que vamos a pulsar de nuevo F12 para ver desde donde se llamó. Para nuestra sorpresa veremos que a sido llamada desde 5C30BD y aquí ya estuvimos antes, por lo que pulsaremos de nuevo F12. Ahora veremos que estamos en una nueva dirección: 005C2D80 sub_5C2D80 proc near ; CODE XREF: sub_5C23B0+43p 005C2D80 mov eax, [esp+4] 005C2D84 push eax 005C2D85 call sub_5C30B0 005C2D8A retn 4 -> ESTAMOS AQUÍ 005C2D8A sub_5C2D80 endp Bueno parece que no hay muchas opciones por lo que pulsaremos F12 de nuevo y veremos: 005C24ED call sub_5C23B0 005C24F2 mov [esi+6], ax -> ESTAMOS AQUÍ, guarda resultado en ESI+6 005C24F6 pop esi -> reajusta la pila 005C24F7 add esp, 4 005C24FA retn 4 -> y retorna notese como se almacena en [esi+6] el resultado de la función previa, pulsamos F12 de nuevo y vemos: 005C396C mov word ptr [esi+6], 403h 005C3972 005C3972 loc_5C3972: ; CODE XREF: sub_5C3910+78 005C3972 cmp word ptr [esi+6], 403h 005C3978 jnz short loc_5C398A 005C397A mov [esi+0Ah], bl 005C397D push esi 005C397E call sub_5C2460 -> venimos de aquí 005C3983 inc bl -> incrementa contador 005C3985 cmp bl, 3 -> llevamos 3 intentos ? 005C3988 jbe short loc_5C3972 -> No, continua en 5C3972 005C398A 005C398A loc_5C398A: ; CODE XREF: sub_5C3910+68j 005C398A mov ax, [esi+6] -> carga en AX resultado de la función 005C398E mov cx, ax -> lo copia a CX 005C3991 and cl, 9 -> realiza un AND sobre el byte bajo del resultado 005C3994 cmp cl, 9 -> es 9? 005C3997 jnz short loc_5C39A2 -> no, salta a 5C39A2 005C3999 mov ax, 3 -> si, devolvemos 3 005C399D pop esi -> reajusta pila 005C399E pop ebx 005C399F retn 8 -> y retorna 005C39A2 loc_5C39A2: ; CODE XREF: sub_5C3997 005C39A2 push eax -> pasa resultado como parametro a la función siguiente 005C39A3 call sub_5C3110 -> llama a una función,valor de retorno en EAX 005C39A8 pop esi -> restaura pila 005C39A9 pop ebx 005C39AA retn 8 -> y retorna. 005C39AA sub_5C3910 endp El programa realiza tres intentos (línea 5C3985) para comprobar la mochila y después de eso lee el valor de retorno de esi+6 realiza un AND con nueve y comprueba el resultado con 9, ni no es igual la función retorna 3 en AX (línea 5C3999) y sale. Si continuas trazando hasta ejecutar el ret, veras que después te aperecerá el código al cual hemos llegado utilizando el metodo del MessageBox(pincha aquí para ir a este código), a partir de aquí el modus operandi es el mismo :). Con esto queda demostrado que siempre existe más de una puerta de entrada.
[ 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