| ESTUDIO COLECTIVO DE DESPROTECCIONES Última Actualizacion: 25/10/2001 |
Programa | API Spy 32 v2.4 | W95 / W98 / NT
Descripción | Programa que permite monitorizar las llamadas a las funciones de API de windows o de cualquier DLL.
Tipo | Funciones Limitadas
Tipo de Tutorial | [X]Original, []Adaptación, []Aplicación, []Traducción
Url | http://madmat.hypermart.net http://www.cryogen.com/protectit http://www.chat.ru/~madmat http://www.crackstore.com
Protección | Serial Number
Dificultad | 1) Principiante, 2) Amateur, 3) Aficionado, 4) Profesional, 5) Especialista
Herramientas | SoftIce v4, W32dasm v8.9, ProcDump y UltraEdit
Objetivo | Descomprimir el ejecutable mediante la creación de un script con Procdump y parcheado del código en tiempo de ejecución para que acepte cualquier serial.
Cracker | Black Fenix
Grupo | http://kickme.to/wkt
Fecha | Abril del 2000
INTRODUCCION
Aquí estoy de nuevo, esta vez con un tema nuevo que parece ser se ha puesto bastante de moda: La compresión/encriptación de los ejecutables. Para el ejemplo usaremos un programa llamado APIS 32 v2.4 se trata de un monitorizador de las funciones del API de windows, también permine la exportación de simbolos con lo que se puede monitorizar cualquier función que se encuentre en una DLL. Este programa está comprimido, pero desconozco el nombre del compresor utilizado, aunque también podría ser que estuviera comprimido con alguna utilidad del mismo autor del programa. Objetivo: Modificar el ejecutable comprimido para que se cambie lo que sea necesario en tiempo de ejecución logrando que sirva cualquier número de registro que le introduzcamos, habilitanto a si todas las funciones del programa. Para lograr esto necesitaremos poder descomprimir el ejecutable y una vez que se sabe lo que hay que cambiar, hacer el parche en el ejecutable comprimido. Esta lección promete bastante ya que se introduciran varios temas no tocados hasta el momento, aprenderemos el manejo del ProcDump y tambien algunas cosillas básicas sobre la estructura de los archivos PE (Portable Executable), será largo pero valdrá la pena.
AL ATAQUE
En principio procederemos de la forma normal, ejecutar el programa, introducir los datos de registro y copiar el mensaje de error que nos aparece. Desensamblamos el ejecutable apis32.exe y vemos que no hay ninguna referencia a cadenas, ni tabla de funciones de importación.Esto son dos de los sintomas más normales en los archivos comprimidos/encriptados. Si examinamos el código por encima veremos que no parece un código muy lógico, repetición de instrucciones, escrituras a puerto frecuentes etc. esto es debido a que este no es el código real del programa. Bueno pero sabemos que de alguna manera el ejecutable debe descomprimirse/desencriptarse a si mismo y por lo tanto el código que realiza este trabajo debe aparecer. Efectivamente, y sólo sólo puede estar en un sitio: el punto de entrada del programa (Program Entry Point). Vamos al menu Goto/Program Entry Point y el W32DAsm nos llevará al punto de entrada del programa. Veremos algo así:
:0041A000 | 669C | pushf
:0041A002 | 60 | pushad
:0041A003 | E8CA000000 | call 0041A0D2 | //llamada a la rutina de descompresión
:0041A008 | 0300 | add eax, dword ptr [eax] | // todo esto ya no se ejecutará
:0041A00A | 0400 | add al, 00
:0041A00C | 0500060007 | add eax, 07000600
:0041A011 | 0008 | add byte ptr [eax], cl
:0041A013 | 0009 | add byte ptr [ecx], cl
:0041A015 | 000A | add byte ptr [edx], cl
:0041A017 | 000B | add byte ptr [ebx], cl
:0041A019 | 000D000F0011 | add byte ptr [11000F00], cl
:0041A01F | 0013 | add byte ptr [ebx], dl
:0041A021 | 0017 | add byte ptr [edi], dl
:0041A023 | 001B | add byte ptr [ebx], bl
:0041A025 | 001F | add byte ptr [edi], bl a
Ok, según el W32DAsm este es el punto de entrada del programa, pero el código no parece muy lógico a partir de la llamada (call) de la tercera linea. Probablemente, después de la llamada, ya no se vuelve a la siguiente línea, sino que el programa saltará al punto de entrada del programa original (el punto de entrada del programa descomprimido), es de suponer que lo que sigue a la llamada, son datos de la sección. Antes de continuar, vamos a hechar un vistazo a las diferentes secciones del ejecutable, para ello utilizaremos el ProcDump. Ejecutamos el ProcDump y hacemos click en el botón PE Editor, seleccionaremos el ejecutable apis32.exe y aceptamos (deberemos salir del W32DAsm para que el Procdump pueda leer el archivo). Nos aparecerá un cuadro de dialogo como el siguiente: Para saber el punto de entrada exacto del programa, sumaremos el valor de Image Base con el valor Entry Point, resultando ser igual que el que nos daba el W32DAsm. Podemos asegurar pues que este el el punto de entrada. Ahora miraremos en que sección se encuentra el punto de entrada, hacemos click en el botón Sections y nos aparece un cuadro de diálogo como el siguiente: Vemos que aparecen las secciones .itext , .idata , .rsrc y por último .madmat. Si miramos el valor Virtual Offset de la sección .madmat, vemos que coincide con el valor Entry Point anterior, esto nos indica que esta sección es la encargada de descomprimir/desencriptar el ejecutable y que por lo tanto contiene el código que estamos buscando.Es curioso también que coincida con parte de la URL del autor http://madmat.hypermart.net :) Salimos del ProcDump cancelando todos los cuadros de diálogo abiertos.Volvemos a desensamblar el ejecutable y nos vamos al punto de entrada del programa (menu Goto/Program Entry Point), una vez allí vamos a ver que es lo que hace la llamada que hay en la segunda línea. Nos situamos sobre esta (linea azul encima de la linea de código ) y pulsamos el botón Call de la barra de botones. Esto nos llevará al código siguiente:
:0041A0D5 | 50 | push eax
:0041A0D6 | 8BC8 | mov ecx, eax
:0041A0D8 | 8BD0 | mov edx, eax
:0041A0DA | 81C168D20000 | add ecx, 0000D268
:0041A0E0 | 81C2DC150000 | add edx, 000015DC
:0041A0E6 | 8920 | mov dword ptr [eax], esp
:0041A0E8 | 8BE1 | mov esp, ecx
:0041A0EA | 50 | push eax
:0041A0EB | 812C2400A00100 | sub dword ptr [esp], 0001A000
:0041A0F2 | FF30 | push dword ptr [eax]
:0041A0F4 | 50 | push eax
:0041A0F5 | 80042408 | add byte ptr [esp], 08
:0041A0F9 | 50 | push eax
:0041A0FA | 80042446 | add byte ptr [esp], 46
:0041A0FE | 50 | push eax
:0041A0FF | 80042465 | add byte ptr [esp], 65
:0041A103 | 50 | push eax
:0041A104 | 800424A1 | add byte ptr [esp], A1
:0041A108 | 50 | push eax
:0041A109 | 800424BF | add byte ptr [esp], BF
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0041A172(U)
:0041A10D | 833A00 | cmp dword ptr [edx], 00000000
:0041A110 | 0F84A7140000 | je 0041B5BD
:0041A116 | F70200000080 | test dword ptr [edx], 80000000
:0041A11C | 741B | je 0041A139
:0041A11E | FD | std
:0041A11F | 8B0A | mov ecx, dword ptr [edx]
:0041A121 | 81E1FFFFFF7F | and ecx, 7FFFFFFF
:0041A127 | 8B742418 | mov esi, dword ptr [esp+18]
:0041A12B | 8BFE | mov edi, esi
:0041A12D | 037204 | add esi, dword ptr [edx+04]
:0041A130 | 037A08 | add edi, dword ptr [edx+08]
:0041A133 | F3 | repz
:0041A134 | A5 | movsd
:0041A135 | 83C20C | add edx, 0000000C
:0041A138 | FC | cld
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0041A11C(C)
:0041A139 | 52 | push edx
:0041A13A | FF32 | push dword ptr [edx]
:0041A13C | 8B5A08 | mov ebx, dword ptr [edx+08]
:0041A13F | 035C2420 | add ebx, dword ptr [esp+20]
:0041A143 | 53 | push ebx
:0041A144 | 8B5A04 | mov ebx, dword ptr [edx+04]
:0041A147 | 035C2424 | add ebx, dword ptr [esp+24]
:0041A14B | 53 | push ebx
:0041A14C | E84A000000 | call 0041A19B
:0041A151 | 85C0 | test eax, eax
:0041A153 | 741F | je 0041A174
:0041A155 | 8B7C2404 | mov edi, dword ptr [esp+04]
:0041A159 | 83C40C | add esp, 0000000C
:0041A15C | 5A | pop edx
:0041A15D | 8B4A0C | mov ecx, dword ptr [edx+0C]
:0041A160 | C1F902 | sar ecx, 02
:0041A163 | 33C0 | xor eax, eax
:0041A165 | F3 | repz
:0041A166 | AB | stosd
:0041A167 | 8B4A0C | mov ecx, dword ptr [edx+0C]
:0041A16A | 83E103 | and ecx, 00000003
:0041A16D | F3 | repz
:0041A16E | AA | stosb
:0041A16F | 83C210 | add edx, 00000010
:0041A172 | EB99 | jmp 0041A10D
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0041A153(C)
:0041A174 | 8B642424 | mov esp, dword ptr [esp+24]
:0041A178 | 83C426 | add esp, 00000026
:0041A17B | C3 | ret
Fijate en los las instrucciones repz movsd, son muy típicas en las rutinas de descompresion/desencriptación, ya que se debe copiar el código y esta es una de las pocas formas de hacerlo. No nos interesa el algoritmo de compresión que se este utilizando, nuestro objetivo es encontrar la línea de código que nos envie al punto de entrada del programa descomprimido. Puede que lo que busquemos este en la línea 41a17b (ret), ya que es posible que allí se retorne al punto de entrada del programa descomprimido.Es hora del Soft-Ice. Cargaremos el Symbol Loader del Soft-Ice y haremos click en Files/Open Module y seleccionaremos el fichero apis32.exe. Esto cargará el EXE en memoria y podremos trazarlo desde su punto de entrada original con Load/Module. Pulsaremos F8 una sola vez y entraremos en el código.Ahora pondremos un BPX en la línea 41a17b con: > bpx 41a17b y pulsaremos g para continuar. El BPX no surtirá efecto y en su lugar obtendremos un cuadro anunciandonos que el programa a efectuado una operación no válida. Parece que estamos equivocados y el ret no se ejecuta como esperabamos.Volviendo a examinar el código anterior buscando otro punto donde se pueda saltar, vemos una comparación bastante sospechosa en la línea 41a10D: :0041A10D 833A00 cmp dword ptr [edx], 00000000 :0041A110 0F84A7140000 je 0041B5BD Si nos fijamos, el salto se ejecutara cuando el dword apuntado por [EDX] sea igual a 0, enviandonos a una dirección bastante lejana a este código, el resto de los saltos, nunca llegan a salir de esta rutina, por lo que bamos a trazar de nuevo con el Soft-Ice hasta llegar a esta línea, una vez allí, pondremos un BPX a la dirección donde se saltará con: > bpx 41B5BD ahora pulsamos g+ENTER para continuar y nuestro BPX habrá surtido efecto, veremos lo siguiente:
:0041B5BD | 8B642414 | mov esp, dword ptr [esp+14]
:0041B5C1 | 5E | pop esi
:0041B5C2 | 8BFE | mov edi, esi
:0041B5C4 | 81C6D7150000 | add esi, 000015D7
:0041B5CA | 6A05 | push 00000005
:0041B5CC | 59 | pop ecx
:0041B5CD | F3 | repz
:0041B5CE | A4 | movsb
:0041B5CF | 61 | popad
:0041B5D0 | 669D | popf
:0041B5D2 | E9E99FFEFF | jmp 004055C0 | // salto incondicional a una dirección bastante "diferente"
:0041B5D7 | E9BBB5FEFF | jmp 00406B97
Esto si que parece el fín de la rutina de descompresión, ya que restauran los registros y los flags que fueron empujados al inicio del programa y se salta incondicionalmente a una posición de código bastante diferente.Si seguimos trazando con F8, ejecutando el salto, veremos que este nos lleva a lo siguiente:
:004055C0 | 55 | push ebp
:004055C1 | 8BEC | mov ebp, esp
:004055C3 | 6AFF | push FFFFFFFF
:004055C5 | 6810804000 | push 00408010
:004055CA | 6818544000 | push 00405418
:004055CF | 64A100000000 | mov eax, dword ptr fs:[00000000]
:004055D5 | 50 | push eax
:004055D6 | 64892500000000 | mov dword ptr fs:[00000000], esp
:004055DD | 83C4A8 | add esp, FFFFFFA8
:004055E0 | 53 | push ebx
:004055E1 | 56 | push esi
:004055E2 | 57 | push edi
:004055E3 | 8965E8 | mov dword ptr [ebp-18], esp
* Reference To: KERNEL32.GetVersion, Ord:014Ch
:004055E6 | FF15B8024100 | Call dword ptr [004102B8] | // Esto es el tipico inicio de todos los ejecutables
:004055EC | 33D2 | xor edx, edx
:004055EE | 8AD4 | mov dl, ah
:004055F0 | 8915A0BB4000 | mov dword ptr [0040BBA0], edx
:004055F6 | 8BC8 | mov ecx, eax
:004055F8 | 81E1FF000000 | and ecx, 000000FF
:004055FE | 890D9CBB4000 | mov dword ptr [0040BB9C], ecx
:00405604 | C1E108 | shl ecx, 08
:00405607 | 03CA | add ecx, edx
:00405609 | 890D98BB4000 | mov dword ptr [0040BB98], ecx
:0040560F | C1E810 | shr eax, 10
:00405612 | A394BB4000 | mov dword ptr [0040BB94], eax
:00405617 | E8840E0000 | call 004064A0
:0040561C | 85C0 | test eax, eax
:0040561E | 750A | jne 0040562A
:00405620 | 6A1C | push 0000001C
:00405622 | E839010000 | call 00405760
:00405627 | 83C404 | add esp, 00000004
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040561E(C)
:0040562A | C745FC00000000 | mov [ebp-04], 00000000
:00405631 | E86A0C0000 | call 004062A0
:00405636 | E8550C0000 | call 00406290
* Reference To: KERNEL32.GetCommandLineA, Ord:00AAh
:0040563B | FF1574034100 | Call dword ptr [00410374] | // Esto es tipìco al inicio de todos los ejecutables
Las llamadas a GetVersion y GetCommandLineA, delatan con toda seguridad, que este es el punto de entrada del programa original, por lo que apuntaremos su dirección que es 41B5BD. Si continuamos con la ejecución del programa, veremos que este funciona correctamente. Ahora llega el momento de la verdad, vamos a usar el ProcDump para volcar el ejecutable una vez se halla descomprimido, para ello vamos a utilizar un script del ProcDump. Abriremos el fichero script.ini que se encuentra con el ProcDump, y agregaremos una linea al final de la sección [INDEX], la sintaxis será: Pxx=APIS32 v2.4 xx= Numero de línea que toce, teniendo en cuenta que va en hexadecimal, por ejemplo si tenemos una sección INDEX tal que así: [INDEX] P1=Hasiuk/NeoLite P2=PESHiELD P3=Standard P4=Shrinker 3.3 P5=Wwpack32 I P6=Manolo P7=Petite<1.3 P8=Wwpack32 II P9=Vbox Dialog deberemos escribir PA=APIS32 v2.4 ahora creamos una sección que se llame igual que la línea que indica PXX (en nuestro caso [APIS32 v2.4] justo debajo y segiidamente le añadiremos las siguiente lineas: L1=LOOK E9,E9,9F,FE,FF L2=BP L3=WALK L4=EIP L5=STEP La línea L1, le indica al ProcDump que busque esta secuencia de bytes en el código del ejecutable, esta secuencia de bytes es el salto que hay en la línea 41B5D2 :0041B5D2 E9E99FFEFF jmp 004055C0 Este es el salto que nos envia al punto de entrada del ejecutable original, por lo que el ProcDump buscará esta posición de memoria. Con la línea L2 le decimos que ponga un breakpoint en esa misma posición de memoria que se encontró. La línea L3 le indica al ProcDump que ejecute la siguiente instrucción a partir de la posición donde se puso el breakpoint, en este caso lo que se hace es que el salto se ejecuta, situandonos en el punto de entrada del programa original. Una vez en el punto de entrada original, la línea L4 le indica al ProcDump, que use el valor actual de EIP como punto de entrada del programa que va a volcar y posteriormente con la línea L4 finalizamos el trazado y procedemos al volcado del ejecutable. Salvamos los cambios al fichero script.ini y ejecutamos el ProcDump. (Antes, entrar en el Soft-Ice y desactivar todos los breakpoints, ya que sino, el ProcDump encontrará los breakpoint del SI y se colcagará al descomprimir el ejecutable). Pulsamos sobre Unpack, seleccionamos APIS 32 v2.4 y pulsamos OK, ahora buscamos el archivo apis32.exe y lo seleccionamos para descomprimirlo. Nos aparecerá un cuadro de mensaje solicitando un nombre para el fichero descomprimido, le llamaremos apis32un.exe y lo guardaremos junto al original. Ahora, sin salir del ProcDump, podemos ejecutar el fichero recien descomprimido y veremos que este funciona perfectamente, y además ocupa más que el comprimido. Ahora ya casi tenemos el fichero original, a este fichero le sobra el código que antes usaba para descomprimirse, ese código está en la sección .madmat, por lo que vamos a eliminarla para reducir el tamaño del ejecutable. Dentro del ProcDump, hacemos click en PE Editor, seleccionamos el archivo descomprimido y en el marco que dice "Apply changes method" activaremos la opción "To PE file", ya que sino, solo eliminariamos la sección de la cabezera y no del archivo. ahora pinchamos sobre el botón Sections, veremos los nombres de todas las secciones. Click con el botón derecho, nos aparece un menú con varias opciones, seleccionamos Kill Section. Esto eliminará la sección. Pulsamos Ok y Ok de nuevo y salimos del ProcDump. Si miramos el ejecutable veremos que ahora tiene unos 45K menos que antes, debido a que le hemos eliminado la sección .madmat. El ejecutable debe ser totalmente funcional, puedes comprobarlo tu mismo. Bueno la parte más difícil ya está, ahora sólo quedá buscar donde se comprueba el número de série. Para ello procederemos de la manera estandar, buscando la referencia a la cadena que nos muestra el mensaje que se nos da al intentar registrarnos sin éxito, esta cadena dice algo así: The registration information you entered... bla bla Vale, desensamblamos el archivo que hemos descomprimido y buscamos esta cadena. Cuando la encontremos, doble click sobre esta y el W32DAsm nos transportará al siguiente código:
:00401764 | FF15F8024100 | Call dword ptr [004102F8]
:0040176A | E8312F0000 | call 004046A0 | // llama a la rutina en 4046a0
:0040176F | A374CE4000 | mov dword ptr [0040CE74], eax | // guarda valor de retorno en memoria mmm....
:00401774 | EB01 | jmp 00401777 | // salto incondicional de un solo byte
:00401776 | B8 | BYTE B8
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401774(U)
:00401777 | 0AC0 | or al, al | // comprueba si el valor de retorno es 0
:00401779 | 7402 | je 0040177D | // si es así, nos envia al código que hace referencia a la cadena de error
:0040177B | EB2C | jmp 004017A9 | // salto incondicional, buen chico, programa registrado.
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401779(C)
* Possible StringData Ref from Data Obj ->"The registration information you " ->"provided is incorrect. Please"
:0040177D | BFE8904000 | mov edi, 004090E8 | // referencia a la cadena
:00401782 | BAE0D14000 | mov edx, 0040D1E0
Que te parece? Pues lo tipico, llamada a una función que comprueba los datos, se guarda el resultado de la comprobación, se comprueba este resultado y se actua en consecuencia. Podrimos hacer los cambios aquí, pero eso no es lo más elegante, vamos a ver que hace la función 4046a0.
:004046A0 | 51 | push ecx
:004046A1 | 53 | push ebx
:004046A2 | 55 | push ebp
:004046A3 | 56 | push esi
:004046A4 | 57 | push edi
:004046A5 | 6A50 | push 00000050
:004046A7 | 68A0C64000 | push 0040C6A0
* Possible StringData Ref from Data Obj ->"UserKey"
:004046AC | 6808964000 | push 00409608 | // clave del registro que contiene el código introducido.
:004046B1 | E81A030000 | call 004049D0 | // obtiene valor de la clave y retorna su longitud en EAX
:004046B6 | 83C40C | add esp, 0000000C | // restaura la pila
:004046B9 | 83F810 | cmp eax, 00000010 | // comprueba que el código tenga una longitud superior a 10h caracteres,
:004046BC | 7D08 | jge 004046C6 | // si, es válido, se pasa a comprobar el nombre
:004046BE | 33C0 | xor eax, eax | // código no válido debido a su longitud
:004046C0 | 5F | pop edi
:004046C1 | 5E | pop esi
:004046C2 | 5D | pop ebp
:004046C3 | 5B | pop ebx
:004046C4 | 59 | pop ecx
:004046C5 | C3 | ret
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004046BC(C)
:004046C6 | 6A2F | push 0000002F
:004046C8 | 6800CF4000 | push 0040CF00
* Possible StringData Ref from Data Obj ->"UserName"
:004046CD | 68F8954000 | push 004095F8 | // clave del registro que contiene el nombre del usuario introducido
:004046D2 | E8F9020000 | call 004049D0 | // obtiene valos de la clave y su longitud en caracteres
:004046D7 | 83C40C | add esp, 0000000C | // restaura la pila
:004046DA | 83F805 | cmp eax, 00000005 | // comprueba que el nombre tenga una longitud de 5 caracteres o más
:004046DD | 7D08 | jge 004046E7 | // superior o igual a 5 caracteres, pasa a computar si el nombre y código son correctos
:004046DF | 33C0 | xor eax, eax | // si es inferior a 5 caracteres, error, nombre muy corto
:004046E1 | 5F | pop edi
:004046E2 | 5E | pop esi
:004046E3 | 5D | pop ebp
:004046E4 | 5B | pop ebx
:004046E5 | 59 | pop ecx
:004046E6 | C3 | ret
El código que sigue a este, se encarga de comprobar si el número y el nombre són válidos, no nos interesa como lo hace, por lo que avanzaremos el código hasta llegar al primer ret que encontremos, veremos lo siguiente:
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00404807(U)
:00404815 | 03EA | add ebp, edx
:00404817 | 41 | inc ecx
:00404818 | 4E | dec esi
:00404819 | 75DA | jne 004047F5
:0040481B | 33C0 | xor eax, eax
:0040481D | 5F | pop edi
:0040481E | 85ED | test ebp, ebp | // comprueba si ebp es 0
:00404820 | 5E | pop esi | // restaura registro
:00404821 | 5D | pop ebp
:00404822 | 0F94C0 | sete al | // pone al a 1 si ebp=0
:00404825 | 5B | pop ebx
:00404826 | 59 | pop ecx
:00404827 | C3 | ret | // retorna, si al=1, el código es válido. |
La línea 404822 parece bastante sospechosa, ya que se pone AL a 0 o a 1 según una comparación anterior, si cambiamos la instrucción sete al (0F94C0) por setne al (0F95C0), y intentamos registrar el programa introduciendo un nombre más largo de 5 caracteres y un código más largo de 12 (10h) caracteres, veremos que el programa se registrará. Pruebaló, apunta el offset de esta instrucción, abre el archivo descomprimido, vete al offset que apuntaste y cambia el 94 por un 95. Salva los cambios y pruebaló, verás que el programa se ha registrado. Para desregistrarlo, puedes borrar la clave del registro H_KEY_LOCAL_MACHINE/SoftWare/APIS32/UserKey. Pero si lo hacemos así, resultará que si por casualidad se acierta el código de registro, este no se registrará, por lo que la manera más correcta será cambiar el test ebp,ebp (85 ED) por xor ebp,ebp (33 ED), haciendo que ebp sea siempre 0 y por lo tanto el sete al posterior siempre pondra al a 1. Por lo tanto sabemos que el único byte de código que es necesario cambiar es el 85 (test) por un 33 (test) que se halla en la posición 40481. Apuntaremos estos datos, ya que los necesitamos para realizar el parche. Ahora ya sabemos que es lo que hay que cambiar, falta saber cómo vamos a hacer para cambiarlo en el ejecutable comprimido. Pues es sencillo, vamos a buscar un sitio dentro del ejecutable donde podamos colocar nuestro parche. Podemos editar el archivo comprimido con el editor hexadecimal, y ver que después del mensaje de copyright "API Spy 32 - Copyright (c) 1999 Vitaly Evseenko", hay bastante sitio. Pues nada podemos colocar nuestro código detrás del mensaje en el offset 250h del archivo (Nota: esto es posible, porque la primera sección del ejecutable empieza en el offset 1000h, por lo tanto si nosotros colocamos nuestro código aquí, no estaremos sobresccribiendo nada, ya que estamos escribiendo el código en el espacio sobrante de la cabezera del archivo). Por lo tanto si la Image Base Address del programa comprimido es 40000h (puedes comprobarlo con el ProcDump si editas la cabezera de este), sabemos que nuestro código se encontrará en la posición 400250h una vez que este se haya cargado en memoria. Por lo tanto, deberemos saltar a esta posición después de que el programa se haya descomprimido, este salto lo podemos realizar justo donde se hace el salto de la línea: :0041B5D2 E9E99FFEFF jmp 004055C0 // salto al punto de entrada del programa por lo tanto deberemos cambiar esta línea por :0041b5d2 E9794CFEFF jmp 400250 // salta a nuestra rutina que parchea el código. Cómo sabemos que se debe cambiar el E9E99FFEFFF por E9794CFEFF? Pues fácil, si estamos en la posición 41B5D2 y queremos saltar a la 400250, restaremos (porque vamos hacia atras) a 400250 la dirección 41B5D2 dando como resultado FFFE4C7E, a este dirección faltan restarle los 5 bytes que ocupa el salto quedando FFFE4C79, que en ordenamiento Intel resulta 794CFEFF que es el valor que junto con el código del salto (E9) debemos cambiar. Bien ahora, hay que saber que instrucción haremos servir para parchear el código, sabemos que el byte que debemos cambiar está en la dirección 40481E y debemos cambiarlo por un 33 (xor), esto deberá hacerse con la instrucción siguiente: mov byte ptr [40481e],33 luego faltá que saltemos al punto de entrada del programa con un: jmp 4055c0 Para saber la codificación de estas instrucciones, vamos a usar el SoftIce. Activaremos los breakpoints que teniamos y ejecutaremos el programa comprimido, aparecerá el SoftIce y iremos trazando hasta llegar al salto jmp 4055c0 (línea 41B5D2) , la cambiaremos por jmp 400250 (nuestra posición de código) con: > a 41B5D2 > jmp 400250 > pulsar enter 2 veces Pulsaremos F8 y esto nos enviará al lugar donde deberá estar nuestro código, allí ensamblarenos las lineas de código que necesitamos con : > a > mov byte ptr [40481e],33 > jmp 4055c0 > pulsar enter 2 veces Ahora vamos a ver el código de operación necesario para estas instrucciones con: > d 400250 en la ventana de datos veremos los valores: 66C6051E48400033E963530000 esta es la cadena de bytes que corresponden a las instrucciones que hemos ensamblado, se divide de la siguiente manera: 66C6051E48400033 -> mov byte ptr [40841E],33 E963530000 -> jmp 4055C0 Continuaremos con la ejecución del programa y veremos que este funciona correctamente y nos dirá que está registrado al nombre que pusimos anteriormente. Si no pusijmos ningún nombre, bastará que introduzcamos un nombre de más de 5 carácteres y un código de más de 12 para que se registre. Tiempo para hacer las modificaciones al ejecutable comprimido, el primer cambio será cambiar el salto de la rutina de descompresión por el salto a nuestra código de parcheado. Recordar que el offset para este salto es E9D2, (puedes comprobarlo con el W32DAsm) cambiaremos la cadena que encontremos en este lugar del archivo (E9E99FFEFF) por la que calculamos anteriormente (E9794CFEFF). Luego iremos al offset 250h y allí reemplazaremos lo que haya (debe haber ceros) por los bytes 66,C6,05,1E,48,40,00,33,E9,63,53,00,00 nuestro código de parcheado. Pues ya está a correr. Este a sido un tutorial bastante largo pero creo que el contenido a sido bastante interesante, y hemos visto cosas nuevas, podiamos haber hecho un keygenerator, pero mi propósito era mostrar como se puede parchear un archivo comprimido en tiempo de ejecución. Podriamos haber prescindido de descomprimir el ejecutable y haber buscado la rutina de comprobación del número con el Soft-Ice, pero lo he hecho así para mostrar el uso del ProcDump, con el cual podemos descomprimir un ejecutable, sin tener que hacerlo manualmente.
[ 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