Clear Sky Science · fr
Tranchage binaire statique basé sur la pile et mutation de WebAssembly pour générer des sous‑binaires valides
Pourquoi il est important de scinder le code en morceaux plus petits
Les applications web modernes s’appuient de plus en plus sur WebAssembly, un langage compact de type machine qui permet à des programmes écrits en C, C++ ou Rust de s’exécuter à une vitesse quasi‑native dans les navigateurs, les clouds et même sur de petits dispositifs embarqués. À mesure que davantage de systèmes exécutent WebAssembly, il devient nécessaire de disposer de méthodes sûres et exhaustives pour tester ces moteurs d’exécution à la recherche de bogues et de failles de sécurité. Mais les programmes WebAssembly réels sont volumineux, complexes et difficiles à rassembler en assez grande variété. Cet article présente une nouvelle façon de découper des programmes WebAssembly existants en de nombreux mini‑programmes autonomes, puis de les modifier intelligemment. Le résultat est un approvisionnement riche en cas de test valides et de petite taille qui peuvent mettre à l’épreuve les moteurs WebAssembly bien plus efficacement que les outils actuels.

D’un gros programme à beaucoup de petits
Les auteurs partent de l’observation que générer du code WebAssembly aléatoire marche presque jamais : le langage est fortement vérifié, en particulier autour de son utilisation d’une pile qui stocke des valeurs temporaires. Plutôt que de créer du code à partir de rien, ils commencent par un binaire WebAssembly « de base » existant et utilisent une technique appelée tranchage de programme. Une tranche est une version réduite d’un programme qui conserve uniquement les portions de code qui influencent un point d’intérêt choisi, par exemple une instruction particulière à l’intérieur d’une fonction. En suivant les flux de données, l’utilisation de la mémoire et le flot de contrôle en remontant depuis ce point, la méthode extrait un fragment compact qui « a encore du sens » en termes de calcul, plutôt que d’être du bruit aléatoire.
Maintenir la pile invisible en équilibre
Les programmes WebAssembly reposent sur une discipline stricte de la pile : chaque instruction dépile et empile des valeurs, et les blocs structurés et les branches doivent laisser la pile exactement dans la bonne forme à la fin. Couper naïvement des parties d’un programme casse presque toujours cette discipline, rendant le résultat invalide. Des travaux antérieurs réparaient les tranches en les bourrant avec des motifs fixes d’instructions factices, ce qui les rendait exécutables mais limitait leur diversité. Cet article introduit à la place un algorithme dédié de correction de l’équilibre de la pile. Il analyse le flot de contrôle à l’intérieur de chaque tranche, repère des endroits où les branches ou les fins de bloc perturbent la forme attendue de la pile, puis insère des séquences d’instructions adaptées qui éliminent les valeurs inutiles et synthétisent de nouvelles valeurs des bons types. Ces petits « gadgets » restaurent la validité tout en autorisant des motifs d’instructions beaucoup plus riches que le simple bourrage.
Construire des mini‑programmes complets avec une complexité contrôlée
Une tranche corrigée n’est encore qu’un corps de fonction, et cette fonction peut appeler d’autres fonctions ou dépendre de caractéristiques au niveau du module comme des variables globales et la mémoire linéaire. Les auteurs étendent donc leur méthode pour assembler des mini‑modules exécutables complets. En partant d’une fonction d’entrée choisie aléatoirement, ils tranchent et corrigent de façon itérative toutes les fonctions appelées, jusqu’à une « profondeur d’appel » choisie par l’utilisateur qui contrôle combien de couches d’appels sont conservées. Au‑delà de cette profondeur, les appels sont remplacés par de courts substituts qui miment le bon nombre d’arguments et de résultats sans importer davantage de code. Le système reconstruit aussi les sections entourant un module WebAssembly — types, tables, mémoire, etc. — afin que chaque binaire généré soit autonome et puisse être exécuté directement par les outils et environnements d’exécution standard.

Ajouter de la variété par une mutation soigneuse
Même avec le tranchage, beaucoup de binaires générés ressemblent encore à leur programme parent. Pour élargir la couverture, les auteurs introduisent une phase de mutation qui travaille en remontant chaque fonction. Pour les instructions qui consomment des entrées, l’algorithme choisit aléatoirement un nouveau type de résultat, trouve des instructions de substitution qui produisent ce type, puis mutile de façon récursive les instructions précédentes qui fournissent ses entrées afin que toute la chaîne reste cohérente. Cela préserve la correction de la pile tout en remodelant le calcul. Par rapport à un ensemble de programmes WebAssembly du monde réel pris comme référence, les binaires mutés contiennent bien plus de motifs d’instructions distincts et exploitent beaucoup plus souvent des fonctionnalités rarement vues, comme les opérations vectorielles, ce qui est important pour tester pleinement les implémentations des moteurs WebAssembly.
Ce que révèlent les expériences
Pour tester leur approche, les auteurs ont implémenté environ 17 000 lignes de Python couvrant près de la totalité de la spécification WebAssembly 2.0. En utilisant un vaste jeu de données public contenant des milliers de binaires réels, ils ont montré que leur technique peut réduire régulièrement les programmes à une fraction de leur nombre d’instructions d’origine — souvent en dessous de 40 % des tailles maximales de la référence — tout en les gardant valides dans plus de 99 % des cas lorsque la mutation est activée. La méthode s’exécute rapidement, typiquement bien en dessous d’une seconde par binaire généré de taille modérée, et augmente significativement à la fois la diversité des types d’instructions et le nombre de séquences d’instructions uniques observées. En termes pratiques, cela signifie que testeurs et chercheurs en sécurité peuvent transformer un corpus modeste de programmes WebAssembly en une large suite diversifiée de petits binaires valides, idéale pour le fuzzing, les tests différentiels et les tests de régression des environnements d’exécution WebAssembly.
Comment cela aide à maintenir WebAssembly sûr
En termes concrets, l’article décrit un « affinage de code » intelligent pour WebAssembly : il découpe les gros programmes en nombreux morceaux plus petits et significatifs, les répare automatiquement pour qu’ils respectent toujours les règles strictes du langage, puis les reforme pour explorer des coins inhabituels de l’ensemble d’instructions. Parce que ces mini‑programmes restent réalistes tout en étant compacts, ils peuvent être exécutés rapidement et en grand nombre, augmentant les chances de découvrir des bogues subtils ou des problèmes de sécurité dans les logiciels qui exécutent WebAssembly. À mesure que WebAssembly se diffuse des navigateurs vers les clouds et les dispositifs, une génération systématique de binaires de test valides et diversifiés constitue un outil important pour maintenir cet écosystème robuste et sécurisé.
Citation: Choi, G., Jeon, S. Stack-based static WebAssembly binary slicing and mutation for generating valid sub-binaries. Sci Rep 16, 10910 (2026). https://doi.org/10.1038/s41598-026-45837-y
Mots-clés: Tests WebAssembly, tranchage de programme, mutation binaire, sécurité logicielle, vérification à l’exécution