Un outil dont personne ne connaît l’auteur
La rétro-ingénierie, en anglais reverse engineering, consiste à comprendre comment un programme fonctionne à partir du programme lui-même, sans son code source. Elle sert à trouver une faille, à vérifier ce que fait un outil inconnu ou à comprendre ce que le compilateur a produit.
Une bibliothèque universitaire trouve un petit outil sur l’un de ses serveurs. Plus personne ne sait qui l’a écrit. Avant de le lancer, il faut le lire.
La règle de ce module
Important
Vous lisez uniquement les programmes de votre labo, sur votre propre copie. Vous n’ouvrez jamais le logiciel de quelqu’un d’autre, ni une licence, ni un jeu, ni une protection. Le but est de défendre : trouver et corriger les failles. Rien ici ne vise un vrai système. Entrer sans droit dans un système est un délit.
À la fin de cette leçon
Remarque
Je peux apprendre ce que contient un programme sans le lancer.
Mots-clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Rétro-ingénierie | comprendre un programme à partir du programme seul | |
| Binaire | un programme tel que la machine l’exécute, un fichier d’instructions | bibli |
| ELF | le format des programmes sous Linux | |
| Chaîne de caractères | un texte lisible rangé dans un fichier | Pret : 3 semaines |
| Désassembleur | un outil qui retraduit les instructions en assembleur lisible | objdump |
| Assembleur | les instructions du processeur écrites en mots courts | call |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
La commande file décrit un binaire
Un programme compilé est un binaire. Sous Linux, son format s’appelle ELF. La commande file lit le début du fichier et dit ce que c’est, sans rien exécuter.
Les trois Runs suivants écrivent un petit programme à nous, bibli.c, le compilent, puis le décrivent. Les réglages de gcc sont ceux du labo : pas d’optimisation, des adresses fixes et pas de protection de pile, pour que la lecture reste simple.
Écrire le programme bibli.c
printf '%s\n' '#include <stdio.h>' 'int main(void) {' ' puts("Bienvenue a la bibliotheque");' ' puts("Pret : 3 semaines");' ' return 0;' '}' > bibli.cAffiché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
gcc -O0 -no-pie -fno-stack-protector -o bibli bibli.cAffiché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.
Demander ce que contient le fichier
file bibliAffiché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.
strings sort le texte d’un binaire
Un programme porte son texte avec lui, lisible, que son auteur l’ait voulu ou non. strings affiche chaque suite de caractères lisibles du fichier.
La liste est longue, car un binaire contient aussi des noms de fonctions. Le Run garde donc seulement la ligne qui contient Pret, avec grep. Vous trouvez ce que le programme dit sans l’avoir lancé.
Chercher une phrase dans le fichier
strings bibli | grep PretAffiché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.
Erreur fréquente
Attention
Beaucoup de gens pensent que compiler un programme cache ce qu’il dit. Compiler change la forme du programme, pas son contenu : les textes, les noms d’appels et l’ordre des étapes y sont toujours. Tout ce qu’un programme doit savoir pour fonctionner, un lecteur peut le trouver. Ne cachez donc jamais un secret dans un programme.
La commande objdump montre les instructions
Un désassembleur retraduit les instructions en assembleur : une instruction par ligne, en mots courts. objdump -d est celui de binutils. L’option --disassemble=main ne garde que la fonction main, le point de départ du programme.
Le Run choisit la syntaxe Intel avec -M intel et garde les lignes qui contiennent puts. Il y en a deux, car le programme affiche deux phrases. Chacune est un call, un appel de la fonction puts de la bibliothèque, qui affiche du texte.
Trouver les appels à puts dans main
objdump -d -M intel bibli --disassemble=main | grep putsAffiché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é : trois outils, trois questions
| Outil | Question posée | Réponse pour bibli |
|---|---|---|
| file | Quelle sorte de fichier ? | Un exécutable ELF 64 bits, noms conservés |
| strings | Quel texte contient-il ? | Bienvenue a la bibliotheque, Pret : 3 semaines |
| objdump -d | Quelles instructions ? | Deux appels à puts dans main |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Pour aller plus loin
Changez la phrase de puts dans bibli.c, recompilez avec la même commande gcc, puis relancez strings bibli | grep avec un mot de votre nouvelle phrase.
Ensuite, dites en une phrase pourquoi un mot de passe écrit en toutes lettres dans un programme est lisible par n’importe qui. Votre labo contient un dossier revlab : ne le lisez pas encore, la leçon suivante prépare l’outil dont vous aurez besoin.