建议食用前先熟悉CE基本操作
游戏版本Plants_Vs_Zombies_V1.0.0.1051_EN
0.找到PVZ进程这一步是之后对内存操作的基础
导入windows.h头文件, 我们就可以使用winAPI,于是我们可以根据窗口标题找到游戏进程。
使用winAPI FindWindow, 下方代码展现了他的一种用法
2.找到PVZ进程ID(DWORD类型)DWORD即无符号int
使用API GetWindowThreadProcessId
使用API OpenProcess
HANDLE CatchPvzProcessByTitle(LPCTSTR ProcessTitleName){
HWND hwnd = FindWindow(NULL, ProcessTitleName);
DWORD processID = 0;
HANDLE PVZprocess = NULL;
GetWindowThreadProcessId(hwnd, &processID);
if(!processID) return NULL;
PVZprocess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,processID);
return PVZprocess;
}
1.修改阳光
1.找地址
使用CE精确数值搜索,可以轻易确定阳光地址
1.5 好的我们来寻找基址, 找基址的方法是直接莽(因为真不会找), 然后就找到了!
找到阳光的基址和偏移, 发现是
[
[
[
p
o
p
c
a
p
g
a
m
e
1.
e
x
e
+
2
A
9
E
C
0
]
+
768
]
+
5560
]
[[[popcapgame1.exe+2A9EC0] + 768] + 5560]
[[[popcapgame1.exe+2A9EC0]+768]+5560]
而pvz起始申请的地址固定是0x400000, 所以起始地址是62A9EC0
我们可以调用两个winAPI来读写内存: 这里意识流地介绍一点用法, 具体建议自己去查,因为作者也不会
WriteProcessMemory ReadProcessMemory 参数: (pvz进程句柄,地址,新值/读取值保存地址,数据大小,NULL) 返回值: bool类型, 读写失败会返回0
先读地址,确定目标地址是否可以访问, 若成功读取,则修改之。
(如果在选择游戏模式界面, 显然不能修改阳光值, 或者你的地址写错了,也无法修改,所以要先读,如果读取能成功,可以排除一部分问题)
若正确开始了一句游戏,找到了正确的阳光基址以及偏移量,正确调用修改内存的函数,便可以成功修改阳光数值。
2. 卡片无冷却 一些探索 1.刚开始根据网上搜索的思路,以1字节为单位搜索,可以找到卡片是否在冷却的标志位,1代表准备就绪,0代表正在冷却。
2.当你点击卡片,卡片就会变暗,这说明你点击卡片的同时,游戏修改了标志位的数值。
3.生成反汇编代码,把mov [标志位地址], 00 的改为 01,这样点击卡片时,即标志位数值不变,即可让卡片无冷却。
但这样会遇到一些问题, 这种操作只是“不让卡片从就绪状态进入冷却状态”, 如果你先使用卡片,在卡片冷却是修改代码,正在冷却的卡片是不会立刻准备就绪的。
遇到了另一个问题,在寻找基址的过程中,有一个中间步骤为[edi + 24], 但查找edi的值时无匹配项, 寻找基址无果。好在后来通过一个等价地址[eax + ecx + 70]寻得,至于为何用到了两个寄存器做偏移, 当时未知, 之后探索出来了。
5.后来经过玄学+盯代码+猜+不严谨证明,习得了部分卡槽机制。
- 每个卡槽都有一个“已经冷却了多长时间”的计时(即反汇编代码中的[edi + 24]), 这个计时会从冷却开始时增加。
- 每个卡槽都会根据所选植物不同有一个冷却时长(即反汇编代码中的[edi + 28]),当卡槽冷却计时达到了这个冷却时长,则冷却计时置0, 卡片进入就绪状态。
- 相邻卡槽冷却标志位地址做差,可以得到80(0x50), 相邻卡槽冷却计时的地址做差,可以得到80(0x50), 且对于同一卡槽,其冷却计时地址相对其冷却标志位地址的偏移为-36
. - 可以推测出,储存卡槽信息的是一系列连续的结构体,每个结构体占用0x50Byte的空间, 而经验证,双偏移中的[eax + ecx + 70]eax是50的倍数,即使第几个卡槽,可以直接通过ecx找到基址
找到了许多种,但未能深入理解代码
在反汇编代码中, 冷却计时每次加1,通过不断的类似这样的循环,实现冷却恢复。只要冷却计时小于等于(jle)目标时间,循环就继续,游戏中的卡片冷却进度条也不断刷新。
1. 修改反汇编代码,固定地址0x487290处3个字节冷却计时+1
mov, eax , 冷却计时
cmp eax,目标时间
把eax sub成0
每次冷却计时+1, 把对应mov [xxx] 01改为 00,即冷却计时一直是0,可以实现卡片无冷却(貌似计时置0后循环就会跳出)。
2. 修改反汇编代码,固定地址0x487296处1个字节把jle 改成ja(判大于), 直接结束循环,之后卡片冷却标志位置1,实现无冷却
3.修改反汇编代码以及内存数据先修改“使得卡片标志位变为00”的mov代码为01,使卡片不会从就绪状态进入冷却状态,然后通过时间计数+固定偏移36(0x28)修改所有卡槽的标志位为01,令正在冷却中的卡片刷新。
没用的东西作者在CE中使用了这三种方法,但只选择方法2进行了代码实现
3.阳光自动收集 0.进行4Byte搜索, 阳光会有一个标志判断是否被点击, 没点击时为0, 点击后为1。(不过点了阳光马上暂停好像找不出来,需要等一会)。
1.找到阳光是否被点击的标志位后, 查看“什么访问了这个地址”, 发现一些有趣的数据,(节选):
若干个(cmp byte ptr [ebx+50],00 出现次数:非常非常多次)
cmp byte ptr [ebx+50],00 出现次数:x (后跟jne)
mov byte ptr [ebp+50],01 出现次数:x
其中下方两行,每点击一次阳光,出现次数都加一。猜测时点击阳光时先判断阳光点击标志位是否=1(等价于标志位是否!=0),如果不为0,则跳转, 否则进行第三行操作把标志位置1。
2.然后联想到还有很多个出现非常多次的“cmp byte ptr [ebx+50],00”, 说明游戏会经常检验阳光是否被点击, 那么猜想,检测到阳光被点击后,游戏应该会进行收集操作,很可能有一个cmp后会跟收集阳光操作。
于是把其中一个“cmp byte ptr [ebx+50],00”后面的jne改为je(由if 标志位!=0-阳光被点击则跳转到收集操作 改为 if 标志位==0-阳光不被点击则跳转到收集操作), 或者改成jmp也行
所以, 只要把popcapgame1.exe+3158F位置的jne改为je,即可实现阳光的自动收集



