Clear Sky Science · ja

有効なサブバイナリを生成するためのスタックベース静的WebAssemblyバイナリスライシングと変異

· 一覧に戻る

コードを小さな断片に分けることが重要な理由

近年のウェブアプリケーションはますますWebAssemblyに依存しています。これはC、C++、Rustで書かれたプログラムをブラウザやクラウド、さらには小型の組み込み機器でほぼネイティブ速度で動作させるための、コンパクトで機械に近い言語です。より多くのシステムがWebAssemblyを実行するにつれて、それらの実行エンジンのバグやセキュリティ欠陥を安全かつ徹底的にテストする手段が必要になります。しかし、実世界のWebAssemblyプログラムは大規模かつ複雑で、十分に多様なサンプルを集めるのは難しい。本稿は、既存のWebAssemblyプログラムを多数の小さく自己完結したミニプログラムに切り出し、さらに巧妙に変異させる新しい手法を紹介します。その結果、有効で扱いやすいテストケースが豊富に得られ、現在のツールよりもはるかに効果的にWebAssemblyエンジンを負荷検査できます。

Figure 1
Figure 1.

一つの大きなプログラムから多数の小さなプログラムへ

著者らは、ランダムにWebAssemblyコードを生成するだけではほとんどうまくいかないという観察から出発します:この言語は特に一時値を保持するスタックの使用に関して厳密に検査されます。ゼロからコードを作る代わりに、既存の「ベース」WebAssemblyバイナリを出発点とし、プログラムスライシングと呼ばれる手法を用います。スライスとは、特定の関心点(例えば関数内部のある命令)に影響を与えるコードだけを残して縮小したプログラムです。データフロー、メモリ使用、制御フローをその点から遡って追跡することで、計算上で「意味を持つ」コンパクトな断片を抽出し、単なるランダムノイズではない部分を取り出します。

見えないスタックを均衡させる

WebAssemblyプログラムは厳格なスタック規律に依存します:各命令は値をポップしプッシュし、構造化ブロックや分岐は終了時にスタックの形を正確に整えておかなければなりません。単純にプログラムの一部を切り出すとほとんど確実にこの規律が破られ、結果は無効になります。以前の研究は固定パターンのダミー命令でスライスを埋めて実行可能にしていましたが、これは多様性を制限していました。本稿では代わりに専用のスタック均衡補正アルゴリズムを導入します。各スライス内部の制御フローを解析し、分岐やブロックの終了が期待されるスタック形状を乱す箇所を見つけ、不要な値を捨てたり適切な型の新しい値を合成したりするための調整済み命令列を挿入します。これらの小さな“ガジェット”は単純な埋め合わせよりも豊かな命令パターンを許容しつつ正当性を回復します。

制御された複雑さで完全なミニプログラムを構築する

補正されたスライスは依然として関数本体に過ぎず、その関数は他の関数を呼び出したり、グローバル変数や線形メモリなどモジュールレベルの機能に依存したりします。そこで著者らは手法を拡張し、完全な実行可能なミニモジュールを組み立てます。ランダムに選んだエントリ関数から出発し、呼び出される関数をユーザ選択の「呼び出し深度」まで繰り返しスライスして補正します。この深度を超えると、呼び出しは引数と戻り値の数を模倣する短い代替で置き換えられ、さらなるコードを取り込まないようにします。システムはまた、型、テーブル、メモリなどWebAssemblyモジュールの周辺セクションを再構成して、各生成バイナリが自己完結し標準のツールやランタイムで直接実行できるようにします。

Figure 2
Figure 2.

慎重な変異による多様化の付与

スライシングによっても多くの生成バイナリは親プログラムに似続けます。カバレッジを広げるため、著者らは各関数を逆方向にたどる変異段階を導入します。入力を消費する命令についてアルゴリズムはランダムに新しい結果型を選び、その型を生成する代替命令を見つけ、さらにその入力を供給する前段の命令を再帰的に変異させてチェーン全体が一致するようにします。これによりスタックの正当性を保ちながら計算を再構成できます。実世界のWebAssemblyプログラムをベースラインと比較すると、変異されたバイナリはより多くの異なる命令パターンを含み、ベクトル演算など普段あまり使われない機能の利用頻度が大幅に増えています。これらはWebAssemblyエンジンの実装全体を検査する上で重要です。

実験が明らかにしたこと

手法を検証するため、著者らはほぼWebAssembly 2.0標準全体をカバーする約17,000行のPython実装を作成しました。数千の実世界バイナリから成る大規模な公開データセットを使い、この手法がプログラムをしばしば元の命令数の一部に縮小できることを示しました—多くの場合、最大ベースラインサイズの40%未満にまで—かつ変異を有効にすると99%以上のケースで有効性を維持します。手法は高速で、適度な大きさの生成バイナリ当たり通常1秒未満で動作し、命令型の範囲とユニークな命令列の数を大幅に増加させます。実務的には、テスターやセキュリティ研究者が限られたWebAssemblyプログラム群を多数で多様な小さな有効バイナリ群へと変換でき、ファジング、差分テスト、回帰テストに理想的な資源を提供することを意味します。

これがWebAssemblyの安全性維持にどう役立つか

日常的な言い方をすれば、本稿はWebAssembly向けの賢い「コード再精錬器」を説明しています:大きなプログラムを多くの小さく意味のある断片に切り分け、それらを言語の厳格な規則に従うよう自動修復し、命令セットの珍しい領域を探索するよう再構成します。これらのミニプログラムは現実的でありながらコンパクトなので、短時間で大量に実行でき、WebAssemblyを実行するソフトウェアの微妙なバグやセキュリティ問題を発見する可能性を高めます。WebAssemblyがブラウザからクラウドやデバイスへ広がる中で、有効で多様なテストバイナリを体系的に生成することは、このエコシステムを堅牢かつ安全に保つための重要な手段となります。

引用: 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

キーワード: WebAssemblyテスト, プログラムスライシング, バイナリ変異, ソフトウェアセキュリティ, ランタイム検証