キーワード
相対アドレス
ベース
レジスタ
論理積、排他的論理和
内容
攻撃すると敵即死
獲得経験値x倍その2
名前無しキャラ以外の仲間出現(セーブ反映)
わかっている範囲のセーブアドレス、相対アドレス
いつもの様に最大値検索し特定、後はセーブデータとのアドレス差で出せば大体下のものは見つけられます
基本値は装備等での増加分を除いた値。補正値は増加分を加算した値でLvupすると再計算される
キリル
幼少:青年:相対アドレス
9DB0:2AD8:00:Exp
9DB4:2ADC:04:武器Lv
基本値
9DB8:2AE0:08:現在HP
9DBA:2AE2:0A:最大HP
9DBC:2AE4:0C:力
9DBE:2AE6:0E:技
9DC0:2AE8:10:魔
9DC2:2AEA:12:避
9DC4:2AEC:14:直防
9DC6:2AEE:16:魔防
9DC8:2AF0:18:速
9DCA:2AF2:1A:運
補正値
9DCC:2AF4:1C:最大HP
9DCE:2AF6:1E:力
9DD0:2AF8:20:技
9DD2:2AFA:22:魔
9DD4:2AFC:24:避
9DD6:2AFE:26:直防
9DD8:2B00:28:魔防
9DDA:2B02:2A:速
9DDC:2B04:2C:運
9DDE:2B06:2E:装備体
9DE0:2B08:30:装備手
9DE2:2B0A:32:装備アイテム1
9DE4:2B0C:34:装備アイテム2
〜
9DF0:2B18:40:装備アイテム8
9DF0:2B1A:42:頭装備紋章
9DF0:2B1B:43:右手装備紋章
9DF0:2B1C:44:左手装備紋章
9DF5:2B1D:45:最大MPLv1
9DF6:2B1E:46:MPLv2
9DF7:2B1F:47:MPLv3
9DF8:2B20:48:MPLv4
9DF9:2B21:49:残りMPLv1
9DFA:2B22:4A:MPLv2
9DFB:2B23:4B:MPLv3
9DFC:2B24:4C:MPLv4
9E00:2B28:50:フラグその1 +01存在,+02バトル参加,+10ツノウマ乗,+40バトル強制参加
9E01:2B29:51:フラグその2 +02死亡
9E04:2B2C:54:フラグその3 +02死亡
9E08:2B30:58:?
9E10:2B38:60:好感度?1
9E11:2B39:61:好感度?2
9E1C:2B44:6C:好感度Lv?1
9E1D:2B45:6D:好感度Lv?2
9E30:2B58:80:装備スキル1
9E31:2B59:81:装備スキル2
〜
9E37:2B5F:87:装備スキル8
9E38:2B60:88:スキルLv
〜
9E5B:2B83:AB:スキルLv
主人公の紋章回数制限フラグ除去
C61Dの最下位1ビットを排除
MP=紋章回数
攻撃すると敵即死
このソフトの処理は特徴があり、敵と味方のステータスの処理が明確に分かれています
通常の場合HPの変動等は敵と味方で共通で行われており、
addu v0,v0,v1の様になっている部分を変えると双方で効果が出てしまう為に
効果の切り換えをしなくてはなりませんが、それをする必要がないので楽です
実際にどの様になっているのかは画像を見て下さい
例の如く、残りHPlhは勝手に付けたラベルです
$002a55dcの分岐で分岐すると敵。分岐しないと味方
敵の方は"WMonster_"というラベルへの参照があり、実際にデータを変えてみると
敵だけに効果が出るのでわかります
ちなみにこの画像部分は残りHPのロード部分で、変動、ストアは別の場所となります
攻撃すると瀕死の方が変動、ストア部分なので最初はそこを0にしてみましたが
それでは変動後0になるだけで倒した事にはならないという状況になり、
無意味なので減算する部分の元の値、つまりロード部分を0にする事で一撃で倒せる様になります
もう少し基本部分からの説明
最大値の探し方
$03e7を16ビット検索又は参照箇所の検索で探し、分岐を潰していくと
$002e9e40の分岐を潰し装備を変更するとHP・力〜運が最大値になるという事がわかります
しかしこれでは不十分でLvupすると変更前の値に戻ってしまいます
これは上のリストにある様に元となるステータスに装備等での増加部分を加算した値を最大値修正している為。
(この状態でセーブしてデータを見ると$03e7が並んでいますが、その前の部分に元となる値がある事が確認できます)
Lvupしても特定の数値を維持する為にはこの元の値を変更する必要がありますが
今回は関係ないのでアドレス差を出すだけでいいです
次にsh v0, $0000(a1)の辺りを見て下さい
ベースとなるa1レジスタがaddiu a1, v0, $001cで設定されています
この$001cを相対アドレスとして考えます
そうしてセーブデータとのアドレス差で出来た結果が最初のリスト。
この部分では比較命令と1ビットシフト(+2h)の組み合わせで9種類のデータが管理されています
$001cはその9種類のデータの先頭の相対アドレスで現在HPの相対アドレスはセーブデータを見る限り$0008
大体似た様な処理は固まってあるので画像の部分付近でlhu x,$0008(y)となっている部分を探すとこちらが見つかります
$002ea07cがその味方の現在HPとなりますので、敵用を探す為にこの処理の先頭からF3を押し参照箇所へ行きます
最初の画像の$002a55ecが参照箇所となり、その前の分岐で分岐すると$002a5600の敵用の処理へのジャンプがあるので
ここを→キーで飛び見ると
この様になっているのでこのロード部分のv0を0に変えるとダメージを与えると死亡するかの判定で
すでに0になっている為一撃死させる事が出来ます
これを踏まえボタンを押している時のみ有効になる様なコードはこの様になっています
フックを掛ける場所はlhu v0, $0006(v1)の部分を潰すと、潰したロード命令を加えなければならない為
この一つ手前の処理(最初の画像)の$002a5600に掛けています。
L2を押している場合はv0=0となるようにしたかったので押している場合はv0=0で分岐、
jr raで復帰する為ロードの処理は通らないようになり、押していない場合は0以外が入るので分岐せず
ロードの処理へまわります。
$004955c2はマイナス形式のパッドアドレスですのでL2のみを押した場合$FEFFが入っています。
L2を押した場合0にするにはxori v0,v0,$FEFFを入れる。というものが思いつくかと思いますが
これでは他のボタンも同時に押していると0にはならなくなってしまう為、
andi v0,v0,$0100を使い、押していない場合にフラグかかみ合いv0=$0100になるようにしています。
押している場合は$FEFF(例え他のボタンを押していても9ビットの部分は0)と$0100(9ビットの部分が1)の
論理積ですので0になります。これが出来たコードです。
ダメージあたえると敵即死
1C9AF334 2054E75E
1C9AF338 88941AE7
1C9AF33C 2494E6A5
1C9AF340 0496E7A8
1C9AF348 0C4B8093
1C9AF350 15F6E79D
1CBDD928 0C5393A8
獲得経験値x倍その2
最大値を見つけられると比較的すぐに見付かります。
LvはExp1000毎にupする様に固定されており、セーブデータを見ると1500(10進数)だとした場合Lv2,Exp500となっています
45678だとLv46,Exp678
つまり最大のLv50,Exp999は10進数で49999になります。
後はこれを16進数の$c34fで16ビット検索し比較している所を見つけ、
必ず$c34fが入るようにしてやると経験値獲得すると最大になるコードができます。
後はその部分の処理を遡ればできます。
上のmovn s1,v1,v0のs1にv1が入るようにしてやる
$002e8590へのjalは経験値のロードでv0に経験値を入れて復帰。
比較命令はこのv0+s1で比較しているのでs1が増加分となります。
遡ると$002e843cでdaddu s1, a1, zeroとなっていてこの処理より前の
a1レジスタに増加量が入っています。
獲得時の表示は変わりませんが、x倍にするだけならここをsll s1, a1, xにするだけでもいいです。
x=1=2倍,x=2=4倍
ですが表示まで変えられる場合もある為遡れるだけ遡った方がいいです
経験値x倍その1ではLvup画面がでない為に効果がないと思われた方も結構居た模様
では続けて遡ります
処理の先頭$002e8430から参照箇所を検索する
参照箇所=$002a6174
参照箇所の処理の先頭$002a6140
この処理では
$002a6158 daddu s1, a1, zero
$002a6164 daddu a1, s1, zero
増加量=a1で$002e8430へ続く
↓
処理の先頭$002a6140から参照箇所を検索する
参照箇所=$002bb054
参照箇所の処理の先頭$002bafc8
この処理では
$002baff0 daddu s5, a1, zero
$002bb04c daddu a1, s5, zero
増加量=a1で$002a6140へ続く
↓
処理の先頭$002bafc8から参照箇所を検索する
参照箇所=$002d390cこの処理では
daddu s1, v0, zero
daddu a1, s1, zero
増加量=a1で$002bafc8へ続く
ここまで参照箇所としてヒットする場所はそれぞれ1箇所のみ
このdaddu s1, v0, zeroの
v0が増加量。遅延スロットである為手前のjal$002baf50に行くと
$002baf8c lh v0, $0106(s1)ここが大体の基礎となり、v0をロードして復帰
daddu s1, v0, zero→sll s1, v0, 1にして増加量2倍にしたものが獲得経験値x倍その1。となりますが
これでは正常にLvup画面がでない場合があるので大体の基礎のlh v0, $0106(s1)のv0を
復帰前に空きメモリへ飛ばし2倍にしています。
このロードがある処理は参照箇所が2箇所あるのでここで復帰する前に変更するとLvupが正常に表示されるようです。
名前無しキャラ以外の仲間出現(セーブ反映)
キャラの存在フラグは固まってあるか、それぞれのステータス周辺にある場合が多く、
ラプソディアはステータスに含まれていました。
見つけ方はわざと死亡させてフラグをたててやり、セーブデータで比較します。
仲間になっている場合となっていない場合で比べてもいいのですが、
このソフトは一度に数人仲間になる場合が多く相違箇所を調べるのに手間がかかる為死亡させて比較します。
死亡した場合はp$0051,p$0054それぞれに+02されると分かります。
仲間になっているかはこの辺りだと目安をつけて仲間になっている、仲間になっていないキャラとの
データを見比べていきます。
そうするとp$0050が$00E1だと仲間になっている。$00E0だと仲間になっていないという事が分かります。
ですからp$0050の最下位1ビットが存在フラグで、p$0050のロードとビット命令が
ある場所を探します。
$0050で16ビット検索をするとヒットする数が多すぎるので
ステータスはlh x, $01d4(y)でxの値が各キャラのナンバーとなり、
アドレスをずらしている。という点から$01d4を16ビット検索し、
それによる数値がベースでp$0050のロード命令を探していくと
若干手間はかかりますが見付かります。
$002ea5cc lw v0, $0050(v1)をaddiu v0,0,$00e1にしてやると仲間全員出現(セーブ未反映)ができます。
セーブに反映させるにはストアさせなければならないので空きメモリにとばすか、
フラグ追加の際の処理へ無理矢理まわすかになります。
このフラグチェックの付近を見ると下の方にorかnorでp$0050にストアさせています。
これを利用し、無理矢理フラグチェック時にフラグ追加させてやればセーブ反映となります。
やり方は復帰を潰し、必要なデータを入れるだけ。
$002ea5e0を潰し復帰させずにフラグ追加・除去処理へ続けてまわす。
addiu sp,sp,$xxxxで処理の先頭、復帰前それぞれでspの値を元に戻している為
ここの復帰を潰しても大丈夫です
正確には大丈夫とは言えませんが、フラグのチェックでの復帰後使用されるレジスタはv0で
フラグ追加・除去処理ではv0=1かv0=ffffffffで復帰します。
その為チェック時に問題が発生し、仲間が全員表示されない状態になりますが、チェック時に記録されるフラグは
下に記載した様に固定されている為、セーブ後使用をやめると一応大丈夫なのですが、
そんな中途半端な物は使いたくないという場合はこちらを使用して下さい
1C9A0328 3846E7A6
1C9A032C 1486D7C2
1C9A0330 B074E775
1C9A0334 0C4B7E92
1C9A0338 1485D7C1
1CB926F8 0C53C7A5
この様に長くなるのであの状態になりました
上のコードはこの様になっています
002ea5d0 j $000f8000
000f8000 addiu s0,0,$0001
000f8004 or v0,v0,s0
000f8008 sw v0, $0050(v1)
000f800c j $002ea5d4
000f8010 and v0,v0,s1
元に戻り復帰を潰した後
$002ea664のs2が0だとnorでフラグ除去、s2が0以外だとorでフラグ追加となるため
$002ea604をaddiu s2, zero, $0001にして追加にする。
or v0, v0, s1のv0がlw v0, $0050(a0)である為s1が追加するビットとなる
$002ea5f4をaddiu s1, zero, $0001にして最下位1ビットに設定する
これで仲間になっているかフラグをチェックする際にフラグを追加させる事ができます。
但し本来は論理積での復帰である為常に動作させる訳にはいかず、セーブ後使用を止める
という流れになります。