Site cover image

🐾 flag3

ポケットモンスター ファイアレッド・リーフグリーン 殿堂入り(任意コード実行)

The English version is here:

📄Arrow icon of a page linkHall 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ばんどうろで入手することができます
  • メール
    • タマムシデパートで50円で購入することができます
    • 7個以上用意してください

手順1: 材料ポケモン用意

リーフグリーンのゲーム内交換で入手できるニドラン♂(ニドくん)の経験値を466、488、493のいずれかに調整したものを使うのが、材料ポケモンの最も簡単な入手方法です。以下に当てはまる場合はデテロニーさんの解説動画またはfinalさんの記事をご参照ください。

  • ファイアレッドを使用している
  • ニドくんをすでに持っていて経験値を466、488、493にするのが困難
  • ニドくんがすでに進化している

なお、ゲーム内交換で入手したニドくんは性格値が0x4C970B9E、トレーナーIDが63184であるため、経験値を別の値に調整することで材料ポケモンとして使用することができます。

手順2: メールバグ

以下の3匹のポケモンを手持ちに用意し、先頭2匹を以下の1と2のポケモンにしてください。

  1. 消費アイテムをもたせた任意のポケモン
  2. はたきおとすを覚えたポケモン
  3. メールをもたせたリサイクルを覚えたポケモン(メッセージは何でも可)

ダブルバトルを開始します。開始する前にセーブをすることをおすすめします。ダブルバトルでは以下の手順を実行してください。

  1. ポケモンに持たせた消費アイテムを発動させる。
  2. アイテムを消費したら、そのポケモンをメールをもたせたリサイクルを覚えたポケモンに入れ替える。
  3. メールをもたせたリサイクルを覚えたポケモンにはたきおとすを使用し、メールをはたきおとす。
  4. リサイクルを使用し、消費アイテムを拾う。
  5. 戦闘を終了させる。

手持ちを確認して、リサイクルを覚えたポケモンがメールをもっていなければメールバグに成功です。リサイクルを覚えたポケモンにメールをもたせなおしてください。

手順3: バグポケモン入手

手順1で入手した材料ポケモンをボックス3の1番目に入れ、手持ちを6匹にしてください。

Image in a image block

6匹全員にメールをもたせます(メッセージは何でも可)。6匹目にメールを渡そうとすると、???が入力されたメール画面が表示されます。

リーフグリーンを使用していて、材料ポケモンがニドくんである場合は、メールの3番目と5番目を以下のものにしてください。表中の_____は?????となっている言葉を消してください。

経験値 3番目 5番目
466 ポケモンゲット _____
488 レッド _____
493 レベル _____
Image in a image block
Image in a image block
Image in a image block

ファイアレッドを使用していたり別の材料ポケモンを使用している場合はデテロニーさんが作成した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を後述の専用名にしてください。

⚠️
「へ」は平仮名の「へ」、「l」は小文字の「l」(エル)を入力してください。

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で紹介した文献に加えて、以下を参考にしています。