Título: He vuelto... y con un tuto :) Publicado por: frankener1986 en 7 Enero 2009, 19:31 pm Hola a todos!!! Mil años después de mi último post estoy aquí de nuevo jejeje No he tenido tiempo de estar mucho conectado, pero bueno, en ese tiempo he aprendido bastante xD Le doy un saludo a Karmany que veo que sigue por estos barrios xD
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 (http://www.2shared.com/file/4598721/7b08488/d2k2crkme09.html?) - Keygen (http://www.2shared.com/file/4614639/ed80d11b/d2k2solve.html) (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] es el valor de la key que estemos comprobando ahora... la primera en mi caso es 'a' de "alFGOyrr"hace un bucle donde va a comparar Código: cadena2[x] (llamemos al contador X) con Código: key[i] y el valor de esa X es el que retorna la función y podemos apreciar arriba que lo guarda en 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] (la x la obtuvimos en el call anterior) hasta el final...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] , sí, el último x obtenido jeje...Si conseguimos que este valor sea igual que Código: name[i] para todas las i (osea, letras xD), iremos al GoodBoyVeamos la lógica: x es un número resultado de buscar Código: name[i] (pongamos 'F' como ejemplo) dentro de cadena2"wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuv" ... pues x daría 9 y Código: serial[i] debe ser igual a Código: cadena3[x] "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"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 :D Un saludo !!! :D Título: Re: He vuelto... y con un tuto :) Publicado por: Amerikano|Cls en 8 Enero 2009, 00:52 am Muy buen aporte, y que bueno que regreses :)
Título: Re: He vuelto... y con un tuto :) Publicado por: frankener1986 en 12 Enero 2009, 15:26 pm ni 1 duda ni 1 opinion? XD
Título: Re: He vuelto... y con un tuto :) Publicado por: karmany en 13 Enero 2009, 09:57 am Bienvenido de nuevo.
Muchas gracias por el tute y keygen, realmente muy bien trabajado. Encontrar la rutina nombre-serial puede resultar una labor tediosa y más después explicarlo en un tute... Muchísimas gracias por la aportación. Un saludo karmany |