CoDe_InSiDe Crackme #10
By MiNoS
Bon, on perd pas de temps, on remplit les
champs nom / sérial, on pose un bpx
GetDlgItemTextA, et SI break dès que l'edit du
nom ou du sérial n'est plus actif. Un petit coup de F12, et on est dans le
crackme, on retient l'adresse (401068), et on sort de SI. A peine sorti,
ça break à nouveau. Après un F12, on arrive en 40841B (c'est juste après
le call qui récupère le sérial). On trace, et là aussi, on retient
l'adresse (401185). Avant d'aller plus loin, on se décide à aller faire un
tour sous W32Dasm pour voir ça de plus près. Malheureusement, W32Dasm n'apprécie guère les plaisanteries de CoDe InSiDe, et c'est avec un "Cannot Allocate File Buffer Memory" que l'on est accueilli ! Pas de panique, on ouvre le crackme avec un éditeur hexa, et on regarde de plus près le PE File Header : 00000080 5045 0000 4C01 0500 0000 0000 0000 0000 PE..L........... 00000090 0000 0000 F000 0F01 ........ C'est pas beau tout ça ! Le 00F0 représente la
taille de l'Optional Header. Habituellement, cette taille est de 224
octets (00E0h), mais ici, elle est de 240 octets (00F0h). Il y a donc 10h
octets de trop. Bien que ceci ne dérange pas Windows (du moment que la
taille indiquée est égale à la taille réelle), W32Dasm n'a pas l'air
d'aimer ce genre de modifications. On va donc corriger ceci. Maintenant que l'on peut utiliser W32Dasm, on va pas s'en priver : :00401050 push 00000100 :00401055 push 0040A000 :0040105A push 000003E8 :0040105F push [ebp+08] * Reference To: USER32.GetDlgItemTextA, Ord:0000h | :00401062 Call dword ptr [00401D60] :00401068 pop ebp :00401069 mov dword ptr [00401F00], eax Ici, on a la routine qui récupère notre nom. Celui-ci sera donc stocké en 40A000 et le nombre de caractères du nom sera stocké en 401F00. Allons voir ce qui se trouve en 401185 : :00401185 mov eax, dword ptr [00401F10] < nbre de char du sérial :0040118A cmp al, 00 < on a entré un sérial ? :0040118C jne 0040118F < non, :0040118E ret < au revoir < sinon, on continue * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040118C(C) | :0040118F push eax :00401190 pop ecx < ecx = nbre de char du sérial :00401191 mov eax, dword ptr [00401F00] < eax = nbre de char du nom :00401196 cmp ecx, eax < le sérial est - long que le nom ? :00401198 jb 0040119C < oui ---> bye bye :0040119A jmp 0040119D < non, on continue * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401198(C) | :0040119C ret * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040119A(U) | :0040119D mov edi, 0040A100 < edi pointe sur le sérial :004011A2 mov ebx, 00408000 < tien tien :004011A7 xor eax, eax < les registres sont :004011A9 xor ecx, ecx remis à 0 :004011AB xor edx, edx J'espère que les commentaires sont assez explicites et que tout le
monde comprendra. Ici, ça commence à se compliquer, car en 408000, on
trouve une chaine qui est dérivée du nom. * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004010D1(U) | :0040109F mov al, byte ptr [edi+00002000] < prend un char du nom :004010A5 cmp al, 00 < il reste des chars ? :004010A7 je 004010D3 < non, on s'en va :004010A9 imul eax, 00000043 < sinon, eax = eax * 43h :004010AC lea edx, dword ptr [eax+4*eax]< edx = 5 * eax :004010AF add edx, eax < edx = edx + eax :004010B1 push eax < save eax :004010B2 xor eax, eax < eax = 0 :004010B4 push edx < save edx :004010B5 xchg eax,edx < échange eax et edx :004010B6 xor ecx, ecx < ecx = 0 :004010B8 mov cl, 0A < ecx = 0Ah :004010BA idiv ecx < edx = eax mod ecx :004010BC pop eax < eax = ancienne valeur de edx :004010BD imul eax, edx < eax = eax * edx :004010C0 push eax < save eax :004010C1 xor eax, eax < eax = 0 :004010C3 imul edx, esi < edx = edx * esi :004010C6 xchg eax,edx < échange eax et edx :004010C7 pop edx < edx = ancienne valeur de eax :004010C8 xor dl, al < dl = dl xor al :004010CA add edx, 00000070 < edx = edx + 70h :004010CD mov byte ptr [edi], dl < on écrit un char :004010CF dec esi < esi = esi - 1 :004010D0 inc edi < char suivant :004010D1 jmp 0040109F < retour au début Je sais pas si vous avez remarqué, mais ici, on a 3 push, et seulement 2 pop. On verra plus loin ce que deviennent les valeurs d'eax stockées dans la pile. Je crois que le keygen va pas être des plus facile ! Et comme si on avait pas assez de problèmes comme ça, il faut qu'un esi se pointe dans cette routine. Hé oui, il est bien gentil, mais il nous a pas dit sa valeur ;-). On va donc chercher un peu avant voir si on trouve quelque chose : :00401092 call 004010DA < on rentre dans le call :004010DA xor eax, eax < eax = 0 :004010DC mov edi, 00408000 :004010E1 mov ecx, 000003C0 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004010EC(C) < on rajoute 4 * 3C0h octets (00h) | à partir de l'@ 408000 :004010E6 mov dword ptr [edi], eax :004010E8 add edi, 00000004 :004010EB dec ecx :004010EC ne 004010E6 :004010EE mov eax, dword ptr [00401F00]< enfin ! :004010F3 ret :00401097 lea edi, dword ptr [00408000] :0040109D mov esi, eax < esi = eax Esi sera donc égal au nombre de caractères du nom
(contenu en 401F00). On remarque en passant que des 0 sont ajoutés a
partir de 408000. * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004011C7(U) | :004011AD mov cl, byte ptr [edi] < prend 1 char du sérial :004011AF cmp ecx, 00000000 < il reste des char ? :004011B2 je 004011C9 < non, alors on saute * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004011BC(U) | :004011B4 mov al, byte ptr [ebx] < prend 1 char du nom modifié :004011B6 cmp al, 00 < il reste des char ? :004011B8 jne 004011BE < oui, on saute :004011BA xor bl, bl < non, on remet bl à 0 :004011BC jmp 004011B4 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004011B8(C) | :004011BE imul eax, ecx < eax = eax * ecx :004011C1 add edx, eax < edx = edx + eax :004011C3 inc ebx < char suivant (de la chaine) :004011C4 inc edi < char suivant (du sérial) :004011C5 xor eax, eax < eax = 0 :004011C7 jmp 004011AD < on revient * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004011B2(C) | :004011C9 push edx :004011CA pop eax < eax = edx :004011CB imul eax, 65446F43 < eax = eax * 65446F43h :004011D1 xor edx, edx < edx = 0 :004011D3 push eax :004011D4 mov eax, dword ptr [00408300] < c'est quoi ça encore ? :004011D9 pop ecx < ecx = ancienne valeur de eax :004011DA xor eax, ecx < eax = ecx ? :004011DC je 00401234 < oui, on saute :004011DE pushad < save des registres Ici, les ennuis continuent. En effet, le mov eax, dword ptr [00408300] pose problème. On revient donc sous W32Dasm, et on fait une recherche sur [00408300], on remonte un peu dans le listing, et voici ce que l'on obtient : * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004010A7(C) | :004010D3 mov eax, dword ptr [00401F00] < eax = nbre de char du nom :004010D8 jmp 004010F4 | | {coupé} | * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004010D8(U) | :004010F4 mov edi, 00408200 < il n'y a que des 0 à partir de 408200 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004010FF(C) | :004010F9 pop dword ptr [edi] :004010FB add edi, 00000004 :004010FE dec eax :004010FF jne 004010F9 Je vais expliquer le bloc en rouge plus en détail. Vous vous souvenez des 3 push et des 2 pop ? Ben ici, on va récupérer les valeur qui sont encore dans la pile. On a n push de retard avec n le nbre de char du nom. Je vous donne un petit exemple avec mon nom : 0030:00408200 B9 15 00 00 0D 1D 00 00 6A 14 00 00 7B 1B 00 00 ;.......j...{... 0030:00408210 27 14 . En rouge, les valeurs qui étaient stockées dans la pile. On continue donc : :00401101 mov eax, dword ptr [00401F00] < eax = nbre de char du nom :00401106 push eax :00401107 imul eax, 00000004 < eax = eax * 4 :0040110A sub edi, eax < on revient au début des valeurs :0040110C pop eax :0040110D mov esi, eax < esi = nbre de char du nom :0040110F xor eax, eax < eax = 0 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401117(C) | :00401111 add eax, dword ptr [edi] < ajoute la valeur contenue dans edi :00401113 add edi, 00000004 < valeur suivante :00401116 dec esi < il reste des valeurs ? :00401117 jne 00401111 < oui, on boucle :00401119 imul eax, 436F4465 < eax = eax * 436F4465h :0040111F mov dword ptr [00408300], eax < enfin ! Bon, maintenant que l'on sait ce qui se trouve à l'adresse 408300, on peut continuer là où on s'était arrété : * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401232(U) | :004011DF call 004011E4 * Referenced by a CALL at Address: |:004011DF | < cette routine vérifie si l'on a patché ou pas le je 00401234 de l'@ 4011DC :004011E4 pop ebp :004011E5 cmp byte ptr [ebp-08], 75 :004011E9 je 004011F9 :004011EB cmp byte ptr [ebp-08], EB :004011EF je 004011F9 :004011F1 cmp byte ptr [ebp-08], 74 :004011F5 jne 004011F9 :004011F7 jmp 0040121D < aucun patch, on continue * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:004011E9(C), :004011EF(C), :004011F5(C) | :004011F9 popad < sinon, bad boy * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:0040123F(U), :00401298(U) | :004011FA push ebp :004011FB mov ebp, esp :004011FD push 00000000 * Possible StringData Ref from Code Obj ->"Please" | :004011FF push 00401ED0 * Possible StringData Ref from Code Obj ->"Don't patch the file =)" | :00401204 push 00401C00 :00401209 push [ebp+08] * Reference To: USER32.MessageBoxA, Ord:0000h | :0040120C Call dword ptr [00401D5C] :00401212 pop ebp :00401213 ret * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040121E(U) | :00401214 mov eax, dword ptr [00401F20] < registered flag dans eax :00401219 test al, al < c'est bon ou pas ? :0040121B jmp 00401220 < la suite après le saut ;-) * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004011F7(U) | :0040121D popad < restaure les registres :0040121E jmp 00401214 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040121B(U) | :00401220 test al, al < et si on retestait ? :00401222 jne 00401225 < si al = 1, c'est bon :00401224 ret < sinon au revoir * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401222(C) | :00401225 jmp 00401240 < un petit peu de CCA ! ;-) * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040123D(U) | :00401227 xor eax, eax < eax = 0 :00401229 inc eax < eax = 1 :0040122A mov dword ptr [00401F20], eax < flag registered à true ;-) :0040122F xor eax, eax < eax = 0 :00401231 pushad < save des registres :00401232 jmp 004011DF < et on va vers les vérifs * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004011DC(C) | :00401234 mov eax, dword ptr [00401F20] < eax = flag registered :00401239 cmp al, 00 < al = 0 ? :0040123B jne 0040123F < oui, on continue :0040123D jmp 00401227 < sinon ---> bad boy * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040123B(C) | < code polymorphe :0040123F jmp 004011FA :00401241 lock :00401242 push ds :00401243 inc eax :00401244 BYTE 0 :00401245 push ebp :00401246 mov ebp, esp :00401248 push 00000000 :0040124A push ecx < ecx pointe sur "Greet !!!" * Possible StringData Ref from Code Obj ->"You did it !!! =)" | :0040124B push 00401C18 :00401250 push [ebp+08] * Reference To: USER32.MessageBoxA, Ord:0000h | :00401253 Call dword ptr [00401D5C] Vive le code spaghetti ; je viens de passer 1/4
d'heure pour comprendre comment ça fonctionnait ! J'espère que les
couleurs et les commentaires vous aiderons une fois de plus à comprendre,
car ce passage n'est pas des plus simples. on avait : on aura (après le jmp 00401240) : :0040123F EBB9 jmp 004011FA :0040123F EB BYTE EB :00401241 F0 lock :00401240 B9F01E4000 mov eax, 00401EF0 :00401242 1E push ds :00401243 40 inc eax :00401244 00 BYTE 0 On va résumer un peu tout ça pour y voir plus clair :
Ce résumé et bien entendu très simplifié, mais je pense qu'il contient l'essenciel. Bon, maintenant qu'on est lancé, on va s'attaquer au keygen. Autant vous le dire tout de suite, si vous n'avez pas tout compris à ce que l'on vient de faire, relisez, car la partie keygen n'est vraiment pas facile. La première idée que j'ai eu était de calculer la
valeur correspondant au eax du xor eax, ecx
(donc en passant par imul eax, 65446F43), et ensuite
de remonter au ecx du xor eax, ecx (en divisant la valeur obtenue par 436F4465). C'était même pas la
peine d'y penser ! Si la valeur correspondant à notre nom dépasse
seulement 2, eax dépassera FFFFFFFFh, et donc va être tronqué. Si l'on
obtient 0012451Fh à la place de 12E0012451Fh, on va quand même pas
considérer que c'est pareil ! Donc, on oublie ... | i * 65446F43h = x | j * 436F4465h = x Encore une chose avant de coder ce premier bruteforce, si on regarde bien la routine de génération du eax du xor eax, ecx, on trouve en 004010A9 imul eax, 00000043, c'est à dire que j devra être divisible par 43h. On va donc faire un brute forcer 2 en 1 (comme la lessive ;-) ! procedure TForm1.Button1Click(Sender: TObject); var i, j, x : LongInt; begin for j := 1 to 1000000 do if (j mod $43 = 0) then begin x := j * $436F4465; for i := 1 to 1000000 do begin if i * $65446F43 = x then Memo1.Lines.Add(IntToHex(i, 8) + ' ' + IntToHex(j, 8) + ' ' + IntToHex(x, 8)); end; end; end; Bon, attendez-moi là, je vais prendre une douche. Pompompommm..... ...... ..... Voilà, un petit coup d'oeil sur la gauge que j'ai rajouté au brute forcer : 27%. Bon, on a déjà deux x, on va s'arréter là (un petit exit sous SI devrait suffir). Voilà ce que j'ai : x i j 29FA9645 377D7 23C61 53F52C8A 6EFAE 478C2 Maintenant que l'on a nos "passages", on va pouvoir
continuer. On va prendre le premier x (29FA9645h), et les valeurs de i et
j correspondantes. Comme il faut bien commencer quelque part, on va s'arranger pour avoir eax = 23C61h. Je remet l'essenciel de l'algo qui traite de cette partie de la génération : :0040109F mov al, byte ptr [edi+00002000] < prend un char du nom :004010A5 cmp al, 00 < il reste des chars ? :004010A7 je 004010D3 < non, on s'en va :004010A9 imul eax, 00000043 < sinon, eax = eax * 43h :004010AC lea edx, dword ptr [eax+4*eax]< edx = 5 * eax :004010AF add edx, eax < edx = edx + eax :004010B1 push eax {coupé} * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401117(C) | :00401111 add eax, dword ptr [edi] < ajoute la valeur contenue dans edi :00401113 add edi, 00000004 < valeur suivante :00401116 dec esi < il reste des valeurs ? :00401117 jne 00401111 < oui, on boucle :00401119 imul eax, 436F4465 < eax = eax * 436F4465h :0040111F mov dword ptr [00408300], eax < enfin ! On va tirer de ceci une petite formule, pour un nom à 5 caractères (je ne compte pas les chars qui seront issus de Cte ; a, b, c, d, e sont les valeur ascii des caractères du nom), cette égalité devra-être vérifiée : a * 43h + b * 43h + c * 43h + d * 43h + e * 43h + Cte * 43h = 23C61h <=> 43h * (a + b + c + d + e + Cte) = 23C61h <=> a + b + c + d + e + Cte = 88Bh Vous aurez bien compris que l'on arrive au résultat avec autant de caractères que l'on veut (du moment que la somme de leur valeur ascii + cte est égale à 88Bh). Cte est une constante. Elle nous sert à atteindre 88Bh. On la décomposera en caractères pour faire le keygen. Maintenant, on va s'arranger pour que ecx = 377D7h, et là ça va être un peu plus dur ... Encore une fois, voici la partie de l'algo qui nous interresse : * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004010D1(U) | :0040109F mov al, byte ptr [edi+00002000] < prend un char du nom :004010A5 cmp al, 00 < il reste des chars ? :004010A7 je 004010D3 < non, on s'en va :004010A9 imul eax, 00000043 < sinon, eax = eax * 43h :004010AC lea edx, dword ptr [eax+4*eax]< edx = 5 * eax :004010AF add edx, eax < edx = edx + eax :004010B1 push eax < save eax :004010B2 xor eax, eax < eax = 0 :004010B4 push edx < save edx :004010B5 xchg eax,edx < échange eax et edx :004010B6 xor ecx, ecx < ecx = 0 :004010B8 mov cl, 0A < ecx = 0Ah :004010BA idiv ecx < edx = eax mod ecx :004010BC pop eax < eax = ancienne valeur de edx :004010BD imul eax, edx < eax = eax * edx :004010C0 push eax < save eax :004010C1 xor eax, eax < eax = 0 :004010C3 imul edx, esi < edx = edx * esi :004010C6 xchg eax,edx < échange eax et edx :004010C7 pop edx < edx = ancienne valeur de eax :004010C8 xor dl, al < dl = dl xor al :004010CA add edx, 00000070 < edx = edx + 70h :004010CD mov byte ptr [edi], dl < on écrit un char :004010CF dec esi < esi = esi - 1 :004010D0 inc edi < char suivant :004010D1 jmp 0040109F < retour au début {coupé} * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004011C7(U) | :004011AD mov cl, byte ptr [edi] < prend 1 char du sérial :004011AF cmp ecx, 00000000 < il reste des char ? :004011B2 je 004011C9 < non, alors on saute * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004011BC(U) | :004011B4 mov al, byte ptr [ebx] < prend 1 char du nom modifié :004011B6 cmp al, 00 < il reste des char ? :004011B8 jne 004011BE < oui, on saute :004011BA xor bl, bl < non, on remet bl à 0 :004011BC jmp 004011B4 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004011B8(C) | :004011BE imul eax, ecx < eax = eax * ecx :004011C1 add edx, eax < edx = edx + eax :004011C3 inc ebx < char suivant (de la chaine) :004011C4 inc edi < char suivant (du sérial) :004011C5 xor eax, eax < eax = 0 :004011C7 jmp 004011AD < on revient Ici non plus, une petite formule ne nous ferais pas de mal. On sait que la chaine formée à partir de notre nom aura le même nombre de caractères que celui-ci, dont les valeurs ascii seront respectivement a', b', c', d', e' (on garde notre nom de 5 lettres), et on garde la constante. On aura donc : algo a, b, c, d, e, Cte --------> a', b', c', d', e', Cte' Comme notre sérial devra avoir au moins le même
nombre de caractères que notre nom, on va aussi prendre un sérial à 5
caractères (dont les valeurs ascii seront respectivement v, w, x, y, z)
plus une constante Cte2. Cte2 devra contenir le même nombre de caractères
que Cte' (Cte' * Cte2) + (a' * v) + (b' * w) + (c' * x) + (d' * y) + (e' * z) = 377D7h (1) Le problème c'est que ça va nous donner quelque chose de très compliqué à résoudre ! On pourrait chercher un diviseur de 377D7h, j'ai essayé, et c'est pas la meilleure solution ! On va donc prendre un sérial de n caractères, dont (n-1) caractères sont égaux, et le dernier servira à atteindre 377D7h : (1) <=> v * (a' + b' + c' + d' + char(1) + char(2) + .. + char(n)) + z * e' = 377D7h Les chars de char(1) à char(n) sont les caractères qui étaient contenus dans Cte'. En fait comme Cte nous servait à atteindre 88Bh, on aurait pu le remplacer par n * (FFh) + Reste (le reste étant une valeur ascii valide). Si vous ne comprenez pas, essayez de comprendre la source du keygen (tout en bas). On en tire donc (XXh et Reste' étant des valeurs ascii valides) : (1) <=> v * (a' + b' + c' + d' + n * (XXh) + Reste') + z + e' = 377D7h On revient à nos moutons ;-) procedure TForm1.Button1Click(Sender: TObject); var eax, edx, save_eax, save_edx, esi, i : LongInt; begin for esi := 1 to $FF do begin for i := 1 to $FF do begin eax := i * $43; edx := eax * 6; save_edx := edx; eax := edx; edx := eax mod $A; eax := save_edx; eax := eax * edx; save_eax := eax; edx := edx * esi; eax := edx; edx := save_eax; edx := StrToInt('$' + Copy(IntToHex(edx,8), 7, 2)); eax := StrToInt('$' + Copy(IntToHex(eax,8), 7, 2)); edx := edx xor eax; edx := edx + $70; edx := StrToInt('$' + Copy(IntToHex(edx,8), 7, 2)); if edx = 1 then Memo1.Lines.Add(IntToStr(esi) + ' ' + IntToStr(i)); end; end; end; On lance le prog, et .... non ! Il a rien trouvé le c.. ! Bon, c'est pas très grave, on a qu'à chercher e' = 2 (on remplace if edx =1 then par if edx = 2 then), ça compliquera pas beaucoup plus. Voici ce que l'on obtient : position val. ascii 1 63 1 196 3 61 . . . . 255 131 255 238 On va prendre la première ligne : Si on cherche une valeur e pour e' = {3, 5, 7, 9 ....}, on ne trouvera rien, car e' est toujours pair, et ça c'est pas très bon. Je m'explique, on doit avoir : v * (a' + b' + c' + d' + Char(1) + .. + Char(n)) + z * e' = 377D7h ************************************************ ****** ****** pair pair impair Chez moi, la somme de deux nombres pairs donne un nombre pair, et apparemment, ici, ça risque de poser problème. On reprend donc ce que l'on avait trouvé avec le premier brute forcer : x i j 29FA9645 377D7 23C61 53F52C8A 6EFAE 478C2 Ce coup-ci, on va prendre la deuxième ligne, et voilà ce qu'on devra obtenir : | a + b + c + d + e + Cte = 1116h | v * (a' + b' + c' + d' + Char(1) + .. + Char(n)) + z * e' = 6EFAEh Bon, maintenant, on en assez pour coder un joli petit keygen : procedure TForm1.Button1Click(Sender: TObject); var Ascii, Reste, Manque, eax, ecx, edx, save_eax, save_edx : LongInt; i, esi, NBFF, Coeff, a, b : Integer; chaine : string; begin for a := 1 to $FF do for b := 1 to $FF do begin Edit1.Text := 'MiNoS-' + Chr(a) + Chr(b); Ascii := 0; for i := 1 to length(Edit1.Text) do Ascii := Ascii + Ord(Edit1.Text[i]); Manque := $1116 - Ascii; NbFF := Manque div $FF; Reste := Manque mod $FF; Edit1.Text := Edit1.Text + Chr(Reste); for i := 1 to NbFF - 1 do Edit1.Text := Edit1.Text + Chr($FF); Edit1.Text := Edit1.Text + Chr(192) + Chr(63); chaine := ''; esi := Length(Edit1.Text); for i := 1 to Length(Edit1.Text) do begin eax := Ord(Edit1.Text[i]); eax := eax * $43; edx := eax * 6; save_edx := edx; eax := edx; edx := 0; edx := eax mod $A; eax := save_edx; eax := eax * edx; save_eax := eax; edx := edx * esi; eax := edx; edx := save_eax; edx := StrToInt('$' + Copy(IntToHex(edx,8), 7, 2)); eax := StrToInt('$' + Copy(IntToHex(eax,8), 7, 2)); edx := edx xor eax; edx := edx + $70; edx := StrToInt('$' + Copy(IntToHex(edx,8), 7, 2)); Chaine := Chaine + Chr(edx); esi := esi - 1; end; Edit2.Text := Chaine; Ascii := 0; for i := 1 to (Length(Chaine)-1) do Ascii := Ascii + Ord(Chaine[i]); Coeff := $6EFAE div Ascii; Reste := $6EFAE mod Ascii; if (Reste <= 255) and (reste mod 2 = 0) then begin for i := 1 to (Length(Edit2.Text) - 1) do Edit3.Text := Edit3.Text + Chr(Coeff); Edit3.Text := Edit3.Text + Chr(Reste div 2); Memo1.Lines.Add(Edit1.Text + ' ------> '+ Edit3.text); Edit3.Text := ''; end; end; end; Désolé, mais j'ai pas le courage de commenter, j'ai
mis en rouge les points principaux que l'on a abordé précédemment.
J'espère que cela vous aidera à comprendre ce keygen (qui est d'ailleur
très mal codé en Delphi). Quelques greets pour : Christal : rien qu'a la présentation du tut, on voit déjà que je te
dois beaucoup ;-), merci pour tout |
C'est fini pour aujourd'hui !