Clear Sky Science · sv
Stapelbaserad statisk WebAssembly-binära delning och mutation för att generera giltiga sub-binarier
Varför det är viktigt att dela upp kod i mindre delar
Moderna webbappar förlitar sig i allt högre grad på WebAssembly, ett kompakt maskinliknande språk som låter program skrivna i C, C++ eller Rust köras i nästan inbyggd hastighet i webbläsare, moln och till och med små inbäddade enheter. När fler system kör WebAssembly behöver vi säkra och grundliga metoder för att testa dessa körningsmotorer för buggar och säkerhetsbrister. Men verkliga WebAssembly-program är stora, komplexa och svåra att samla i tillräcklig variation. Denna artikel introducerar ett nytt sätt att snida upp befintliga WebAssembly-program i många mindre, självständiga miniprogram och sedan klokt justera dem. Resultatet är ett rikt utbud av giltiga, lättsmälta testfall som kan stressa WebAssembly-motorer mycket effektivare än dagens verktyg.

Från ett stort program till många små
Författarna utgår från observationen att att slumpmässigt generera WebAssembly-kod nästan aldrig fungerar: språket är strikt kontrollerat, särskilt kring användningen av en stack som håller temporära värden. Istället för att skapa kod från grunden börjar de med en befintlig ”bas” WebAssembly-binär och använder en teknik kallad programslicing. En slice är en reducerad version av ett program som behåller endast de koddelar som påverkar en vald intressepunkt, till exempel en viss instruktion inne i en funktion. Genom att följa dataflöde, minnesanvändning och kontrollflöde bakåt från den punkten extraherar metoden ett kompakt fragment som fortfarande ”betyder något” beräkningsmässigt, istället för att vara slumpmässigt brus.
Att hålla den osynliga stacken i balans
WebAssembly-program förlitar sig på en strikt stackdisciplin: varje instruktion poppar och pushar värden, och strukturerade block och grenar måste lämna stacken i exakt rätt form när de avslutas. Att näppeligen klippa bort delar av ett program bryter nästan alltid mot denna disciplin och gör resultatet ogiltigt. Tidigare arbete reparerade slices genom att fylla dem med fasta mönster av dummy-instruktioner, vilket höll dem körbara men begränsade deras variation. Denna artikel introducerar istället en särskild algoritm för att korrigera stackbalansen. Den analyserar kontrollflödet inom varje slice, hittar platser där grenar eller blockslut rubbar den förväntade stackformen, och infogar skräddarsydda instruktionssekvenser som släpper oönskade värden och syntetiserar nya av rätt typer. Dessa små ”gadgets” återställer korrektheten samtidigt som de tillåter mycket rikare instruktionsmönster än enkel utfyllnad.
Bygga hela miniprogram med kontrollerad komplexitet
En korrigerad slice är fortfarande bara en funktionskropp, och den funktionen kan anropa andra eller bero på modulnivåegenskaper som globala variabler och linjärt minne. Författarna utökar därför sin metod för att montera kompletta, exekverbara minimoduler. Med start från en slumpmässigt vald ingångsfunktion slicear och åtgärdar de upprepade gånger alla funktioner som anropas, upp till ett användarvalt ”anropsdjup” som kontrollerar hur många lager av anrop som bevaras. Bortom det djupet ersätts anrop med korta stand-ins som efterliknar rätt antal argument och resultat utan att dra in mer kod. Systemet rekonstruerar också de omgivande sektionerna i en WebAssembly-modul — typer, tabeller, minne med mera — så att varje genererad binär är självständig och kan köras direkt av standardverktyg och körmiljöer.

Lägga till variation genom noggrann mutation
Även med slicing liknar många genererade binärer fortfarande sitt föräldraprogram. För att bredda täckningen inför författarna en mutationsfas som arbetar bakåt genom varje funktion. För instruktioner som konsumerar indata väljer algoritmen slumpmässigt en ny resultattyp, hittar ersättningsinstruktioner som producerar den typen, och muterar sedan rekursivt de tidigare instruktionerna som levererar dess indata så att hela kedjan fortfarande går ihop. Detta bevarar stackkorrektheten samtidigt som beräkningen omformas. Jämfört med en basuppsättning av verkliga WebAssembly-program innehåller de muterade binärerna många fler distinkta instruktionsmönster och använder i mycket större utsträckning sällan sedda funktioner såsom vektoroperationer, vilket är viktigt för att testa hela implementeringen av WebAssembly-motorer.
Vad experimenten visar
För att testa sitt tillvägagångssätt implementerade författarna ungefär 17 000 rader Python som täcker nästan hela WebAssembly 2.0-standarden. Med en stor offentlig datamängd av tusentals verkliga binärer visade de att deras teknik rutinmässigt kan krympa program till en bråkdel av deras ursprungliga instruktionsantal — ofta under 40 % av de största baseline-storlekarna — samtidigt som de förblir giltiga i över 99 % av fallen när mutation är aktiverat. Metoden är snabb, typiskt väl under en sekund per genererad binär av måttlig storlek, och ökar avsevärt både sortimentet av instruktionstyper och antalet unika instruktionssekvenser som observeras. I praktiska termer innebär detta att testare och säkerhetsforskare kan omvandla ett blygsamt korpus av WebAssembly-program till en stor, diversifierad svit av små, giltiga binärer som är idealiska för fuzzing, differentiell testning och regressionstestning av WebAssembly-körtider.
Hur detta hjälper att hålla WebAssembly säkert
I vardagstermer beskriver artikeln en smart ”kodförfinares” för WebAssembly: den hugger upp stora program i många mindre, meningsfulla bitar, reparerar dem automatiskt så att de fortfarande följer språkets strikta regler och omformar dem sedan för att utforska ovanliga hörn av instruktionsuppsättningen. Eftersom dessa miniprogram förblir realistiska men kompakta kan de köras snabbt och i stor mängd, vilket ökar chansen att upptäcka subtila buggar eller säkerhetsproblem i mjukvaran som kör WebAssembly. När WebAssembly sprider sig från webbläsare till moln och enheter erbjuder sådan systematisk generering av giltiga, varierade testbinarier ett viktigt verktyg för att hålla detta ekosystem robust och säkert.
Citering: 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
Nyckelord: WebAssembly-testning, programslicing, binär mutation, programvarusäkerhet, körningsverifiering