Le Crackme qui se cracke tout seul
2° Cracker le crackme pour qu'il nous donne le bon serial.
Niveau :
Avancé. (Non mais bougez pas, restez sur votre siège !)
Ce qu'il vous faut :
- Connaître les bases de l'Assembleur (lire
mon cours à ce sujet)
- Savoir utiliser WinDasm (si vous avez compris mes cours précédents c'est bon !
;-) )
- WinDasm
- Un éditeur hexadécimal
- Le crack-me du
cours n°3 et 4 (il aura souffert celui là !)
- 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
étant 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 ou d'ajouter des
fonctions d'un programme en rajoutant, modifiant du code de ce dernier. Enfin du
moins 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, pour utiliser
mes connaissances en assembleur et pour vous en faire profiter. Donc je vous
montrerai 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 brève 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 (ou
plutôt doit) devenir un réflexe désormais : regarder si le programme est
compressé ou voir en quel langage il a été programmé. Donc lancez 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 grâce à l'ajout d'un raccourci
dans le menu "clic-droit". 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 notre
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 il faut donc modifier le JNE en 00401595 et le remplacer par un JE
ou deux NOP. Il va falloir que le crackme modifie lui-même ce saut comme un
grand :-). Pour modifier par exemple le JNE en JE on mettra donc :
MOV byte PTR [00401595], 74 : il s'agit donc
de mettre 74 (JE) à l'adresse 401595.
Il va falloir insérer cette instruction à un endroit où il y
a de la place (là où c'est plein de 00). La plupart du temps vers la fin du
programme on trouve de la place. Ouvrez le avec l'éditeur hexadécimal et allez
donc vers la fin du programme. 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 court le premier byte (octet)
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) octets. Il prendra environ 5 bytes (1 pour le 74 et 4 pour la taille du
saut) ce qui est donc impossible à faire comme cela. Si le saut avez été
inférieur à FF on aurait très bien pu faire comme ceci : exemple :
JMP 00401234 --> le programme original saute à 00401234
xxxxxxx --> instructions
[...]
xxxxxxx
Remplacer par :
JMP 00404890 --> saut à l'endroit que nous avons créé
xxxxxxx --> instructions
[...]
xxxxxxx
MOV byte PTR [00401595], 74 --> modifie le JNE en JE (75 par 74)
JMP 00401234 --> saute à l'endroit prévu par le programme original
Mais là il va falloir remplacer une instruction qui ne sert
pas (ou plutôt 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 ce test ne sert à rien pour nous, car il
nous force à taper quelque chose. Et faignant comme on est (je sais pas vous
mais moi si :-) ) et bien pouvoir ne rien taper c'est mieux.
Vous vous demandez 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 et bien 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 taper directement en assembleur nos instructions. Donc on tape :
JMP 00404890. C'est là qu'on va placer le
patch en lui-même. On fait 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 éventuellement
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 c'est qu'elle est
cachée 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ées 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 deux permettent d'avancer en pas à
pas. Mais sachez que le Step Into rentre dans les CALL contrairement au Step
Over.
Une fois le F7 (ou F8) 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é. On va insérer notre patch ici même,
donc on clique sur "Patch Mode" et on met :
Pourquoi sauter à 00401585 et pas sauter à l'élastique ?
Rappelez-vous ! On avait : :0040156D 7316 jnb 00401585
--> si c'est supérieur saute, si pas de lettre ne saute
pas.
Donc il saute à cette adresse s'il y a des caractères. Donc
là on pourra mettre rien du tout et 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 section dans laquelle doit
être effectuée le patch ne peut pas être modifiée (comme si elle était en
lecture seule).
Faites quand même les modifications que l'on vient d'effectuer dans l'éditeur
hexadécimal. Si vous n'avez pas copié les instructions en hexa vous n'avez plus
qu'à recommencer ! 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 ne 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 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 du
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 correspondance du PUSH en hexa : PUSH = 68 et ensuite les octets sont inversés, regardez le joli (si si regardez bien ! :-P) 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 > pour le bon serial.
Voilà c'est fini pour aujourd'hui, j'espère vous avoir appris
quelque chose de plus avec ce cours ! 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.new.fr et
deamon.crack (at) netcourrier.com.
Deamon, le 24 et 25 juillet 2003
Passer au cours suivant >>> [ Reverse Engineering sur la calculatrice Windows ] |