Pendant la plupart de l'histoire informatique, « le binaire » sur le web était JavaScript — du texte lisible par l'homme que vous pouviez ouvrir dans devtools et comprendre. WebAssembly a changé cela. Wasm est un format d'instruction binaire compact qui s'exécute à une vitesse proche de celle du natif dans les navigateurs, et de plus en plus sur les périphéries, dans les modules, dans les runtimes serverless et à l'intérieur d'applications intégrant un sandbox wasm. Sa performance et sa portabilité en ont fait un succès, mais elles ont aussi créé une nouvelle réalité pour quiconque fait du travail de sécurité : une part croissante de la logique expédiée aux utilisateurs arrive maintenant sous forme d'un blob binaire opaque plutôt que de code source lisible. Quand ce blob est un mineur de crypto-monnaie contrebandé dans une page Web, une vérification de licence obfusquée ou un maliciel utilisant wasm pour éviter la détection axée sur JavaScript, quelqu'un doit en faire l'ingénierie inverse. En 2026, ce « quelqu'un » est de plus en plus souvent un analyste de sécurité, et l'outillage s'est mature pour répondre au besoin.
Ce guide est une introduction pratique à l'ingénierie inverse de WebAssembly. Il explique ce qui rend wasm différent des binaires natifs, parcourt la chaîne d'outils open-source devenue standard — la Web Assembly Binary Toolkit (WABT), le décompilateur diswasm, Binaryen et wasm-tools — et établit un flux de travail pour passer d'un fichier .wasm inconnu à une compréhension de ce qu'il fait. L'objectif est de démystifier un format qui semble intimidant mais qui est, à certains égards, plus analysable que le code natif.
Ce qui rend wasm différent
Pour faire l'ingénierie inverse de wasm efficacement, vous devez comprendre comment il diffère des binaires x86 ou ARM pour lesquels la plupart des outils RE ont été construits. Les différences jouent dans les deux sens — certaines rendent wasm plus facile à analyser, d'autres plus difficile.
Le premier trait déterminant est que wasm est une machine à pile, pas une machine à registres. Le code natif manipule un ensemble fixe de registres CPU ; les instructions wasm poussent et dépilent des valeurs sur une pile opérande. C'est étrange au premier abord, mais c'est aussi structuré et prévisible, et cela signifie qu'il n'y a pas d'allocation de registre dont se préoccuper. Le deuxième trait, et plus utile, est que wasm a un flux de contrôle structuré. Où le code natif utilise des sauts arbitraires que les décompilateurs doivent minutieusement reconstruire en boucles et conditionnelles, wasm a des constructions explicites de block, loop et if intégrées au format. Le graphe du flux de contrôle est, en un sens, déjà récupéré — l'une des parties les plus difficiles de la décompilation native vous est largement donnée. Le troisième trait est une structure de module propre : un module wasm est organisé en sections bien définies (types, imports, fonctions, code, données, exports), vous savez donc toujours où sont les fonctions, ce que le module importe de son hôte et ce qu'il expose.
Cette structure import/export est la chose la plus précieuse pour un analyste. Un module wasm ne peut rien faire au monde extérieur de lui-même — il n'a pas d'appels système. Tout ce qu'il fait qui compte (accès réseau, manipulation du DOM, E/S de fichiers) se fait en appelant des fonctions hôtes importées, et ces imports sont explicitement listés dans le module. La lecture de la section d'import vous dit les capacités du module avant d'analyser une seule instruction : s'il n'importe rien qui peut atteindre le réseau, il ne peut pas exfiltrer les données ; s'il importe des fonctions pour la récupération ou la crypto, c'est là qu'il faut regarder. C'est un niveau d'aperçu des capacités en amont que les binaires natifs donnent rarement.
Le côté plus difficile : wasm supprime les noms de symbole par défaut (les fonctions deviennent func[42]), les types sont limités à une poignée de primitifs numériques donc la structure de haut niveau est perdue, et les chaînes d'outils et les obfuscateurs peuvent produire un code dense, généré par machine. Mais le flux de contrôle structuré et la disposition explicite du module compensent largement, ce qui est pourquoi la décompilation wasm est généralement considérée comme plus tractable que la décompilation native.
La chaîne d'outils
La chaîne d'outils RE wasm open-source est petite, axée et complémentaire — aucun outil unique ne fait tout, et le flux de travail standard utilise plusieurs ensemble. Il est utile de savoir à quoi sert chacun.
WABT, la Web Assembly Binary Toolkit, est la base. Elle convertit entre le format binaire .wasm et le format texte lisible .wat (WebAssembly Text) avec wasm2wat, vide les sections et désassemble le code avec wasm-objdump, valide les modules et — important pour l'ingénierie inverse — produit une décompilation de type C avec wasm-decompile. WABT est la première chose à laquelle vous recourez : elle transforme le binaire en quelque chose de lisible et vous montre la structure du module. Son option --generate-names synthétise les noms pour les fonctions non nommées, ce qui rend la sortie beaucoup plus facile à suivre.
diswasm va un cran plus loin vers la lisibilité, en décompilant le bytecode wasm en pseudocode de haut niveau plutôt que le WAT fidèle mais bas niveau que wasm2wat produit. Où WABT vous montre exactement ce que dit le module, diswasm essaie de vous montrer ce qu'il veut dire, en reconstruisant du code structuré qui se lit plus comme un programme normal. Pour comprendre rapidement la logique lors du triage, cette vue de haut niveau est précieuse.
Binaryen est une chaîne d'outils de qualité compilateur dont la pertinence pour l'ingénierie inverse est légèrement indirecte mais réelle. Son outil wasm-opt exécute l'optimisation et les passes de transformation sur un module, et plusieurs de ces passes — pliage constant, élimination du code mort, simplification locale — se produisent à nettoyer le bruit que les compilateurs et les obfuscateurs laissent derrière. Une astuce pratique est d'exécuter un module confus à travers les passes de simplification puis de décompiler le résultat plus propre. Le wasm-dis de Binaryen désassemble également, et wasm-reduce peut réduire un module au morceau minimal qui exhibe un comportement d'intérêt.
wasm-tools, la boîte à outils bas niveau Rust, complète les choses avec la validation, l'analyse, la mutation et le support des propositions wasm plus récentes (composants, GC, threads). Quand vous avez besoin d'inspecter ou de manipuler programmatiquement un module — ou quand un binaire utilise des fonctionnalités que les outils plus anciens rejettent — wasm-tools est l'option moderne et activement maintenue. Ensemble, ces quatre couvrent le cycle de vie de l'ingénierie inverse : WABT et diswasm pour lire, Binaryen pour simplifier, wasm-tools pour valider et muter.
Un flux de travail d'analyse pratique
Confronté à un fichier .wasm inconnu — disons, tiré d'une page Web suspecte — un flux de travail reproductible vous amène à comprendre rapidement. La séquence ci-dessous est celle sur laquelle les analystes expérimentés convergent.
Commencez par les capacités, pas le code. Avant de lire une seule instruction, videz les imports et exports : wasm-objdump -x module.wasm (ou les sections d'import/export spécifiquement). Les imports vous indiquent ce que le module peut faire — quelles fonctions hôtes il peut appeler — et les exports vous indiquent ses points d'entrée, les fonctions que le JavaScript environnant invoque réellement. Cela encadre tout : un module qui n'importe que des fonctions mathématiques est une menace très différente de celle qui importe fetch et des primitifs crypto. De nombreuses analyses se terminent effectivement ici, parce que la liste des capacités répond déjà à la question (« il ne peut pas atteindre le réseau, donc il n'exfiltre rien »).
Ensuite, désassemblez avec des noms : wasm2wat --generate-names module.wasm. Cela vous donne la structure fidèle avec les noms synthétisés, et vous permet de voir la disposition de la section, la section de données (contenant souvent des chaînes, URLs ou constantes intégrées intéressantes pour grep) et la forme globale. Grep la section de données et le WAT pour les chaînes révélatrices — domaines, chemins d'API, constantes crypto, messages d'erreur — qui révèlent fréquemment l'intention sans lecture approfondie du code.
Ensuite, si vous avez besoin de comprendre une logique spécifique, décompillez pour la lisibilité : exécutez wasm-decompile (WABT) ou diswasm pour obtenir du pseudocode, et si la sortie est dense ou obfusquée, simplifiez d'abord avec Binaryen (wasm-opt --precompute --simplify-locals --vacuum) avant de décompiler le module nettoyé. Concentrez votre lecture sur les fonctions exportées et tous les appels aux imports intéressants — vous avez rarement besoin de lire le module entier. Enfin, pour un échantillon vraiment têtu, wasm-reduce peut isoler le module minimal qui reproduit un comportement, réduisant la surface que vous devez comprendre.
Cette progression capability-first, then-structure, then-logic reflète la bonne pratique native d'ingénierie inverse mais exploite les avantages de wasm : les imports explicites rendent l'étape de capacité inhabituellement informative, et le flux de contrôle structuré rend l'étape de décompilation inhabituellement propre.
Maliciel Wasm et évasion
Il est intéressant de comprendre pourquoi les analystes ont de plus en plus besoin de ces compétences, parce que cela façonne ce qui faut regarder. Les attaquants ont adopté wasm pour des raisons concrètes. La plus établie est le cryptomining : la vitesse proche du natif de wasm le rend idéal pour miner la crypto-monnaie dans le navigateur d'une victime, et les mineurs de conduite libre ont expédié leurs boucles de hachage en tant que wasm pendant des années. Plus largement, wasm offre un degré d'évasion : un écosystème de sécurité qui a passé une décennie à apprendre à analyser et détecter le JavaScript malveillant est moins mature à l'inspection du wasm, donc déplacer la logique vers un module wasm peut glisser au-delà des outils et des examinateurs humains qui ne lisent que le JavaScript. La logique obfusquée — vérifications de licence, routines anti-analyse, dérivation de clé — est également plus difficile à extraire d'un binaire wasm que du JS lisible, donc certains fournisseurs et certains maliciels utilisent wasm spécifiquement pour résister à l'ingénierie inverse.
L'implication défensive est que « nous avons examiné le JavaScript » n'est plus une assurance suffisante pour le code expédié par le Web. Si une page expédie un module wasm, ce module fait partie de la surface d'attaque et mérite l'analyse capability-first ci-dessus. La bonne nouvelle, réitérant le thème, est que la structure d'import explicite de wasm rend au moins la question de capacité rapide à répondre — vous pouvez déterminer si un module peut faire quelque chose de dangereux beaucoup plus rapidement que vous ne pouvez pour un binaire natif obfusqué. Cette asymétrie favorise les défenseurs disposés à apprendre la chaîne d'outils.
Intégration de wasm dans les outils RE traditionnels
Une question qui se pose rapidement pour les reversers expérimentés est de savoir s'ils peuvent utiliser leurs outils existants — Ghidra, IDA, Binary Ninja — sur wasm plutôt que d'apprendre une chaîne d'outils entièrement séparée. La réponse en 2026 est un oui qualifié, et il est intéressant de comprendre le compromis. Les modules communautaires apportent le support de wasm dans les principales plates-formes RE : il y a des modules processeur/chargeur WebAssembly pour Ghidra et autres, vous permettant de charger un .wasm et d'utiliser le flux de travail de vue de graphe familier, les références croisées et le décompilateur que vous connaissez déjà. Pour un analyste profondément compétent dans l'un de ces environnements, cette familiarité peut l'emporter sur les avantages des outils wasm dédiés.
Le compromis est la maturité et l'adéquation. La chaîne d'outils wasm dédiée — WABT, diswasm, Binaryen — est construite autour de la structure réelle de wasm et tend à produire des résultats plus propres et idiomatiques pour wasm spécifiquement, tandis que les plates-formes RE générales adaptent un modèle conçu pour le code natif à une machine à pile, ce qui peut être lossy ou maladroit aux bords. L'approche pragmatique sur laquelle de nombreux analystes se concentrent est d'utiliser les deux : les outils wasm CLI légers pour le triage de capacité rapide décrit plus tôt (vider les imports, désassembler, grep strings, obtenir du pseudocode rapide), et ensuite, si un échantillon mérite une analyse manuelle profonde, charger le dans leur plate-forme de choix pour le travail d'ingénierie inverse plus lourd avec tous ses caractéristiques de navigation et d'annotation.
C'est aussi où les fondamentaux de l'ingénierie inverse se transposent. L'ingénierie inverse de wasm n'est pas une discipline entièrement séparée — les compétences fondamentales de lecture du code d'assemblage, de suivi du flux de contrôle et de données, d'identification des fonctions intéressantes à partir de leurs appelants et appelés, et de raisonnement sur ce qu'un binaire fait, se transposent directement. Ce qui change, c'est les détails de surface : une machine à pile au lieu de registres, un flux de contrôle structuré au lieu de sauts bruts, des imports hôtes au lieu d'appels système. Un reverseur expérimenté peut apprendre wasm rapidement précisément parce que les intuitions durement gagnées s'appliquent toujours ; les outils spécifiques à wasm éliminent simplement les frictions. Cette transférabilité est rassurante pour quiconque hésite à investir — vous étendez les compétences existantes, pas en recommençant.
Le résultat net
WebAssembly est devenu un format binaire de première classe du Web moderne, ce qui signifie le lire est maintenant une compétence de sécurité plutôt qu'une curiosité. Wasm est véritablement différent du code natif — une machine à pile avec un flux de contrôle structuré, des sections de module propres et, plus utilement, des imports hôtes explicites qui révèlent les capacités d'un module avant de lire un code. La chaîne d'outils open-source correspond au besoin : WABT pour désassembler et décompiler, diswasm pour le pseudocode de haut niveau, Binaryen pour simplifier l'obfuscation, et wasm-tools pour valider et muter. Travaillez capability-first — imports et exports avant instructions — puis désassemblez avec des noms, puis décompillez les parties qui importent, en simplifiant selon les besoins. Faites cela, et le nouveau binaire du Web cesse d'être un blob opaque et devient juste une autre chose que vous pouvez lire.
Références et ressources
Outils
Contexte et analyse
- Ingénierie inverse de WebAssembly — PNF Software
- Analyse des binaires WebAssembly — Forcepoint X-Labs
- Une étude complète des techniques de décompilation pour les binaires WebAssembly
Cheatsheets 1337skills associés