- NES版Tetrisのキルスクリーンでのクラッシュは単なるゲーム終了ではなく、改造していないハードウェアとカートリッジ上で新しい動作を実行する入口として利用されている
- レベル155以降、スコア計算がフレーム間に終わらないと制御フローが崩れ、ゲームが意図しないRAM位置を命令のように読み込む任意コード実行につながる可能性がある
- Famicomの拡張コントローラーポート入力RAMがジャンプルーチンの位置と重なっており、3番・4番コントローラーのボタン入力でクラッシュ後に移動するアドレスを操作できる
- Displaced Gamersは、ジャンプ先をハイスコアテーブルへ送り、名前とスコアのデータをNES CPUのopcodeのように読ませる概念実証コードを公開した
- 入力可能な文字と数字、保存装置がないことにより実用性は限られるが、クラッシュ回避パッチやRAM全体の制御へ拡張できる可能性がある
キルスクリーンのクラッシュがコード実行に変わる流れ
- NES版Tetrisのクラッシュは、スコア処理ルーチンが新しいスコアをフレーム間に計算するのに時間がかかりすぎると発生する可能性がある
- この状況はレベル155以降に現れる可能性がある
- 遅延が起きると、制御コードの一部が新しいフレームの書き込みルーチンによって中断される
- その後ゲームは次の命令を探すため、意図しないRAM位置へジャンプする
- 通常、この予期しないジャンプによりRAM先頭付近のごみデータをコードのように読み込み、すぐにクラッシュする
- Displaced Gamersの最近の動画は、NES版Tetrisにハイスコアテーブルを機械語命令のように読ませる手順を公開した
- 似た任意コード実行グリッチは、過去にSuper Mario World、Paper Mario、The Legend of Zelda: Ocarina of Timeでも知られていた
- NES版Tetrisに外部コードを入れる基本的な方法は少なくとも2021年から公に理論化されており、コミュニティ内ではRAM全体を制御する方法もかなり前から知られていたとされる
Famicomの入力処理でジャンプ位置を制御
- このハックはTetrisのクラッシュ方法だけでなく、Famicomの入力構造にも依存している
- 日本版Famicomは米国版NESと異なり、2つのコントローラーが本体に固定接続されており、サードパーティ製コントローラーは前面の拡張ポートに接続できた
- Tetrisのコードはこの「追加」コントローラーポートの入力を読み取る
- アダプターを使えば、標準のNESコントローラーをさらに2つ接続できる
- FamicomにはBullet-Proof Softwareによる別のTetris版があったが、この入力処理の性質はNES版Tetrisのコードで動作する
- 追加コントローラー入力を処理するRAM領域は、クラッシュ時に使われるジャンプルーチンのメモリ位置と重なっている
- クラッシュでジャンプルーチンが中断されると、そのRAMにはコントローラーで押されたボタンを表すデータが入っている
- プレイヤーはこの値を使って、クラッシュ後にゲームコードが移動する位置を精密に制御できる
ハイスコアテーブルを実行コードのように読む
- Displaced Gamersのジャンプ制御方式には特定のコントローラー入力が必要になる
- 3番コントローラーで
upを押す
- 4番コントローラーで
right、left、downを押す
leftとrightを同時に入力するにはコントローラー操作が必要になる
- この入力はジャンプコードを、ゲームのハイスコア一覧の名前とスコアが保存されたRAM領域へ送る
- B-Typeのハイスコアテーブルの目標位置に
(Gを入れると、ゲームはハイスコアテーブル内の別の領域へ再びジャンプする
- その後ゲームは名前とスコアを順番に読み取り、Displaced Gamersが「bare metal」コードと呼ぶ方式でNES CPUのopcodeのように処理する
概念実証が示した可能性と限界
- ハイスコア名の入力領域では43個の記号しか使えず、スコアには10個の数字しか入れられない
- この制約により、NESで可能なopcodeの一部だけをハイスコアテーブルに「コーディング」できる
- 限られた入力だけでも短い概念実証コードは可能だった
- 例のデータには
))"-P)という名前と、A-Type 2位のスコア8,575が含まれる
- このルーチンはゲームスコアの上位2桁を0にする
- スコア処理時間を下げてクラッシュ原因を減らすが、プレイを続けるとスコアは再びクラッシュの「危険域」に達する
- 基本のNES版Tetrisにはバッテリーバックアップ保存装置がないため、電源を入れるたびに必要なハイスコアと複雑な名前を手作業で作る必要がある
- ハイスコアテーブルの空間も限られているため、Tetrisの実際のコード上に複雑なプログラムを直接入れるのは難しい
- HydrantDudeは、特定のハイスコア名と数字の組み合わせでブートストラッパーを作り、さらに別のブートストラッパーを作ってRAM全体の制御を得る方法があると書いている
クラッシュ回避を超えた再プログラミングの可能性
- RAM全体の制御が可能になれば、上位プレイヤーがNES版Tetrisのクラッシュバグをパッチするようにゲームを再コーディングすることもできる
- この方式はレベル255を超えようとするプレイヤーに特に役立つ可能性がある
- レベル255以降、ゲームは再びLevel 0に戻る
- 同じ原理をさらに拡張すれば、Super Mario Worldのスピードランナーの事例のように、TetrisをFlappy Birdに変えるような改変も可能になる
1件のコメント
Hacker Newsのコメント
こういうエクスプロイトを見ると、いつも Stross の Accelerando に出てくるハッキングの究極の最終段階を思い出す。「時空そのものの計算的超構造に対してタイミングチャネル攻撃を仕掛け、その下にある何かへ侵入しようとすること」
真空崩壊を引き起こして宇宙がブルースクリーンになる、とても良い方法に聞こえる
こういう人たちは本当に好き
役に立たない可能性が高いことを面白さだけでやってみる ハッカーマインド が自分にはなくて、恥ずかしく感じるくらいだ
ほかの私たちは、こういうエクスプロイトをやる時間がないほど食べていくので忙しい。しゃれのつもりはない
全文を読みたいわけではないが、「NES カートリッジって ROM から実行されるんじゃないの?」と気になったなら、その通り
ただ、このエクスプロイトは CPU を ハイスコア保存用 RAM にジャンプさせる。実にクールだ
任意コード実行 に至るまでの過程は、そのあと何をするかよりいつも面白い
ゲームを分解して、いつどこでそうした動作をするのか突き止め、どこを操作すれば命令を入力できるのか見つける執念には感服する
Pokemon Yellow: https://www.youtube.com/watch?v=Vjm8P8utT5g
Super Mario World: https://www.youtube.com/watch?v=hB6eY73sLV0
任意コード実行が実際のシェルコードとして発火する。文字どおりゲーム内で Koopa の甲羅を操作して実行する
誰かが Tetris で Doom を動かすまでどれくらいかかるだろう?
見事に無駄にした時間だ
本気で聞いている。以前は面白いことも時間の無駄だと思っていたが、長年の高ストレス生活の代償を払ううちに、歳を取るほど考えが変わってきた
Factorio でこれをやってみたい
ベルトで作った巨大なコンピューターを Factorio の中に作って、セグメンテーションフォールトを起こしてゲームの外へ脱出するみたいに
古いゲームで 任意コード実行 を見つけるのは本当に魅力的だ
数年前に Super Mario World でこういうのを見たとき、どうやって可能なのかしばらく夢中になった
良い意味で、褒め言葉として言っているのだが、ちょっと意地悪に聞こえるかもしれない。本当に賢い人たちが、まったく役に立たないことにものすごい時間と労力を注ぐのが好きだ
NES Tetris にコードを注入する差し迫った理由はあるか? おそらくない。だが重要なのはそこではなく、何が可能なのかを突き止め、古いコードと原始的なコンピューターにどこまで無理をさせられるかを探ることにある
古典的な意味では「有用」ではないかもしれないが、数独やクロスワード、そもそも NES Tetris を遊ぶこと自体も同じだ
上級プレイヤーが、ある地点以降のプレイを不可能にする クラッシュを回避して、より長くプレイ できるようにしてくれる
平均的なプレイヤーには実用性はないが、ハイスコアを競いたい人たちにとっては限界を解消し、新しい競争の可能性を開く
整数論ももともとは役に立たないと思われていたが、今では事実上すべての公開鍵暗号を支えている
他人が、私が好きでもないのにやっていることから得る有用性は、幸運な副産物か、金や評価のように間接的に自分の利益になるものだ
好きでやることは、最も重要な人、つまり自分自身にとって最も直接的な形の有用性になる
正直、Tetris がこんなに遅くまで破られなかったのが驚きだ
これは新しい any% 実行時代を開く気がする。目標はゲームのエンディングシーンやクレジットをできるだけ早く実行することだ
私のお気に入りの例は Ocarina of Time で、すでに何年も前から ACE エクスプロイトがあった
ゲームが完全に壊れていて、ゲームメモリを操作し、特定の入口ワープを編集すれば、数分で「クリア」できる
さらに驚くのは、人々が手作業で、ボタン数個とアナログスティックだけを使ってメモリを編集している点だ
3分でクレジットを表示した例: https://www.speedrun.com/oot/runs/z1l1627m
ワープトンネルの欠陥を見つけたところ 範囲外読み取り が発動し、その前にジョイスティック操作でバッファのすぐ外側に、望む動作を起こすバイトを書き込んでおくというものだった
Pokemon ゲームのひとつでは、メモリを正確に整えるために売買を大量にこなしたあと、アイテム数をオーバーフローさせてジャンプを発動させる必要があった
本当に素晴らしい話だ。いつか宇宙人が攻めてきたら、こういういたずらが私たちを救うだろう
この ACE はまず キルスクリーン に到達しないと成立しないように見える
Ocarina of Time の ACE が、エンディングクレジットが流れたあとにしか発動しないと想像してみればいい。すでに正常に完走したあとにしか起きないなら、記録短縮にはならない
こういう種類の作業は本当に好きだ
Super Mario World の中で不具合を利用して Flappy Bird をプログラムした話を思い出す。狂気の沙汰だ
https://www.youtube.com/watch?v=hB6eY73sLV0