CanYouHack.it Crack6 Challenge – Lights Out (English)

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.

Intro

This crackme is for the crack challenge 6 of canyouhack.it.

In this crackme the goal is to turn on all the lights. Note that a light off to the next, so if we interrupt this, we win.

Tools

Exeinfo (For crackme info)

Delphi Decompiler (For decompile)

 OllyDbg (For debug)

Decompiling

With Delphi Decompiler we can found easy the buttons and his offsets.
Go to the offset 401A64 in OllyDbg and analyze the code.
We view two jumps, one turn ON the light and the other Turn OFF the next light. Patching the call from offset 401A8B we get the serial.

Links


Intro Os comparto un reto stego que me gustó cuando lo hice hace unos años. En realidad se tarda pocos
Introducción Aquí tenemos un crackme hecho en Java, lo que como comprobareis a continuación no es muy buena idea ya
Estamos ante un ELF un poco más interesante que los vistos anteriormente. Básicamente porque es divertido y fácil encontrar la
AVISO: Debido a que este reto está en activo no publicaré a donde pertenece. El reto en cuestión nos presenta

Stego XVI – Bytes

Intro

Os comparto un reto stego que me gustó cuando lo hice hace unos años. En realidad se tarda pocos minutos en resolverlo pero depende de tus recursos es posible que se te atragante.

Procesando a la víctima

Cuando te has enfrentado a unos cuantos retos stego lo normal es que tengas un arsenal de herramientas por las que vas a pasar a la víctima. En mi caso cuando se trata de imágenes, mi fondo de armario está formado por steganabara y stegsolve. Si con esas dos herramientas no lo veo claro ya empiezo a mirar en sus entrañas y en este caso es justo lo que hace falta, mirar en su interior.

La víctima

imagen original del reto

Estamos ante una imagen GIF de 6,36KB (6513 bytes) cuya resolución es 236×42. Debido a la extensión tenderemos a analizar los frames por si se trata de una animación. Una vez desestimada la animación entran en juego steganabara, stegsolve y demás familia. Si todo lo anterior falla abro el archivo con un editor hexadecimal y lo reviso manualmente por si hay algo que me llama la atención.

Bytes

Explorando el interior del archivo enseguida encontramos algo que llama la atención, una sucesión de bytes con espacios intercalados.

Tras copiar los bytes lo primero es eliminar los espacios y empezar a jugar con ellos. Una de las cosas que podemos hacer es convertir los bytes a ascii y voilá, nos encontramos con lo que parece otro archivo GIF.

Copiamos los bytes con la ayuda de nuestro editor hexadecimal favorito, guardamos el archivo como GIF y reto superado.

Enlaces

Nota: si algo os pide clave es deurus.info

Dark_Prince’s crackme in Java Keygen

Introducción

Aquí tenemos un crackme hecho en Java, lo que como comprobareis a continuación no es muy buena idea ya que conseguir el código fuente e incluso modificarlo no es muy dificil.

Decompilado

Abrimos la víctima con nuestro decompilador favorito y nos fijamos en su contenido.

Lo interesante está en la clase Main > doneActionPerformed(ActionEvent), ya que contiene el código al ejecutar el botón que chequea el serial.
Llegados a este punto podríamos hacer cualquier cosa, parchear, que el serial válido nos lo mostrara una MessageBox etc. Pero vamos a hacer algo mejor, vamos a modificar la victima para crear nuestro keygen personalizado.

Creando un Keygen a partir de la víctima

Solamente tendremos que modificar un poco la apariencia y modificar la rutina de comprobación del serial para que lo muestre en la caja de texto del serial. Finalmente abrá que recompilar.
Aquí resalto el texto a modificar para el aspecto.
Así queda la modificación para mostrar el serial correcto en la caja de texto.
El aspecto del keygen finalmente es así.
Y como podeis apreciar funciona correctamente.

Links


Intro President’s cat was kidnapped by separatists. A suspect carrying a USB key has been arrested. Berthier, once again, up
Intro Os comparto un reto stego que me gustó cuando lo hice hace unos años. En realidad se tarda pocos
Intro Análisis Keygen Links Intro El crackme que analizamos hoy está hecho en ensamblador y si bien su dificultad es
El reto consiste en dos imágenes (v1.png y v2.png) que, a simple vista, parecen contener ruido aleatorio. Sin embargo, ambas

Stego XVI – Bytes

Intro

Os comparto un reto stego que me gustó cuando lo hice hace unos años. En realidad se tarda pocos minutos en resolverlo pero depende de tus recursos es posible que se te atragante.

Procesando a la víctima

Cuando te has enfrentado a unos cuantos retos stego lo normal es que tengas un arsenal de herramientas por las que vas a pasar a la víctima. En mi caso cuando se trata de imágenes, mi fondo de armario está formado por steganabara y stegsolve. Si con esas dos herramientas no lo veo claro ya empiezo a mirar en sus entrañas y en este caso es justo lo que hace falta, mirar en su interior.

La víctima

imagen original del reto

Estamos ante una imagen GIF de 6,36KB (6513 bytes) cuya resolución es 236×42. Debido a la extensión tenderemos a analizar los frames por si se trata de una animación. Una vez desestimada la animación entran en juego steganabara, stegsolve y demás familia. Si todo lo anterior falla abro el archivo con un editor hexadecimal y lo reviso manualmente por si hay algo que me llama la atención.

Bytes

Explorando el interior del archivo enseguida encontramos algo que llama la atención, una sucesión de bytes con espacios intercalados.

Tras copiar los bytes lo primero es eliminar los espacios y empezar a jugar con ellos. Una de las cosas que podemos hacer es convertir los bytes a ascii y voilá, nos encontramos con lo que parece otro archivo GIF.

Copiamos los bytes con la ayuda de nuestro editor hexadecimal favorito, guardamos el archivo como GIF y reto superado.

Enlaces

Nota: si algo os pide clave es deurus.info

Solución para el KeygenMe ASM de Flamer

Intro

El crackme que analizamos hoy está hecho en ensamblador y si bien su dificultad es baja, la creación del keygen es un poco liosa. Al keygen que veremos más adelante, le he dado cierta aleatoriedad para que quede más elegante.

El crackme comprueba el serial en función de un identificador de 4 dígitos que el mismo crackme genera.

Análisis

Coje nuestro serial mediante la función GetDlgItemTextA.

004010D3  |.  68 FF000000   PUSH 0FF                                 ; /MaxCount = 255.
004010D8  |.  68 40324000   PUSH OFFSET 00403240                     ; |String
004010DD  |.  68 EC030000   PUSH 3EC                                 ; |ItemID = 1004.
004010E2  |.  FF75 08       PUSH DWORD PTR SS:[ARG.1]                ; |hDialog => [ARG.1]
004010E5  |.  E8 6E010000   CALL <JMP.&user32.GetDlgItemTextA>       ; \USER32.GetDlgItemTextA
004010EA  |.  68 40324000   PUSH OFFSET 00403240                     ; /String
004010EF  |.  E8 52010000   CALL <JMP.&kernel32.lstrlenA>            ; \KERNEL32.lstrlen
004010F4  |.  A3 47334000   MOV DWORD PTR DS:[403347],EAX
004010F9  |.  33DB          XOR EBX,EBX
004010FB  |.  33C0          XOR EAX,EAX
004010FD  |.  EB 54         JMP SHORT 00401153

Comprueba que nuestro serial esté formado por números (30h – 39h), letras de la A a la F (41h – 46h) y el guión (2Dh), es decir, el alfabeto hexadecimal más el guión. Si hay algún dígito indeseado nos tira fuera.

004010FF  |>  8A83 40324000 /MOV AL,BYTE PTR DS:[EBX+403240]
00401105  |.  3C 2D         |CMP AL,2D
00401107  |.  74 40         |JE SHORT 00401149
00401109  |.  3C 30         |CMP AL,30
0040110B  |.  74 3C         |JE SHORT 00401149
0040110D  |.  3C 31         |CMP AL,31
0040110F  |.  74 38         |JE SHORT 00401149
00401111  |.  3C 32         |CMP AL,32
00401113  |.  74 34         |JE SHORT 00401149
00401115  |.  3C 33         |CMP AL,33
00401117  |.  74 30         |JE SHORT 00401149
00401119  |.  3C 34         |CMP AL,34
0040111B  |.  74 2C         |JE SHORT 00401149
0040111D  |.  3C 35         |CMP AL,35
0040111F  |.  74 28         |JE SHORT 00401149
00401121  |.  3C 36         |CMP AL,36
00401123  |.  74 24         |JE SHORT 00401149
00401125  |.  3C 37         |CMP AL,37
00401127  |.  74 20         |JE SHORT 00401149
00401129  |.  3C 38         |CMP AL,38
0040112B  |.  74 1C         |JE SHORT 00401149
0040112D  |.  3C 39         |CMP AL,39
0040112F  |.  74 18         |JE SHORT 00401149
00401131  |.  3C 41         |CMP AL,41
00401133  |.  74 14         |JE SHORT 00401149
00401135  |.  3C 42         |CMP AL,42
00401137  |.  74 10         |JE SHORT 00401149
00401139  |.  3C 43         |CMP AL,43
0040113B  |.  74 0C         |JE SHORT 00401149
0040113D  |.  3C 44         |CMP AL,44
0040113F  |.  74 08         |JE SHORT 00401149
00401141  |.  3C 45         |CMP AL,45
00401143  |.  74 04         |JE SHORT 00401149
00401145  |.  3C 46         |CMP AL,46
00401147  |.  75 07         |JNE SHORT 00401150
00401149  |>  8305 4B334000 |ADD DWORD PTR DS:[40334B],1
00401150  |>  83C3 01       |ADD EBX,1
00401153  |>  3B1D 47334000 |CMP EBX,DWORD PTR DS:[403347]
00401159  |.^ 76 A4         \JBE SHORT 004010FF
0040115B  |. A1 47334000 MOV EAX,DWORD PTR DS:[403347]
00401160  |. 3905 4B334000 CMP DWORD PTR DS:[40334B],EAX     ; si no coincide el tamaño del serial con el
00401166  |. 0F85 94000000 JNE 00401200                      ; contador nos tira fuera

La comprobación del serial la realiza sumando el valor ascii del primer dígito al valor ascii del tercero y sucesivos y a continuación restando la suma anterior al ID. Cuando finalice la comprobación de todos los dígitos del serial, el restador tiene que ser cero, de lo contrario nos tira fuera. Si el ID es cero también nos tira fuera.

Ejemplo (base 10)para ID = 4011 y SERIAL: 1-23456

  • Valores del serial: 1(49) -(no se usa) 2(50) 3(51) 4(52) 5(53) 6(54)
  • 1º + 3º: 49 + 50 = 99
  • 4011 – 99 = 3912
  • 1º + 4º: 49 + 51 = 100
  • 3912 – 100 = 3812
  • 1º + 5º: 49 + 52 = 101
  • 3812 – 101 = 3711
  • 1º + 6º: 49 + 53 = 102
  • 3711 – 102 = 3609
  • 1º + 7º: 49 + 54 = 103
  • 3609 – 103 = 3506
  • ¿3506 = 0?
0040116C  |.  33C0          XOR EAX,EAX
0040116E  |.  BB 02000000   MOV EBX,2
00401173  |.  A0 40324000   MOV AL,BYTE PTR DS:[403240]
00401178  |.  A3 43334000   MOV DWORD PTR DS:[403343],EAX
0040117D  |.  EB 13         JMP SHORT 00401192
0040117F  |>  8A83 40324000 /MOV AL,BYTE PTR DS:[EBX+403240]         ; Coje el dígito correspondiente
00401185  |.  0305 43334000 |ADD EAX,DWORD PTR DS:[403343]           ; 1ºdig + dig
0040118B  |.  2905 4F334000 |SUB DWORD PTR DS:[40334F],EAX           ; ID - (1ºdig + dig)
00401191  |.  43            |INC EBX
00401192  |>  3B1D 47334000 |CMP EBX,DWORD PTR DS:[403347]
00401198  |.^ 72 E5         \JB SHORT 0040117F
0040119A  |.  833D 4F334000 CMP DWORD PTR DS:[40334F],0              ; CHECK RESTADOR SEA = 0
004011A1  |.  75 49         JNE SHORT 004011EC
004011A3  |.  833D 3F334000 CMP DWORD PTR DS:[40333F],0              ; CHECK ID <> 0
004011AA  |.  74 40         JE SHORT 004011EC
004011AC  |.  FF35 3F334000 PUSH DWORD PTR DS:[40333F]               ; /<%d> = 0
004011B2  |.  68 00304000   PUSH OFFSET 00403000                     ; |Format = "REGISTRADO CON ID:%d"
004011B7  |.  68 40324000   PUSH OFFSET 00403240                     ; |Buf
004011BC  |.  E8 A9000000   CALL <JMP.&user32.wsprintfA>             ; \USER32.wsprintfA

Como veis, el resultado de ir restando todos los dígitos de nuestro serial con la ID debe ser cero para que el serial sea correcto.

Keygen

Lo primero que se me ocurre para obtener una solución directa es buscar una combinación de dígito + dígito que sea múltiplo del ID. Para ello podemos usar la función módulo. La función módulo lo que hace es darnos el resto de la división de dos números, de modo que si el resto es cero los números son múltiplos. Para ello debemos cruzar todos los números y letras hasta encontrar los dígitos múltiplos del ID. Un serial de este primer tipo quedaría algo así como 1-FFFFFFFFFFFFFFFFFF ya que como el primer dígito es fijo el otro se repetirá tanta veces como sea necesario para hacer que el ID sea cero.

Con nuestro reducido alfabeto, cabe la posibilidad de que no encontremos una combinación válida, por lo que tendremos que pensar en un plan B. El plan B que se me ocurre a mi es intentar forzar el plan A restando caracteres aleatorios al ID y volviendo a comprobar si encontramos múltiplos del nuevo ID. Un serial de este tipo quedaría más elegante, por ejemplo 3-A6D53B628BBBBB.

Os dejo unos cuantos números de serie.

  • Tipo A
    • ID: 1111 SERIAL: 0-55555555555
    • ID: 2500 SERIAL: 0-4444444444444444444444444
    • ID: 4982 SERIAL: 1-99999999999999999999999999999999999999999999999
    • ID: 4992 SERIAL: 0-0000000000000000000000000000000000000000000000000000
  • Tipo B
    • ID: 1112 SERIAL: 9-19247C5555
    • ID: 2499 SERIAL: A-C5ADC2233333333333333
    • ID: 4981 SERIAL: 7-C6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
    • ID: 4999 SERIAL: 4-A37BEEB8146A5CE6ECFB422B1BFF8474E852314F5A999
'Keygen for Flamer's asm keygenme
    Dim id As Integer
    Dim serial As String
    Dim tmp, tmp2, na, nb As Integer
    Dim alfabeto As Integer() = New Integer() {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70}
    Dim r As Random = New Random
    'Button generate
    Private Sub btngen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btngen.Click
ini:
        If txtid.TextLength <> 4 Then GoTo Mal
        id = txtid.Text
        txtdebug.Text = ""
        na = alfabeto(r.Next(1, 16))
        serial = Chr(na) & "-"
        tmp = id
        For i = 0 To alfabeto.Length - 1
            For y = 0 To alfabeto.Length - 1
                'Solución directa
                If id Mod (alfabeto(i) + alfabeto(y)) = 0 Then
                    tmp = id / (alfabeto(i) + alfabeto(y))
                    txtserial.Text = Chr(alfabeto(i)) & "-"
                    For z = 0 To tmp - 1
                        txtserial.Text &= Chr(alfabeto(y))
                    Next
                    GoTo fuera
                End If
                'Indirecta con aleatoriedad
                nb = alfabeto(r.Next(1, 16))
                tmp = tmp - (na + nb)
                serial &= Chr(nb)
                If tmp Mod (na + nb) = 0 Then
                    tmp2 = tmp / (na + nb)
                    For z = 0 To tmp2 - 1
                        serial &= Chr(nb)
                    Next
                    txtserial.Text = serial
                    GoTo fuera
                End If
                If tmp < 0 Then
                    GoTo ini
                Else
                    txtdebug.Text &= tmp & " "
                End If
            Next
        Next
Mal:
        txtserial.Text = "¿id?"
fuera:

    End Sub

Me doy cuenta que en el keygen no he utilizado el guión, pero no pasa nada, se lo dejo al lector como curiosidad.

Links


Hoy analizamos Copycat, un thriller psicológico de 1995 que, como muchas películas de la época, no pudo resistirse a incorporar
Primeras impresiones Analizamos el programa con PEiD y nos muestra que está hecho en ensamblador. Unas pruebas introduciendo datos nos
Computer Password Security Hacker En el primer vistazo con el editor hexadecimal ya vemos la solución al reto: Pho Al
http://youtu.be/c4CNY902SAE Versión de texto Lista de reproducción

Blooper Tech Movie XIII – Copycat

Hoy analizamos Copycat, un thriller psicológico de 1995 que, como muchas películas de la época, no pudo resistirse a incorporar elementos tecnológicos que, vistos desde una perspectiva actual, nos sacan una sonrisa. Vamos a desmontar algunos gazapos tecnológicos y curiosidades relacionadas con los sistemas informáticos que aparecen en la película.

El escritorio de tres pantallas: ¿el futuro en 1995?

La protagonista, la Dra. Helen Hudson (Sigourney Weaver), trabaja en un escritorio con tres pantallas, algo futurista para la época. En 1995, esto no era tan común como hoy en día. Para lograrlo, probablemente necesitaría tres ordenadores conectados de forma independiente, ya que los sistemas operativos y hardware de la época no solían soportar múltiples monitores en una sola máquina. Esto plantea preguntas interesantes sobre la logística de su set-up: ¿Cómo sincronizaba su trabajo entre tres PCs?

Un detalle curioso es que, en algunas tomas, se distingue la marca Compaq en los equipos. Compaq era una de las compañías líderes en la fabricación de ordenadores personales durante los 90 y conocida por sus soluciones de alta calidad. Este dato refuerza la idea de que el set-up de Helen estaba diseñado para representar lo último en tecnología de la época, aunque hoy resulte un tanto rudimentario. La elección de Compaq no es casual: en ese momento, era sinónimo de equipos potentes, usados tanto en oficinas como en entornos domésticos avanzados.

Internet y la magia de los módems

En una escena, Helen navega por internet con lo que suponemos es un módem de 28.8 kbps (o como mucho, un flamante 33.6 kbps, tecnología de vanguardia allá por 1995). Hasta ahí, vale. Sin embargo, la fluidez de su conexión sorprende: carga archivos, recibe correos y no se queda esperando con una pantalla de “Conectando…”. Pero lo mejor llega cuando, estando conectada, ¡suena el teléfono! En la realidad, esto cortaría la conexión o comunicaría, a menos que tuviera dos líneas telefónicas (algo raro en domicilios particulares de la época) o algún dispositivo milagroso que no conocemos.

¿Qué sistema operativo usa?

Aunque no se distingue claramente el sistema operativo, vemos una interfaz gráfica con ventanas y una consola de comandos. Esto podría ser un guiño a Windows 3.1 o Windows 3.11, ya maduro en esa época aunque la interfaz no termina de encajar. Sin embargo, también podría ser una mezcla ficticia para hacer que el entorno luciera “tecnológico” sin comprometerse demasiado con la realidad. Detalle curioso: en los 90, las películas solían personalizar las interfaces para no tener problemas legales.

El email como el epicentro de la tecnología

En los 90, el email era el rey. En las películas, los escritorios siempre tenían un gran icono de correo (a menudo animado, porque lo cool siempre parpadeaba). En Copycat, Helen recibe un correo con un archivo AVI de unos 30 segundos, lo cual plantea otra duda técnica: ¿Cuánto espacio ocupaba ese archivo en 1995?

Un AVI de 30 segundos probablemente tendría una resolución baja (320×240 píxeles o menos) y una tasa de compresión eficiente para la época, pero aun así podría pesar entre 2 y 5 MB, dependiendo de la calidad del audio y vídeo. Eso hubiera supuesto una odisea por email, ya que los servidores de la época limitaban los adjuntos a unos pocos cientos de KB. ¿Quizás el villano usó un protocolo privado para saltarse las restricciones?

Tomorrow.AVI

Tras recibir un inquietante archivo AVI, la protagonista llama a la policía, lo que desencadena una conversación cargada de decisiones tecnológicas cuestionables:

  • «¿Cómo le han enviado esto?» / «Consiguiendo su dirección de internet»: El archivo es descrito como enviado a través de «su dirección de internet», un término extraño para la época en la que lo habitual habría sido referirse al correo electrónico. Esto refleja un intento de sonar sofisticado sin usar los términos correctos.
  • «¿No podríamos localizarlo?»: La respuesta de los policías es que no pueden rastrear el origen del archivo «a no ser que esté conectado». Sin embargo, incluso en 1995, las cabeceras de los emails contenían suficiente información para rastrear el servidor de origen, aunque la práctica era más rudimentaria que en la actualidad. Ignorar esto parece una licencia creativa del guion o un concepto equivocado de localizar asociándolo quizá a las llamadas telefónicas.
  • «Es demasiado grande para pasarlo a disco»: Aquí surge el principal obstáculo: el archivo AVI es considerado «demasiado grande» para transferirlo a un disquete de 3,5 pulgadas (con una capacidad máxima de 1,44 MB). Aunque esto tiene sentido desde una perspectiva técnica, resulta extraño que fuera posible enviarlo por email en primer lugar, dado que los servidores de correo de la época tenían limitaciones más estrictas que un disquete. Esto sugiere una inconsistencia en la lógica tecnológica de la escena.
  • «Lo pasaremos a vídeo»: Ante la imposibilidad de transferirlo a un disquete, la solución propuesta es convertir el archivo a un formato reproducible en un dispositivo analógico (probablemente una cinta VHS) para transportarlo físicamente. Aunque esta decisión es plausible dentro de las limitaciones tecnológicas de la época, omite soluciones más digitales, como volver a enviarlo por email (¿acaso la policía no tenía correo electrónico?). Además, surge la pregunta de por qué no se recurre a los forenses técnicos de la policía (o del FBI) para analizar el disco duro, quienes, curiosamente, no aparecen en ningún momento de la película.
  • «Oh, Dios. ¿Cómo sabes todas estas cosas?» / «Malgasté mi juventud en los salones de videojuegos»: Esta frase añade un toque humorístico, pero no tiene relación alguna con las habilidades necesarias para resolver el problema en cuestión. Más bien, refuerza la desconexión entre los diálogos y las acciones tecnológicas presentadas.

Conclusión

Copycat (1995) es un buen ejemplo de cómo el cine de los 90 abordaba la tecnología con una mezcla de admiración y confusión. Desde la exageración de tener tres monitores en el escritorio de Helen hasta la torpe gestión del archivo Tomorrow.AVI, la película refleja tanto las limitaciones tecnológicas de la época como las libertades creativas de los guionistas.

En el caso del archivo AVI, los personajes deciden que no se puede gestionar digitalmente y optan por convertirlo a vídeo analógico, ignorando soluciones más simples como volver a enviarlo por correo electrónico (suponiendo que fuera posible). Este detalle, combinado con la ausencia aparente de personal técnico en la policía, subraya una desconexión entre la narrativa y las capacidades reales de la tecnología, incluso para 1995.

Aunque estos detalles pueden parecer cómicos 30 años después, forman parte del encanto de un cine que imaginaba el futuro sin comprender del todo su presente. Más que errores, son un recordatorio de cómo la tecnología ha evolucionado y de cómo nuestra percepción de ella también lo ha hecho.

Enlaces

  • Copycat [IMDb]
  • Historia de Internet [Wikipedia]
  • Correo electrónico [Wikipedia]
  • Compaq [Wikipedia]
  • Silicon Cowboys: la historia de cómo Compaq retó (y venció) a IBM y Apple [Xataka]
  • Formato de vídeo AVI [Wikipedia]
  • Analysis of video file formats in forensics (.avi example) [DiViLine]

Galería

Keygen para el KeygenMe#01 de eBuC – Comparación lineal

Primeras impresiones

Analizamos el programa con PEiD y nos muestra que está hecho en ensamblador.


Unas pruebas introduciendo datos nos muestran que el nombre debe tener entre 3 y 10 dígitos.


Determinando la rutina de creación del serial con Ollydbg

Llegados a este punto tenemos dos opciones que funcionan en el 90% de los casos. La primera es mediante las referenced strings o mediante los names.
 
Para el primer caso, con el keygenme cargado en olly, click derecho y Search > All referenced text strings. Haciendo doble click en “You got it” o en “Bad boy” vamos directamente a la rutina de comprobación del serial o muy cerca de ella en la mayoría de los casos.


Para el segundo caso, haremos click derecho y Search > Name (label) in current módule, o Ctrl+N. Vemos dos llamadas interesantes como son user32.GetDlgItemInt y user32.GetDlgItemTextA. Lo más seguro es que user32.GetDlgItemInt coja del textbox nuestro serial y user32.GetDlgItemTextA coja nuestro nombre. Para este caso colocaríamos breakpoints en las dos llamadas.


En mi caso elijo la primera opción. Nada más pulsar en “You got it” nos fijamos un poco más arriba y vemos las funciones donde coge el nombre y el serial y a simple vista se ven las operaciones que hace con ellos.

Generando un serial válido

Como se muestra en la imagen siguiente, la creación del serial es muy sencilla y al final la comparación es lineal ya que se compara nuestro serial con el serial válido. Veamos el serial válido para el usuario “abc” cuyos dígitos en hexadecimal son 0x61, 0x62 y 0x63.

Letra a
Letra b
Letra c
Suma + 0x61
Suma * 0x20
Suma xor 0xBEFF
Suma / 4
Suma = 0x2CB7
Suma + 0x62
Suma * 0x20
Suma xor 0xBEFF
Suma / 4
Suma = 0x14777
Suma + 0x63
Suma * 0x20
Suma xor 0xBEFF
Suma / 4
Suma = 0xA116F
Suma xor 0xBEA4 = 0xAAFCB
Serial válido = 700363

Generando un keygen con WinASM studio desde cero

Abrimos WinASM studio y pulsamos en File > New Project y en la pestaña dialog elegimos base.

  

Vemos que se nos generan tres archivos, uno con extensión asm, otro con extensión inc y otro con extensión rc. El archivo asm es el que contendrá nuestro código. El archivo inc no lo vamos a usar para simplificar las cosas y el archivo rc es nuestro formulario al que pondremos a nuestro gusto.
Empecemos con el aspecto del formulario. Por defecto viene como se muestra en la siguiente imagen. Que por cierto, es todo lo que necesitamos para un keygen básico.

Y el aspecto final:

Ahora veamos cómo viene nuestro archivo asm inicialmente y que haremos con él. En la siguiente imagen lo indico.

    Encima de la sección .code hemos creado dos secciones como son .data y .data? y hemos declarado las variables necesarias. 
  • szFormat está declarada en formato integer (%i). Más tarde la utilizaremos junto a la función wsprintf para dar formato a un número.
  • szSizeMin: habla por sí misma.
  • szSizeMax: habla por sí misma.
  •  szCap: habla por sí misma.
  • szName: contendrá el nombre introducido.
  • szCode: contendrá el serial válido.
Nuestro código queda de la siguiente manera:

A partir de aquí ya simplemente es escribir el código necesario para generar el serial válido. Una de las ventajas que tiene el ensamblador para hacer keygens sin muchas complicaciones, es que prácticamente es copiar el código que nos muestra Ollydbg. Si os fijáis a continuación, en el botón llamado “IDC_OK” (no le he cambiado el nombre) he puesto todo el código necesario para generar la simple rutina del serial.
Como veis el bucle del nombre es una copia de lo que nos mostró Ollydbg. Una vez que tenemos en EAX nuestro serial válido, mediante la función wsprintf guardamos en la variable szCode el serial válido con formato integer. Finalmente mediante la función SetDlgItemText, mostramos el serial válido en la caja de texto 1002, que es la del serial.

Enlaces


La serie "Expediente X" (The X-Files) ha capturado la imaginación de los espectadores desde su debut en 1993, con sus
Introducción Aquí tenemos un CrackMe diferente a lo que estamos acostumbrados, ya que en vez del típico número de serie
Se nos entrega el siguiente ELF: Extracción de la Flag Si nos fijamos en las líneas 41 a la 45
Introducción Tal y como nos adelanta el creador está programado en .NET. Lo abrimos para ver su comportamiento y a

Del Hacking a la IA: Cómo Expediente X Abordó la Tecnología de Vanguardia

La serie «Expediente X» (The X-Files) ha capturado la imaginación de los espectadores desde su debut en 1993, con sus intrigantes historias de fenómenos paranormales y conspiraciones gubernamentales. Sin embargo, más allá de los extraterrestres y las criaturas sobrenaturales, la serie también exploró el mundo del hacking, la inteligencia artificial y la piratería informática, temas que se adelantaron a su tiempo y que siguen siendo relevantes hoy en día. A continuación, exploramos algunos de los episodios más emblemáticos que abordan estos temas, revelando detalles fascinantes, curiosidades y tomas falsas que los hicieron memorables.

«Ghost in the Machine» (Temporada 1, Episodio 7)

En este episodio, Mulder y Scully investigan un asesinato en una empresa de tecnología avanzada, Eurisko, donde un sistema de inteligencia artificial llamado «COS» (Central Operating System) podría ser el responsable. La trama se centra en las posibles implicaciones de las IA descontroladas y las vulnerabilidades tecnológicas.

Curiosidades:

  • Este episodio fue uno de los primeros en abordar el tema de la inteligencia artificial en la televisión.
  • El nombre «COS» es una referencia al sistema operativo OS/2 de IBM, que estaba en uso en la época.

Tomas falsas:

  • Durante una de las escenas de acción, el actor encargado de operar el COS tuvo dificultades para mantener la seriedad debido a los efectos especiales rudimentarios, resultando en varias tomas falsas.

«Kill Switch» (Temporada 5, Episodio 11)

Escrito por los renombrados autores de ciencia ficción William Gibson y Tom Maddox, este episodio trata sobre un hacker llamado Donald Gelman que desarrolla una inteligencia artificial avanzada y peligrosa. Mulder y Scully se encuentran en una carrera contra el tiempo para detener a la IA antes de que cause más daño.

Curiosidades:

  • William Gibson es considerado el padre del ciberpunk, y su influencia se nota en la atmósfera y el estilo del episodio.
  • La tecnología y los conceptos presentados en «Kill Switch» fueron increíblemente visionarios para su tiempo, anticipando el desarrollo de IA avanzada y redes cibernéticas.

Tomas falsas:

  • Las escenas de acción en el episodio, especialmente las que involucran a Mulder y Scully en entornos virtuales, resultaron en varios momentos divertidos detrás de cámaras, con los actores luchando por coordinar sus movimientos con los efectos especiales.

«First Person Shooter» (Temporada 7, Episodio 13)

En este episodio, Mulder y Scully se encuentran atrapados en un videojuego de realidad virtual mientras investigan una serie de asesinatos en una empresa de desarrollo de videojuegos. La trama explora los peligros potenciales de la inmersión tecnológica y los límites entre la realidad y la ficción.

En este episodio, Mulder y Scully se encuentran atrapados en un videojuego de realidad virtual mientras investigan una serie de asesinatos en una empresa de desarrollo de videojuegos. La trama explora los peligros potenciales de la inmersión tecnológica y los límites entre la realidad y la ficción.

Curiosidades:

  • Este episodio fue dirigido por Chris Carter, el creador de la serie, y escrito por William Gibson y Tom Maddox, quienes también escribieron «Kill Switch».
  • «First Person Shooter» fue criticado y elogiado a partes iguales por su tratamiento de la cultura de los videojuegos y la tecnología de realidad virtual.

Tomas falsas:

  • Las escenas dentro del videojuego requirieron el uso de efectos especiales avanzados para la época, lo que resultó en numerosos errores técnicos y momentos de risas entre el elenco.

«Rm9sbG93ZXJz» (Temporada 11, Episodio 7)

Este episodio de la temporada más reciente se centra en el impacto de la inteligencia artificial y la tecnología moderna en la vida cotidiana. Mulder y Scully son perseguidos por drones y dispositivos automatizados después de un malentendido en un restaurante automatizado.

Curiosidades:

  • El título del episodio, «Rm9sbG93ZXJz», es «Followers» en base64, una referencia a la temática del episodio sobre las redes sociales y la vigilancia tecnológica.
  • Este episodio es casi completamente sin diálogos, lo que crea una atmósfera única y tensa que subraya la dependencia moderna de la tecnología.

Tomas falsas:

  • La falta de diálogos resultó en situaciones cómicas durante el rodaje, ya que los actores tenían que comunicar mucho con expresiones faciales y movimientos, lo que llevó a varios malentendidos y momentos divertidos.

Cabe mencionar que, en esta ocasión, no he incluido ningún episodio protagonizado por los Pistoleros Solitarios, el trío de hackers y teóricos de la conspiración favoritos de los fans. Este grupo merece un artículo dedicado para explorar en profundidad sus contribuciones únicas a la serie y su propio spin-off, que también aborda numerosos temas tecnológicos y conspirativos con su estilo distintivo.

Estos episodios no solo nos ofrecen emocionantes tramas y misterios tecnológicos, sino que también nos brindan un vistazo a un futuro potencial, uno en el que la línea entre lo humano y lo artificial se vuelve cada vez más difusa. Las curiosidades y tomas falsas detrás de cámaras añaden una capa adicional de encanto, mostrando el esfuerzo y la creatividad necesarios para dar vida a estos complejos temas.

Como fanáticos de «Expediente X», podemos apreciar cómo la serie ha sido capaz de mantenerse relevante y cautivadora al abordar cuestiones tecnológicas que son tanto atemporales como urgentes. Nos ha llevado a cuestionar nuestra confianza en las máquinas, a temer las posibles repercusiones de una inteligencia artificial sin control y a maravillarnos con las posibilidades de la realidad virtual.

En resumen, «Expediente X» no solo ha sido un pionero en la televisión de ciencia ficción y misterio, sino que también ha demostrado una notable capacidad para explorar y anticipar los dilemas tecnológicos que enfrentamos hoy en día. Estos episodios son un recordatorio de que, en el vasto universo de lo desconocido, la tecnología juega un papel crucial y, a veces, aterrador. Para los verdaderos fans, cada uno de estos episodios es una joya que merece ser revivida y analizada, apreciando su profundidad y relevancia en nuestro mundo cada vez más digital.


Todas las imágenes de esta entrada han sido generadas con ChatGPT.

Solución al CrackMe Matrix de ZemoZ

Introducción

Aquí tenemos un CrackMe diferente a lo que estamos acostumbrados, ya que en vez del típico número de serie asociado a un nombre la comprobación se realiza mediante checkboxes con una matriz de 7×3. El CrackMe está realizado en Visual C++ lo que facilita en parte encontrar rápidamente la rutina de comprobación.

Comprobación

004013C5   > /8B7424 10     MOV     ESI,[DWORD SS:ESP+10]						;
004013C9   . |33FF          XOR     EDI,EDI
004013CB   > |8B86 74304000 MOV     EAX,[DWORD DS:ESI+403074]                   ;
004013D1   . |8BCB          MOV     ECX,EBX
004013D3   . |50            PUSH    EAX
004013D4   . |E8 6F020000   CALL    <JMP.&MFC42.#3092_CWnd::GetDlgItem>			; Lee el estado del checkbox
004013D9   . |8B48 20       MOV     ECX,[DWORD DS:EAX+20]
004013DC   . |6A 00         PUSH    0
004013DE   . |6A 00         PUSH    0
004013E0   . |68 F0000000   PUSH    0F0
004013E5   . |51            PUSH    ECX                                         ; 
004013E6   . |FFD5          CALL    NEAR EBP
004013E8   . |3B86 20304000 CMP     EAX,[DWORD DS:ESI+403020]					; Comprueba el estado del checkbox (1 activado 0 desactivado)
004013EE   . |75 20         JNZ     SHORT Matrix_C.00401410						; Salto a chico malo
004013F0   . |47            INC     EDI											; Incrementa contador
004013F1   . |83C6 04       ADD     ESI,4
004013F4   . |83FF 07       CMP     EDI,7										; ¿Hemos terminado de leer las columnas? ¿contador = 7?
004013F7   .^|7C D2         JL      SHORT Matrix_C.004013CB                     ; si terminan las columnas deja pasar
004013F9   . |8B4424 10     MOV     EAX,[DWORD SS:ESP+10]
004013FD   . |83C0 1C       ADD     EAX,1C										; contador de filas
00401400   . |83F8 54       CMP     EAX,54										; 3 filas = 1C+1C+1C=54
00401403   . |894424 10     MOV     [DWORD SS:ESP+10],EAX
00401407   .^\7C BC         JL      SHORT Matrix_C.004013C5						; ¿Hemos terminado de leer la fila? ¿contador = 54?
00401409   .  68 D8304000   PUSH    Matrix_C.004030D8                           ;  ASCII "Registration successful!"
0040140E   .  EB 05         JMP     SHORT Matrix_C.00401415
00401410   >  68 C8304000   PUSH    Matrix_C.004030C8                           ;  ASCII "Not registered!"

En la rutina de comprobación se ve fácil un CMP EDI,7 por lo que podemos deducir que si el creador no se ha molestado mucho la comprobación se realiza de izquierda a derecha y de arriba hacia abajo.

Orden de comprobación

Tal es así que si ponemos un breakpoint en 4013E8, podemos ir sacando el estado correcto de los checkboxes sin mucha molestia.

Resultado final

Enlaces

Migas de pan

Se nos entrega el siguiente ELF:

/* 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);
void sub_1020();
// int printf(const char *format, ...);
// int getchar(void);
// int fflush(FILE *stream);
// __int64 __isoc99_scanf(const char *, ...); weak
// void __noreturn exit(int status);
// int __fastcall _cxa_finalize(void *);
void __fastcall __noreturn start(__int64 a1, __int64 a2, void (*a3)(void));
FILE **deregister_tm_clones();
__int64 register_tm_clones(); // weak
FILE **_do_global_dtors_aux();
__int64 __fastcall frame_dummy(_QWORD, _QWORD, _QWORD); // weak
int __fastcall main(int argc, const char **argv, const char **envp);
_BOOL8 __fastcall comprobacion(char a1, char a2, int a3);
void _libc_csu_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);
// int __fastcall __cxa_finalize(void *);
// __int64 _gmon_start__(void); weak

//-------------------------------------------------------------------------
// Data declarations

_UNKNOWN _libc_csu_init;
__int64 (__fastcall *_frame_dummy_init_array_entry)() = &frame_dummy; // weak
__int64 (__fastcall *_do_global_dtors_aux_fini_array_entry)() = &_do_global_dtors_aux; // weak
void *_dso_handle = &_dso_handle; // idb
char *a = "MdfnJk"; // weak
char *b = "jYx}"; // weak
char *c = "gWmfk"; // weak
char *d = "mlvpc"; // weak
char *f = "neU++w"; // weak
FILE *_bss_start; // idb
char completed_0; // weak


//----- (0000000000001000) ----------------------------------------------------
__int64 (**init_proc())(void)
{
  __int64 (**result)(void); // rax

  result = &_gmon_start__;
  if ( &_gmon_start__ )
    return (__int64 (**)(void))_gmon_start__();
  return result;
}
// 40D0: using guessed type __int64 _gmon_start__(void);

//----- (0000000000001020) ----------------------------------------------------
void sub_1020()
{
  JUMPOUT(0LL);
}
// 1026: control flows out of bounds to 0

//----- (0000000000001090) ----------------------------------------------------
// 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))_libc_csu_init,
    _libc_csu_fini,
    a3,
    &v5);
  __halt();
}
// 1096: positive sp value 8 has been found
// 109D: variable 'v3' is possibly undefined

//----- (00000000000010C0) ----------------------------------------------------
FILE **deregister_tm_clones()
{
  return &_bss_start;
}

//----- (00000000000010F0) ----------------------------------------------------
__int64 register_tm_clones()
{
  return 0LL;
}
// 10F0: using guessed type __int64 register_tm_clones();

//----- (0000000000001130) ----------------------------------------------------
FILE **_do_global_dtors_aux()
{
  FILE **result; // rax

  if ( !completed_0 )
  {
    if ( &__cxa_finalize )
      _cxa_finalize(_dso_handle);
    result = deregister_tm_clones();
    completed_0 = 1;
  }
  return result;
}
// 4080: using guessed type char completed_0;

//----- (0000000000001175) ----------------------------------------------------
int __fastcall main(int argc, const char **argv, const char **envp)
{
  char v4; // [rsp+7h] [rbp-9h] BYREF
  int v5; // [rsp+8h] [rbp-8h]
  bool v6; // [rsp+Fh] [rbp-1h]

  v6 = 1;
  v5 = 0;
  while ( v6 )
  {
    fflush(_bss_start);
    printf("\nIntroduce la letra correcta:\t");
    __isoc99_scanf("%c", &v4);
    getchar();
    if ( v5 > 5 )
    {
      if ( v5 > 9 )
      {
        if ( v5 > 14 )
        {
          if ( v5 > 19 )
            v6 = comprobacion(v4, f[v5 - 20], 10);
          else
            v6 = comprobacion(v4, d[v5 - 15], 2);
        }
        else
        {
          v6 = comprobacion(v4, c[v5 - 10], 8);
        }
      }
      else
      {
        v6 = comprobacion(v4, b[v5 - 6], 17);
      }
    }
    else
    {
      v6 = comprobacion(v4, a[v5], 5);
    }
    if ( !v6 )
    {
      printf("Incorrecta");
      exit(1);
    }
    printf("\n%c\n", (unsigned int)v4);
    if ( v5 == 25 )
    {
      printf("Ya tienes la flag!!");
      exit(1);
    }
    ++v5;
  }
  return 0;
}
// 1060: using guessed type __int64 __isoc99_scanf(const char *, ...);
// 4050: using guessed type char *a;
// 4058: using guessed type char *b;
// 4060: using guessed type char *c;
// 4068: using guessed type char *d;
// 4070: using guessed type char *f;

//----- (0000000000001352) ----------------------------------------------------
_BOOL8 __fastcall comprobacion(char a1, char a2, int a3)
{
  return a1 == (a3 ^ a2);
}

//----- (0000000000001390) ----------------------------------------------------
void __fastcall _libc_csu_init(unsigned int a1, __int64 a2, __int64 a3)
{
  signed __int64 v4; // rbp
  __int64 i; // rbx

  init_proc();
  v4 = &_do_global_dtors_aux_fini_array_entry - &_frame_dummy_init_array_entry;
  if ( v4 )
  {
    for ( i = 0LL; i != v4; ++i )
      ((void (__fastcall *)(_QWORD, __int64, __int64))*(&_frame_dummy_init_array_entry + i))(a1, a2, a3);
  }
}
// 1170: using guessed type __int64 __fastcall frame_dummy(_QWORD, _QWORD, _QWORD);
// 3DE8: using guessed type __int64 (__fastcall *_frame_dummy_init_array_entry)();
// 3DF0: using guessed type __int64 (__fastcall *_do_global_dtors_aux_fini_array_entry)();

//----- (00000000000013F4) ----------------------------------------------------
void term_proc()
{
  ;
}

Extracción de la Flag

Si nos fijamos en las líneas 41 a la 45 vemos las siguientes cadenas:

a = «MdfnJk»
b = «jYx}»
c = «gWmfk»
d = «mlvpc»
f = «neU++w»

Usaremos las cadenas y los valores XOR especificados para cada rango de v5 en el main (líneas 123 a 182) para determinar los caracteres correctos.

Para v5 de 0 a 5: v6 = comprobacion(v4, a[v5], 5);
Significa que: v4 debe ser igual a a[v5] ^ 5

Para v5 de 6 a 9: v6 = comprobacion(v4, b[v5 – 6], 17);
Significa que: v4 debe ser igual a b[v5 – 6] ^ 17

Para v5 de 10 a 14: v6 = comprobacion(v4, c[v5 – 10], 8);
Significa que: v4 debe ser igual a c[v5 – 10] ^ 8

Para v5 de 15 a 19: v6 = comprobacion(v4, d[v5 – 15], 2);
Significa que: v4 debe ser igual a d[v5 – 15] ^ 2

Para v5 de 20 a 25: v6 = comprobacion(v4, f[v5 – 20], 10);
Significa que: v4 debe ser igual a f[v5 – 20] ^ 10

Cálculo de los caracteres correctos:
Para v5 de 0 a 5:
a[0] = ‘M’, M ^ 5 = 0x4D ^ 0x05 = 0x48 -> ‘H’
a[1] = ‘d’, d ^ 5 = 0x64 ^ 0x05 = 0x61 -> ‘a’
a[2] = ‘f’, f ^ 5 = 0x66 ^ 0x05 = 0x63 -> ‘c’
a[3] = ‘n’, n ^ 5 = 0x6E ^ 0x05 = 0x6B -> ‘k’
a[4] = ‘J’, J ^ 5 = 0x4A ^ 0x05 = 0x4F -> ‘O’
a[5] = ‘k’, k ^ 5 = 0x6B ^ 0x05 = 0x6E -> ‘n’
Resulta en la cadena: HackOn

Para v5 de 6 a 9:
b[0] = ‘j’, j ^ 17 = 0x6A ^ 0x11 = 0x7B -> ‘{‘
b[1] = ‘Y’, Y ^ 17 = 0x59 ^ 0x11 = 0x48 -> ‘H’
b[2] = ‘x’, x ^ 17 = 0x78 ^ 0x11 = 0x69 -> ‘i’
b[3] = ‘}’, } ^ 17 = 0x7D ^ 0x11 = 0x6C -> ‘l’
Resulta en la cadena: {Hil

Para v5 de 10 a 14:
c[0] = ‘g’, g ^ 8 = 0x67 ^ 0x08 = 0x6F -> ‘o’
c[1] = ‘W’, W ^ 8 = 0x57 ^ 0x08 = 0x5F -> ‘_’
c[2] = ‘m’, m ^ 8 = 0x6D ^ 0x08 = 0x65 -> ‘e’
c[3] = ‘f’, f ^ 8 = 0x66 ^ 0x08 = 0x6E -> ‘n’
c[4] = ‘k’, k ^ 8 = 0x6B ^ 0x08 = 0x63 -> ‘c’
Resulta en la cadena: o_enc

Para v5 de 15 a 19:
d[0] = ‘m’, m ^ 2 = 0x6D ^ 0x02 = 0x6F -> ‘o’
d[1] = ‘l’, l ^ 2 = 0x6C ^ 0x02 = 0x6E -> ‘n’
d[2] = ‘v’, v ^ 2 = 0x76 ^ 0x02 = 0x74 -> ‘t’
d[3] = ‘p’, p ^ 2 = 0x70 ^ 0x02 = 0x72 -> ‘r’
d[4] = ‘c’, c ^ 2 = 0x63 ^ 0x02 = 0x61 -> ‘a’
Resulta en la cadena: ontra

Para v5 de 20 a 25:
f[0] = ‘n’, n ^ 10 = 0x6E ^ 0x0A = 0x64 -> ‘d’
f[1] = ‘e’, e ^ 10 = 0x65 ^ 0x0A = 0x6F -> ‘o’
f[2] = ‘U’, U ^ 10 = 0x55 ^ 0x0A = 0x5F -> ‘_
f[3] = ‘+’, + ^ 10 = 0x2B ^ 0x0A = 0x21 -> ‘!’
f[4] = ‘+’, + ^ 10 = 0x2B ^ 0x0A = 0x21 -> ‘!’
f[5] = ‘w’, w ^ 10 = 0x77 ^ 0x0A = 0x7D -> ‘}’
Resulta en la cadena: do_!!}

Uniendo todas las partes, obtenemos la flag completa: HackOn{Hilo_enc_ontrado_!!}

WinFan’s NETCrackMe#1 Keygen

Introducción

Tal y como nos adelanta el creador está programado en .NET. Lo abrimos para ver su comportamiento y a simple vista ya vemos algo que no nos gusta y es que se abre una ventana de DOS y posteriormente aparece el crackme. Esto indica que el ejecutable está escondido dentro de otro, empaquetado, encriptado o vete a saber.

Desempaquetado

Nuestras sospechas eran ciertas, abrimos el executable con ILSpy y no encontramos lo que buscamos, pero si vemos que al assembly se le hace algo parecido a un XOR. Probemos con algo sencillo, abrimos el crackme y la herramienta .Net Generic Unpacker y probamos a desempaquetar.
27-08-2014-2B12-33-33
Esto nos genera un par de «exes» que ahora si abre correctamente nuestro decompilador.

Decompilado

Vamos a fijarnos en la rutina de comprobación del serial. Lo interesante se encuentra en btnCheckClick y TLicense.
Código fuente.
Como vemos en el código, License.a.a, License.a.b y License.a.c cogen 8 dígitos y License.a.d coge 10. A continuación comprueba que Licenseb.a = License.a.a XOR License.a.b y que Licenseb.b = License.a.c XOR License.a.d.
Una imagen vale más que mil palabras.
En su día hice un keygen, aquí teneis una captura.
Podeis encontrar el crackme, mi solución y otras soluciones en crackmes.de.

Links


En una entrada anterior sobre cómo Expediente X abordó la tecnología de vanguardia, comenté que dedicaría un espacio a esos
Aquí os dejo un video tutorial. El crackme lo podeis encontrar en crackmes.de.
Estamos ante un ELF un poco más interesante que los vistos anteriormente. Básicamente porque es divertido y fácil encontrar la
Warning: This challenge is still active and therefore should not be resolved using this information.  Aviso: Este reto sigue en

Los Pistoleros Solitarios

En una entrada anterior sobre cómo Expediente X abordó la tecnología de vanguardia, comenté que dedicaría un espacio a esos tres personajes tan peculiares y entrañables que, desde el segundo plano, se ganaron un hueco en el corazón de los seguidores de la serie: los Pistoleros Solitarios. Pues bien, ha llegado el momento.

Estos tres tipos —John Fitzgerald Byers, Melvin Frohike y Richard “Ringo” Langly— no necesitaban armas ni placas del FBI. Su poder estaba en los teclados, los cables enredados y los monitores de tubo que parpadeaban en un sótano lleno de conspiraciones y café frío. Eran los outsiders de Expediente X, tres hackers con alma de periodistas que luchaban por algo tan simple y tan enorme como la verdad.

Su primera aparición fue en E.B.E. (temporada 1), casi como un alivio cómico: tres frikis que ayudaban a Mulder a rastrear información sobre ovnis. Pero pronto quedó claro que había algo especial en ellos. No solo eran fuente de datos, sino conciencia crítica en un mundo plagado de mentiras digitales y gobiernos con demasiados secretos. Con el tiempo se convirtieron en aliados imprescindibles de Mulder y Scully, y también en el reflejo más humano de lo que significa ser hacker: curiosos, testarudos, torpes a veces, pero con un sentido moral inquebrantable.

Byers era el idealista, el que aún creía en la decencia y en las instituciones (al menos en teoría). Frohike, el cínico veterano con corazón de oro, siempre dispuesto a arriesgarse por una buena causa… o por impresionar a Scully. Y Langly, el genio rebelde que parecía vivir en permanente conversación con su módem de 56 k. Juntos formaban un trío excéntrico, pero perfectamente equilibrado.

Mientras Mulder y Scully perseguían abducciones y virus extraterrestres, los pistoleros combatían en otra trinchera: la digital. Hackeaban redes gubernamentales, interceptaban comunicaciones cifradas y desmantelaban cortafuegos que, en los noventa, parecían pura ciencia ficción. Lo suyo no era la acción física, sino la resistencia informativa. Y aunque muchas veces eran el chiste del capítulo, también representaban algo muy real: la gente corriente que lucha contra el poder desde el conocimiento.

Su lema no declarado podría haber sido el clásico “la información quiere ser libre”, y en eso se mantuvieron firmes hasta el final. Si había que elegir entre la seguridad o la verdad, ellos siempre elegían la verdad, aunque les costara caro.

TemporadaEpisodioTítuloComentario
117E.B.E.Primera aparición de los pistoleros.
23BloodManipulación de dispositivos y mensajes ocultos. También control mental a través de la tecnología.
225AnasaziUn hacker roba archivos clasificados. Se tratan temas como el cifrado y filtración de datos del gobierno.
315ApocryphaAcceso a bases de datos secretas y descifrado de archivos comprometidos.
323WetwiredManipulación de señales televisivas.
414Memento MoriInfiltración digital en sistemas médicos y vigilancia biotecnológica.
51ReduxRobo y manipulación de pruebas digitales.
53Unusual SuspectsOrígenes de los pistoleros: intrusión, cifrado y espíritu hacker de los noventa.
511Kill SwitchIA autónoma y malware inteligente.
620Three of a KindHacking social, suplantación y síntesis de voz para infiltración corporativa.
713First Person ShooterHackeo de entornos virtuales y brechas de seguridad en sistemas de realidad aumentada.
915Jump the SharkSu sacrificio final: bloqueo de una amenaza biológica, ética hacker y altruismo extremo.
112ThisLangly como conciencia digital en un servidor. Debate sobre IA y trascendencia del código.

Morir por la verdad

El final de los pistoleros fue tan inesperado como heroico. En el episodio “Jump the Shark” de la novena temporada, descubren un complot bioterrorista que amenaza con liberar un virus mortal. No hay tiempo para avisar a nadie, ni margen para escapar. Así que, fieles a su estilo, deciden sacrificarse para salvar a otros. Sellan el laboratorio desde dentro, sabiendo que no volverán a salir.

Lo reconozco, este desenlace mi cogió completamente por sorpresa. No hay épica de Hollywood, ni música grandilocuente. Solo tres hombres anónimos haciendo lo correcto. Mueren juntos, sin reconocimiento, sin medallas, pero con la serenidad de quienes saben que su causa era justa. Y en ese silencio final, Expediente X nos recordó algo que las grandes historias suelen olvidar: que los verdaderos héroes a veces no llevan traje ni pistola, solo convicción.

Años después, Mulder vuelve a verlos —o cree verlos— en The Truth. Ya no están en este mundo, pero siguen a su lado, como fantasmas digitales de la conciencia hacker. Es un homenaje discreto a quienes siempre pelearon desde las sombras por liberar la verdad.

Para cerrar el círculo, Langly reaparece de forma inesperada en la temporada 11, dentro del episodio This. Su mente, o más bien su copia digital, sobrevive atrapada en un servidor, reclamando ser liberada. Es el epílogo perfecto: el hacker que muere físicamente, pero cuya conciencia sigue inmortal. Una vez más me volvió a sorprender Chris Carter con este homenaje.

Me gusta pensar que los pistoleros solitarios representaban algo más que tres hackers secundarios en una serie de los noventa. Fueron el reflejo de una época en la que creíamos que la tecnología podía liberar al ser humano, antes de que las redes sociales y la hiperconectividad lo diluyeran todo. Byers, Frohike y Langly no luchaban por fama ni por dinero: luchaban por entender el sistema para exponerlo, por esa curiosidad genuina que hoy apenas sobrevive entre líneas de código y algoritmos opacos. Quizá por eso seguimos recordándolos y mola tanto volver a ver los capítulos. Porque, de algún modo, todos los que amamos el conocimiento libre llevamos dentro un pequeño pistolero solitario, buscando la verdad entre los bits.

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 – Realistic Challenge 1

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

 Realistic Challenge 1: Your friend tried to purchase some software off a company. But after he paid they decided to increase it’s price by a large amount. They are now refusing to send it him. Get them back by getting their most expensive software a lot cheaper than they intended you to.
Lo que nos dice el enunciado del reto a groso modo es que debemos cambiar el precio del software antes de comprarlo.

Firebug

 Para resolver este reto basta con tener instalado el complemento para Firefox «Firebug«. Abrimos la web y echamos un vistazo con Firebug
Vemos un parámetro oculto que se llama «amount» y que tiene un valor de 100$. Basta con cambiarlo a 00,01$ y ya tenemos resuelto el reto.

Links