List of file signatures for file carving

File carving is the process of reassembling computer files from fragments in the absence of filesystem metadata. Wikipedia.
«File carving», literalmente tallado de archivos aunque lo traduciremos como extracción, es el proceso de re-ensamblado de archivos extraídos de un conjunto de mayor tamaño.
Índice
- Image files / Archivos de imagen
- Microsoft Office >2007
- Open Office
- Autocad
- Others / Otros
- Links / Enlaces
List of headers and tails / Lista de cabeceras y pies
Header = Cabecera
Footer or tail = Pie
Image files / Archivos de imagen
- JPEG
- Header: FFD8
- Footer: FFD9
- GIF87a
- Header: 47 49 46 38 37 61
- Footer: 00 3B
- GIF89a
- Header: 47 49 46 38 39 61
- Footer: 00 3B
- BMP
- Header: 42 4D
- Footer: Don’t have footer, but size is in bytes 2,3,4,5 in little-endian order (low byte first).
- Example: 00 00 C0 38 == 49208 bytes
- PNG
- Header: 89 50 4E 47 0D 0A 1A 0A
- Footer: 49 45 4E 44 AE 42 60 82
Microsoft Office >2007
All this documents have the same header and footer, because of this, we need search the middle bytes. This type uses a ZIP file package.
Los documentos de Microsoft Office >2007 tienen la misma cabecera y pie, por lo que necesitamos bytes intermedios para distinguirlos. Usan encapsulado ZIP.
- DOCX
- Header: 50 4B 03 04 14 00 06 00
- Middle: 77 6F 72 64 (word)
- Footer: 50 4B 05 06 (PK..) followed by 18 additional bytes at the end of the file.
- Header: 50 4B 03 04 14 00 06 00
- XLSX
- Header: 50 4B 03 04 14 00 06 00
- Middle: 77 6F 72 6B 73 68 65 65 74 73 (worksheets)
- Footer: 50 4B 05 06 (PK..) followed by 18 additional bytes at the end of the file.
- Header: 50 4B 03 04 14 00 06 00
- PPTX
- Header: 50 4B 03 04 14 00 06 00
- Middle: 70 72 65 73 65 6E 74 61 74 69 6F 6E (presentation)
- Footer: 50 4B 05 06 (PK..) followed by 18 additional bytes at the end of the file.
- Header: 50 4B 03 04 14 00 06 00
- MDB / ACCDB
- Header: 00 01 00 00 53 74 61 6E 64 61 72 64 20 4A 65 74 20 44 42 (….Standard Jet DB)
- Footer: Don’t have footer.
Open Office
All this documents have the same header and footer, because of this, we need some bytes to differentiate them. In this case we can do this jumping 73 bytes from header. This type uses a ZIP file package.
Los documentos de OpenOffice tienen la misma cabecera y pie, por lo que necesitamos bytes intermedios para distinguirlos. Usan encapsulado ZIP.
- ODS
- Header: 50 4B 03 04 14 (PK..) jump +73 (0x49) bytes and 73 70 72 65 (spre)
- Footer: 6D 61 6E 69 66 65 73 74 2E 78 6D 6C 50 4B 05 06 (manifest.xmlPK) followed by 18 additional bytes.
- ODT
- Header: 50 4B 03 04 14 (PK..) jump +73 (0x49) bytes and 74 65 78 64 (text)
- Footer: 6D 61 6E 69 66 65 73 74 2E 78 6D 6C 50 4B 05 06 (manifest.xmlPK) followed by 18 additional bytes.
- ODB
- Header: 50 4B 03 04 14 (PK..) jump +73 (0x49) bytes and 62 61 73 65 (base)
- Footer: 6D 61 6E 69 66 65 73 74 2E 78 6D 6C 50 4B 05 06 (manifest.xmlPK) followed by 18 additional bytes.
- ODG
- Header: 50 4B 03 04 14 (PK..) jump +73 (0x49) bytes and 67 72 61 70 (grap)
- Footer: 6D 61 6E 69 66 65 73 74 2E 78 6D 6C 50 4B 05 06 (manifest.xmlPK) followed by 18 additional bytes.
- ODF
- Header: 50 4B 03 04 14 (PK..) jump +73 (0x49) bytes and 66 6F 72 6D (form)
- Tail: 6D 61 6E 69 66 65 73 74 2E 78 6D 6C 50 4B 05 06 (manifest.xmlPK) followed by 18 additional bytes.
- ODP
- Header: 50 4B 03 04 14 (PK..) jump +73 (0x49) bytes and 70 72 65 73 (pres)
- Footer: 6D 61 6E 69 66 65 73 74 2E 78 6D 6C 50 4B 05 06 (manifest.xmlPK) followed by 18 additional bytes.
Autocad
- DWG (R11/R12 versions)
- Header: 41 43 31 30 30 39
- Footer: CD 06 B2 F5 1F E6
- DWG (R14 version)
- Header: 41 43 31 30 31 34
- Footer: 62 A8 35 C0 62 BB EF D4
- DWG (2000 version)
- Header: 41 43 31 30 31 34
- Footer: DB BF F6 ED C3 55 FE
- DWG (>2007 versions)
- Header: 41 43 31 30 XX XX
- Footer: Don’t have
Note: >2007 versions have two patterns and the key is the position 0x80. If in this position we get the bytes «68 40 F8 F7 92», we need to search again for this bytes and displace 107 bytes to find the end of the file. If in the position 0x80 we get another different bytes, we need to search again this bytes and displace 1024 bytes to find the end of the file.
Nota: Las versiones >2007 siguen dos patrones y la clave está en la posición 0x80. Si en la posicion 0x80 obtenemos los bytes «68 40 F8 F7 92», los buscamos una segunda vez y ha 107 bytes encontramos el final del archivo. Si en la posición 0x80 obtenemos otros bytes diferentes a los del primer caso, los volvemos a buscar y a 1024 bytes hallaremos el final del archivo.
Others / Otros
- PDF
- Header: 25 50 44 46 (%PDF)
- Footers:
- 0A 25 25 45 4F 46 (.%%EOF) or
- 0A 25 25 45 4F 46 0A (.%%EOF.) or
- 0D 0A 25 25 45 4F 46 0D 0A (..%%EOF..) or
- 0D 25 25 45 4F 46 0D (.%%EOF.)
- ZIP
- Header: 50 4B 03 04
- Footer: 50 4B 05 06 (PK..) followed by 18 additional bytes at the end of the file.
- RAR (< 4.x version)
- Header: 52 61 72 21 1A 07 00
- Tail: C4 3D 7B 00 40 07 00
- 7ZIP
- Header: 37 7A BC AF 27 1C 00 03 (7z¼¯’…)
- Footer: 01 15 06 01 00 20 followed by 5 additional bytes at the end of the file.
- RTF
- Header: 7B 5C 72 74 66 31
- Footer: 5C 70 61 72 20 7D
Links / Enlaces
Blooper Tech Movie V – Algo huele a podrido en Hawkins

He de iniciar esta entrada diciendo que la segunda temporada de Stranger Things es sencillamente genial. Son 9 horas intensas que no dejan indiferente a nadie y además en el capítulo 8 nos han dejado una de esas perlas informáticas que tanto nos gustan.
La escena la protagoniza Bob Newby, un buen hombre amante de la electrónica de aquella época que trabaja en RadioShack y transcurre en el laboratorio secreto de Hawkins. En un momento dado, Bob propone «saltarse» la seguridad del laboratorio y para ello se traslada al sótano donde se encuentran los «servidores».
El PC de la época
Para comprender esta escena hay que situarse temporalmente. Estamos hablando de los años 80, en concreto la escena transcurre en 1984 y los equipos de los que dispone el laboratorio son unos maravillosos IBM. No se llega a apreciar bien el modelo de IBM utilizado pero teniendo en cuenta que el monitor que aparece es un terminal IBM 3180, la búsqueda se reduce a los sistemas compatibles S/36, S/38, AS/400, 5294 ó 5394.
Cracking BASIC or BASIC Cracking?
La escena plantea un ataque de fuerza bruta a un código de 4 dígitos como se puede observar en la imagen a continuación. Esto puede parecer una chorrada hoy día pero podía suponer un pequeño reto para un micro de 8 bits.
A simple vista se aprecian una serie de bucles recursivos, una llamada a una función y una sentencia condicional. Desconozco si la sintaxis del lenguaje es la correcta pero mucho me temo que es más bien una mezcla de BASIC y pseudocódigo. Pero lo que más me ha llamado la atención sin duda es que la palabra THEN parece que se sale del monitor como si estuviera realizado en post-producción. Os invito a que ampliéis la imagen y comentéis lo que os parece a vosotr@s.
Os dejo aquí el código para los más curiosos.
10 DIM FourDigitPassword INTEGER 20 FOR i = 0 TO 9 30 FOR j = 0 TO 9 40 FOR k = 0 TO 9 50 FOR l = 0 TO 9 60 FourDigitPassword = getFourDigits (i,j,k,l) 70 IF checkPasswordMatch(FourDigitPassword) = TRUE THEN 80 GOTO 140 90 END 100 NEXT l 110 NEXT k 120 NEXT j 130 NEXT i 140 PRINT FourDigitPassword
Aunque la entrada está dentro del contexto de los Blooper Tech Movies, digamos que en esta ocasión no voy a ir más allá. La escena es creíble y queda bien integrada en la época en la que se desarrolla el capítulo. Por esto mismo, solamente espero que las temporadas venideras sean tan buenas y cuiden tanto los detalles como sus predecesoras.
Referencias
[1] Ficha IMDB – Stranger Thing
[3] IBM 3180
[4] BASIC
Reversing – Nosotros y ChatGPT contra un ELF desde Windows

Intro
Antes que nada, es importante saber que un archivo ELF en Linux es equivalente a un archivo EXE en Windows. Dicho esto, es bastante común encontrarnos con ejecutables ELF en diversos CTFs (Capture The Flag), y a menudo representan un desafío para aquellos no familiarizados con el uso cotidiano de Linux. Sin embargo, tengo una buena noticia si no eres aficionado de Linux: existen herramientas que permiten realizar un análisis preliminar para determinar si es necesario abordar el problema desde Linux o si podemos resolverlo directamente desde Windows. Estas herramientas facilitan una transición más cómoda para los usuarios de Windows, permitiéndoles interactuar eficazmente con archivos ELF.
ELF
Un archivo ELF (Executable and Linkable Format) es un formato común de archivo para archivos ejecutables, código objeto, bibliotecas compartidas y volcados de memoria en sistemas basados en Unix, como Linux. Es el estándar de formato de archivo para programas compilados y enlazados en este tipo de sistemas operativos.
La cabecera de un archivo ELF es una estructura de datos al comienzo del archivo que proporciona información esencial sobre el contenido y la forma de procesar el archivo. Esta cabecera es fundamental para que el sistema operativo y otros programas puedan interpretar correctamente el archivo ELF. Aquí están los componentes clave de la cabecera de un archivo ELF:
- Identificación (e_ident): Esta sección incluye la magia del archivo ELF, representada por los primeros cuatro bytes
0x7F 'E' 'L' 'F'. También incluye información como la clase del archivo (32 o 64 bits), la codificación de datos (endianness), y la versión del formato ELF. - Tipo (e_type): Indica el tipo de archivo ELF, como EXEC (ejecutable), DYN (biblioteca compartida), REL (relocalizable), entre otros.
- Máquina (e_machine): Especifica la arquitectura de hardware para la cual se diseñó el archivo, por ejemplo, x86, ARM.
- Versión (e_version): La versión del formato ELF, generalmente establecida en 1.
- Punto de Entrada (e_entry): La dirección de memoria virtual donde comienza la ejecución del proceso.
- Desplazamiento del Program Header (e_phoff): Indica dónde comienza el encabezado del programa en el archivo.
- Desplazamiento del Section Header (e_shoff): Indica dónde comienza el encabezado de la sección en el archivo.
- Flags (e_flags): Banderas específicas del procesador.
- Tamaño de esta cabecera (e_ehsize): El tamaño de la cabecera ELF.
- Tamaño del Program Header (e_phentsize): El tamaño de una entrada del encabezado del programa.
- Número de entradas del Program Header (e_phnum): El número total de entradas en el encabezado del programa.
- Tamaño del Section Header (e_shentsize): El tamaño de una entrada del encabezado de la sección.
- Número de entradas del Section Header (e_shnum): El número total de entradas en el encabezado de la sección.
- Índice del Section Header Table (e_shstrndx): El índice del encabezado de la sección que contiene los nombres de las secciones.
El reto
Se nos proporciona un fichero de 20KB que rápidamente catalogamos como ELF.

Para realizar un análisis preliminar siempre uso DogBolt, que no es más que un decompilador online con la ventaja de que usa varios motores y de esta forma casi siempre te da una decompilación aceptable. La versión actual tiene disponibles 11 motores y además es open source, ¿Qué más se puede pedir?

Echamos un vistazo y enseguida encontramos algo interesante.

La flag parece codificada de modo que vamos a indagar acerca de la función FUN_0010285d

Dentro de la función FUN_0010285d vemos que nuestra flag codificada la procesa la función FUN_00102752

Aquí os diría que depende de vuestra experiencia en programación veríais que se está procesando byte a byte la cadena de entrada (param_1) y haciendo a cada byte un XOR (^) con el param_3 (que es 1 según vemos en la llamada de la función FUN_00102752), pero en estos tiempos que corren vamos a preguntar a ChatGPT que opina.
ChatGPT
Le pido a ChapGPT que me analice el código y me responde:
Este código en C define una función llamada
FUN_00102752que realiza una operación de XOR (exclusivo OR) byte a byte sobre un bloque de memoria. La función toma tres parámetros:
long param_1: Este parámetro es tratado como una dirección de memoria. Se utiliza como la base de un bloque de memoria sobre el que se realizará la operación.ulong param_2: Este parámetro especifica el tamaño del bloque de memoria que será afectado por la operación.byte param_3: Este es el valor de un solo byte que se utilizará en la operación XOR.El cuerpo de la función consiste en un bucle
forque itera sobre el bloque de memoria:
int local_cse declara como una variable local y se inicializa en 0. Esta variable actúa como un contador para el bucle.- La condición del bucle
(ulong)(long)local_c < param_2asegura que el bucle se ejecute sobre el rango completo del bloque de memoria especificado porparam_2.- Dentro del bucle,
*(byte *)(param_1 + local_c) = *(byte *)(param_1 + local_c) ^ param_3;realiza la operación XOR. Aquí,*(byte *)(param_1 + local_c)accede al byte actual en el bloque de memoria. Este byte se modifica aplicándole un XOR conparam_3. La operación XOR se realiza entre el byte actual en la memoria y el valor deparam_3, y el resultado se escribe de nuevo en la misma ubicación de memoria.En resumen, la función
by ChatGPTFUN_00102752modifica un bloque de memoria aplicando una operación XOR con un valor dado (param_3) a cada byte dentro del rango de memoria especificado desdeparam_1hastaparam_1 + param_2. Este tipo de operación es común en tareas como la manipulación de datos para cifrado/descifrado o para la generación de patrones específicos en un bloque de datos.
Ahora imaginad que no sois muy dados a programar o simplemente estáis vagos de modo que volvemos a recurrir a ChatGPT con el promt «Haz un XOR 1 con javascript a la cadena: gmfzuihr^vr^o^drx^nod^shfiu|» a lo que responde:
function xorString(str) {
return Array.from(str).map(char => String.fromCharCode(char.charCodeAt(0) ^ 1)).join(»);
}console.log(xorString(‘gm
by ChatGPTfzuihr^vr^o^drx^nod^shfiu|’));
Copiamos el código y lo pegamos en un entorno online como por ejemplo playcode.io.

Este es un ejemplo simple, pero ¿percibís su potencial?
La imagen de portada de esta entrada ha sido generada con ChatGPT.
Solución al Crackme Zebra 1.1 de aLoNg3x

Introducción
Hoy tenemos aquí un crackme de los que te hacen temblar las conexiones neuronales. Estamos acostumbrados al típico serial asociado a un nombre y a veces nos sorprenden.
El crackme data del año 2000, está realizado por aLoNg3x y lo tenéis colgado en crackmes.de. En crackmes.de también disponéis de una solución muy elegante realizada por cronos, pero que no acaba de saciar nuestro afán de descubrir todas las soluciones posibles.
El algoritmo
Abrimos el crackme con Olly y enseguida encontramos la rutina de comprobación junto con los mensajes de éxito y error. Os dejo la rutina comentada como siempre.
004012D7 |. 83C4 08 ADD ESP,8 ;
004012DA |. 09C0 OR EAX,EAX ;
004012DC |. /74 16 JE SHORT Zebrone.004012F4 ; Salta a Bad boy
004012DE |. |6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
004012E0 |. |68 26324000 PUSH Zebrone.00403226 ; |Title = "Great !!!"
004012E5 |. |68 30324000 PUSH Zebrone.00403230 ; |Text = "Congratulations, you have cracked the Zebra Crackme ver 1.1"
004012EA |. |FF75 08 PUSH [ARG.1] ; |hOwner = 0011067C ('Zebra - aLoNg3x - 1.1 Version',class='#32770')
004012ED |. |E8 C6010000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
004012F2 |. |EB 14 JMP SHORT Zebrone.00401308
004012F4 |> \6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
004012F6 |. 68 F8314000 PUSH Zebrone.004031F8 ; |Title = "Hmmmm :P"
004012FB |. 68 01324000 PUSH Zebrone.00403201 ; |Text = "Sorry... The Serial isn't correct :Þ"
00401300 |. FF75 08 PUSH [ARG.1] ; |hOwner = 0011067C ('Zebra - aLoNg3x - 1.1 Version',class='#32770')
00401303 |. E8 B0010000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
00401308 |> 31C0 XOR EAX,EAX
0040130A |. 40 INC EAX
0040130B |. EB 39 JMP SHORT Zebrone.00401346
0040130D |> 6A 00 PUSH 0 ; /Result = 0
0040130F |. FF75 08 PUSH [ARG.1] ; |hWnd = 0011067C ('Zebra - aLoNg3x - 1.1 Version',class='#32770')
00401312 |. E8 89010000 CALL <JMP.&USER32.EndDialog> ; \EndDialog
00401317 |. 31C0 XOR EAX,EAX
00401319 |. 40 INC EAX
0040131A |. EB 2A JMP SHORT Zebrone.00401346
0040131C |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
0040131E |. 68 40304000 PUSH Zebrone.00403040 ; |Title = "Zebra ver. 1.1"
00401323 |. 68 4F304000 PUSH Zebrone.0040304F ; |Text = "This is the 1.1 Zebra Crackme, Thanks to Quequero and Koma, to have said me a bug of the previous version. (It was due to an orrible cpu appoximation). As usually you cannot patch this .EXE, you've to find one of the many correct solut"...
00401328 |. FF75 08 PUSH [ARG.1] ; |hOwner = 0011067C ('Zebra - aLoNg3x - 1.1 Version',class='#32770')
0040132B |. E8 88010000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
00401330 |. 31C0 XOR EAX,EAX
00401332 |. 40 INC EAX
00401333 |. EB 11 JMP SHORT Zebrone.00401346
00401335 |> 6A 00 PUSH 0 ; /Result = 0
00401337 |. FF75 08 PUSH [ARG.1] ; |hWnd = 0011067C ('Zebra - aLoNg3x - 1.1 Version',class='#32770')
0040133A |. E8 61010000 CALL <JMP.&USER32.EndDialog> ; \EndDialog
0040133F |. 31C0 XOR EAX,EAX
00401341 |. 40 INC EAX
00401342 |. EB 02 JMP SHORT Zebrone.00401346
00401344 |> 31C0 XOR EAX,EAX
00401346 |> C9 LEAVE
00401347 \. C2 1000 RETN 10
================================================================
0040134A /$ 55 PUSH EBP
0040134B |. 89E5 MOV EBP,ESP
0040134D |. 83EC 68 SUB ESP,68
00401350 |. FF75 08 PUSH [ARG.1] ; /x1
00401353 |. E8 78010000 CALL <JMP.&CRTDLL.atof> ; \atof
00401358 |. DD55 E8 FST QWORD PTR SS:[EBP-18]
0040135B |. 83EC 08 SUB ESP,8
0040135E |. DD1C24 FSTP QWORD PTR SS:[ESP]
00401361 |. E8 82010000 CALL <JMP.&CRTDLL.floor>
00401366 |. DD5D F8 FSTP QWORD PTR SS:[EBP-8]
00401369 |. FF75 0C PUSH [ARG.2] ; /x2
0040136C |. E8 5F010000 CALL <JMP.&CRTDLL.atof> ; \atof
00401371 |. DD55 D8 FST QWORD PTR SS:[EBP-28]
00401374 |. 83EC 08 SUB ESP,8
00401377 |. DD1C24 FSTP QWORD PTR SS:[ESP]
0040137A |. E8 69010000 CALL <JMP.&CRTDLL.floor>
0040137F |. 83C4 18 ADD ESP,18
00401382 |. DD55 F0 FST QWORD PTR SS:[EBP-10]
00401385 |. DC4D F8 FMUL QWORD PTR SS:[EBP-8]
00401388 |. D9EE FLDZ
0040138A |. DED9 FCOMPP ; floor(x1)*floor(x2)=0 ???
0040138C |. DFE0 FSTSW AX ; <<Store status word
0040138E |. 9E SAHF ; <<Store AH into FLAGS
0040138F |. 75 07 JNZ SHORT Zebrone.00401398 ; Si salta todo OK
00401391 |. 31C0 XOR EAX,EAX
00401393 |. E9 96000000 JMP Zebrone.0040142E ; Bad boy
00401398 |> DD45 F8 FLD QWORD PTR SS:[EBP-8] ; <<Floating point load
0040139B |. DC5D F0 FCOMP QWORD PTR SS:[EBP-10] ; x1 = x2 ???
0040139E |. DFE0 FSTSW AX ; <<Store status word
004013A0 |. 9E SAHF ; <<Store AH into FLAGS
004013A1 |. 75 07 JNZ SHORT Zebrone.004013AA ; Si salta todo OK
004013A3 |. 31C0 XOR EAX,EAX
004013A5 |. E9 84000000 JMP Zebrone.0040142E ; Bad boy
004013AA |> DD45 F8 FLD QWORD PTR SS:[EBP-8] ; <<Floating point load
004013AD |. DD5D C8 FSTP QWORD PTR SS:[EBP-38]
004013B0 |. D9E8 FLD1 ; Carga 1 en el stack
004013B2 |. DD55 C0 FST QWORD PTR SS:[EBP-40] ; <<Floating point store
004013B5 |. DC5D C8 FCOMP QWORD PTR SS:[EBP-38] ; x1 > 1 ???
004013B8 |. DFE0 FSTSW AX ; <<Store status word
004013BA |. 9E SAHF ; <<Store AH into FLAGS
004013BB |. 77 2D JA SHORT Zebrone.004013EA ; Si salta bad boy
004013BD |. DF2D 38304000 FILD QWORD PTR DS:[403038] ; <<Load integer>> 2540BE400 = 10^10
004013C3 |. DD55 B8 FST QWORD PTR SS:[EBP-48] ; <<Floating point store
004013C6 |. DC5D C8 FCOMP QWORD PTR SS:[EBP-38] ; x1 < 10^10 ???
004013C9 |. DFE0 FSTSW AX ; <<Store status word
004013CB |. 9E SAHF ; <<Store AH into FLAGS
004013CC |. 72 1C JB SHORT Zebrone.004013EA ; Si salta bad boy
004013CE |. DD45 F0 FLD QWORD PTR SS:[EBP-10] ; <<Floating point load
004013D1 |. DD5D B0 FSTP QWORD PTR SS:[EBP-50] ; <<Store and pop
004013D4 |. DD45 C0 FLD QWORD PTR SS:[EBP-40] ; <<Floating point load
004013D7 |. DC5D B0 FCOMP QWORD PTR SS:[EBP-50] ; x2 > 1 ???
004013DA |. DFE0 FSTSW AX ; <<Store status word
004013DC |. 9E SAHF ; <<Store AH into FLAGS
004013DD |. 77 0B JA SHORT Zebrone.004013EA ; Si salta bad boy
004013DF |. DD45 B8 FLD QWORD PTR SS:[EBP-48] ; <<Floating point load>> carga 10^10
004013E2 |. DC5D B0 FCOMP QWORD PTR SS:[EBP-50] ; x2 < 10^10 ???
004013E5 |. DFE0 FSTSW AX ; <<Store status word
004013E7 |. 9E SAHF ; <<Store AH into FLAGS
004013E8 |. 73 04 JNB SHORT Zebrone.004013EE ; Salta si menor
004013EA |> 31C0 XOR EAX,EAX
004013EC |. EB 40 JMP SHORT Zebrone.0040142E ; Bad boy
004013EE |> DD45 F8 FLD QWORD PTR SS:[EBP-8] ; <<Floating point load>> carga x1
004013F1 |. D9FE FSIN ; Sin(x1)
004013F3 |. DD5D A8 FSTP QWORD PTR SS:[EBP-58] ; <<Store and pop
004013F6 |. DD45 F0 FLD QWORD PTR SS:[EBP-10] ; <<Floating point load>> carga x2
004013F9 |. D9FE FSIN ; Sin(x2)
004013FB |. DD5D A0 FSTP QWORD PTR SS:[EBP-60] ; <<Store and pop
004013FE |. DD45 A8 FLD QWORD PTR SS:[EBP-58] ; <<Floating point load
00401401 |. DC4D A0 FMUL QWORD PTR SS:[EBP-60] ; Sin(x1) * Sin(x2)
00401404 |. DF2D 30304000 FILD QWORD PTR DS:[403030] ; <<Load integer>> 2386F26FC10000 = 10^16
0040140A |. DEC9 FMULP ST(1),ST ; 10^16 * (Sin(x1) * Sin(x2))
0040140C |. 83EC 08 SUB ESP,8
0040140F |. DD1C24 FSTP QWORD PTR SS:[ESP] ; <<Store and pop
00401412 |. E8 D1000000 CALL <JMP.&CRTDLL.floor>
00401417 |. 83C4 08 ADD ESP,8
0040141A |. DD5D 98 FSTP QWORD PTR SS:[EBP-68]
0040141D |. D9EE FLDZ ; <<Load 0.0 onto stack
0040141F |. DC5D 98 FCOMP QWORD PTR SS:[EBP-68] ; 10^16 * (Sin(x1) * Sin(x2)) = 0 ???
00401422 |. DFE0 FSTSW AX
00401424 |. 9E SAHF ; <<Store AH into FLAGS
00401425 |. 75 05 JNZ SHORT Zebrone.0040142C ; Si NO salta todo OK
00401427 |. 31C0 XOR EAX,EAX
00401429 |. 40 INC EAX
0040142A |. EB 02 JMP SHORT Zebrone.0040142E
0040142C |> 31C0 XOR EAX,EAX
0040142E |> C9 LEAVE
0040142F \. C3 RETN
La primera dificultad que podemos encontrar es que utiliza instrucciones FPU y coma flotante, ya que si no tenemos la vista entrenada nos puede resultar un engorro. Superado esto, la rutina de comprobación se puede resumir así:
- x1 * x2 != 0
- x1 != x2
- x1 > 1 y < 10^10
- x2 > 1 y < 10^10
- Floor[10^16 * sin(x1) * sin(x2)] = 0
A priori no parece que tenga mucha dificultad, pero vamos a analizarlo más concienzudamente. Necesitamos que la parte entera del resultado de la multiplicación sea 0, algo que parece sencillo, pero fíjate que la constante 10^16 nos obliga a su vez, a que el resultado del seno sea muy pequeño, cosa que como comprobaréis limita mucho los resultados satisfactorios.
Repasando trigonometría
Cuando nos enseñó nuestro profesor la función del seno nos hizo el siguiente dibujo:
Partiendo de la circunferencia unitaria, podemos concluir que el seno de alpha es igual a la altura x. Como lo que nos interesa a nosotros es que el seno sea muy pequeño, en realidad estamos buscando que la x sea lo más pequeña posible. Llegamos entonces a la conclusión de que las soluciones para enteros entre 1 y 10^10 van a ser muy reducidas. Además nos percatamos que el ángulo alpha va a tener que estar muy proximo a 0º – 360 (0 – 2π) y a 180º (π). En el siguiente gráfico queda claro el estrecho margen en el que nos movemos.
Si habéis leído la solución de cronos ahora le encontraréis algo más de sentido a por que él utilizó fracciones continuas de π y cogió como resultado los numeradores más cercanos a 10^10, en su caso 245850922 y 411557987.
Análisis operacional
Vamos a analizar un ejemplo operacional.
sin( x rad) sin(245850922) = 6,1180653830011163142712109862972e-9 sin(411557987) = 2,536716051963676479648989773448e-9 sin(245850922)*sin(411557987) = 1,5519794664022230015882605365808e-17 10^16 * 1,5519794664022230015882605365808e-17 = 0,15519794664022230015882605365808 Floor(0,15519794664022230015882605365808) = 0
Como veis, el exponente negativo (^-17) debe ser mayor que el positivo (^16) para tener éxito.
Fuerza bruta
Lo que vamos a hacer a continuación es buscar todos los senos con exponente negativo ^-8 ó ^-9 de enteros entre 1 y 10^10, y vamos a cruzar los resultados para determinar todos los resultados válidos.
Preparamos el programa y le dejamos trabajar. En principio vamos a filtrar todos los resultados que tengan exponente negativo y luego ya aislaremos los que nos interesan. Esto lo hago por curiosidad.
La fuerza bruta nos arroja 63663 resultados con exponente negativo entre ^-5 y ^-9, de los cuales solamente nos quedamos con 65, que son los comprendidos a exponentes de entre ^-8 y ^-9. Los números mágicos son los siguientes:
Los rojos son exponentes ^-9, el resto ^-8.
La mayoría de estos números solo valen con ciertas combinaciones, de hecho, ninguno vale para todos. Esto se debe, a parte del propio exponente, a que hay senos positivos y negativos y para hacer válido a un seno negativo hay que combinarlo con otro negativo. Esto último se debe únicamente a la interpretación que hace el crackme.
Finalmente cruzamos los resultados y obtenemos 44 combinaciones de seriales válidos que si obviamos repeticiones se reducen a la mitad.
Combinaciones válidas:
Conclusiones
Podemos concluir que para cada 10^10 enteros hay 22 soluciones posibles. Finalmente comentar que si aLoNg3x no hubiera puesto el límite en 10^10, habría soluciones infinitas.
Links
- Crackme
- Archivos del proyecto (programas, logs…)
- Solución de cronos
- Instrucciones FPU
- Fracción continua o cual es la mejor aproximación (Gaussianos)
- Circunferencia unitaria (Video)
- Función Seno
- Función Floor
lost_in_bin

Estamos ante un ELF un poco más interesante que los vistos anteriormente. Básicamente porque es divertido y fácil encontrar la solución en el decompilado y quizá por evocar recuerdos de tiempos pretéritos.
ELF Decompilado
/* This file was generated by the Hex-Rays decompiler version 8.4.0.240320.
Copyright (c) 2007-2021 Hex-Rays <info@hex-rays.com>
Detected compiler: GNU C++
*/
#include <defs.h>
//-------------------------------------------------------------------------
// Function declarations
__int64 (**init_proc())(void);
__int64 sub_400650(); // weak
// int printf(const char *format, ...);
// int puts(const char *s);
// void __noreturn exit(int status);
// size_t strlen(const char *s);
// __int64 __fastcall MD5(_QWORD, _QWORD, _QWORD); weak
// int sprintf(char *s, const char *format, ...);
// __int64 ptrace(enum __ptrace_request request, ...);
// __int64 strtol(const char *nptr, char **endptr, int base);
// __int64 __isoc99_scanf(const char *, ...); weak
// int memcmp(const void *s1, const void *s2, size_t n);
void __fastcall __noreturn start(__int64 a1, __int64 a2, void (*a3)(void));
void *sub_400730();
__int64 sub_400760();
void *sub_4007A0();
__int64 sub_4007D0();
void fini(void); // idb
void term_proc();
// int __fastcall _libc_start_main(int (__fastcall *main)(int, char **, char **), int argc, char **ubp_av, void (*init)(void), void (*fini)(void), void (*rtld_fini)(void), void *stack_end);
// __int64 _gmon_start__(void); weak
//-------------------------------------------------------------------------
// Data declarations
_UNKNOWN main;
_UNKNOWN init;
__int64 (__fastcall *funcs_400E29)() = &sub_4007D0; // weak
__int64 (__fastcall *off_601DF8)() = &sub_4007A0; // weak
__int64 (*qword_602010)(void) = NULL; // weak
char *off_602080 = "FLAG-%s\n"; // idb
char a7yq2hryrn5yJga[16] = "7Yq2hrYRn5Y`jga"; // weak
const char aO6uH[] = "(O6U,H\""; // idb
_UNKNOWN unk_6020B8; // weak
_UNKNOWN unk_6020C8; // weak
char byte_6020E0; // weak
char s1; // idb
char byte_602110[]; // weak
char byte_602120[33]; // weak
char byte_602141[7]; // idb
__int64 qword_602148; // weak
__int64 qword_602150; // weak
__int64 qword_602158; // weak
__int64 qword_602160; // weak
__int64 qword_602178; // weak
//----- (0000000000400630) ----------------------------------------------------
__int64 (**init_proc())(void)
{
__int64 (**result)(void); // rax
result = &_gmon_start__;
if ( &_gmon_start__ )
return (__int64 (**)(void))_gmon_start__();
return result;
}
// 6021D8: using guessed type __int64 _gmon_start__(void);
//----- (0000000000400650) ----------------------------------------------------
__int64 sub_400650()
{
return qword_602010();
}
// 400650: using guessed type __int64 sub_400650();
// 602010: using guessed type __int64 (*qword_602010)(void);
//----- (0000000000400700) ----------------------------------------------------
// positive sp value has been detected, the output may be wrong!
void __fastcall __noreturn start(__int64 a1, __int64 a2, void (*a3)(void))
{
__int64 v3; // rax
int v4; // esi
__int64 v5; // [rsp-8h] [rbp-8h] BYREF
char *retaddr; // [rsp+0h] [rbp+0h] BYREF
v4 = v5;
v5 = v3;
_libc_start_main((int (__fastcall *)(int, char **, char **))main, v4, &retaddr, (void (*)(void))init, fini, a3, &v5);
__halt();
}
// 400706: positive sp value 8 has been found
// 40070D: variable 'v3' is possibly undefined
//----- (0000000000400730) ----------------------------------------------------
void *sub_400730()
{
return &unk_6020C8;
}
//----- (0000000000400760) ----------------------------------------------------
__int64 sub_400760()
{
return 0LL;
}
//----- (00000000004007A0) ----------------------------------------------------
void *sub_4007A0()
{
void *result; // rax
if ( !byte_6020E0 )
{
result = sub_400730();
byte_6020E0 = 1;
}
return result;
}
// 6020E0: using guessed type char byte_6020E0;
//----- (00000000004007D0) ----------------------------------------------------
__int64 sub_4007D0()
{
return sub_400760();
}
//----- (00000000004007D7) ----------------------------------------------------
__int64 __fastcall main(int a1, char **a2, char **a3)
{
size_t v3; // rax
size_t v4; // rax
int i; // [rsp+1Ch] [rbp-24h]
int n; // [rsp+20h] [rbp-20h]
int m; // [rsp+24h] [rbp-1Ch]
int k; // [rsp+28h] [rbp-18h]
int j; // [rsp+2Ch] [rbp-14h]
if ( ptrace(PTRACE_TRACEME, 0LL, 0LL, 0LL) == -1 )
goto LABEL_2;
if ( a1 > 4 )
{
qword_602148 = strtol(a2[1], 0LL, 10);
if ( qword_602148 )
{
qword_602150 = strtol(a2[2], 0LL, 10);
if ( qword_602150 )
{
qword_602158 = strtol(a2[3], 0LL, 10);
if ( qword_602158 )
{
qword_602160 = strtol(a2[4], 0LL, 10);
if ( qword_602160 )
{
if ( -24 * qword_602148 - 18 * qword_602150 - 15 * qword_602158 - 12 * qword_602160 == -18393
&& 9 * qword_602158 + 18 * (qword_602150 + qword_602148) - 9 * qword_602160 == 4419
&& 4 * qword_602158 + 16 * qword_602148 + 12 * qword_602150 + 2 * qword_602160 == 7300
&& -6 * (qword_602150 + qword_602148) - 3 * qword_602158 - 11 * qword_602160 == -8613 )
{
qword_602178 = qword_602158 + qword_602150 * qword_602148 - qword_602160;
sprintf(byte_602141, "%06x", qword_602178);
v4 = strlen(byte_602141);
MD5(byte_602141, v4, byte_602110);
for ( i = 0; i <= 15; ++i )
sprintf(&byte_602120[2 * i], "%02x", (unsigned __int8)byte_602110[i]);
printf(off_602080, byte_602120);
exit(0);
}
}
}
}
}
LABEL_2:
printf("password : ");
__isoc99_scanf("%s", &s1);
if ( strlen(&s1) > 0x10 )
{
puts("the password must be less than 16 character");
exit(1);
}
for ( j = 0; j < strlen(&s1); ++j )
*(&s1 + j) ^= 6u;
if ( !strcmp(&s1, a7yq2hryrn5yJga) )
{
v3 = strlen(&s1);
MD5(&s1, v3, byte_602110);
for ( k = 0; k <= 15; ++k )
sprintf(&byte_602120[2 * k], "%02x", (unsigned __int8)byte_602110[k]);
printf(off_602080, byte_602120);
exit(0);
}
puts("bad password!");
exit(0);
}
printf("password : ");
__isoc99_scanf("%s", &s1);
if ( strlen(&s1) > 0x10 )
{
puts("the password must be less than 16 character");
exit(1);
}
for ( m = 0; m < strlen(&s1); ++m )
{
*(&s1 + m) ^= 2u;
++*(&s1 + m);
*(&s1 + m) = ~*(&s1 + m);
}
if ( !memcmp(&s1, &unk_6020B8, 9uLL) )
{
for ( n = 0; n < strlen(aO6uH); n += 2 )
{
aO6uH[n] ^= 0x45u;
aO6uH[n + 1] ^= 0x26u;
}
puts(aO6uH);
}
else
{
puts("bad password!");
}
return 0LL;
}
// 4006A0: using guessed type __int64 __fastcall MD5(_QWORD, _QWORD, _QWORD);
// 4006E0: using guessed type __int64 __isoc99_scanf(const char *, ...);
// 602148: using guessed type __int64 qword_602148;
// 602150: using guessed type __int64 qword_602150;
// 602158: using guessed type __int64 qword_602158;
// 602160: using guessed type __int64 qword_602160;
// 602178: using guessed type __int64 qword_602178;
//----- (0000000000400DE0) ----------------------------------------------------
void __fastcall init(unsigned int a1, __int64 a2, __int64 a3)
{
signed __int64 v3; // rbp
__int64 i; // rbx
v3 = &off_601DF8 - &funcs_400E29;
init_proc();
if ( v3 )
{
for ( i = 0LL; i != v3; ++i )
(*(&funcs_400E29 + i))();
}
}
// 601DF0: using guessed type __int64 (__fastcall *funcs_400E29)();
// 601DF8: using guessed type __int64 (__fastcall *off_601DF8)();
//----- (0000000000400E54) ----------------------------------------------------
void term_proc()
{
;
}
// nfuncs=33 queued=10 decompiled=10 lumina nreq=0 worse=0 better=0
// ALL OK, 10 function(s) have been successfully decompiled
Análisis estático
Anti-debug
Si la función ptrace retorna -1, significa que el programa está siendo depurado y redirige a LABEL_2.
if (ptrace(PTRACE_TRACEME, 0LL, 0LL, 0LL) == -1) {
goto LABEL_2;
}
Cálculos y validaciones
El programa espera al menos 5 argumentos (nombre del programa y cuatro números enteros). Si se proporcionan los cuatro números enteros, se realizan los siguientes cálculos:
if (-24 * qword_602148 - 18 * qword_602150 - 15 * qword_602158 - 12 * qword_602160 == -18393
&& 9 * qword_602158 + 18 * (qword_602150 + qword_602148) - 9 * qword_602160 == 4419
&& 4 * qword_602158 + 16 * qword_602148 + 12 * qword_602150 + 2 * qword_602160 == 7300
&& -6 * (qword_602150 + qword_602148) - 3 * qword_602158 - 11 * qword_602160 == -8613)
Esto es un sistema de ecuaciones lineales mondo y lirondo que debe ser resuelto para encontrar los valores correctos de qword_602148, qword_602150, qword_602158 y qword_602160. Una vez resuelto el sistema de ecuaciones se realiza la operación:
qword_602178 = qword_602158 + qword_602150 * qword_602148 - qword_602160;
A continuación se pasa el resultado de la variable qword_602178 a hexadecimal y se genera su hash MD5.
Solución en Python
Lo más rápido en esta ocasión es usar Python, pero esto se puede resolver hasta con lápiz y papel 😉
from sympy import symbols, Eq, solve
import hashlib
# Definir las variables
A, B, C, D = symbols('A B C D')
# Definir las ecuaciones
eq1 = Eq(-24*A - 18*B - 15*C - 12*D, -18393)
eq2 = Eq(9*C + 18*(A + B) - 9*D, 4419)
eq3 = Eq(4*C + 16*A + 12*B + 2*D, 7300)
eq4 = Eq(-6*(A + B) - 3*C - 11*D, -8613)
# Resolver el sistema de ecuaciones
solution = solve((eq1, eq2, eq3, eq4), (A, B, C, D))
# Verificar si se encontró una solución
if solution:
print("Solución encontrada:")
print(solution)
# Obtener los valores de A, B, C y D
A_val = solution[A]
B_val = solution[B]
C_val = solution[C]
D_val = solution[D]
# Mostrar los valores encontrados
print(f"A = {A_val}")
print(f"B = {B_val}")
print(f"C = {C_val}")
print(f"D = {D_val}")
# Calcular qword_602178
qword_602178 = C_val + B_val * A_val - D_val
qword_602178 = int(qword_602178) # Convertir a entero de Python
print(f"qword_602178 = {qword_602178}")
# Convertir qword_602178 a una cadena en formato hexadecimal
byte_602141 = f"{qword_602178:06x}"
print(f"byte_602141 (hex) = {byte_602141}")
# Calcular el MD5 de la cadena
md5_hash = hashlib.md5(byte_602141.encode()).hexdigest()
print(f"MD5 hash = {md5_hash}")
# Generar la flag
flag = f"FLAG-{md5_hash}"
print(f"Flag = {flag}")
else:
print("No se encontró una solución.")
Al ejecutar el script veremos algo como esto:
Solución encontrada:
{A: 227, B: 115, C: 317, D: 510}
A = 227
B = 115
C = 317
D = 510
qword_602178 = 25912
byte_602141 (hex) = 006538
MD5 hash = 21a84f2c7c7fd432edf1686215db....
Flag = FLAG-21a84f2c7c7fd432edf1686215db....
ThisIsLegal.com – User Challenge 1 (Javascript)

Warning: This challenge is still active and therefore should not be resolved using this information.
Aviso: Este reto sigue en activo y por lo tanto no se debería resolver utilizando esta información.
Introducción
Este es el típico reto de Javascript, no tiene mucha complicación pero he decidido dedicarle una entrada por que me llamó la atención lo que utiliza de usuario y clave.
El Script
function getStyle(el,styleProp)
{
var x = document.getElementById(el);
if (x.currentStyle)
var y = x.currentStyle[styleProp];
else if (window.getComputedStyle)
var y = document.defaultView.getComputedStyle(x,null).getPropertyValue(styleProp);
if (y.substr(0, 1) == "#"){ return y; } else {
var value = y.split(',');
var R = value[0].substr(4);
var G = value[1];
var B = value[2].substr(0, value[2].length-1);
var RGB = "#" + toHex(R)+ toHex(G)+toHex(B);
return RGB;
}
}
function toHex(N) {
if (N==null) return "00";
N=parseInt(N); if (N==0 || isNaN(N)) return "00";
N=Math.max(0,N); N=Math.min(N,255); N=Math.round(N);
return "0123456789ABCDEF".charAt((N-N%16)/16)
+ "0123456789ABCDEF".charAt(N%16);
}
function pw (form)
{
var d1, d2, d3;
if (navigator.appName == "Netscape"){
d1= getStyle('content', 'background-color');
} else {
d1= getStyle('content', 'backgroundColor');
}
d2=form.Name.value;
d3=form.Password.value;
if (d2==d1.length) {
if (d3==d1) {
window.open ("../" + d1.substr(1, 10), "_self")
} else {
alert("Muhaha! Wrong!")
}
} else {
alert("Muhaha! Wrong!")
}
}
El Formulario
<div class="chal_box" style="padding:10px;">
<form name="form" action="" method="post">
Username<br />
<input id="inputd2" type="text" name="Name" value="" size="30" maxlength="30"><br />
Password<br />
<input id="inputd1" type="text" name="Password" value="" size="30" maxlength="30"><br /><br />
<input type="button" name="Only a button" value="Enter Site" id="Only a button" class="btn" onclick="pw(this.form)">
</form>
</div>
Interpretando el Script
En el formulario vemos que llama a la función «pw» y ésta a su vez llama a la función «getStyle«, bueno, pués es tan simple como poner un «alert();» dentro de la función «pw» para cazar la clave. Con éste método podemos cazar la clave del 90% de este tipo de pruebas.
Con esto ya tenemos la clave. El usuario responde a la siguiente sentencia «d2==d1.length«, es decir, es el número de dígitos de la clave.
¿Fácil no?
Links
Solución al Time Trial de Detten

Intro
Hoy tenemos aquí otro crackme sacado del baúl de los recuerdos. En este caso se trata de una protección por tiempo límite a través de un keyfile llamado «data.det«. Disponemos de tres días o nueve sesiones antes de que el crackme expire.
El algoritmo
La primera vez que ejecutamos el crackme, crea el fichero «data.det» y realiza lo siguiente:
- Lee el fichero data.det que inicialmente tiene 10 bytes a cero y el último byte un 60(`).
- Comprueba que tenga 11 bytes (B) y continúa.
- Al detectar el fichero vacío le mete valores codificandolos con XOR 6969. Los almacena en memoria 4030AB y siguientes.
00401000 t>/$ 6A 00 PUSH 0 ; /pModule = NULL 00401002 |. E8 0B020000 CALL <JMP.&KERNEL32.GetModuleHandleA> ; \GetModuleHandleA 00401007 |. A3 F4304000 MOV DWORD PTR DS:[4030F4],EAX ; kernel32.BaseThreadInitThunk 0040100C |. 6A 00 PUSH 0 ; /hTemplateFile = NULL 0040100E |. 68 80000000 PUSH 80 ; |Attributes = NORMAL 00401013 |. 6A 03 PUSH 3 ; |Mode = OPEN_EXISTING 00401015 |. 6A 00 PUSH 0 ; |pSecurity = NULL 00401017 |. 6A 00 PUSH 0 ; |ShareMode = 0 00401019 |. 68 000000C0 PUSH C0000000 ; |Access = GENERIC_READ|GENERIC_WRITE 0040101E |. 68 A2304000 PUSH timetria.004030A2 ; |FileName = "DATA.DET" 00401023 |. E8 DE010000 CALL <JMP.&KERNEL32.CreateFileA> ; \CreateFileA 00401028 |. 83F8 FF CMP EAX,-1 0040102B |. 74 07 JE SHORT timetria.00401034 0040102D |. A3 14314000 MOV DWORD PTR DS:[403114],EAX ; kernel32.BaseThreadInitThunk 00401032 |. EB 18 JMP SHORT timetria.0040104C 00401034 |> 6A 30 PUSH 30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL 00401036 |. 68 38304000 PUSH timetria.00403038 ; |Title = "I don't like this !" 0040103B |. 68 02304000 PUSH timetria.00403002 ; |Text = "Where is my DATA.DET file?\r\nI can't run without it..." 00401040 |. 6A 00 PUSH 0 ; |hOwner = NULL 00401042 |. E8 B3010000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA 00401047 |. E9 22010000 JMP timetria.0040116E 0040104C |> 6A 00 PUSH 0 ; /pOverlapped = NULL 0040104E |. 68 E0304000 PUSH timetria.004030E0 ; |pBytesRead = timetria.004030E0 00401053 |. 6A 32 PUSH 32 ; |BytesToRead = 32 (50.) 00401055 |. 68 AB304000 PUSH timetria.004030AB ; |Buffer = timetria.004030AB 0040105A |. FF35 14314000 PUSH DWORD PTR DS:[403114] ; |hFile = NULL 00401060 |. E8 B9010000 CALL <JMP.&KERNEL32.ReadFile> ; \ReadFile 00401065 |. 833D E0304000 0B CMP DWORD PTR DS:[4030E0],0B 0040106C |. 0F85 E9000000 JNZ timetria.0040115B 00401072 |. BB AB304000 MOV EBX,timetria.004030AB 00401077 |. 68 E4304000 PUSH timetria.004030E4 ; /pSystemTime = timetria.004030E4 0040107C |. E8 97010000 CALL <JMP.&KERNEL32.GetSystemTime> ; \GetSystemTime 00401081 |. 803B 00 CMP BYTE PTR DS:[EBX],0 00401084 |. 75 22 JNZ SHORT timetria.004010A8 ; Si existe el fichero salta a las comprobaciones 00401086 |. 51 PUSH ECX 00401087 |. 33C9 XOR ECX,ECX 00401089 |. EB 15 JMP SHORT timetria.004010A0 0040108B |> 66:8B81 E4304000 /MOV AX,WORD PTR DS:[ECX+4030E4] ; | 00401092 |. 66:35 6969 |XOR AX,6969 ; | 00401096 |. 66:8981 AB304000 |MOV WORD PTR DS:[ECX+4030AB],AX ; | 0040109D |. 83C1 02 |ADD ECX,2 ; | Bucle de codificacion de data.det por primera vez 004010A0 |> 83F9 08 CMP ECX,8 ; | 004010A3 |.^ 76 E6 \JBE SHORT timetria.0040108B ; | 004010A5 |. 59 POP ECX ; kernel32.7580EE1C 004010A6 |. EB 3A JMP SHORT timetria.004010E2
Vigilando el proceso de creación del archivo podemos llegar a la conclusión de como se genera.
- Los dos primeros bytes son el año = 2014 = 0x7DE. 7DE XOR 6969 = 6EB7.
- Los dos siguientes son el mes = 10 = 0xA. A XOR 6969 = 6963.
- Los dos siguientes usa un 4 (día de la semana???) = 0x4. 4 XOR 6969 = 696D.
- Los dos siguientes son el día del mes = 2 = 0x2. 2 XOR 6969 = 696B
- Los dos siguientes usa un 1 = 0x1. 1 XOR 6969 = 6968.
- El número de sesiones lo deja como está, 60.
Estado de la memoria:
004030AB B7 6E 63 69 6D 69 6B 69 68 69 60 ·ncimikihi`
- Finalmente le resta 1 al número de sesiones y guarda el fichero.
004010E2 |> \A0 B5304000 MOV AL,BYTE PTR DS:[4030B5] 004010E7 |. 34 69 XOR AL,69 004010E9 |. 3C 00 CMP AL,0 004010EB |. /74 59 JE SHORT timetria.00401146 004010ED |. |FEC8 DEC AL 004010EF |. |A2 01304000 MOV BYTE PTR DS:[403001],AL 004010F4 |. |34 69 XOR AL,69 004010F6 |. |A2 B5304000 MOV BYTE PTR DS:[4030B5],AL 004010FB |. |6A 00 PUSH 0 ; /Origin = FILE_BEGIN 004010FD |. |6A 00 PUSH 0 ; |pOffsetHi = NULL 004010FF |. |6A 00 PUSH 0 ; |OffsetLo = 0 00401101 |. |FF35 14314000 PUSH DWORD PTR DS:[403114] ; |hFile = 00000034 (window) 00401107 |. |E8 18010000 CALL <JMP.&KERNEL32.SetFilePointer> ; \SetFilePointer 0040110C |. |6A 00 PUSH 0 ; /pOverlapped = NULL 0040110E |. |68 E0304000 PUSH timetria.004030E0 ; |pBytesWritten = timetria.004030E0 00401113 |. |6A 0B PUSH 0B ; |nBytesToWrite = B (11.) 00401115 |. |68 AB304000 PUSH timetria.004030AB ; |Buffer = timetria.004030AB 0040111A |. |FF35 14314000 PUSH DWORD PTR DS:[403114] ; |hFile = 00000034 (window) 00401120 |. |E8 05010000 CALL <JMP.&KERNEL32.WriteFile> ; \WriteFile
En cada ejecución realiza tres comprobaciones.
Recordemos el contenido del fichero:
B7 6E 63 69 6D 69 6B 69 68 69 60 ·ncimikihi`
1) Mes y año (4 primeros bytes)
004010A8 |> \8B0D AB304000 MOV ECX,DWORD PTR DS:[4030AB] ; ECX=69636EB7 004010AE |. 81F1 69696969 XOR ECX,69696969 ; 69636EB7 xor 69696969 = A07DE (A = mes y 7DE = año) 004010B4 |. A1 E4304000 MOV EAX,DWORD PTR DS:[4030E4] 004010B9 |. 3BC1 CMP EAX,ECX ; Compara con mes y año actuales 004010BB |. 0F85 85000000 JNZ timetria.00401146 ; Bad boy
2) Día (7º y 8º byte)
004010C1 |. 66:8B0D B1304000 MOV CX,WORD PTR DS:[4030B1] ; CX = 696B 004010C8 |. 66:81F1 6969 XOR CX,6969 ; 696B xor 6969 = 2 004010CD |. 66:A1 EA304000 MOV AX,WORD PTR DS:[4030EA] ; AX = día actual obtenido con GetSystemTime 004010D3 |. 66:2BC1 SUB AX,CX ; Los resta 004010D6 |. 66:83F8 03 CMP AX,3 ; Compara con 3 004010DA |. 77 6A JA SHORT timetria.00401146 ; Si el resultado >=3 Bad Boy
3) Sesiones (11º byte)
004010DC |. 2805 00304000 SUB BYTE PTR DS:[403000],AL ; 004010E2 |> A0 B5304000 MOV AL,BYTE PTR DS:[4030B5] ; AL = numero de sesiones actual 004010E7 |. 34 69 XOR AL,69 ; 61 Xor 69 = 8 004010E9 |. 3C 00 CMP AL,0 ; Compara con 0 004010EB |. 74 59 JE SHORT timetria.00401146 ; Salta si hemos superado las 9 sesiones. Bad boy 004010ED |. FEC8 DEC AL ; Si no le resta 1 004010EF |. A2 01304000 MOV BYTE PTR DS:[403001],AL 004010F4 |. 34 69 XOR AL,69 ; y le hace xor 69 para codificar el nuevo valor de sesión 004010F6 |. A2 B5304000 MOV BYTE PTR DS:[4030B5],AL
Con esto ya podemos alterar el archivo a nuestro antojo sin necesidad de parchear.
Keygen
Try
ano = ano Xor 26985
mes = mes Xor 26985
dia = dia Xor 26985
anos = Hex(ano).ToString
mess = Hex(mes).ToString
dias = Hex(dia).ToString
If txtsesiones.Text <= 255 Then
sesioness = Hex(sesiones)
Else
sesiones = 255
End If
sesioness = Hex(sesiones)
'key = 00 00 00 00 00 00 00 00 00 00 00
'key = año+año+mes+mes+X+X+dia+dia+X+sesiones
key = Chr(Convert.ToInt32(anos.Substring(2, 2), 16)) & Chr(Convert.ToInt32(anos.Substring(0, 2), 16)) _
& Chr(Convert.ToInt32(mess.Substring(2, 2), 16)) & Chr(Convert.ToInt32(mess.Substring(0, 2), 16)) _
& Chr(106) & Chr(105) _
& Chr(Convert.ToInt32(dias.Substring(2, 2), 16)) & Chr(Convert.ToInt32(dias.Substring(0, 2), 16)) _
& Chr(103) & Chr(105) _
& Chr(Convert.ToInt32(sesioness.Substring(0, 2), 16))
'Creo el archivo llave
Dim ruta As String = Application.StartupPath & "\DATA.DET"
If File.Exists(ruta) Then
File.Delete(ruta)
End If
Using sw As StreamWriter = New StreamWriter(ruta, True, System.Text.Encoding.Default)
sw.Write(key)
sw.Close()
End Using
MsgBox("DATA.DET generado correctamente", MsgBoxStyle.Information + MsgBoxStyle.OkOnly, "Info")
Catch ex As Exception
MsgBox("Ocurrió algún error" & vbCrLf & ex.Message)
End Try
Links
ThisIsLegal.com – Realistic Challenge 2

Warning: This challenge is still active and therefore should not be resolved using this information.
Aviso: Este reto sigue en activo y por lo tanto no se debería resolver utilizando esta información.
Introducción
Break into the site, find the file and remove it. Also leave no evidence that you was ever there so they wont realise until its too late!
Analizando la seguridad de la víctima
Pass: ‘ or 1=1–‘;
Solo nos queda borrar la lista de objetivos y nuestras huellas. Para ello borramos los siguientes archivos y reto superado.
Lista de objetivos: root/misc/targets
Logs: root/images/logs
Links
VideoTutorial – RegisterMe de Shadow – Parcheando un NET

JS Deobfuscator

Se nos entrega un html con un juego que consiste en hacer clic en un botón tantas veces como podamos para ganar al juego. Acompañando al html tenemos un código javascript ofuscado aparentemente con Obfuscator.io
El código javascript ofuscado tiene el siguiente aspecto.
(function(_0x144932, _0xfc69c5) { var _0x187428 = _0x588c,
_0x3064c6 = _0x144932(); while (!![]) { try { var _0xb96d19 = -parseInt(_0x187428(0x1bd)) / 0x1 + parseInt(_0x187428(0x137)) / 0x2 + -parseInt(_0x187428(0x140)) / 0x3 * (-parseInt(_0x187428(0x13b)) / 0x4) + parseInt(_0x187428(0x15e)) / 0x5 * (parseInt(_0x187428(0x18c)) / 0x6) + -parseInt(_0x187428(0x159)) / 0x7 * (parseInt(_0x187428(0x1c3)) / 0x8) + parseInt(_0x187428(0x129)) / 0x9 * (-parseInt(_0x187428(0x149)) / 0xa) + parseInt(_0x187428(0x16d)) / 0xb; if (_0xb96d19 === _0xfc69c5) break;
else _0x3064c6['push'](_0x3064c6['shift']()); } catch (_0x377a04) { _0x3064c6['push'](_0x3064c6['shift']()); } } }(_0x5be3, 0x6fe59));;
function _0x5be3() { var _0x5a2048 = ['Utf8', 'push', 'createDecryptor', 'Malformed\x20UTF-8\x20data', '_ENC_XFORM_MODE', 'string', '_prevBlock', 'extend', '_doReset', 'AnsiX923', 'error', 'fromCharCode', 'object', '130340XnpiqM', '#res', 'HmacSHA256', 'DES', '4FuuDzS', 'finalize', 'byteLength', 'salt', '_keyPriorReset', '372669TnxSTf', '_xformMode', 'HMAC', 'stringify', 'Latin1', 'cfg', 'start', 'padding', 'show', '47650FNyFfQ', 'parse', 'TripleDES', 'MD5', 'ZeroPadding', 'length', 'Rabbit', 'console', 'Base', 'HmacSHA3', 'kdf', '_doFinalize', 'drop', 'BufferedBlockAlgorithm', 'Cipher', 'HmacSHA1', '7PKTjbP', 'CTR', '_reverseMap', 'clone', 'Encryptor', '43750GcrrDy', 'SHA384', 'byteOffset', 'indexOf', 'Word', '#loader', 'algo', 'apply', 'bind', 'HmacMD5', 'Base64', '_key', 'createEncryptor', 'min', '_counter', '4232173VijiOj', '_lBlock', 'You\x20Lose', 'ECB', 'BlockCipherMode', 'ciphertext', 'floor', 'constructor', 'log', 'search', 'flush', 'Iso10126', 'update', 'NoPadding', 'max', 'HmacSHA384', 'SHA512', 'decrypt', '_des2', '(((.+)+)+)+$', 'high', 'U2FsdGVkX189ylLOlgNSxq/TLeSxBr7cYDcRBgMXXS9VmwusKZx1XFDNdpkwg24v98iYGnUATwQVyWwFnlyoCg==', 'charAt', 'return\x20(function()\x20', 'pow', 'prototype', 'compute', 'reset', 'warn', '_rBlock', 'HmacSHA512', '498WcTnbi', 'join', 'HmacSHA224', 'display', '#trim', 'StreamCipher', 'enc', 'click', '#statistic', 'random', 'keySize', 'SHA1', '_process', 'sigBytes', '$super', '#mybut', 'clamp', 'RC4', '_invSubKeys', 'loader', '_cipher', '#backstart', 'BlockCipher', 'formatter', 'WordArray', 'slice', 'decryptBlock', '_minBufferSize', 'execute', '_iv', '_hash', 'mixIn', '__proto__', 'text', 'concat', 'RabbitLegacy', 'ceil', 'splice', 'Utf16LE', 'array[0]', 'function', 'SHA3', 'charCodeAt', 'EvpKDF', 'toString', 'css', '_state', 'Decryptor', 'Hex', '82275HVLogQ', 'ivSize', 'encrypt', '_des1', '_mode', 'words', '5353976ERfqhe', 'init', '_hasher', '_createHmacHelper', '_oKey', 'lib', 'CipherParams', 'x64', '_keySchedule', 'RC4Drop', 'PBKDF2', '__creator', '_subKeys', '_nDataBytes', '_DEC_XFORM_MODE', 'format', 'substr', '_createHelper', '_data', '_parse', '#cssfilter', '_map', 'create', 'OpenSSL', 'hasher', 'table', 'key', 'hide', 'iterations', '#timecount', 'undefined', 'pad', '_iKey', 'CBC', 'OFB', '#apply', 'SHA224', '_keystream', 'mode', 'exception', 'call', 'hasOwnProperty', 'Utf16', 'encryptBlock', '_invKeySchedule', '#buttons', '_doCryptBlock', 'RIPEMD160', 'blockSize', 'low', '_des3', '{}.constructor(\x22return\x20this\x22)(\x20)', '_nRounds', 'Hasher', 'addClass', 'AES', 'CFB', 'sqrt', '171bibExj'];
_0x5be3 = function() { return _0x5a2048; }; return _0x5be3(); }
...
Deofuscado el código con la web Obfuscator.io llegamos a interpretar la estructura aunque sigue siendo un galimatías en gran parte. Aún así, si nos fijamos al final encontramos una parte interesante con una clave encriptada cuya desencriptación depende de una comparación (línea 13 resaltada). Invirtiendo esa comparación engañamos al código y obtenemos la flag.
$("#mybut").click(function () {
_0x4171cc++;
$("#cssfilter").text(_0x4171cc);
});
$("#statistic").addClass("hide");
_0x35a8b9 = setInterval(function () {
_0x97292c--;
$("#timecount").text(_0x97292c);
if (_0x97292c == 0x0) {
clearInterval(_0x35a8b9);
$("#mybut").hide();
$("#buttons").show(0x64);
if (_0x4171cc > _0x43eef3) {
$('#trim').text(CryptoJS.AES.decrypt("U2FsdGVkX189ylLOlgNSxq/TLeSxBr7cYDcRBgMXXS9VmwusKZx1XFDNdpkwg24v98iYGnUATwQVyWwFnlyoCg==", "array[0]").toString(CryptoJS.enc.Utf8));
} else {
$("#trim").text("You Lose");
}
}
}, 0x3e8);
intervalcomp = setInterval(function () {
_0x43eef3++;
$('#apply').text(_0x43eef3);
if (_0x97292c == 0x0) {
clearInterval(intervalcomp);
}
}, 0x32);
}
});
Keygen para el Crackme 1 de VisionZ

Intro
Aquí tenemos un crackme clásico realizado en Visual C++. La única particularidad que tiene es que no muestra MessageBox al introducir bien o mal el serial, simplemente cambia una imagen de un emoticono. Si observamos el comportamiento del crackme notaremos que inicialmente el emoticono está neutral y al fallar se pone triste y por lo tanto es de suponer que al acertar se pondrá contento.
El BreakPoint

Al mirar en las Intermodular Calls de OllyDbg vemos que LoadIconA es un buen candidato para ubicar la comprobación del serial. Si nos fijamos hay tres llamadas, ponemos un breakpoint en las tres y enseguida llegamos a la zona de comprobación del serial.
La comprobación
00401180 . 6A FF PUSH -1 00401182 . 68 68194000 PUSH CrackMe_.00401968 00401187 . 64:A1 00000000 MOV EAX,DWORD PTR FS:[0] 0040118D . 50 PUSH EAX 0040118E . 64:8925 000000>MOV DWORD PTR FS:[0],ESP 00401195 . 83EC 0C SUB ESP,0C 00401198 . 53 PUSH EBX 00401199 . 55 PUSH EBP 0040119A . 8BE9 MOV EBP,ECX 0040119C . 56 PUSH ESI 0040119D . 57 PUSH EDI 0040119E . 8D4C24 10 LEA ECX,DWORD PTR SS:[ESP+10] 004011A2 . E8 2F050000 CALL <JMP.&MFC42.#540> 004011A7 . 8D4C24 14 LEA ECX,DWORD PTR SS:[ESP+14] 004011AB . C74424 24 0000>MOV DWORD PTR SS:[ESP+24],0 004011B3 . E8 1E050000 CALL <JMP.&MFC42.#540> 004011B8 . 8D4424 10 LEA EAX,DWORD PTR SS:[ESP+10] 004011BC . 8BCD MOV ECX,EBP 004011BE . 50 PUSH EAX 004011BF . 68 E9030000 PUSH 3E9 004011C4 . C64424 2C 01 MOV BYTE PTR SS:[ESP+2C],1 004011C9 . E8 02050000 CALL <JMP.&MFC42.#3097> ; Lee el tamano del nombre 004011CE . 8D4C24 14 LEA ECX,DWORD PTR SS:[ESP+14] 004011D2 . 51 PUSH ECX 004011D3 . 68 EA030000 PUSH 3EA 004011D8 . 8BCD MOV ECX,EBP 004011DA . E8 F1040000 CALL <JMP.&MFC42.#3097> ; Lee el tamano del serial 004011DF . 51 PUSH ECX 004011E0 . 8D5424 14 LEA EDX,DWORD PTR SS:[ESP+14] 004011E4 . 8BCC MOV ECX,ESP 004011E6 . 896424 1C MOV DWORD PTR SS:[ESP+1C],ESP 004011EA . 52 PUSH EDX 004011EB . E8 DA040000 CALL <JMP.&MFC42.#535> 004011F0 . 8D4424 1C LEA EAX,DWORD PTR SS:[ESP+1C] 004011F4 . 8BCD MOV ECX,EBP 004011F6 . 50 PUSH EAX 004011F7 . E8 D4010000 CALL CrackMe_.004013D0 004011FC . 50 PUSH EAX 004011FD . 8D4C24 14 LEA ECX,DWORD PTR SS:[ESP+14] 00401201 . C64424 28 02 MOV BYTE PTR SS:[ESP+28],2 00401206 . E8 B9040000 CALL <JMP.&MFC42.#858> 0040120B . 8D4C24 18 LEA ECX,DWORD PTR SS:[ESP+18] 0040120F . C64424 24 01 MOV BYTE PTR SS:[ESP+24],1 00401214 . E8 A5040000 CALL <JMP.&MFC42.#800> 00401219 . 8B4C24 10 MOV ECX,DWORD PTR SS:[ESP+10] 0040121D . 8B5424 14 MOV EDX,DWORD PTR SS:[ESP+14] 00401221 . 8B41 F8 MOV EAX,DWORD PTR DS:[ECX-8] 00401224 . 8B4A F8 MOV ECX,DWORD PTR DS:[EDX-8] 00401227 . 3BC1 CMP EAX,ECX ; CMP len nombre y len serial 00401229 . 0F85 2C010000 JNZ CrackMe_.0040135B 0040122F . 83F8 03 CMP EAX,3 ; len nombre >=3 00401232 . 0F8C 23010000 JL CrackMe_.0040135B 00401238 . 50 PUSH EAX 00401239 . E8 7A040000 CALL <JMP.&MFC42.#823> 0040123E . 8BF0 MOV ESI,EAX 00401240 . 8B4424 14 MOV EAX,DWORD PTR SS:[ESP+14] 00401244 . 83C4 04 ADD ESP,4 00401247 . 33C9 XOR ECX,ECX 00401249 . 8B50 F8 MOV EDX,DWORD PTR DS:[EAX-8] 0040124C . 4A DEC EDX 0040124D . 85D2 TEST EDX,EDX 0040124F . 7E 37 JLE SHORT CrackMe_.00401288 ....... 1ºBUCLE ....... 00401251 > 8A1401 MOV DL,BYTE PTR DS:[ECX+EAX] 00401254 . 8A5C01 01 MOV BL,BYTE PTR DS:[ECX+EAX+1] 00401258 . 8B4424 14 MOV EAX,DWORD PTR SS:[ESP+14] 0040125C . 0FBED2 MOVSX EDX,DL 0040125F . 0FBE0401 MOVSX EAX,BYTE PTR DS:[ECX+EAX] 00401263 . 8D4410 FE LEA EAX,DWORD PTR DS:[EAX+EDX-2] 00401267 . 99 CDQ 00401268 . 2BC2 SUB EAX,EDX 0040126A . 0FBED3 MOVSX EDX,BL 0040126D . D1F8 SAR EAX,1 0040126F . 40 INC EAX 00401270 . 83EA 02 SUB EDX,2 00401273 . 3BC2 CMP EAX,EDX 00401275 . 0F94C0 SETE AL 00401278 . 880431 MOV BYTE PTR DS:[ECX+ESI],AL 0040127B . 8B4424 10 MOV EAX,DWORD PTR SS:[ESP+10] 0040127F . 41 INC ECX 00401280 . 8B50 F8 MOV EDX,DWORD PTR DS:[EAX-8] 00401283 . 4A DEC EDX 00401284 . 3BCA CMP ECX,EDX 00401286 .^7C C9 JL SHORT CrackMe_.00401251 ........ Última comprobación ........ 00401288 > 0FBE1401 MOVSX EDX,BYTE PTR DS:[ECX+EAX] 0040128C . 0FBE78 01 MOVSX EDI,BYTE PTR DS:[EAX+1] 00401290 . 8B4424 14 MOV EAX,DWORD PTR SS:[ESP+14] 00401294 . 83C7 FE ADD EDI,-2 00401297 . 0FBE0401 MOVSX EAX,BYTE PTR DS:[ECX+EAX] 0040129B . 8D4410 FE LEA EAX,DWORD PTR DS:[EAX+EDX-2] 0040129F . 99 CDQ 004012A0 . 2BC2 SUB EAX,EDX 004012A2 . D1F8 SAR EAX,1 004012A4 . 40 INC EAX 004012A5 . 3BC7 CMP EAX,EDI 004012A7 . 0F94C2 SETE DL 004012AA . 881431 MOV BYTE PTR DS:[ECX+ESI],DL
La comprobación es muy sencilla, en resumen hace esto con todas las letras del nombre excepto la última:
1º Caracter
(1ºname + 1ºserial - 2 = X)
(X / 2)
(X + 1)
(2ºname - 2 = Y)
¿Y = X?
2º Caracter
(2ºname + 2ºserial - 2 = X)
(X / 2)
(X + 1)
(3ºname - 2 = Y)
¿Y = X?
...
Con el último caracter del nombre hace lo siguiente:
(6ºname + 6ºserial - 2 = X)
(X / 2)
(X + 1)
(2ºname - 2 = Y)
¿Y = X?
---------
Para revertir la primera parte de la comprobación para el nombre deurus quedaría:
X1 = (((2ºname-2-1)*2)+2)-1ºname
X2 = (((3ºname-2-1)*2)+2)-2ºname
X3 = (((4ºname-2-1)*2)+2)-3ºname
X4 = (((5ºname-2-1)*2)+2)-4ºname
X5 = (((6ºname-2-1)*2)+2)-5ºname
X6 = (((2ºname-2-1)*2)+2)-6ºname
Keygen
var nombre = "deurus";
nombre = nombre.toUpperCase();
var serial = "";
var tmp = "";
var i;
for (i = 0; i < nombre.length-1 ; i++) {
tmp = ((nombre.charCodeAt(i+1)-2-1)*2+2)-nombre.charCodeAt(i);
serial += String.fromCharCode(tmp);
}
tmp = ((nombre.charCodeAt(1)-2-1)*2+2)-nombre.charCodeAt(nombre.length-1);
serial += String.fromCharCode(tmp);
document.write(serial);
Enlaces
Y eso es todo, ¡a disfrutar!






























