09 — Opinion / Miss Baker Log

Le binaire a parlé. On a juste appris à écouter.

Un faux fichier système de trente kilo-octets, Ghidra piloté par une IA, et trente-deux fonctions qui retrouvent leur nom en une soirée. Récit d'un reverse engineering où l'humain ne lit presque plus l'assembleur.

Publié31 mai 2026
AuteurStéphane Giner
Lecture7 min
▸ Sommaire · 6 sections
  1. Ce qu'on avait sur la table
  2. Le binaire qui tenait un journal
  3. Reconnaître une bibliothèque à ses jurons
  4. Du tas d'octets au verdict
  5. Qui fait quoi, dans cette histoire
  6. Ce que ça change, et pour qui

Un binaire anonyme de trente kilo-octets disséqué, ses fonctions retrouvant leurs noms une à une sous l'œil croisé d'un humain et d'une machine.
Un binaire anonyme de trente kilo-octets disséqué, ses fonctions retrouvant leurs noms une à une sous l'œil croisé d'un humain et d'une machine.

Trente kilo-octets. Pas un nom de fonction, pas un commentaire, pas un symbole. Un faux fichier système posé à côté d'un logiciel, et une seule question: qu'est-ce qu'il trafique?

Il y a cinq ans, répondre à cette question voulait dire des heures de désassembleur, un café froid et une feuille de papier pour suivre les sauts. Hier soir, ça a pris le temps d'une conversation. Pas parce que l'outil a magiquement « compris » le binaire à ma place, mais parce que la division du travail a changé. Et c'est ça qui mérite qu'on s'y arrête.

Ce qu'on avait sur la table

Trois choses. Ghidra, le désassembleur et décompileur que la NSA a fini par offrir au monde, devenu en quelques années le standard ouvert de l'analyse de binaires. Un petit pont logiciel, du genre qui laisse un assistant comme Claude piloter Ghidra en direct au lieu de se faire recopier du pseudo-code à la main. Et le binaire lui-même: un échantillon anonyme, sans documentation, sans intention déclarée.

Le branchement n'a pas été lisse, d'ailleurs, et c'est honnête de le dire. Le pont avait été compilé pour une version de Ghidra plus ancienne que la mienne, l'extension refusait de se charger, et il a fallu recompiler la chose contre les bibliothèques de la nouvelle version avant que quoi que ce soit ne fonctionne. Une demi-heure de plomberie. On y reviendra, parce que cette friction raconte quelque chose elle aussi.

Une fois le tuyau ouvert, le décor était posé. D'un côté, un outil qui voit chaque octet. De l'autre, un modèle capable de lire ce que l'outil affiche, de tirer des fils, et surtout d'agir: renommer une fonction, poser un commentaire, suivre une référence croisée, le tout directement dans le projet. Moi, au milieu, je donnais le cap.

Le binaire qui tenait un journal

Une fonction de log laissée dans la version finale, où chaque fonction anonyme inscrit son propre nom en passant.
Une fonction de log laissée dans la version finale, où chaque fonction anonyme inscrit son propre nom en passant.

Premier réflexe, le plus bête et le plus efficace: lister les chaînes de caractères. Un binaire dépouillé de ses symboles garde presque toujours ses textes, et les textes parlent.

Celui-là parlait beaucoup. Il tenait un journal de débogage. Quelque part dans le code, une fonction de log recevait, à chaque appel, le niveau du message, le fichier source, le numéro de ligne, et le nom de la fonction appelante. Le développeur avait laissé tout ça dans la version finale.

Vous voyez où ça mène. Chaque fonction anonyme passait son propre nom à ce logger. Il suffisait de décompiler, de regarder quel texte chaque fonction donnait en argument, et de lui recoller son nom d'origine. Pas un nom inventé par une heuristique. Le vrai, celui que le développeur avait tapé.

En quelques passes, trente-deux fonctions sont sorties de l'anonymat. La routine qui charge la vraie bibliothèque système et renvoie les appels vers elle. Le moteur qui cherche un motif d'octets en mémoire et le réécrit. Le détour qui se déclenche au point d'entrée réel du programme cible. Les noms étaient là depuis le début, éparpillés dans un format de log. Le travail n'était pas de les deviner, mais de les ramasser, méthodiquement, sans en oublier.

C'est un cas d'école sur une vérité que les développeurs oublient: ce que vous laissez dans un binaire de production raconte votre programme à qui sait lire.

Reconnaître une bibliothèque à ses jurons

Une série de messages d'erreur préfixés « MH_ », signature reconnaissable d'une bibliothèque de hooking open source.
Une série de messages d'erreur préfixés « MH_ », signature reconnaissable d'une bibliothèque de hooking open source.

Autre chaîne, autre cadeau. Une série de messages d'erreur très reconnaissables, tous préfixés de la même façon, énumérant des états du genre « déjà initialisé », « pas exécutable », « échec de protection mémoire ».

Pour qui a déjà croisé la chose, c'est une signature. Ce préfixe MH_ et cette litanie d'états, c'est MinHook, la bibliothèque de hooking open source écrite par Tsuda Kageyu, distribuée sous licence BSD. Une brique qu'on retrouve partout dans le logiciel parfaitement légitime: overlays de jeu, injecteurs d'effets graphiques, outils d'instrumentation et de profilage. Un indice dans le code laissait même penser à un dérivé adapté au multi-instance plutôt qu'à la version d'origine, mais le moteur reste le sien.

La reconnaître, c'est nommer d'un coup une demi-douzaine de fonctions sans même les décompiler: l'initialisation, la création de hook, l'activation, le convertisseur de code d'erreur en texte. On ne réanalyse pas du code déjà connu. On l'étiquette et on passe à la suite. Et au passage, ça illustre la morale de toute l'affaire: la même bibliothèque sert au meilleur comme au reste, c'est l'intention autour qui décide.

Le binaire devenait lisible par blocs entiers. Pas ligne à ligne. Par reconnaissance de formes.

Du tas d'octets au verdict

La table des fonctions importées, éloquente par ses absences : aucune fonction réseau, aucune écriture du registre, aucun chiffrement.
La table des fonctions importées, éloquente par ses absences : aucune fonction réseau, aucune écriture du registre, aucun chiffrement.

À ce stade, la vraie question n'était plus « comment c'est fait » mais « est-ce que c'est méchant ». Et c'est là que la méthode compte plus que l'outil.

On ne déclare pas un binaire malveillant parce qu'il « a l'air louche ». On regarde ce qu'il peut faire, et surtout ce qu'il ne peut pas faire. La table des fonctions importées, c'est-à-dire les capacités que le programme emprunte au système, dit énormément.

Celle-là était éloquente par ses absences. Aucune fonction réseau. Pas d'ouverture de socket, pas de requête web, rien pour parler à un serveur distant. Donc pas d'exfiltration, pas de canal de commande. Le registre Windows, uniquement lu, jamais écrit. Donc pas d'installation au démarrage. Aucune création de service, aucune tâche planifiée, aucune copie de soi-même ailleurs sur le disque. Aucune fonction de chiffrement. Pas de second fichier caché à déballer.

Ce qui restait, en revanche, était cohérent et précis. De l'écriture mémoire, de la manipulation de threads, du hooking. Une activation conditionnée au nom du programme hôte, comme une liste blanche de cibles. Et une vérification d'autorisation avant de faire quoi que ce soit.

Le portrait se referme tout seul. Ce n'était pas un virus au sens où l'on craint le mot. Pas de propagation, pas de persistance, pas de vol. C'était un outil qui se déguise en composant système pour s'injecter dans un logiciel précis et en modifier le comportement en mémoire, une fois ce logiciel décompressé et arrivé à son point d'exécution réel. La catégorie que les antivirus rangent sous « outil indésirable » plutôt que sous « menace ». La nuance n'est pas cosmétique. Elle change ce qu'on en dit, et ce qu'on en fait.

Le point intéressant, pour un ingénieur, c'est l'architecture. Un moteur générique de patch et de hook d'un côté, réutilisable. Une table de descripteurs de l'autre, qui dit quoi modifier pour telle cible. Séparer la mécanique des données. C'est du bon design logiciel mis au service d'un usage discutable, et c'est précisément ce qui le rend transposable.

Qui fait quoi, dans cette histoire

Il faut être clair sur la répartition, parce que c'est elle le vrai sujet.

L'IA n'a pas « compris » le binaire dans un éclair de génie. Elle a fait, vite et sans se lasser, ce qui fatigue un humain: décompiler des dizaines de fonctions, repérer dans chacune le texte qui trahit son nom, suivre les références croisées, recoller les morceaux, et tout réécrire dans le projet pour que ça reste. Le travail ingrat, celui où l'attention humaine s'effrite vers la trentième fonction et où les erreurs se glissent.

Moi, je n'ai quasiment pas lu d'assembleur. J'ai orienté. D'abord « dis-moi ce que c'est », puis « concentre-toi sur la dangerosité », puis « rends le code lisible ». À chaque étape je tranchais une direction, l'outil creusait, et je relisais le résultat avec l'œil de quelqu'un qui sait à quoi ressemble un faux pas.

C'est ça, le déplacement. On ne passe pas de « l'humain analyse » à « la machine analyse ». On passe de « l'humain déchiffre » à « l'humain dirige une enquête ». La compétence rare n'est plus la capacité à lire mentalement du code machine. C'est de savoir quelle question poser, et de reconnaître quand la réponse sent le vrai ou le faux.

Ce que ça change, et pour qui

Le réflexe serait de conclure que le reverse engineering devient facile. C'est à la fois vrai et trompeur.

Vrai, parce que la barrière d'entrée s'effondre. Comprendre la structure d'un binaire inconnu, retrouver le nom de ses fonctions, établir un premier verdict de dangerosité, c'était un savoir-faire de spécialiste. Ça devient accessible à quiconque sait formuler une demande claire et garder son esprit critique. Pour un analyste qui débute, pour un développeur qui veut savoir ce que charge son jeu, pour une petite équipe sécurité sans budget d'expert, c'est un gain réel.

Trompeur, parce que la même baisse de barrière ne sert pas qu'aux gentils. La technique que cet échantillon mettait en œuvre est ancienne et documentée. Ce qui change, c'est que la comprendre, la cartographier, et donc l'apprendre, ne demande plus le palier d'expertise qui servait de filtre. L'accessibilité coupe des deux côtés. Elle outille l'analyste autant qu'elle éclaire celui qui voudrait reproduire. C'est inconfortable à écrire, mais le nier serait malhonnête.

Et puis il reste la friction. Souvenez-vous de la demi-heure de plomberie au début, l'extension qui refuse de se charger, la recompilation. C'est le rappel utile que rien de tout ça n'est encore un bouton magique. Il faut un environnement qui tient, des outils qu'on sait réparer quand ils cassent, et un humain qui comprend assez le terrain pour repérer quand la machine se trompe avec assurance. Le jour où cette friction disparaîtra complètement sera intéressant à vivre. On n'y est pas.

En attendant, le binaire de trente kilo-octets a fini la soirée avec ses fonctions nommées, ses commentaires posés, et un verdict défendable. Il n'avait rien d'un chef-d'œuvre. C'était un bon élève qui avait oublié d'effacer ses brouillons. La vraie nouvelle n'est pas qu'on l'ait lu. C'est qu'on l'ait lu sans presque jamais regarder l'assembleur.

▸ Briefing hebdomadaire

Vous avez aimé ce briefing ?
On en envoie un par semaine.

L'essentiel de l'IA pour dirigeants, condensé en cinq minutes de lecture. Désinscription en un clic. Aucun spam.

S'inscrire à la newsletter →