Cours n°1
L'hexadécimal et les types de sauts
Comprendre l'hexadécimal
Tout d'abord ouvrez un programme avec WinDasm (si vous ne savez pas l'utiliser allez voir le
cours
précédent). Vous devez apercevoir des lignes semblables à celle-ci :
Exemple :
:0040100E |
E839000000 |
Call 0040104C |
:00401013 |
83F807 |
cmp eax, 00000007 |
:00401016 |
EB1A |
jmp 00401032 |
:00401018 |
6A40 |
push 00000040 |
Le numéro en bleu est l'adresse de la ligne pour WinDasm.
Le nombre en blanc est l'instruction en hexadécimal correspondant
aux instructions rouges. C'est
cela qu'on recherchera dans l'éditeur hexadécimal et qu'on modifiera.
Les mots et nombres en rouge sont les instructions en assembleur du programme désassemblé. C'est en fait la "traduction" de l'instruction en hexadécimal en blanc.
En décimal vous comptez comme ça (ou du moins je l'espère...) :
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, ...
Et bien en hexadécimal il y a non pas 10 chiffres mais 16 (les 10 du décimal + les 6 lettres A,B,C,D,E,F) on compte donc de cette manière :
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 10, 11, ...
Donc par exemple 15 en décimal s'écrira F en hexa, 16 => 10, 17 => 11, 26 => 1A, etc...
Les adresses de WinDasm sont en hexadécimal
et dans l'ordre croissant, mais il ne les met pas toutes comme on peut le voir
dans l'exemple ci-dessus. C'est tout simplement car l'adresse correspond en fait non pas à l'instruction mais au premier octet de l'instruction (un octet est composé de 2 chiffres hexadécimal) donc par exemple à l'adresse 401016 "EB1A" comporte 2 octets ainsi l'instruction "6A40" aura pour adresse 401016+2 soit 401018.
Qu'est-ce qu'un saut ?
Je vais en premier lieu vous
montrer le schéma d'une protection utilisée la plupart du temps. Une fois le
code rentré il le compare avec le bon code, si c'est pas le
même il saute pour arriver vers le mauvais message sinon il affiche le bon
message et continue sa route vers de nouvelles aventures en passant au dessus du
mauvais message.
JNE est un saut conditionnel. Il saute si le code est faux dans ce cas là (saut si inégal)
ou continue sa route si le code est bon.
JMP ( = Jump = Saut) est aussi un saut mais inconditionnel puisqu'il saute obligatoirement,
même au bord d'un précipice il sautera quand même :-P ...
Et ça donne à peu près ça en assembleur (les adresses sont fictives et je n'ai
pas mis l'intégralité de ce passage comme notamment les instructions pour
afficher les messages pour ne garder que le nécessaire) :
:00401001 |
#### |
Teste si le code est bon |
:00401002 |
75## |
jne 00401003 |
Le JNE saute uniquement si le code n'est pas bon.
* Possible StringData Ref from Data Obj ->"Le code est bon"
Windasm indique que "Le code est bon" est le message d'une boîte de dialogue.
:00401003 |
EB## |
jmp 00401005 |
Le JMP est un saut. Le numéro à sa droite est l'adresse où il va sauter.
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401002(U)
Il indique que la portion de code suivante est appelée par un saut conditionnel (l'adresse de celle-ci est à gauche du "(U)"
: 00401002)
* Possible StringData Ref from Data Obj ->"Le code n'est pas bon"
Après ces schémas, vous avez donc compris (du moins je l'espère) que c'est le jne qu'il faut changer. Mais vous allez me dire :
Comment change-t-on un saut conditionnel ?
Regardez le schéma en assembleur et plus précisément la ligne 00401002 avec le jne. Dans le code hexa, on voit 75##. Et
bien le 75 c'est notre jne. Tout comme le jmp qui
correspond à EB.
Voici une petite liste de sauts conditionnels que vous pourrez trouver le plus souvent :
Instruction |
Valeur hexa |
Description |
jne |
75 ou 0F85 |
Saut si inégal |
je |
74 ou 0F84 |
Saut si égal |
jmp |
EB
ou E9 |
Saut |
nop |
90 |
Pas d'opération |
Pour modifier un saut, il suffira donc de rechercher sa valeur et de la modifier avec l'éditeur hexadécimal. Par exemple pour le schéma ci-dessus on mettra un je (il sautera à "Le code est bon" si le code est mauvais) ou nop (il ne sautera pas du
tout et ira donc directement vers "Le code est bon") à la place de
jne.
Pour information les 75, 74, EB sont des sauts courts et 0F85, 0F84, E9 des
sauts longs. Après les sauts courts on a le nombre (en hexa) d'octets sautés (un
octet est un nombre de 2 chiffres qui va donc en hexa de 00 à FF comme peut
l'être 75 ou 90) et donc pour les sauts de plus de FF (soit 255 en décimal)
octets on utilise des sauts longs à la suite desquelles on met l'adresse de
destination. Par exemple EB02 représente un saut (JMP) de 2 octets.
Après la théorie place à la pratique, dans le cours n°2 nous essaierons de cracker un crack-me.