14
3

More than 1 year has passed since last update.

コンパイル済み wasm ファイルに後からデータを注入して使用する

Posted at

TL;DR

  • コンパイル済みの wasm ファイルに後からデータを注入し、注入したデータをその wasm から読むことができた
  • あらかじめローカルでビルドしておいた wasm に対し、ブラウザ上で動的にリソースを追加することが可能になる
  • サンプルコードのリポジトリはこちら

はじめに

Rust から WebAssembly の memory.init 命令を使いたかった話 という記事を書きましたが、その後日談です。

上記記事中で、 memory_init 命令を使用したい箇所をダミー関数として括りだしておき、後から本物の memory.init を内容を注入するというアイディアを書きましたが、それがうまく行ったのでその報告です。

サンプルコードの実行

サンプルコードとして、注入された文字列とその長さを読み取って出力するだけの wasm ファイルと、その wasm ファイルに文字列を注入するプログラムを用意しました。ここではそれを実行してみます。

Rustの開発環境一式(ネイティブおよび wasm ターゲット)は揃っているものとします。筆者の手元ではWindows上の rustc 1.72.0-nightly (5ea666864 2023-06-27) で検証を行いました。

  1. cargo cargo-wasiおよびwasmtime1をインストールします。
  2. サンプルコードを適当な場所に clone します
  3. データ注入の対象となるwasmをビルドします
    a. crates/tartget-wasm/ 以下に移動します
    b. cargo wasi build -r を実行します
  4. データ注入を行います
    a. リポジトリのルートに移動し、 cargo run -- (注入元wasm) (生成先) (表示文字列) を実行します
    例: cargo run -- .\target\wasm32-wasi\release\target-wasm.wasi.wasm .\hello.wasi.wasm "hello world!"
    b. 上記コマンドで生成された wasm ファイルを wasmtime などで実行します
    c. a. で与えた表示文字列が出力されれば成功です

技術的な解説

先の記事でも書いたとおり、Rust単体では WebAssembly の memory.init 命令を直に使用することができません。
そのため、データ注入側で memory.init を使ってデータをメモリ上にロードする処理を追加してあげる必要があります。

被注入側

被注入側のコード(target-wasm)には、 memory_init という関数を設けています。注入側のプログラムはこの関数をプレースホルダとして利用し、この関数を書き換えることで上記の処理を追加します。

memory_init には __core_memory_init というエクスポート名が指定してあります。これはビルド時に関数名がwasmファイル内から消されてしまう場合が多いため、注入側がこの関数をエクスポート名から識別できるようにするためです。

また、memory_init は内部で __core_memory_init_dummy というインポート関数を呼び出しています。これは memory_init やその引数を最適化等から防ぐ意図があります。

注入側

注入側のコード(wasm-data-injection-sample)では、まずエクスポートされている関数に、そのエクスポート名をつけ直しています。これは上記の、関数名が消去されている状況に対応するためです。
次に __core_memory_init に対して、実際に WebAssembly の memory.init 命令を叩くコードを追加します。
最後に後片付けとして、最適化防止用のダミーである __core_memory_init_dummy を消去したり、memory_init の不要なエクスポート指定を外したりしています。

最後に

注入側のコードも当然wasmにコンパイルできるため、あらかじめビルドしておいたwasmファイルに対し、ブラウザ上で動的にリソースを追加したりすることができます。
これはブラウザで完結するゲーム制作ツールやコンパイラ、自己解凍書庫などに応用できるのではと考えています。

  1. wasmer など、WASIに準拠する他のランタイムでも構いません

14
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
3