妖怪ウォッチバスターズ 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

※この記事を読む前にこちらの記事を必ずお読みください。 

https://nightdo.hatenablog.com/entry/2020/05/31/202242?_ga=2.211086165.1562156662.1591049795-504348120.1588957124

 

 

 

LDR( ロードレジスタ, 読み込み )命令とは

メモリからレジスタへ(ロード)コピー : 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 の使い方はこちら↓の記事をお読みください。

https://nightdo.hatenablog.com/entry/2020/05/29/202009

https://nightdo.hatenablog.com/entry/2020/05/31/215051

 

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 に直したい場合こちらのページをご利用ください。

https://armconverter.com/

[ 使い方↑ ]

開いた直後、Assembly code となっているので、

HEX to ASM に直したい場合は、⇔マークをクリックし Hex code に直してください。Hex code の欄に 目的のASMコードを知りたい場合、<例> E3A00001 を入力します。自動で変換されると思うので、ARM Big Endianの欄にある ASMコードがHex code で入力した ASMです。

 

[ 本題 ]

F0F条件コードとは?

F0F は Gateway条件コードに組まれている自作ASMエンジンです。

F0F の 使い方をこちらの記事ではご説明しています。

https://nightdo.hatenablog.com/entry/2020/05/29/202009

 

下のコードを組み立ててください。

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

 

命令一覧 :

LDR(ロードレジスタ, 読み込み)命令 /W, H, B

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 = 読込命令

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 - 2113F69

A_ 113F69

 分岐値が割り出せたら、

00291A58E5920678EB113F69 >> BL 0x6E1804 に 書き換えてください。

これで分岐は完了しましたが、ここからASMを組み立てていきます。

00291A58E5920678  分岐先アドレス[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改造解析]

※この記事を読む前に以前の記事をお読みください。

 https://nightdo.hatenablog.com/entry/2020/05/25/205113

 

あなたに重要なメッセージ:

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