なるほどえたきちのブログじゃねーの

チラ裏雑記帳

ポケモン過去作の解析とか乱数調整とかそこら辺。不定期更新。

【Em】ふしぎなカードの偽造その1

ふしぎなカードのデータ書き込みについて紹介します。
例によって16進数やバイナリエディタに対するそれなりの理解があることを前提としています。

書き込むデータの例として公式のふるびたかいずを使用します。
データの位置特定や書き込みにはゲーム内バイナリエディタを使用するため、バイナリエディタ未導入の方は以下の記事を参考に導入してください。
http://bzl.hatenablog.com/entry/2019/09/29/182642bzl.hatenablog.com
データサイズが大きい都合上、打ち込むデータの指定にはPC用バイナリエディタのスクショを使用しています。

1)カードのデータ書き込み



0x03005AECからの4byteに格納されたポインタに0x3310byteを加算したアドレスがふしぎなカード格納メモリです。
このアドレスを始点に以下のデータを書き込んでください。
f:id:BZL:20191006103229p:plain

また、上記のデータの代わりに以下のデータを書き込むことで、一次配布可能なカードを生成することができます。
生成ROMから他のROMに配布されたカードは正規のカードと全く同じバイナリデータになります。
f:id:BZL:20191006110333p:plain

2)スクリプトのデータ書き込み



0x03005AECからの4byteに格納されたポインタに0x3728byteを加算したアドレスが配達員スクリプトの格納メモリです。
このアドレスを始点に以下のデータを書き込んでください。
f:id:BZL:20191006104449p:plain

書き込みが終了したら一旦レポートを書いて保存します。
ふしぎなおくりものからカードの情報を見ることができれば書き込みは成功です。
もし弾かれた場合は再度アドレスを特定してからミスのある箇所を修正してください。
打ち込みミスのある状態で配達員に話しかけると打ち込んだデータがクリアされてしまうので、確認は必ずふしぎなおくりものメニューから行うようにしてください。


以上の手順で外部ツールを使用せずに正規と全く同じデータのふるびたかいずを生成することができます。
Twitterで紹介したオリジナルのふしぎなカード作成については別記事で纏めます。
↓続き
bzl.hatenablog.com

【Em】バイナリエディタの導入

数ヶ月前に書いたこの記事の情報が色々と古くなってきたので新しく纏め直しました。
bzl.hatenablog.com

この記事では0x085F入手後~バイナリエディタ起動までの流れについて解説します。

この記事で紹介しているコードは0x2B5Cによる呼び出しを推奨していません。
使用しているRAM改竄方式にもよりますが、技アニメスクリプト用のコードを挟ませていないので状況次第でクラッシュに繋がります。
0x085Fをまだ持っていない場合はこの記事の手順を踏んで生成させてください。
bzl.hatenablog.com

以下実行手順の説明です。
この記事で使用されている『へ』『べ』『ぺ』は全て平仮名になります。

1)RAMコピー用のダメタマゴ生成


ボックスRAMへ効率良くデータをコピーする為に、メモリコピー処理を埋め込んだダメタマゴをボックス1/15に生成します。
以下の通りにボックス名を編集した後、0x085Fのステータスを開いて処理を実行してください。

ボックス ボックス名
ボックス1 『ォめンばつい『は』
ボックス2 『アこぅほょ l』
ボックス3 『せもっめコづグね』
ボックス4 『アCTなGけl』
ボックス5 『ロば むいぽゆリ』
ボックス6 『アアアzをけd』
ボックス7 『CTぃGCTるG』
ボックス8 『アへTなGねl』
ボックス9 『9をうW l99』
ボックス10 『アアアキっうぅ』
ボックス11 『アアオエあぅ』
ボックス12 『アっるあV』
ボックス13 『あゃポば l99』
ボックス14 『アアアミBィC』

正しく処理が実行できていれば、以下のようにダメタマゴが配置されます。
このダメタマゴは動かさないでください。
f:id:BZL:20190929152204p:plain


2)バイナリエディタ実体コピー


バイナリエディタのプログラムデータをボックス1/2~1/13にコピーします。

まず先程生成したダメタマゴを参照するための処理を入力します。
以下の通りにボックス名を編集してください。

ボックス ボックス名
ボックス1 『ォらぜいっむきぼ』
ボックス2 『アぼづワば l』
ボックス3 『oひせみぶづボね』
ボックス4 『アひねねゃポば』

この処理で先程のダメタマゴを呼び出すことでボックスRAM上に0x50byteのデータをコピーできます。
データのコピー先はボックス5の最初の4文字で決定され、『    』(0x00000000)の場合はボックス1/2、『ふ   』(0x0000001C)の場合はボックス1/30といったようにポケモンの位置に対応したコピー先を指定できます。
ボックスのポケモン1匹分のデータサイズは0x50byteで、バイナリエディタは0x3C0byte(ポケモン12匹分)のデータで構成されているので合計12回のコード実行でコピーが完了します。
以上の通り、ボックス5-ボックス13のボックス名は任意コードの呼び出し毎に変更してください。

1回目

ボックス ボックス名
ボックス5 『    ィ♂ミ」』
ボックス6 『fぶYぴァばおが』
ボックス7 『Dばルl9おふV』
ボックス8 『ぴァばおがDばム』
ボックス9 『l みUぴ9ァば』
ボックス10 『おがDばノl9く』
ボックス11 『むUぶPぴァば9』
ボックス12 『けがDばセlOべ』
ボックス13 『9すメSぶ』


2回目

ボックス ボックス名
ボックス5 『あ   くタ リ』
ボックス6 『くム みべムミB』
ボックス7 『ィCPぶ9たむけ』
ボックス8 『いぞね めMべあ』
ボックス9 『ィあぅあも9あも』
ボックス10 『あもあもあも9あ』
ボックス11 『もあもあもいぃ9』
ボックス12 『あィあぇせれxW』
ボックス13 『9あぅあィ』


3回目

ボックス ボックス名
ボックス5 『い   あぅAぶ』
ボックス6 『ぞもためついィね』
ボックス7 『あィGイ9いぅふ』
ボックス8 『ぃあィGイあぅ♀』
ボックス9 『ぶためつい9ィね』
ボックス10 『あィあぅ め9あ』
ボックス11 『もあもあもあも9』
ボックス12 『あもあもあもあも』
ボックス13 『9あもあも』


4回目

ボックス ボックス名
ボックス5 『う   いぃあィ』
ボックス6 『あぇせれxWあぅ』
ボックス7 『あィミび96ばF』
ボックス8 『ばィ♂ミ」ャ…ビ』
ボックス9 『ぷりレちむ9ッぴ』
ボックス10 『ァばけがDば9ヲ』
ボックス11 『l やんふりリ9』
ボックス12 『あけけるいeたぅ』
ボックス13 『90ぅぅヤ』


5回目

ボックス ボックス名
ボックス5 『え   そむあぞ』
ボックス6 『ける eたぅ0ぅ』
ボックス7 『ムヤあゅ9いょあ』
ボックス8 『ゃおわおVえわp』
ボックス9 『Wあょns9ィぷ』
ボックス10 『んふぇふたゲ9W』
ボックス11 『ゲVェちェっゲ9』
ボックス12 『ダゲゾェアェ み』
ボックス13 『9ぃツミツ』


6回目

ボックス ボックス名
ボックス5 『お   …ツミル』
ボックス6 『えりきVぞ たぃ』
ボックス7 『ぅコたぃ9ぅイき』
ボックス8 『lミンるむミエ…』
ボックス9 『ンれむミエ9ァみ』
ボックス10 『ィぃぃラ…ュ9た』
ボックス11 『ょいバ みあゾ9』
ボックス12 『ノぶ ゾりレ む』
ボックス13 『9 め も』


7回目

ボックス ボックス名
ボックス5 『か   ミぴィゃ』
ボックス6 『ァばおがDばはl』
ボックス7 『たょいバ9 みあ』
ボックス8 『ゾタぶ ゾりレ 』
ボックス9 『む め も9ニぴ』
ボックス10 『ィゃァばけが9D』
ボックス11 『ばえlえ…ミB9』
ボックス12 『ィC6ばィ♂ミ」』
ボックス13 『9きふリば』


8回目

ボックス ボックス名
ボックス5 『き   おぃョば』
ボックス6 『てsぷぷサぺょギ』
ボックス7 『たみぃぞ9おVネ』
ボックス8 『ルえりヤVあぃネ』
ボックス9 『ムヒlみみ9ぃぞ』
ボックス10 『けVネル り9ヌ』
ボックス11 『Vあぎネムセl9』
ボックス12 『ぞみぃぞつVネル』
ボックス13 『9えりいV』


9回目

ボックス ボックス名
ボックス5 『く   Fづうむ』
ボックス6 『くぞるシあぅるエ』
ボックス7 『えりぴV9りネ 』
ボックス8 『リりムばlィみぃ』
ボックス9 『ぞそVネル9えり』
ボックス10 『えVFづうむ9く』
ボックス11 『ぞるシあぐ ぐ9』
ボックス12 『osネルえりとW』
ボックス13 『9たみ あ』


10回目

ボックス ボックス名
ボックス5 『け   ぃぞうV』
ボックス6 『るルたぅるムよl』
ボックス7 『みみ あ9ぃぞえ』
ボックス8 『Vえみるルたぐる』
ボックス9 『ムひlあみ9ぃぞ』
ボックス10 『おVりネるル9あ』
ボックス11 『ミたlいみぃぞ9』
ボックス12 『ちVぎふよぴァば』
ボックス13 『9けがDば』


11回目

ボックス ボックス名
ボックス5 『こ   ァsやぶ』
ボックス6 『 むあミおlァば』
ボックス7 『けがDば9trミ』
ボックス8 『BィCFば けけ』
ボックス9 『せいそゼ 9 い』
ボックス10 『う  えお 9っ』
ボックス11 『ぇ くシょ く9』
ボックス12 『ぶめ くリギこく』
ボックス13 『9 bうい』


12回目

ボックス ボックス名
ボックス5 『さ   シYうい』
ボックス6 『どXういネYうい』
ボックス7 『フYうい9   』
ボックス8 『いたv かとn 』
ボックス9 『 っv か9Vv』
ボックス10 『 かねご く9ワ』
ボックス11 『ボのくゾも う9』
ボックス12 『トグこくわそ う』
ボックス13 『9アアアア』

以上のコード実行を終えるとボックス1が以下のような状態になります。
コピー先のミスはタマゴの位置で判別可能ですが、細かいデータ内容のミスまでは判別できません。
(チェック用のコードを書くことも可能ですが、できればミスのないよう慎重に打ち込んでもらうのが望ましいです)
f:id:BZL:20190929155156p:plain



3)バイナリエディタの起動


バイナリエディタを起動する為のコードです。

以下の通りにボックス名を編集した後、0x085Fのステータスを開いて処理を実行してください。

ボックス ボックス名
ボックス1 『ォめリばついィは』
ボックス2 『アこぃおべ l』
ボックス3 『しふみぅリめヂ 』
ボックス4 『アさkいべおl』
ボックス5 『 Vういりぃ も』
ボックス6 『アみふいふ l』
ボックス7 『むぇえぱせFいぶ』
ボックス8 『ア むあタおl』
ボックス9 『ぎせ うらい  』
ボックス10 『アGタあむ l』
ボックス11 『あメあぅだメえチ』
ボックス12 『アミBィC』

バイナリエディタの打ち込み、起動コードの打ち込みにミスが無ければバイナリエディタが実行されます。
操作に関しての簡潔な纏めは以下の通り

  • 十字キーでフォーカスの移動、0x01単位での値操作
  • Aボタンで値の書き込み
  • LRボタンで0x10単位での値操作
  • Bボタンでバイナリエディタ処理終了、主人公のロック解除

f:id:BZL:20190929150026p:plain

バイナリエディタ導入後、セーブハックを行うと更に自由度が高まります。
bzl.hatenablog.com
操作ミスでセーブデータが破損する可能性があるので実践する方はセーブデータのコピーを推奨します。
(一見するとセーブデータコピーの方が危険そうですが割と安全です)
bzl.hatenablog.com


おまけ


スクリプト実行

0x03000E40 <- 0x01
0x03000E41 <- 0x02
0x03000E44 <- 0x00000000(word)
0x03000E48 <- イベントスクリプトのアドレス(word)
0x03000E38 <- 0x00 ※このアドレスの上書きは必ず最後に行う

任意ポケモンエンカウントスクリプト

個体値等はランダムです
乱数調整したいならMethod1で計算するといいかもしれないです

B6 PP PP LV IT IT B7 02

PP PP = ポケモンコード
LV = レベル(100 = 0x64)
IT IT = アイテムコード
任意マップワープスクリプト
39 MP MP 00 00 00 00 00 02

MP MP = マップID
1A 38 = さいはてのことう
1A 09 = みなみのことう
1A 3A = たんじょうのしま
1A 42 = へそのいわ
18 67 = うみのどうくつ
18 69 = りくのどうくつ
フラグ書き換えスクリプト
フラグをONにする
29 FL FL 02

フラグをOFFにする
2A FL FL 02

FL FL = フラグID

91 00 = ルギア捕獲済み
92 00 = ホウオウ捕獲済み
AD 01 = デオキシス捕獲済み
BB 01 = レジロック捕獲済み
BC 01 = レジアイス捕獲済み
BD 01 = レジスチル捕獲済み
BE 01 = カイオーガ捕獲済み
BF 01 = グラードン捕獲済み
C0 01 = レックウザ捕獲済み
C9 01 = 孤島ラティ捕獲済み
CA 01 = ミュウ捕獲済み
C0 01 = レックウザ捕獲済み
50 0D = むげんのチケット配達員出現

【Em】バグポケモン0x085Fを使用した任意コード実行

技アニメ実行とは別の任意コード実行方法が見つかったので紹介します。

このコード実行方法の特徴は以下の通りです。

  • 不正ポケモンコードを利用する
  • プログラムの直参照なのでボックスを適切な状態にしていれば100%成功する
  • 技アニメと比べて実行の手間が少ない
  • スクリプトの記述が必要ない分多くのメモリを処理の記述に使用できる


↓実践動画

以下実行手順です。

1)バグポケモン0x085Fの生成



生成に使用する個体はNPC交換のタネボー(NN:セブン)です。


f:id:BZL:20190923172314p:plain
交換にはラルトスが必要なので所持していない場合は102番道路で捕まえます。


f:id:BZL:20190923172413p:plainf:id:BZL:20190923172425p:plain
カナズミジム隣の民家にいるボーイスカウトに話しかけます。


f:id:BZL:20190923172453p:plain
ラルトスが欲しいと言われるのでタネボーと交換します。


ここで交換したタネボー努力値をH95、A8に調整します。
私は以下の通りに振りました。

マックスアップ*9

ケムッソ*5

ポチエナ*8



f:id:BZL:20190923175740p:plain
努力値の調整が終わったらこのタネボーを材料にダブルコラプションを行います。
成功するとこの画像のようなバグポケモンが生成されます。


2019/10/07 追記
実機環境ではダブコラを行わずPID破損のみ行えば生成されたタマゴを孵化させて0x085Fを入手できます。
PID破損したタマゴが生成された場合はボックス12の11匹目からボックス14の30匹目までを全て空欄にし、ボックス1の名前をボックス1『いぶたぃ び』、ボックス2の名前を『アアアyコくく』にしてからポケセンで孵化させてください。
(ポケセン外で孵化させるとフリーズします。例外が存在する可能性有り)
「おや…?」からの暗転時間が少々長い(恐らくLZ77解凍処理の不正実行によるループ)ですが、約5秒程度待機すれば正常に孵化処理が実行されます。
孵化処理後はメモリが不安定になっている可能性があるのでレポート保存後のリセットをおすすめします。


以上でバグポケモン0x085Fの生成は終了です。
この段階ではまだ0x085Fの様子は見ないでください。

2)任意コードの入力



重要:ボックス12の11匹目からボックス14の30匹目までを全て空欄にしてください。
実行されるプログラムの記述にはボックス名1-14を使用することができます。
プログラムを記述したら0x085Fの様子を見ます。
スクリプト実行の場合ボックスを閉じたタイミングで処理が発動します。
以下はコードの例です。


さいはてのことうへのワープスクリプト

ボックス ボックス名
ボックス1 『くぶ むあめあミ』
ボックス2 『アいメGタ l』
ボックス3 『いむだメえぱうチ』
ボックス4 『アのメえぶけl』
ボックス5 『ぎせ うぃVうい』
ボックス6 『アアアぐはぎ 』
ボックス7 『ねタミび』

ボックス6の『はぎ』の部分を適当な文字列に書き換えるとワープ先を任意のものに変更できます。

ワープ先 対応する文字列
みなみのことう 『はけ』
たんじょうのしま 『はげ』
へそのいわ 『はぢ』



エンディング処理実行

ボックス ボックス名
ボックス1 『 ぶ びじオぬく』




3)コード実行の原理について



完全におまけなので興味なかったら見なくていいです



エメラルドで追加された処理の内の一つにポケモンのアニメーション』というものがあり、ポケモンの種族ごとに様々なアニメーションが割り当てられています。
内部処理的にアニメーションの割り当てには1ByteのID指定と、そのIDに紐付けられたアニメーションのプログラム参照テーブル、そしてポケモンの種族とアニメーションのIDを紐付けるテーブルが使用されます。

バグポケモンは不正なポケモンコードを持っているのでポケモンコードを使用して参照されるテーブルの殆どで不正参照が行われます。(正面画像等の例外は有り)
前述した通りポケモンのアニメーションのプログラムはIDに紐付いたテーブルを参照して実行されるので、不正なIDを渡すと本来プログラムでない領域を参照させることができます。

アニメーションのプログラム参照テーブルは0x085D34E8に配置されています。
このテーブルの内容を調べると有効なアニメーションIDは0x00-0x96でそれ以降のIDは不正領域参照となっていることが分かります。
使用可能な1Byte分のIDを一通り調査した結果、プレイヤーが自由に変更できるRAMを参照させることのできるIDは0xBA(参照RAM:0x0202FFFF)のみとなりました。
0x0202FFFFのプログラム参照の場合、参照位置より先にポケモンを置かないことによってボックス名の格納RAMまで安全にアクセスすることができます。
(0xBDはボックスRAM0x0202FFFEを参照しているので一見使用できるように思えますがTHUMBステートで実行されないアドレスなので除外しています)

ポケモン毎のアニメーションIDの指定テーブルは0x082FA374に配置されているので、この領域を調査することでバグポケモンに割り当てられたIDを調べることができます。
アニメーションID0xBAを参照していて尚且生成に必要な努力値調整数の少ないバグポケモンを調べた結果、0x085Fがこの条件に合致しているのではないかと考えました。

このコード実行バグについて調査・考察した内容は以上となります。
因みにこのコード実行法はFRLGでは無理です。

【Em】セーブデータ改竄によるシステムハック

セーブデータに保存されるデータを利用して、ゲーム開始時に任意コードを実行できる方法を発見したので解説します。
この記事で紹介する方法ではゲーム開始時に自動的に実行される任意コードからバイナリエディタ起動準備を行い、L+Rの同時押しでいつでもバイナリエディタが起動できるようになります。


↓動画

また、システムハックの導入にはバイナリエディタの起動環境を整えていること、16進数を理解していることを前提条件とします。

導入手順解説の前に、具体的に何を行ったかについて解説します。

従来の手法では、技アニメスクリプトの不正アドレス参照をトリガーにしてボックス上に記述した任意コードを実行する、といった方式でチューリング完全の処理を実行させることができていました。

実行できる任意コードはGBAのハードウェアを完全に制御することが可能なので、割り込み処理等を変更することでシステムハック自体は簡単に行えます。
(この記事で行っていることも大体同じ原理です)
bzl.hatenablog.com

割り込み処理変更によるシステムハックを実行すれば、技アニメ再生後は任意のタイミングで任意コードを実行することができます。
しかし、割り込み処理のポインタを含む静的RAMの変更内容は基本的にゲーム終了と同時にリセットされてしまうため、システムハックを行ってもその効果をゲーム終了後も持続させることはできませんでした。

そこでゲーム開始時にメモリを改竄するため、ゲーム開始時の処理をトリガーに任意コードを実行する方法がないか調査した結果、主人公スプライトに紐付けられたオブジェクトアクションID(デフォルト0x0B)がセーブデータ上に保存され、開始時にセーブデータ依存でRAM展開されることに気付きました。
(オブジェクトアクションIDについての資料はこちら)
オブジェクトアクションIDに紐付けられたプログラムはNPCスプライトが描画されている限り実行され続けるので、ここで不正プログラムを参照させれば主人公スプライトが描画されるゲーム開始時に任意コードを実行させることができます。

紐付けられたプログラムの参照テーブル付近のデータを調査した結果、0x084DDA40にボックスRAM0x02030401(0x02030400に記述されたプログラムをTHUMBステートで参照する)へのポインタとなるデータが配置されていたので、ここを参照できるオブジェクトアクション0x6Eを任意コード実行のトリガーとして使用することにしました。

ゲーム開始時に行われる処理の流れは以下の通りです。

  1. 主人公スプライト描画
  2. オブジェクトアクション0x6Eに紐付けられたプログラム(0x02030400)の実行
  3. 静的RAM(0x0203D000)へのスクリプト展開
  4. ボックス1の2匹目から記述されているプログラムを静的RAM(0x0203D020)にコピー
  5. 静的RAM(0x0203CE00)への割り込み処理展開
  6. 割り込み処理参照ポインタ(0x03007FFC)の書き換え
  7. システムハックの完了


導入手順


1)バイナリエディタの導入



記事冒頭で前提条件として挙げた通り、データの打ち込みにはバイナリエディタを使用します。
(理論上はアニメスクリプトでも書き込めるが、使用できるバイナリデータに限りがあるのとボックス埋め込み用にコード組むのがめんどくさい)

バイナリエディタ未導入の場合、以下の記事を参考に導入してください。
http://bzl.hatenablog.com/entry/2019/07/16/075233bzl.hatenablog.com

2)データ書き込みアドレスの始点計算



バイナリエディタが導入できたら、バグ技0x2B5C、又はバグポケ0x085Fを使用してバイナリエディタを起動します。
今回データを書き込む領域はボックスRAM(動的RAM)になるので、乱数によって対応するメモリアドレスが変化してしまいます。
適当な領域に書き込むとダメタマゴフラグの影響でプログラムが破損するので、正確な位置にデータを書き込む必要があります。

まず、バイナリエディタで0x03005AF4、0x03005AF5、0x03005AF6、0x03005AF7のデータを読み込み、この時読み込んだデータを前から①、②、③、④として扱います。
f:id:BZL:20190922205425p:plain
画像で読み込まれたデータは①AC、②94、③02、④02となっています。
このデータを④③②①の順に並び替えると0x020294ACというアドレスになると思います。
これがボックスRAMの始点です。

ボックスRAMの始点に0x6ED8を加算するとデータ書き込み先のアドレスが算出できます。
この画像のケースではデータ書き込み先のアドレスは0x02030384になります。

この手順で開いたバイナリエディタは閉じずにそのまま手順3に移行してください。
もし閉じてしまった場合は、再度手順2の頭からやり直しです。(動的RAMの先頭アドレスは画面切り替え毎に変動するため)

3)データ書き込み



手順2で算出したアドレスをこれ以降pと表記します。

任意コード実行にバグポケ0x085Fを使用している場合p+0x00~p+0xBBまでの改変は必要ありません。
その代わりにp-0x34の位置を始点に以下のデータを書き込んでください。

書き込み位置 データ
p-0x34 00
p-0x33 48
p-0x32 00
p-0x31 47
p-0x30 F1
p-0x2F 17
p-0x2E 03
p-0x2D 02


p+0x00~p+0x7Fまでのメモリ領域を0x1A,0x00,0x1A,0x00...と埋めていきます。
バイナリエディタの導入時点で既にここのメモリは書き換えられているはずなので実際に書き込む手間はそこまで多くありません。

プログラムとして参照しても問題ないようにした上で0x2B5Cを引き続き使用できるようにする為にp+0x80の位置に以下のスクリプトを記述します。

書き込み位置 データ
p+0x80 03
p+0x81 DD
p+0x82 17
p+0x83 33
p+0x84 02
p+0x85 99
p+0x86 00
p+0x87 08

0x023317DDをポインタとして扱って大丈夫なのか?と思う方がいるかもしれませんが問題なく参照可能です。(実機、VBA1.7.2で確認済み)

p+0x88~p+0xBBまでの領域を0x00で埋めます。

p+0xBCを始点に以下のプログラムデータを書き込みます。
(長いのでスポイラーにしています)

書き込み位置 データ
p+0xBC F0
p+0xBD B4
p+0xBE 04
p+0xBF 1C
p+0xC0 29
p+0xC1 48
p+0xC2 01
p+0xC3 38
p+0xC4 01
p+0xC5 78
p+0xC6 00
p+0xC7 29
p+0xC8 47
p+0xC9 D1
p+0xCA 01
p+0xCB 21
p+0xCC 00
p+0xCD E0
p+0xCE AA
p+0xCF AA
p+0xD0 01
p+0xD1 70
p+0xD2 41
p+0xD3 1C
p+0xD4 26
p+0xD5 48
p+0xD6 00
p+0xD7 68
p+0xD8 54
p+0xD9 30
p+0xDA 20
p+0xDB 31
p+0xDC 78
p+0xDD 22
p+0xDE 92
p+0xDF 00
p+0xE0 00
p+0xE1 E0
p+0xE2 AA
p+0xE3 AA
p+0xE4 0B
p+0xE5 DF
p+0xE6 20
p+0xE7 48
p+0xE8 22
p+0xE9 49
p+0xEA 02
p+0xEB 1C
p+0xEC 00
p+0xED E0
p+0xEE AA
p+0xEF AA
p+0xF0 21
p+0xF1 32
p+0xF2 89
p+0xF3 23
p+0xF4 9B
p+0xF5 00
p+0xF6 03
p+0xF7 33
p+0xF8 00
p+0xF9 E0
p+0xFA AA
p+0xFB AA
p+0xFC 02
p+0xFD 25
p+0xFE 2E
p+0xFF C0
p+0x100 1D
p+0x101 48
p+0x102 1E
p+0x103 49
p+0x104 00
p+0x105 E0
p+0x106 AA
p+0x107 AA
p+0x108 1E
p+0x109 4A
p+0x10A 1F
p+0x10B 4B
p+0x10C 20
p+0x10D 4D
p+0x10E 21
p+0x10F 4E
p+0x110 22
p+0x111 4F
p+0x112 EE
p+0x113 C0
p+0x114 22
p+0x115 49
p+0x116 24
p+0x117 4A
p+0x118 24
p+0x119 4B
p+0x11A 25
p+0x11B 4D
p+0x11C 00
p+0x11D E0
p+0x11E AA
p+0x11F AA
p+0x120 24
p+0x121 4E
p+0x122 25
p+0x123 4F
p+0x124 EE
p+0x125 C0
p+0x126 26
p+0x127 49
p+0x128 26
p+0x129 4A
p+0x12A 27
p+0x12B 4B
p+0x12C 27
p+0x12D 4E
p+0x12E F4
p+0x12F 25
p+0x130 00
p+0x131 E0
p+0x132 AA
p+0x133 AA
p+0x134 AD
p+0x135 19
p+0x136 80
p+0x137 27
p+0x138 BF
p+0x139 00
p+0x13A 01
p+0x13B 37
p+0x13C 00
p+0x13D E0
p+0x13E AA
p+0x13F AA
p+0x140 EE
p+0x141 C0
p+0x142 09
p+0x143 49
p+0x144 03
p+0x145 31
p+0x146 23
p+0x147 4A
p+0x148 00
p+0x149 E0
p+0x14A AA
p+0x14B AA
p+0x14C 22
p+0x14D 4B
p+0x14E 0E
p+0x14F C0
p+0x150 09
p+0x151 48
p+0x152 23
p+0x153 49
p+0x154 00
p+0x155 E0
p+0x156 AA
p+0x157 AA
p+0x158 08
p+0x159 60
p+0x15A F0
p+0x15B BC
p+0x15C 20
p+0x15D 1C
p+0x15E 01
p+0x15F 49
p+0x160 08
p+0x161 47
p+0x162 00
p+0x163 00
p+0x164 FD
p+0x165 A2
p+0x166 08
p+0x167 08
p+0x168 00
p+0x169 D0
p+0x16A 03
p+0x16B 02
p+0x16C 00
p+0x16D E0
p+0x16E AA
p+0x16F AA
p+0x170 F4
p+0x171 5A
p+0x172 00
p+0x173 03
p+0x174 28
p+0x175 30
p+0x176 00
p+0x177 23
p+0x178 00
p+0x179 CE
p+0x17A 03
p+0x17B 02
p+0x17C 0F
p+0x17D 00
p+0x17E A0
p+0x17F E1
p+0x180 00
p+0x181 E0
p+0x182 AA
p+0x183 AA
p+0x184 05
p+0x185 00
p+0x186 80
p+0x187 E2
p+0x188 10
p+0x189 FF
p+0x18A 2F
p+0x18B E1
p+0x18C 00
p+0x18D E0
p+0x18E AA
p+0x18F AA
p+0x190 0A
p+0x191 48
p+0x192 40
p+0x193 78
p+0x194 03
p+0x195 21
p+0x196 88
p+0x197 42
p+0x198 00
p+0x199 E0
p+0x19A AA
p+0x19B AA
p+0x19C 0B
p+0x19D D1
p+0x19E 09
p+0x19F 4B
p+0x1A0 1B
p+0x1A1 78
p+0x1A2 01
p+0x1A3 2B
p+0x1A4 00
p+0x1A5 E0
p+0x1A6 AA
p+0x1A7 AA
p+0x1A8 07
p+0x1A9 D0
p+0x1AA 08
p+0x1AB 4B
p+0x1AC 00
p+0x1AD 20
p+0x1AE 18
p+0x1AF 60
p+0x1B0 D8
p+0x1B1 60
p+0x1B2 07
p+0x1B3 48
p+0x1B4 98
p+0x1B5 60
p+0x1B6 07
p+0x1B7 48
p+0x1B8 18
p+0x1B9 61
p+0x1BA 07
p+0x1BB 48
p+0x1BC 00
p+0x1BD E0
p+0x1BE AA
p+0x1BF AA
p+0x1C0 6E
p+0x1C1 21
p+0x1C2 81
p+0x1C3 71
p+0x1C4 06
p+0x1C5 4B
p+0x1C6 18
p+0x1C7 47
p+0x1C8 8C
p+0x1C9 23
p+0x1CA 00
p+0x1CB 03
p+0x1CC 38
p+0x1CD 0E
p+0x1CE 00
p+0x1CF 03
p+0x1D0 00
p+0x1D1 E0
p+0x1D2 AA
p+0x1D3 AA
p+0x1D4 F0
p+0x1D5 6F
p+0x1D6 03
p+0x1D7 02
p+0x1D8 F0
p+0x1D9 27
p+0x1DA 00
p+0x1DB 03
p+0x1DC 00
p+0x1DD E0
p+0x1DE AA
p+0x1DF AA
p+0x1E0 FC
p+0x1E1 7F
p+0x1E2 00
p+0x1E3 03


殿堂入り処理等、何らかの原因でシステムハックが解除された時にすぐ復帰できるように、バグ技0x2B5Cやバグポケ0x085Fで実行できる任意コードを記述します。
内容は0x02036FF6に0x6Eを代入するコードです。
ボックス名1の領域(p+0x146C)を始点に以下のデータを書き込みます。

書き込み位置 データ
p+0x146C 02
p+0x146D 48
p+0x146E 6E
p+0x146F 21
p+0x1470 81
p+0x1471 75
p+0x1472 70
p+0x1473 BC
p+0x1474 FF
p+0x1475 51
p+0x1476 80
p+0x1477 BD
p+0x1478 E0
p+0x1479 6F
p+0x147A 03
p+0x147B 02

ボックス名に直した場合の文字列データは以下の通りです。

ボックス ボックス名
ボックス1 いぶホむゥユミB
ボックス2 アィClマうい

最後に、以下のメモリ改変を行います。

メモリアドレス データ
0x0203CFFF 0x?? → 0x00
0x02036FF6 0x0B → 0x6E

以上でRAM改竄は完了です。


!注意
RAM改竄終了後は手順4の内容を終えるまで絶対にレポートを書かないこと。
もし入力ミスがあった場合ゲーム起動時にクラッシュするようになるので実質的なセーブ破損状態になる。
この状態になった場合『さいしょから はじめる』を選択してニューゲームするか外部ツールでセーブデータを改造する以外に回避する手段がない。


4)処理の実行



ポケモン選択画面やバッグ等を開いてから再度スタートメニュー画面に戻ります。
マップが再描画されオブジェクトアクションに紐付けられたプログラムが参照し直されると、前述の手順で書き込んだプログラムが実行され、割り込み処理の差し替えとバイナリエディタの静的RAMコピーが行われます。

フリーズせず正常に動作することを確認できたら、レポートを書いて終了してください。




以上の操作を完了させることにより、無改造のエメラルドをほぼ完全にハックすることができます。
ゲーム性は完全に崩壊しますが、メモリ弄りが大好きな方は是非試してみては如何でしょうか。
因みに、FRLGでも同じ手法でハックすることが可能です。

【FRLG,Em】CartRAMの取り扱いメモ

メモ記事です

ポケモン等のGBAソフトのセーブデータは基本的にCartRAMに保存されますが、このRAMは通常のWorkRAMとは読み書きの方法が異なるので愚直に弄ろうとしてもまず上手くいきません。
この記事ではポケモンで使用されているFRAM(1Mbit)の扱い方について記します。

↓FRLG/Emで使用されているらしいFRAMのデータシート
f:id:BZL:20190922061033p:plain

但しこのデータシートには1MbitのFRAMを扱う上で肝となっているバンクの切り替えについて記述されていません。(見落としてるだけかもしれないけど)
今回はよく使われるデータ書き込みとバンク切り替えについてのみ解説したいと思います。

バンク切り替えについて



CartRAMは基本的に0x0E000000-0x0E00FFFFのアドレス空間を持っています。
しかし1MbitのFRAMの場合、このアドレス空間だけではメモリの全領域を参照させることができません。
ここで使用するのがバンク切り替えです。
メモリ内のアドレス0x00000-0x0FFFFをバンク0、アドレス0x10000-0x1FFFFをバンク1として扱うことで実質的に0x0E000000-0x0E01FFFFのアドレス空間を使用することができるようになります。
しかしこのバンク切り替えは使用するアドレスが0x0E00FFFFまでの範囲を超えていれば自動的に行われる訳ではなく、プログラムを組むユーザー側で適宜切り替える必要があります。
また、アドレス空間はあくまで0x0E000000-0x0E00FFFFの範囲なので、メモリ内アドレス0x10000以降を参照させる場合はバンク1に切り替えた後に0x10000を始点としたアドレス指定を行う必要があります。
(例:0x0E01C000を参照させたい場合はバンク1に切り替えた後に0x0E00C000を参照させる)

バンク切り替え処理は以下のコードの通りです。

/*バンク切り替えサンプルコード*/
.thumb
 
/*r0 = バンクID*/
 
/*コマンド操作にstrb命令を使用しているが実際にデータは書き込まれない*/
ldr r1, =0x0e005555
ldr r2, =0x0e002aaa
ldr r3, =0x0e000000
mov r4, #0xb0
strb r2, [r1] /*0x5555 <- 0xAA*/
strb r1, [r2] /*0x2AAA <- 0x55*/
strb r4, [r1] /*0x5555 <- 0xB0*/
strb r0, [r3] /*0x0000 <- バンクID*/


データ書き込みについて



次はFRAMへのデータ書き込みの方法について解説します。
前述のバンク切り替えと同じく、strb命令を使用したコマンド操作が必要なのでWorkRAMと同じように扱っても書き換えることができません。
また、1byte書き込む度に再度コマンド操作を挟む必要があります。
データの読み込みに関してはバンク合わせてから普通にldrbで読み込むだけです。

書き込み処理は以下のコードの通りです。

/*データ書き込みサンプルコード*/
.thumb
 
/*r0 = 任意のデータ(1byte)*/
/*r1 = 書き込み先アドレス*/
 
ldr r2, =0x0e005555
ldr r3, =0x0e002aaa
mov r4, #0xa0
strb r3, [r2] /*0x5555 <- 0xAA*/
strb r2, [r3] /*0x2AAA <- 0x55*/
strb r4, [r2] /*0x5555 <- 0xA0*/
 
/*データ書き込み*/
/*この書き込み処理以外はCartRAM上には反映されない*/
strb r0, [r1]

【FRLG】任意コード実行による色違いデオキシスの動的生成

色違い固定のエンカウント処理を走らせてみたくなったので作りました。

デバッグ環境はFR前期ROMですが呼び出し元を調整すればFRLG前期後期の4バージョンで動くと思います。
FRLGにおいてバグ技持ちの個体を入手していることを前提とします。

色個体生成の原理は以前投稿したこの記事のものとほぼ同じです。
bzl.hatenablog.com

以前のものと違う点は個体検索処理を全て任意コード側に任せていることです。
そのため、任意コードを打ち込んで実行するだけで任意の種族のポケモンとの色違い固定エンカウントが行えるようになります。

任意コードが長くなってしまっているので本来はバイナリエディタ起動環境を整えた後に実行する方が望ましいのですが、興味のある方は是非試してみてください。

・ボックス配置ポケモン



スクリプト呼び出し用ポケモン
TNの変更が面倒な場合はNNのみで充分です。
NNのみの場合バグ技の成功率は1/8から1/16に下がります。
へ(平仮名)と(カタカナ)の区別が付き辛いのでカタカナのみ赤字で記述しています。

FR 0x38C9用
ボックス12/22:NN『てムにうい』TN『てナにうい』
ボックス12/23:NN『てむにうい』TN『てなにうい』

LG 0x21BE用
ボックス12/23:NN『てにうい』TN『てチにうい』
ボックス12/24:NN『てへにうい』TN『てちにうい』


プログラム用ポケモン(ボックス13/12からスタート)
かなり数が多くなっているので、作業の簡略化のため容量度外視でNNのみ使用する形式にしています。

ボックス13/12:NN『てぺぷl』
ボックス13/13:NN『 Vうい』
ボックス13/14:NN『てぶぷl』
ボックス13/15:NN『7せ う』
ボックス13/16:NN『 むゆl』
ボックス13/17:NN『あミゆl』
ボックス13/18:NN『Gタゆl』
ボックス13/19:NN『かチゆl』
ボックス13/20:NN『あむゆl』
ボックス13/21:NN『あメゆl』
ボックス13/22:NN『いむゆl』
ボックス13/23:NN『だメゆl』
ボックス13/24:NN『てぶぷl』
ボックス13/25:NN『にえィボ』
ボックス13/26:NN『てべぷl』
ボックス13/27:NN『あにおィ』
ボックス13/28:NN『てぼぷl』
ボックス13/29:NN『ほ にか』
ボックス13/30:NN『てぱぷl』

ボックス14/1:NN『ィ  も』
ボックス14/2:NN『てぴぷl』
ボックス14/3:NN『へVうい』
ボックス14/4:NN『てぷぷl』
ボックス14/5:NN『ゆAあゆ』
ボックス14/6:NN『てぽぷl』
ボックス14/7:NN『ぎあい 』
ボックス14/8:NN『ELゆl』
ボックス14/9:NN『てぶぷl』
ボックス14/10:NN『ミ♂すぱ』
ボックス14/11:NN『てべぷl』
ボックス14/12:NN『hネ わ』
ボックス14/13:NN『てぼぷl』
ボックス14/14:NN『あWッぉ』
ボックス14/15:NN『てぱぷl』
ボックス14/16:NN『hネタグ』
ボックス14/17:NN『てぴぷl』
ボックス14/18:NN『3グでぞ』
ボックス14/19:NN『まLゆl』
ボックス14/20:NN『nぶゆl』
ボックス14/21:NN『Uべゆl』
ボックス14/22:NN『Cぼゆl』
ボックス14/23:NN『!ぱゆl』
ボックス14/24:NN『ぴゆl』
ボックス14/25:NN『ガぷゆl』
ボックス14/26:NN『ヤぽゆl』
ボックス14/27:NN『ELゆl』
ボックス14/28:NN『ぺぶレl』
ボックス14/29:空欄
ボックス14/30:空欄

・ボックス名



ボックス1:『リばレらァあFひ』
ボックス2:『アしぎガば』
ボックス3:『つべてぼなぱなぴ』
ボックス4:『アまLミBィC』
ボックス5:『へネリばくぼんふ』
ボックス6:『アアアくべぷづ』
ボックス7:『アア。ねノづ』
ボックス8:『アグねノぞ』
ボックス9:『けしチぞきる e』
ボックス10:『アアアガばほタ』
ボックス11:『アアミC  』
ボックス12:『アッぽ う』
ボックス13:『モタ  ぺLだ』
ボックス14:『うダなういィ く』

上記の打ち込みが終了したら、適当な野生ポケモン相手にバグ技を使用します。
技成功後に逃げるを選択し、戦闘を終了させるとイベントスクリプトが実行され、色違いデオキシス(フラグ付き)lv30が出現します。
f:id:BZL:20190923100219p:plain

使用したコードは以下の通りです。
このコードをSpecial0x1BB(固定シンボル個体生成処理)の前に挟んでSeed値を書き換えることにより、実行したROMに適合した色違いPIDを生成させています。
但し、この処理とPID生成処理の間に割り込みが入って乱数値が更新されてしまう可能性もあるので完全な100%出現ではありません。(所謂メソズレ)

.thumb
	
shinyseed_get:
	push {r4-r6, lr}
	ldr r3, =0x03004fa0
	ldr r4, [r3, #0xc] /*後期ROM*/
	cmp r4, #0x0
	bne tidget
	add r3, #0xa0
	ldr r4, [r3, #0xc] /*前期ROM*/
	
tidget:
	ldrh r0, [r4, #0xa] /*TID*/
	ldrh r4, [r4, #0xc] /*SID*/
	eor r4, r0 /*TID xor SID -> TSV*/
	ldr r5, [r3] /*初期Seed取得*/
	mov r0, pc /*b命令が後ろに飛べないのでpc更新で代用*/
	ldr r2, =0x00006073
	
shinysearch:
	mov r6, r5
	ldr r1, =0x41c64e6d
	mul r5, r1
	add r5, r2 /*LID生成*/
	mul r1, r5
	add r1, r2 /*HID生成*/
	eor r1, r5 /*HID xor LID -> PSV*/
	lsr r1, #0x10
	eor r1, r4 /*PSV xor TSV*/
	cmp r1, #0x7
	bls setseed
	mov pc, r0
	
setseed:
	str r6, [r3]
	pop {r4-r6, pc}
	
/*
イベントスクリプト
	setvar 0x8004 0x019A
	setvar 0x8005 0x001E
	setvar 0x8006 0x0000
	callasm shinyseed_get+1
	special 0x1BB
	special 0x138
	end
*/

LG用任意コード実行に関するアレコレ

LG前期ROMでの任意コード実行法が割れていないようなので簡潔に纏めます。
任意コード実行バグ自体の原理としてはEm,FRで行ったものと全く同じですので細かい解説は省きます。
アセンブリやメモリ構造を理解しており、Emでの任意コード実行環境が整っている方向けです。

Emの0x2B5CやFRの0x38C9のような都合の良いバグ技が存在しなかったので幾つか候補となる技を挙げています。
それぞれ参照されるメモリアドレスが異なっている為、使用する技に合わせて各自でプログラムを調整するようにお願いします。

バグ技持ちの個体調達はEmで行うことを推奨します。
GBA同士の交換ではバグ技持ちが扱えないのでGC(Co,XD)経由で送ってください。

使用できるバグ技



0x2348

威力:37
命中:37
PP:37
参照メモリアドレス:0x02030400
効果は『ねむる』と同一。
HPが満タンの場合は失敗する。
f:id:BZL:20190916053758p:plain


0x21BE

威力:153
命中:153
PP:17
参照メモリアドレス:0x020300C0
効果は自分に対し『あくび』を使用するというもの。
使用後は基本的にすぐに戦闘離脱するのでほぼノーデメリット?
この記事の最後に紹介している任意コード実行ではこのバグ技を使用しています。
f:id:BZL:20190916054042p:plain


0x0259

威力:---
命中:96
PP:1
参照メモリアドレス:0x02030400
効果は通常攻撃。
PPが非常に少ない。ごく稀に外れる。
f:id:BZL:20190916060123p:plain


0x0506

威力:64
命中:11
PP:45
参照メモリアドレス:0x02030085
効果は『つるぎのまい』と同一。
参照アドレスが4の倍数ではないので注意。
f:id:BZL:20190916060452p:plain


0x20F9

威力:153
命中:153
PP:153
参照メモリアドレス:0x02030087
効果は『テレポート』と同一。
任意コード実行と戦闘離脱を同時に行ってくれるが、参照アドレスが4の倍数ではないのでスクリプトが記述しづらい。
f:id:BZL:20190916054228p:plain



実行するコードの例


0x21BE用たんじょうのしまワープ
技成功後にテレポートを使用するとたんじょうのしまにワープします。
f:id:BZL:20190916091650p:plain


.thumb

/*元のコード*/
ldr r0, =0x03005048 /*動的RAM制御ポインタ*/
ldr r0, [r0]
ldr r1, =0x00003802 /*マップ指定*/
str r1, [r0, #0x1c]
pop {r4-r7, pc}
/**/
/*===========================*/
/**/
/*ボックス名埋め込み用*/
/*Box1*/
box1:
ldr r0, var2
ldr r0, [r0]
ldr r1, var1
b box3

/*Box3*/
box3:
str r1, [r0, #0x1C]
pop {r4-r6}
pop {r7, pc}

/*Box5*/
var1:
.word 0x00003802

/*Box7*/
var2:
.word 0x03005048

box7:
b box1

ボックス内編集内容


ジャンプスクリプト

13 07 16 03 02 (12/23 NN:てきにうい)
13 01 16 03 02 (12/23 TN:てあにうい)
13 D5 15 03 02 (12/24 NN:てaなうい)


任意コード実行スクリプト

03 35 16 03 02 80 00 08 (Box2:うゅにういィ く)
03 ED 15 03 02 80 00 08 (Box4: うyなういィ く)
03 A9 15 03 02 80 00 08 (Box6:う8なういィ く)


任意コード部

0D 48 00 68 07 49 04 E0 (box1:すぶ ネきべえl)
C1 61 70 BC 80 BD (box3:GチミBィC)
02 38 00 00 (box5:いぎ  )
51 51 48 50 00 03 E0 E7 (box7:アアぶっ うls)


ボックス5の名前を書き換えることでワープ先を変更できます。
以下はその例になります。
[い   ]:へそのいわ
[あえ  ]:サント・アンヌごう桟橋
[あぜ  ]:サファリゾーン
[あっ  ]:殿堂入り部屋
[うゃ  ]:8ばんななしま
[うゅ  ]:9ばんななしま