ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» º Keygen de TwinExplorer º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ niveau : Bah on va voir ~~~~~~~~~~~~~~~~~~~~~~~~ GOGOGO. Bon on regarde le prog d'un peu plus pret. A premiere vue il a l'air keygenable. Y a un gros bouton order en haut a doite. Quand on clique dessus on se retrouve sur une boite de dialogue qui permet de mettre un nom et un serial. Bah on aller jetter un coup d'oeil la dessus. Si on met un mauvais nom/serial, le programme l'efface tout simplement sans rien dire de plus. On va pas trainer (j'ai pas que ca a foutre moi ;), on place un: bpx hmemcpy sous softice evidemment (tiens en passant j'ai essaye TRW2000 mais je suis pas enchante par ce debugger ;) Bon avant de placer ce Breakpoint on a mit un nom et un serial bidon. Maintenant y a plus qu'a cliquer sur "OK" et a matter ce qui se passe. Voyons voyons. Deja mauvais point, le programme break plus de 2 fois. Il va donc falloir trier un peu pour savoir quel call demande la lecture du nom et du serial. En mattant un peu on trouve tres vite. Voila un apercu vu sous wdasm (hehe la je viens de me rendre compte qu'il est packe aspack et que j'ai plus l'unpacker de Lutin_Noir sur moi ;) Le dump sera donc vu de softice c'te flemme que j'ai ! allez merde je le dump et je le donne vu de dasm ! Donc voila le code apres un petit dump avec procdump et quelques modif des sections (il faut les mettre en read/write/exec soit characteristics E0000020) La je viens de me rendre compte que j'avais laisse un bpx donc j'ai un joli CC dans le dump, tout a refaire ;( crise de nerfs ! Bon voila enfin ce que ca donne quand on deconne pas: :004D1DA2 E84DD4F5FF call 0042F1F4 <<<< choppe le serial :004D1DA7 8B85F8FEFFFF mov eax, dword ptr [ebp+FFFFFEF8] <<<< eax pointe le serial :004D1DAD 8D95FCFEFFFF lea edx, dword ptr [ebp+FFFFFEFC] :004D1DB3 E87065F3FF call 00408328 :004D1DB8 8B95FCFEFFFF mov edx, dword ptr [ebp+FFFFFEFC] :004D1DBE 8BC6 mov eax, esi :004D1DC0 E85FD4F5FF call 0042F224 :004D1DC5 8D95F8FEFFFF lea edx, dword ptr [ebp+FFFFFEF8] :004D1DCB 8B8300030000 mov eax, dword ptr [ebx+00000300] :004D1DD1 E81ED4F5FF call 0042F1F4 :004D1DD6 8B85F8FEFFFF mov eax, dword ptr [ebp+FFFFFEF8] :004D1DDC E8FF1FF3FF call 00403DE0 <<<< (1) :004D1DE1 83F805 cmp eax, 00000005 :004D1DE4 7C21 jl 004D1E07 :004D1DE6 8D95F8FEFFFF lea edx, dword ptr [ebp+FFFFFEF8] :004D1DEC 8B8304030000 mov eax, dword ptr [ebx+00000304] :004D1DF2 E8FDD3F5FF call 0042F1F4 :004D1DF7 8B85F8FEFFFF mov eax, dword ptr [ebp+FFFFFEF8] :004D1DFD E8DE1FF3FF call 00403DE0 <<<< (2) :004D1E02 83F808 cmp eax, 00000008 :004D1E05 7D1F jge 004D1E26 Voila le debut. Apres notre bpx hmemcpy en remontant avec F12 on tombe la dessus. Le premier call choppe le serial, comment je le sait vous allez me dire. Bah regardez juste en dessous, vous avez un "mov eax, dword ptr [ebp+FFFFFEF8]" et bien en faisant un bouton droit->display sur eax on se retrouve nez a nez avec notre serial. Passons a la suite. En sortie du call repere par (1) eax contient "6" ! Mais oui 6 c'est le nombre de lettre de "TiPiaX" (c'est le nom que j'avais entre). A en juger par le saut conditionnel qui suit, le nom ne doit pas etre inferieur a 5. Le nom doit donc etre superieur ou egal a 5. En sortie du call repere par (2) eax contient "4". Hum , bah ca c'est le nombre de lettres de notre serial. Et d'apres le saut qui suit le serial doit etre superieur ou egal a 8 lettres. Voila de precieux renseignements, non ? Bon continuons. On reprend le programme mais cette fois ci on rentre un serial de plus de 8 lettres. Par exemple "1234567891" fera l'affaire. Puis on fait OK. Hehe une jolie boite de dialogue vient nous dire que le serial n'est pas valide, c'est deja mieux non ? Et en plus il fout notre nom en majuscule. On sait donc qu'il doit etre en majuscules ;) (on fera ca directement dans les options de l'edit box dans le keygenerator...) Maintenant qu'on a pas mal d'infos, partons a la peche au serial ;) On trace un peu avec F10, et on passe par dessus pleins de call (ca pue le delphi ou le c++ builder ca, ca pue le borland quoi...) Puis on arrive sur le JNZ fatal: :004D1EDA 8D85FCFEFFFF lea eax, dword ptr [ebp+FFFFFEFC] :004D1EE0 8D9500FFFFFF lea edx, dword ptr [ebp+FFFFFF00] :004D1EE6 E8991EF3FF call 00403D84 :004D1EEB 8B95FCFEFFFF mov edx, dword ptr [ebp+FFFFFEFC] :004D1EF1 58 pop eax :004D1EF2 E8F91FF3FF call 00403EF0 :004D1EF7 0F8502010000 jne 004D1FFF Ouais je sais, sous dasm ca donne un jne pas un jnz mais c'est la meme chose. La c'est tres simple, si le saut a lieu on a la mauvaise boite de dialogue. Maintenant allez dessus et faites "R FL Z" pour inverser les conditions de saut. Et la miracle ! Thank You et patati et patata hehe. C'est bien beau mais ca nous avance pas des masses car nous on veut pas un crack on veut un keygenerator. Le pire c'est qu'il n'y a pas de conditions testees avant le saut. Va donc falloir aller voir dans le call juste au dessus: :00403EF0 53 push ebx :00403EF1 56 push esi :00403EF2 57 push edi :00403EF3 89C6 mov esi, eax :00403EF5 89D7 mov edi, edx :00403EF7 39D0 cmp eax, edx :00403EF9 0F848F000000 je 00403F8E :00403EFF 85F6 test esi, esi :00403F01 7468 je 00403F6B :00403F03 85FF test edi, edi :00403F05 746B je 00403F72 :00403F07 8B46FC mov eax, dword ptr [esi-04] // mov eax, 0A :00403F0A 8B57FC mov edx, dword ptr [edi-04] // mov edx, 0F :00403F0D 29D0 sub eax, edx // EAX = :00403F0F 7702 ja 00403F13 :00403F11 01C2 add edx, eax * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00403F0F(C) | :00403F13 52 push edx :00403F14 C1EA02 shr edx, 02 :00403F17 7426 je 00403F3F * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00403F35(C) | :00403F19 8B0E mov ecx, dword ptr [esi] // esi pointe le serial :00403F1B 8B1F mov ebx, dword ptr [edi] // edi pointe un truc :00403F1D 39D9 cmp ecx, ebx // bizarre :00403F1F 7558 jne 00403F79 // on les compare :00403F21 4A dec edx :00403F22 7415 je 00403F39 :00403F24 8B4E04 mov ecx, dword ptr [esi+04] :00403F27 8B5F04 mov ebx, dword ptr [edi+04] :00403F2A 39D9 cmp ecx, ebx :00403F2C 754B jne 00403F79 :00403F2E 83C608 add esi, 00000008 :00403F31 83C708 add edi, 00000008 :00403F34 4A dec edx :00403F35 75E2 jne 00403F19 :00403F37 EB06 jmp 00403F3F * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00403F22(C) | :00403F39 83C604 add esi, 00000004 // prochain DWORD :00403F3C 83C704 add edi, 00000004 // prochain DWORD * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:00403F17(C), :00403F37(U) | :00403F3F 5A pop edx :00403F40 83E203 and edx, 00000003 :00403F43 7422 je 00403F67 :00403F45 8B0E mov ecx, dword ptr [esi] // on refait :00403F47 8B1F mov ebx, dword ptr [edi] // "" :00403F49 38D9 cmp cl, bl :00403F4B 7541 jne 00403F8E :00403F4D 4A dec edx :00403F4E 7417 je 00403F67 :00403F50 38FD cmp ch, bh :00403F52 753A jne 00403F8E :00403F54 4A dec edx :00403F55 7410 je 00403F67 :00403F57 81E30000FF00 and ebx, 00FF0000 :00403F5D 81E10000FF00 and ecx, 00FF0000 :00403F63 39D9 cmp ecx, ebx :00403F65 7527 jne 00403F8E * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:00403F43(C), :00403F4E(C), :00403F55(C) | :00403F67 01C0 add eax, eax :00403F69 EB23 jmp 00403F8E * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00403F01(C) | :00403F6B 8B57FC mov edx, dword ptr [edi-04] :00403F6E 29D0 sub eax, edx :00403F70 EB1C jmp 00403F8E * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00403F05(C) | :00403F72 8B46FC mov eax, dword ptr [esi-04] :00403F75 29D0 sub eax, edx :00403F77 EB15 jmp 00403F8E * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:00403F1F(C), :00403F2C(C) | :00403F79 5A pop edx :00403F7A 38D9 cmp cl, bl :00403F7C 7510 jne 00403F8E :00403F7E 38FD cmp ch, bh :00403F80 750C jne 00403F8E :00403F82 C1E910 shr ecx, 10 :00403F85 C1EB10 shr ebx, 10 :00403F88 38D9 cmp cl, bl :00403F8A 7502 jne 00403F8E :00403F8C 38FD cmp ch, bh // la comparaison * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:00403EF9(C), :00403F4B(C), :00403F52(C), :00403F65(C), :00403F69(U) |:00403F70(U), :00403F77(U), :00403F7C(C), :00403F80(C), :00403F8A(C) | :00403F8E 5F pop edi :00403F8F 5E pop esi :00403F90 5B pop ebx :00403F91 C3 ret Cette routine bien longue ne fait que comparer ce qui est pointe par ESI et ce qui est pointe par EDI. C'est a dire qu'il compare le bon au mauvais serial. En faisant un display sur EDI on trouve ceci : "HPNGUVPLYLWJTED". Et oui ! c'est le bon serial. (testez le en faisant gaffe a inverser le saut pour pas etre enregistre sinon on pourra plus chercher la routine qui genere le serial). Bon on a fait le serial fishing, maintenant trouvons où est genere ce serial. Le bon serial est place en 00CDAE0. faisons donc "e 00CDAE0" puis refaisons la manip avec un nom different. Puis on trace jusqu'a voir apparaitre le bon serial a cet endroit. Bingo c'est dans le call en 004D1EE6. Juste le call avant la verification du serial ;). Mais on se rend compte que ce n'est que la copie de ce serial et qu'il est genere avant. On trouve donc la generation du serial apres le call en 004D1EBD. Et voila donc l'algo: ----------------------------------------------------------------------- :004D21DC 0FB63E movzx edi, byte ptr [esi] <<< edi = lettre du nom :004D21DF 8B45F8 mov eax, dword ptr [ebp-08] :004D21E2 0FB64418FF movzx eax, byte ptr [eax+ebx-01] <<< EAX pointe une table :004D21E7 6603F8 add di, ax <<"GR84M5LSDdpKevd" | :004D21EA B8B4224D00 mov eax, 004D22B4 :004D21EF 0FB64418FF movzx eax, byte ptr [eax+ebx-01] <<"ABCDEFGHJKLMNPQRTUVWXYZ" | :004D2218 B8CC224D00 mov eax, 004D22CC <<< eax pointe la chaine :004D221D 8A1410 mov dl, byte ptr [eax+edx] <<< modifie dl. :004D2220 8D85ECFBFFFF lea eax, dword ptr [ebp+FFFFFBEC] :004D2226 885001 mov byte ptr [eax+01], dl :004D2229 C60001 mov byte ptr [eax], 01 :004D222C 8D95ECFBFFFF lea edx, dword ptr [ebp+FFFFFBEC] :004D2232 8D85F8FDFFFF lea eax, dword ptr [ebp+FFFFFDF8] :004D2238 E84308F3FF call 00402A80 <<< fo aller regarder :) :004D223D 43 inc ebx <<< prochaine lettre :004D223E 46 inc esi <<< prochaine lettre :004D223F 83FB10 cmp ebx, 00000010 <<< fini ? :004D2242 7598 jne 004D21DC <<< non ! on boucle ----------------------------------------------------------------------- On remarque que le champ qui sert a generer le serial est un peu modifie. Au lieu d'un simple "TiPiaX" on a "TiPiaXTiPiaXTiP" soit 15 lettres. Allons voir ce qui se passe dans le petit call: Bah je vais pas vous coller le code. Suffit de regarder un peu comment ca fonctionne et on voit que le call ne fait que copier la valeur de BL dans le tableau contenant le serial. Petit recapitulatif: Le prog choppe une lettre. Il joue avec la valeur de celle ci en l'ajoutant a quelques valeurs choppees dans une table. Ensuite il obtient donc une valeur qui va lui servir d'index pour aller "piocher" la bonne lettre dans la chaine "ABCDEFGHJKLMNPQRTUVWXYZ". Et voila, le prog fout chaque valeur piochee les unes a la suite des autres et ca donne le serial ;))))) ----------------------------------------------------------------------- Passons a l'ecriture du keygen. (copier coller powaaaahhhh ou presque) Tout d'abord il faut copier le nom comme je viens de vous le dire: (ps: la boite d'edition ne permet pas de mettre plus de 25 caracteres, il faut en tenir compte aussi) nom db 100 dup (0) newnom db 20 dup (0) taille dd 0 pushad invoke GetDlgItemText, hwnd, IDC_NAME, offset nom, 100 mov taille,eax cmp eax, 5 jl tooshort cmp eax, 25 jg toolong ;generate the code ;------------------- mov ecx, 15 lea edi, newnom on_recopie_encore: lea esi, nom copie: mov al, byte ptr [esi] test al, al je on_recopie_encore mov byte ptr [edi], al dec ecx test ecx, ecx je keygennow inc edi inc esi jmp copie keygennow: A partir de la on a une chaine du style "TiPiaXTiPiaXTiP" en newnom. Maintenant il faut generer le serial. la variable "index" permet de se deplacer dans le buffer contenant le futur serial (j'ai utilise quasiment tous les registres alors je passe aux variables...) Table1 db "061602v2",02Eh,"8TWINXSTD",0 Table2 db "GR84M5LSDdpKevd",0 Table3 db "ABCDEFGHJKLMNPQRTUVWXYZ",0 index dd 0 serial db 100 dup (0) ;on commence par initialiser les trucs qui ont besoin de l'etre xor ebx, ebx mov index, 0 lea esi, newnom boucle: movzx edi, byte ptr [esi] movzx eax, byte ptr [ebx+Table1] add di, ax movzx eax, byte ptr [ebx+Table2] add di, ax add di, 031h add di, 036h movsx eax, di mov ecx, 017h cdq idiv ecx lea eax, Table3 mov dl, [edx+eax] ;maintenant qu'on a "pioche" on met la valeur de bl dans le buffer du nouveau ;serial. Index permettant de savoir où on en est. lea edi, serial add edi, index mov byte ptr [edi], dl inc index inc esi inc ebx cmp ebx, 15 jnz boucle ;puis on affiche le resultat: ;end of keygen ;--------------- invoke SetDlgItemText,hwnd,IDC_SERIAL,offset serial popad ret ----------------------------------------------------------------------- Et voila un keygenerator qui fonctionne nikel. On fait une jolie interface graphique pour lui avec visual c++. On obtient un joli fichier .res. Ensuite on n'a plus qu'a compiler ca sous Masm comme ceci: c:\masm32\bin\ml /c /coff /Cp keygen.asm c:\masm32\bin\link /SUBSYSTEM:WINDOWS /LIBPATH:c:\masm32\lib keygen.obj keygen.res ps: changez le chemin en fonction de l'endroit où vous avez Masm sur votre disque dur. Bon je me dis que je vais le tester quand meme. Je rentre les infos et tout, nikel ca marche. ALors je redemarre le programme et la, malheur ! c'est pas bon ! On est pas enregistre. J'ai jamais vu ca j'hallucine. J'augmente mon horloge de PC d'un mois et le programme redemarre, alors on a plus qu'a tester. Il nous demande nom et serial et la bah ca marche plus ! on a du faire une erreur, je pense qu'on a du se servir d'une valeur comme ci elle etait constante alors qu'elle ne l'est pas. Je pense que ca vient de la Table1. En effet en tracant on se rend compte qu'elle est devenue: Table1 db "061602v2",02Eh,"8TWINXSTD",0 <<< avant Table1 db "071602v2",02Eh,"8TWINXSTD",0 <<< apres Je vous avouerais que la j'ai du mal a l'expliquer ! Le nom n'a pas change et le serial de sortie est different. Sans doute un bug du programmeur ?! Enfin si c'est pas un bug ca doit etre tres subtil je pense. J'ai pose quelques bpr sur cette valeur mais ca me donne rien expliquant cette difference. On change un peu la keygen alors en mettant cette nouvelle table. Il semblerait que ca fonctionne nikel. C'est a croire que les programmeurs sont cons de nos jours ;) Bon bah voila pour ce tutorial. TiPiaX - hccc@caramail.com