Changer un crackme en keygen

par superjuju, le vendredi 13 juin 2003

 

Introduction

Ceci est mon premier cours, je suis moi-même un cracker débutant mais j'avais envie de faire quelque chose par moi même alors voila ce tut ...

En fait j'avais commencé le cracking il y a déja 3 ans de cela mais bon j'ai du m'arrêter entre-temps par manque de temps ( ahhh viva la prépa ! ) mais depuis que les concours sont finis j'ai pris un coup de speed j'ai eu envie de m'y remettre... Bon allons y !

Je pars sur le principe que tu connais déja quelque chose à l'art ancestral du cracking alors je vais pas tout détailler. Si jamais tu t'estimes doué ne reste pas par ici tu perds ton temps. Va plutot lire quelques cours sur le manual unpacking ou sur les dongles ... Mais si tu ne sais pas ce que signifient ces mots barbares reste par là j'espère que j'arriverai a t'apprendre quelque chose... sur des choses bien plus simples !

 

Outils nécessaires

 

Analyse du programme

Alors on lance le proggy, et on observe : c'est un classique name / sérial.

On clique sur info : ah voila enfin quelque chose d'interressant : " Write in Delphi 2.0 in july 1999. " Bon la date on s'en bat les cahouettes mais savoir que c'est en Delphi risque d'être utile : en effet le Delphi est un langage un peu différent des autres : il n'utilise pas les API windows (ou du moins pas directement j'en sais rien). Tout ce que je sais c'est que les BPX MessageBoxA ou BPX GetDlgItemTextA ne marchent pas sous SoftIce.. Mais on s'en fout on va utiliser W32Dasm uniquement :-) L'autre problême avec Delphi c'est sous W32Dasm justement : les strings refs ne sont pas accessibles en général ... :-( Mais bon c'est notre jour de chance (va voir la date en haut !!!) içi ca va marcher .... :-)))

On rentre un nom bidon : superjuju ( j'ai passé des années à trouver un pseudo aussi débile !) et un s/n bidon : 121212. Paf une boite nous pète à la face : "Nop! Keep working !" Ben bien sur on va pas trouver le bon sérial du premier coup ! ah c'est chiant de se faire insulter par un p'tit crackme alors qu'on a même pas encore commencé à le cracker... On va régler ca !!!

Programme des réjouissances :

Essaye de faire les manips en même temps que moi c'est plus efficace pour retenir.

 

1. Crack simple

On va s'faire ca vite fais bien fait ! Alors on lance W32Dasm et on désassemble le crackme. Un petit clic sur les string refs, on cherche "Nop! Keep working!" et on arrive là :

 

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00427277(C)
|
:004272CE 8BC3                   mov eax, ebx
:004272D0 F7EB                   imul ebx
:004272D2 8BD8                   mov ebx, eax
:004272D4 8D55EC                 lea edx, dword ptr [ebp-14]
:004272D7 8BC3                   mov eax, ebx
:004272D9 E80EE2FDFF             call 004054EC
:004272DE 8B45EC                 mov eax, dword ptr [ebp-14]
:004272E1 50                     push eax
:004272E2 8D55F0                 lea edx, dword ptr [ebp-10]
:004272E5 8B87BC010000           mov eax, dword ptr [edi+000001BC]
:004272EB E8D8A7FEFF             call 00411AC8
:004272F0 8B55F0                 mov edx, dword ptr [ebp-10]
:004272F3 58                     pop eax
:004272F4 E897C1FDFF             call 00403490                                ; teste le code entré
:004272F9 7517                   jne 00427312                                 ; saute vers le message d'erreur si il
:004272FB 6A00                   push 00000000                                  est faux.
:004272FD 668B0D54734200         mov cx, word ptr [00427354]
:00427304 B202                   mov dl, 02

* Possible StringData Ref from Code Obj ->"Well done! The serial is correct!"
|
:00427306 B894734200             mov eax, 00427394
:0042730B E89CF9FFFF             call 00426CAC
:00427310 EB15                   jmp 00427327

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004272F9(C)                                                                  ; intéressant
|
:00427312 6A00                   push 00000000
:00427314 668B0D54734200         mov cx, word ptr [00427354]
:0042731B B202                   mov dl, 02

* Possible StringData Ref from Code Obj ->"Nop! Keep working."
|
:0042731D B8C0734200             mov eax, 004273C0
:00427322 E885F9FFFF             call 00426CAC                                 ; affichage du message d'erreur

 

Bon ben c'est très simple : en 004272F9 , si le code entré est faux on saute vers le message d'erreur ! Comment lutter contre ca ?? En fait c'est ce saut qui fout sa merde alors noppons le ! Dans un éditeur hexadécimal on remplace 7517 par 9090 ! On relance... Et voilou yapalou !!

 

2. Recherche d'un sérial valide

Ce qu'on viens de faire c'était juste pour se mettre en bouche, alors attaquons les choses sérieuses !

On va se servir du debugger de W32Dasm ca ira bien mieux que SoftIce surtout qu'on a déja tout sous la main ! Alors on va se servir un peu de l'un de nos neurones (pas trop hein) pour comprendre un peu mieux ce qui se passe dans le programme.

Déja on n'est pas aidé car le programme est en Delphi : on ne connait pas le nom des fonctions que l'on appelle : un Call MessageBoxA est beaucoup plus clair qu'un Call 00421546 !!!

Je rappelle la partie du code qui va nous servir :

 

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00427277(C)
|
:004272CE 8BC3                   mov eax, ebx
:004272D0 F7EB                   imul ebx
:004272D2 8BD8                   mov ebx, eax
:004272D4 8D55EC                 lea edx, dword ptr [ebp-14]
:004272D7 8BC3                   mov eax, ebx
:004272D9 E80EE2FDFF             call 004054EC
:004272DE 8B45EC                 mov eax, dword ptr [ebp-14]                  ; change la valeur de eax
:004272E1 50                     push eax                                     ; empile eax
:004272E2 8D55F0                 lea edx, dword ptr [ebp-10]
:004272E5 8B87BC010000           mov eax, dword ptr [edi+000001BC]
:004272EB E8D8A7FEFF             call 00411AC8
:004272F0 8B55F0                 mov edx, dword ptr [ebp-10]
:004272F3 58                     pop eax                                      ; dépile eax
:004272F4 E897C1FDFF             call 00403490                                ; teste le code entré
:004272F9 7517                   jne 00427312                                 ; saute vers le message d'erreur si il
:004272FB 6A00                   push 00000000                                  est faux.
:004272FD 668B0D54734200         mov cx, word ptr [00427354]
:00427304 B202                   mov dl, 02

 

Pour comprendre ce qu'il se passe, le mieux est de remonter le code !

On part du jne 00427312 : saute vers le message d'erreur

Une ligne plus haut, on a un call 00411AC8 : on en déduis que c'est le call qui compare le bon code et le faux.

Encore plus haut, un pop eax : on dépile eax (ce qui implique qu'on l'a empilé un peu plus haut bien sur) : ca servira de parametre à la fonction suivante, notre fameux call! Mais dis donc, n'y aurait-il pas quelque chose d'interressant dans ce eax ??? Ca mérite d'y jeter un coup d'oeil... Lançons le débugger ( CTRL + L ), allons ligne 004272F3 et posons un ptit breakpoint avec F2. Ainsi dès qu'on arrivera sur cette ligne W32Dasm breakera ( zoli néologisme ...) et on pourra voir ce qu'il y a dans eax!

On clique sur run (ou on appuie sur F9) et paf le crackme se lance. On rentre un pseudo : superjuju, un code bidon : 121212 et on valide! Et si tout a bien marché tu devrais arriver dans W32Dasm.

Va voir la valeur de eax en cliquant sur le ptit bouton marqué eax dessus (jvais pas faire un cours sur le debugger de W32Dasm je le connais pas assez !). Pour l'instant ya une merde c'est normal on ne l'a pas encore dépilé ! On appuie sur F8 pour tracer (executer la ligne en cours) et là oh magie un nombre louche apparait !

Pour moi j'ai 252996160. On quitte le debugger (terminate), on teste et ... ca marche !!! Ce qui est normal d'ailleurs car on a analysé le code avant d'essayer de partir n'importe comment comme je fait d'habitude :))

 

3. Transformer le crackme en keygen

Après les banalités d'usage, je propose de ne pas s'arrêter là en si bon chemin! Essayons de faire un keygen :)) Ou plutot pour ne pas se faire chier à chercher la routine qui calcule le code, à la comprendre et la reprogrammer (ce dont je suis incapable d'ailleurs !) utilisons le crackme. Je propose de procéder ainsi : remplacer le fuckin' " Nop! Keep working! " par le numéro de série correspondant au nom entré ! Oui mais comment faire te demandes-tu ? Mais c'est très simple voyons ! il suffit encore une fois de regarder le code !

 

:004272DE 8B45EC                 mov eax, dword ptr [ebp-14]                  ; change la valeur de eax
:004272E1 50                     push eax                                     ; empile eax

 

Je récapépette : à la 2ème ligne dans eax on a le bon code. A la 1ère on met dans eax la valeur de dword ptr [ebp-14]. On en déduis que dword ptr [ebp-14] contient le bon code ... ce qui peut d'ailleurs etre vérifié avec le débugger.

Bon ya juste un truc qui peut foirer : le bon code sera t'il encore dans un coin de la mémoire quand on affiche le message d'erreur ? Et oui ! C'est notre jour de chance je te le rappelle ! On vérifie avec le debugger que dword ptr [ebp-14] contient encore le bon code quand le message s'affiche. Alors ya juste à changer le message par dword ptr [ebp-14].

Pour faire ceci regardons de plus près l'affichage de la boite :

 

:00427312 6A00                   push 00000000
:00427314 668B0D54734200         mov cx, word ptr [00427354]
:0042731B B202                   mov dl, 02

* Possible StringData Ref from Code Obj ->"Nop! Keep working."
|
:0042731D B8C0734200             mov eax, 004273C0
:00427322 E885F9FFFF             call 00426CAC

 

On déduit par l'habitude d'utiliser W32Dasm que le message d'erreur est conservé à l'adresse 004273C0 ( voir la StringData Ref )

Ainsi on met dans eax le message d'erreur, et on appelle le call 00426CAC qui est l'affichage de la boite. Donc eax contient le message que l'on va afficher. Il serait interressant de changer la valeur de eax à dword ptr [ebp-14] pour afficher le numéro de série au lieu de ce foutu message d'erreur. Comment faire? Je prétend qu'il suffit de remplacer le mov eax, 004273C0 par mov eax, dword ptr [ebp-14]. Oui mais comment faire ?? Inverser un saut ou nopper un call on sait faire par coeur, mais les mov machin chose on connais pas le code ascii ??? Ah bon? regarde un peu plus haut, ligne 004272DE ! ohhh et oui c'est exactement ce que l'on veut ! et en plus cette instruction ne prend que 3 octets alors que le vieux call en prend 5 ! Donc ca va rentrer ! Quand je te dis que c'est notre jour de chance !!!!

Patch à réaliser : remplacer B8C0734200 par 8B45EC9090.

On lance le crackme, on met un nom, un code bidon, et hop une fenêtre s'affiche avec un serial ! On l'essaye, ca marche !!!!!

 

Conclusion

Bon ben voila c'était mon premier cours, j'espere que tout va bien que tu as tout bien compris, etc ... Ah ca prend plus de temps que je l'imaginais de faire un tut :) . Mes remerciments sont pour tout ceux qui font des tuts sans lesquels je ne saurais même pas ce qu'est qu'un crack !!! En particulier à la scene francaise :) Ya trop de noms pour que je les cite tous !!!

superjuju