1.常量值修改
1.1修改阳光
直接通过搜索精确值找到阳光的地址,直接修改数值可以看到修改成功
2.函数值调用
2.1 找到种植函数
查找谁在修改阳光值然后种植向日葵得到汇编代码,蓝色行里的是改写代码,红色框整个函数的内容,分析寄存器数据得知eax是玩家阳光值,ebx是种植植物需要消耗的阳光值
2.2 获取植物花费函数
在调用该函数的时候,ebx里就已经存了向日葵的费用,说明向日葵的费用一定是在这个函数之前就已经得到了,所以我们还得返回到调用它的函数里去分析一下。通过返回地址我们知道调用地址是PlantsVsZombies.exe+10876
红色1表示调用种植函数的地方,红色2和红色3表示能修改eax和ebx值的地方,红色行表示断点,蓝色行表示程序准备运行的代码行。
当代码准备运行蓝色行时eax=ebx=0,而在红色1的时候ebx=豌豆费用,所以猜测蓝色行调用的函数能获取到豌豆的费用并保存到eax中,再由下一行语句mov ebx,eax
,把eax中的值保存到ebx中。
我们只关注eax值什么时候等于64即可(因为十六进制的64=十进制的100)
步入,然后再进入第一个call
步入,一直执行到蓝色处未发现eax变化
一个大跳转,然后继续执行发现eax的值变成了16进制的64,即我们可以知道就是红框的两句起到作用,由于执行前eax=0,所以我们可以猜测PlantsVsZombies.exe+29F2C0 的数据就是豌豆射手的花费。
3.分析数据结构
3.1 简单介绍
如果有一丢丢游戏开发的经验,应该能知道游戏开发者会把所有的植物放到一个表中进行储存,而每个植物自己的属性又是一个小表。我用lua来简单举例
plant =
{
enemy1 =
{
health = 100,
speed =50
},
enemy2 =
{
health = 200,
speed =70
}
}
这样做的目的是为了更好的进行数据管理,和进行对象遍历。而这对我们的游戏逆向有什么启发呢?
如果我们得到了enemy1的health值存放的地址a,那我们找a的后四个字节地址不就找到了enemy的speed的值吗,再往后找4个字节不就找到了enemy2的health值吗,这些数据就会躺的整整齐齐的任你挑选。
3.2 结构分析
所以这里我们对PlantsVsZombies.exe+29F2C0 进行结构分析
显然数据排列的井然有序,为了更加直观的感受,我把PlantsVsZombies.exe+29F2C0 改成了PlantsVsZombies.exe+29F2BC,不然看不到图里的第一行的数据0,起始就是植物的编号。
3.3 数据比对
到了此处我并不知道是否正确,我也得去验证一下,所以我去网上搜了一下植物图鉴。
重新更新了一下数据结构