
Je t'ai laissé sur quatre verbes. Ripper, réindexer, détourner, compresser. Le savoir-faire qui transformait une disquette protégée en copie propre sur Atari ST, à la fin des années 80. Je pensais ce langage mort avec les lecteurs trois pouces et demi. Il y a quelques soirs, je l'ai retrouvé mot pour mot dans un fichier de trente kilo-octets, sur une machine que mes vingt ans n'auraient pas su imaginer.
Le faux fichier qui mentait

Le décor a changé, l'astuce non. Windows, quand un programme réclame une bibliothèque, regarde d'abord juste à côté de l'exécutable avant d'aller fouiller le système. Tu poses là un faux composant, baptisé comme une brique système que presque tous les logiciels chargent, et il se fait avaler à la place du vrai. Pour rester invisible, ce faux composant ré-exporte tous les noms de l'original et renvoie poliment chaque appel vers la vraie bibliothèque. Le programme hôte ne voit rien. Il croit parler au système. Il parle à toi.
C'est la disquette qui mentait, en costume moderne. Hier on cachait la façon de lire les pistes. Aujourd'hui on se déguise en fichier système. Dans les deux cas, le but est le même : être chargé par un programme qui ne t'a rien demandé, et t'installer entre lui et ce en quoi il a confiance.
Ghidra, et une machine qui tient le débogueur
À l'époque, j'avais un débogueur et une nuit. Là, j'avais Ghidra, le désassembleur ouvert que la NSA a fini par lâcher dans la nature, et quelque chose de neuf à côté : un pont qui laisse une intelligence artificielle piloter Ghidra en direct. Décompiler une fonction, la renommer, poser un commentaire, suivre une référence croisée, le tout écrit directement dans le projet.
Je vais être honnête sur la répartition, parce que c'est elle, le vrai sujet. La machine n'a pas eu d'illumination. Elle a fait, vite et sans fatigue, le travail qui m'usait les yeux à vingt ans : décompiler des dizaines de fonctions d'affilée, recoller les morceaux, ne rien oublier. Moi, je n'ai presque pas lu d'assembleur. J'ai dirigé. Dis-moi ce que c'est. Concentre-toi sur la dangerosité. Rends le code lisible. À chaque cap, elle creusait, et je relisais avec l'œil de celui qui sait à quoi ressemble un faux pas. On n'est pas passé de « l'humain analyse » à « la machine analyse ». On est passé de « l'humain déchiffre » à « l'humain mène l'enquête ».
Le binaire qui tenait un journal

Premier réflexe, le même qu'il y a trente-huit ans : regarder ce que le binaire laisse traîner. Avant, on lisait les pistes brutes. Aujourd'hui, on liste les chaînes de caractères. Et celui-là était bavard.
Il tenait un journal de débogage. Une fonction de log qui recevait, à chaque appel, le niveau du message, le fichier source, la ligne, et le nom de la fonction appelante. Le développeur avait tout laissé dans la version finale. Tu vois où ça mène. Chaque fonction anonyme criait son propre nom au passage. Il suffisait de décompiler, de lire quel texte chacune donnait au logger, et de lui recoller son étiquette d'origine. Pas un nom deviné par une heuristique. Le vrai, celui que le programmeur avait tapé.
En quelques passes, trente-deux fonctions sont sorties de l'anonymat. C'était mon vieux filer, l'extracteur, mais retourné comme un gant. Au lieu de voler les données du jeu, on volait au binaire la vérité sur lui-même. Et la leçon est identique des deux côtés de l'histoire : ce que tu laisses dans une version de production raconte ton programme à qui sait lire.
Reconnaître une bibliothèque à ses jurons
Autre chaîne, autre cadeau. Une série de codes d'erreur très reconnaissables, tous préfixés pareil, qui énuméraient des états du genre déjà initialisé, pas exécutable, échec de protection mémoire.
Pour qui a déjà mis les mains dedans, c'est une signature. C'était MinHook, une bibliothèque de détournement de fonctions open source écrite par Tsuda Kageyu, sous licence BSD. La même brique qu'on retrouve dans des overlays de jeu, des injecteurs d'effets graphiques, des outils d'instrumentation parfaitement honnêtes. La reconnaître, c'est nommer d'un coup une demi-douzaine de fonctions sans même les décompiler. On ne réanalyse pas du code déjà connu, on l'étiquette et on avance.
Et c'était ça, mon vieux détournement. Hier je remplaçais une routine de lecture par la mienne en patchant un vecteur. Aujourd'hui MinHook pose un trampoline devant la fonction d'origine et redirige l'exécution vers la version maison. Le mot a changé. Le geste est exactement le même.
La table, encore la table

Puis le moteur a montré son ossature, et là, j'ai souri tout seul.
Au cœur du faux composant, un mécanisme générique de modification mémoire et de hook, réutilisable tel quel. Et à côté, une table de descripteurs qui lui disait quoi faire : pour ce module, voici les octets à réécrire, voici les fonctions à détourner. Une routine d'aiguillage interrogeait cette table avec un numéro de mode. L'application est-elle dans la liste des cibles. Donne les patches. Donne les hooks. Exécute le post-traitement.
Sépare la mécanique des données. C'était, trait pour trait, ma table de redirection du ST, celle qui faisait correspondre un numéro de bloc logique à un emplacement de fichier. Le moteur générique d'un côté, le descriptif spécifique à la cible de l'autre. Trente-huit ans d'écart, et la même idée d'architecture, parce que c'est simplement la bonne façon de faire ce genre de chose.
Décompresser en RAM, à la bonne adresse

Restait le dernier verbe. La cible était compressée, empaquetée par un packer d'exécutable, exactement comme on packait nos fichiers à la fin du chargement. Patcher trop tôt, c'est patcher de la donnée compressée qui ne veut rien dire.
La parade du faux composant était d'une élégance qui m'a parlé directement. Il posait un hook sur le point d'entrée du programme, détectait la signature du dépaquetage, attendait que le code se décompresse tout seul en mémoire, et ne frappait qu'au vrai point d'exécution, une fois la cible étalée en clair dans la RAM. Hier, ma routine dépackait les données pile à l'adresse attendue avant de rendre la main. Là, le code attendait que quelqu'un d'autre dépaquette, puis se glissait au bon endroit au bon instant. Le même rendez-vous avec la mémoire, à la milliseconde près.
Le verdict, et ce qui n'a pas changé
Une fois le code lisible, la vraie question n'était plus comment, mais est-ce méchant. Et là, la méthode prime sur l'outil.
On ne déclare pas un binaire malveillant parce qu'il sent mauvais. On regarde ce qu'il peut faire, et surtout ce qu'il ne peut pas. La liste des fonctions empruntées au système parlait par ses absences. Aucune capacité réseau, donc rien à exfiltrer, aucun serveur à appeler. Le registre lu mais jamais écrit, donc aucune installation au démarrage. Pas de service, pas de tâche planifiée, pas de copie de soi ailleurs, aucun chiffrement. Ce qui restait était cohérent : de l'écriture mémoire, du hook, une activation réservée à une liste de cibles, et une vérification d'autorisation avant d'agir, neutralisée d'un saut conditionnel transformé en saut sec.
Le portrait se referme seul. Pas un virus, au sens où l'on craint le mot. Pas de propagation, pas de persistance, pas de vol. Un outil qui se déguise en composant système pour s'injecter dans un programme précis et lui changer son comportement en mémoire. Côté antivirus, ça tombe dans la case outil indésirable, pas dans la case menace. La nuance n'est pas cosmétique, elle change ce qu'on en dit.
Ripper, réindexer, détourner, compresser. Je les avais quittés sur une disquette trois pouces et demi. Je les ai retrouvés dans une DLL. Les protections changent de costume à chaque génération, les chips et les systèmes d'exploitation avec. Les idées des crackers, elles, ne vieillissent pas. La seule chose qui a vraiment changé, c'est qui tient la pelle. Le travail ingrat, celui où l'attention humaine s'effrite vers la trentième fonction, une machine le fait maintenant à ma place pendant que je décide où creuser. La barrière d'entrée qui m'a coûté des années s'est effondrée en une soirée. Reste à savoir, comme toujours, qui s'en empare et pour en faire quoi.