Un ELF contient des symboles — noms de fonctions, de variables globales — stockés dans des sections comme .symtab, .strtab, .dynsym. Selon qu’ils ont été retirés ou non, l’analyse d’un même binaire change radicalement de nature.
Un binaire non strippé conserve sa table de symboles complète, parfois même ses informations de débogage : main, check_password, vulnerable, win apparaissent en clair. Un binaire strippé a vu ces symboles supprimés, en tout ou partie ; les fonctions deviennent sub_401020, fcn.00401123, sans noms parlants — une technique classique d’anti-analyse. Il faut noter que le strip ne change ni le code machine, ni les adresses d’un binaire par ailleurs identique : il n’affecte que la visibilité qu’on en a.
Face à un binaire non strippé
C’est le cas le plus favorable : la stratégie consiste à capitaliser sur les noms. nm -C, objdump -t, ou info functions sous GDB, révèlent d’emblée des fonctions comme check_serial, validate, vuln, win. Pour un crackme, repérer check_serial() permet d’y poser directement un point d’arrêt et de suivre la logique de validation — voire de patcher le retour pour le forcer. Pour du pwn, on identifie tout aussi vite la fonction vulnérable (vuln(), overflow()) et une éventuelle fonction win() menant à un shell. nm livre en outre directement les adresses PLT (system@plt, puts@plt) nécessaires à un ret2plt ou une chaîne ROP. On passe alors bien moins de temps sur la reconstruction structurelle, et davantage sur la logique et l’exploitation proprement dites.
Face à un binaire strippé
L’information « humaine » a disparu, mais le processeur, lui, s’en moque : il faut recréer du sens.
Ce qui subsiste malgré tout
Même strippé, un binaire conserve son .text intact, ses chaînes .rodata, et — point souvent négligé — ses symboles dynamiques (.dynsym) s’il est lié dynamiquement. readelf -s ./bin | grep FUNC révèle fréquemment que les fonctions d’API (puts, printf, read, system) restent nommées, même quand toute la logique interne du programme a perdu ses noms.
Reconstruire la structure
Radare2, IDA, Ghidra ou Cutter effectuent une première passe de détection de fonctions, qu’il faut ensuite renommer progressivement : fcn.00401234 devient vuln_like() si l’on y voit un gets ou un read sans borne de taille, fcn.004013f0 devient menu() si elle affiche plusieurs choix. La méthode suit un ordre assez stable :
- partir de l’entrée —
_start, oumainsi l’outil l’a retrouvé, sinon relancer une détection de fonctions (aflsous radare2) ; - suivre les chaînes de caractères —
strings -tx ./binrévèle offsets et contenus ; on cherche ensuite, dans l’outil, les références croisées vers"Enter password","Wrong","FLAG", dont les fonctions appelantes sont presque toujours les fonctions de logique ; - repérer les patrons de code classiques — prologue de fonction, appels à
strcmp/memcmp/strncmp, gestion de fichiers (fopen,fgets) ; - renommer au fur et à mesure, même approximativement (
read_input,do_auth,loop_menu) — essentiel pour ne pas se perdre dans un crackme long.
Exploiter malgré l’absence de symboles
Pour un binaire non-PIE, les gadgets ROP restent parfaitement localisables même strippé — ROPgadget --binary ./bin | grep "pop rdi ; ret" s’en moque entièrement — et les offsets restent stables d’une exécution à l’autre.
Plusieurs stratégies s’offrent alors. Le ret2plt / ret2libc reste souvent accessible via .dynsym, qui conserve puts@plt, printf@plt, system@plt — plus simple, en somme, que de chercher une éventuelle win(). Cette dernière, précisément, se retrouve fréquemment malgré le strip : les auteurs de crackme « oublient » souvent de nettoyer les chaînes "sh", "/bin/sh", "cat flag" de .rodata, qu’il suffit de remonter jusqu’à leur fonction appelante. Enfin, si vraiment rien n’est exploitable (binaire statiquement lié, strip agressif), une chaîne ROP « pure » reste possible : charger les registres pour un execve("/bin/sh", NULL, NULL) et clore par un gadget syscall — voir le ret2syscall.
Ce que le choix pédagogique révèle
Un binaire non strippé, remis en exercice, teste avant tout la compréhension d’une logique — une condition à inverser, un algorithme à décrypter — plus que la survie sans repères. Un binaire strippé teste autre chose : la capacité à reconstruire une vue globale, la discipline du renommage, et l’aptitude à travailler avec très peu de confort — gadgets anonymes, syscalls directs. Le strip n’est d’ailleurs, dans une perspective d’analyse de malware, qu’une première couche d’anti-analyse parmi d’autres, aux côtés des techniques d’obfuscation plus poussées.
Mini-aide-mémoire
Pour vérifier si un binaire est strippé : file ./bin (« not stripped » / « stripped ») et readelf -S ./bin (présence de .symtab, .strtab).
Face à un binaire non strippé : nm -C / objdump -t pour cartographier les fonctions, points d’arrêt par nom sous GDB, recherche des fonctions « intéressantes » par leur nom puis par leur code.
Face à un binaire strippé : strings -tx, readelf -s (dynsym), checksec ; laisser l’outil reconstruire les fonctions, puis renommer progressivement, suivre les références croisées de chaînes et d’appels libc, chercher gadgets ROP et syscalls directs.