Keygen para el Crackme 1 de VisionZ

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

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

- Introducción
- Cripto 1
- Cripto 2
- Cripto 3
- Cripto 4
- Cripto 5
- Cripto 6
- Cripto 7
- Cripto 8
- Cripto 9
- Cripto 10
- Enlaces
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.
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.
Al pulsar Re-Check
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
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
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.
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):
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
Solución a los retos criptográficos de Rogerfm.net

- Introducción
- Cripto 1
- Cripto 2
- Cripto 3
- Cripto 4
- Cripto 5
- Cripto 6
- Cripto 7
- Cripto 8
- Cripto 9
- Cripto 10
- Enlaces
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
VideoTutorial – KeyGen para el Crackme#1 de WinFan

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.
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);























