Para aportar algo os dejo un tutorial que he hecho de un crackme y cómo hacer el keygen me ha costado algo adaptar el texto para postearlo pero weno.. ya me contaréis xDD
Diablo2002’s Crackme #09
En este tutorial vamos a estudiar el funcionamiento de este crackme y a hacer un keygen funcional.
Explicaré todo de forma básica, pero si alguien no entiende algo que pregunte
Links:
- Crackme
- Keygen
(si te lo vas a bajar el link de download está abajo a la derecha de la página)
No le metáis mano del tirón a la solución, intentad resolver el crackme primero, si no podéis, intentad resolverlo con el tutorial, y si tampoco podéis, haced lo que sea xD
1. Encontrando el código de la rutina de comprobación
Este paso es muy fácil. Podéis abrir el crackme en el olly y veréis cómo en las cadenas de texto está el goodboy, entre otras. También podéis poner breakpoints en las Apis obvias que hay como GetDlgWindowText, MessageBox o strlen.
Hecho esto comprobaréis que el principio del código ejecutado al pulsar el botón es:
00401129 |> \FFB5 FCFEFFFF PUSH [LOCAL.65]
Ponemos un breakpoint en esa línea, ejecutamos el programa, introducimos los datos, en mi caso FreeSoul y 252525 y presionamos el botón.
2. Estudiando el código
Donde estamos se pueden apreciar la llamada a un par de funciones, la
llamada al MessageBox bueno y al MessageBox malo, y un bucle grande.
Tal que así:
Código:
00401129 |> \FFB5 FCFEFFFF PUSH [LOCAL.65]
0040112F |. 8D85 00FFFFFF LEA EAX,[LOCAL.64]
00401135 |. 50 PUSH EAX
00401136 |. E8 C4000000 CALL d2k2_crk.004011FF
0040113B |. 8D85 00FFFFFF LEA EAX,[LOCAL.64]
00401141 |. 50 PUSH EAX
00401142 |. 8D45 80 LEA EAX,[LOCAL.32]
00401145 |. 50 PUSH EAX
00401146 |. FF75 0C PUSH [ARG.2]
00401149 |. E8 72000000 CALL d2k2_crk.004011C0
0040114E |. 8D75 80 LEA ESI,[LOCAL.32]
00401151 |. 8B7D 10 MOV EDI,[ARG.3]
00401154 |. 8B5D 0C MOV EBX,[ARG.2]
00401157 |. EB 3E JMP SHORT d2k2_crk.00401197
00401159 |> 0FB616 /MOVZX EDX,BYTE PTR DS:[ESI]
0040115C |. 0FB60F |MOVZX ECX,BYTE PTR DS:[EDI]
0040115F |. 8D85 00FFFFFF |LEA EAX,[LOCAL.64]
00401165 |. 50 |PUSH EAX ; /Arg3 = 00000006
00401166 |. 51 |PUSH ECX ; |Arg2 = 7C80BDE6
00401167 |. 52 |PUSH EDX ; |Arg1 = 0012FAD5 ASCII "52525"
00401168 |. E8 B7000000 |CALL d2k2_crk.00401224 ; \d2k2_crk.00401224
0040116D |. 3A03 |CMP AL,BYTE PTR DS:[EBX]
0040116F |. 74 1D |JE SHORT d2k2_crk.0040118E
00401171 |. 6A 30 |PUSH 30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
00401173 |. 68 7A304000 |PUSH d2k2_crk.0040307A ; |Title = "Hey Cracker"
00401178 |. 68 6D304000 |PUSH d2k2_crk.0040306D ; |Text = "Wrong Serial"
0040117D |. FF75 08 |PUSH [ARG.1] ; |hOwner = 002B03F4 ('diablo2oo2's Crackme#09',class='#32770')
00401180 |. E8 87010000 |CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
00401185 |. 33C0 |XOR EAX,EAX
00401187 |. 5B |POP EBX
00401188 |. 5F |POP EDI
00401189 |. 5E |POP ESI ; d2k2_crk.00401040
0040118A |. C9 |LEAVE
0040118B |. C2 0C00 |RETN 0C
0040118E |> FF8D FCFEFFFF |DEC [LOCAL.65]
00401194 |. 46 |INC ESI ; d2k2_crk.00401040
00401195 |. 47 |INC EDI
00401196 |. 43 |INC EBX
00401197 |> 83BD FCFEFFFF 00 CMP [LOCAL.65],0
0040119E |.^ 75 B9 \JNZ SHORT d2k2_crk.00401159
004011A0 |. 6A 40 PUSH 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
004011A2 |. 68 93304000 PUSH d2k2_crk.00403093 ; |Title = "Hey Cracker"
004011A7 |. 68 86304000 PUSH d2k2_crk.00403086 ; |Text = "Serial is OK"
004011AC |. FF75 08 PUSH [ARG.1] ; |hOwner = 002B03F4 ('diablo2oo2's Crackme#09',class='#32770')
004011AF |. E8 58010000 CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
004011B4 |. B8 01000000 MOV EAX,1
004011B9 |. 5B POP EBX
004011BA |. 5F POP EDI
004011BB |. 5E POP ESI ; d2k2_crk.00401040
004011BC |. C9 LEAVE
004011BD \. C2 0C00 RETN 0C
CALL 1
Traceamos por dentro de la primera call y encontramos lo siguiente:
Código:
004011FF /$ 55 PUSH EBP
00401200 |. 8BEC MOV EBP,ESP
00401202 |. 8B45 0C MOV EAX,[ARG.2]
00401205 |. C1E0 02 SHL EAX,2
00401208 |. 83F8 3C CMP EAX,3C
0040120B |. 76 05 JBE SHORT d2k2_crk.00401212
0040120D |. B8 1E000000 MOV EAX,1E
00401212 |> 50 PUSH EAX
00401213 |. FF75 08 PUSH [ARG.1]
00401216 |. 68 00304000 PUSH d2k2_crk.00403000 ; ASCII "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
0040121B |. E8 53000000 CALL d2k2_crk.00401273
00401220 |. C9 LEAVE
00401221 \. C2 0800 RETN 8
Bien... vamos traceando y vemos que en el offset 0x401202 lo que hace es mover a EAX un numero que hace referencia a la longitud del nombre introducido. En mi caso 8.
Después vemos SHL EAX,2, esto realiza una operación binaria (no voy a entrar en esos temas ahora)
que equivale a multiplicar por cuatro. Compara ese número con 0x3C (60 decimal), si es inferior o igual,
sustituye eax por 0x1E (30 decimal).
En resumen: eax = strlen(name)*4; ... if (eax >= 60) eax = 30;
Acto seguido vemos que pasa como argumentos el valor EAX y una cadena con números y letras.
Entramos en la call 0x401273
Vemos lo siguiente:
Código:
00401273 /$ 55 PUSH EBP
00401274 |. 8BEC MOV EBP,ESP
00401276 |. 56 PUSH ESI ; d2k2_crk.00401040
00401277 |. 57 PUSH EDI
00401278 |. 8B75 08 MOV ESI,[ARG.1] ; 1
0040127B |. 8B7D 0C MOV EDI,[ARG.2] ; 2
0040127E |. 0375 10 ADD ESI,[ARG.3] ; 3
00401281 |. EB 02 JMP SHORT d2k2_crk.00401285
00401283 |> AC /LODS BYTE PTR DS:[ESI]
00401284 |. AA |STOS BYTE PTR ES:[EDI]
00401285 |> 803E 00 CMP BYTE PTR DS:[ESI],0
00401288 |.^ 75 F9 \JNZ SHORT d2k2_crk.00401283 ; 4
0040128A |. 8B4D 10 MOV ECX,[ARG.3] ;5
0040128D |. 8B75 08 MOV ESI,[ARG.1] ;6
00401290 |. EB 03 JMP SHORT d2k2_crk.00401295
00401292 |> AC /LODS BYTE PTR DS:[ESI]
00401293 |. AA |STOS BYTE PTR ES:[EDI]
00401294 |. 49 |DEC ECX ; kernel32.7C80BDE6
00401295 |> 0BC9 OR ECX,ECX ; kernel32.7C80BDE6
00401297 |.^ 75 F9 \JNZ SHORT d2k2_crk.00401292 ;7
00401299 |. B0 00 MOV AL,0
0040129B |. AA STOS BYTE PTR ES:[EDI]
0040129C |. 5F POP EDI ; d2k2_crk.00401220
0040129D |. 5E POP ESI ; d2k2_crk.00401220
0040129E |. C9 LEAVE
0040129F \. C2 0C00 RETN 0C
Vamos traceando y vemos lo siguiente:
1. Pasa a esi el puntero a la cadena de números y letras (lamémosla cadena).
2. Pasa a edi el puntero a un buffer
3. Añade al puntero de la cadena el valor anterior de EAX. (4*8=32 en mi caso).
De modo que ahora la cadena apunta en vez de a "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
a cadena[32], "wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".
4. tracead este loop y comprobad que pasa al buffer (edi) ese trozo de cadena.
5. Pasa a ecx el valor anterior de EAX otra vez (0x20 o 32d, lo que queráis)
6. Carga otra vez la cadena en esi
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
7. este bucle termina copiando a la nueva cadena
"wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
lo que le faltaba de la inicial empezando por el principio, en otras palabras:
"wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789abcdefghijklmnopqrstuv"
"wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuv"
Yo he usado strcpy y strxfrm para hacer esto... lo veréis en el código. A esta cadena la vamos a llamar cadena2... acordaos de esto
CALL 2
Bueno ya no hace nada más hasta aquí, retornamos a la rutina principal... y
entramos a la siguiente call
00401149 |. E8 72000000 CALL d2k2_crk.004011C0
Vemos lo siguiente:
Código:
004011C0 /$ 55 PUSH EBP
004011C1 |. 8BEC MOV EBP,ESP
004011C3 |. 56 PUSH ESI
004011C4 |. 57 PUSH EDI
004011C5 |. FF75 10 PUSH [ARG.3] ; /String = "wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuv"
004011C8 |. E8 51010000 CALL <JMP.&kernel32.lstrlenA> ; \lstrlenA
004011CD |. 8BD8 MOV EBX,EAX
004011CF |. 8B75 08 MOV ESI,[ARG.1]
004011D2 |. 8B7D 0C MOV EDI,[ARG.2]
004011D5 |. 8A16 MOV DL,BYTE PTR DS:[ESI]
004011D7 |. C0C2 03 ROL DL,3
004011DA |. EB 16 JMP SHORT d2k2_crk.004011F2
004011DC |> AC /LODS BYTE PTR DS:[ESI]
004011DD |. 3206 |XOR AL,BYTE PTR DS:[ESI]
004011DF |. 02C2 |ADD AL,DL
004011E1 |. 02D0 |ADD DL,AL
004011E3 |. 52 |PUSH EDX
004011E4 |. 0FB6C0 |MOVZX EAX,AL
004011E7 |. 99 |CDQ
004011E8 |. F7F3 |DIV EBX
004011EA |. 8B45 10 |MOV EAX,[ARG.3]
004011ED |. 8A0402 |MOV AL,BYTE PTR DS:[EDX+EAX]
004011F0 |. AA |STOS BYTE PTR ES:[EDI]
004011F1 |. 5A |POP EDX ; 0012FC3C
004011F2 |> 803E 00 CMP BYTE PTR DS:[ESI],0
004011F5 |.^ 75 E5 \JNZ SHORT d2k2_crk.004011DC
004011F7 |. AC LODS BYTE PTR DS:[ESI]
004011F8 |. AA STOS BYTE PTR ES:[EDI]
004011F9 |. 5F POP EDI ; 0012FC3C
004011FA |. 5E POP ESI ; 0012FC3C
004011FB |. C9 LEAVE
004011FC \. C2 0C00 RETN 0C
Bien, hasta 004011DA va cargando en los registros, en esi un puntero al
nombre (en mi caso "FreeSoul"),
en EAX, la longitud de la famosa cadena2 (62d) (por cierto vaya programador... que llama a la función
strlen() para una cadena que siempre va a ser igual de larga... xD)
Llegados aquí entramos al bucle:
Código:
004011C0 /$ 55 PUSH EBP
004011C1 |. 8BEC MOV EBP,ESP
004011C3 |. 56 PUSH ESI
004011C4 |. 57 PUSH EDI
004011C5 |. FF75 10 PUSH [ARG.3] ; /String = "wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuv"
004011C8 |. E8 51010000 CALL <JMP.&kernel32.lstrlenA> ; \lstrlenA
004011CD |. 8BD8 MOV EBX,EAX ;; ebx = eax (longitud cadena)
004011CF |. 8B75 08 MOV ESI,[ARG.1]
004011D2 |. 8B7D 0C MOV EDI,[ARG.2] ; (antes de empezar el bucle)
004011D5 |. 8A16 MOV DL,BYTE PTR DS:[ESI] ; dl = rol name[0], 3
004011D7 |. C0C2 03 ROL DL,3
004011DA |. EB 16 JMP SHORT d2k2_crk.004011F2
004011DC |> AC /LODS BYTE PTR DS:[ESI] ; al = name[i]
004011DD |. 3206 |XOR AL,BYTE PTR DS:[ESI] ; al = al ^ name[i+1]
004011DF |. 02C2 |ADD AL,DL ; al += dl
004011E1 |. 02D0 |ADD DL,AL ; dl += al
004011E3 |. 52 |PUSH EDX ; var1 = edx
004011E4 |. 0FB6C0 |MOVZX EAX,AL
004011E7 |. 99 |CDQ
004011E8 |. F7F3 |DIV EBX ; edx = eax mod 0x3E
004011EA |. 8B45 10 |MOV EAX,[ARG.3]
004011ED |. 8A0402 |MOV AL,BYTE PTR DS:[EDX+EAX]
004011F0 |. AA |STOS BYTE PTR ES:[EDI] ; key[i] = cadena2[edx]
004011F1 |. 5A |POP EDX ; 0012FC3C ... edx = var1
004011F2 |> 803E 00 CMP BYTE PTR DS:[ESI],0
004011F5 |.^ 75 E5 \JNZ SHORT d2k2_crk.004011DC ; loop
004011F7 |. AC LODS BYTE PTR DS:[ESI]
004011F8 |. AA STOS BYTE PTR ES:[EDI]
004011F9 |. 5F POP EDI ; 0012FC3C
004011FA |. 5E POP ESI ; 0012FC3C
004011FB |. C9 LEAVE
004011FC \. C2 0C00 RETN 0C
vale... vemos que prepara en ebx la longitud de la cadena... (0x3E)
luego prepara el valor de dl (dl = rol name[0], 3),
luego hace un bucle dodne hace operaciones... (sumas, xor, mod),
y el resultado lo usa como índice en la cadena2 para guardar el valor
para explicarme mejor:
name -> nombre introducido
i -> contador del bucle
var1 -> variable donde guardaremos un dato
al -> parte del registro eax
dl -> parte del registro edx
key -> donde guardamos la nueva cadena...
cadena2 -> esto está claro jeje
... qué es mod? pues es simplemente el resto de dividir un número con otro
así 12 mod 7 = 5.
por fin... salimos de la función y volvemos a la rutina principal... vemos
que un puntero
a esa Key está en el registro ESI. El próximo paso es ver que hace con eso.
Código:
00401149 |. E8 72000000 CALL d2k2_crk.004011C0 ; salimos...
0040114E |. 8D75 80 LEA ESI,[LOCAL.32] ; <- Mueve la key, en mi
caso ASCII "alFGOyrr"
00401151 |. 8B7D 10 MOV EDI,[ARG.3] ; <- serial
00401154 |. 8B5D 0C MOV EBX,[ARG.2] ; <- name
y seguidamente vemos un pedazo de loop que impone pero q no es pa tanto xD
Código:
00401157 |. /EB 3E JMP SHORT d2k2_crk.00401197 ; entramos al loop
00401159 |> |0FB616 /MOVZX EDX,BYTE PTR DS:[ESI]
0040115C |. |0FB60F |MOVZX ECX,BYTE PTR DS:[EDI] ; aki abajo hay 1 call decisiva... donde se comparan valores
0040115F |. |8D85 00FFFFFF |LEA EAX,[LOCAL.64]
00401165 |. |50 |PUSH EAX ; /Arg3 = 0012F900
00401166 |. |51 |PUSH ECX ; |Arg2 = 7C80BDE6
00401167 |. |52 |PUSH EDX ; |Arg1 = 0012F906
00401168 |. |E8 B7000000 |CALL d2k2_crk.00401224 ; \d2k2_crk.00401224
0040116D |. |3A03 |CMP AL,BYTE PTR DS:[EBX]
0040116F |. |74 1D |JE SHORT d2k2_crk.0040118E ; Salto que nos libra del badboy
00401171 |. |6A 30 |PUSH 30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
00401173 |. |68 7A304000 |PUSH d2k2_crk.0040307A ; |Title = "Hey Cracker"
00401178 |. |68 6D304000 |PUSH d2k2_crk.0040306D ; |Text = "Wrong Serial"
0040117D |. |FF75 08 |PUSH [ARG.1] ; |hOwner = 002B03F4 ('diablo2oo2's Crackme#09',class='#32770')
00401180 |. |E8 87010000 |CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
00401185 |. |33C0 |XOR EAX,EAX
00401187 |. |5B |POP EBX
00401188 |. |5F |POP EDI
00401189 |. |5E |POP ESI
0040118A |. |C9 |LEAVE
0040118B |. |C2 0C00 |RETN 0C
0040118E |> |FF8D FCFEFFFF |DEC [LOCAL.65]
00401194 |. |46 |INC ESI
00401195 |. |47 |INC EDI
00401196 |. |43 |INC EBX
00401197 |> \83BD FCFEFFFF 00 CMP [LOCAL.65],0
0040119E |.^ 75 B9 \JNZ SHORT d2k2_crk.00401159 ; salto que nos manda a comprobar la siguiente letra...
004011A0 |. 6A 40 PUSH 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
004011A2 |. 68 93304000 PUSH d2k2_crk.00403093 ; |Title = "Hey Cracker"
004011A7 |. 68 86304000 PUSH d2k2_crk.00403086 ; |Text = "Serial is OK"
004011AC |. FF75 08 PUSH [ARG.1] ; |hOwner = 002B03F4 ('diablo2oo2's Crackme#09',class='#32770')
004011AF |. E8 58010000 CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
004011B4 |. B8 01000000 MOV EAX,1
004011B9 |. 5B POP EBX
004011BA |. 5F POP EDI
004011BB |. 5E POP ESI
004011BC |. C9 LEAVE
004011BD \. C2 0C00 RETN 0C
Se resume en un loop que va comparando letra por letra nuestro name con algo...
si detecta algún error tomamos el camino del bad boy... si no... tiramos hacia el goodboy
Vale... entremos a la call de una vez
CALL 3 - COMPROBACIÓN
Hay 3 calls... qué pereza no? bah que va, no son para tanto XD
Algunas no voy a explicarlas porque ya las hemos visto
Aunque llega la parte que quizás sea mas difícil de entender
Código:
00401224 /$ 55 PUSH EBP
00401225 |. 8BEC MOV EBP,ESP
00401227 |. 81C4 78FFFFFF ADD ESP,-88
0040122D |. 56 PUSH ESI
0040122E |. 57 PUSH EDI
0040122F |. 53 PUSH EBX
00401230 |. FF75 08 PUSH [ARG.1]
00401233 |. FF75 10 PUSH [ARG.3]
00401236 |. E8 67000000 CALL d2k2_crk.004012A2 ; 1
0040123B |. 8945 FC MOV [LOCAL.1],EAX ; guarda el valor generado (veremos abajo cómo lo genera)
0040123E |. FF75 FC PUSH [LOCAL.1]
00401241 |. 8D85 78FFFFFF LEA EAX,[LOCAL.34]
00401247 |. 50 PUSH EAX
00401248 |. FF75 10 PUSH [ARG.3]
0040124B |. E8 23000000 CALL d2k2_crk.00401273 ; 2
00401250 |. FF75 0C PUSH [ARG.2]
00401253 |. 8D85 78FFFFFF LEA EAX,[LOCAL.34]
00401259 |. 50 PUSH EAX
0040125A |. E8 43000000 CALL d2k2_crk.004012A2 3:
0040125F |. 8945 F8 MOV [LOCAL.2],EAX
00401262 |. 8B4D F8 MOV ECX,[LOCAL.2]
00401265 |. 8B45 10 MOV EAX,[ARG.3]
00401268 |. 0FB60401 MOVZX EAX,BYTE PTR DS:[ECX+EAX]
0040126C |. 5B POP EBX ; d2k2_crk.0040116D
0040126D |. 5F POP EDI ; d2k2_crk.0040116D
0040126E |. 5E POP ESI ; d2k2_crk.0040116D
0040126F |. C9 LEAVE
00401270 \. C2 0C00 RETN 0C
a.
Esta call devuelve a EDX un puntero a una cadena...
Código:
Veamos como se forma
004012A2 /$ 55 PUSH EBP
004012A3 |. 8BEC MOV EBP,ESP
004012A5 |. 8B55 08 MOV EDX,[ARG.1] ; edx -> cadena2
004012A8 |. 8B4D 0C MOV ECX,[ARG.2] ; ecx -> key[0]
004012AB |. 33C0 XOR EAX,EAX
004012AD |. EB 0A JMP SHORT d2k2_crk.004012B9
004012AF |> 380C10 /CMP BYTE PTR DS:[EAX+EDX],CL
004012B2 |. 75 04 |JNZ SHORT d2k2_crk.004012B8
004012B4 |. C9 |LEAVE
004012B5 |. C2 0800 |RETN 8
004012B8 |> 40 |INC EAX
004012B9 |> 803C10 00 CMP BYTE PTR DS:[EAX+EDX],0
004012BD |.^ 75 F0 \JNZ SHORT d2k2_crk.004012AF ; loop until
004012BF |. B8 FFFFFFFF MOV EAX,-1 ; cadena2[x] == key[i]
004012C4 |. C9 LEAVE
004012C5 \. C2 0800 RETN 8
el resumen es este:
Código:
Key[i]
hace un bucle donde va a comparar
Código:
cadena2[x]
Código:
key[i]
Código:
[LOCAL, 1]
vallamos a la siguiente call...
b.
Veamos esta call
Código:
00401273 /$ 55 PUSH EBP
00401274 |. 8BEC MOV EBP,ESP
00401276 |. 56 PUSH ESI
00401277 |. 57 PUSH EDI
00401278 |. 8B75 08 MOV ESI,[ARG.1] ; esi = &cadena2
0040127B |. 8B7D 0C MOV EDI,[ARG.2] ; edi = serial introducido
0040127E |. 0375 10 ADD ESI,[ARG.3] ; esi = cadena2[x] , sí, lo que
00401281 |. EB 02 JMP SHORT d2k2_crk.00401285 ; guardamos en [LOCAL, 1];
00401283 |> AC /LODS BYTE PTR DS:[ESI]
00401284 |. AA |STOS BYTE PTR ES:[EDI]
00401285 |> 803E 00 CMP BYTE PTR DS:[ESI],0
00401288 |.^ 75 F9 \JNZ SHORT d2k2_crk.00401283
0040128A |. 8B4D 10 MOV ECX,[ARG.3]
0040128D |. 8B75 08 MOV ESI,[ARG.1]
00401290 |. EB 03 JMP SHORT d2k2_crk.00401295
00401292 |> AC /LODS BYTE PTR DS:[ESI]
00401293 |. AA |STOS BYTE PTR ES:[EDI]
00401294 |. 49 |DEC ECX
00401295 |> 0BC9 OR ECX,ECX
00401297 |.^ 75 F9 \JNZ SHORT d2k2_crk.00401292
00401299 |. B0 00 MOV AL,0
0040129B |. AA STOS BYTE PTR ES:[EDI]
0040129C |. 5F POP EDI
0040129D |. 5E POP ESI
0040129E |. C9 LEAVE
0040129F \. C2 0C00 RETN 0C
Vale... tracead y comprobaréis que lo que hace es cortar la cadena2 desde
Código:
cadena2[x]
y a ese trozo de cadena le añade cadena2 desde el principio hasta
Código:
cadena2[x]
es decir, en mi caso hace lo siguiente:
"wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - "abcdefghijklmnopqrstuv"
"abcdefghijklmnopqrstuv" + "wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
llamemos a esta cadena3 xD
OOOOokei, todo bien, sigamos hasta la última call XD
c. ÚLTIMA CALL...
Código:
004012A2 /$ 55 PUSH EBP
004012A3 |. 8BEC MOV EBP,ESP
004012A5 |. 8B55 08 MOV EDX,[ARG.1] ; edx -> cadena2 /// cadena3
004012A8 |. 8B4D 0C MOV ECX,[ARG.2] ; ecx -> key[0] /// serial[0]
004012AB |. 33C0 XOR EAX,EAX
004012AD |. EB 0A JMP SHORT d2k2_crk.004012B9
004012AF |> 380C10 /CMP BYTE PTR DS:[EAX+EDX],CL
004012B2 |. 75 04 |JNZ SHORT d2k2_crk.004012B8
004012B4 |. C9 |LEAVE
004012B5 |. C2 0800 |RETN 8
004012B8 |> 40 |INC EAX
004012B9 |> 803C10 00 CMP BYTE PTR DS:[EAX+EDX],0
004012BD |.^ 75 F0 \JNZ SHORT d2k2_crk.004012AF ; loop until
004012BF |. B8 FFFFFFFF MOV EAX,-1 ; cadena3[x] == serial[i]
004012C4 |. C9 LEAVE
Os acordais de la 1º call??? pues esta es igual, pero en lugar de cadena2, hay cadena3 y en lugar de comparar con la letra de la key, ahora comparamos la letra del serial con el contador x hasta encontrar la letra que buscamos en cadena3...
Igual te parece todo esto un quebradero de cabeza... pero ahora lo explicaré de una forma más sencilla, salgamos de esta call.
...
Salimos y vemos lo que queda:
Código:
0040125A |. E8 43000000 CALL d2k2_crk.004012A2 ; <- hemos salido de aquí
0040125F |. 8945 F8 MOV [LOCAL.2],EAX
00401262 |. 8B4D F8 MOV ECX,[LOCAL.2]
00401265 |. 8B45 10 MOV EAX,[ARG.3]
00401268 |. 0FB60401 MOVZX EAX,BYTE PTR DS:[ECX+EAX] ; WoooOhh
0040126C |. 5B POP EBX
0040126D |. 5F POP EDI
0040126E |. 5E POP ESI
0040126F |. C9 LEAVE
00401270 \. C2 0C00 RETN 0C
vale, la función esta que tiene 3 subfunciones y que retorna a la principal, retorna
el valor de
Código:
cadena2[x]
Si conseguimos que este valor sea igual que
Código:
name[i]
Veamos la lógica:
x es un número resultado de buscar
Código:
name[i]
"wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuv" ... pues x daría 9
y
Código:
serial[i]
Código:
cadena3[x]
por lo tanto...
Código:
serial[0] = cadena3[9]
La primera letra de mi serial.... 'j'
Vamos haciendo el bucle con todas las letras hasta cosneguir el serial completo 'jgnoaqpg'
Te parecerá quizás imposible hacer un keygen... pero a la larga es más sencillo xD
Os dejo el código del keygen mío... adaptarlo y probadlo si queréis xD
Código:
char* CheckSum(HWND hWnd, char* name)
{
char* serial;
serial = new char[60];
char* key;
key = new char[60];
char something[63] =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
char* newsomething;
newsomething = new char[63];
int nlen, mlen;
nlen = strlen(name);
mlen = nlen*4;
if (mlen > 0x3C) mlen=0x1E;
int i; int a;
a = 63-mlen;
strxfrm(newsomething, &something[mlen], a);
char* nspart;
nspart = new char[64];
strxfrm(nspart, &something[0], mlen);
nspart[mlen]='\0';
strcat(newsomething, nspart);
char xdl, xal;
char xdl2;
int b;
xdl = name[0];
__asm {
push eax
mov eax, 00000000
mov al, xdl
rol al, 3
mov xdl, al
pop eax
}
for(i=0; i<nlen; i++)
{
xal = name[i];
b = i+1;
xal = xal ^ name[b];
xal += xdl;
xdl += xal;
xdl2 = xdl;
__asm {
pushad
xor eax, eax
xor ebx, ebx
mov al, xal
mov bl, 03Eh
xor edx, edx
div ebx
mov xdl, dl
popad
}
xal = newsomething[xdl];
key[i] = xal;
xdl = xdl2;
}
key[nlen] = 0;
char *newsom;
newsom = new char[64];
int j;
char ch = 0;
for (i=0; i<nlen; i++)
{
/////j = loop until newsomething[j] == algo[i]
j = 0;
while(newsomething[j] != key[i]) j++;
j;
///edi = newsomething[j-final]
a = 63-j;
strxfrm(newsom, &newsomething[j], a);
///edi -> strcat newsomething[0-j]
///edx = edi
strcpy(nspart, newsomething);
nspart[j] = 0;
strcat(newsom, nspart);
/*
j es un numero al buscar name[i] dentro de edx
serial[i] debe corresponder con newsomething[j]
...
loop until edx[j] == serial[i]
letter = newsomething[j] // letter must = name[i]
*/
j = 0;
while(newsomething[j] != name[i]) j++;
serial[i] = newsom[j];
serial[nlen] = 0;
}
return serial;
}
Espero que alguien se lea todo esto y que le sirva de algo... cualquier duda preguntadme
Un saludo !!!