2006.02.09
No.005 マスターコードのサーチ方法

※当記事で説明している内容はツールで全自動化できます※

Project-DipStar- Ver3.55以降、マスターコードサーチツール ndsmas.exe を同封するようになりました。
よって、この回で説明しているサーチ方法は全てツールで自動化できるようになったため、
単純に「改造コードを作りたい」と思っている方は読む必要がありません。

詳しい原理を知りたいと思う人のみ、以下をご覧下さい。

どうしてマスターコードが必要なのか?
サーチ方法の前に、Project-DipStar-の動作原理を説明しておきましょう。
まず、デフォルト状態である「起動時に1回だけ書き込む」という仕組みは、
図1
上図のような流れになっています。
電源投入後、PassMeによってGBAフラッシュカートのプログラムへ制御が移ってからDipStarが処理を行い、
メモリ内容を書き換えてから本来の処理に制御を戻しているわけですね。
当然、本来の処理に制御を渡した時点でDipStarは役目を果たし、後に呼び出されることはありません。

マスターコードを定義した状態を図に表すと…
図2
こんな感じで、Project-DipStar-で言うマスターコードには
任意の命令を潰し、代わりにDipStarのプログラムを呼び出すように流れを捻じ曲げる
役割があります。
なお、潰した命令はDipStarのプログラムの終端に置くことで「何事も無かったかのように」実行され、
その後、DipStarを呼び出した場所に戻ります。

つまりマスターコードに指定するアドレスは…
大抵の場合、マスターコードを定義する改造コードは「常に書き込み続ける」ことが目的なので、
ゲームプログラムで「常に実行しつづけている処理」をマスターコードに使うと良いでしょう。

その中でも最も特徴的で、ほぼ全てのゲームで同じ手法が使える場所…それはキー(ボタン)入力です。
GBA及びNDSでは、ボタン入力情報のほとんどはアドレス04000130に格納されています。
(NDSの場合、X/Yボタンやタッチパッドだけは場所や条件が異なる)

例えば「直感ヒトフデ」の逆アセンブルリストから文字列 "04000130" を検索すると…
:020014F0 E59F1048 ldr r1,[r15, #+0x48]		;r15+0x48=*(02001540)=#67109168(0x04000130)
:020014F4 E59F0048 ldr r0,[r15, #+0x48]		;r15+0x48=*(02001544)=#41942952(0x027fffa8)
:020014F8 E1D130B0 ldrh r3,[r1, #+0x0]		;r1+0xb0=*(040001e0)=#0(0x00000000)
こんな感じでキー入力処理ルーチンにヒットします。
この処理は毎秒数十回(割込が使われているともっと多いかも)実行されているため、
マスターコードとして使うにはちょうど良い感じです。

なので04000130を参照しているアドレス020014F0の命令を潰してマスターコードに……してはいけません。
「r15レジスタを使う命令の含まれるアドレスは絶対にマスターコードに使えません」

そもそもレジスタとは?
ニンテンドーDSに採用されているCPU(ARM)では数値を処理するための入れ物として、
r0〜r15までの16個の汎用レジスタやCPSRやSPSR系といったステータスレジスタなどの数十個のレジスタがあります。
(改造コードを作るために使うのは汎用レジスタだけなので、ステータスレジスタは気にしなくていいです)。

そのレジスタとメモリとのやり取りで計算を行うわけですが「汎用と言いながら微妙に専用なレジスタ」があります。
r13はスタックポインタ(PUSH/POP)のアドレス管理に用います。
r14にはサブルーチンを呼び出す際の「戻るべき場所(リターンアドレス)」を保持し、
r15には次に実行するべき命令のアドレス(プログラムカウンタ)が格納されています。
(厳密にはr15には命令実行アドレスにプリフェッチで先読みした8を加算した数値が入ります。要はr15=実行アドレス+8)。

ldr r1,[r15, #+0x48]の意味は「r1レジスタに、アドレスr15+0x48に格納されたデータを入れる」なのですが、
r15は「命令を実行した場所」に影響される命令なので、DipStarのルーチン内で実行すると全く違う意味になってしまいます。
先ほどのキー入力処理ルーチンですら、アドレス020014F0と020014F4で、全く違う結果が返っていますね。

ならば、どこをマスターコードアドレスに…
キー入力処理ルーチンをしばらく下に向かってスクロールしていくと…
:02001530 E1C230B0 strh r3,[r2, #+0x0]		;r2+0xb0=*(020b93a0)=#-369098725(0xea00001b)
:02001534 E1C2C0B2 strh r12,[r2, #+0x2]		;r2+0xb2=*(020b93a2)=#6744576(0x0066ea00)
:02001538 E5810000 str r0,[r1, #+0x0]		;r1+0x0=*(020b6148)=#-494088671(0xe28cce21)
:0200153C E12FFF1E bx r14 (Jump to addr_04000008?)
bx r14……b(ブランチ/ジャンプ・分岐)命令をレジスタに対して行うbxと、r14(リターンアドレス)の組み合わせ、
要は「キー入力処理ルーチンを呼び出したところに帰る」処理を行っているわけですね。
ここをマスターコードとして利用するのが「最も手っ取り早い」です。

このアドレスからDipStarの改造コード処理に分岐した後、bx r14命令が実行されて本来の処理に戻る……
つまり、本来の処理に帰る直前を狙って割り込んでいるわけです。
特にレジスタ値などに影響されることも無いため、安全確実、バッチリです。

というわけでマスターコードの書式はF{実行アドレス} {本来のコード}ですので、
F200153C E12FFF1E
が、直感ヒトフデのマスターコードになります。

前回hasteDSでサーチしたスコアの書き換えコードと組み合わせると…
F200153C E12FFF1E
220B627C 05F5E0FF

Project-DipStar-のコードエディタで上記コードを実行して、スコアが99999999になるか確認してみてください。

さいごに
これで、マスターコードを利用した常時書き込みコードが作れるようになりました。
今回の教訓は「"04000130"を検索して、その後にあるbx r14をマスターコードにする」ですね。

次回は「条件分岐コードの活用」です。

それで〜は〜
>>次の講座へ進む