-
-
[原创]通过DLL注入魔改植物大战僵尸(2)——僵尸篇
-
发表于:
2020-12-19 13:11
6093
-
[原创]通过DLL注入魔改植物大战僵尸(2)——僵尸篇
上一篇文章为我们的魔改打下了基本框架,接下来我们就在这个框架上对功能进行扩展。这篇文章研究如何魔改僵尸,不要忘了我们的最终目标是仿制PVZ95版的功能噢,所以在僵尸篇我们主要打算实现下面几个功能:
通过DLL注入魔改植物大战僵尸(1)——准备工作
GitHub仓库
根据吾爱破解上一些帖子提供的思路,我通过扫描存活僵尸数量得到了两处关键指令,一处是减少存活僵尸数量,另一处是增加存活僵尸数量。显然我们要研究生成僵尸的过程,得从增加存活僵尸数量的指令着手。
IDA查看0x0041DE07处的汇编,eax看来是这一波生成僵尸的数量,然而我们发现上方的 mov eax, 1 指令已经把eax的值设为1了,动调调试也发现修改eax的值并没有什么作用。
在 retn 处下断点,动态调试查看这个函数的返回地址,意外发现PVZ在加载关卡时就触发了断点,返回地址是0x0040DE0B,猜测是预先设置好本关卡要生成的僵尸。但我们先不管这个,因为我们现在要研究的是如何在关卡中生成僵尸。
继续动调,进入关卡等待第一波僵尸生成,发现还是同一个返回地址(因为我在写文章的时候已经测试过了,函数名称是我自己改的)。
F8步过返回到上一层函数,找到了 call sub_41DDA0 指令。然而根据常识判断生成僵尸的函数总得传点比如僵尸的种类,生成的位置这样的参数吧,但是这个 sub_41DD10 函数没有传任何参数,所以猜测并不是真正的生成僵尸的函数。
所以我们继续动调找到上一层函数,发现 0x00413059 处的call指令就很符合我们的要求。push eax 和 push esi 传入了两个参数,edi估计是PVZ游戏状态对象之类的,暂时还没有深究。经过反复调试我发现第一个 push esi 传入的是生成僵尸的行数(0~4),第二个 push eax 传入的是生成僵尸的种类,。
以下是部分僵尸种类的宏定义,通过动调得到的,完整的宏定义可以去我的GitHub仓库上看:
于是我们得到了 CallZombie 函数的原型,edi 理论上也是一个参数,不过是通过eax传入的,很奇怪,不过我也没深究了:
现在我们来劫持 CallZombie 函数,改成我们自己写的函数。这一块总共有9个字节,我们传入三个参数(包括edi)总共需要3个字节,call指令需要5个字节,还是够用的。
在patch函数中写上:
注入以后原来那一块的汇编代码就变成了:
其中CallZombie是我们导出函数的地址,注意调用协定一定得是 __stdcall ,因为已经没有多余的字节给我们去还原esp了,所以栈清理工作只能交给被调用函数完成。在这个函数中我们稍微修改了一下生成僵尸函数的功能——在每一行上生成了不同种类(0~4)的僵尸,调用PVZ函数的过程中注意保持调用形式不变,其具体实现如下:
顺便附上几种不同函数调用协定的区别:
测试一下劫持效果:
真不戳!
...
void CallZombie(DWORD ztype,DWORD row);
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2021-2-9 23:36
被34r7hm4n编辑
,原因: