ByteScope

WebAssembly ファイル形式

コンパイル済みの WebAssembly バイナリモジュール。

MIME タイプ
application/wasm
拡張子
.wasm
カテゴリ
実行ファイル・バイトコード

マジックナンバー(ファイル署名)

0x000000000061736D·asm0x00 'asm'

WebAssembly 形式について

WebAssembly のモジュールは、このカタログの中で最も規則的なバイナリ形式です。8 バイトの前置きの後ろにセクションが並び、各セクションは 1 バイトの id、LEB128 の長さ、その長さぶんのペイロードという形をしています。8 バイト目より先に固定オフセットは 1 つもありませんが、必要もありません。読み手はセクションを順に歩き、興味のないものは読み飛ばせます。モジュールの残りをダウンロードしながらブラウザがコンパイルを始められるのはこの性質のおかげです。既知のセクションは決まった順序で現れなければならないので、検証器は 2 度読みせずに不正なモジュールを弾けます。

ヘッダーの構造(バイト単位)

オフセット長さフィールド意味
04magic00 61 73 6D — NUL バイト 1 つに ASCII の asm が続きます。先頭の NUL は意図的で、このファイルが妥当なテキストにならないことを保証します。文字エンコーディングに手を出す何かを経由したモジュールは、予測できない場所ではなく 1 バイト目で失敗します。
44version32 ビットのリトルエンディアンのバージョンで、現在は 01 00 00 00(バージョン 1)。形式が世に出てから変わっていません。以降の拡張はこの番号を上げるのではなく、すべて後方互換の形で行われてきたからです。
81First section idセクションの種類を示す 1 バイト。0 が custom、1 が type、2 が import、3 が function、4 が table、5 が memory、6 が global、7 が export、8 が start、9 が element、10 が code、11 が data、12 が data count。既知のセクションは昇順に、しかもそれぞれ最大 1 回しか現れないので、前置きの直後のバイトはたいてい 1(type)か、ツールチェーンが前に置いた 0(custom)です。
9variableSection size (LEB128)セクション本体のバイト数を符号なし LEB128 で。1〜5 バイトで、各バイトが 7 ビットの値を運び、最上位ビットが継続フラグです。この形式で唯一の長さフィールドであり、セクションの境界はすべてこれを足して求めます。オフセット 8 より後ろに固定アドレスが存在しないのはそのためです。
variablevariableSection bodyエントリのベクタが並び、そのベクタ自体も LEB128 の個数が前に付きます。次のセクション id は、サイズフィールドが主張した最後のバイトの直後から始まるので、id とサイズを足していくとちょうどファイル末尾に着地するはずです。この形式に組み込まれた切り詰め検出です。
variablevariableCustom sections (id 0)意味論を持たない名前付きのブロブです。スタックトレース用の関数名を持つ 'name' セクション、DWARF のデバッグ情報、生成元のメタデータ、ターゲット機能の記録など。他のセクションの間ならどこにでも置けて、リリースビルドがモジュールを小さくするためにやっているのは、まさにこれを剥がすことです。

似た形式との見分け方

紛らわしい形式見分け方
WAT text同じモジュールのテキスト形式は、バイナリの変種ではなくソースです。開き括弧と module という語で始まり、全体が UTF-8 です。00 61 73 6D で始まるものはバイナリ形式で、ブラウザがインスタンス化できるのはそちらだけです。
GZIP実務上は一番よくある混同です。.wasm はほぼ必ず圧縮して配信されるからです。1F 8B で始まるファイルは gzip ストリームで、wasm のマジックナンバーは展開して初めて現れます。ネットワークタブからそのまま保存したビルド成果物は、.wasm という名前の gzip であることがよくあります。
ELF 実行ファイルどちらも仮想または実在のマシン向けのコンパイル出力で、emscripten や wasi-sdk のビルドディレクトリには両方が入っています。.o ファイルは ELF で、wasm なのは最終的なモジュールだけです。オフセット 0 の 7F 45 4C 46 と 00 61 73 6D が、曖昧さなく両者を分けます。
asm.js祖先にあたるもので、古いバンドルの中に今も見つかります。asm.js は JavaScript であり、'use asm' ディレクティブの付いたプレーンテキストのファイルが .js として配られます。これを WebAssembly.instantiate に渡せばマジックナンバーで失敗します。そもそもバイナリモジュールがどこにも入っていないからです。

よくある壊れ方

  • 途中切れ。セクションのサイズは中身より先に宣言されるので、途中までのダウンロードでも、あるセクションが残りより多くのバイトを主張するところまでは正しくパースできます。デコーダは 'unexpected end of section or function' と報告します。このカタログのどの形式よりも明快な切り詰めのメッセージです。
  • gzip 圧縮のまま配信・保存された。Content-Encoding が gzip の .wasm をそのままディスクに書くとファイルは 1F 8B で始まり、WebAssembly.instantiate はマジックナンバーで拒否します。バイト自体は正しく、間違っているのは層だけです。
  • セクション本体に紛れ込んだ 1 バイト。長さフィールドさえ無傷ならセクションの走査は正しい境界に着地し続けるので、モジュールはたいてい読み込まれ、実行時にトラップしたり挙動がおかしくなったりします。ヘッダで失敗するより、ずっと診断しにくい形です。
  • テキストモード転送、あるいはエディタが末尾に改行を足した。末尾に 1 バイト増えるだけで、セクションの走査がファイル末尾の 1 バイト手前で終わるモジュールができあがり、厳格なデコーダは受け入れずに余分なバイトがあると報告します。

この形式の現在地

WebAssembly は、既存のネイティブコードをブラウザへ持ち込むための手段です。動画や画像のコーデック、PDF や CAD のエンジン、SQLite、Python や Ruby のランタイム、エミュレータ、ブラウザ内アーカイブツールの裏にある圧縮ライブラリ。どれも .wasm モジュールとして配られます。JavaScript の代替ではありませんし、UI に使うものでもありません(自前の DOM アクセスを持ちません)。ただし、利用者のマシン上で走らせる必要がある計算量の多い処理には既定の答えであり、アップロード不要でブラウザだけで完結するツールが成立するのもこれのおかげです。ブラウザの外でも、可搬なサンドボックスとして第二の人生を得ました。WASI のランタイム、エッジコンピューティングの基盤、プラグインの仕組みが同じバイナリ形式を使っているので、ウェブサイト向けにビルドしたモジュールがサーバー上でそのまま動くこともよくあります。

WebAssembly ファイルをこのサイトで開く

どれもブラウザ内で動きます。ファイルが端末から出ることはありません。

関連する形式

WebAssembly と混同しやすい形式です。先頭バイトを見比べてください。

形式先頭バイト拡張子
ELF 実行ファイル7F 45 4C 46.elf
Java class ファイルCA FE BA BE.class

よくある質問

ファイルのマジックナンバーとは何ですか?

ファイル先頭の数バイトで、名前が何であろうとその形式を示すものです。PNG は必ず 89 50 4E 47 で始まり、ZIP は 50 4B 03 04 で始まります。OS もブラウザも file コマンドも、拡張子を信用せずこのバイト列を読みます。だからファイル名を変えても中身の正体は変わりません。

マジックナンバーを自分で確認する方法は?

macOS や Linux なら xxd -l 16 ファイル名 で先頭 16 バイトが表示されます。Windows なら PowerShell で Format-Hex -Path ファイル名 -Count 16 です。あるいはこのサイトのファイル形式判別ツールにドロップすれば、ローカルでバイト列を読んで形式を教えてくれます。アップロードはありません。

2 つの形式が同じマジックナンバーを持つのはなぜ?

一方が他方の上に作られているからです。docx、xlsx、pptx、apk、jar、epub はすべて中身が ZIP アーカイブなので ZIP の署名で始まり、区別するには内部のエントリを見る必要があります。Java の class ファイルと macOS のユニバーサルバイナリはどちらも CA FE BA BE で始まり、直後のフィールドで見分けます。

マジックナンバーがまったくないファイルもある?

あります。XML、HTML、JSON、SVG、CSV といったテキストベースの形式には固定のバイト署名がないため、構造から判別します。先頭の <?xml 宣言、<svg 要素、あるいは { に続く引用符付きのキーなどです。これは確定ではなく推測なので、このリファレンスではそうした形式をプローブ判別として示しています。

マジックナンバーが一致すればそのファイルは安全?

いいえ。わかるのは形式であって、中身が無害かどうかではありません。正規の PDF や docx でも悪意のあるペイロードを含んでいることがあります。特に拡張子とバイト列が食い違うときに真の形式を知るのは有用な第一段階ですが、マルウェアスキャンではありません。

WebAssembly かもしれないファイルをお持ちですか?ファイル形式判別ツールで調べる — マジックナンバーをローカルで読み取ります。アップロードは一切ありません。またはすべての形式を見る。