Cours n°11 : Le Crackme qui se cracke tout seul

 

    Objectif : 

        1° Faire que le crakme se patche lui-même.

        2° Faire en sorte que le crackme nous donne le bon serial.

    Niveau :

        - Avancé.

    Ce qu'il vous faut :

        - Connaître les bases de l'Assembleur (lire mon cours)

        - Savoir utiliser WinDasm (si vous avez compris mes cours précédents c'est bon ! ;-) )

        - WinDasm (Voir page "Outils")

        - Un éditeur hexadécimal comme HexDecCharEditor (Idem)

        - Le crackme du cours n°3 et 4 (20 Ko)

        - StudPE (409 Ko)

 

    Introduction

        Je n'ai pas de définition exacte du Reverse Engineering, donc je ne sais pas si on peut considérer ce cours comme un cours de Reverse Engineering. Mais cela n'est pas bien grave. Pour ceux qui ne savent pas ce que c'est, c'est l'art de modifier les fonctions d'un programme en rajoutant, modifiant du code dans ce programme. Enfin c'est comme ça que je le définirais.

        Dans ce cours tout ce que je vais vous montrer ne vous servira pas forcément plus tard. Je fais cela juste pour m'amuser et pour utiliser mes connaissances en assembleur. Donc je vous montrerais des méthodes qui sont beaucoup plus longues que la simple inversion de saut, mais dont le résultat revient au même.

        Dans ce cours vous apprendrez également à mieux utiliser le débuggeur de WinDasm.

 

    Le Crack-Me qui se patche lui-même !

        J'ai pris le crackme du cours n°3 et 4. Donc nous l'avons déjà cracké ensemble de manière rapide mais efficace. Le crack-me comporte juste une boite de dialogue qui demande un serial. Et si c'est pas le bon, comme d'habitude, nous avons le droit à un beau message "Incorrect try again!!".

        Maintenant que vous avez téléchargé StudPe, cela va devenir un réflexe désormais : regarder si le programme est compressé ou voir en quel langage a-t-il été programmé. Donc lancez donc StudPe, allez directement à Options, ne passez pas par la case départ et ne recevez pas 20.000 F. Oups pardon je m'égare quelque peu ! Une fois sur l'onglet "Options", cochez la case "Shell Menu Extension". Cela vous permettra, en faisant un clic droit sur un .exe ou .dll de l'analyser avec StudPe. N'oubliez pas de configurer l'éditeur hexa avec la case "HexEditor" en sélectionnant le .exe de votre éditeur préféré.

        Une fois tout cela fait, ouvrez notre crackme avec et allez à l'onglet "Signature". Là on peut voir qu'il a été programmé avec Visual C++ 6.0. Donc il n'est pas compressé. Bon allez, vous vous amuserez à voir les autres onglets quand j'aurai fini mon cours.

        Bon cela ne nous empêche pas bien sûr de désassembler ce cher crackme. On recherche le message d'erreur, on tombe sur :

:0040158D FF1500204000 Call dword ptr [00402000]
:00401593 85C0 test eax, eax
:00401595 7516 jne 004015AD
:00401597 6A40 push 00000040

* Possible StringData Ref from Data Obj ->"CrackMe"
|
:00401599 6850304000 push 00403050

* Possible StringData Ref from Data Obj ->"Correct way to go!!"
|
:0040159E 6858304000 push 00403058
:004015A3 8B4DE0 mov ecx, dword ptr [ebp-20]

* Reference To: MFC42.Ordinal:1080, Ord:1080h
|
:004015A6 E853050000 Call 00401AFE
:004015AB EB14 jmp 004015C1

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401595(C)

|
:004015AD 6A40 push 00000040

* Possible StringData Ref from Data Obj ->"CrackMe"
|
:004015AF 686C304000 push 0040306C

* Possible StringData Ref from Data Obj ->"Incorrect try again!!"

 

        Oula que c'est dur à cracker ça ! ;-) Bon donc il faut modifier le JNE en 00401595 et le remplacer par un JE ou deux NOP. Bon alors il va falloir que le crackme modifie lui-même ce saut. Pour modifier par exemple le JNE en JE on mettra donc :

MOV byte PTR [00401595], 74

        Il va falloir insérer cette instruction à un endroit où il y a plein de 00. La plupart du temps à la fin du programme. Ouvrez le avec l'éditeur hexadécimal et allez vers la fin. On le mettra par exemple à l'offset 4890. Et pour que le programme passe par ici il va falloir l'ammener par un JMP. Donc il faut trouver une instruction qu'on peut remplacer par le JMP. Et il ne faut pas oublier non plus le JMP après le MOV pour pouvoir revenir de là où on vient. J'espère avoir été assez clair.

        Petit rappel : pour un saut le premier byte correspond au type de saut et le deuxième au nombre (en hexa bien sur) de bytes qu'il va sauter. Ex: 7516 : 75 = JNE et saute de 16 bytes.

        Le problème ici c'est que le saut est largement supérieur à FFh (255d). Il prendra environ 5 bytes (1 pour le 74 et 4 pour la taille du saut).

        Si le saut avez été inférieur à FF on aurait très bien pu faire comme ceci : exemple :

        Remplacer par :

        Mais là il va falloir remplacer une instruction qui ne sert pas (ou plutot qui sert mais à rien ;-) ) d'une taille minimum de 5 bytes et dont le programme passe forcément dessus.

        Donc on regarde au-dessus du test qui ammène de notre message d'erreur car il y passe forcément :

* Reference To: KERNEL32.lstrlenA, Ord:0308h
|
:00401560 FF1504204000 Call dword ptr [00402004]
:00401566 8945F0 mov dword ptr [ebp-10], eax
--> met le nombre de lettres du serial dans ebp-10
:00401569 837DF001 cmp dword ptr [ebp-10], 00000001
--> compare à 1
:0040156D 7316 jnb 00401585
--> si c'est supérieur saute, si pas de lettre ne saute pas
:0040156F 6A40 push 00000040

* Possible StringData Ref from Data Obj ->"CrackMe"
|
:00401571 682C304000 push 0040302C

* Possible StringData Ref from Data Obj ->"Enter Registration Number"
|
:00401576 6834304000 push 00403034
:0040157B 8B4DE0 mov ecx, dword ptr [ebp-20]

* Reference To: MFC42.Ordinal:1080, Ord:1080h
|
:0040157E E87B050000 Call 00401AFE
:00401583 EB3C jmp 004015C1

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040156D(C)

|
:00401585 8D4DE4 lea ecx, dword ptr [ebp-1C]
:00401588 51 push ecx
:00401589 8D55F4 lea edx, dword ptr [ebp-0C]
:0040158C 52 push edx

* Reference To: KERNEL32.lstrcmpA, Ord:02FCh
|
:0040158D FF1500204000 Call dword ptr [00402000]
:00401593 85C0 test eax, eax
:00401595 7516 jne 004015AD
--> saute vers bon ou mauvais message
:00401597 6A40 push 00000040

* Possible StringData Ref from Data Obj ->"CrackMe"
|
:00401599 6850304000 push 00403050

* Possible StringData Ref from Data Obj ->"Correct way to go!!"
 

        Là où il teste s'il y a des caractères ou non, il y aurait de la place car de plus ce test nous sert à rien, car il nous force à taper quelque chose. Et faignant comme on est (vous je sais pas mais moi si :-) ) et bien pouvoir rien taper c'est mieux.

        Vous vous dîtes peut-être comment je sais que c'est le nombre de caractères du serial. Et bien lancez le débuggeur, mettez un BreakPoint sur la ligne en 00401566, faites "Run", tapez n'importe quoi comme serial et faites Ok. Là il break ! Regardez dans la fenêtre des registres (celle en bas à gauche) et plus particulièrement le cadre "Regs". Vous pouvez voir la valeur de EAX. En mettant "123456" comme serial vous aurez 6.

        Bon ben pendant qu'on break ici et bien on va installer notre patch ! On clique sur "Patch Mode" de la fenêtre de droite. Et là on va pouvoir tapez directement en assembleur nos instructions. Donc on tape : JMP 00404890. C'est là qu'on va placer le patch en lui-même. On fais Entrée, si l'instruction est fausse il l'indique et si c'est juste il la met dans le cadre du dessous. L'avantage de le faire ici c'est de pouvoir voir la correspondance en hexa, qu'on pourra recopier dans l'éditeur hexadécimal.

        Une fois l'instruction validée, on fait "Apply Patch", là une fenêtre de confirmation s'affiche. Si vous ne la voyez pas elle est derrière la fenêtre actuelle. On fait "Oui" et avant de fermer la fenêtre du Patch Mode on clique sur "Copy" et on colle ça quelque part pour s'en souvenir. Les modifications effectués ne se voient pas dans la fenêtre principale de WinDasm mais dans celle de droite.

        Là on va devoir aller à 00404890 donc on fait "F7" - Step Into ou "F8" - Step Over (peu importe). Les 2 permettent d'avancer en pas à pas. Mais sachez que le Step Into rentre dans les CALL contrairement au Step Over.

        Une fois le F7 fait, on voit :  :00404890 add byte ptr [eax], al (toujours dans la fenêtre de droite). C'est là où le JMP nous a emmené. Là on va insérer notre patch, donc on clique sur "Patch Mode". On met :

        Pourquoi sauter à 00401585 ? Rappelez-vous ! On avait : :0040156D 7316 jnb 00401585 --> si c'est supérieur saute, si pas de lettre ne saute pas

        Donc il sautait à cette adresse si il y a des caractères. Donc là on pourra mettre rien il nous dira quand même que c'est bon. C'est-y pas magique ? Ben en fait non ! Car appliquez ce patch là (n'oubliez pas de copier les instructions) ! Pour le tester ensuite, cliquez sur Run. Et là plantage ! AAARRRRGGG ! Cela vient du fait que la mémoire ne peut pas être écrite.

        Faites quand même les modifications que l'on vient d'effectuer dans l'éditeur hexadécimal. Si vous avez pas copier les instructions en hexa vous n'avez plus qu'à recommercer ! Et respectez bien les endroits !!!

        Ouvrez ensuite le crackme modifié avec StudPe. Allez dans "section", double-cliquez sur la ligne de ".text" et cochez "MEM_WRITE". Faites Save et voilà, vous pouvez maintenant le tester : notre crackme est cracké en s'auto-patchant.

        Pour remplacer le JNE par des NOP il aurait fallu inscrire :

:00401DE0 66C6059515400090 mov byte ptr [00401595], 90
:00401DE8 66C6059615400090 mov byte ptr [00401596], 90

 

    Petite variante

        On aurait pu mettre un call à la place d'un jump. Exemple :

        Voici ce qu'il y a dans le programme original :
:00401566 8945F0 mov dword ptr [ebp-10], eax
--> met le nombre de lettres du serial dans ebp-10
:00401569 837DF001 cmp dword ptr [ebp-10], 00000001
--> compare à 1
:0040156D 7316 jnb 00401585
--> si c'est supérieur saute, si pas de lettre ne saute pas

        Si on break sur la ligne en 00401566 on peut voir que EBX est tout le temps égal à 1. Donc on pourrait mettre :

:00401566 39D8 cmp eax, ebx --> Compare notre nombre de lettres à EBX (=1), ce qui revient au même que les 2 lignes MOV et CMP.
:00401568 E823330000 call 00404890
--> Va à l'endroit de notre patch

        Puis à l'endroit du patch, en 00404890 :

:00404890 66C6059515400074 mov byte ptr [00401595], 74 --> Remplace le saut 75 en 74
:00404898 C3 ret --> Retourne juste après le CALL

        Par contre si vous mettez rien comme serial il vous demandera d'en mettre un.

 

    Le crackme qui nous donne le bon serial !

        Voilà comment le crackme vous donne le bon serial !

* Possible StringData Ref from Data Obj ->"CrackMe"
|
:004015AF 686C304000 push 0040306C

* Possible StringData Ref from Data Obj ->"Incorrect try again!!"
|
:004015B4 6874304000 push 00403074
:004015B9 8B4DE0 mov ecx, dword ptr [ebp-20]


        Le PUSH envoie en fait le texte situé au dessus que WinDasm nous montre gentiment :-) , pour le vérifier faites lancez le debuggeur, et tapez le numéro qui suit le PUSH dans la case "User Addr" 1 ou 2 (en dessous des registres) et cliquez en dessous sur UA1 ou UA2 selon le numéro choisi. En mettant 00403074 vous pourrez voir  "Incorrect try again". Les autres messages se situent vers le même endroit (dans les 004030xx), on va donc aller dans l'éditeur hexa à l'offset 3074 par exemple. Et là on voit les autres messages dont le serial !! On repère donc son adresse en relevant l'offset ds premier caractère (<) du serial. Ici on a 3020. Donc on va remplacer le PUSH que vous souhaitez par un PUSH 00403020.

        Par exemple celui du "Incorrect..." : 6874304000     push 00403074
        On mettra à la place : 6820304000     push 00403020

 

        Je rappelle la représentation du PUSH en hexa : PUSH = 68 et ensuite les bytes sont inversés, regardez l'exemple en couleur :

            6874304000     push 00403074

        Et donc une fois les modifications effectuées, on teste : on met n'importe quoi on valide ! Et là un beau message vient nous rappeler le bon serial : <BrD-SoB>. Et n'oubliez pas de mettre les < et >.

 

        Voilà c'est fini pour aujourd'hui, j'espère vous avoir appris quelque chose de plus avec ce cous ! Et comme toujours si vous avez un problème ou si vous n'avez pas compris quelque chose 2 adresses sont là pour ça : www.forumcrack.fr.st et deamon.crack@netcourrier.com .

 

Deamon le 24 et 25 juillet 2003

<<< Cours précédent    Cours suivant >>>