Karpoff’s CrackME1 Keygen

Introducción
El otro día navegando por la red fuí a dar a un mirror de la gran web «Karpoff Spanish Tutor«. Para los que no la conozcais, debeis saber que fué una referencia para el Cracking en la escena nacional. Contenía manuales, cursos, utilidades y todo lo que te pudieras imaginar y/o necesitar para iniciarte en el mundillo del Cracking. Por aquel entonces yo era un cigoto en esto de la Ingeniería Inversa pero la web de Karpoff sentó mis bases y contribuyó a mi afán por saber y compartir. El lector debería saber que estamos hablando de finales de los 90, por lo que este crackme y sucesivos de la web de Karpoff ahora pueden parecer más fáciles pero hay que tener en cuenta que ahora tenemos mejores herramientas.
El objetivo es sacar un serial valido o hacer un generador de llaves, esta hecho para newbies y no tiene ninguna otra proteccion.
El crackme está hecho en Delphi y no tiene ningún tipo de protección antidebug ni nada por el estilo.
El algoritmo
Abrimos Delphi Decompiler y buscamos en los eventos el botón de registro, en este caso se llama «focusClick» y vemos que su RVA apunta a la dirección «442AEC«, lo apuntamos y abrimos el crackme con Ollydbg.
En Olly pulsamos Ctrl+G e introducimos el offset anterior. Un poco más abajo vemos un Call interesante, entramos en el.
Dentro del Call vemos a simple vista dos funciones muy interesantes como son «GetVolumeInformationA» y «GetUserNameA«.
Traceamos el código y vemos que obtiene el número de serie del disco C y el usuario de windows y finalmente los concatena. Se puede ver a simple vista en el Stack o Pila.
No necesitamos saber nada más, probamos el número de serie cazado y funciona. Os adjunto el keygen hecho en C++.
Links
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.
| Temporada | Episodio | Título | Comentario |
|---|---|---|---|
| 1 | 17 | E.B.E. | Primera aparición de los pistoleros. |
| 2 | 3 | Blood | Manipulación de dispositivos y mensajes ocultos. También control mental a través de la tecnología. |
| 2 | 25 | Anasazi | Un hacker roba archivos clasificados. Se tratan temas como el cifrado y filtración de datos del gobierno. |
| 3 | 15 | Apocrypha | Acceso a bases de datos secretas y descifrado de archivos comprometidos. |
| 3 | 23 | Wetwired | Manipulación de señales televisivas. |
| 4 | 14 | Memento Mori | Infiltración digital en sistemas médicos y vigilancia biotecnológica. |
| 5 | 1 | Redux | Robo y manipulación de pruebas digitales. |
| 5 | 3 | Unusual Suspects | Orígenes de los pistoleros: intrusión, cifrado y espíritu hacker de los noventa. |
| 5 | 11 | Kill Switch | IA autónoma y malware inteligente. |
| 6 | 20 | Three of a Kind | Hacking social, suplantación y síntesis de voz para infiltración corporativa. |
| 7 | 13 | First Person Shooter | Hackeo de entornos virtuales y brechas de seguridad en sistemas de realidad aumentada. |
| 9 | 15 | Jump the Shark | Su sacrificio final: bloqueo de una amenaza biológica, ética hacker y altruismo extremo. |
| 11 | 2 | This | Langly 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.
Solución para el KeyGenMe#3 de T.0.R.N.A.D.0.

Intro
Hoy tenemos aquí un crackme del 2009 originario de crackmes.de. El Crackme está hecho en VB6, sin empacar y consta de 4 tareas a superar. Un anti-debugger, un parcheo, una sorpresa y finalmente un algoritmo sencillo.
Tarea#1 – Anti-Debugger
Nuestro primer incordio es el anti-debbuger. Este lo podemos afrontar de diferentes maneras, con un plugin desde Olly o de forma permanente parcheando. Si elegimos parchear debemos hacerlo en el offset 408328, cambiando el salto je por jmp.
00408328 /0F84 69030000 je T0RNAD0'.00408697
Tarea#2 – Parche
Si iniciamos el crackme nos encontramos con la siguiente nag que nos impide el arranque.
Las referencias de texto parecen encriptadas así que, ponemos un breakpoint a MSVBVM60.rtcMsgBox y vemos que la llamada se hace desde el offset 406897. Un poco más arriba encontramos un salto condicional muy interesante, concretamente en el offset 40677B. Lo cambiamos por un jmp y arrancamos el programa.
Tarea#3 – Encontrando el camino
A continuación arranca el crackme y vemos lo siguiente.
La sorpresa es que el formulario no se mueve y no hay rastro de las cajas de texto del keygenme. Por suerte para nosotros este crackme está hecho en vb6 y como tal podemos abrirlo con VB Reformer para ver que se nos ofrece.
Abrimos VB Reformer y cambiamos la propiedad «Moveable» del formulario a true.
Ahora ya podemos mover el formulario y por suerte para nosotros, si lo movemos hacia la esquina superior izquierda aparecen las cajas de texto por arte de magia.
Tarea#4 – El keygen
Como hemos dicho antes, las referencias de texto son inútiles, de modo que ponemos un breakpoint a MSVBVM60.__vbaStrCmp y enseguida obtenemos nuestro primer serial válido. También nos percatamos de que hasta que no metemos en el nombre 8 dígitos, no nos muestra un mensaje de error. De este mismo modo obtenemos que el nombre más grande puede tener 30 dígitos.
Username: deurusab (lenght 8)
0012F3F0 0040533A RETURN to T0RNAD0'.0040533A from MSVBVM60.__vbaStrCmp
0012F3F4 0015C954 UNICODE "L-8-deurus-0199F9CA"
Username: abcdefghijklmnopqrstuvwxyz1234 (lenght 30)
0012F3F0 0040533A RETURN to T0RNAD0'.0040533A from MSVBVM60.__vbaStrCmp
0012F3F4 0015F40C UNICODE "L-30-lmnopq-DD19F9CA"
Finalmente llegamos a la rutina de comprobación del serial. Usaremos como nombre: abcdefghijklmnopqrstuvwxyz1234.
00404E82 . 52 push edx 00404E83 . 56 push esi 00404E84 . C746 34 0DF0D1BA mov dword ptr ds:[esi+34],BAD1F00D |Variables cachondas 00404E8B . C746 38 01ADDE10 mov dword ptr ds:[esi+38],10DEAD01 |Variables cachondas 00404E92 . C746 3C EFBE1010 mov dword ptr ds:[esi+3C],1010BEEF |Variables cachondas 00404E99 . C746 40 D0BA0110 mov dword ptr ds:[esi+40],1001BAD0 |Variables cachondas 00404EA0 . FF91 2C070000 call ds:[ecx+72C] 00404EA6 . 3BC7 cmp eax,edi 00404EA8 . DBE2 fclex 00404EAA . 7D 12 jge short T0RNAD0'.00404EBE 00404EAC . 68 2C070000 push 72C 00404EB1 . 68 14404000 push T0RNAD0'.00404014 00404EB6 . 56 push esi 00404EB7 . 50 push eax 00404EB8 . FF15 40104000 call ds:[<&MSVBVM60.__vbaHresultCheckObj>] ; MSVBVM60.__vbaHresultCheckObj 00404EBE > 8B45 B4 mov eax,ss:[ebp-4C] 00404EC1 . 8D55 E0 lea edx,ss:[ebp-20] 00404EC4 . 52 push edx 00404EC5 . 50 push eax 00404EC6 . 8B08 mov ecx,ds:[eax] 00404EC8 . 8985 48FFFFFF mov ss:[ebp-B8],eax 00404ECE . FF91 A0000000 call ds:[ecx+A0] 00404ED4 . 3BC7 cmp eax,edi 00404ED6 . DBE2 fclex 00404ED8 . 7D 18 jge short T0RNAD0'.00404EF2 00404EDA . 8B8D 48FFFFFF mov ecx,ss:[ebp-B8] 00404EE0 . 68 A0000000 push 0A0 00404EE5 . 68 7C414000 push T0RNAD0'.0040417C 00404EEA . 51 push ecx 00404EEB . 50 push eax 00404EEC . FF15 40104000 call ds:[<&MSVBVM60.__vbaHresultCheckObj>] ; MSVBVM60.__vbaHresultCheckObj 00404EF2 > 8B45 E0 mov eax,ss:[ebp-20] |Mueve el nombre a eax 00404EF5 . 8D55 A0 lea edx,ss:[ebp-60] 00404EF8 . 8945 A8 mov ss:[ebp-58],eax 00404EFB . 6A 01 push 1 00404EFD . 8D45 90 lea eax,ss:[ebp-70] 00404F00 . 52 push edx 00404F01 . 50 push eax 00404F02 . 897D E0 mov ss:[ebp-20],edi 00404F05 . C745 A0 08000000 mov dword ptr ss:[ebp-60],8 00404F0C . FF15 40114000 call ds:[<&MSVBVM60.#619>] ; MSVBVM60.rtcRightCharVar 00404F12 . 8B3D D0104000 mov edi,ds:[<&MSVBVM60.__vbaStrVarVal>] ; MSVBVM60.__vbaStrVarVal 00404F18 . 8D4D 90 lea ecx,ss:[ebp-70] 00404F1B . 8D55 DC lea edx,ss:[ebp-24] 00404F1E . 51 push ecx 00404F1F . 52 push edx 00404F20 . FFD7 call edi ; <&MSVBVM60.__vbaStrVarVal> 00404F22 . 50 push eax 00404F23 . FF15 30104000 call ds:[<&MSVBVM60.#516>] ; MSVBVM60.rtcAnsiValueBstr |Toma el último dígito en ascii (4 asc = 34) 00404F29 . 66:6BC0 7B imul ax,ax,7B |34 * 7B = 18FC 00404F2D . 8B4E 34 mov ecx,ds:[esi+34] |Mueve BAD1F00D a ecx 00404F30 . 0F80 05070000 jo T0RNAD0'.0040563B 00404F36 . 0FBFC0 movsx eax,ax 00404F39 . 33C8 xor ecx,eax |18FC xor BAD1F00D = BAD1E8F1 00404F3B . 894E 34 mov ds:[esi+34],ecx 00404F3E . 8D4D DC lea ecx,ss:[ebp-24] 00404F41 . FF15 5C114000 call ds:[<&MSVBVM60.__vbaFreeStr>] ; MSVBVM60.__vbaFreeStr 00404F47 . 8D4D B4 lea ecx,ss:[ebp-4C] 00404F4A . FF15 60114000 call ds:[<&MSVBVM60.__vbaFreeObj>] ; MSVBVM60.__vbaFreeObj 00404F50 . 8D4D 90 lea ecx,ss:[ebp-70] 00404F53 . 8D55 A0 lea edx,ss:[ebp-60] 00404F56 . 51 push ecx 00404F57 . 52 push edx 00404F58 . 6A 02 push 2 00404F5A . FF15 20104000 call ds:[<&MSVBVM60.__vbaFreeVarList>] ; MSVBVM60.__vbaFreeVarList 00404F60 . 8B06 mov eax,ds:[esi] 00404F62 . 83C4 0C add esp,0C 00404F65 . 8D4D B4 lea ecx,ss:[ebp-4C] 00404F68 . 51 push ecx 00404F69 . 56 push esi 00404F6A . FF90 2C070000 call ds:[eax+72C] 00404F70 . 85C0 test eax,eax 00404F72 . DBE2 fclex 00404F74 . 7D 12 jge short T0RNAD0'.00404F88 00404F76 . 68 2C070000 push 72C 00404F7B . 68 14404000 push T0RNAD0'.00404014 00404F80 . 56 push esi 00404F81 . 50 push eax 00404F82 . FF15 40104000 call ds:[<&MSVBVM60.__vbaHresultCheckObj>] ; MSVBVM60.__vbaHresultCheckObj 00404F88 > 8B45 B4 mov eax,ss:[ebp-4C] 00404F8B . 8D4D E0 lea ecx,ss:[ebp-20] 00404F8E . 51 push ecx 00404F8F . 50 push eax 00404F90 . 8B10 mov edx,ds:[eax] 00404F92 . 8985 48FFFFFF mov ss:[ebp-B8],eax 00404F98 . FF92 A0000000 call ds:[edx+A0] 00404F9E . 85C0 test eax,eax 00404FA0 . DBE2 fclex 00404FA2 . 7D 18 jge short T0RNAD0'.00404FBC 00404FA4 . 8B95 48FFFFFF mov edx,ss:[ebp-B8] 00404FAA . 68 A0000000 push 0A0 00404FAF . 68 7C414000 push T0RNAD0'.0040417C 00404FB4 . 52 push edx 00404FB5 . 50 push eax 00404FB6 . FF15 40104000 call ds:[<&MSVBVM60.__vbaHresultCheckObj>] ; MSVBVM60.__vbaHresultCheckObj 00404FBC > 8B45 E0 mov eax,ss:[ebp-20] 00404FBF . 6A 01 push 1 00404FC1 . 8945 A8 mov ss:[ebp-58],eax 00404FC4 . 8D45 A0 lea eax,ss:[ebp-60] 00404FC7 . 8D4D 90 lea ecx,ss:[ebp-70] 00404FCA . 50 push eax 00404FCB . 51 push ecx 00404FCC . C745 E0 00000000 mov dword ptr ss:[ebp-20],0 00404FD3 . C745 A0 08000000 mov dword ptr ss:[ebp-60],8 00404FDA . FF15 2C114000 call ds:[<&MSVBVM60.#617>] ; MSVBVM60.rtcLeftCharVar 00404FE0 . 8D55 90 lea edx,ss:[ebp-70] 00404FE3 . 8D45 DC lea eax,ss:[ebp-24] 00404FE6 . 52 push edx 00404FE7 . 50 push eax 00404FE8 . FFD7 call edi 00404FEA . 50 push eax 00404FEB . FF15 30104000 call ds:[<&MSVBVM60.#516>] ; MSVBVM60.rtcAnsiValueBstr |Toma el primer dígito en ascii (a asc = 61) 00404FF1 . 66:6BC0 7B imul ax,ax,7B |61 * 7B = 2E9B 00404FF5 . 8B56 3C mov edx,ds:[esi+3C] |Mueve 1010BEEF a edx 00404FF8 . 0F80 3D060000 jo T0RNAD0'.0040563B 00404FFE . 0FBFC8 movsx ecx,ax 00405001 . 33D1 xor edx,ecx | 2E9B xor 1010BEEF = 10109074 00405003 . 8D4D DC lea ecx,ss:[ebp-24] 00405006 . 8956 3C mov ds:[esi+3C],edx 00405009 . FF15 5C114000 call ds:[<&MSVBVM60.__vbaFreeStr>] ; MSVBVM60.__vbaFreeStr 0040500F . 8D4D B4 lea ecx,ss:[ebp-4C] 00405012 . FF15 60114000 call ds:[<&MSVBVM60.__vbaFreeObj>] ; MSVBVM60.__vbaFreeObj 00405018 . 8D55 90 lea edx,ss:[ebp-70] 0040501B . 8D45 A0 lea eax,ss:[ebp-60] 0040501E . 52 push edx 0040501F . 50 push eax 00405020 . 6A 02 push 2 00405022 . FF15 20104000 call ds:[<&MSVBVM60.__vbaFreeVarList>] ; MSVBVM60.__vbaFreeVarList 00405028 . 66:8BCB mov cx,bx |Mueve a CX el tamaño del nombre 0040502B . 83C4 0C add esp,0C 0040502E . 66:69C9 4101 imul cx,cx,141 |Tamaño nombre(1E) * 141 = 259E 00405033 . 8B46 3C mov eax,ds:[esi+3C] 00405036 . 0F80 FF050000 jo T0RNAD0'.0040563B 0040503C . 0FBFD1 movsx edx,cx 0040503F . 8B4E 38 mov ecx,ds:[esi+38] |Mueve a ECX 10DEAD01 00405042 . 33D0 xor edx,eax |10109074 xor 259E = 1010B5BA 00405044 . 33CA xor ecx,edx |1010B5BA xor 10DEAD01 = 00CE18EB 00405046 . 66:8BD3 mov dx,bx 00405049 . 66:69D2 4101 imul dx,dx,141 |Tamaño nombre(1E) * 141 = 259E 0040504E . 0F80 E7050000 jo T0RNAD0'.0040563B 00405054 . 894E 38 mov ds:[esi+38],ecx 00405057 . 81F1 01010101 xor ecx,1010101 |00CE18EB xor 1010101 = 01CF19EA (Temp1) 0040505D . 0FBFD2 movsx edx,dx 00405060 . 3356 34 xor edx,ds:[esi+34] |BAD1E8F1 xor 259E = BAD1CD6F 00405063 . 894E 38 mov ds:[esi+38],ecx 00405066 . 35 10101010 xor eax,10101010 |10109074 xor 10101010 = 8064 0040506B . 8D4D B4 lea ecx,ss:[ebp-4C] 0040506E . 3156 40 xor ds:[esi+40],edx |BAD1CD6F xor 1001BAD0 = AAD077BF (Temp2) 00405071 . 8946 3C mov ds:[esi+3C],eax 00405074 . 8B06 mov eax,ds:[esi] 00405076 . 51 push ecx 00405077 . 56 push esi 00405078 . FF90 2C070000 call ds:[eax+72C] 0040507E . 85C0 test eax,eax 00405080 . DBE2 fclex 00405082 . 7D 12 jge short T0RNAD0'.00405096 00405084 . 68 2C070000 push 72C 00405089 . 68 14404000 push T0RNAD0'.00404014 0040508E . 56 push esi 0040508F . 50 push eax 00405090 . FF15 40104000 call ds:[<&MSVBVM60.__vbaHresultCheckObj>] ; MSVBVM60.__vbaHresultCheckObj 00405096 > 8B45 B4 mov eax,ss:[ebp-4C] 00405099 . 8D4D DC lea ecx,ss:[ebp-24] 0040509C . 51 push ecx 0040509D . 50 push eax 0040509E . 8B10 mov edx,ds:[eax] 004050A0 . 8985 48FFFFFF mov ss:[ebp-B8],eax 004050A6 . FF92 A0000000 call ds:[edx+A0] 004050AC . 85C0 test eax,eax 004050AE . DBE2 fclex 004050B0 . 7D 18 jge short T0RNAD0'.004050CA 004050B2 . 8B95 48FFFFFF mov edx,ss:[ebp-B8] 004050B8 . 68 A0000000 push 0A0 004050BD . 68 7C414000 push T0RNAD0'.0040417C 004050C2 . 52 push edx 004050C3 . 50 push eax 004050C4 . FF15 40104000 call ds:[<&MSVBVM60.__vbaHresultCheckObj>] ; MSVBVM60.__vbaHresultCheckObj 004050CA > 8B06 mov eax,ds:[esi] 004050CC . 8D4D B0 lea ecx,ss:[ebp-50] 004050CF . 51 push ecx 004050D0 . 56 push esi 004050D1 . FF90 2C070000 call ds:[eax+72C] 004050D7 . 85C0 test eax,eax 004050D9 . DBE2 fclex 004050DB . 7D 12 jge short T0RNAD0'.004050EF 004050DD . 68 2C070000 push 72C 004050E2 . 68 14404000 push T0RNAD0'.00404014 004050E7 . 56 push esi 004050E8 . 50 push eax 004050E9 . FF15 40104000 call ds:[<&MSVBVM60.__vbaHresultCheckObj>] ; MSVBVM60.__vbaHresultCheckObj 004050EF > 8B45 B0 mov eax,ss:[ebp-50] 004050F2 . 8D4D D0 lea ecx,ss:[ebp-30] 004050F5 . 51 push ecx 004050F6 . 50 push eax 004050F7 . 8B10 mov edx,ds:[eax] 004050F9 . 8985 3CFFFFFF mov ss:[ebp-C4],eax 004050FF . FF92 A0000000 call ds:[edx+A0] 00405105 . 85C0 test eax,eax 00405107 . DBE2 fclex 00405109 . 7D 18 jge short T0RNAD0'.00405123 0040510B . 8B95 3CFFFFFF mov edx,ss:[ebp-C4] 00405111 . 68 A0000000 push 0A0 00405116 . 68 7C414000 push T0RNAD0'.0040417C 0040511B . 52 push edx 0040511C . 50 push eax 0040511D . FF15 40104000 call ds:[<&MSVBVM60.__vbaHresultCheckObj>] ; MSVBVM60.__vbaHresultCheckObj 00405123 > 8B45 D0 mov eax,ss:[ebp-30] 00405126 . 6A 01 push 1 00405128 . 8945 98 mov ss:[ebp-68],eax 0040512B . 8D45 90 lea eax,ss:[ebp-70] 0040512E . 8D4D 80 lea ecx,ss:[ebp-80] 00405131 . 50 push eax 00405132 . 51 push ecx 00405133 . C745 A8 06000000 mov dword ptr ss:[ebp-58],6 0040513A . C745 A0 02000000 mov dword ptr ss:[ebp-60],2 00405141 . C745 D0 00000000 mov dword ptr ss:[ebp-30],0 00405148 . C745 90 08000000 mov dword ptr ss:[ebp-70],8 0040514F . FF15 40114000 call ds:[<&MSVBVM60.#619>] ; MSVBVM60.rtcRightCharVar 00405155 . 8D55 80 lea edx,ss:[ebp-80] 00405158 . 8D45 CC lea eax,ss:[ebp-34] 0040515B . 52 push edx 0040515C . 50 push eax 0040515D . FFD7 call edi 0040515F . 50 push eax 00405160 . FF15 30104000 call ds:[<&MSVBVM60.#516>] ; MSVBVM60.rtcAnsiValueBstr 00405166 . 8B56 40 mov edx,ds:[esi+40] |Mueve a EDX AAD077BF (Temp2) 00405169 . 68 90414000 push T0RNAD0'.00404190 ; UNICODE "L-" |Comienza el serial 0040516E . 0FBFC8 movsx ecx,ax |Mueve a ECX último dígito en ascii (34) 00405171 . 8B46 38 mov eax,ds:[esi+38] |Mueve a EAX 01CF19EA (Temp1) 00405174 . 53 push ebx 00405175 . 03D0 add edx,eax |AAD077BF + 01CF19EA = AC9F91A9 00405177 . C785 70FFFFFF 0300000>mov dword ptr ss:[ebp-90],3 00405181 . 0F80 B4040000 jo T0RNAD0'.0040563B 00405187 . 03CA add ecx,edx |AC9F91A9 + 34 = AC9F91DD (Nuestro serial) 00405189 . 0F80 AC040000 jo T0RNAD0'.0040563B 0040518F . 898D 78FFFFFF mov ss:[ebp-88],ecx 00405195 . FF15 04104000 call ds:[<&MSVBVM60.__vbaStrI2>] ; MSVBVM60.__vbaStrI2 0040519B . 8B3D 38114000 mov edi,ds:[<&MSVBVM60.__vbaStrMove>] ; MSVBVM60.__vbaStrMove 004051A1 . 8BD0 mov edx,eax 004051A3 . 8D4D E0 lea ecx,ss:[ebp-20] 004051A6 . FFD7 call edi ; <&MSVBVM60.__vbaStrMove> 004051A8 . 50 push eax |EAX = tamaño del nombre 004051A9 . FF15 38104000 call ds:[<&MSVBVM60.__vbaStrCat>] ; MSVBVM60.__vbaStrCat |Concatena con "L-" 004051AF . 8BD0 mov edx,eax 004051B1 . 8D4D BC lea ecx,ss:[ebp-44] 004051B4 . FFD7 call edi 004051B6 . 66:83EB 06 sub bx,6 |Tamaño nombre - 6 = 18 004051BA . 50 push eax 004051BB . 0F80 7A040000 jo T0RNAD0'.0040563B 004051C1 . 0FBFCB movsx ecx,bx 004051C4 . 898D 08FFFFFF mov ss:[ebp-F8],ecx 004051CA . 8D45 A0 lea eax,ss:[ebp-60] 004051CD . DB85 08FFFFFF fild dword ptr ss:[ebp-F8] 004051D3 . 68 9C414000 push T0RNAD0'.0040419C 004051D8 . 50 push eax 004051D9 . DD9D 00FFFFFF fstp qword ptr ss:[ebp-100] 004051DF . DD85 00FFFFFF fld qword ptr ss:[ebp-100] 004051E5 . 833D 00A04000 00 cmp dword ptr ds:[40A000],0 004051EC . 75 08 jnz short T0RNAD0'.004051F6 004051EE . DC35 78114000 fdiv qword ptr ds:[401178] |18 / 2 = C (C es la posición para cojer dígitos del nombre, coje 6) 004051F4 . EB 11 jmp short T0RNAD0'.00405207 004051F6 > FF35 7C114000 push dword ptr ds:[40117C] 004051FC . FF35 78114000 push dword ptr ds:[401178] 00405202 . E8 3DC0FFFF call <jmp.&MSVBVM60._adj_fdiv_m64> 00405207 > DFE0 fstsw ax 00405209 . A8 0D test al,0D 0040520B . 0F85 25040000 jnz T0RNAD0'.00405636 00405211 . FF15 44114000 call ds:[<&MSVBVM60.__vbaR8IntI4>] ; MSVBVM60.__vbaR8IntI4 00405217 . 8B55 DC mov edx,ss:[ebp-24] |EDX = nombre 0040521A . 50 push eax |Eax = C 0040521B . 52 push edx 0040521C . FF15 6C104000 call ds:[<&MSVBVM60.#631>] ; MSVBVM60.rtcMidCharBstr |Mid(nombre,C,6) = "lmnopq" 00405222 . 8BD0 mov edx,eax 00405224 . 8D4D D8 lea ecx,ss:[ebp-28] 00405227 . FFD7 call edi 00405229 . 8B1D 38104000 mov ebx,ds:[<&MSVBVM60.__vbaStrCat>] ; MSVBVM60.__vbaStrCat 0040522F . 50 push eax 00405230 . FFD3 call ebx ; <&MSVBVM60.__vbaStrCat> |Concatena "-lmnopq" 00405232 . 8BD0 mov edx,eax 00405234 . 8D4D D4 lea ecx,ss:[ebp-2C] 00405237 . FFD7 call edi 00405239 . 50 push eax 0040523A . 68 9C414000 push T0RNAD0'.0040419C 0040523F . FFD3 call ebx |Concatena "-lmnopq-" 00405241 . 8BD0 mov edx,eax 00405243 . 8D4D C4 lea ecx,ss:[ebp-3C] 00405246 . FFD7 call edi 00405248 . 50 push eax 00405249 . 8D85 70FFFFFF lea eax,ss:[ebp-90] 0040524F . 50 push eax 00405250 . FF15 F0104000 call ds:[<&MSVBVM60.#572>] ; MSVBVM60.rtcHexBstrFromVar |serial "AC9F91DD" 00405256 . 8BD0 mov edx,eax 00405258 . 8D4D C8 lea ecx,ss:[ebp-38] 0040525B . FFD7 call edi 0040525D . 50 push eax 0040525E . FF15 B4104000 call ds:[<&MSVBVM60.#713>] ; MSVBVM60.rtcStrReverse |Invierte el serial "DD19F9CA" 00405264 . 8BD0 mov edx,eax 00405266 . 8D4D C0 lea ecx,ss:[ebp-40] 00405269 . FFD7 call edi 0040526B . 50 push eax 0040526C . FFD3 call ebx |Concatena "-lmnopq-DD19F9CA" 0040526E . 8BD0 mov edx,eax 00405270 . 8D4D B8 lea ecx,ss:[ebp-48] 00405273 . FFD7 call edi 00405275 . 50 push eax 00405276 . FFD3 call ebx |Concatena "L-30-lmnopq-DD19F9CA" ... 00405334 . FF15 80104000 call ds:[<&MSVBVM60.__vbaStrCmp>] ; MSVBVM60.__vbaStrCmp |Comparación final
Ejemplos:
Nombre: abcdefghijklmnopqrstuvwxyz1234 Serial: L-30-lmnopq-DD19F9CA Nombre: deurus2014 Serial: L-10-eurus2-84D8F9CA
Links
- Crackme y Keygen [crackmes.de]
Crudd’s Splish Splash KeyGen

Intro
Hoy tenemos un crackme hecho en ensamblador y que cuenta con tres niveles. En el primero de todos nos enfrentamos a una «Splash screen» o nag. El segundo en un serial Hardcodeado y el tercero un número de serie asociado a un nombre.
Nopeando la Splash Screen
Abrimos el crackme con Olly y vamos a las «Intermodular Calls«, enseguida vemos la función que crea las ventanas «CreateWindowExA«. Se puede ver lo que parece ser la creación de la pantalla del crackme y al final hay algo que salta a la vista y es la propiedad «WS_TOPMOST», es decir, que se mantenga delante del resto de ventanas.
Pinchamos sobre la función y vamos a parar aquí.
Vemos la llamada a CreateWindowExA que podríamos parchear pero vamos a pensar un poco. Vemos la función GetTickCount y que carga el valor 7D0. 7D0 es 2000 en decimal, que perfectamente pueden ser milisegundos, por lo tanto el parcheo más elegante sería poner la función GetTickCount a 0. En la imagen inferior se puede ver como queda parcheado el valor 7D0.
Probamos y funciona, pasamos a lo siguiente.
Serial Hardcodeado
El mensaje de error del serial hardcodeado dice «Sorry, please try again». Lo buscamos en las string references y vamos a parar aquí.
Vemos un bucle de comparación que carga unos bytes de la memoria, los bytes dicen «HardCoded«, probamos y prueba superada.
El nombre y número de serie
Con el mismo método de las string references localizamos el código que nos interesa. Metemos deurus como nombre y 12345 como serial y empezamos a tracear. Lo primero que hace es una serie de operaciones con nuestro nombre a las que podemos llamar aritmética modular. Aunque en la imagen viene bastante detallado se vé mejor con un ejemplo.
Ejemplo para Nombre: deurus
d e u r u s 64 65 75 72 75 73 -hex 100 101 117 114 117 115 -dec 1ºByte = ((Nombre[0] % 10)^0)+2 2ºByte = ((Nombre[1] % 10)^1)+2 3ºByte = ((Nombre[2] % 10)^2)+2 4ºByte = ((Nombre[3] % 10)^3)+2 5ºByte = ((Nombre[4] % 10)^4)+2 6ºByte = ((Nombre[5] % 10)^5)+2 1ºByte = ((100 Mod 10) Xor 0) + 2 2ºByte = ((101 Mod 10) Xor 1) + 2 3ºByte = ((117 Mod 10) Xor 2) + 2 4ºByte = ((114 Mod 10) Xor 3) + 2 5ºByte = ((117 Mod 10) Xor 4) + 2 6ºByte = ((115 Mod 10) Xor 5) + 2 Si el byte > 10 --> Byte = byte - 10 1ºByte = 2 2ºByte = 2 3ºByte = 7 4ºByte = 9 5ºByte = 5 6ºByte = 2
Lo que nos deja que los Bytes mágicos para deurus son: 227952.
Debido a la naturaleza de la operación IDIV y el bucle en general, llegamos a la conclusión de que para cada letra es un solo byte mágico y que este está comprendido entre 0 y 9.
A continuación realiza las siguientes operaciones con el serial introducido.
Ejemplo para serial: 12345
1 2 3 4 5 31 32 33 34 35 -hex 49 50 51 52 53 -dec 49 mod 10 = 9 50 mod 10 = 0 51 mod 10 = 1 52 mod 10 = 2 53 mod 10 = 3
Los bytes mágicos del serial son: 90123, que difieren bastante de los conseguidos con el nombre.
A continuación compara byte a byte 227952 con 90123.
En resumen, para cada nombre genera un código por cada letra y luego la comprobación del serial la realiza usando el módulo 10 del dígito ascii. Lo primero que se me ocurre es que necesitamos cotejar algún dígito del 0 al 9 para tener cubiertas todas las posibilidades. Realizamos manualmente mod 10 a los números del 0 al 9 y obtenemos sus valores.
(0) 48 mod 10 = 8 (1) 49 mod 10 = 9 (2) 50 mod 10 = 0 (3) 51 mod 10 = 1 (4) 52 mod 10 = 2 (5) 53 mod 10 = 3 (6) 54 mod 10 = 4 (7) 55 mod 10 = 5 (8) 56 mod 10 = 6 (9) 57 mod 10 = 7
Con esto ya podríamos generar un serial válido.
0123456789 - Nuestro alfabeto numérico 8901234567 - Su valor Mod 10
Por lo que para deurus un serial válido sería: 449174. Recordemos que los bytes mágicos para deurus eran «227952», solo hay que sustituir.
Para realizar un KeyGen más interesante, he sacado los valores de un alfabeto mayor y le he añadido una rutina aleatoria para que genere seriales diferentes para un mismo nombre.
'abcdefghijklmnñppqrstuvwxyz0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ - Alfabeto
'7890123456778901234567789018901234567567890123455678901234556880 - Valor
Dim suma As Integer = 0
'Para hacer el serial más divertido
Dim brute() As String = {"2", "3", "4", "5", "6", "7", "8", "9", "0", "1"}
Dim brute2() As String = {"d", "e", "f", "g", "h", "i", "j", "a", "b", "c"}
Dim brute3() As String = {"P", "Q", "R", "S", "T", "U", "j", "a", "D", "E"}
Dim alea As New Random()
txtserial.Text = ""
'Evito nombres mayores de 11 para evitar el BUG comentado en le manual
If Len(txtnombre.Text) > 0 And Len(txtnombre.Text) < 12 Then
For i = 1 To Len(txtnombre.Text)
Dim aleatorio As Integer = alea.Next(0, 9)
suma = (((Asc(Mid(txtnombre.Text, i, 1))) Mod 10) Xor i - 1) + 2
If suma > 9 Then
suma = suma - 10
End If
If (aleatorio) >= 0 And (aleatorio) <= 4 Then
txtserial.Text = txtserial.Text & brute(suma)
ElseIf (aleatorio) > 4 And (aleatorio) <= 7 Then
txtserial.Text = txtserial.Text & brute2(suma)
ElseIf (aleatorio) > 7 And (aleatorio) <= 10 Then
txtserial.Text = txtserial.Text & brute3(suma)
End If
suma = 0
Next
Else
txtserial.Text = "El Nombre..."
End If
Notas finales
Hay un pequeño bug en el almacenaje del nombre y serial y en el guardado de bytes mágicos del serial. Si nos fijamos en los bucles del nombre y el serial, vemos que los bytes mágicos del nombre los guarda a partir de la dirección de memoria 403258 y los bytes mágicos del serial a partir de 40324D. En la siguiente imagen podemos ver seleccionados los 11 primeros bytes donde se almacenan los bytes mágicos del serial. Vemos que hay seleccionados 11 bytes y que el siguiente sería ya 403258, precisamente donde están los bytes mágicos del nombre. Como puedes imaginar si escribes un serial >11 dígitos se solapan bytes y es una chapuza, de modo que el keygen lo he limitado a nombres de 11 dígitos.
Links
Solución a los retos javascript de rogerfm.net

- Introducción
- Javascript 1 (Serial a la vista)
- Javascript 2 (La función charAt())
- Javascript 3 (Input)
- Javascript 4 (Fuerza bruta manual)
- Javascript 5 (Fuerza bruta)
- Enlaces
Introducción
Los retos de Javascript son los retos más sencillos que podemos encontrar. Muchas veces solamente mirando el código fuente obtenemos la respuesta. Suponen una mala implementación de seguridad debido a que el código se ejecuta del lado del cliente, por lo que el código fuente es accesible y por lo tanto, javascript no garantiza seguridad alguna. En estos cinco casos haremos un recorrido por lo más básico, cinco retos fáciles de superar y que nos proporcionan los conocimientos base para Javascript. Dicho esto os puedo asegurar que en ocasiones he encontrado retos javascript realmente complicados que requieren de horas descifrarlos y en los que es fácil tirar la toalla.
Cuando el reto lo requiera, es buena idea utilizar un compilador online para obtener de forma rápida el valor de una variable o realizar una prueba concreta. Yo utilizo Jsfiddle para realizar pruebas pero existen muchos más.
Javascript 1
Este primer reto es lo básico, en el código fuente se pueden apreciar directamente el usuario y la clave.
<script language=JavaScript>
function Verify(name,pass)
{
if (name=="admin" & pass=="3***3")
{
location.href = name + pass + '.htm';
}
else
{
alert("Si ya fallamos el primero...");
};
}
</script>
Javascript 2
Este segundo reto es bastante sencillo pero ya te obliga a conocer la función charAt() de Javascript. Dicha función lo que hace es coger el caracter indicado mediante un índice que comienza en cero. Por ejemplo si nombre = deurus y hacemos letra = nombre.charAt(3), estariámos extrayendo la cuarta letra, es decir, la letra r de la variable nombre.
function Verify(name,pass)
{
var name1 = "CrawlinG", pass1 = "capriccio"
if (name==name1 & pass==pass1)
{
location.href = name + ".htm";
}
else
{
var x = name1.charAt(7) + pass1.charAt(3)+ name1.charAt(2) + pass1.charAt(5) + name1.charAt(5) + pass1.charAt(1);x = x.toLowerCase();
var y = name.charAt(3) + name.charAt(1) + pass.charAt(1)+ pass.charAt(6) + pass.charAt(7) + name.charAt(2);var x1 = "des" + y;
if (x==y){location.href = x1 + ".htm"}else{alert("Esto no va bien");location.href = "js2.htm"}
}
}
Lo interesante está en la formación de las variables x e y. La variable x se forma de las variables name1 y pass1, formando la palabra gracia. Por otro lado, la variable y se forma con el nombre y clave que introduzcamos nosotros. Vemos que la variable x e y deben ser iguales, por lo tanto debemos construir un nombre (name) y una clave (pass) que cumpla con lo siguiente:
- 4ª letra del nombre = 1ª letra de la palabra «gracia»
- 2ª letra del nombre = 2ª letra de la palabra «gracia»
- 2ª letra de la clave = 3ª letra de la palabra «gracia»
- 7ª letra de la clave = 4ª letra de la palabra «gracia»
- 8ª letra de la clave = 5ª letra de la palabra «gracia»
- 3ª letra del nombre = 6ª letra de la palabra «gracia«
Como véis simplemente se trata de interpretar correctamente la función charAt() y de fijarse bien en los nombres de las variables.
Javascript 3
Este reto nos muestra diálogo donde nos pide la contraseña para validar el reto. Al fallar o cancelar vuelve al índice para no dejarnos ver el código fuente. Aquí se pueden seguir varios caminos como bloquear el uso de javascript en el navegador o instalar un plugin en chrome o firefox para habilitar/deshabilitar de forma rápida el uso de javascript.
Una vez deshabilitado javascript vemos lo siguiente:
<script language="JavaScript" src="js3.gif" type=text/javascript>
<!--
function verify()
{
var pass="thebest";
var password=prompt("Introduce el password para superar el nivel","");
if (password==pass)
{
location.href = pass + ".htm";
}
else
{
alert("No vamos bien...");
location.href = "index.htm";
}
}
//-->
</script>
Aquí el truco es darse cuenta que el código que se está ejecutando esta en «js3.gif» y no el código que nos muestra como válida la clave thebest. Si descargamos el archivo js3.gif y lo abrimos con un archivo de texto vemos nuestra querida clave.
function verify()
{
var pass="mo****ver";
var password=prompt("Introduce el password para superar el nivel","");
if (password==pass)
{
location.href = pass + ".htm";
}
else
{
alert("No vamos bien...");
location.href = "index.htm";
}
}
Javascript 4
En este reto ya entramos con que la clave no es reversible y la debemos obtener por fuerza bruta. En este reto utiliza una nueva función como charCodeAt() que lo que hace es obtener el valor ascii del caracter indicado.
function Verify(pass1)
{
var cont1= 2, cont2= 6
var suma1 = 0, suma2 = 0
var pass2 = "FDRLF"
for(i = 0; i < pass1.length; i++)
{
suma1 += (pass1.charCodeAt(i) * cont1);
cont1++
}
for(i = 0; i < pass2.length; i++)
{
suma2 += (pass2.charCodeAt(i) * cont2);
cont2++
}
if (suma1==suma2)
{
window.location=suma1+".htm";
}
else
{
alert ("Algo no va bien...");
}
}
Vemos dos bucles en los que se calculan sendos valores suma que finalmente se comparan. la variable suma1 se calcula mediante nuestro password y la variable suma2 la obtiene de la palabra «FDRLF». Con el script que os muestro a continuación obtenemos que usando como clave deurus, suma1 = 3048 y suma2 = 2936. Nuestro punto de referencia es suma2 = 2936, de modo que vamos alterando con paciencia la variable pass1 obteniendo valores cercanos a 2936. Por ejemplo «deurua» nos da suma1 = 2922, un valor bastante cercano.
var pass1 = "deurus";
var cont1= 2, cont2= 6
var suma1 = 0, suma2 = 0
var pass2 = "FDRLF"
for(i = 0; i < pass1.length; i++)
{
suma1 += (pass1.charCodeAt(i) * cont1);
cont1++
}
for(i = 0; i < pass2.length; i++)
{
suma2 += (pass2.charCodeAt(i) * cont2);
cont2++
}
alert (suma1);
alert (suma2);
La solución a este reto es múltiple. Dos claves válidas son por ejemplo dfurqf y zwfabz.
Javascript 5
Este último reto es similar al anterior pero ya nos obliga a crearnos una pequeña herramienta que nos busque el serial válido.
function Verify(pass)
{
var suma=0
var cadena = "abcdefghijklmnopqrstuvwxyz"
for (var i = 0; i < pass.length; i++)
{
var letra = pass.charAt(i)
var valor = (cadena.indexOf(letra))
valor++
suma *= 26
suma += valor
}
if (suma==6030912063)
{
window.location=pass+".htm";
}
else
{
alert ("Algo no va bien...");
}
}
Para esta ocasión utiliza una nueva función llamada indexOf() que lo que hace es devolver un número entero que representa la posición en la que se encuentra el parámetro pasado a la función. Por ejemplo, si tengo variable = deurus y realizo posición = variable.indexOf(«s»), obtengo como resultado 5 (se empieza a contar desde cero).
Las operaciones que realiza el bucle son las siguientes:
- Coge las letras del nombre una a una.
- valor = posición de nuestra letra dentro de la variable de texto llamada cadena.
- valor = valor + 1.
- Multiplica la variable suma por 26.
- Suma = suma + valor.
Aunque el proceso de recuperación de esta clave es algo más largo, podemos acortarlo introduciendo una clave de inicio de fuerza bruta próxima al objetivo. Al ser una función bastante lineal podemos rápidamente mediante pruebas con nuestro código de fuerza bruta o con un compilador online, establecer que la clave tendrá 7 caracteres e incluso que para ahorrar tiempo podemos aproximar la clave para que su valor suma esté cercano al valor suma buscado 6030912063.
Realizando pruebas obtenemos:
- Clave = aaaaaaa -> suma = 321272407
- Clave = zzzzzzz -> suma = 8353082582
- Clave = smaaaaa -> suma = 6024332887
- Clave = smkkkkk -> suma = 6029085437
Como vemos, la clave smkkkkk ya está bastante próxima al objetivo y será un buen punto para lanzar la fuerza bruta.
Os dejo el código de fuerza bruta en .Net
Module Module1
Sub Main()
inicio:
Console.WriteLine("-------------------------")
Console.WriteLine("Modo [1] Prueba password")
Console.WriteLine("Modo [2] Fuerza bruta")
Console.WriteLine("-------------------------")
Dim modo = Console.ReadLine()
'
If modo = 2 Then
Console.WriteLine("¿Password para comenzar?")
Dim pass = Console.ReadLine()
inicio2:
Dim cadena As String = "abcdefghijklmnopqrstuvwxyz"
Dim valor As Integer = 0
Dim suma As Long = 0
Dim letra As String
For i = 0 To pass.Length - 1
letra = Mid(pass, i + 1, 1)
valor = cadena.IndexOf(letra)
valor += 1
suma *= 26
suma += valor
Next
Console.WriteLine("Password: " & pass & " - Sum: " & suma.ToString)
pass = IncrementString(pass)
If suma = 6030912063 Then
MsgBox("Password is " & pass)
Else
If pass = "aaaaaaaa" Then
Console.WriteLine("pass not found")
Console.ReadKey()
Else
GoTo inicio2
End If
End If
End If
'------------------------------------------------
If modo = 1 Then
Console.WriteLine("Password:")
Dim pass = Console.ReadLine()
Dim cadena As String = "abcdefghijklmnopqrstuvwxyz"
Dim valor As Integer = 0
Dim suma As Long = 0
Dim letra As String
For i = 0 To pass.Length - 1
letra = Mid(pass, i + 1, 1)
valor = cadena.IndexOf(letra)
valor += 1
suma *= 26
suma += valor
Next
Console.WriteLine("Password: " & pass & " - Sum: " & suma.ToString)
Console.WriteLine(".......")
Console.WriteLine("Good = 6030912063")
Console.WriteLine("Suma = " & suma.ToString)
Console.ReadKey()
Console.Clear()
GoTo inicio
End If
End Sub
Function IncrementString(ByVal strString As String) As String
'
' Increments a string counter
' e.g. "a" -> "b"
' "az" -> "ba"
' "zzz" -> "aaaa"
'
' strString is the string to increment, assumed to be lower-case alphabetic
' Return value is the incremented string
'
Dim lngLenString As Long
Dim strChar As String
Dim lngI As Long
lngLenString = Len(strString)
' Start at far right
For lngI = lngLenString To 0 Step -1
' If we reach the far left then add an A and exit
If lngI = 0 Then
strString = "a" & strString
Exit For
End If
' Consider next character
strChar = Mid(strString, lngI, 1)
If strChar = "z" Then
' If we find Z then increment this to A
' and increment the character after this (in next loop iteration)
strString = Left$(strString, lngI - 1) & "a" & Mid(strString, lngI + 1, lngLenString)
Else
' Increment this non-Z and exit
strString = Left$(strString, lngI - 1) & Chr(Asc(strChar) + 1) & Mid(strString, lngI + 1, lngLenString)
Exit For
End If
Next lngI
IncrementString = strString
Exit Function
End Function
End Module
Enlaces
- Web del reto
- Jsfiddle (compilador online)
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!
5 revistas sobre Hacking imprescindibles

Si te interesa el mundo del hacking, ya sea como aficionado o como profesional, seguramente querrás estar al día de las últimas novedades, técnicas y herramientas que se utilizan en este campo. Para ello, una buena opción es suscribirte a alguna de las revistas sobre hacking que existen en el mercado. Estas publicaciones te ofrecen información de calidad, actualizada y veraz sobre todo lo relacionado con la seguridad informática, el pentesting, el hacking ético y otros temas de interés. En este artículo te presentamos cinco revistas sobre hacking que deberías leer si quieres ampliar tus conocimientos y habilidades en este ámbito.
Es una de las revistas más populares y reconocidas sobre hacking. Se publica desde el año 2005 y cuenta con una amplia comunidad de lectores y colaboradores. Su contenido abarca desde los aspectos más básicos hasta los más avanzados del hacking, con artículos, tutoriales, entrevistas, casos de estudio y reseñas de herramientas. Además, tiene ediciones especiales dedicadas a temas específicos como el hacking web, el hacking móvil, el malware o el IoT. Puedes acceder a su versión digital o impresa desde su página web.


Es una revista electrónica sobre hacking que se publica desde el año 1985. Tiene una periodicidad irregular y se distribuye de forma gratuita a través de Internet. Sus contenidos son principalmente artículos técnicos sobre hacking, seguridad informática, programación, etc. También incluye algunos textos de ficción y humor relacionados con el hacking. Es una revista muy apreciada por la comunidad hacker por su calidad y originalidad.
2600: The Hacker Quarterly es una revista legendaria entre los hackers, ya que se publica desde 1984 y ha sido testigo de la evolución de este movimiento a lo largo de las décadas. Su nombre hace referencia a la frecuencia de 2600 Hz que se usaba para hackear las líneas telefónicas en los años 60 y 70. En sus páginas encontrarás artículos sobre hacking, seguridad informática, cultura hacker, activismo digital y mucho más.


Revista especializada en pentesting o pruebas de penetración, una de las ramas más importantes del hacking ético. Su contenido está dirigido tanto a principiantes como a expertos en esta materia, con artículos prácticos, teóricos y metodológicos sobre cómo realizar pentests eficaces y profesionales. También incluye entrevistas a destacados pentesters, reseñas de herramientas y reportajes sobre proyectos y eventos relevantes. Puedes descargar su versión digital desde su página web o comprar su versión impresa.
Es una revista para los entusiastas del hacking creativo, es decir, aquellos que usan la tecnología para crear proyectos innovadores y divertidos. En sus páginas encontrarás ideas, tutoriales, consejos y reseñas sobre temas como la electrónica, la robótica, el hardware libre, el software libre, el internet de las cosas, la impresión 3D y mucho más..

Retos stego 1-4 de Challengeland.co

Introducción
Hoy vamos a enfrentarnos a cuatro retos de esteganografía relativamente sencillos, y digo relativamente, debido a que hay tantas formas de esconder información en un archivo, ya sea imagen, vídeo o sonido, que afrontarlos suele ser desesperante. Las cuatro imágenes son aparentemente las mismas que la que se ve en portada.
Una buena práctica cuando te enfrentas a retos stego de tipo imagen es realizar una búsqueda inversa. Una búsqueda inversa consiste en buscar la imagen original mediante buscadores especializados como TinEye o Google. Si conseguimos la imagen original podemos resolver el reto simplemente comparando o nos puede dar una idea del tipo de modificación por su diferencia de tamaño, colores, degradados, etc.
Stego 1
Descargamos la imagen del reto. Se trata de una imagen JPEG de 526×263 y 76.6 KB (78445 bytes). Su hash SHA1 es «89aed5bbc3542bf5c60c4c318fe99cb1489f267a«
Realizamos una búsqueda inversa de la imagen y encontramos sin dificultad la imagen original mediante TinEye.
Características de la imagen original:
- Resolución: 526×263
- Tamaño: 78447 bytes (76.6 KB)
- Hash SHA1: 8924676317077fc07c252ddeec04bd2a0ecfdda4
Por lo que vemos ha cambiado el tamaño de 78447 bytes a 78445 bytes y su hash SHA1 tampoco coincide obviamente, lo que nos confirma que ha sufrido alguna modificación. Echando un vistazo con un editor hexadecimal te puedes volver loco por lo que vamos a realizar una comparación mediante la herramienta online DiffNow.
Al realizar la comparación sale a relucir lo que buscamos. La clave es una simple cadena de texto.
Stego 2
Lo primero es realizar de nuevo la comparación.
| Imagen | Tamaño | SHA1 |
|---|---|---|
| Original | 78447 bytes | 8924676317077fc07c252ddeec04bd2a0ecfdda4 |
| imagen2.jpeg | 116386 bytes | 7641e3906f795c137269cefef29f30fcb9cb1b07 |
Como vemos, la imagen ha aumentado significativamente, de 76,6 KB a 113 KB. Cuando el aumento de tamaño llama la atención normalmente tenemos otro archivo insertado. Lo primero que suelo hacer yo es fijarme si ha sido modificado el final del archivo con un editor hexadecimal. Los bytes de cola de un archivo jpg/jpeg son FFD9 y en este caso no vemos modificación alguna al final del archivo. Si el archivo no está al final requiere realizar una búsqueda más exhaustiva. Para estos casos tengo una herramienta de creación propia que se llama Ancillary y que sirve para buscar cierto tipo de archivos dentro de otros como imágenes, documentos de Office, Open Office, pdf, etc. Ancillary encuentra otro jpg que es el que le daba el peso extra y que vemos a continuación. La clave es el título de la película (ojo a las mayúsculas/minúsculas).
Stego 3
El tercer reto parece que tiene algún error debido a que el archivo coincide completamente con el original. Pienso que se ha subido la imagen original por error. Se lo he comunicado al admin del dominio y si algún día obtengo respuesta actualizaré la entrada.
| Imagen | Tamaño | SHA1 |
|---|---|---|
| Original | 78447 bytes | 8924676317077fc07c252ddeec04bd2a0ecfdda4 |
| imagen3.jpeg | 78447 bytes | 8924676317077fc07c252ddeec04bd2a0ecfdda4 |
Actualización 21/08/2016
Al parecer, la solución de este reto es llegar a la conclusión de que la imagen no está modificada. La respuesta del Administrador de la web así lo confirma.
desingsecurity [at] gmail [dot] com – Sorry about the delay, is precisely what is intended with that challenge, they can determine if the image is changed or not , the challenge was solved you . We’ll be equal way improving this point.
Greetings and Thanks
Stego 4
Lo primero es realizar de nuevo la comparación.
| Imagen | Tamaño | SHA1 |
|---|---|---|
| Original | 78447 bytes | 8924676317077fc07c252ddeec04bd2a0ecfdda4 |
| imagen4.jpeg | 93174 bytes | a6329ea4562ef997e5afd067f3b53bdab4665851 |
Al igual que en el caso dos el tamaño ha aumentado significativamente de modo que miramos al final del archivo y esta vez si vemos que hay insertado unos bytes tras el final del jpg (recordemos FFD9)
El archivo tiene pinta de ser una hoja de cálculo de Open Office o Libre Office según indica la palabra «spreadsheet«. Lo abrimos con Excel y tras analizar la maraña de datos enseguida vemos una clave que llama la atención.
Enlaces
- Challengeland (El dominio ya no existe) [Archive]
Herramientas utilizadas
- Editor Hexadecimal: HxD Freeware Hex Editor
- Búsqueda inversa de imágenes: TinEye | Google
- Comparador de archivos online: DiffNow
- File Carving Tool: Ancillary.









































