
『ゼルダの伝説 風のタクト』RTAにてとうとう“エンディングすっ飛び”バグ「任意コード実行」手法が見つかる。しかし議論も勃発
活発なスピードランコミュニティを持つことでも知られる『ゼルダの伝説 風のタクト』において、ついに任意コード実行を可能とするバグが発見された。コミュニティはスピードラン事情を一変させる新しいテクニックの対応に追われているようだ。

往年の名作にして、非常に活発なスピードランコミュニティを持つことでも知られる『ゼルダの伝説 風のタクト』において、ついに任意コード実行を可能とするバグが発見された。これはスピードランにおいては革命的な発見であり、従来の世界記録であったタイムが大きく塗り替えられた。しかし同時に、コミュニティはこのスピードラン事情を一変させた新しいテクニックの対応に追われてもいるようだ。
任意コード実行(Arbitrary Code Execution、以下ACE)はその名の通り、プログラム上の脆弱性を突いて攻撃者(この場合、プレイヤー)が 任意のコードをゲームに実行させることができるバグのことを指す。ACEはスピードランの文脈ではエンディングを直接呼び出すことに使われることが多く、「どんな手段を使ってもいいのでエンディングに辿り着く」までを競うカテゴリであるany%において、辿り着く究極にして最後の手段と呼んでもいい。
もちろんゲームにおいてそうあるバグではないのだが、『ゼルダの伝説』シリーズのスピードランとACEは切っても離せない関係にあり、『時のオカリナ』『ムジュラの仮面』両作品はどちらもこのACEが発見されている。当然ながらACEの発見がスピードランに与える影響は絶大であり、両作品のスピードラン史は「ACE発見以前」と「以後」に分けても良いレベルだと言えるだろう。そんなACEがついに、『風のタクト』でも発見されたと言うのだ。「発見されてしまった」と、そう言い換えてもいいだろう。
“通常プレイ”はわずか2分程度
本校執筆現在で世界最速タイムと思われるJTown2909氏の16分48秒のクリア動画では、このACEが実際にどのようにして行われているのか、確認することが可能だ。
動画では、まず『風のタクト』RTAではお馴染みの高速泳法バグを活用し風のタクトを入手。その後、 真っ先にタウラ島に向かっている。ACEを実行するにあたってもっとも重要なアイテムである「写し絵の箱」(カメラ)を手に入れるためである。カメラ入手後は、いかにも“セットアップ(特定の精密な立ち位置や動作を人力で実現するための手順)”といった動作が続き、謎の茂みをカメラで接写する。

茂みの撮影が終わるとセーブ&ロードが入り、プロロ島に戻る。ここではカメラとタクトを駆使してさらに様子のおかしい挙動が繰り返され、再び露骨にセットアップらしき動きで海岸の特定位置に移動しカメラを起動。その後何事もなかったように小屋のドアを開くと、突然エンディングが始まる。約17分でのクリアとなるが、通常プレイの範疇で理解できる動きはおそらくチンクルの牢屋でカメラを取得する2分間くらいしかないと言える。

このACEがどういう原理で実現しているかについて、非常に専門的な内容ではあるが、筆者の理解の及ぶ範囲で簡単な解説を試みよう。キモとなるのは「テキストスタッキング」と呼ばれる技術だ。『風のタクト』ではNPCのテキストボックスはそのNPCが実際に視界に入るまで生成されないという性質がある。また、カメラのアルバム画面からの画面遷移中には一瞬だけリンクを操作できるタイミングがあり、このタイミングでNPCに話しかけることが出来る。この2つを組み合わせるとNPCの会話がトリガーされているが、(NPCを視界に入れていないため)テキストボックスが実際に表示されない、テキストボックスの「予約状態」のようなものを作り出すことが出来る。
そしてこの予約状態でさらに同じ動作を他のNPCにもすることで、テキストボックスが複数同時に予約されている状態を作り出すことが可能となっている。この状態で、会話を予約したNPCを同時(同フレーム)に視界に入れると、テキストボックスを生成するためのコードが複数同時に走り、想定されていない挙動を引き起こす。
具体的には、まずproc_msgと呼ばれるテキストボックスの表示を管理するオブジェクト(アクター)が2つ生成される。またこれらのテキストを画面に表示するためのJ2DScreenというオブジェクトもそれぞれ生成されるが、このJ2DScreenへのポインタ(メモリアドレスを指す変数)であるsScreenは、本来テキストボックスは画面上に1つずつしか表示されない想定のため、テキストボックス間で共有して使われる静的なポインタとなっている。つまり、proc_msgが2つ同時に発生してしまうと、2つ目のproc_msgが1つ目のセットしたsScreenを上書きしてしまうのだ。2つのproc_msgはそれぞれ終了時にdMsg_Deleteという関数を呼び出し利用したメモリ領域を解放しようとするが、先に解放された側の画面オブジェクトをsScreenが指し続けてしまう(ダングリングポインタ)ため、その後の処理で解放済み領域を再び参照することになる。これはUse-After-Freeと呼ばれる現象で、脆弱性の温床として知られている。
ここからはゲーム内の具体的な手順と一緒に追っていこう。まずテキストスタッキングでNPC AとBのテキストボックスを「予約」するとproc_msgが2つ走り、sScreenの上書きが発生する。次に、まずBだけをを視界に入れるとBのテキストボックスがトリガーされ、会話終了時にBのproc_msgの終了処理によってsScreenの示す先のメモリ領域が解放される(Aのproc_msgが残っているためsScreenはクリアされず、アドレスを保持したままとなる)。
Bとのテキストボックスを閉じた後、今度はAを視界に入れる。するとAのテキストボックスがトリガーされるが、ここで会話終了時にAを視界から外してからテキストボックスを閉じる。すると終了処理であるdMsg_Delete関数が呼び出されず、これは次にAが視界に入った時に実行されることになる。

最後に、リンクの位置を厳密に調整した後、カメラを起動すると同時にAを視界に入れる。この時、まずカメラの起動によってアルバムに保存された写真のデータがメモリに読み込まれるのだが、非常に都合の良いことに「アルバム3枚目に保存された写真の特定のピクセルデータ」がちょうどこのsScreenが示す先のメモリ領域にロードされる。そしてこの次のフレームでAが視界に入ったことによるproc_msgの終了処理dMsg_deleteが走る。こちらの終了処理もsScreenの示す先のメモリ領域を解放しようとするのだが、この上書きされたsScreenの示す先には前述のピクセルデータがすでにロードされており、dMsg_deleteがそのアドレスの示す先のコードを実行してしまうのだ。この時、3枚目の写真の特定ピクセルに80ABBDFFを書き込めるような写真が用意すると、このアドレス(正確には、それに8を足した80ABBE07)のコードが実行されるよう誘発することが出来ることになる。そしてこれが例の茂みの写真である。
ちなみに80ABBE07は、「リンクのX座標の4バイト目」に相当するアドレスである。先程カメラを構える前にリンクのX座標とY座標を正確に調整していたのはこのためで、ここでリンクの位置座標のバイトデータを読み込ませることで今度は803F0F3Cというアドレスに飛ばすことが可能だ。そしてこのアドレスはコントローラー2~4の入力領域となっている。コントローラー2~4の入力はメモリ上ではかなり長い連続した生バイト列であり、ボタンやスティックによる特定の入力でこのバイト列を「次にロードした時にエンディングを呼び出す」といった任意の命令列に仕立て、ゲームに命令として解釈・実行させることができる。ここまでしてついに、ACEの成立というわけだ。

人力ではきわめて困難
なおこのACEを成立させるためのゲーム内の動作(茂みの撮影や立ち位置の調整、NPC会話によるテキストスタッキング)などは全て人力でも十分可能だが、問題はコントローラー2~4による入力である。非常に精密で正確な状態が要求されるこの部分は現状では人力では到底可能ではなく、外部ツールを使って事前に用意することによってのみ可能となっている。この入力に関してはセットアップでどうこうなるというものでもないので、単純にルールがそれを許すか、という問題になってくるだろう。
『風のタクト』スピードランのルールセットでは現状プレイ中にインプットビューワーのような外部ツールを利用することは許可されていないが、事前に利用する際の規定は用意されていない。ACEを実行するためにはインプットビューワーを見ながら正確にスティックやトリガーの位置を調整する必要があるが、例えばコントローラーポート2に接続されたコントローラーの入力は、コントローラーを引き抜いた際の入力の状態でメモリに維持されるため、1つのコントローラーでポート2~4に順々に入力していくことでプレイを開始する前に全ての準備を完了しておくことが可能となっている。ルールの穴を付くようだが、実際現状では特にルールには抵触していないため、これを今後どう扱うかという点でコミュニティでも議論が紛糾しているようだ。また、コントローラー2~4の入力ではなく、人力で実現可能ななんらかの別のデータでのエンディング呼び出しが今後発見される可能性も大いにあるだろう。
そもそも、ACEはany%における「ちゃぶ台返し」に等しい。今まで積み重ねてきたテクニックや技術などが全て無に帰すため、基本的には別カテゴリとして併設されることが多い。『時のオカリナ』や『ムジュラの仮面』が通ってきたのと同じように、『風のタクト』スピードラン界は今回見つかってしまったACEに対して、今後カテゴリやルールセットでどうやって対応していくか、吟味していく必要があるだろう。とはいえ、タイムで見れば革命的な更新であるのも確か。『ゼルダ』走者たちの努力と熱意はとどまることを知らず、ゲームキューブ作品すらもその魔の手からは逃げられないようだ。次に“破壊”されるのは一体どの『ゼルダ』なのか、恐ろしくもあり楽しみでもある。
