妖怪ウォッチバスターズ ASMコード解説
必殺技無限
00632B40 E5980000
00632B44 E92D400F
00632B48 E59F001C
00632B4C E59F101C
00632B50 E5900000
00632B54 EBEC6F81
00632B58 E3500000
00632B5C 08BD800F
00632B60 E3A01000
00632B64 E5801178
00632B68 E8BD800F
00632B6C 0068F3A8
00632B70 F64BEC60
003FAD04 EB08DF8D
Code by 改造博物館
今回は上記のコードを解説していきます。
細かく書くのが面倒なのでアセンブラの詳細は割愛させていただきます。
では、解説をさせていただきます。
必殺技無限
00632B40 E5980000
00632B44 E92D400F
00632B48 E59F001C
00632B4C E59F101C
00632B50 E5900000
00632B54 EBEC6F81
00632B58 E3500000
00632B5C 08BD800F
00632B60 E3A01000
00632B64 E5801178
00632B68 E8BD800F
00632B6C 0068F3A8
00632B70 F64BEC60
003FAD04 EB08DF8D
RAM: 必殺技無限
0C8E3A34 00000000
初期値:003FAD04の値はE5980000で、00632B40に分岐しています。
当然ながら、分岐するためには003FAD04には00632B40への分岐値を、
00632B40には003FAD04の初期値を。
今回、r0とr1を主に使用するので、stmfd(00632B44 E92D400F)命令の拡張レジスタはr0-r3にあらかじめアウトプットさせます。
00632B48 E59F001C
00632B4C E59F101C
この二つは指定値(
00632B6C 0068F3A8
00632B70 F64BEC60
)をr0に0068F3A8を、r1にF64BEC60を代入しています。
00632B50 E5900000←これを宣言した後、00632B54 EBEC6F81(0014E960)へ分岐します。そうすることで、r0とr1の値(0068F3A8, F64BEC60)は0014E960で使われるようになります。
0014E960は必殺技のROMアドレスになります。
00632B58 E3500000
ここで、分岐先(0014E960)のr0を取得します。
よって、r0の中身は、0068F3A8ではなく0C8E38BC(New版)に更新されます。
(00632B58 E3500000
00632B5C 08BD800F) は cmpの値0とr0の値を判別し、08BD800F(ldmeqfd)によって比較され、等しい場合は、ブレークさせます。
つまり、0C8E38BC ==(eq) 0ならbreak;
ブレークせずシステムが始動続けたら、
(00632B60 E3A01000
00632B64 E5801178) r1 は 分岐先(0014E960)によってレジスタが更新されています。
しかし、更新された r1 は不要なので、E3A01000によってr1を初期化します。
E5801178で初期化したr1をメモリに置いたr0(0C8E38BC) + 178加算した場所に書き換えします。
↑の転送アドレスは、0C8E3A34(New版)。
なぜ r1 を初期化したかは、0C8E3A34の値が、1ならば必殺技無効状態、0ならば必殺技有効状態だからです。
終わりに
00632B68 E8BD800Fを置いて(アウトプットさせた拡張レジスタr0-r3をインプットさせる)プログラムは完成です。
今回の場合は、stmfd, ldmfdなので、E12FFF1E(bx lr)は不要です。
最後に
00632B70 F64BEC60はどういうこと?とは下記のアドレスを元に。
CA3B0C4 F64BEC60。
00632B54 EBEC6F81で分岐させれば、r0とr1は分岐先に転送され、システム始動時は元のr0とr1は003FAD04~では初期化されます。
ここは、多分わかりづらいと思うので興味ある方は独自で研究してみてください。
LDR と STR を超わかりやすく説明する [3DS改造解析ASM]
※Gateway条件コードを把握していることが必須です。
Gateway条件コード一覧 :
https://github.com/JourneyOver/CTRPF-AR-CHEAT-CODES/blob/master/ActionReplayCodeTypes.txt
※この記事を読む前にこちらの記事を必ずお読みください。
メモリからレジスタへ(ロード)コピー : GW条件では D9/DA/DB
STR( ストアレジスタ, 書き出し )命令とは
レジスタからメモリへ(ストア)コピー :GW条件では D6/D7/D8
32ビット, 16ビット. 8ビットのロード・ストア命令 :
32ビット = ワード(4バイト)
16ビット = ハーフワード(2byte)
8ビット = バイト(1byte)
LDR( ワード値を読み込む) / STR(ワード値を格納する)
LDRH(符号なしハーフワード値を読み込む) / STRH(符号なしハーフワード値を格納する)
LDRSH(符号付きハーフワード値を読み込む) / STRSH(符号付きハーフワード値を格納する)
LDRB(符号なしバイト値を読み込む) / STRB(符号なしバイト値を格納する)
LDRSB(符号付きバイト値を読み込む) / STRSB(符号付きバイト値を格納する)
GW条件コード の D9~DB は LDR~LDRSB を意味し、
D6~D8 は STR~STRSB を意味します。
GW条件コードで D9 ~ DB / D6 ~ D8 のコードを作るとします。
<例>
D9000000 00632FC0
D5000000 12345678
D6000000 00632FC0
D2000000 00000000
このコードの場合、00632FC0 のアドレスをロードし、データ(12345678)を追加、再び 00632FC0 のアドレスに追加したデータを格納しています。
つまり、00632FC0 の アドレスには データ(12345678)が格納されています。
ASM(アセンブラ)も上の例と全く同じです。
では、F0Fコードを使ってアセンブルしてみましょう!
F0F の使い方はこちら↓の記事をお読みください。
D3000000 00632FC0
D5000000 12345678
F0F00000 00000010
E5940000 E5961000
E5801000 E12FFF1E
<解説>
D3 = r4, D5 = r6
r0, r1 = 汎用レジスタ
F0F00000 00000010 = (16バイト : 4byte x 4 = 16(Hex:10))
E5940000 = LDR r0, [ r4 ]
E5961000 = LDR r1, [ r6 ]
E5801000 = STR r1, [ r0 ]
E12FFF1E = BX LR
LDR r0, [ r4 ] は メモリ内 の r4 を 汎用レジスタである r0 へコピーします。
これは D3 の指定アドレスを汎用レジスタへコピーする際は必ずやらなければいけません。つまり "初期化" を行います。
LDR r1, [ r6 ] は メモリ内 の r6 を 汎用レジスタである r1 へコピーします。
これも D5 の指定データを汎用レジスタへコピーする際は必ず行います。
ここまでで 汎用レジスタ内部を見ると、
r0 = 00632FC0
r1 = 12345678
汎用レジスタ内部はこのようになっています。
では、指定アドレスに追加データを格納しなければいけません。
ここで STR を使います。
STR r1, [ r0 ] は 汎用レジスタ の r1 を メモリ内[] の r0 へコピーします。
そうすることで、00632FC0 には 12345678 が格納されます。
最後にプログラム終了を宣言します。
BX LR
アセンブリ言語講座(ASM)② [3DS改造解析]
F0F条件コードを使ってアセンブルしてみよう!
初めに ASM を HEX に直したいまたは HEX を ASM に直したい場合こちらのページをご利用ください。
[ 使い方↑ ]
開いた直後、Assembly code となっているので、
HEX to ASM に直したい場合は、⇔マークをクリックし Hex code に直してください。Hex code の欄に 目的のASMコードを知りたい場合、<例> E3A00001 を入力します。自動で変換されると思うので、ARM Big Endianの欄にある ASMコードがHex code で入力した ASMです。
[ 本題 ]
F0F条件コードとは?
F0F は Gateway条件コードに組まれている自作ASMエンジンです。
F0F の 使い方をこちらの記事ではご説明しています。
下のコードを組み立ててください。
D3 に 空きアドレス を指定してください。
空きアドレスは RAM の データ0領域でも構いません。
D3000000 XXXXXXXX
F0F00000 00000014
E5940000 E5901000
E3A01001 E5801000
E12FFF1E 00000000
では指定したアドレスを確認してください。
指定したアドレスの値が 1 ならこのASMコードは成立しています。
↑ってどういう仕組みなの?
F0F の使い方でご紹介したレジスタを使って命令(処理)で演算をしています。
D3 に 指定したアドレスは r4 に入っています。
E5940000 -> LDR r0, [ r4 ]
主記憶[メモリ]を使って r4 を 汎用レジスタの r0 第一オペランド(格納レジスタ)に読み込んでいます(格納)。
つまり、 r0 は r4 の質を持っていることと同じ意味です。
更に、汎用レジスタ r1 を使わなければならないため、
E5901000 -> LDR r1, [ r0 ]
先程の r0( D3 に指定されたアドレス ) を r1( 汎用レジスタ) へ読み込みます。
これでコード式に直すことで、XXXXXXXX ZZZZZZZZ
このような形になります。
ZZZZZZZZ = r1 なので、r1 に値を何か代入したいとなった場合
E3A01001 -> MOV r1, #1
r1 ( ZZZZZZZZZ ) には #1 ( 定数1 ) をコピーします。
これで XXXXXXXX 00000001 になるのですが、r1 ( 00000001 ) はどこへ書き出すのでしょうか?書き出すアドレスを指定するため。
E5801000 -> STR r1, [ r0 ]
r1 ( 00000001 ) は、主記憶の r0 ( D3 に指定されたアドレス ) へ書き出します。
そうすることで、D3 で指定したアドレスの値 r1 ( 00000001 ) が正常に書き出されます。最後にプログラム終了をしたい場合
E12FFF1E -> BX LR
を宣言し正常にプログラムは終了しました。
アセンブリ言語講座(ASM)① [3DS改造解析]
ARMアセンブリ言語(32bit) - 3DS改造解析編①
※こちらはARMアセンブリ言語についてだがアセンブリ言語には様々な種類がありレジスタも異なる。
レジスタと主記憶装置は密接に関わっている!
CPUには制御装置、演算装置、主記憶装置、入力装置、補助記憶装置、出力装置(図1)がある!
(図1)
制御装置
演算装置
↑↓
入力装置→主記憶装置→出力装置
↑↓
補助記憶装置
アセンブラの場合は制御装置、演算装置、主記憶装置が非常に関わってくる!
レジスタとは?
CPUには、レジスタがある(記憶領域).
ARMのレジスタには r0~r12まで汎用レジスタ、
r13(sp), r14(lr), r15(pc)がある。
[ 汎用レジスタのポイント ]
演算装置で演算する場合は汎用レジスタに必ず格納してから行うこと!
主記憶(メモリ)装置とは?
主記憶には 65,536(FFFF)個の格納場所がある。
主記憶には一つ一つの番地(アドレス)がある。
[ 主記憶装置の中身 ]
--------------
番地0 | |
--------------
--------------
番地1 | |
--------------
--------------
番地2 | |
--------------
--------------
番地3 | |
-------------- ....
-----------------------------------------------
[ 命令の構成 ]
オペコード(命令)とオペランド(第一, 第二, 第三)
LDR r1, [ r0, #2 ]
↑A ↑B ↑C ↑D
A オペコード(命令(どのような処理をさせるのか?))
B 第一オペランド 汎用レジスタ(格納レジスタ)
C 第二オペランド 汎用レジスタ
D 第三オペランド 即値(定数) LDRの場合なので C, D は [メモリの内 ]
理解してみよう!(MOV編)
MOV r1, r0
r0 には 0000F61E50{ 16129616 }
r1 には 0000000E36{ 3638 }
がある!
MOV = コピーを行う処理
r0 = 汎用レジスタ
r1 = 汎用レジスタ
r0 を r1 へ コピー(MOV) すると r1 の 中身はどうなる?
[答え!]
r0 には 0000F61E50{ 16129616 }
r1 には 0000F61E50{ 16129616 }
F0F条件コードの作成について[3DS改造解析]
ASM分岐値計算装置(ルーチン作成用)
D5000001 XXXXXXXX
D5000002 YYYYYYYY
F0F00000 0000001C
E59F0010 E5962000
E5973000 E0422003
E5802000 E12FFF1E
ZZZZZZZZ 00000000
D9000000 ZZZZZZZZ
F5000000 00000004
D4000000 FFFFFFFE
D6000000 ZZZZZZZZ
D2000000 00000000
使い方 :
①XXXXXXXX には分岐先アドレスを指定してください。
②YYYYYYYY には分岐前アドレスを指定してください。
③ZZZZZZZZ には空きアドレスを指定してください。
コードを実行 :
XXXXXXXX と YYYYYYYY が減算され ÷4 された結果 -2 = 分岐値が
ZZZZZZZZ の 指定アドレス に 書き出されます。
ZZZZZZZZ を HexEditor で確認してください。
コードの仕組み :
XXXXXXXX - YYYYYYYY = Data1;
Data1 / 4 = Data2;
Data2 - 2 = Data3(分岐値)
本題に入る前に
※上記のコードを元にF0F条件コードの解説をしていきます。
※ASMの知識が少ししかない方でも簡単に作れます。
※F0F条件コードは指定レジスタで組み立てます。
※F0F条件コードで主に使う命令一覧をご紹介します。
Gateway条件コード一覧 :
https://github.com/JourneyOver/CTRPF-AR-CHEAT-CODES/blob/master/ActionReplayCodeTypes.txt
命令一覧 :
STR(ストアレジスタ, 書き出し)命令 /W, H, B
MOV(ムーヴ, コピー(代入))命令
ADD(アディション, 加算)命令
SUB(サブトラクション, 減算)命令
MUL(ムルティプリケーション, 乗算)命令
レジスタ一覧 :
r0 = 汎用レジスタ, 第一引数
r1 = 汎用レジスタ, 第二引数
r2 = 汎用レジスタ, 第三引数
r3 = 汎用レジスタ, 第四引数
r4 = オフセット#1
r5 = オフセット#2
r6 = データ#1
r7 = データ#2
r8 = ストレージ#1
r9 = ストレージ#2
r10 = 共有メモリページ(0x01E81000 - 0x01E82000)
r11 = 多分汎用レジスタ(わからない)
r12 = 多分汎用レジスタ(わからない)
r13(sp) = 利用可能な0x1000バイトのスタック
r14(lr) = コードを終了するために戻るアドレス
r15(pc) = 現在値からレジスタエリアまたは即値で分岐
F0F条件コードの作り方(上記のコードの解説)
第一 :
D5000000 XXXXXXXX = r6
D5000001 YYYYYYYY = r7
を定義します。
第二 :
F0F00000 0000UUUU
SSSSSSSS SSSSSSSSS
UUUU は コードサイズ(バイト数)を指定します。
SSSSSSSSS は ASM命令(ARM32)、ARコードに埋め込まれたASM命令を実行します。
第三 :
D9000000 ZZZZZZZZ
F5000000 00000004
D4000000 FFFFFFFE
D6000000 ZZZZZZZZ
D2000000 00000000
D9 は ZZZZZZZZ(指定アドレス) を読み込みます。
F5 は 割り算を行います( /= 4 )。
D4 は 最終結果を減算をします( -2 )。
D6 は 結果を ZZZZZZZZ(指定アドレス) に書き出します。
第二 : の F0F条件コード(上記のコード解説)
F0F00000 0000001C
E59F0010 E5962000
E5973000 E0422003
E5802000 E12FFF1E
ZZZZZZZZ 00000000
UUUU は 1C = 28サイズ です。
E59F0010 = LDR r0, [pc, + #0x10] つまりこの位置{#0x-4}から{#0x10}した位置(ZZZZZZZZの指定アドレス)に分岐されたデータを r0 へ 読み込みます。
E5962000 = LDR r2, [r6] は r6 のデータを r2 へ 読み込みます。
E5973000 = LDR r3, [r7] は r7 のデータを r3 へ 読み込みます。
E0422003 = SUB r2, r2, r3 は r2(XXXXXXXXの指定値) - r3(YYYYYYYYの指定値) の減算された結果を r2 へ格納します。
E5802000 = STR r2, [r0] は 先程減算結果を受け取った r2 を [r0(ZZZZZZZZの指定アドレス)] に 書き出します。
E12FFF1E = BX LR は プログラム終了(D2000000 00000000の役割)
ZZZZZZZZ = E59F0010 で分岐された位置に指定アドレスを入力します。
お疲れさまでした(^^♪
ASMルーチンコード作成について[3DS改造解析]
※こちらの記事ではASMルーチンコードの作成について解説していきます。
LDR = 読込命令
デスティネーションレジスタに代入する。
STR = 書出命令
STR はデスティネーションレジスタの値を
オペランドに指定されたアドレスに書き込む。
LDR/STRのバイト数リスト:
LDR 4byte / STR 4byte
LDRH 2byte / STRH 2byte
LDRB 1byte / STRB 1byte
BX = 分岐と命令セットの切り替えを行う命令
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0489ij/CIHGJAEJ.html
レジスタ(r)この記事では仮とします。
r0 = 00002FF9 r1 = 45ED55AF
r2 = 0815EEC0 r3 = 0987B700
r4 = 007816B0 r5 = 00000000
r6 = 00000000 r7 = 00000003
r8 = 00180F08 r9 = 00000001
r10 = 00AA41C8 r11 = 09879EEA
r12 = 0000188C sp = 0FFFF104
lr = 00291A58 pc = 006E1804
lr = 分岐前のアドレス[Base] 0x291A58
pc = 分岐先のアドレス[Target] 0x6E1804
lr = 00291A58 E5920678 >> LDR r0, [r2, + #0x678]
[] = メモリ
# = 即値
[r2, + #0x678] は r2[0815EEC0] の基準値アドレスから #0x678 加算したアドレスを r0[00002FF9] に読み込んでいます。
pc = 006E1804 00000000 は 空きアドレスです。
ASMルーチンコードの作成に至っては、
00291A58 から 006E1804 へ分岐を行う必要があります。
※分岐については大体リンク付き分岐命令(BL)をおすすめします。
00291A58 から 006E1804 までの分岐値[加減値]を割り出すには、
16進数の計算機[電卓]を使います。
計算方法:
1. 6E1804 - 291A58 = 44FDAC
2. 44FDAC ÷ 4 = 113F6B
3. 113F6B - 2 = 113F69
A_ 113F69
分岐値が割り出せたら、
00291A58 の E5920678 を EB113F69 >> BL 0x6E1804 に 書き換えてください。
これで分岐は完了しましたが、ここからASMを組み立てていきます。
00291A58 の E5920678 は 分岐先アドレス[006E1804] でASMを組み立てる際または、組み立てた後に必ず配置してください。※もし配置しなかった場合はクラッシュします。
組み立て:
006E1804 E5920678 >> LDR r0, [r2, + #0x678]
006E1808 E3A00001 >> MOV r0, #0x1
006E180C E5820678 >> STR r0, [r2, + #0x678]
006E1810 E12FFF1E >> BX lr
00291A58 EB113F69 >> BL 0x6E1804
r0 は 元々00002FF9 でしたが、MOV r0, #0x1 によって
r0 は 00000001 にコピーされました。
新しい r0 は、STR r0, [r2, + #0x678] によって
[r2, + #0x678] したアドレスに書き出しています。
プログラムを終了するため、今回リンク付き分岐命令によって分岐が成り立っているのでBX lr でリンクを返します。
以上で解説を終了します。
お疲れ様でした(⌒∇⌒)
ASMについて 第二編 [3DS改造解析]
※この記事を読む前に以前の記事をお読みください。
あなたに重要なメッセージ:
RAM解析ができる前提であることが、これから先ASM解析[ROM]において最も重要であることをあらかじめ宣言しておきます。
構文:
命令[オペコード] デスティネーション[格納レジスタ] 第1オペランド 第2オペランド 第三オペランド シフト 即値[#]
mov はコピー命令です。
① mov r1, r3 @ r1 << r3
② mov r1, #10 @ r1 << #10
[①]:
第二オペランドのレジスタを第一オペランドに コピー します。
[②]:
①を実行:
r1 = 000036C1
r3 = 0120CF10 : -> mov r1, r3
①の実行結果:
r1 = 0120CF10
r3 = 0120CF10