古い土地

暗い穴

マリオストーリー(N64)とペーパーマリオ(GC)における任意コード実行/任意スクリプト実行について

 

 2021年の2月下旬、2つのペーパーマリオシリーズで相次いで任意コード実行(ACE)/任意スクリプト実行(ASE)が達成された。今更ながらこのことについて書いてみようと思う。

 

 以下はスピードランナーでもグリッチハンターでもない門外漢の筆者が、自分で理解できる範囲で勝手に抄訳・拙訳したものです。翻訳に許可とれという話だったり理解不足・誤訳で記述に誤りがあったりしたら筆者が全ての責任を負います。つまるところ、公開できるレベルまでブラッシュアップした個人的メモに近いので注意してください。誤りがあればコメント等でご教授ください。

 人物名は敬称略。

 

 

2021/2/20 マリオストーリーN64)でACEによるクレジットワープが達成される

 

 感動的なストーリーなので次のツイートスレッドから抄訳する。

 

 

 今回のACE立役者の1人Rainは5年前、プログラミングについて全く無知の状態でコミュニティに参入してきた。全てはマリオストーリーをぶっ壊すために。

 

 

 マリオストーリーグリッチ研究は昔から盛んで、よく火山が複数回噴火していた*1。それでもACEへの挑戦はことごとく撥ねのけられてきた。

 ブレイクスルーのきっかけとなったのが2021/1/9、スピードランナーMorpheusがマリオストーリービンゴの途中で遭遇したクラッシュである。その壊れ方はどうもこれまで発見されたクラッシュと様子が違う。

 Rain、MikeSLD、SeedBornらが解析したところ、特定の粒子のイフェクトが同時に多数出現した際にオーバーフローしたmatrix bufferがコードとして実行されることが判明する。

 

 マリオがジャンプした際やハンマーを振り下ろした際に生じる埃のイフェクト、そのxy座標をコードとして実行できるようになったのが2021/1/12のこと。マリオストーリーには多数のグリッチが存在するが、プレイヤーが意図的に不正コードを実行したのはこれが初めてのことだった。

www.youtube.com

 

 広義ではすでにACEと言えるかもしれない。しかし、プレイヤーの制御からは程遠かった。

 例えば、クレジットワープを実行できたなら、自信をもってACEと言えるだろう。

 

 このあとImglowerが、オープニングの「クリキングの砦」の時点でイフェクトオーバーフローが可能だと指摘する。

 しかしその実践には、イフェクトのxyz座標調整が大きな壁として立ちふさがった。特にy座標(高さ方向)はプレイヤーがジャンプでしかいじれない値である。

 

 マリオストーリーにおいて、各座標はfloat型という32ビットの数値型で管理されている。xyz座標の計96ビットという莫大な組み合わせ(しかし実現可能となると極めて強い制約がかかってくる!)から、エンディングにたどり着く組み合わせを探さなければならない。

 

 2021/2/18、Frayは正にこの神業をやってのけた。特定のセットアップ(xyz float perfect 6回を含む!)によりACEを概念実証したのだ。ついでにクラッシュしないクレジットワープに必要なコントローラの入力もFrayは用意した。

www.youtube.com

 

 一番大きな問題は解かれた。しかしまだ残っているものがある。xyz float perfext 6回の実装だ。Frayの動画では位置の実装をチートで行っていた。

 その困難を理解するために、いわゆる「ピクセルパーフェクト」と比較してみよう。スーパーファミコンのゲームでsubpixel perfectというと、おおよそ2^8ドット * 2^8 サブピクセル/ドット = 2^16 サブピクセルの中から調整する。(floatは32ビットの数値型なので)float perfectはこの2^16倍細かい作業を要求してくるのだ。xyzそれぞれに対して。

 

 幸いにも、クリキングの砦の奇妙な仕様はこれを可能にした。このマップはカメラが微妙に傾いており、xz座標について +2.1875 unitsか -2.1874359 unitsずつ動かせる。プラスとマイナスの非対称性を利用すれば細かい調整が可能だ(ここにMrCheezeが貢献している)。

 

 2021/2/20、Rainは以上の成果をまとめあげ、通しでACEによるクレジットワープ*2を行った。発売から20年経ってのことである。

 TASのany%は15:27ほどになった(2021/3/12 by Gorialis)。2020年に1:30:45の記録があるので*3、1時間15分の大幅更新である。

www.youtube.com

 

 

 さて、マリオストーリーのスピードランナーがいかにフレーム技を連発する人外揃いとはいえ、今回のACEは到底人間には不可能そうだ。RTAは早くならないのか?

 

 このあとのことはご存知の方も多いかもしれない。2020年以降「ゼルダの伝説 時のオカリナ」がメモリ書き換え方面で爆発的に進展したことを思い出そう。

 

 

 2021/2/22、ACE達成から2日後、Jcog*4時のオカリナ(のプラクティスROM)を拡張パックメモリエディタとして利用し、マリオストーリーをクリアする案を出す。時オカに対してもマリオストーリーに対してもあまりに感情が無い。いや、感情がありすぎるのか。

 なお、時オカをPS1におけるアニメティカのようにメモリエディタとして使う手法はこれが初めてだったはず。

 

 2/28には実際に記録が出ている。2021/12/2現在この「Stop 'n' Swop」カテゴリの世界記録は24:13らしい。*5

 本業はマリオストーリーなのに時のオカリナグリッチもそこそこ上手い。

www.youtube.com

 

 その見た目の異様さが受け海外最大のRTAイベントの1つSGDQで披露された。日本語の記事にもなっている。

『マリオストーリー』の世界最速クリアに、『ゼルダの伝説 時のオカリナ』ロムが使用される。カートリッジを抜き差しするとなぜかエンディングへ - AUTOMATON

 

 今更ながら拙稿を提出するのは「Stop 'n' Swop」の前にあったグリッチハンターたちの探究の軌跡を日本語で残しておきたかったからである。結構シェアされた上の記事はここの部分が薄め。

 

 また、今回のACE達成が努力の結晶であることを知ると、そのたった2日後に出た「Stop 'n' Swop」という奇形のアイディアに対する困惑と爆笑もひとしおではないか。

 

 

 2021/12/2現在でも通常のany% RTAは特にACEの恩恵を受けたりはしていない。Tool-AssistedもOcarina-Assistedも必要としないACEの開発が望まれる。

 

 

 追記(2022/2/5):時オカを必要とせずRTA-viableに近いACEが発見された。

https://www.youtube.com/watch?v=s1FEAIV9MHM&ab_channel=Rainchus

 10時間ぐらい試行してようやく1回成功。RTAに取り入れるならセットアップが欲しい。あと今回はファイルネーム参照を行うのだが、それだけでクレジットワープできるのだろうか。

https://twitter.com/JCog_/status/1490415499355643905?s=20&t=e0HaMytbQZfe_WbwgZFYZw

 

 クレジットワープは出来た。any%は1時間40分から40分ほど縮むことになる。ただし

 一時期の時オカany%と同じ状況になっている。地獄のレギュ改訂議論が待っている。

【時のオカリナ・ムジュラの仮面】SRM/ACE 以降の ゼルダ RTA 史 part 1/2:(2019年10月)~2020年2月 - 古い土地

 

 

 

 

 

 マリオストーリーでのACEから3日後。今度はペーパーマリオRPGで異変が起こる。

 

2021/2/23 ペーパーマリオRPGGC)でASEによるクレジットワープが達成される

 

 TASでは2020年に1:47:09の記録*6があるのでそこから約1時間23分の大幅更新。前記録の時点で「チビヨッシーさえスル―出来れば……」と言われていたが、とんでもない形で解決されてしまった。

www.youtube.com

 

 

 次にMalleoによる43分の解説動画がある

www.youtube.com

 字幕をオンにするとめちゃくちゃ明解な日本語訳を読むことができる。ちょっと長いが動画と字幕で全部理解できると思う。

 以下に自分が理解するために書いた大枠のメモ。

 

 

[要点メモ]

ペーパーマリオRPGではイベントが「キュー(queue)」*7というデータ構造で管理されている。イベントの保存量は256個で埋め尽くすことなど不可能と思われていたが、ここ数年「Pause Hammering」というグリッチにより無限にイベントを生成することが可能になった。

 

・2020年、SolidifiedGaming(以下SG)はPause Hammeringを用いた新種のクラッシュを発見した(マリオストーリーと同様にクラッシュがブレイクスルーを生んでいる!)。

 

・イベントキューの中にはID テーブルとIndex テーブルがあり、これら2つを参照することでイベントを実行している。

 ところで、2つのテーブルはメモリ内で隣り合っている。Pause Hammeringにより256個以上のイベントを生成すると、ID テーブルの情報を Index テーブルまで押し出してしまうことが判明した。この状態のままイベント実行処理に進むと、本来ありえないメモリ領域をイベントとして参照してしまう。

 結果、無効なイベントを実行しようとして先のクラッシュは発生した。

 

・このクラッシュは大きなヒントになる。Pause Hammeringによりイベントとして有効な値が書かれた(本来イベントとは関係ない)メモリを読み込ませることができれば、そのイベントを実行できるだろう。特にエンディングもイベント=マップ移動として処理されているので、Pause Hammeringはクレジットワープへの道を開く

 

・PistonMinerによるイフェクトヒープ(EFF heap)*8の利用案。イフェクトヒープは結構制御できるので、今回はここにクレジットワープ相当の情報を書き込みPause Hammeringでイベントとして実行したい。

 

・イフェクトヒープ上でイベント情報を偽装するにあたり、イベントのNextCmdPtrに相当する部分の書き込みがネックになった。数週間の調査後、SGの発見によりマリオのx座標をNextCmdPtrとして書き込めるようになった。これでコントローラーの入力に相当するアドレスを参照しよう。

・検討の末クレジットワープできるコントローラーの入力は決まったの。しかし、そもそもそれを参照できるx座標が5.9 * 10^(-39) というとんでもなく小さい値だった。実現不可能である。

 また、コントローラーの入力に限らずGCのCachedメモリを参照できるx座標はとんでもなく小さい。x座標を使う方法は無理筋だったのか?

 

・ここでUncachedメモリが活躍する*9。こちらからもコントローラー入力を参照でき、今度は-3.014…と十分現実的な座標になった。1回のfloat perfect もTASなら実装可能。

 

・実際のセットアップではイフェクトヒープを参照するために、Next Event IDをひたすら増やさなければならない。どうするのかというと、看板を9分かけて17000回読む。このパートがやたらうるさい。

 

・最終的にどうクレジットワープするか(参照関係)をまとめよう。

①看板読み・ドア開け・Pause Hammeringにより2番目のイベントとしてイフェクトヒープ内のアドレスが参照される。

②これ以前のセットアップにより有効なイベントとして扱われる。特にNextCmdPtr部分はマリオのx座標により予め調整されており、Uncachedメモリ内のコントローラー入力部分を参照する。

③コントローラー入力もコントローラー 2/3を使って予め調整されていて、その値はエンディング呼び出し関数として実行される。

 

・今後について。今回のASEはTAS専用であってRTAでは無理だろう。しかしイフェクトヒープを使用しない方向など、今後の研究次第では人の手でもエンディング呼び出しが可能になるかもしれない。

・また任意スクリプト実行(ASE)でなく任意コード実行(ACE)はどうなのか? ACEは今の手法だとおそらくできない(し、グリッチハンターたちもASEで満足している? ちょっと拡張すればACEまでできるのか、それともGCの仕様上不可能なのか)

 

 

 ペーパーマリオRPGでのASEは、ゲームキューブオリジナルのタイトルでASE/ACEが達成された初めての例にもなっており、この点でも重要。

 

 

 

 

 

 

 

 

*1:RTAなら今でも見ることが出来る風景

*2:なおこの時点でのセットアップは100%TASでしか使えない代物だったらしい

*3:RTAの世界記録は2021/12/2現在1:39:26

*4:目隠しマリオストーリーを4時間50分でクリアするなど精力的に活動している狂人

*5:当然speedrun.comのカテゴリとしては存在しない。レギュレーションが作れない

*6:RTAの世界記録は2021/12/2現在2:18:42

*7:待ち行列」。先入れ先出しのリスト構造。つまりデータの出し入れが設定された容れ物で、人間が行列に並ぶときと同様に先に入れたものから出ていく。

*8:一種の「ヒープ領域」として確保されているのだろうか?

*9:ペーパーマリオASEの5か月後、時のオカリナWii VCにてany% 7分切りするのにも活躍した