Está en la página 1de 16

Tutorial nº 33 – by +NCR/CRC!

[ReVeRsEr] Junio 2004

Programa Crackme 1 by Yllera


Download www.crackslatinos.hispadominio.net
Descripción Un muy buen crackme...
Herramientas Olly 1.10b, RadASM
Dificultad Newbie
Compresor/Compilador MASM/TASM
Protección Serial / Name
Objetivos Obtener un serial válido, hacer el keygen
Cracker +NCR Fecha: 26/06/04
Tutorial nº 33

Introducción

Bueno, una vez más nos volvemos a encontrar y esta vez con lo que más nos gusta, el cracking.
Despúes de un descanso que me había tomado del cracking escriboendo tut’s sobre programación,
he vuelto a la carga con el cracking, y esta vez vamos a trabajar sobre el crackme del amigo Yllera.

Considero que es un muy buen crackme para comenzar a explorar el tema de los keygens. Si bien
vamos a crackearlo, también vamos a intentar crear un keygen ya que, en mi opinión, un cracker
debe saber, además de muchas otras, programar y criptografía, son dos cosas fundamentales que un
cracker debe aprender con el tiempo y creo que mi amigo AkirA está de acuerdo con esto, no?.

Debo reconocer que el keygen me ha costado dado que funcionaba de lo mejor en sistemas
operativos Win98, Win98 SE y WinMe, pero no funkba en WinXp, pero gracias a los amigos de la
lista (gracias RedH@wK y Daniel (La Calavera)) he podido solucionar el tema.

reversing_ar@yahoo.com.ar 1
Tutorial nº 33 – by +NCR/CRC! [ReVeRsEr] Junio 2004

Comenzemos...

Ni bien lo ejecutamos vemos esto:

Un bonito crackme....como sabemos, generalmente, un crackme programado por un cracker no


suele ser muy fácil, es decir, en un programa hecho por una empresa podemos encontrar cosas tan
ridículas como:

Mov eax,serial_bueno
Mov ebx,serial_malo
Cmp eax,ebx
Jne chico_malo

Algo que da pena.....esto no suele verse, no he visto ninguno, en programas creados por crackers,
dado que el objetivo de los crackers es intentar crear un buen sistema de protección que cueste
bastante trabajo romperlo. Pero esto las empresas no lo tienen en cuenta, solo quieren que pagemos
por su software y la verdad es que dan lástima algunas protecciones que estos programas
comerciales traen. En fin....por lo tanto sabemos que puede que esta sea una tarea ardua, más fácil,
más difícil, pero tengamos siempre en mente que un cracker no busca presisamente hacernos las
cosas fáciles, sino todo lo contrario. Esto lo digo para los que recién se están iniciando en el tema
cracking.....(like me, je ).

Sigamos con el crackme. Metemos un nombre y un numertio y esto es lo que sale:

Por lo menos nos avisa de algo, así que ya tenemos por donde comenzar. Nos vamos a olly y
abrimos este crackme. Una vez dentro de olly, nos vamos a buscar el mensaje. Hacemos click
derecho sobre la ventana de code de olly y vamos a Search for  All referenced text strings y
veremos esto:

reversing_ar@yahoo.com.ar 2
Tutorial nº 33 – by +NCR/CRC! [ReVeRsEr] Junio 2004

Ahí lo tienen, el mensaje que estabamos buscando. Lo seleccionamos y le damos a Enter para ver a
donde nos conduce:

Caemos en una zona en la cual hay varios mensajes parecidos a este. Enseguida nos ponemos a ver
cual puede ser el que nos conviene explotar. Si somos buenos observadores, veremos que hay
llamadas a la función GetDlgItemTextA, a la función lstrlenA y por supuesto a MessageBoxA. Ya
sabemos bien para que se usa cada una de estas funciones del api, pero por las dudas se los
recuerdo:

La primera es para tomar datos de un editbox, o sea, datos del teclado, en este caso podría servir
para tomar nuestro nombre y serial. La segunda sirve para calcular la longitud de una cadena, podría
utilizarse en este caso para ver cuantos caracteres tienen nuestro nombre y nuestro serial. Y la
última creo que no necesita presentación, es la aclamada y tan amada MessageBoxA, que lo que
hace es mostrar mensajes.

Si nos fijamos, también, a continuación de las llamadas a lstrlenA hay comprobaciones. Esto quiere
decir que se están verificando las longitudes de cada cadena que introducimos (serial y name), si
pasamos las condiciones impuestas seguiremos adelante con el cálculo del serial, sino nos
mostrarán un mensaje diciendo que nos falta, en el mejor de los casos , claro. Puede ocurrir que no
se no avise de nada y perdamos mucho tiempo tratando de ver porque no funciona el tema.

Este no es el caso, el amigo Yllera nos avisa de cada error que cometemos, por ejemplo. Yo siempre
pongo como datos +NCR y como serial 45561223, ustedes pongan lo que quieran pero respeten el
formato para que puedan seguir la explicación, o sea un nombre con un carácter especial, tres letras
y un serial de 8 caracteres. Ahora pongamos un bp con F2 en la primer llamada a
GetDlgItemTextA, le damos Run (F9) para arrancar y le metemos el nombre y serial, luego le
damos a Probar y veremos que el olly salta en esta parte:

00401083 |. 6A 40 PUSH 40 ; /Count = 40 (64.)


00401085 |. 68 B0314000 PUSH CRACKM E1.004031B0 ; |Buffer = CRACKM E1.004031B0
0040108A |. 68 E9030000 PUSH 3E9 ; |ControlID = 3E9 (1001.)
0040108F |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
00401092 |. E8 5F030000 CALL <JM P.&user32.GetDlgItemTextA> ; \GetDlgItemTextA ;Estamos acá!!!!!!!
00401097 |. 6A 40 PUSH 40 ; /Count = 40 (64.)
00401099 |. 68 BC314000 PUSH CRACKM E1.004031BC ; |Buffer = CRACKM E1.004031BC
0040109E |. 68 EA030000 PUSH 3EA ; |ControlID = 3EA (1002.)
004010A3 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
004010A6 |. E8 4B030000 CALL <JM P.&user32.GetDlgItemTextA> ; \GetDlgItemTextA
004010AB |. 68 B0314000 PUSH CRACKM E1.004031B0 ; /String = "+NCR"
004010B0 |. E8 2F030000 CALL <JM P.&kernel32.lstrlenA> ; \lstrlenA
004010B5 |. 0BC0 OR EAX,EAX
004010B7 |. 75 18 JNZ SHORT CRACKM E1.004010D1
004010B9 |. 6A 00 PUSH 0 ; /Style = M B_OK|M B_APPLMODAL
004010BB |. 68 00304000 PUSH CRACKM E1.00403000 ; |Title = "Crackme por Yllera"
004010C0 |. 68 3B304000 PUSH CRACKM E1.0040303B ; |Text = "Que cansino"
004010C5 |. 6A 00 PUSH 0 ; |hOwner = NULL
004010C7 |. E8 36030000 CALL <JM P.&user32.M essageBoxA> ; \M essageBoxA

reversing_ar@yahoo.com.ar 3
Tutorial nº 33 – by +NCR/CRC! [ReVeRsEr] Junio 2004

004010CC |. E9 B8000000 JM P CRACKM E1.00401189

Primero vemos, en la parte resaltada con azul, que llama a GetDlgItemTextA para tomar nuestro
nombre, los push de arriba de la llamada son los argumentos que le pasa a la función. Luego
comienza a empujar nuevos argumentos para llamar nuevamente a la misma función, pero esta vez
para tomar el serial. Seguido de esto, en la parte amarilla, llama a la función lstrlenA para tomar la
longitud de nustro nombre, después de esto tenemos un xor y un salto condicional. Esto lo hace para
ver si hemos puesto algo en el edit que correponde al nombre, si no hemos puesto llama a la función
MessageBoxA para mostrarnos el siguiente mensaje:

Si hemos puesto algo, se queda con la longitud de dicha cadena y salta a esta parte:

004010D1 |> 83F8 04 CM P EAX,4 ;Caemos acá


004010D4 |. 77 18 JA SHORT CRACKM E1.004010EE
004010D6 |. 6A 00 PUSH 0 ; /Style = M B_OK|M B_APPLMODAL
004010D8 |. 68 00304000 PUSH CRACKM E1.00403000 ; |Title = "Crackme por Yllera"
004010DD |. 68 20304000 PUSH CRACKM E1.00403020 ; |Text = "No seas vago y escribe mas"
004010E2 |. 6A 00 PUSH 0 ; |hOwner = NULL
004010E4 |. E8 19030000 CALL <JM P.&user32.M essageBoxA> ; \M essageBoxA
004010E9 |. E9 9B000000 JM P CRACKM E1.00401189

Lo que hace en esta ocasión es fijarse si la longitud del nombre es mayor que 4 caracteres, sino nos
saca otro mensaje del mismo estilo que el anterior. Ahora si es mayor, vuelve a saltar a esta parte:

004010EE |> 83F8 05 CM P EAX,5 ;Camos justo aquí.


004010F1 |. 0F82 92000000 JB CRACKM E1.00401189
004010F7 |. 68 BC314000 PUSH CRACKM E1.004031BC ; /String = "45561223"
004010FC |. E8 E3020000 CALL <JM P.&kernel32.lstrlenA> ; \lstrlenA
00401101 |. 0BC0 OR EAX,EAX
00401103 |. 75 15 JNZ SHORT CRACKM E1.0040111A
00401105 |. 6A 00 PUSH 0 ; /Style = M B_OK|M B_APPLMODAL
00401107 |. 68 00304000 PUSH CRACKM E1.00403000 ; |Title = "Crackme por Yllera"
0040110C |. 68 6E304000 PUSH CRACKM E1.0040306E ; |Text = "¿te pongo yo el serial?"
00401111 |. 6A 00 PUSH 0 ; |hOwner = NULL
00401113 |. E8 EA020000 CALL <JM P.&user32.M essageBoxA> ; \M essageBoxA
00401118 |. EB 24 JM P SHORT CRACKM E1.0040113E

En esta parte realiza la misma comprobación, pero esta vez el salto es distinto, es decir, se fija si la
longitud de la cadena que correponde al nombre es menor que 5, o si está por debajo de 5. Este salto
es del mismo tipo que el anterior (JA) pero no tiene en cuenta el signo pero tiene en cuenta el flag
de signo. El tema es que debemos meter un nombre con al menos cinco caracteres.

Si metemos un nombre con 5 caracteres, el programa, llamará a la función lstrlenA en la dirección


[4010FC] y tomará la longitud de nuestro serial para realizar las verificaciones pertinentes. Hace lo
mismo que antes, se fija si en el edit del serial hay algo escrito, sino saca un mensaje. Si hemos
metido algo, salta a esta parte:

reversing_ar@yahoo.com.ar 4
Tutorial nº 33 – by +NCR/CRC! [ReVeRsEr] Junio 2004

0040111A |> 83F8 04 CM P EAX,4 ;Caemos acá


0040111D |. 77 15 JA SHORT CRACKM E1.00401134
0040111F |. 6A 00 PUSH 0 ; /Style = M B_OK|M B_APPLMODAL
00401121 |. 68 00304000 PUSH CRACKM E1.00403000 ; |Title = "Crackme por Yllera"
00401126 |. 68 47304000 PUSH CRACKM E1.00403047 ; |Text = ":P ¿No sabes hacerlo mejor?"
0040112B |. 6A 00 PUSH 0 ; |hOwner = NULL
0040112D |. E8 D0020000 CALL <JM P.&user32.M essageBoxA> ; \M essageBoxA
00401132 |. EB 0A JM P SHORT CRACKM E1.0040113E

Lo mismo que con el nombre, si tiene más de 4 caracteres, sigue, sino nos saca otro mensaje de
error. En caso de seguir va a esta parte:

00401134 |> 83F8 05 CM P EAX,5 ;Caemos acá


00401137 |. 72 05 JB SHORT CRACKM E1.0040113E
00401139 |. E8 54000000 CALL CRACKM E1.00401192
0040113E |> EB 49 JM P SHORT CRACKM E1.00401189

Hace los mismo que antes con el nombre, pero esta vez con el serial. Se fija se la longitud del
nombre esta por debajo de 5. Pero en este caso nos afecta dado que nuestro serial tiene 8 caracteres.
Por lo tanto lo que debemos hacer es cambiar el nombre por uno de 5 caracteres o más y el serial lo
dejamos como estaba. En mi caso he elegido seguir con el serial 45561223 y cambiar el nombre a
Reverser.

Vuelvo a reiniciar el crackme y a poner los nuevos datos, una vez que hemos pasado por las
anteriores comprobaciones, vemos que terminamos en la llamada que se encarga de generar el
serial. Esta llamada es la que está en [401137]. Así que no metemos con F7 y veremos esto:

00401192 $ 33DB XOR EBX,EBX


00401194 . 33D2 XOR EDX,EDX
00401196 . 33C0 XOR EAX,EAX
00401198 > 83FB 02 CM P EBX,2
0040119B . 74 20 JE SHORT CRACKM E1.004011BD
0040119D . 8A83 BC314000 M OV AL,BYTE PTR DS:[EBX+4031BC]
004011A3 . 3C 30 CM P AL,30
004011A5 . 73 08 JNB SHORT CRACKM E1.004011AF
004011A7 . 0F82 16020000 JB CRACKM E1.004013C3
004011AD . EB 0A JM P SHORT CRACKM E1.004011B9
004011AF > 3C 39 CM P AL,39
004011B1 . 76 06 JBE SHORT CRACKM E1.004011B9
004011B3 . 0F83 0A020000 JNB CRACKM E1.004013C3
004011B9 > 43 INC EBX
004011BA .^ EB DC JM P SHORT CRACKM E1.00401198
004011BC . C3 RETN

En esta primera parte, lo primero que hace es poner los registros a cero para comenzar con las
operaciones y no tener problemas de que algún dato contenido en dichos registros termine
generando algún error en el cálculo.

Luego compara a EBX con 2, esto lo hace porque va a utilizarlo como variable de control en el
bucle (como contador), si EBX es igual a 2 salta a una instrucción después del RETN para continuar
con el cálculo del serial, sino sigue ejecutandose el bucle. Después mueve el primer carácter de
nuestro serial a AL y lo compara, primero con 30h (48 en decimal; corresponde al valor ASCII del
carácter 0) y luego con 39h (57 decimal; valor ASCII del carácter 9). Básicamente lo que está
haciendo es comprobar si el primer carácter está entre 0 y 9; o sea, si es un número. Si resulta ser un
número, incrementa EBX y toma el segundo carácter y realiza la misma comprobación, sino son
números nos vamos de la llamada y se va todo al coño, je. Una vez que ha tomado los dos

reversing_ar@yahoo.com.ar 5
Tutorial nº 33 – by +NCR/CRC! [ReVeRsEr] Junio 2004

caracteres, EBX se ha incrementado dos veces con lo que toma un valor 2. Por lo tanto sigue en esta
parte:

004011BD > 33DB XOR EBX,EBX


004011BF . 33D2 XOR EDX,EDX
004011C1 . 33C0 XOR EAX,EAX
004011C3 > 83FB 06 CM P EBX,6
004011C6 . 74 20 JE SHORT CRACKM E1.004011E8
004011C8 . 8A83 B0314000 M OV AL,BYTE PTR DS:[EBX+4031B0]
004011CE . 3C 41 CM P AL,41
004011D0 . 73 08 JNB SHORT CRACKM E1.004011DA
004011D2 . 0F82 EB010000 JB CRACKM E1.004013C3
004011D8 . EB 0A JM P SHORT CRACKM E1.004011E4
004011DA > 3C 5A CM P AL,5A
004011DC . 76 06 JBE SHORT CRACKM E1.004011E4
004011DE . 0F83 DF010000 JNB CRACKM E1.004013C3
004011E4 > 43 INC EBX
004011E5 .^ EB DC JM P SHORT CRACKM E1.004011C3
004011E7 . C3 RETN

En esta parte vuelve a limpiar los registros y vuelve a utilizar a EBX como contador, pero esta vez
compara a EBX con 6, así que el nombre debe tener al menos 6 caracteres y no 5 como habíamos
pensado y ya van a ver porque. Va tomando cada carácter del nombre y se fija si los caracteres están
entre 41h y 5Ah que corresponden a los valores ASCII de las letras A y Z mayúsculas, por lo que
deducimos que el nombre debe contener solo mayúsculas. Sigue tomando caracteres hasta que el
contador valga 6, si alguno de los caracteres resulat ser una letra minúscula, un número o un
carácter especial, se termina el bucle y nos saca una MessageBoxA con un mensaje de error.

Pero acá hay una cosa que debemos tener en cuenta. Primero habíamos visto que el nombre debia
tener más de 4 caracteres para pasar las anteriores comprobaciones, pero si ponemos el nombre
REVER, con 5 caracteres, cuando se tome la última R, EBX valdrá 4, y luego se incrementará para
tomar el próximo carácter, con lo que EBX pasará a valer 5. Si hubiera un carácter más (el sexto) se
tomaría, se compararía con 41h y 5Ah y se volvería a incrementar EBX con lo que pasaría a valer 6
y la condición ya sería verdadera, con lo que saldríamos del bucle para seguir el cálculo.

Pero en este caso, si tenemos ese nombre con 5 caracteres, cuando tome el sexto, será un cero (un
carácter nulo) que no está entre el intervalo acotado, por ende terminaríamos saliendo del bucle
antes de tiempo. Por eso decimos que el nombre debe, además de contener solo mayúsculas, tener al
menos 6 caracteres, si hay más no interesa dado que con lo restantes no hace nada, pasa lo mismo
con el serial, debe tener al menos 6 caracteres para que se puedan seguir los cálculos.

Si hemos pasado todas las comprobaciones anteriores, llegaremos a esta parte:

004011E8 > 33DB XOR EBX,EBX


004011EA . 33D2 XOR EDX,EDX
004011EC . 33C0 XOR EAX,EAX
004011EE . 33C9 XOR ECX,ECX
004011F0 > 83F9 02 CM P ECX,2
004011F3 . 74 14 JE SHORT CRACKM E1.00401209
004011F5 . 8A81 BC314000 M OV AL,BYTE PTR DS:[ECX+4031BC]
004011FB . B3 32 M OV BL,32
004011FD . 38D8 CM P AL,BL
004011FF . 0F85 BE010000 JNZ CRACKM E1.004013C3
00401205 . 41 INC ECX
00401206 .^ EB E8 JM P SHORT CRACKM E1.004011F0

reversing_ar@yahoo.com.ar 6
Tutorial nº 33 – by +NCR/CRC! [ReVeRsEr] Junio 2004

Veamos que hace en esta ocasión. Vuelve a limpiar los registros y a uitilzar como contador a ECX.
Esta vez la condición para finalizar el bucle es que ECX valga 2. Básicamente, toma el primer
carácter de nuetro serial y lo guarda en AL, luego mueve un 32h (ASCII de 2) en Bl y compara a
AL con Bl, si son iguales incrementa ECX y toma el segundo carácter con el que vuelve a realizar
la misma operación, sino nos saca de la llamada con una linda MsgBoxA.

De aquí sacamos que los dos primeros caracteres del serial deben de ser “22”.

Si todo fue bien, seguimos, sino reiniciamos el crackme y metemos los nuevos datos. Yo hasta hora
llevo esto:

Nombre: REVERSER
Serial: 22561223

Veamos con que sigue.

00401209 > 33DB XOR EBX,EBX


0040120B . 33D2 XOR EDX,EDX
0040120D . 33C0 XOR EAX,EAX
0040120F . 33C9 XOR ECX,ECX
00401211 . BA A2314000 M OV EDX,CRACKM E1.004031A2 ; ASCII "LATINO"
00401216 > 83F9 06 CM P ECX,6
00401219 . 74 15 JE SHORT CRACKM E1.00401230
0040121B . 8A81 BF314000 M OV AL,BYTE PTR DS:[ECX+4031BF]
00401221 . 8A1C0A M OV BL,BYTE PTR DS:[EDX+ECX]
00401224 . 38D8 CM P AL,BL
00401226 . 0F85 97010000 JNZ CRACKM E1.004013C3
0040122C . 41 INC ECX
0040122D .^ EB E7 JM P SHORT CRACKM E1.00401216
0040122F . C3 RETN

Ya de entrada vemos algo sospechoso, la cadena “LATINO”. Bueno, en esta ocasión limpia los
registros nuevamente, luego mueve el string “LATINO” a EDX, compara ECX con 6 (lo utiliza
como contador) si es igual sale del bucle, sino mueve el cuarto carácter de nuetro serial y lo
almacena en AL, luego toma la primera letra de la cadena (“L”) y la almacena en BL, por último,
las compara, si son iguales sigue haciendo lo mismo con los demás caracteres, es decir, ir tomando
caracteres y comparandolos con las letras de la cadena sino mensaje de error. Con esto llegamos a
que nuetro número (22561223) es insuficiente dado que al tomar el último carácter, estaría tomando
un cadena nula, por lo que para evitar problemas en un futuro, pongamos un bp en el inicio de esta
parte, reiniciemos el crackme y metamosle el mismo nombre (REVERSER; o el que quieran
siempre y cuando tenga más de 6 caracteres y este en mayúsculas) y como serial metámosle un
número grande como 220LATINO0123456789 y sigamos con la faena.

Ya tenemos bastante armado nuetro serial, lo que podemos pensar hasta ahora es que puede llegar a
ser un harcoded, pero esperemos al final a ver que pasa. Una vez que pasamos las comprobaciones
correspondientes llegaremos a esta parte:

00401230 > 33DB XOR EBX,EBX


00401232 . 33D2 XOR EDX,EDX
00401234 . 33C0 XOR EAX,EAX
00401236 . A0 BE314000 M OV AL,BYTE PTR DS:[4031BE]
0040123B . B3 2D M OV BL,2D
0040123D . 38D8 CM P AL,BL
0040123F . 74 05 JE SHORT CRACKM E1.00401246
00401241 . E9 7D010000 JM P CRACKM E1.004013C3

reversing_ar@yahoo.com.ar 7
Tutorial nº 33 – by +NCR/CRC! [ReVeRsEr] Junio 2004

Vuelve a limpiar los registros y a tomar el carácter que quedo enntre el 22 y la cadena “LATINO”,
en este caso tengo un 0. Lo mueve a AL, luego mueve 2D a Bl (ASCII de “-“) y los compara. Acá
se fija si entre el 22 y “LATINO” existe un guión, en caso aformativo, continúa con la generación
del serial, sino chao!!!!.

Osea que hasta ahora tenemos el serial semi armado:

Nombre :REVERSER
Serial: 22-LATINO0123456789

Veamos que más hace. Si pasamos esta otra comprobación llegamos hasta esta parte:

Primer comprobación:
00401246 > |33DB XOR EBX,EBX
00401248 . |33C0 XOR EAX,EAX
0040124A . |A0 C6314000 M OV AL,BYTE PTR DS:[4031C6]
0040124F . |8A1D B2314000 M OV BL,BYTE PTR DS:[4031B2]
00401255 . |38D8 CM P AL,BL
00401257 . |74 0C JE SHORT CRACKM E1.00401265
00401259 . |C705 D0324000>M OV DWORD PTR DS:[4032D0],0
00401263 . |EB 0A JM P SHORT CRACKM E1.0040126F
00401265 > C705 D0324000>M OV DWORD PTR DS:[4032D0],1

En esta y las siguientes 5 partes realiza algo similar. Va tomando los caracteres restantes del serial
saltándose uno entre medio (parece que está reservando espacio para otro guión ), o sea con el
serial 22-LATINO0123456789, toma el 1, lugo el 2 y así sucesivamente en orden y va tomando las
letras del nombre pero comienza a partir del tercer carácter, luego el segundo, luego primero, luego
el sexto, el quinto y por último el cuarto y los va comparando con lo caracteres del serial. En esta
caso compararía:

1 con V
2 con E
3 con R
4 con S
5 con R
6 con E

Es como si fuera armando el nombre al revés. Ahora veamos las demás comprobaciones:

La segunda:

0040126F > 33DB XOR EBX,EBX


00401271 . 33C0 XOR EAX,EAX
00401273 . A0 C7314000 M OV AL,BYTE PTR DS:[4031C7]
00401278 . 8A1D B1314000 M OV BL,BYTE PTR DS:[4031B1]
0040127E . 38D8 CM P AL,BL
00401280 . 74 0C JE SHORT CRACKM E1.0040128E
00401282 . C705 D4324000>M OV DWORD PTR DS:[4032D4],0
0040128C . EB 0A JM P SHORT CRACKM E1.00401298
0040128E > C705 D4324000>M OV DWORD PTR DS:[4032D4],1

reversing_ar@yahoo.com.ar 8
Tutorial nº 33 – by +NCR/CRC! [ReVeRsEr] Junio 2004

la tercera:

00401298 > 33DB XOR EBX,EBX


0040129A . 33C0 XOR EAX,EAX
0040129C . A0 C8314000 M OV AL,BYTE PTR DS:[4031C8]
004012A1 . 8A1D B0314000 M OV BL,BYTE PTR DS:[4031B0]
004012A7 . 38D8 CM P AL,BL
004012A9 . 74 0C JE SHORT CRACKM E1.004012B7
004012AB . C705 D8324000>M OV DWORD PTR DS:[4032D8],0
004012B5 . EB 0A JM P SHORT CRACKM E1.004012C1
004012B7 > C705 D8324000>M OV DWORD PTR DS:[4032D8],1

la cuarta:

004012C1 > 33DB XOR EBX,EBX


004012C3 . 33C0 XOR EAX,EAX
004012C5 . A0 C9314000 M OV AL,BYTE PTR DS:[4031C9]
004012CA . 8A1D B5314000 M OV BL,BYTE PTR DS:[4031B5]
004012D0 . 38D8 CM P AL,BL
004012D2 . 74 0C JE SHORT CRACKM E1.004012E0
004012D4 . C705 DC324000>M OV DWORD PTR DS:[4032DC],0
004012DE . EB 0A JM P SHORT CRACKM E1.004012EA
004012E0 > C705 DC324000>M OV DWORD PTR DS:[4032DC],1

la quinta:

004012EA > 33DB XOR EBX,EBX


004012EC . 33C0 XOR EAX,EAX
004012EE . A0 CA314000 M OV AL,BYTE PTR DS:[4031CA]
004012F3 . 8A1D B4314000 M OV BL,BYTE PTR DS:[4031B4]
004012F9 . 38D8 CM P AL,BL
004012FB . 74 0C JE SHORT CRACKM E1.00401309
004012FD . C705 E0324000>M OV DWORD PTR DS:[4032E0],0
00401307 . EB 0A JM P SHORT CRACKM E1.00401313
00401309 > C705 E0324000>M OV DWORD PTR DS:[4032E0],1

y la sexta:

00401313 > 33DB XOR EBX,EBX


00401315 . 33C0 XOR EAX,EAX
00401317 . A0 CB314000 M OV AL,BYTE PTR DS:[4031CB]
0040131C . 8A1D B3314000 M OV BL,BYTE PTR DS:[4031B3]
00401322 . 38D8 CM P AL,BL
00401324 . 74 0C JE SHORT CRACKM E1.00401332
00401326 . C705 E4324000>M OV DWORD PTR DS:[4032E4],0
00401330 . EB 0A JM P SHORT CRACKM E1.0040133C
00401332 > C705 E4324000>M OV DWORD PTR DS:[4032E4],1

Fijens que después de cada comprobación hay un asalto que da valor a una variable que se está
utilizando como flag según si la comprobación resulta verdadera o falsa.

En caso de que las comprobaciones vayan siendo iguales, mete un 1 en una variable y así con las
seis comprobaciones. Si las seis fueran verdaderas, tendríamos seis 1. Luego de esto, compara cada
uno de los flags son el valor 1, o sea, se fija si las comprobaciones han resultado verdaderas, en
cuyo caso va incrementando ECX. En una última comprobación se fija cuanto vale ECX, si es
menor a 6, nos lleva al mensaje de error, si es igual nos da las garcias y las FELICITACIONES!!!!.
Pero esperen que falta algo, primero veamos las correspondienets comprobaciones:

reversing_ar@yahoo.com.ar 9
Tutorial nº 33 – by +NCR/CRC! [ReVeRsEr] Junio 2004

La primera:

0040133C > 33DB XOR EBX,EBX


0040133E . 33C9 XOR ECX,ECX
00401340 . 33C0 XOR EAX,EAX
00401342 . 8A1D D0324000 M OV BL,BYTE PTR DS:[4032D0]
00401348 . 80FB 01 CM P BL,1
0040134B . 75 03 JNZ SHORT CRACKM E1.00401350
0040134D . 41 INC ECX
0040134E . 74 00 JE SHORT CRACKM E1.00401350

la segunda:

00401350 > 33DB XOR EBX,EBX


00401352 . 33C0 XOR EAX,EAX
00401354 . 8A1D D4324000 M OV BL,BYTE PTR DS:[4032D4]
0040135A . 80FB 01 CM P BL,1
0040135D . 75 03 JNZ SHORT CRACKM E1.00401362
0040135F . 41 INC ECX
00401360 . 74 00 JE SHORT CRACKM E1.00401362

la tercera:

00401362 > 33DB XOR EBX,EBX


00401364 . 33C0 XOR EAX,EAX
00401366 . 8A1D D8324000 M OV BL,BYTE PTR DS:[4032D8]
0040136C . 80FB 01 CM P BL,1
0040136F . 75 03 JNZ SHORT CRACKM E1.00401374
00401371 . 41 INC ECX
00401372 . 74 00 JE SHORT CRACKM E1.00401374

la cuarta:

00401374 > 33DB XOR EBX,EBX


00401376 . 33C0 XOR EAX,EAX
00401378 . 8A1D DC324000 M OV BL,BYTE PTR DS:[4032DC]
0040137E . 80FB 01 CM P BL,1
00401381 . 75 03 JNZ SHORT CRACKM E1.00401386
00401383 . 41 INC ECX
00401384 . 74 00 JE SHORT CRACKM E1.00401386

la quinta:

00401386 > 33DB XOR EBX,EBX


00401388 . 33C0 XOR EAX,EAX
0040138A . 8A1D E0324000 M OV BL,BYTE PTR DS:[4032E0]
00401390 . 80FB 01 CM P BL,1
00401393 . 75 03 JNZ SHORT CRACKM E1.00401398
00401395 . 41 INC ECX
00401396 . 74 00 JE SHORT CRACKM E1.00401398

la sexta:

00401398 > 33DB XOR EBX,EBX


0040139A . 33C0 XOR EAX,EAX
0040139C . 8A1D E4324000 M OV BL,BYTE PTR DS:[4032E4]
004013A2 . 80FB 01 CM P BL,1
004013A5 . 75 01 JNZ SHORT CRACKM E1.004013A8
004013A7 . 41 INC ECX
004013A8 > 83F9 06 CM P ECX,6
004013AB . 74 02 JE SHORT CRACKM E1.004013AF

reversing_ar@yahoo.com.ar 10
Tutorial nº 33 – by +NCR/CRC! [ReVeRsEr] Junio 2004

004013AD . EB 14 JM P SHORT CRACKM E1.004013C3


004013AF > 6A 00 PUSH 0 ; /Style = M B_OK|M B_APPLMODAL
004013B1 . 68 00304000 PUSH CRACKM E1.00403000 ; |Title = "Crackme por Yllera"
004013B6 . 68 63304000 PUSH CRACKM E1.00403063 ; |Text = "bien hecho"
004013BB . 6A 00 PUSH 0 ; |hOwner = NULL
004013BD . E8 40000000 CALL <JM P.&user32.M essageBoxA> ; \M essageBoxA
004013C2 . C3 RETN
004013C3 > 6A 00 PUSH 0 ; /Style = M B_OK|M B_APPLMODAL
004013C5 . 68 00304000 PUSH CRACKM E1.00403000 ; |Title = "Crackme por Yllera"
004013CA . 68 47304000 PUSH CRACKM E1.00403047 ; |Text = ":P ¿No sabes hacerlo mejor?"
004013CF . 6A 00 PUSH 0 ; |hOwner = NULL
004013D1 . E8 2C000000 CALL <JM P.&user32.M essageBoxA> ; \M essageBoxA
004013D6 . C3 RETN
004013D7 . C3 RETN

Fijense que está la comprobación de ECX con 6 para ver si nos da las garcias o nos manda al coño.
Si ECX es igual a 6, nos da las garcias, pero en el serial queda algo medio colgado:

Nombre: REVERSER
Serial: 22-LATINO0VERSRE

Fijense que hay un cero entre el nombre invertido y la cadena “LATINO”. Como el programa no
hace nada con ese carácter yo he decidido, por decreto, convertirlo en un guión (“-“) a la hora de
programar el keygen como para que el serial tenga más bonita pinta, ustedes haganlo como más les
guste.

Bueno, por fin hemos llegado al final del crackeo, veamos como nos quedo:

Nombre: REVERSER
Serial: 22-LATINO-VERSRE

Me da las gracias.....garcias Yllera, je .

Algunos otros seriales válidos son:

Nombre: RICARDO
Serial: 22-LATINO-CIRDRA

Nombre: YLLERA
Serial: 22-LATINO-LLYARE

Nombre: ODRAUDE
Serial: 22-LATINO-RDODUA

En fin...hay muchos.......

reversing_ar@yahoo.com.ar 11
Tutorial nº 33 – by +NCR/CRC! [ReVeRsEr] Junio 2004

Programando el KeyGen

Primero debemos ttener bien en claro lo que debemos hacer. Es decir, recordar las condiciones que
teníamos para que el serial fuera válido. Enumeremos las condiciones:

1- El nombre debe tener al menos 6 caracteres. Por los demás no se preocupen total no hace nada
con ellos.
2- Los caracteres del nombre deben estar solo en mayúsculas.
3- El serial debe tener al menos 6 caracteres también.
4- El serial tiene una cadena constante que se repite en cada serial “22-LATINO-“.
5- La última parte del serial está armada con nuetros nombre. Los tres primeros caracteres
corrresponden a los tres primeros caracteres del nombre pero invertidos y los últimos 3 del
serial a los últimos tres del nombre, también invertidos.

Con esto ya estamos en condiciones de que ponernos a programar el keygen. Hay que tener en
cuenta de que cuando no se cumplan algunas de estas condiciones, deberemos informar al usuario lo
que tiene que hacer o no hacer nada. Pero creo que debemos decirle que esta pasando dado que no
estamos programando un crackme y además el pobre no sabrá que hacer.

Así que habrimos nuestro querido RadASM y creamos un proyecto tal como lo veníamos haciendo
hasta ahora.

Ponemos dos edit’s, dos botones, dos static’s y lo que queramos nosotros. Tratemos de que quede
algo similar a esto:

Ahora veamos que hacemos , je. En el archivo .asm ponemos esto:

Mov eax,uMsg
.if eax==WM_INITDIALOG
invoke LoadIcon,hInstance,500
mov hIcon,eax
invoke SendMessage,hWin,WM_SETICON,NULL,hIcon

Todo eso es para el ícono, pero no viene al caso. Si quieren miren las teorías de Daniel en las que se
explica muy bien como hacer esto.

reversing_ar@yahoo.com.ar 12
Tutorial nº 33 – by +NCR/CRC! [ReVeRsEr] Junio 2004

.elseif eax==WM_COMMAND
mov eax,wParam
.if eax==1007 ;Si presionamos “Generar”
invoke GetDlgItemText,hWin,1003,ADDR nombre,10 ;Toma el nombre
invoke lstrlen,offset nombre ;Obtiene su longitud
.if eax<6 ;Si es menor que seis
invoke MessageBox,hWin,offset men,offset tit,MB_ICONERROR ;Nos saca un
mensaje
ret ;Vuelve de la llamada
.elseif ;Sino
xor ebx,ebx ;Limpia los registros
xor ecx,ecx
xor edx,edx
invoke lstrlen,offset nombre ;Vuelve atomar la longitud del serial
mov edx,eax ;Mueve dicha longitud a EDX
xor ecx,ecx ;Limpia ECX
sigue: ;Inicio del bucle
mov al,byte ptr ds:[ebx+nombre] ;Mueve un carácter a AL
.if al>=41H && al<=5AH ;Se fija si está entre “A” y “Z”
inc ecx ;Si está en ese intervalo, incrementa ECX
.endif ;Termina la condición
inc ebx ;Incrementa EBX (Contador)
.if ebx!=edx ;Si EBX es distinto de EDX
jmp sigue ;Sigue tomando caracteres
.endif ;Termina en caso contrario

Expliquemos un poco que vinimos haciendo hasta acá. Si hemos presionado el botón de generar,
llamará a la función GetDlgItemTextA, la cual se encargará de tomar la cadena que esta en el edit
cuyo ID es 1003 y la guardará en una variable llamada nombre a la cual le he reservado 9
caracteres. Después toma la longitud de dicha cadena llamando a la función lstrlenA a la cual le
pasamos como argumento la variable “nombre”. Si la longitud de dicha cadena es menor que 6,
pues nos saca una MessageBoxA diciendonos que ingresemos un nombre con al menos 6
caracteres, sino comienza con las comprobaciones pertinentes para generar el serial.

Limpia los registros para que ningun valor intefiera con nustro cálculo. Tomamos nuevamente la
longitud de nuetras cadena y movemos la cantidad de caracteres que tiene a EDX. Volvemos poner
a ECX a cero. Esto se hizo así dado que en WinXp, el KeyGen había tenido problemas de
funcionamiento. Yo cuando lo programe, creí que con solo inicializar ECX antes de la llamada a
lstrlenA era suficiente dado que en mi OS, ese registro no se modifica hasta la primera vez que lo
incrementamos. Pero parece que en WinXp, al llamar a lstrlenA, se vuelven a meter valores en
dicho registro con lo que las comprobaciones posteriores no daban y el programa no funkba, así que
para eso esta ese XOR ECX,ECX antes del inicio del bucle. Pero debo aclarar que en Win98,
Win98 SE y WinME, el programa funcionaba de lo mejor sin ese parche (misterios del amigo Bill,
je ). Sigamos....

Luego damos inicio al bucle, el cual comenzamos metiendo el primer carácter del nombre en AL lo
comparamos con 41h y 5Ah (ASCII de “A” y “Z”) para fijarnos si son solo letras mayúsculas. Si la
letra resulta ser mayúscula, incrementamos ECX (contador secundario) sino incrementamos solo
EBX y tomamos el siguiente carácter con el cual hacemos las mismas operaciones, luego nos
fijamos si EBX vale lo mismo que EDX (ahí habíamos movido la longitud del serial, es decir que se

reversing_ar@yahoo.com.ar 13
Tutorial nº 33 – by +NCR/CRC! [ReVeRsEr] Junio 2004

seguirán tomando caracteres hata que se completen los 6 que corresponden), por último, una vez
que hemos terminado el bucle, nos fijamos si ECX (contador secundario) es igual a EDX (longitud
del serial). Si hemos EDX y ECX valen lo mismo, es decir 6, quiere decir que hemos introducido
solo letras mayúsculas y por lo tanto ECX se ha incrementado 6 veces, sino, quiere decir que algun
carácter no fue lo que esperabamos, por lo tanto nos saca un mansaje pidiendonos que metamos
solo letras mayúsculas.

Si todo ha ido bien llamara a la función que generara el serial.

.if edx==ecx ;Si EDX es igual a ECX


call generar ;Genera el serial
invoke SetDlgItemText,hWin,1004,ADDR iserial ;Y nos lo muestra
.elseif ;Sino
invoke MessageBox,hWin,offset men2,offset tit,MB_ICONERROR ;Mensaje de error
.endif ;Termina una condición
.endif ;Termina la otra condición
.elseif eax==1008 ;Esto es de los demás mensajes extras que pongo siempre yo
invoke MessageBox,hWin,offset men3,offset tit2,MB_ICONINFORMATION ;No tienen
impotancia en este caso particular
.elseif eax==1002 ;Ya con lo que tenemos, el keygen debería funcionar
invoke MessageBox,hWin,offset men4,offset tit2,MB_OK
.endif

Lo que hace ahí es fijarse si EDX (longitud del serial) y ECX (contador) son iguales. Si lo son,
llama a la rutina que genera el serial, la cual devolverá en la variable “iserial” la cadena válida para
nuestro nombre y la termina mostrabdo con la función SetDlgItemText en el edit cuyo ID es 1004.

Ahora toca hablar de la parte con la que más me pelié. Nunca antes había programado un keygen
solo, siempre tenía ayuda de alguien, pero esta vez decidí hacerlo solo y tuve que ir probando cosas
hasta que por fin terminé.

La rutina que genera el serial es esta:

generar:
xor eax,eax ;Limpia EAX
mov [iserial],"22" ;Mueve la cadena “22” al la variable “iserial”
mov [iserial2],"- " ;Mueve un guión a la variable “iserial2”
invoke lstrcat,offset iserial,offset iserial2 ;Concaetna (junta, une) las dos cadenas anteriores
mov [iserial2],"TAL" ;Mueve la 1º parte de la cadena “LATINO”
invoke lstrcat,offset iserial,offset iserial2 ;La concatena con lo que hay en la variable “iserial”
mov [iserial2],"ONI" ;Mueve a “Iserial2” la 2º parte de la cadena “LATINO”
invoke lstrcat,offset iserial,offset iserial2 ;Vuelve a concatenar con “Iserial”
mov [iserial2],"- " ;Agrega el guión que faltaba
invoke lstrcat,offset iserial,offset iserial2 ;Y lo concatena
invoke lstrlen,offset nombre ;Toma la longitud del nombre
mov al, byte ptr ds:[nombre+2] ;Toma el 3º carácter del nombre
mov [serial],eax ;Lo mueve a la variable “serial”
invoke lstrcat,offset iserial,offset serial ;Y lo concatena con la cadena que ya tenemos armada
invoke lstrlen,offset nombre ;Toma la longitud del nombre
mov al, byte ptr ds:[nombre+1] ;Mueve el 2º caracter

reversing_ar@yahoo.com.ar 14
Tutorial nº 33 – by +NCR/CRC! [ReVeRsEr] Junio 2004

mov [serial],eax ;Lo mueve a “serial”


invoke lstrcat,offset iserial,offset serial ;Vuelve a concatenar
invoke lstrlen,offset nombre ;Otra vez la longitud
mov al, byte ptr ds:[nombre] ;Ahora el 1º caracter
mov [serial],eax ;A serial
invoke lstrcat,offset iserial,offset serial ;Y concatena
invoke lstrlen,offset nombre ;Vuelve a tomar la longitud de nuestro nombre
mov al, byte ptr ds:[nombre+5] ;Ahora comienza por el 6º caracter
mov [serial],eax ;Lo mueve a serial
invoke lstrcat,offset iserial,offset serial ;Y concatena con la cadena restante
invoke lstrlen,offset nombre ;Toma la longitud del nombre
mov al, byte ptr ds:[nombre+4] ;Mueve el 5º carácter a AL
mov [serial],eax ;Luego lo mueve a “serial”
invoke lstrcat,offset iserial,offset serial ;Y vuelve a unir las cadenas
invoke lstrlen,offset nombre ;La última llamada a lstrlenA
mov al, byte ptr ds:[nombre+3] ;Este es el 4º caracter
mov [serial],eax ;Lo mueve a “serial”
invoke lstrcat,offset iserial,offset serial ;Termina de armar la cadena válida
ret ;Vuelve de la llamada

end start ;Termina la ejecución

Antes de que digan algo, quiero que sapan que esta es la manera en que me fueron saliendo las
cosas, yo iba probando y lo que no me funcionaba lo reemplazaba por otra cosa y volvía a probar
hasta que me funcionó.

Tal vez haya una manera más limpia de hacer este trabajo, pero por ser que estamos comenzando
creo que es bastante, je . Tal vez podríamos haber evitado llamar tantas veces a lstrlenA y hacerlo
todo dentro de un bucle. Pero bueno....sigamos con la explicación de cómo lo hice yo.

Primero utilizo dos variables para ir concatenando la cadena constante que tiene el serial, toda la
primera parte la tuve que hacer así porque no sabía como hacer para mover toda la cadena entera y
solo podía mover de a tres caracteres, sino el RadASM no ensamblaba el proyecto. El amigo
RedH@wK mando a la lista un ejemplo de cómo se hace, se los pongo tal cual:
.in
.m
in
e
vlsik
fde
o v e,1
afS
V =
x la
sriw=
W
t0
b
P
1
eIrm
c
D
g
la 0e_T
M
t,oC
M
O
fs
e
tV
x M
riA
a,h
W N
bD
in
le,1
o
0
fs2
e,o
tvfs
ae
tr3
1V
2;lo
rm
aio
le
b
m
v
;o
v
ae
sm
ao
s
rilb
q
eu
h
e
ayen
varib
lealed
it

Eso es lo que hay en el .asm y en el .inc puso lo siguiente:


.dar3
V
v 1ia
2 d
te
"lh
o
"a
b
d
Yl3
0
,d
e;u
p
s
ra a(0
",0 io
c
),en
b
lan
co

Creo que esta es la forma correcta de hacerlo, pero como yo estaba solo, eran como las 5 de la
mañana y no podía salir a pedir ayuda a ningún CrackLatino, me puse a probar de diferentes
maneras y así fue como salió, jeje.

reversing_ar@yahoo.com.ar 15
Tutorial nº 33 – by +NCR/CRC! [ReVeRsEr] Junio 2004

Lo único que se va haciendo después es ir tomando los caracteres en el orden que ya vimos cuando
crackeamos el programa y los vamos uniendo con la cadena constante que debe aparecer en todas
las cadenas válidas.

Despedida

Creo que ha sido un tut muy largo, por lo menos para mí, así que no tengo nada más que decir.

Agradecimientos

En primer lugar agradecer al amigo Yllera por su crackme con el cual he aprendido mucho y me he
divertido también. Luego agradecer a las personas de siempre, Ricardo Narvaja, RedH@wK,
Shadow&Dark, Daniel, Juan José, COCO, Morales, Odraude, Flipi, Degete, Kaod, _Primax, AkirA,
Joe Cracker, Pr@fesorX y a toda la demás gente de la lista!!!.

Saludos....

+NCR/CRC! [ReVeRsEr]
Junio de 2004

reversing_ar@yahoo.com.ar 16

También podría gustarte