up:: Programming
レジスタとメモリを直接操る言語。
PowerPC Assemblyを見た感想なので、間違ってるかも。
How to Make your own Cheat Codes
Assembly Tutorial
Basic ASM Code Debugging and Analysis for the Beginner Coder
.loc_0x0:
b -0x2EC34
stw r3, 0xB0(r30)
lbz r4, 0x28(r1)
mulli r4, r4, 0x4
lis r5, 0x8000
ori r5, r5, 0x2F00
lwzx r27, r5, r4
cmpwi r27, 0
beq- .loc_0x44
li r3, 0x80
stb r3, 0x2A(r1)
.loc_0x2C:
addi r3, r1, 0x24
bl 0x65E30
stw r3, 0xB4(r30)
subi r27, r27, 0x1
cmpwi r27, 0
bgt+ .loc_0x2C
.loc_0x44:
b 0x2EBF8
このコードはPowerPCアセンブリ言語で書かれており、主にループ処理を行うプログラムです。以下、各部分を詳しく解説します:
初期設定部分
.loc_0x0:
b -0x2EC34 ; 別の場所へ分岐(おそらく初期化処理)
stw r3, 0xB0(r30) ; r3の値をr30+0xB0のメモリ位置に保存
配列アクセスとループカウンタ設定
lbz r4, 0x28(r1) ; r1+0x28から1バイト読み込み(配列インデックス)
mulli r4, r4, 0x4 ; r4を4倍(4バイト単位でのアクセス)
lis r5, 0x8000 ; r5の上位16ビットに0x8000を設定
ori r5, r5, 0x2F00 ; r5に0x2F00をOR(結果:0x80002F00)
lwzx r27, r5, r4 ; 配列[r5+r4]からループカウンタをr27に読み込み
ループ条件チェック
cmpwi r27, 0 ; r27と0を比較
beq- .loc_0x44 ; r27が0なら終了処理へジャンプ
li r3, 0x80 ; r3に0x80を設定
stb r3, 0x2A(r1) ; r1+0x2Aに0x80を1バイト保存
メインループ処理
.loc_0x2C:
addi r3, r1, 0x24 ; r3 = r1 + 0x24(引数設定)
bl 0x65E30 ; 関数呼び出し
stw r3, 0xB4(r30) ; 戻り値をr30+0xB4に保存
subi r27, r27, 0x1 ; ループカウンタを1減算
cmpwi r27, 0 ; カウンタと0を比較
bgt+ .loc_0x2C ; カウンタ>0なら.loc_0x2Cへ戻る
終了処理
.loc_0x44:
b 0x2EBF8 ; 終了処理へジャンプ
処理の概要
- メモリアドレス0x80002F00を基準とした配列から、インデックスに基づいてループ回数を取得
- 取得した回数分だけループを実行
- ループ内では関数(0x65E30)を呼び出し、その結果を保存
- カウンタが0になるまで繰り返し
- 最終的に終了処理へ移行
このようなパターンは、ゲームやシステムプログラムでよく見られる、配列データに基づいた反復処理の実装です。
この関数そのものをクローンキャラクターの数分繰り返している。
で、キャラクターの読み込み回数を0x80002F00から4バイト分で抜いてる。
実際にクローンするコードの一例が04002F04 00000001
。これは2人分。
さて、それはともかく読み込んだキャラクターのデータを何処に保存してるの問題。
li r3, 0x80
stb r3, 0x2A(r1)
.loc_0x2C:
addi r3, r1, 0x24
bl 0x65E30
stw r3, 0xB4(r30)
この辺。ループカウンタが無いならbeq-によりb 0x2EBF8まで飛ばすので。
load immediate。r3に0x80を登録。addi r3, r0, 0x80
(r0は常に0)の省略形。
store byte。r3のうち下位8ビット、つまり1バイトをr1+0x2Aに登録。r1は事前に出て来てない。
add immediate。r3にr1+0x24を登録。
branch and link。まず用語。Program Counter(PC)は現在実行中の命令のアドレス。Link Register(LR)は戻りアドレス。ここでPC+0x04をLRに保存しとけば、現在の次のアドレスからすぐ始められる。それからPCに任意のアドレスを打ち込めばジャンプが実現できる。つまりこれは次アドレスをLRに保存しつつ0x65E30をPCに打ち込みジャンプするための命令。ちなみに32MB±がジャンプ限界。
store word。r3のうち32ビット、つまり1ワード(4バイト)をr30+0xB4に登録。今回のasmは0x00000000からも分かるように、1ワードとはつまり全部を指す。
キャラクターのデータ長はE90(海外版02)程度。
最初2行が別々なのは仕様。全部32ビットで命令長を統一するため。他にもいろいろあるらしい。
怪しいのはr1, 0x65E30, r30。r3は完全に入れ物なので違いそう。
beq-まではクローン分含めた全てのキャラクター分読み込まれる。
なのでこの間で新しいキャラクター分のデータを用意してるはず。
80031b4c
parcent書き込み
8008904c
800894c4
800893fc
sp
804ec8d8
804EC902
r30
80451f50
80452004
ピチューを使ってもクローンHP値を特定できない。
たまに正しい値があるということは、絶対どこかに確保してるのは間違いないのに。取る順も変わらない。
完全に乱数制御して同じ値を取るしかなさそう。
65E30自体は全てのキャラクターが通る。