Bible du
cracker
Par Falcon
L'ASSEMBLEUR
1 - Les bases indispensables pour débuter
Pour cracker n'importe quel logiciel, il est indispensable de connaître le
fonctionnement de l'assembleur et ses instructions.
Pour cela, je vous
conseille vivement d'acheter les 2 livres suivants :
Assembleur " Une
découverte pas à pas " de Philippe Mercier - Edition Marabout n°885 (environ 50
francs).
Assembleur " Théorie, pratique et exercices " de Bernard
Fabrot - Edition Marabout n°1087 (environ 50 francs).
Comme vous le verrez, ce cours est surtout destiné à la programmation en asm.
A - Définition de l'assembleur
L'assembleur est un langage de programmation transformant un fichier texte contenant des instructions, en un programme que le processeur peut comprendre (programme en langage machine).
Ce langage machine a la particularité d'être difficile à programmer car il n'est composé que de nombres en hexadécimal (base 16). L'assembleur est une "surcouche" du langage machine, il permet d'utiliser des instructions qui seront transformées en langage machine donc il présente une facilité de programmation bien plus grande que le langage machine. Le fichier texte qui contient ces instructions s'appelle le source.
Nous allons aborder un aspect très important de la programmation en
assembleur : le système de numérotation en hexadécimal.
Ce système est basé
sur l'utilisation des chiffres et de certaines lettres de l'alphabet (de A à F).
Vous connaissez bien entendu le système décimal (base 10).
En assembleur,
les nombres décimales sont suivis d'un "d" (1000=1000d) mais en principe la
majorité des assembleurs calculent en décimal par défaut.
La notation
hexadécimale (base 16) implique qu'il faut disposer de 16 signes alignables dans
une représentation et, comme les chiffres ne suffisent plus, on a décidé que les
signes de 0 à 9 seraient représentés pas les chiffres 0..9 et les signes
manquants pour obtenir 16 signes seraient les 6 premières lettres de l'alphabet
soit A, B, C, D, E, F avec :
Hexadécimal | Décimal |
A |
10 |
B | 11 |
C | 12 |
D |
13 |
E | 14 |
F | 15 |
Nous ne pouvons pas utiliser le G et les lettres qui suivent, donc nous augmenterons le premier chiffre ce qui donne 16d=10h. Continuez ainsi jusqu'à 255 qui fait FF. Et après. Et bien on continue. 256d=0100h (le h et le zéro qui précède indiquent que ce nombre est en hexadécimal). 257d=101h. 65535=FFFFh. Bon, je pense que vous avez compris.
Pour convertir des nombres du décimal en hexadécimal, vous pouvez utiliser la calculatrice de Windows en mode scientifique.
Exemples :
8 = 8*1
78 = 7*16 + 8*1
A78
= 10*256 + 7*16 + 8*1
EA78 = 14*4096 +
10*256 + 7*16 + 8*1
Je vais finir mon explication avec le calcul binaire. Vous savez probablement que les ordinateurs calculent en base 2 (0 ou 1). Le calcul binaire consiste à mettre un 1 ou un 0 selon la valeur désirée. Chaque 0 ou 1 est appelé un bit, 8 bits forment un octet.
Pour le nombre 1, nous avons 00000001b (le b signifie binaire). Un nombre
binaire se décompose comme ceci :
128|64|32|16|8|4|2|1
Pour le nombre 1,
la première case est remplie (1=rempli). Pour avoir le nombre 2, nous aurons
00000010b et pour le nombre 3, nous aurons 00000011 (1 case=1 - 2ème case=1
=> 1+2=3).
Le nombre 11111111b donnera 255 puisque en additionnant
1+2+4+...+128, on obtient 255. Plus il y a de bits, plus le nombre peut être
grand, nous verrons plus tard qu'il existe différentes unités selon le nombre de
bits.
Exemples :
Base 2 | Base 10 |
00000001 | 1 = 1*1 |
00000011 | 3 = 1*2 + 1*1 |
00001011 | 11 = 1*8 + 0*4 * 1*2 + 1*1 |
00011011 | 27 = 1*16 + 1*8 + 0*4 + 1*2 + 1*1 |
D - Conversion binaire ó hexadécimal
Voici un exemple démontrant la simplicité de conversion d'un nombre binaire en hexadécimal :
Soit le nombre hexadécimal EA78 à convertir en binaire, 16 étant 2 à la
puissance 4, chaque signe de la représentation hexadécimale sera converti en 4
signes binaires et le tour sera joué :
Hexadécimal | Décimal | Binaire |
E | 14 | 1110 |
A | 10 | 1010 |
7 | 7 | 0111 |
8 | 8 | 1000 |
En alignant les représentations binaires obtenues, on trouve le nombre
binaire suivant : 1110101001111000.
Inversement, pour convertir un nombre
binaire en hexadécimal, c'est tout aussi simple, on regroupera les bits par
groupe de 4 :
Soit 1110101001111000 à traduire en hexadécimal :
On le
découpe d'abord en 4 : 1110 1010 0111 1000
Binaire | Décimal | Hexadécimal |
1110 | 14 | E |
1010 | 10 | 10 |
0111 | 7 | 7 |
1000 | 8 | 8 |
E - Le processeur et ses registres
Le processeur est composé de différentes parties. Les registres sont les éléments les plus importants du processeur pour celui qui programme en asm. Les registres sont souvent représentés comme des cases dans lesquelles sont stockées différentes valeurs de différentes tailles selon le type et le nom du registre. Il existe plusieurs types de registres :
ils servent à manipuler des données, à transférer des paramètres lors de
l'appel de fonction DOS et à stocker des résultats intermédiaires.
ils contiennent une valeur représentant un offset à combiner avec une adresse
de segment
ils sont utilisés pour stocker l'adresse de début d'un segment. Il peut
s'agir de l'adresse du début des instructions du programme, du début des données
ou du début de la pile.
il contient des bits qui ont chacun un rôle indicateur.
On a plusieurs registres généraux (de travail) qui commencent par A,B,C et D.
Ces quatre registres sont les plus utilisés.
Le 1er, AX (registre de 16
bits) qui se divise en deux petits registres de 8 bits, AL (l=low=bas) et AH
(h=high=haut).
Il est utilisé lors d'opérations arithmétiques.
Nous
avons ensuite BX (BL et BH), CX (CL et CH) et DX (DL et DH), ces registres sont
divisés comme AX en 2 parties hautes et basses.
On peut rajouter un "E"
devant les registres 16 bits afin d'obtenir un registre 32 bits.
Ce qui
donne EAX,EBX,ECX et EDX. Notez que l'on ne peut avoir de EAH ou ECL. La partie
haute d'un registre 32 bits, n'est pas directement accessible, on doit utiliser
différentes instructions afin de la faire "descendre" dans un registre de 16
bits et pouvoir finalement l'utiliser.
Ces registres peuvent contenir une
valeur correspondant à leur capacité.
AX=65535 au maximum (16 bits) et
AL=255 au maximum (8 bits). Je répète que la partie haute du registre 32 bits ne
peut pas être modifiée comme un registre. Elle peut être modifiée seulement si
l'on modifie tout le registre 32 bits (y compris la partie basse), ou par le
biais de quelques instructions qui permettent de copier la partie basse du
registre dans la partie haute, mais cela ne nous concerne pas pour l'instant.
Les processeurs 286 et moins ne peuvent pas utiliser les registres 32 bits
(EAX,EBX,ECX,EDX = impossible). Ce n'est qu'à partir du 386 que l'utilisation du
32 bits est possible.
b ) Les registres pointeurs ou d'offset
Pour terminer, je vais parler des registres pointeurs qui sont DI (destination index), SI (source index), BP (base pointer), IP (instruction pointer) et SP (stack pointer).
Ces registres peuvent eux aussi être étendus à 32 bits en rajoutant un "E" (EDI,ESI,EIP,ESP,EBP).
Ces registres n'ont pas de partie 8 bits, il n'y a pas de EDL ou de ESH.
Les registres SI et DI sont le plus souvent employés pour les instructions de chaîne et pour accéder à des blocs en mémoire.
Le registre SP est utilisé pour accéder à la pile.
Nous ne l'employons presque pas, sauf pour du code très spécifique.
Ces registres (sauf IP) peuvent apparaître comme des opérandes dans toutes les opérations arithmétiques et logiques sur 16 bits.
c ) Le processeur et ses registres de segment
Pour pouvoir chercher et placer des choses dans sa mémoire, un ordinateur a besoin de ce qu'on appelle une adresse. Celle-ci se compose de deux parties de 32 bits (ou 16 bits, cela dépend du mode employé). La première est le segment et la deuxième, l'offset.
Voici un exemple :
0A000h:00000h (adresse de la mémoire vidéo)
Dans cet exemple, il s'agit d'un adressage 16 bits. L'adressage 16 bits s'utilise en mode réel_. Le mode réel est un état du processeur où il ne peut accéder à des blocs de taille supérieure à 16 bits (65536 bytes). Le 286 introduira un mode dit protégé qui permet de franchir cette barrière pour pouvoir accéder à quasiment tout la RAM en un bloc (ce mode protégé sera grandement amélioré à partir du 386).
Nous nous contenterons du mode réel au début, car il est plus simple mais il présente tout de même des limites. Sur 386, les segments ont été conservés pour garder une certaine comptabilité avec les vieilles générations de PC.
Les registres de segment ne sont que lus et écris sur 16 bits. Le 386 utilise un offset de 32 bits (sauf en mode réel où il travaille toujours en 16 bits). Voici la liste de ces segments, ils sont au nombre de 6 :
Ce registre indique l'adresse du début des instructions d'un programme ou d'une sous-routine
Il pointe sur une zone appelée la pile. Le fonctionnement de cette pile seront expliqués au chapitre 3.
Ce registre contient l'adresse du début des données de vos programmes. Si votre programme utilise plusieurs segments de données, cette valeur devra être modifié durant son exécution.
Ce registre est utilisé, par défaut, par certaines instructions de copie de bloc. En dehors de ces instructions, le programmeur est libre de l'utiliser comme il l'entend.
Ces deux derniers registres ont un rôle fort similaire à celui du segment ES
Le registre FLAG est en ensemble de 16 bits. La valeur représentée par ce nombre de 16 bits n'a aucune signification en tant qu'ensemble : ce registre est manipulé bit par bit, certains d'entre eux inf