Le décompilateur qui compile n'est pas le décompilateur qui a raison
Trois résultats de 2026 fixent ce qu'un décompilateur LLM peut prétendre. Deux sont de bonnes nouvelles : le raffinement guidé par retour transforme désormais le pseudo-C de Ghidra en source qui recompile et se ré-exécute la plupart du temps, pour quelques centimes par binaire. Le troisième est l'avertissement à imprimer sur chaque outil : du code qui recompile et passe tous les tests livrés diverge encore de l'original sur d'autres entrées dans environ un cas sur vingt, et parfois ce qui a disparu est précisément la vulnérabilité cherchée. Ce billet lit les quatre articles ensemble et se termine par une règle sur la confiance à accorder.
Les chiffres d'un coup d'œil
Le raffinement fonctionne : trois systèmes, une boucle
AutoDecompiler (arXiv 2606.16162, révisé le 3 octobre) est un LLM entraîné par apprentissage par renforcement à traiter la décompilation comme un raffinement itératif plutôt qu'une génération en un coup : il révise son code avec les retours de compilation, d'exécution et de tests entrées/sorties, avec des récompenses pour la validité, la recompilabilité, la cohérence d'exécution et la fidélité sémantique, plus des diagnostics par étape et des avantages pondérés par tour pour que les révisions tardives ne défassent pas les gains acquis. Le résumé revendique des gains constants sur les variantes à un seul tour, à taille égale, sans publier les chiffres.
MCGD (Multi-level Constraint-Guided Decompilation, arXiv 2604.23940) vérifie les candidats à trois niveaux, syntaxe, compilation GCC et équivalence comportementale par des tests générés par LLM, et renvoie les échecs à des agents spécialisés avec un retour d'erreur structuré. Sur 1 641 binaires réels d'ExeBench, à travers RetDec, Ghidra et angr, la ré-exécutabilité atteint 84 à 97 %, soit 28 à 89 points au-dessus des décompilateurs bruts.
CHISEL (arXiv 2608.27981, accepté à ACM CCS SURE 2026) fait de même sans aucune suite de tests : retour du compilateur pour l'analyse statique, fuzzer guidé par la couverture pour l'analyse différentielle, 120 fonctions de O0 à O3, strippées ou non, avec un Gemma4 31B à poids ouverts. Le prix de l'absence de tests est un oracle qui accepte à tort 9,4 % des candidats.
L'ablation de MCGD est la phrase à retenir : les approches qui ne vérifient que la compilation atteignent 0 % d'exactitude comportementale malgré 91 à 99 % de compilation. Un décompilateur jugé sur « est-ce que ça compile » n'est jugé sur rien.
Préserver moins : le résultat de Decompile-Diverge
Liu, Raff et Micinski (arXiv 2609.05370, 4 septembre) posent une autre question : quand la fonction recompilée passe tous les tests livrés, se comporte-t-elle comme l'original sur les entrées que les tests ne couvrent pas ? Leur outil, Decompile-Diverge, génère un pilote, fait croître un corpus de fuzzing à partir du binaire de référence et compare les comportements sur les mêmes entrées. Sur huit systèmes en neuf configurations, 4,9 % des fonctions qui passaient ont divergé, jusqu'à 13 % pour un système. Sur 300 fonctions réelles de bibliothèques GitHub, le raffinement LLM le plus fort fait passer le taux de compilation de Ghidra de 75 à 90 % tandis que le taux de comportement conforme tombe de 74 à 62 %.
Pire, sur 287 fonctions liées à des CVE, jusqu'à un dixième des sorties montrent ce que les auteurs appellent l'absence de crash : une vulnérabilité publiée qui ne se déclenche plus, sans trace visible d'une suppression. La cause est mécanique. Un décompilateur classique laisse des inconnues visibles : undefined4, FUN_00401a30, une arithmétique de pointeur brute. Un modèle de langage les remplace par des champs, des types, des appels et des gardes plausibles, et la garde qu'il ajoute est exactement le contrôle de bornes qui manquait à l'original.
Une règle pour faire confiance à la sortie
Les quatre articles s'accordent sur la barrière, même si aucun ne l'énonce comme une politique : compiler est nécessaire, les tests livrés ne suffisent pas, le fuzzing différentiel contre le binaire de référence est la seule preuve d'équivalence, et en sécurité l'absence de crash est un signal à instruire, pas un succès. Tout l'arbre ci-dessous doit tenir avant d'appeler « source » le texte raffiné ; un candidat qui échoue à la branche fuzzing sert au tri et à rien qui finisse en patch ou en exploit.
Pour une équipe de recherche de vulnérabilités, la conséquence est simple : raffiner avec la boucle, juger avec le fuzzer, et garder la sortie brute du décompilateur à côté de la version raffinée. La belle version sert à lire ; la laide sert à dire vrai.