bgm,最近血洗B站的极乐净土
上篇中,我们成功的找到了从光盘中读取的数据得到的怪物种族Id和副种族Id在内存中存储的位置.
通过修改该内存位置,可以直接决定最后生成的怪物,包括特殊怪物都能直接生成.
接下来我们会看下这些数据是如何通过CDROM中读取的数据计算得到的,顺便会挖掘下其他受CDROM影响的初始怪物数据.
通过查询外文攻略站得到如下信息.
- CD中最后一条音轨的分钟数决定了怪物的主种族Id.
- CD中除去最后一条音轨,剩余的总时间的秒数部分,决定了怪物的副种族Id.
- 根据CD中第一条音轨的秒数部分对怪物属性进行修正.
- 根据CD中全部音轨的秒数部分对怪物属性进行再次修正.
- 特殊怪物的主种族Id和副种族Id似乎是根据数据硬编码得到的,不使用通用的规则.
可以推测出,从CD中读取的信息应该是这些.
我们仍然先使用寄生前夜2的B盘来做测试,外站上看到这个盘的音轨数据如下,
0+3667秒(全部音轨长度61:07、最后一条音轨长度61:07)
继续调试看看,仍然在0x001ffc98处下个数据写入断点,看看数据是如何从CD到这个内存位置的.发现断在了如下位置,
从调用栈可以看到上层函数是0xd9a04,我们执行到返回看看.
可以看到这里会一直拷数据,将0x76868(r6)到0x76888(r9)拷贝到0x1ffc98开始的内存.
之后函数就返回到了上层.
可以看到上面有句jal 0xda0a4,因此返回前的那个函数的入口地址是0xda0a4.
我们在0xda0a4下个断点,重新调试看看具体做了哪些事情.
可以看到我们成功来到了这个函数的入口处.
首先addiu r29,r29,0xffb0,这里把r29的值减少了0x50,查了下资料发现r29是stack pointer,这里开辟了0x50的栈空间,从0x76858到0x768a8.
sw r17,0x44(r29) 这里把0x1ffe70存到了r29+0x44处.
sw r31,0x48(r29) 这里把返回地址保存到了r29+0x48处.
sw r16,0x40(r29) 这里把0x1ffd30保存到了r29+0x40处.
lbu r2,0x48(r17) 这里读取0x1ffe70+0x48=0x1ffeb8
beq r2,r0,0xda120 这里r2为0,跳转到0xda120.之后发现,如果生成时直接使用怪物农场2的盘,则这里r2为1,不会跳转
0xda120处直接跳到了0x34228
0x34228入口处,这里分配了0x20的栈空间.
sw r17,0x0014(r29) 将0x1ffe70存到栈上+0x14的地址.
r4 = 64
r5 = 4
之后将r31存到r29+14处,跳到0x3cf08
0x3cf08中暂时不容易看出太多信息,我们回到上一层继续执行.
从0x34264开始似乎在把0x1fcdd0处的数据搬到0x76890,继续执行看看.
这个时间点,从0x34228返回,由于r2为0,将跳转到0xda188.可以看到0x76890处的内存此时为0x61,0x09.
来到0xda188处.
r2 = r5 = r7 = 0x800c0000 r6 = 0x800c646c r16 = 0
接下来又做了一些意义不明的赋值.
r10 = 2 r9 = 0x76888 r4 = 0x800c6472 r2 = [0x800c6468] = 0x100
如果r16大于等于r2,则跳转到0xda2b8.否则继续执行,r3为之前保存的0x61,这个0x61看起来很像前面提到的61分钟.
直接改r3的值试了下,确实能改变怪物的种族,数值也会和外网攻略站上的一样,只是这边不知道为什么把61分钟存成了0x61.
r2,r3不相等,则会跳转到0xda2a8
这里将r4和r6增加8,又跳回0xda1a8处.此外跳转下面一条语句也会执行,所以r16每次会自增1.
再调试下,发现这里这个循环,是从1到100,根据从CD中读取的那些数据查找匹配的项.然后根据项中记录的某个整数作为偏移查找到指定的数据.
通过调试发现最终是从0xc80fc拷的数据到0x76868附近的内存,0xc80fc这里的数据是静态的,似乎记录了所有可能生成的怪物的数据,每段数据的长度是0x28,怪物属性也可以在这段数据中找到.
我们用怪物农场2的盘做实验看看现象,
使用怪物农场2的盘后发现,这里r2为1,不会跳转,所以这时的流程和读CD中的数据来生成怪物是完全不一样的.
调试发现这里检测到是怪物农场2的盘,就直接硬编码生成了种族Id为19的モッチー.
这边在0xda0ec处,我们patch这里的代码,直接改成addiu r2,r0,0x261C,就能生成前面的那只特殊的液体终结者了,其中0x26和0x1C对应了液体终结者的副种族Id和主种族Id.
简单做了个金手指用于测试,只要修改#Summon Specified Monster的前两行,不用换盘就能任意生成所有的怪物,包括野外训练中遇到的怪物.(大成功?)
#Summon Specified Monster
300DA0EC 0011
300DA0ED 0027
300DA0EE 0002
300DA0EF 0024
#Undo Summon Specified Monster
300DA0EC 0000
300DA0ED 0000
300DA0EE 00E2
300DA0EF 008C
但是这个方式并不能保证生成的怪物的数据正确,而且是直接patch代码,首先不确定这个地址是不是每次都一样,也很难保证不会有其他问题.
接下来,准备仔细的再分析下这边的几个函数,尝试找到更好的修改点,或者制作修改器.
To be continued...