Plus facile à lire avec un fond crème, une teinte, plus de contraste ou un texte plus grand ? Choisissez vos couleurs et votre texte, une fois pour toutes les pages.

Leçon gratuite

Lire de l’assembleur x86-64

Après cette leçon: Je peux lire quelques lignes d’assembleur x86-64 et dire ce qu’elles font.

Leçon de 60 min5 commandesLab de rétro-ingénierie : lire des programmes avec gdb, radare2, strace et ltrace dans une VM

Sept euros jusqu’à vingt-cinq ans

L’assembleur x86-64 est le langage des instructions que comprennent la plupart des ordinateurs et des serveurs actuels, ceux à processeur Intel ou AMD. En lire quelques lignes suffit pour voir où un programme prend une décision.

Une piscine municipale fait payer 7 euros jusqu’à 25 ans et 12 euros ensuite. Cette règle tient en six lignes de C, et en peu de lignes d’assembleur. Rappel : seuls les programmes de votre labo se lisent ici.

À la fin de cette leçon

Remarque

Je peux lire quelques lignes d’assembleur x86-64 et dire ce qu’elles font.

Mots-clés

MotCe que ça veut direExemple
Registreune toute petite mémoire à l’intérieur du processeureax
Instructionun ordre simple donné au processeurmov
Comparaisonun test de deux valeurs dont le résultat est retenucmp
Saut conditionnelune instruction qui change la suite selon la dernière comparaisonjne
Syntaxe Intelune écriture où la destination vient en premiermov eax, 5

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Des instructions et des registres

Un processeur n’a presque pas de mémoire à lui. Il utilise quelques registres, de petites cases nommées. eax sert souvent à garder une valeur de retour.

Chaque instruction est un nom et des opérandes. En syntaxe Intel, la destination vient en premier : mov eax, 5 range 5 dans eax. add ajoute, sub retire. cmp compare deux valeurs et n’en change aucune. Elle ne laisse qu’un résultat que l’instruction suivante lit.

Un saut conditionnel lit le résultat de cmp

Un programme décide avec deux instructions : d’abord cmp, ensuite un saut conditionnel. je saute si les valeurs étaient égales, jne si elles étaient différentes, jg si la première était plus grande.

Si la condition est fausse, le processeur passe à la ligne suivante. Presque chaque « si » d’un programme devient ce couple.

Écrire le programme tarif.c

Commande
printf '%s\n' '#include <stdio.h>' '#include <stdlib.h>' 'int prix(int age) {' '    int p = 12;' '    if (age < 26) p = 7;' '    return p;' '}' 'int main(int argc, char **argv) {' '    if (argc != 2) return 2;' '    printf("%d euros\n", prix(atoi(argv[1])));' '    return 0;' '}' > tarif.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Le compiler avec les réglages du labo

Commande
gcc -O0 -no-pie -fno-stack-protector -o tarif tarif.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Le tarif pour 20 ans

Commande
./tarif 20

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Le tarif pour 30 ans

Commande
./tarif 30

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

objdump montre la fonction prix en assembleur

Le Run suivant désassemble la fonction prix en syntaxe Intel et garde trois lignes : la comparaison cmp, le saut jg et le retour ret. Les nombres sont en hexadécimal, le préfixe 0x les marque : 0x19 vaut 25 et 0xc vaut 12.

Notez que gcc n’a pas écrit « moins de 26 » : il a écrit « plus de 25, on saute ». C’est le même test dit à l’envers.

Garder la comparaison, le saut et le retour

Commande
objdump -d -M intel tarif --disassemble=prix | grep -E 'cmp|jg|ret'

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Exemple travaillé : la fonction prix, ligne à ligne

InstructionCe qu’elle fait
endbr64, push rbp, mov rbp, rspMet la fonction en place : à ignorer pour l’instant
mov DWORD PTR [rbp-0x14], ediRange l’argument age, arrivé dans edi, en mémoire
mov DWORD PTR [rbp-0x4], 0xcp = 12, la variable p est en mémoire
cmp DWORD PTR [rbp-0x14], 0x19Compare age et 25
jg (vers la ligne du retour)Si age est plus grand que 25, saute le tarif réduit
mov DWORD PTR [rbp-0x4], 0x7p = 7, seulement si le saut n’a pas eu lieu
mov eax, DWORD PTR [rbp-0x4]Met p dans eax, la valeur rendue
pop rbp, retQuitte la fonction

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Erreur fréquente

Attention

Beaucoup de gens lisent mov eax, 5 comme « copier eax dans 5 ». C’est faux : la valeur va vers le premier opérande. Gardez ce réflexe tant que vous lisez la syntaxe Intel. D’autres outils écrivent l’inverse, avec des signes % et $. Vérifiez toujours quelle syntaxe un outil affiche.

Pour aller plus loin

Dans tarif.c, remplacez 26 par 18, recompilez, puis relancez la ligne objdump avec grep. Quel nombre hexadécimal voyez-vous après cmp ?

Calculez-le à la main : l’âge limite devient 17 dans le test « plus grand que ». Convertissez 17 en hexadécimal, puis vérifiez votre résultat.

À propos de ce labo et de sa source: Lab de rétro-ingénierie : lire des programmes avec gdb, radare2, strace et ltrace dans une VM

Vous enseignez à une classe ? Proposez ce module à vos étudiants avec un guide de l'enseignant, des devoirs corrigés et un laboratoire pour chaque étudiant.