Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - PeterPunk77

#22
Ingeniería Inversa / Re: Ayuda con ImportRec (Dump)
30 Noviembre 2011, 22:10 PM
También reparé la IAT. Normalmente uso ImpRec y LordPE, pero si me veo obligado a dumpear con ChimpRec que menos que usarlo también para la IAT.
Saludos.
#23
Ingeniería Inversa / Re: [Reto] Diofanto's Crackme
30 Noviembre 2011, 21:45 PM
Perdona _Enko, pero no entiendo qué problema tienes.
Efectivamente el crackme no es más que una ecuación bicuadrada que evidentemente tiene 4 posibles soluciones y cualquiera de ellas debería ser válida. Yo sólo he hecho una prueba para comprobar que todo estuviese correcto y con la solución obtenida con los positivos de las raíces cuadradas no he obtenido ningún error.
Saludos.
#24
Ingeniería Inversa / Re: [Reto] Dioniso's Crackme
30 Noviembre 2011, 21:40 PM
Buenas .:UND3R:.,
la verdad es que no se qué quieres que te explique.
La primera parte del crackme es obvia: con el crc32 del nombre y el serial introducido (en base 4) hago un xor y el resultado es un dword que es el usado para descifrar el procedimiento que muestra el mensaje de chico bueno. Así que lo único que necesitamos hacer es encontrar esta dword.
Una forma de hacerlo es encontrarla por fuerza bruta, por ejemplo con este código:
.386
.model flat,stdcall
option casemap :none

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data
   cte db 084h, 08Eh, 056h, 02Bh, 0E3h, 040h, 0D4h, 0A8h, 0BEh, 077h, 0DBh, 0A2h, 0A4h, 060h, 0D4h, 0A1h
       db 0F1h, 066h, 0C8h, 0A1h, 0B2h, 06Eh, 0DFh, 0B2h, 0FFh, 008h, 0B0h, 0CDh, 0DBh, 044h, 0D2h, 0AFh
       db 0A3h, 064h, 09Ah, 0B0h, 0A3h, 06Ah, 0DDh, 0B2h, 0B0h, 068h, 0DBh, 0E0h, 0B4h, 069h, 09Ah, 0ABh
       db 0B4h, 07Ch, 0DDh, 0A5h, 0BFh, 02Bh, 0BAh, 0AAh, 0D1h, 06Dh, 0D6h, 0F0h, 091h, 005h, 0D2h, 018h
       db 0C3h, 045h, 0BAh, 03Fh, 0A4h, 00Dh, 052h, 0DCh, 0D1h, 005h, 0BAh, 009h, 013h, 001h, 0BAh
   CRCPOLY dd 0EDB8831Fh
   dwCRC32 dd 3C048143h
   szHex db "%X",0
   szTitulo db "Brute", 0

.data?
   CRCTaboa db 1024 dup (?)
   funcion_encriptada db 80 dup (?)
   dwNumMaxico dd ?
   szNumMaxico db 9 dup (?)
   
.code

start:
   call taboa_crc32
@bucle_bruto:
   mov edx, dwNumMaxico
   mov esi, offset cte
   mov edi, offset funcion_encriptada
   xor ecx, ecx
@@:            
   mov eax, [esi]
   mov [edi], eax
   add esi, 4
   add edi, 4
   inc ecx
   cmp ecx, 19
   jb @B
   mov ax, word ptr [esi]
   mov word ptr [edi], ax
   mov al, byte ptr [esi + 2]
   mov byte ptr [edi + 2], al
   mov esi, offset funcion_encriptada
   mov ecx, 20
@@:            
   xor [esi], edx
   add esi, 4
   loop @B
   push offset funcion_encriptada
   push 79
   call crc32
   cmp eax, dwCRC32
   jz @correcto
   inc dwNumMaxico
   jmp @bucle_bruto
@correcto:
   push dwNumMaxico
   push offset szHex
   push offset szNumMaxico
   call wsprintf
   add esp, 12
   push MB_OK
   push offset szTitulo
   push offset szNumMaxico
   push 0
   call MessageBox
   push 0
   call ExitProcess

taboa_crc32 proc    
   push ebx
   mov edi, CRCPOLY
   inc edi
   xor ebx, ebx
   mov ecx, offset CRCTaboa
taboa_bucle:
   movzx eax, bx
   add eax, eax
   mov dx, 0fff7h
taboa_salto:
   test al, 01h
   jz taboa_salto_1
   shr eax, 01h
   xor eax, edi
   jmp taboa_salto_2
taboa_salto_1:
   shr eax, 01h
taboa_salto_2:
   inc dx
   jnz taboa_salto
   mov [ecx], eax
   inc ebx
   add ecx, 04h
   cmp bx, 0100h
   jnz taboa_bucle
   pop ebx
   ret
taboa_crc32 endp

crc32 proc len:DWORD, lpBuffer    
   mov ebx, lpBuffer
   mov esi, len
   mov edi, 0FFFFFFFFh
crc32_bucle:
   mov edx, edi
   mov eax, [ebx]
   and eax, 0FFh
   xor al, dl
   mov eax, [eax * 4 + offset CRCTaboa]
   shr edx, 08h
   xor eax, edx
   mov edi, eax
   inc ebx
   dec esi
   jnz crc32_bucle
crc32_salir:
   not edi
   mov eax, edi
   ret
crc32 endp

end start

y una vez encontrada ya podemos hacer un keygen fácilmente.
De todos modos yo no lo haría así, y aunque creo que el código de arriba no tardará ni media hora en encontrar la palabra mágica, seguramente la intentaría intuir:
Estudiando el resto del programa suponemos que las tres primeras instrucciones serán:
004012D3  /$ 55             PUSH EBP
004012D4  |. 8BEC           MOV EBP,ESP
así que si hacemos el xor de desencriptación de estos tres valores con los de la función encritpada nos escontramos con que los tres primeros bytes del dword mágico serían 0xD105BA?? y ahora podríamos hacer un brutalizador aún más rápido, con sólo 256 posibilidades. De esta forma me lo solucionaron en otro foro.
Y es que sí, el procedimiento empieza con "Push EBP y Mov EBP, ESP". ¿Por qué? Porque cuando programé el código quería que fuese solucionable sin fuerza bruta y el compilador MASM cuando llamo a un procedimiento al que le envío parámetros comienza con esas instrucciones para controlar la pila.
Así que le envío un parámetro del que realmente podría prescindir pero necesario para poder solucionarlo sin fuerza bruta, ya que, además de empezar con esas instrucciones, acabará con
0040131E  |. C9             LEAVE
0040131F  \. C2 0400        RETN 4
y aquí si que conozco 4 bytes seguidos para poder encontrar la clave mágica sin tener que crear nada.
Bueno, tendríamos que fijarnos que hay un RETN 4, porque precisamente sólo le envié un parámetro dword al procedimiento. Si vemos el regreso del procedimiento que calcula el CRC32 vemos que acaba con un RETN 8 porque se le envían 2 parámetros (inicio de memoria y longitud).
0xC9C20400 xor 091301BA = 0xC0D105BA
que está desordenado porque tenemos 79 bytes a cifrar/descifrar, así que 79 mod 4 = 3. Corremos los tres bytes y obtenemos el dword bueno.

@.:UND3R:. si no es esto lo que querías que te explicase por favor vuelve a preguntarme.

Saludos.
#25
Ingeniería Inversa / Re: Ayuda con ImportRec (Dump)
30 Noviembre 2011, 20:23 PM
Me suena haber tenido algo parecido. Creo recordar que el dumpeo estaba mal porque el empacador había modificado algo de la cabecera PE:
Antes de dumpear, cuando estés en el OEP comprueba la cabecera PE (si ha modificado algo con respecto a la original abres el programa en otro olly y la copias y pegas entera en modo binario).
Y para dumpear en ese momento el programa creo que usé el ChimpRec en lugar del OllyDump o el LordPE y me fue mejor.
Suerte y saludos.
#26
Cita de: karmany en 26 Noviembre 2011, 18:23 PM¿Tú no estás entre los cinco ganadores?
Buenas karmany, no estoy entre los ganadores porque antes del sorteo se pusieron en contacto con todos nosotros para ver quien podría asistir. Y como el asunto era en Argentina y yo estoy al otro lado del charco rapidamente me desvinculé de todo.
Lo cierto es que cuando lo solucioné ya sabía que no iba a ir, pero me gustó cómo estaba programado el manejador de excepciones del crackme y envié la solución para felicitar al programador. Un chico, muy majo por cierto, que me envió un correo para agradecerme las felicitaciones que le envié por el crackme.
#27
Ingeniería Inversa / Re: [Reto] Diofanto's Crackme
25 Noviembre 2011, 13:04 PM
Enhorabuena a todos. Ya veo que no ha durado nada el crackme. Pues nada, ahora a solucionar el Dioniso's.
Saludos.
#28
Tutorial del sencillo pero interesante crackme de ESET

Primero debería haber abierto el crackme con el PEiD o cualquier otro programa, pero confiando en la experiencia lo abrí sin más con el OllyDbg. Bien, parecía programado en MASM32, así que seguro que iba a estar todo bastante claro, además es el lenguaje que normalmente utilizo para mis crackmes y keygens.

Veo que no tiene mensaje de "chico bueno" y en seguida aprecio que lo primero que hace tras pulsar el botón OK es poner un controlador de errores. Supongo el error que busca pero por el momento no le hago caso. Luego lee el nombre introducido (mínimo 4 letras, máximo 19) y entra en un procedimiento 0x401000 que parece la inicialización de un MD5, así que paso de las dos siguientes llamadas y compruebo lo que hizo. Pues tenía razón, veo en el dump el hash MD5 de mi nick "PeterPunk" (empieza por 8D y acaba en 9D). A continuación suma los 16 bytes (más exactamente conjuntos de 8 bits) que componen el hash, y multiplica el resultado por 3. Así que para "PeterPunk" obtengo 0x163E.

Unas imágenes para aclarar esto:


Vemos como el PEiD coincide conmigo tanto en el lenguaje de programación como en el uso del hash MD5.


Esta es la parte de código que acabo de comentar.


Y en ésta apreciamos como en 0x404344 se encuentra el MD5 de "PeterPunk".

Lo siguiente que hace el crackme es leer el serial (número entero con signo). Al número introducido como serial se le suma el resultado del cálculo anterior y se le resta 0x42B8. Luego divide 1 entre el resultado anterior y muestra el mensaje de "Chico malo".

Obviamente y aunque el cracker en cuestión no entienda de excepciones va a suponer que lo único a lo que aspira es a que esa división sea entre 0, y a ver que pasa. Así que probamos

17080 (0x42B8) - 5694 (0x163E) = 11386 (qué número más bonito, acaba en 386). Probamos con la dupla "PeterPunk", "11386" y por arte de magia obtengo un mensaje de "chico bueno".

Otra tanda de imágenes:


Aquí vemos la parte de código que acabo de comentar y apreciamos que no hay comparación posible del serial introducido.  Y aparentemente obligatoriedad de mostrar el mensaje de "Chico malo". Por lo que sólo parece posible forzar una división por 0.


Esta es mi dupla típica. "PeterPunk" y "81818181" que irremediablemente siempre me devuelve el mensaje de error.


Si meto el valor que fuerza una división por 0 me muestra un mensajito de que soy bueno.

Por tanto vemos que cualquier persona que comience con el maravilloso mundo de la ingeniería inversa va a poder resolver el crackme, pero igual no se dan cuenta de lo verdaderamente interesante del mismo, el procedimiento programado para el control de excepciones.

Como he comentado con anterioridad en el primer vistazo del crackme reparé en que existía un procedimiento para controlar las posibles excepciones. Está definido en:
00402353   |.  BE 62224000        MOV ESI,00402262
00402358   |.  56                 PUSH ESI
00402359   |.  64:FF35 00000000   PUSH DWORD PTR FS:[0]
00402360   |.  64:8925 00000000   MOV FS:[0],ESP
y vemos que, por tanto, ese manejador está en 0x402262.

Lo voy a ir despiezando para comentar que es lo que hace cada cosa:

00402265   |.  8B5C24 08            MOV EBX,[ESP+8]Con lo que logramos que EBX señale a la estructura EXCEPTION_RECORD (http://msdn.microsoft.com/en-us/library/aa363082(v=VS.85).aspx).

A continuación:
00402269   |.  813B 940000C0        CMP DWORD PTR [EBX],C0000094
0040226F   |.  75 43                JNZ SHORT 004022B4
00402271   |.  E8 D6FFFFFF          CALL 0040224C
Si el código de la excepción es 0xC0000094 (EXCEPTION_INT_DIVIDE_BY_ZERO) llamamos al procedimiento 0x40224C que simplemente cambia el mensaje de "Bad boy!" por "Good boy" por medio de unos xor.

00402276   |.  8B7B 0C              MOV EDI,[EBX+C]
00402279   |.  83C7 16              ADD EDI,16
Aquí, lo que hacemos es que EDI apunte a la instrucción 0x40241B (por si no os coinciden las derecciones, va a ser siempre la siguiente a la llamada del MessageBox de "chico bueno", y ¿por qué?, porque [EBX+C] (EXCEPTION_RECORD + 0Ch) apunta a la dirección que produjo el error (la de DIV EBX) que en mi caso se trata de 0x402405, así que al sumarle 0x16 bytes vamos a apuntar siempre a la instrucción siguiente al MessageBox.

0040227C   |.  8B4424 10            MOV EAX,[ESP+10]Con esto logramos que EAX apunte a la estructura CONTEXT que contiene muchísima información (http://msdn.microsoft.com/en-us/library/ms679284(v=VS.85).aspx).

00402280   |.  C700 10000100        MOV DWORD PTR [EAX],10010
00402286   |.  8108 07000100        OR DWORD PTR [EAX],10007
Esto nos cambia las banderas de la estructura (ContextFlags) que controlan la información que guarda la estructura. Particularmente creo que no hace falta ya que por defecto nos va a aparecer con un valor de 0x1003F (información de todo) pero el crackme lo cambia a 0x10017 (CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_EGMENTS or DEBUG_REGISTERS).

0040228C   |.  8978 04              MOV [EAX+4],EDI
0040228F   |.  C740 18 01010000     MOV DWORD PTR [EAX+18],101
Aquí empieza lo bueno. Recordamos que EDI apuntaba a la instrucción siguiente al MessageBox. Bien, pues ahora lo guardamos en [EAX+4] (CONTEXT + 4h) que es el Debug Register #0, y en [EAX+18] (CONTEXT + 18h) que es el Debug Register 7, más conocido como DR7 o Debug Control, guardamos 0x101. Pues lo que acabamos de hacer es poner un BreakPoint eXecution en la dirección a la que apunta EDI. Si bajáis los PDFs de los manuales de desarrolladores de software para arquitecturas Intel 64 e IA-32 de la web de Intel, veréis que de el Debug Register #0 al #3 hacen referencia a las direcciones de los 4 breakpoints que se pueden usar y el Debug Control Register (DR7) controla la activación o desactivación de los mismos así como de sus condiciones. En este caso en este DR7 sólo hemos marcado el bit #0 (bp local activado en el primer breakpoint, que es el DR0) y el #8 (activado bp local exacto, que según Intel no está soportado desde el P6 pero recomiendan su uso por retrocompatibilidad o futura reimplementación).

00402296   |.  83EF 12              SUB EDI,12
00402299   |.  89B8 B8000000        MOV [EAX+B8],EDI
Vale, ahora hacemos que EDI apunte en mi caso a 0x402409 que para todos va a ser tercer parámetro del MessageBox (el título) y lo guardamos en [EAX+B8] (CONTEXT + 0B8h) que es el EIP, bueno exactamente el EIP en el momento que se produjo la excepción, así que si os fijáis, el valor que tiene [EAX+B8] antes de volcarle la nueva es el DIV EBX que produjo la división por 0. ¿Y para qué se cambia este valor? para que cuando se salga de este controlador de errores y el sistema operativo devuelva el control del programa a su rutina normal siga ejecutándose desde aquí. ¡Pero nos comemos el primer parámetro del MessageBox (uType) que controla los botones e iconos del mismo!. Tranquilos, el programador sabía lo que hacía:

0040229F   |.  83A8 C4000000 04     SUB DWORD PTR [EAX+C4],4
004022A6   |.  8B90 C4000000        MOV EDX,[EAX+C4]
004022AC   |.  C702 40000000        MOV DWORD PTR [EDX],40
Le resta 4 a [EAX+C4] (CONTEXT + 0C4h) que es el valor del ESP en el momento de la excepción. O sea, que modificamos el valor de la pila, como si hubiésemos hecho un "push dword" más y en esa dirección de la pila guardamos el valor 0x40 (MB_ICONINFORMATION) ya que lo que estamos es creando el parámetro que nos faltaba para el MessageBox y ahora el programa cuando siga su curso, ya no va a ejecutar el "PUSH 10h" como 4º parámetro del mensaje, que le otorgaría el MB_ICONERROR, sino que ha sido sustituido por un ficticio "PUSH 40h" (decrementando el valor de ESP y copiando ahí directamente el parámetro que queríamos).

Todo esto está muy bien, pero ¿para qué hemos creado un punto de ruptura en la instrucción siguiente al mensaje? Pues porque al llegar a esa instrucción, va a saltar la excepción STATUS_SINGLE_STEP (0x80000004) que también está controlada en el código manejador de excepciones:
004022B4   |> \813B 04000080        CMP DWORD PTR [EBX],80000004
004022BA   |.  75 37                JNZ SHORT 004022F3
004022BC   |.  E8 8BFFFFFF          CALL 0040224C
004022C1   |.  8B4424 10            MOV EAX,[ESP+10]
004022C5   |.  C700 07000100        MOV DWORD PTR [EAX],10007
004022CB   |.  8108 10000100        OR DWORD PTR [EAX],10010
004022D1   |.  C740 04 00000000     MOV DWORD PTR [EAX+4],0
004022D8   |.  C740 18 00000000     MOV DWORD PTR [EAX+18],0
004022DF   |.  8348 18 00           OR DWORD PTR [EAX+18],0
004022E3   |.  8148 18 00040000     OR DWORD PTR [EAX+18],400


O sea, como hemos puesto el breakpoint, cuando el código llega a esa instrucción (tras mostrar el mensaje de "Chico bueno"), nos salta una excepción, y con nuestro controlador de excepciones volvemos al procedimiento 0x402262.Ahí primero va a comprobar, como hemos visto antes, que el error sea 0xC0000094 (EXCEPTION_INT_DIVIDE_BY_ZERO) y como no lo es ya nos salta a la parte de código que acabo de pegar.

Al igual que antes vemos que EAX va a apuntar a la estructura CONTEXT.

Después vuelve a llamar al procedimiento que cambia el mensaje (esta vez el de "Chico bueno" por el de "Chico malo") para que no quede el bueno fijo ya que sino, aunque a continuación metiésemos un serial malo nos mostraría el bueno (eso sí, con el icono de error en el mensaje).

También vuelve a cambiar las banderas (ContextFlags) aunque sigo convencido de que esto no hace falta y esta vez borra el contenido de [EAX+4] (Debug Register #0) y cambia el valor de [EAX+18] (Debug Control o DR7) por 0x400. O sea que elimina el BPX que antes había puesto. Realmente para esto bastaría con poner a 0 el bit #0 del DR7, pero de todas formas lo normal para eliminar los breakpoints es poner a 0 ese DR7. Aquí, el crackme activa el bit #10 (0x400 = 100 0000 0000) pero lo cierto es qué no sé el motivo ya que en el manual de Intel, los bits #10, #11, #12, #14 y #15 de este Debug Control Register no están descritos, lo cual me hace suponer que no tienen ninguna utilidad si bien es cierto que en la figura 16.1 de dicho manual el bit #10 aparece con un 1 mientras que los otros cuatro con 0.


Este es el código del manejador de excepciones que realmente es el corazón del crackme.

Y eso es todo amigos, para cualquier duda u observación dejen un comentario a continuación.

Gracias a todos por leer este "ladrillo" y sobre todo gracias al programador del crackme por tomarse su tiempo en la construcción del manejador de excepciones.

Saludos.
#29
Buenas a todos. Lo cierto es que no suelo escribir ningún tutorial porque cuando lo hago tardo muchísimo más en crearlo que lo que he tardado en saltarme una protección y crear un parche/keygen. Y eso me desespera. Pero el siguiente lo he escrito por deferencia al autor.
El crackme en cuestión fue un desafío publicado a mediados de Agosto con motivo de la Ekoparty de este año:
http://blogs.eset-la.com/laboratorio/2011/08/15/crackme-de-eset-para-ekoparty-2011/
Los que lo hayáis estudiado o los que lo hagáis sin leer el tutorial veréis que se trata de un crackme muy simple y que resulta obvio de "keygenear" (inventando palabras desde ...). Pero tal vez no os deis cuenta de lo bien programado que está el manejador de excepciones, así que publico este tutorial (previamente publicado en otros foros) porque espero que sea instructivo para cualquier persona que comienza en este apasionante mundo de la ingeniería inversa.

Saludos.
#30
Ingeniería Inversa / Re: [Reto] Dioniso's Crackme
23 Noviembre 2011, 14:12 PM
@.:UND3R:. , puedes hacer esa parte con fuerza bruta si quieres. De todas formas creo que se puede resolver sin necesidad de ella, con un poco de estudio.
Saludos.