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

Suivre les appels avec ltrace et strace

Après cette leçon: Je peux voir avec ltrace et strace ce qu’un programme demande à la bibliothèque et au système.

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

Quel fichier ce programme cherche-t-il ?

ltrace et strace sont deux outils qui affichent les appels qu’un programme fait, sans lire une seule instruction. ltrace montre les appels à la bibliothèque, strace ceux au système d’exploitation.

Un programme de la salle de lecture répond « Pas de profil. » sans dire de quel fichier il parle. Sa trace le dit. Rappel : seuls les programmes de votre labo se lisent ici.

À la fin de cette leçon

Remarque

Je peux voir avec ltrace et strace ce qu’un programme demande à la bibliothèque et au système.

Mots-clés

MotCe que ça veut direExemple
Appel de bibliothèqueun appel à du code déjà écrit, fourni avec le systèmestrlen
Appel systèmeune demande du programme au noyau du systèmeopenat
Noyaule cœur du système, qui seul touche aux fichiers et à l’écran
Tracela liste des appels qu’un programme a faits, dans l’ordre
ENOENTle code du noyau pour « ce fichier n’existe pas »

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

Une bibliothèque et un noyau, deux sortes d’appels

Un programme demande des choses à deux endroits. La bibliothèque fournit du code tout fait, comme strlen qui compte des lettres ou getenv qui lit une variable. Le noyau est le seul à toucher aux fichiers et à l’écran : on lui demande par un appel système, comme openat ou write.

Les deux Runs suivants écrivent profil.c et le compilent. Il lit la variable SALLE, puis cherche un fichier de réglages.

Écrire le programme profil.c

Commande
printf '%s\n' '#include <stdio.h>' '#include <stdlib.h>' '#include <string.h>' 'int main(void) {' '    const char *salle = getenv("SALLE");' '    if (salle == NULL) salle = "inconnue";' '    printf("Salle : %s (%d lettres)\n", salle, (int)strlen(salle));' '    FILE *f = fopen("/tmp/.profil-demo.cfg", "r");' '    if (f == NULL) { puts("Pas de profil."); return 1; }' '    fclose(f);' '    puts("Profil charge.");' '    return 0;' '}' > profil.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 profil profil.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.

ltrace affiche les appels à la bibliothèque

ltrace lance le programme et note chaque appel de bibliothèque avec ses arguments et ce qu’il rend. L’option -e getenv+fopen ne garde que ces deux fonctions.

Le trait de la sortie profil->getenv(…) dit que l’appel part du programme. nil veut dire « rien ». Le Run garde avec grep les lignes qui contiennent ->.

Suivre getenv et fopen

Commande
ltrace -e getenv+fopen ./profil 2>&1 | grep -- '->'

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.

Donner une valeur à la variable SALLE

Commande
SALLE=B12 ltrace -e getenv+fopen ./profil 2>&1 | grep -- '->'

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.

strace affiche les appels au système

strace note chaque appel au noyau. -e trace=openat ne garde que l’ouverture de fichiers. Une ligne finit par = 3 si le fichier s’est ouvert, ou par = -1 ENOENT s’il n’existe pas.

Le premier Run garde avec grep la ligne qui contient ENOENT : le fichier que le programme a cherché en vain. Le second ne montre que l’appel write, avec le texte envoyé à l’écran.

Trouver le fichier qui manque

Commande
strace -e trace=openat ./profil 2>&1 | grep ENOENT

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.

Voir ce que le programme écrit

Commande
strace -e trace=write ./profil 2>&1 >/dev/null

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é : ce que montre chaque outil

OutilIl voitPour le programme profil
ltraceLes appels de bibliothèquegetenv("SALLE"), puis fopen du fichier de réglages
straceLes appels au noyauopenat du fichier, puis write du texte
Ni l’un ni l’autreLes calculs entre deux appelsLe compte des lettres reste invisible

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

Erreur fréquente

Attention

Beaucoup de gens pensent qu’une trace explique pourquoi le programme agit ainsi. Elle montre seulement ce qu’il a demandé et ce qu’on lui a répondu. Pour savoir pourquoi, il faut relire la décision avec objdump ou radare2. Et un ENOENT n’est pas toujours une erreur : le chargeur essaie plusieurs chemins de bibliothèques.

Pour aller plus loin

Lancez strace -e trace=openat,write ./profil 2>&1 | tail -3 et comptez les appels. Dans quel ordre le programme ouvre-t-il le fichier et écrit-il son texte ?

Dites ensuite ce que le programme ferait si le fichier cherché existait, en une phrase. Son texte « Profil charge. » est dans le C, et strings profil le montre sans lancer rien.

À 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.