crackmes

Intro Aquí tenemos un crackme clásico realizado en Visual C++. La única particularidad que tiene es que no muestra MessageBox
Introducción Cripto 1 Cripto 2 Cripto 3 Cripto 4 Cripto 5 Cripto 6 Cripto 7 Cripto 8 Cripto 9 Cripto 10
Intro Es un crackme realizado en ensamblador y en el que el objetivo es remover la NAG de la forma
En el BTM anterior nos remontábamos al año 2006 para ver un pequeño gazapo ocurrido en la serie Dexter. En

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

Intermodular Calls

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!

Solución a los retos criptográficos de Rogerfm.net

Introducción

Los retos de encriptación son muy variados como hemos comentado anteriormente. Aquí tenemos unos buenos ejemplos de ello.

Cripto 1

En este primer nivel nos encontramos con un método de encriptación muy antíguo.    Sólo diré como pista, que es de los más antiguos que se conocen.

ozhlofxrlmvhxzorulimrz

Lo primero que suelo hacer en este tipo de retos cuando son solamente letras, es comprobar las dos opciones más típicas, que son el cifrado César y Vigenere. En este caso necesitamos ahondar un poco más, aunque enseguida llegamos a la conclusión de que el cifrado usado es el afín. Un ataque por fuerza bruta nos devuelve la solución y los coeficientes utilizados.

Solución: A=25,B=25  – LASOLUCIONESCALIFORNIA

Fuente: http://www.dcode.fr/chiffre-affine


Cripto 2

En este segundo nivel recordaremos a un general romano muy conocido. Lo complicaremos un poco, sólo lo justo para que cueste algo más de cinco minutos encontrar la clave 🙂

oehoeahhjoexhkzqhfsvzhffhwrhotqk

Lo primero que nos viene a la cabeza es el cifrado César pero no va. Probando varios cifrados por sustitución al final damos con el correcto. De nuevo un ataque por fuerza bruta nos da frutos.

Solución: (3,4,5)/1  – LACLAVEDELASEGUNDAPRUEBAESMEKONG

Fuente: https://www.dcode.fr/chiffre-decalages


Cripto 3

Este nivel también va a ser sencillo. Estos caracteres, pertenecientes a un sistema bastante conocido de encriptado, esconden una palabra que, al introducirla (en minúsculas), nos permitirá superar el nivel.

Investigando un poco llegamos a la conclusión de que se trata del cifrado Francmasón o Pig Pen.

Solución: primates

Fuente: https://www.dcode.fr/chiffre-pig-pen-francs-macons


Cripto 4

Esta prueba es tan simple que la he dividido en dos partes que, aunque de apariencia similar, se resuelven de distinta manera. La clave es la unión de las dos palabras resultantes de descifrar las dos líneas de números y que, juntas, forman una tercera palabra.

0111001101110101011100000110010101110010
0001001110011000111110100100110010010001

La primera parte se puede convertir en bloque:

0111001101110101011100000110010101110010 = super

Fuente: https://www.rapidtables.com/convert/number/binary-to-ascii.html

Para la segunda debemos separar en grupos de 5 dígitos y listo:

00010   01110   01100   01111   10100   10011   00100   10001

 C             O          M           P            U          T           E           R

Fuente: www.lindau-nobel.org


Cripto 5

Para descubrir la palabra clave sólo se necesita una mínima capacidad de observación.

31 04 40 23 20 34 33 13 23 22

Se trata del cuadrado de Polibio.


Cripto 6

Aquí hay que hacer un poco de trabajo de investigación: Hay que descubrir la clave que empleó un escritor francés (Una pista: «Lagardère») en una de sus novelas, que es la empleada aquí para formar la palabra clave (en minúsculas) que, por cierto, es alemana.

RI3I2MIL2I2A3

POR RESOLVER


Cripto 7

Seguimos con cosas fáciles. Se trata de descifrar este texto escrito en inglés.

kgw qkoev ol 617 qthpreoz iwjpz sdkg kgw pdeyeplk rwqdjzwe ipezwq spbbdq sgo sgwz goqkdbdkdwq iwjpz spq rwkwecdzwr ko cpmw gdq uweqozpb yozkedihkdoz ko kgw spe wlloek

Una vez descifrado, nos será fácil descubrir la clave:

pzpyozrp

Se trata de  un cifrado de sustitución mono alfabético.

ABCDEFGHIJKLMNOPQRSTUVWXYZ
ZLMIRVHUBGTFJKOASDWQPYEXCN

THE STORY OF 617 SQUADRON BEGAN WITH THE AIRCRAFT DESIGNER BARNES WALLIS WHO WHEN HOSTILITIES BEGAN WAS DETERMINED TO MAJE HIS PERSONAL CONTRIBUTION TO THE WAR EFFORT

Una vez descifrado el alfabeto la solución queda:

pzpyozrp = anaconda

Cripto 8

A veces, las cosas no son lo que parecen. Donde aparecen unos números, en realidad hay otros números distintos.

273664524572348321143738
853442616537643005319627

POR RESOLVER


Cripto 9

Para resolver algunos problemas, hay que tener una buena base. Este es un buen ejemplo de ello:

ZW50ZXJwcmlzZQ0K

¿Os suena base 64?

Solución: enterprise

Fuente: https://www.base64decode.org/


Cripto 10

Esto es más complicado. Para descifrar este texto que contiene la clave para superar el nivel, se necesita otra clave. Para que no sea demasiado difícil, he utilizado una palabra muy sencilla de sólo cuatro letras 🙂

myiemyuvbaeewcxweghkflxw

Mediante fuerza bruta matamos dos pájaros de un tiro.

lapalabraclaveesdiogenes

Fuente: https://www.guballa.de/vigenere-solver


Enlaces

TDC’s Remove the NAG – Parche

Intro

Es un crackme realizado en ensamblador y en el que el objetivo es remover la NAG de la forma más limpia posible.

Analizando a la víctima

Abrimos el crackme con Olly y ya a simple vista vemos los mensajes de la Nag y parte del código interesante. Si necesitaramos localizar la Nag podemos mirar en las intermodular calls las típicas subrutinas, en este caso se ve claramente  a MessageBoxA, bastaría con poner un breakpoint para localizar quien llama.

Aquí vemos la implicación de MessageBoxA.

004010A7     |> \6A 40                    PUSH 40                                         ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
004010A9     |.  68 61304000              PUSH Nag1.00403061                              ; |Title = "[NAG] Please register this software!"
004010AE     |.  68 86304000              PUSH Nag1.00403086                              ; |Text = "[BULLSHIT] Please register this software for support and you'll receive the full version!"
004010B3     |.  FF75 08                  PUSH [ARG.1]                                    ; |hOwner = 7FFDF000
004010B6     |.  E8 49010000              CALL <JMP.&user32.MessageBoxA>                  ; \MessageBoxA
........
00401137     |.  6A 40                    PUSH 40                                         ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00401139     |.  68 6E324000              PUSH Nag1.0040326E                              ; |Title = "Thank you!"
0040113E     |.  68 79324000              PUSH Nag1.00403279                              ; |Text = "Thank you for registering this software!"
00401143     |.  FF75 08                  PUSH [ARG.1]                                    ; |hOwner = 7FFDF000
00401146     |.  E8 B9000000              CALL <JMP.&user32.MessageBoxA>                  ; \MessageBoxA
........
00401155     |.  6A 40                    PUSH 40                                         ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00401157     |.  68 E0304000              PUSH Nag1.004030E0                              ; |Title = "About"
0040115C     |.  68 E6304000              PUSH Nag1.004030E6                              ; |Text = "Remove the NAG by TDC\r\n\n..: Coded by\t: TDC\t\t\t:..\t\r\n..: Also known as\t: The Dutch Cracker\t:..\t\r\n..: Protection\t: Custom\t\t\t:..\t\r\n..: Contact info\t: tdc123@gmail.com\t:..\t\r\n..: Release date\t: 09-08-2005\t\t:..\t"...
00401161     |.  FF75 08                  PUSH [ARG.1]                                    ; |hOwner = 7FFDF000
00401164     |.  E8 9B000000              CALL <JMP.&user32.MessageBoxA>                  ; \MessageBoxA

 Un poco encima vemos la función SetDlgItemTextA, que nos mostrará el mensaje de que hemos parcheado correctamente.

dlgitem

00401106     |> \68 21304000              PUSH Nag1.00403021                              ; /Text = "Dirty crack! Nag removed not registered!"
0040110B     |.  6A 73                    PUSH 73                                         ; |ControlID = 73 (115.)
0040110D     |.  FF75 08                  PUSH [ARG.1]                                    ; |hWnd = 7FFDF000
00401110     |.  E8 FB000000              CALL <JMP.&user32.SetDlgItemTextA>              ; \SetDlgItemTextA
00401115     |.  EB 36                    JMP SHORT Nag1.0040114D
00401117     |>  68 10304000              PUSH Nag1.00403010                              ; /Text = "Nag not removed!"
0040111C     |.  6A 73                    PUSH 73                                         ; |ControlID = 73 (115.)
0040111E     |.  FF75 08                  PUSH [ARG.1]                                    ; |hWnd = 7FFDF000
00401121     |.  E8 EA000000              CALL <JMP.&user32.SetDlgItemTextA>              ; \SetDlgItemTextA
00401126     |.  EB 25                    JMP SHORT Nag1.0040114D
00401128     |>  68 4A304000              PUSH Nag1.0040304A                              ; /Text = "Clean crack! Good Job!"
0040112D     |.  6A 73                    PUSH 73                                         ; |ControlID = 73 (115.)
0040112F     |.  FF75 08                  PUSH [ARG.1]                                    ; |hWnd = 7FFDF000
00401132     |.  E8 D9000000              CALL <JMP.&user32.SetDlgItemTextA>              ; \SetDlgItemTextA

Encima de SetDlgItemTextA vemos el código que analiza si la Nag tiene que aparecer.

004010E6     |.  E8 C4000000              CALL Nag1.004011AF                              ;  ; Llamada interesante a analizar
004010EB     |.  803D B0324000 03         CMP BYTE PTR DS:[4032B0],3
004010F2     |.  74 12                    JE SHORT Nag1.00401106                          ;  ; Si de la llamada volvemos con un 3 -> Parcheo chapuza
004010F4     |.  803D B0324000 02         CMP BYTE PTR DS:[4032B0],2
004010FB     |.  74 1A                    JE SHORT Nag1.00401117                          ;  ; Si de la llamada volvemos con un 2 -> Sin parchear
004010FD     |.  803D B0324000 01         CMP BYTE PTR DS:[4032B0],1
00401104     |.  74 22                    JE SHORT Nag1.00401128                          ;  ; Si de la llamada volvemos con un 1 -> Buen trabajo Joe!
........
004011AF     /$  68 A2324000              PUSH Nag1.004032A2                              ; /String2 = "Value1"
004011B4     |.  68 A9324000              PUSH Nag1.004032A9                              ; |String1 = "Value2"
004011B9     |.  E8 64000000              CALL <JMP.&kernel32.lstrcmpA>                   ; \lstrcmpA
004011BE     |.  50                       PUSH EAX                                        ;  kernel32.BaseThreadInitThunk
004011BF     |.  85C0                     TEST EAX,EAX                                    ;  kernel32.BaseThreadInitThunk
004011C1     |.  75 10                    JNZ SHORT Nag1.004011D3
004011C3     |.  33C0                     XOR EAX,EAX                                     ;  kernel32.BaseThreadInitThunk
004011C5     |.  58                       POP EAX                                         ;  kernel32.75CDEE1C
004011C6     |.  85C0                     TEST EAX,EAX                                    ;  kernel32.BaseThreadInitThunk
004011C8     |.  74 15                    JE SHORT Nag1.004011DF
004011CA     |.  C605 B0324000 03         MOV BYTE PTR DS:[4032B0],3
004011D1     |.  EB 17                    JMP SHORT Nag1.004011EA
004011D3     |>  58                       POP EAX                                         ;  kernel32.75CDEE1C
004011D4     |.  33C0                     XOR EAX,EAX                                     ;  kernel32.BaseThreadInitThunk
004011D6     |.  C605 B0324000 02         MOV BYTE PTR DS:[4032B0],2
004011DD     |.  EB 0B                    JMP SHORT Nag1.004011EA
004011DF     |>  33C0                     XOR EAX,EAX                                     ;  kernel32.BaseThreadInitThunk
004011E1     |.  C605 B0324000 01         MOV BYTE PTR DS:[4032B0],1
004011E8     |.  EB 00                    JMP SHORT Nag1.004011EA
004011EA     \>  C3                       RETN

 Vemos dentro del Call 4011AF que Compara si Value1 = Value2 y dependiendo de esa comparación guarda en memoria (4032B0), los valores 1, 2 ó 3.

Basta con modificar en un editor hexadecimal la parabra «Value2» por «Value1» y ya tenemos el problema resuelto.

09-09-2014 11-04-03

09-09-2014 11-04-34

09-09-2014 11-05-26

Al pulsar Re-Check

09-09-2014 11-06-01

Notas finales

Se podía haber parcheado un montón de código para obtener el mismo resultado pero fijándonos en el código lo hemos conseguido parcheando un solo byte. Recuerda, cuando halla que parchear, cuantos menos bytes mejor.

 Links


Introducción Funcionamiento de RSA OllyDbg Calculando un serial válido Ejemplo operacional Keygen Links Introducción Empezamos con lo que espero que
Introducción Aquí tenemos un crackme hecho en Java, lo que como comprobareis a continuación no es muy buena idea ya
Warning: This challenge is still active and therefore should not be resolved using this information. Aviso: Este reto sigue en
Toda esta aventura comienza con un archivo llamado pretty_raw, sin extensión. Porque sí. Porque las extensiones son una invención heredada

Yoire PE Stage 3 Reversing Challenge (Benten) – Fuerza Bruta

Aviso: Este crackme forma parte de una serie de pruebas de Yoire.com que todavía está en activo. Lo ético si continuas leyendo este manual es que no utilices la respuesta para completar la prueba sin esfuerzo. 😉

Analizando

Abrimos el crackme con Ollydbg y vamos a las referenced strings.

Pinchamos sobre cualquiera.

 

Vemos un «Call» donde seguramente se generará un SUM en función del serial metido ya que después del Call vemos una comprobación contra «B79E763E» lo que nos da una pista de que vamos a tener que utilizar fuerza bruta para llegar a ese valor. Vamos a explorar el Call.

Lo que resalto con la flecha son una par de Calls que podemos NOPear ya que lo único que hacen es ralentizar la generación del SUM.
A continuación vamos a analizar el algoritmo de generación del SUM.
MOV EDI,5EED                   - EDI = 5EED
JMP SHORT 01_crack.004010D7
/MOV EAX,EDI                   <----Bucle
|SHL EAX,5                     - 5EED * 32 = BDDA0
|MOVZX EDX,BYTE PTR DS:[EBX]   - Coge el dígito
|XOR EAX,EDX                   - BDDA0 XOR digito
|MOV EDI,EAX
|XOR EDI,1D0B1EED              - XOR 1D0B1EED
|INC EBX
|..
|MOV ESI,EAX
CMP BYTE PTR DS:[EBX],0
JNZ SHORT 01_crack.004010B4   - Bucle ---->

Para un serial de tres dígitos la secuencia sería esta (valores en hexadecimal):

1º Digit —> BDDA0 XOR 1D0B1EED XOR 1ºDigit XOR 1D0B1EED = Temp
2º Digit —> Temp = Temp * 20 Xor 1D0B1EED XOR 2ºDigit
3º Digit —> Temp = Temp * 20 Xor 1D0B1EED XOR 3ºDigit

CMP Temp, B79E763E

Aplicando Fuerza Bruta

La creación del «BruteForcer» os la dejo a vosotros. Aquí teneis un fragmento hecho en VB.Net.

Dim temp As Long
Dim temp2 As String
Dim letter As Integer
Dim brute As String
brute = TextBox4.Text
temp = 0
temp = Asc(Mid(brute, 1, 1)) Xor 487268077 Xor 777632
temp2 = Hex(temp)
temp2 = Microsoft.VisualBasic.Right(temp2, 8)
temp = Convert.ToUInt64(temp2, 16)
For i = 2 To Len(brute)
letter = Asc(Mid(brute, i, 1))
temp = temp * 32
temp2 = Hex(temp)
temp2 = Microsoft.VisualBasic.Right(temp2, 8)
temp = Convert.ToUInt64(temp2, 16)
temp = temp Xor 487268077
temp2 = Hex(temp)
temp2 = Microsoft.VisualBasic.Right(temp2, 8)
temp = Convert.ToUInt64(temp2, 16)
temp = temp Xor letter
'
temp2 = Hex(temp)
Next

Links


Introducción Cripto 1 Cripto 2 Cripto 3 Cripto 4 Cripto 5 Cripto 6 Cripto 7 Cripto 8 Cripto 9 Cripto 10
http://youtu.be/b9-GdmIQINQ Lista de reproducción
Se nos entrega un ELF que decompilado presenta este aspecto: Para resolver el juego y obtener una licencia válida, nos
Rebuscando entre todo el caos que puede llegar a ser mi disco duro, he encontrado una serie de programas que

Solución a los retos criptográficos de Rogerfm.net

Introducción

Los retos de encriptación son muy variados como hemos comentado anteriormente. Aquí tenemos unos buenos ejemplos de ello.

Cripto 1

En este primer nivel nos encontramos con un método de encriptación muy antíguo.    Sólo diré como pista, que es de los más antiguos que se conocen.

ozhlofxrlmvhxzorulimrz

Lo primero que suelo hacer en este tipo de retos cuando son solamente letras, es comprobar las dos opciones más típicas, que son el cifrado César y Vigenere. En este caso necesitamos ahondar un poco más, aunque enseguida llegamos a la conclusión de que el cifrado usado es el afín. Un ataque por fuerza bruta nos devuelve la solución y los coeficientes utilizados.

Solución: A=25,B=25  – LASOLUCIONESCALIFORNIA

Fuente: http://www.dcode.fr/chiffre-affine


Cripto 2

En este segundo nivel recordaremos a un general romano muy conocido. Lo complicaremos un poco, sólo lo justo para que cueste algo más de cinco minutos encontrar la clave 🙂

oehoeahhjoexhkzqhfsvzhffhwrhotqk

Lo primero que nos viene a la cabeza es el cifrado César pero no va. Probando varios cifrados por sustitución al final damos con el correcto. De nuevo un ataque por fuerza bruta nos da frutos.

Solución: (3,4,5)/1  – LACLAVEDELASEGUNDAPRUEBAESMEKONG

Fuente: https://www.dcode.fr/chiffre-decalages


Cripto 3

Este nivel también va a ser sencillo. Estos caracteres, pertenecientes a un sistema bastante conocido de encriptado, esconden una palabra que, al introducirla (en minúsculas), nos permitirá superar el nivel.

Investigando un poco llegamos a la conclusión de que se trata del cifrado Francmasón o Pig Pen.

Solución: primates

Fuente: https://www.dcode.fr/chiffre-pig-pen-francs-macons


Cripto 4

Esta prueba es tan simple que la he dividido en dos partes que, aunque de apariencia similar, se resuelven de distinta manera. La clave es la unión de las dos palabras resultantes de descifrar las dos líneas de números y que, juntas, forman una tercera palabra.

0111001101110101011100000110010101110010
0001001110011000111110100100110010010001

La primera parte se puede convertir en bloque:

0111001101110101011100000110010101110010 = super

Fuente: https://www.rapidtables.com/convert/number/binary-to-ascii.html

Para la segunda debemos separar en grupos de 5 dígitos y listo:

00010   01110   01100   01111   10100   10011   00100   10001

 C             O          M           P            U          T           E           R

Fuente: www.lindau-nobel.org


Cripto 5

Para descubrir la palabra clave sólo se necesita una mínima capacidad de observación.

31 04 40 23 20 34 33 13 23 22

Se trata del cuadrado de Polibio.


Cripto 6

Aquí hay que hacer un poco de trabajo de investigación: Hay que descubrir la clave que empleó un escritor francés (Una pista: «Lagardère») en una de sus novelas, que es la empleada aquí para formar la palabra clave (en minúsculas) que, por cierto, es alemana.

RI3I2MIL2I2A3

POR RESOLVER


Cripto 7

Seguimos con cosas fáciles. Se trata de descifrar este texto escrito en inglés.

kgw qkoev ol 617 qthpreoz iwjpz sdkg kgw pdeyeplk rwqdjzwe ipezwq spbbdq sgo sgwz goqkdbdkdwq iwjpz spq rwkwecdzwr ko cpmw gdq uweqozpb yozkedihkdoz ko kgw spe wlloek

Una vez descifrado, nos será fácil descubrir la clave:

pzpyozrp

Se trata de  un cifrado de sustitución mono alfabético.

ABCDEFGHIJKLMNOPQRSTUVWXYZ
ZLMIRVHUBGTFJKOASDWQPYEXCN

THE STORY OF 617 SQUADRON BEGAN WITH THE AIRCRAFT DESIGNER BARNES WALLIS WHO WHEN HOSTILITIES BEGAN WAS DETERMINED TO MAJE HIS PERSONAL CONTRIBUTION TO THE WAR EFFORT

Una vez descifrado el alfabeto la solución queda:

pzpyozrp = anaconda

Cripto 8

A veces, las cosas no son lo que parecen. Donde aparecen unos números, en realidad hay otros números distintos.

273664524572348321143738
853442616537643005319627

POR RESOLVER


Cripto 9

Para resolver algunos problemas, hay que tener una buena base. Este es un buen ejemplo de ello:

ZW50ZXJwcmlzZQ0K

¿Os suena base 64?

Solución: enterprise

Fuente: https://www.base64decode.org/


Cripto 10

Esto es más complicado. Para descifrar este texto que contiene la clave para superar el nivel, se necesita otra clave. Para que no sea demasiado difícil, he utilizado una palabra muy sencilla de sólo cuatro letras 🙂

myiemyuvbaeewcxweghkflxw

Mediante fuerza bruta matamos dos pájaros de un tiro.

lapalabraclaveesdiogenes

Fuente: https://www.guballa.de/vigenere-solver


Enlaces

Afinador

Se nos entrega un ELF que decompilado presenta este aspecto:

/* 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_401020();
__int64 sub_401030(); // weak
__int64 sub_401040(); // weak
__int64 sub_401050(); // weak
__int64 sub_401060(); // weak
__int64 sub_401070(); // weak
// int puts(const char *s);
// int printf(const char *format, ...);
// __int64 __isoc99_scanf(const char *, ...); weak
// void __noreturn exit(int status);
void __fastcall __noreturn start(__int64 a1, __int64 a2, void (*a3)(void));
void dl_relocate_static_pie();
char *deregister_tm_clones();
__int64 register_tm_clones();
char *_do_global_dtors_aux();
__int64 frame_dummy();
int __fastcall main(int argc, const char **argv, const char **envp);
_BYTE *__fastcall encode(__int64 a1);
__int64 __fastcall validar(const char *a1);
int banner();
int comprar();
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);
// __int64 _gmon_start__(void); weak

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

_UNKNOWN _libc_csu_init;
const char a31mparaSeguirU[43] = "\x1B[31mPara seguir usando este producto deber"; // idb
const char a32myaPuedesSeg[61] = "\x1B[32mYa puedes seguir afinando tus instrumentos (y tus flags "; // idb
const char aDirigaseANuest[21] = "\nDirigase a nuestra p"; // idb
__int64 (__fastcall *_frame_dummy_init_array_entry)() = &frame_dummy; // weak
__int64 (__fastcall *_do_global_dtors_aux_fini_array_entry)() = &_do_global_dtors_aux; // weak
__int64 (*qword_404010)(void) = NULL; // weak
char _bss_start; // weak


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

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

//----- (0000000000401020) ----------------------------------------------------
__int64 sub_401020()
{
  return qword_404010();
}
// 404010: using guessed type __int64 (*qword_404010)(void);

//----- (0000000000401030) ----------------------------------------------------
__int64 sub_401030()
{
  return sub_401020();
}
// 401030: using guessed type __int64 sub_401030();

//----- (0000000000401040) ----------------------------------------------------
__int64 sub_401040()
{
  return sub_401020();
}
// 401040: using guessed type __int64 sub_401040();

//----- (0000000000401050) ----------------------------------------------------
__int64 sub_401050()
{
  return sub_401020();
}
// 401050: using guessed type __int64 sub_401050();

//----- (0000000000401060) ----------------------------------------------------
__int64 sub_401060()
{
  return sub_401020();
}
// 401060: using guessed type __int64 sub_401060();

//----- (0000000000401070) ----------------------------------------------------
__int64 sub_401070()
{
  return sub_401020();
}
// 401070: using guessed type __int64 sub_401070();

//----- (00000000004010D0) ----------------------------------------------------
// 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();
}
// 4010DA: positive sp value 8 has been found
// 4010E1: variable 'v3' is possibly undefined

//----- (0000000000401100) ----------------------------------------------------
void dl_relocate_static_pie()
{
  ;
}

//----- (0000000000401110) ----------------------------------------------------
char *deregister_tm_clones()
{
  return &_bss_start;
}
// 404050: using guessed type char _bss_start;

//----- (0000000000401140) ----------------------------------------------------
__int64 register_tm_clones()
{
  return 0LL;
}

//----- (0000000000401180) ----------------------------------------------------
char *_do_global_dtors_aux()
{
  char *result; // rax

  if ( !_bss_start )
  {
    result = deregister_tm_clones();
    _bss_start = 1;
  }
  return result;
}
// 404050: using guessed type char _bss_start;

//----- (00000000004011B0) ----------------------------------------------------
__int64 frame_dummy()
{
  return register_tm_clones();
}

//----- (00000000004011B6) ----------------------------------------------------
int __fastcall main(int argc, const char **argv, const char **envp)
{
  int v4; // [rsp+10h] [rbp-10h] BYREF
  int v5; // [rsp+14h] [rbp-Ch]
  unsigned __int64 v6; // [rsp+18h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  v5 = 0;
  puts("\n\x1B[31m    -----------Se le ha acabado el periodo de prueba gratuito-----------\n");
  puts(a31mparaSeguirU);
  do
  {
    banner();
    __isoc99_scanf("%d", &v4);
    if ( v4 == 3 )
      exit(0);
    if ( v4 > 3 )
      goto LABEL_10;
    if ( v4 == 1 )
    {
      comprar();
      continue;
    }
    if ( v4 == 2 )
      v5 = validar("%d");
    else
LABEL_10:
      puts("Opcion invalida, pruebe otra vez");
  }
  while ( !v5 );
  puts(a32myaPuedesSeg);
  return 0;
}
// 4010B0: using guessed type __int64 __isoc99_scanf(const char *, ...);

//----- (0000000000401291) ----------------------------------------------------
_BYTE *__fastcall encode(__int64 a1)
{
  _BYTE *result; // rax
  int i; // [rsp+14h] [rbp-4h]

  for ( i = 0; i <= 33; ++i )
  {
    if ( *(char *)(i + a1) <= 96 || *(char *)(i + a1) > 122 )
    {
      if ( *(char *)(i + a1) <= 64 || *(char *)(i + a1) > 90 )
      {
        result = (_BYTE *)*(unsigned __int8 *)(i + a1);
        *(_BYTE *)(i + a1) = (_BYTE)result;
      }
      else
      {
        result = (_BYTE *)(i + a1);
        *result = (5 * ((char)*result - 65) + 8) % 26 + 65;
      }
    }
    else
    {
      result = (_BYTE *)(i + a1);
      *result = (5 * ((char)*result - 97) + 8) % 26 + 97;
    }
  }
  return result;
}

//----- (00000000004013DB) ----------------------------------------------------
__int64 __fastcall validar(const char *a1)
{
  int i; // [rsp+Ch] [rbp-64h]
  char v3[48]; // [rsp+10h] [rbp-60h] BYREF
  __int64 v4[6]; // [rsp+40h] [rbp-30h] BYREF

  v4[5] = __readfsqword(0x28u);
  qmemcpy(v4, "RisgAv{rIU_ihHwvIxA_sAppCsziq3vzC}", 34);
  printf("\nIntroduce tu licencia: ");
  __isoc99_scanf("%s", v3);
  encode((__int64)v3);
  for ( i = 0; i <= 33; ++i )
  {
    if ( v3[i] != *((_BYTE *)v4 + i) )
    {
      puts("\n\x1B[31mTu licencia es incorrecta\x1B[37m\n");
      return 0LL;
    }
  }
  puts("\n\x1B[32mEres un crack, lo conseguiste\x1B[37m");
  return 1LL;
}
// 4010B0: using guessed type __int64 __isoc99_scanf(const char *, ...);
// 4013DB: using guessed type char var_60[48];

//----- (00000000004014CE) ----------------------------------------------------
int banner()
{
  puts("                     ___________OPCIONES___________");
  puts("                    | 1: Comprar licencia premium  |");
  puts("                    | 2: Validar clave de licencia |");
  puts("                    | 3: Salir                     |");
  puts("                     ------------------------------");
  return printf("> ");
}

//----- (0000000000401526) ----------------------------------------------------
int comprar()
{
  return puts(aDirigaseANuest);
}

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

  init_proc();
  v3 = &_do_global_dtors_aux_fini_array_entry - &_frame_dummy_init_array_entry;
  if ( v3 )
  {
    for ( i = 0LL; i != v3; ++i )
      (*(&_frame_dummy_init_array_entry + i))();
  }
}
// 403E10: using guessed type __int64 (__fastcall *_frame_dummy_init_array_entry)();
// 403E18: using guessed type __int64 (__fastcall *_do_global_dtors_aux_fini_array_entry)();

//----- (00000000004015B0) ----------------------------------------------------
void _libc_csu_fini(void)
{
  ;
}

//----- (00000000004015B8) ----------------------------------------------------
void term_proc()
{
  ;
}

// nfuncs=33 queued=21 decompiled=21 lumina nreq=0 worse=0 better=0
// ALL OK, 21 function(s) have been successfully decompiled

Para resolver el juego y obtener una licencia válida, nos fijamos en el proceso de validación que se encuentra en la función validar (líneas 237 a 258). Esta función compara una entrada de licencia codificada con una licencia codificada almacenada en el programa.

La licencia almacenada es "RisgAv{rIU_ihHwvIxA_sAppCsziq3vzC}", y se utiliza la función encode (líneas 207 a 234) para codificar la entrada del usuario antes de compararla. La función encode aplica un cifrado simple a la entrada, alterando los caracteres alfabéticos según una fórmula específica.

La función de cifrado encode realiza lo siguiente:

  • Si el carácter es una letra minúscula (a-z), se convierte según la fórmula (5 * (char - 97) + 8) % 26 + 97.
  • Si el carácter es una letra mayúscula (A-Z), se convierte según la fórmula (5 * (char - 65) + 8) % 26 + 65.

Nos construimos una función en Python para decodificar la Flag y reto superado.

def decode(encoded_char):
    if 'a' <= encoded_char <= 'z':
        original_char = chr(((ord(encoded_char) - 97 - 8) * 21) % 26 + 97)
    elif 'A' <= encoded_char <= 'Z':
        original_char = chr(((ord(encoded_char) - 65 - 8) * 21) % 26 + 65)
    else:
        original_char = encoded_char
    return original_char

encoded_license = "RisgAv{rIU_ihHwvIxA_sAppCsziq3vzC}"
decoded_license = "".join(decode(char) for char in encoded_license)

print("Licencia descifrada:", decoded_license)

Algoritmo de HEdit 2.1.11

Rebuscando entre todo el caos que puede llegar a ser mi disco duro, he encontrado una serie de programas que utilizaba antiguamente cuando empezó a interesarme el Cracking. Ya sabéis que no soy partidario de crackear programas comerciales pero hoy voy a hacer una excepción ya que la versión del programa es muy vieja (1997) e incluso podría considerarse abandonware.

Este ejercicio es ideal para los que están empezando ya que es fácil localizar donde está el algoritmo y éste es sumamente sencillo.

Table of Contents

Algoritmo

Address   Hex dump          Command                                      Comments
00402213    E8 78170000     CALL HEdit.00403990
........
004039C0    8BC1            MOV EAX,ECX
004039C2    99              CDQ
004039C3    33C2            XOR EAX,EDX
004039C5    2BC2            SUB EAX,EDX
004039C7    83E0 03         AND EAX,00000003
004039CA    33C2            XOR EAX,EDX
004039CC    2BC2            SUB EAX,EDX
004039CE    8A540C 04       MOV DL,BYTE PTR SS:[ECX+ESP+4]  ;Coge el dígito i*3
004039D2    8A5C04 04       MOV BL,BYTE PTR SS:[EAX+ESP+4]  ;Coge el dígito i
004039D6    8D4404 04       LEA EAX,[EAX+ESP+4]             ;Guarda en memoria 12EE90
004039DA    32DA            XOR BL,DL
004039DC    41              INC ECX                         ; i +=1
004039DD    81F9 00010000   CMP ECX,100                     ;El bucle se repite 256 veces (0x100)
004039E3    8818            MOV BYTE PTR DS:[EAX],BL
004039E5  ^ 7C D9           JL SHORT HEdit.004039C0
004039E7    8B4424 04       MOV EAX,DWORD PTR SS:[ESP+4]
004039EB    85C0            TEST EAX,EAX                    ;Comprueba que el serial no sea 0
004039ED    7D 02           JGE SHORT HEdit.004039F1        ;Si es 0 se acabó
004039EF    F7D8            NEG EAX
004039F1    3B8424 0C010000 CMP EAX,DWORD PTR SS:[ESP+10C]  ;Comprobación de serial válido
004039F8    75 13           JNE SHORT HEdit.00403A0D        ;Si no es igual bad boy
004039FA    85C0            TEST EAX,EAX                    ;Comprueba que el serial no sea 0
004039FC    74 0F           JE SHORT HEdit.00403A0D         ;Si es 0 se acabó
004039FE    B8 01000000     MOV EAX,1
00403A03    5B              POP EBX
00403A04    81C4 00010000   ADD ESP,100
00403A0A    C2 0800         RETN 8

En resumen hace esto:

- Nombre introducido: deurus
- Convierte el nombre a mayúsculas

D  E  U  R  U  S
44 45 55 52 55 53 (En Hexadecimal)

1) 55 xor 44 = 11
2) 53 xor 45 = 16
3) 00 xor 55 = 55
4) 00 xor 52 = 52
   --------------- solo vale hasta aquí EAX(32 bits)
5) 00 xor 55 = 55
6) 00 xor 53 = 53
7) 00 xor 00 = 00
8) ...
            HEX         DEC
Serial = 52551611 = 1381307921

Como veis, realiza un bucle 256 veces pero como al final utiliza el registro EAX para hacer la comparación, solamente nos sirven las cuatro primeras operaciones. De hecho, no comprueba ni la longitud del nombre por lo que si introducimos un solo dígito como nombre, el serial será el valor ascii de ese dígito en decimal. La única comprobación que realiza es que el serial no sea 0.

Keygen

Os dejo una prueba de concepto en Javascript.

var nombre = "deurus";
nombre = nombre.toUpperCase();
var serial = "";

serial = serial + nombre.charCodeAt(3).toString(16) + nombre.charCodeAt(2).toString(16);
serial = serial + (nombre.charCodeAt(5) ^ nombre.charCodeAt(1)).toString(16);
serial = serial + (nombre.charCodeAt(2) ^ nombre.charCodeAt(0)).toString(16);
serial = "Nº Serie: " + parseInt(serial,16);

document.write(serial);

Enlaces

Yuri Software