The English version is here:
📄Hall of Fame in Pokémon FireRed/LeafGreen (JP) (Arbitrary Code Execution)
本記事ではポケットモンスター ファイアレッド・リーフグリーンで任意コード実行を用いて殿堂入りする方法について紹介します。バグあり(セーブ中リセットなし)でなるべく早く殿堂入りを目指すRTAのAny% No Save Corruptionのカテゴリーで使うことができます。
殿堂入り手順
環境
ポケットモンスター ファイアレッド・リーフグリーンの日本語版のみに対応しています。日本語版以外のバージョンには対応していません。GBA版とSwitch版の両方に対応しています。
バージョンの違い
GBA版のポケットモンスター ファイアレッド・リーフグリーンはそれぞれにv1.0とv1.1が存在します。カートリッジの基板に刻まれている数字によってどのバージョンであるかを判定することができます。
- 末尾の数字が20であればv1.0。
- 末尾の数字が30であればv1.1。
準備
- はたきおとすを覚えたポケモン
- ゲーム内交換で入手できるカモネギ(じんすけ)はレベル21ではたきおとすを覚えます
- リサイクルを覚えたポケモン
- ゲーム内交換で入手できるバリヤード(バリヤン)はレベル33でリサイクルを覚えます
- 消費アイテム(例:きのみ)
- HP50%以下で発動するオレンのみが最適です
- オレンのみは25ばんどうろで入手することができます
- HP50%以下で発動するオレンのみが最適です
- メール
- タマムシデパートで50円で購入することができます
- 7個以上用意してください
手順1: 材料ポケモン用意
リーフグリーンのゲーム内交換で入手できるニドラン♂(ニドくん)の経験値を466、488、493のいずれかに調整したものを使うのが、材料ポケモンの最も簡単な入手方法です。以下に当てはまる場合はデテロニーさんの解説動画またはfinalさんの記事をご参照ください。
- ファイアレッドを使用している
- ニドくんをすでに持っていて経験値を466、488、493にするのが困難
- ニドくんがすでに進化している
なお、ゲーム内交換で入手したニドくんは性格値が0x4C970B9E、トレーナーIDが63184であるため、経験値を別の値に調整することで材料ポケモンとして使用することができます。
手順2: メールバグ
以下の3匹のポケモンを手持ちに用意し、先頭2匹を以下の1と2のポケモンにしてください。
- 消費アイテムをもたせた任意のポケモン
- はたきおとすを覚えたポケモン
- メールをもたせたリサイクルを覚えたポケモン(メッセージは何でも可)
ダブルバトルを開始します。開始する前にセーブをすることをおすすめします。ダブルバトルでは以下の手順を実行してください。
- ポケモンに持たせた消費アイテムを発動させる。
- アイテムを消費したら、そのポケモンをメールをもたせたリサイクルを覚えたポケモンに入れ替える。
- メールをもたせたリサイクルを覚えたポケモンにはたきおとすを使用し、メールをはたきおとす。
- リサイクルを使用し、消費アイテムを拾う。
- 戦闘を終了させる。
手持ちを確認して、リサイクルを覚えたポケモンがメールをもっていなければメールバグに成功です。リサイクルを覚えたポケモンにメールをもたせなおしてください。
手順3: バグポケモン入手
手順1で入手した材料ポケモンをボックス3の1番目に入れ、手持ちを6匹にしてください。
6匹全員にメールをもたせます(メッセージは何でも可)。6匹目にメールを渡そうとすると、???が入力されたメール画面が表示されます。
リーフグリーンを使用していて、材料ポケモンがニドくんである場合は、メールの3番目と5番目を以下のものにしてください。表中の_____は?????となっている言葉を消してください。
| 経験値 | 3番目 | 5番目 |
|---|---|---|
| 466 | ポケモンゲット | _____ |
| 488 | レッド | _____ |
| 493 | レベル | _____ |
ファイアレッドを使用していたり別の材料ポケモンを使用している場合はデテロニーさんが作成したFRLG任意コード実行用バグポケモン作製用計算機、もしくはfinalさんのSpecies Word FinderとChecksum Adjustment Calculatorをお使いください。
手順4: 殿堂入り
ボックス12〜14にはポケモンを預けないようにし、手持ちのポケモンを4匹以下にしてください。手持ちを5匹以上にすると殿堂入りの途中でフリーズします。
使っているソフトのバージョンとバグポケモンの種族IDに応じてボックスの名前を付けてください。下の三角形をクリックすることで表示される表でバグポケモンの種族IDに対応する型を確認し、その型のボックス名を設定してください。なお経験値466、488、493のニドくんをバグポケモンにした場合はARM-2型を使ってください。
ファイアレッド種族ID
| 種族ID | 型 |
|---|---|
| 0x03F8 | ARM-2型 |
| 0x060C | ARM-2型 |
| 0x15BC | ARM-0型 |
| 0x1626 | ARM-0型 |
| 0x4312 | Thumb型 |
| 0x4317 | Thumb型 |
| 0x4D12 | ARM-0型 |
| 0x7912 | Thumb型 |
| 0x89FA | Thumb型 |
| 0xA253 | Thumb型 |
| 0xB2A9 | ARM-0型 |
| 0xC7FE | Thumb型 |
| 0xC950 | ARM-0型 |
| 0xCAA2 | ARM-2型 |
| 0xCD48 | Thumb型 |
| 0xCF8B | Thumb型 |
| 0xD624 | Thumb型 |
| 0xDD37 | Thumb型 |
| 0xE472 | ARM-0型 |
| 0xE69D | ARM-0型 |
| 0xFF3B | ARM-2型 |
| 0xFF41 | ARM-2型 |
| 0xFF61 | ARM-2型 |
| 0xFF6B | Thumb型 |
| 0xFF78 | ARM-0型 |
| 0xFF79 | Thumb型 |
| 0xFF7B | Thumb型 |
| 0xFF7E | Thumb型 |
| 0xFF81 | Thumb型 |
| 0xFF83 | Thumb型 |
| 0xFF86 | Thumb型 |
| 0xFF8B | Thumb型 |
| 0xFF8E | Thumb型 |
| 0xFF96 | Thumb型 |
| 0xFF99 | Thumb型 |
| 0xFF9B | Thumb型 |
| 0xFF9E | Thumb型 |
| 0xFFA1 | Thumb型 |
| 0xFFA3 | Thumb型 |
| 0xFFAB | Thumb型 |
| 0xFFAE | Thumb型 |
| 0xFFB1 | Thumb型 |
| 0xFFB3 | Thumb型 |
| 0xFFB6 | Thumb型 |
| 0xFFB9 | Thumb型 |
| 0xFFBB | Thumb型 |
| 0xFFC3 | Thumb型 |
| 0xFFC6 | Thumb型 |
| 0xFFC9 | Thumb型 |
| 0xFFCE | Thumb型 |
| 0xFFD3 | Thumb型 |
| 0xFFF8 | ARM-0型 |
| 0xFFF9 | Thumb型 |
リーフグリーン種族ID
| 種族ID | 型 |
|---|---|
| 0x03F8 | ARM-2型 |
| 0x060C | ARM-2型 |
| 0x15BC | ARM-0型 |
| 0x1626 | ARM-0型 |
| 0x3D88 | ARM-2型 |
| 0x4D1B | Thumb型 |
| 0x9151 | Thumb型 |
| 0xBCB2 | Thumb型 |
| 0xC290 | Thumb型 |
| 0xC6AA | ARM-2型 |
| 0xCFAD | ARM-2型 |
| 0xD45D | ARM-2型 |
| 0xD628 | Thumb型 |
| 0xEA20 | ARM-0型 |
| 0xEB51 | Thumb型 |
| 0xFBED | ARM-0型 |
| 0xFF11 | ARM-2型 |
| 0xFF37 | ARM-2型 |
| 0xFF41 | ARM-2型 |
| 0xFF57 | ARM-2型 |
| 0xFF5C | ARM-2型 |
| 0xFF61 | ARM-2型 |
| 0xFF6C | Thumb型 |
| 0xFF79 | Thumb型 |
| 0xFF7C | Thumb型 |
| 0xFF7F | Thumb型 |
| 0xFF81 | Thumb型 |
| 0xFF84 | Thumb型 |
| 0xFF87 | Thumb型 |
| 0xFF8C | Thumb型 |
| 0xFF8F | Thumb型 |
| 0xFF97 | Thumb型 |
| 0xFF99 | Thumb型 |
| 0xFF9C | Thumb型 |
| 0xFF9F | Thumb型 |
| 0xFFA1 | Thumb型 |
| 0xFFA4 | Thumb型 |
| 0xFFAC | Thumb型 |
| 0xFFAF | Thumb型 |
| 0xFFB1 | Thumb型 |
| 0xFFB4 | Thumb型 |
| 0xFFB7 | Thumb型 |
| 0xFFB9 | Thumb型 |
| 0xFFBC | Thumb型 |
| 0xFFC4 | Thumb型 |
| 0xFFC7 | Thumb型 |
| 0xFFC9 | Thumb型 |
| 0xFFCE | ARM-0型 |
| 0xFFD1 | Thumb型 |
| 0xFFF9 | Thumb型 |
型に応じて以下のいずれかを使用してください。
ARM-0型
ボックス1: [ア]
ボックス2: [ まqた]
ボックス3: [ぁm〇〇しく] ARM-2型
ボックス1: [ア]
ボックス2: [ まqた]
ボックス3: [ぁmしく〇〇] Thumb型
ボックス1: [ ぶ び〇〇しく] 〇〇 は使用中のバージョンに応じて下表の文字に置き換えてください。
| バージョン | 〇〇 |
|---|---|
| GBA版ファイアレッドv1.0 | 『」 |
| GBA版ファイアレッドv1.1 | す♂ |
| Switch版ファイアレッド | 『y |
| GBA版リーフグリーンv1.0 | ュ」 |
| GBA版リーフグリーンv1.1 | m」 |
| Switch版リーフグリーン | ュy |
なおSwitch版のARM-0型、ARM-2型についてはボックス1の名前がデフォルトの ボックス1 でも良いです。
ボックス12~14にポケモンが預けられていない状態で「ボックスをせいりする」で任意のポケモンをつかみ、バグポケモンの上に移動し入れ換えることで殿堂入りとなります。
なお、殿堂入り後はバグポケモンが消滅することに気をつけてくだ替い。
おまけ: THE ENDを直接表示する
手順3で用意したバグポケモンを使い、THE ENDの画面を直接表示することもできます。手順4の殿堂入りを行うとバグポケモンが消滅するため、殿堂入り前の状態から行ってください。
ボックス12〜14にはポケモンを預けないようにしてください。
使っているソフトのバージョンとバグポケモンの種族IDに応じてボックスの名前を付けてください。型は手順4の種族IDの表で確認してください。なお経験値466、488、493のニドくんをバグポケモンにした場合はARM-2型を使ってください。
型に応じて以下のいずれかを使用してください。全6版で、ARM-0型・ARM-2型はボックス1〜4、Thumb型はボックス1〜3を使用します。GBA版リーフグリーンv1.1のARM-0型・ARM-2型だけは、ボックス3・4を後述の専用名にしてください。
ARM-0型
ボックス1: [く ぽnびへャn]
ボックス2: [あゥqあ ゼnた]
ボックス3: [ぁmあぶぃチ び]
ボックス4: [ア〇〇そく] ARM-2型
ボックス1: [こ ぽnびへャn]
ボックス2: [あゥqあ ぽnた]
ボックス3: [ぁmあぶぃチ び]
ボックス4: [ア〇〇そく] Thumb型
ボックス1: [ルば ぼ〇〇そく]
ボックス2: [アけぅゾネ l]
ボックス3: [てげぇチあタたび] 〇〇 は使用中のバージョンと型に応じて下表の文字に置き換えてください。
| バージョン | ARM-0型・ARM-2型の 〇〇 | Thumb型の 〇〇 |
|---|---|---|
| GBA版ファイアレッドv1.0 | eカ | xカ |
| GBA版ファイアレッドv1.1 | へキ | ぃキ |
| Switch版ファイアレッド | ルゼ | ザゼ |
| GBA版リーフグリーンv1.0 | 『カ | Jカ |
| GBA版リーフグリーンv1.1 | 下の専用設定を使用 | くキ |
| Switch版リーフグリーン | アゼ | トゼ |
GBA版リーフグリーンv1.1でARM-0型・ARM-2型を使う場合は、ボックス1・2はそのままにして、ボックス3・4を次の名前にしてください。Thumb型ではこの変更は不要です。
ボックス3: [ぁmあぶでぃぃチ]
ボックス4: [め『カそく び] ボックス12〜14にポケモンが預けられていない状態で「ボックスをせいりする」で任意の通常ポケモンをつかみ、バグポケモンの上に移動し入れ替えることでTHE ENDが表示されます。
なお、この方法ではTHE ENDの画面を表示するだけで、殿堂入りの記録やクリア状態は更新されません。スタッフロールは流れず、表示後はリセットが必要です。
コード
殿堂入りを実行するプログラム
ここではGBA版ファイアレッドv1.0を例に説明します。ボックス名のプログラムは、ゲーム本体の殿堂入り開始関数 0x080CB4B0 へ処理を渡します。この関数はThumb命令で書かれているため、分岐に使う値は下位1ビットを1にした 0x080CB4B1 です。
ARM-0
以下は、ボックス名の中で関数への分岐を行う部分です。各コード例の先頭のLDRを格納する位置を 0000 とし、左端にそこからの16進オフセットを示します。
0000: e51f0000 ldr r0, [pc, #-0] ; オフセット0008の値をr0へ読む
0004: e12fff10 bx r0 ; Thumbで080CB4B0へ分岐
0008: 080cb4b1 .word 0x080cb4b1 ; 分岐先を表すデータ ARM命令でPCを読むと、実行中の命令の8バイト先を指します。この例ではオフセット 0x0008 の4バイトを読み、r0に 0x080CB4B1 を入れます。続くBXは、その下位ビットをThumbの指定として使い、実際の命令がある 0x080CB4B0 から実行を続けます。
バイナリ
00 00 1F E5 10 FF 2F E1 B1 B4 0C 08 ARM-2
ARM-0型と同じLDR・BXを使いますが、末尾の定数を2バイトずつ入れ替えます。次はメモリ上の配置です。
0000: e51f0000 ldr r0, [pc, #-0] ; ARM-2ではオフセット000Aを指定して読む
0004: e12fff10 bx r0 ; Thumbで080CB4B0へ分岐
0008: b4b1080c .word 0xb4b1080c ; 2バイトのずれに合わせた定数 ARM-2型では、実行時のPCに2バイトのずれが残るため、LDRが指定する読出し先のオフセットも 0x0008 から 0x000A へずれます。この32ビット読出しでは、4バイト境界の値を16ビット回転した結果が得られます。そこで定数をあらかじめ 0xB4B1080C にしておくと、r0にはARM-0型と同じ 0x080CB4B1 が入ります。
手順4でボックス3の 〇〇しく を しく〇〇 に入れ替えるのは、この定数の配置を合わせるためです。
バイナリ
00 00 1F E5 10 FF 2F E1 0C 08 B1 B4 Thumb
0000: 4800 ldr r0, [pc, #0] ; オフセット0004の値をr0へ読む
0002: 4700 bx r0 ; Thumbで080CB4B0へ分岐
0004: 080cb4b1 .word 0x080cb4b1 ; 分岐先を表すデータ ThumbのこのLDRは、命令の4バイト先を4バイト境界に揃えた位置を基準にします。この例ではオフセット 0x0004 から同じ関数ポインタを読みます。すでにThumbで実行していますが、BXの分岐先にも下位ビット1が必要です。
バイナリ
00 48 00 47 B1 B4 0C 08 いずれの型も、ここで実行するのはLDRとBXの2命令です。末尾の4バイトは分岐先を表すデータであり、この場所で命令として実行するものではありません。ARM-0型とThumb型では B1 B4 0C 08、ARM-2型では2バイトずつ入れ替えた 0C 08 B1 B4 を置きます。
また、BX自体は戻り先のLRを書き換えません。殿堂入り開始関数は処理後に0を返して元の呼び出し元へ戻り、以後の殿堂入り処理は登録済みのcallback2を通して進みます。
THE ENDを表示するプログラム
こちらもGBA版ファイアレッドv1.0を例に説明します。ゲーム本体のTHE END描画関数 0x080F56D8 をThumb命令で呼び出します。関数ポインタはThumbを指定するため、末尾に1を加えた 0x080F56D9 です。
Sをボックス1の名前の先頭とします。以下のコードの左端はSからの16進オフセットです。実際のRAMアドレスはボックス管理領域の位置によって変わります。
ARM-0型
0000: e24f0008 sub r0, pc, #8 ; r0 = S(ARM-0のPCはS+8)
0004: e2841d47 add r1, r4, #0x11c0 ; r1 = 0x0203A8BC
0008: e58101ff str r0, [r1, #511] ; sCreditsMgr = S
000c: e28f0001 add r0, pc, #1 ; r0 = S+0x15
0010: e12fff10 bx r0 ; S+0x14からThumb命令
0014: 4801 ldr r0, [pc, #4] ; r0 = 0x080F56D9
0016: 6130 str r0, [r6, #16] ; gMain.callback2 = r0
0018: 4700 bx r0 ; 描画関数へ末尾分岐
001a: 51ff .hword 0x51ff ; 実行しない終端FFと配置用「ア」
001c: 080f56d9 .word 0x080f56d9 ; 描画関数のポインタ
0020: ffffffff .word 0xffffffff ; 名前の残り 発火時の r4=0x020396FC と r6=gMain-12 を再利用しています。0x0203A8BC+511=0x0203AABB への32ビット書き込みは、ARM7TDMIが下位2ビットを無視するため 0x0203AAB8 に入ります。これで管理ポインタ用の定数を省き、終端のFFもSTR命令に使えます。
S+1は先頭命令の00、S+9はSTR命令の01です。描画関数はこの2バイトを進行段階と画像選択として読みます。実行後にはS+1が03に変わるため、RAM上のボックス名も変化します。
バイナリ
各行が1ボックスの9バイトです。FFは名前の終端で、短い名前の残りもFFになります。
08 00 4F E2 47 1D 84 E2 FF
01 81 E5 01 00 8F E2 10 FF
2F E1 01 48 30 61 00 47 FF
51 D9 56 0F 08 FF FF FF FF ARM-2型
ARM-0型から次の2命令を変更します。ARM-2型では実行時のPCに2バイトのずれが残るため、Sを求める命令と、Thumbへ切り替える先を求める命令を補正します。ここでは左端にメモリ上のオフセットを示しています。
0000: e24f000a sub r0, pc, #10 ; PC=S+10からSを求める
000c: e24f0001 sub r0, pc, #1 ; PC=S+0x16からS+0x15を求める どちらの型も、BXへ渡す値は S+0x15 です。下位ビット1でThumbを指定し、実際には S+0x14 からThumb命令を実行します。それ以降のコードと、描画関数の定数はARM-0型と同じです。
バイナリ
0A 00 4F E2 47 1D 84 E2 FF
01 81 E5 01 00 4F E2 10 FF
2F E1 01 48 30 61 00 47 FF
51 D9 56 0F 08 FF FF FF FF Thumb型
0000: 4679 mov r1, pc ; r1 = S+4
0002: 4a00 ldr r2, [pc, #0] ; r2 = 0x080F56EC(関数先頭+20)
0004: 080f56ec .word 0x080f56ec ; 定数を命令としても実行
0008: 51ff str r7, [r7, r7] ; r7=0。BIOS領域への書込みは反映されない
000a: 3109 adds r1, #9 ; r1 = S+0x0D
000c: 6890 ldr r0, [r2, #8] ; r0 = sCreditsMgrの格納先
000e: e000 b 0x12 ; この命令の00を進行段階に兼用
0010: ffff .hword 0xffff ; 実行しない終端FF FF
0012: 3a13 subs r2, #19 ; r2 = 0x080F56D9
0014: 6132 str r2, [r6, #16] ; gMain.callback2 = r2
0016: 6001 str r1, [r0] ; sCreditsMgr = S+0x0D
0018: 4710 bx r2 ; 描画関数へ末尾分岐
001a: ff .byte 0xff ; 名前の終端 管理データの先頭を S+0x0D にします。進行段階はそこから1バイト後の S+0x0E にある分岐命令の00、画像選択は9バイト後の S+0x16 にあるSTR命令の01です。描画関数が進行段階を書き換える時点では、この分岐命令の実行は終わっています。
関数先頭の28バイト後に管理ポインタの格納先が定数として置かれているため、関数先頭+20 を読み、そこから8バイト後を参照します。その後19を引くと 関数先頭+1 になり、Thumbの関数ポインタとして使えます。この配置は6版共通で、0x04の定数だけが版によって変わります。
0x04の定数は、この例では次の2命令としても実行されます。
0004: 56ec ldrsb r4, [r5, r3] ; 読み取った値は描画の設定には使わない
0006: 080f lsrs r7, r1, #32 ; r7 = 0 この2命令はr1・r2・r6を保ちます。定数を飛び越す分岐を省き、進行段階と画像選択も必要な命令と兼用することで、3ボックスに収めています。
バイナリ
79 46 00 4A EC 56 0F 08 FF
51 09 31 90 68 00 E0 FF FF
13 3A 32 61 01 60 10 47 FF LG v1.1のARM型も4ボックスに収める方法
LG v1.1のThumb関数ポインタは 0x080F56F5 ですが、F5はボックス名で入力できません。そこで 0x080F56B1 を置き、68を加えます。各型の先頭20バイトは上記のままにし、後半を次のようにします。
0014: 4801 ldr r0, [pc, #4] ; r0 = 0x080F56B1
0016: 3044 adds r0, #68 ; r0 = 0x080F56F5
0018: 6130 str r0, [r6, #16] ; gMain.callback2 = r0
001a: 22ff movs r2, #255 ; 終端FFを含む命令
001c: 080f56b1 .word 0x080f56b1 ; 定数を、この位置では命令としても実行
0020: 4700 bx r0
0022: ffff .hword 0xffff 0x1Cの4バイトは、Thumb命令として読むと次の2命令になります。
001c: 56b1 ldrsb r1, [r6, r2] ; IWRAM内を1バイト読む
001e: 080f lsrs r7, r1, #32 ; r7 = 0 謝辞
Switch版において殿堂入りの関数アドレスを特定してくれたぼんじりさんに感謝します。
参考文献
手順1で紹介した文献に加えて、以下を参考にしています。



