怪物农场2修改日志4 - 决战前夜

接上篇,怪物农场2修改日志3 - 年轮

bgm 潮与虎 第二季 ED 决战前夜

 

上篇中,我们成功找到了"种族允许生成"列表(0x97336),修改该列表可以在初期生成所有种族的怪物.

我们推测的游戏中的处理逻辑如下,

1,从CDROM中读取数据.

2,根据数据计算出要生成的怪物的ID,以及其他初始数据.

3,如果怪物的生成条件不满足,则提示玩家该怪物还无法生成.

4,播放生成怪物的动画.

5,确认玩家是否要收养怪物,如果确定,将怪物ID添加到"已收集怪物Id"列表.

 

以三色鸟为例,程序通过读取(0x97336 + 33-1 = 0x97356)这个位置,来判断三色鸟是否允许生成.

我们可以在0x97356处下个内存断点,看是否能反推出这里的种族Id 33是来自哪里.

重新读取镜像生成怪物,发现代码断在了0xd91b8.

我们从这里反推
0xd91b8 这里读取了0x97356(r2+0x15da)处的内存,触发了断点.
0xd91b4 反推可得到r5 = 0x20 对应三色鸟的种族33,可以知道这里r5保存的就是种族id,而这个种族id的数据应该是从CDROM中读取的.
再继续就不好推了.
 
我们在0xd91b8和0xd91a8处都下断点看看.发现0xd91a8不会经过.
继续单步执行,直到返回,发现0xd9c64这里跳转到了0xd914c,在0xd91b4上面一些,因此可能就是是从这里跳转过来的.我们在0xd9c64处下个断点.
 
查了下mips的文档,发现jal会跳转到指定位置,并将返回地址保存在r31.后续可以根据r31的值找到函数的返回地址.
我们跳到0xd914C处,开始单步调试.
 
可以注意到,刚进入0xd914c这个函数时,R5就已经是0x20了.调试了下,没有发现太多的线索,因此我们继续看R5的值是从哪里得到的.
我们从这个跳转,往上反推,看上一层的函数,0xd914c会返回到0xd9c6c,因此我们从0xd9c6c往上看.
 
 
在0xd9c5c处 这里发现r5是从[r4+48]得到的,r4为0x1fcb40.
但是查看[1fcb40+48]处,并不能找到线索.
我们继续看上层函数0x900EC.
 
 
我们在0x900E4处下个断点,重新读取光盘生成怪物.
发现这里的指令是跳转到r2寄存器中存储的地址,会很频繁的触发断点,这里必须要对r2做限制才行.
尝试了多次还是没办法在0x900E4处下断点,因为不知道0x900E4这里要跳转到的R2是多少,无法设置条件断点.
 
似乎方向不对,还是回到0xd9c5c这个位置,既然找到了R5的读取来源内存[1fcb40 +48],显然这个内存地址是在读取CD后,根据CD中的数据被计算出来并被写入这个地址的,R5的数据其实就来自这个内存地址.
我们尝试直接读怪物农场2的镜像,发现[1fcb40 +48]这个位置写入的值是0x19,对应编号26(0x19+1)的怪物モッチー,也就是怪物农场2自身镜像对应的怪物的种族Id.
所以前面的推理是正确的,从CDROM中的读取数据后.会将怪物的种族id,写到[1fcb40 +48]处.
 
注意这里的1fcb40是存在r4中,值是动态的,每次调试可能都不同,需要从0xd9c5c下断点获得.
先存好档,重新在0xd9c5c下断点并生成怪物,发现r4是0x1ffc50.
 
这样的话,我们只要在[0x1ffc50+48]处下个内存断点,在读取CDROM数据的时候应该会触发该断点.
 
发现在换盘并按确定的那一刻,触发了断点.此时正在将r2的值0x2020写入[0x1ffc50+48],而r2的值是从r7[0x76868]读取的.
 
简单调试了下,发现这边似乎是从CDROM读取数据后,将数据写到了[0x1ffc50+48]开始的这一片内存中.
我们之前推测是根据怪物Id,决定最后会生成的怪物的.那是否怪物Id也是在这个时候写入的?
三色鸟的Id是0x148,但是在这块内存附近找不到0x48,0x01这样的数据.
 
如果我们在读取CDROM并写入[0x1ffc50+48]后,修改存储在这里的种族Id,会发生什么?
之前就很喜欢甲虫,也很难入手,甲虫的种族Id是5,在内存中就是0x04,我们直接把[0x1ffc50+48]处的两字节改成0x04,0x04,因为甲虫初期无法生成,所以也顺便把"种族允许生成"列表+4的位置写1(0x97336+5-1 = 1).
继续执行,然后换回怪物农场2的镜像,生成怪物.
 
果然成功了.
 
但是为什么这里会有两个重复的种族Id?
突然想到,合体的怪物,确实有主种族Id和副种族Id之分.
我们可以用人马+龙的合体来试试,人马的种族Id是3,龙的种族Id是2.
按刚才的修改方式,读档触发数据断点,把[0x1ffc50+48]处修改成0x02,0x01.
把"种族允许生成"列表+3,+2的位置写1(0x97336+3-1 = 1, 0x97336+2-1 = 1).
重新生成,发现真的生成了人马+龙的合体.
 
到这一步,理论上我们可以生成所有的怪物了,除了特殊怪物.
怪物农场2中有一些特别稀有的怪物,只能通过某些特定光盘镜像生成.
比如ps游戏寄生前夜的B盘,可以生成金属液体人,就是终结者里面那个T1000,超酷的有没有.
绝对不是巧合哦,用Terminator 2 Sound Track的光盘也能生成这个怪物.
 
我们用寄生前夜的B盘生成怪物试试.
读光盘的时候又触发了内存断点.
 
可以看到,液态金属人的主种族Id是0x1C,也就是28+1,29.副种族Id是0x26,也就是38+1.
怪物农场2一共只有38个种族,看起来似乎38以外的种族Id被专门用于特殊稀有怪物.
 
我们用种族Id为8的Golem来试试吧.
[0x1ffc50+48]处写入0x07,0x26.
"种族允许生成"列表+8的位置写1(0x97336+8-1 = 1).
好吧,虽然有点怪,但是确实是稀有怪物.
 
至此,我们已经可以生成所有游戏中的怪物了,包括不可用的野外怪物也可以生成.
最初的目标已经实现了一大半.
 
接下来会尝试分析从CDROM中读取的数据,如果可能的话,再做个简单的修改器或者光盘生成器,最好是我能直接在安卓手机上使用模拟器随意生成怪物.
 

posted on 2016-08-03 01:43  gauldoth  阅读(556)  评论(0编辑  收藏  举报