逆向之植物大战僵尸(一)

植物大战僵尸是一款很适合逆向入门的游戏,而设计的辅助主要实现了下面几个功能:
1. 无限阳光和无限金币
2. 取消植物放置的CD
3. 同一个位置可以重复放置植物

无限阳光

静态基址与动态地址

  1. 静态基址:是指静态基址中的内容,不会因程序的重新启动而改变,只有在程序重新编译后才会变动

  2. 动态地址:是指地址中的内容,会因程序的重新启动而变动的地址,也就是说,当前状态下,地址中保存的信息是我们所需的信息,但程序重新启动后,该地址中的内容就不再是我们所需的信息了

寻找阳光动态地址

  1. 首先通过CE附加植物大战僵尸进程,因为阳光是一个精确的数值50,所以可以选择exact value来进行搜索,首次搜索会得到很多相关的结果
1
  1. 收集一个阳光后,改变数值为75并再次搜索,此时搜索到唯一的一个结果

为了验证这个结果是否正确,我们可以手动修改地址中的数值

如何判断这个地址是否是静态基址,若CE标识的地址为绿色,则该地址为静态基址,而此处的地址并不是绿色的,所以这是个动态地址,因此我们需要寻找基址

寻找基址

  1. 我们已经找到了阳光的动态地址,那么如何寻找基址,思路是,阳光每次变动就意味着一定有一条指令修改了这个地址中的值,那么我们可以下一个内存写入断点,看看哪条指令写入了这个地址,所以我们再CE中选中这个地址,右键找到find out what writes to this address

之后我们收集一个阳光,发现得到了一条指令,我们双击打开

此时我们可以知道,ecx的值0x19,也就是25,写入了阳光地址标识的内存中,因此阳光的地址 = eax + 0x5560,该地址内存放了当前阳光的具体数值,其中eax = 0x17326B58,而0x5560为偏移地址

  1. 此时我们猜想,内存中有没有一个位置存放了0x17326B58这个值,因此我们可以使用CE,并以16进制搜索0x17326B58,发现很多搜索结果,首先可以排除地址在0x00400000以下的内容,这部分是不进行映射的,以便捕获异常的空指针引用,因此我们找到第一个大于0x00400000的地址,这个值通常是我们需要的,即0x0290A938

此时我们可以知道0x0290A938这个地址内保存了0x17326B58这个值,但是0x0290A938这个地址仍是个动态地址,所以我们还需要进一步寻找基址

此时我们用CE下个内存访问断点,查看哪条指令访问了0x0290A938这个地址内的值,可以看到4个结果,我们点进第一个指令发现0x0290A938 = edi + 0x768,其中edi = 0290A1D0,0x768也是偏移地址

那么同理我们可以看看内存中哪里存放了0290A1D0,得到如下结果

这时我们看到几个绿色的地址,这就代表这些地址就是静态基址,我们选择第一个,可以看到其地址为0x6A9EC0,这就是我们需要的静态基址,那么如何通过静态基址找到最后的阳光地址呢

  1. 现在梳理一下这个过程
    • 阳光的动态地址 = 0x17326B58 + 0x5560,而0x17326B58存在地址为0x0290A938的内存中,即[0x0290A938] = 0x17326B58
    • 地址0x0290A938 = 0290A1D0 + 0x768,而0290A1D0存在地址为静态基址为0x6A9EC0的内存中,即[0x6A9EC0] = 0x0290A1D0
    • 所以我们可以得到,阳光地址 = [[0x6A9EC0] + 0x768] + 0x5560

之后我们在CE中验证我们的结果,选择add address manually

之后选择Point,因为此处包含两个偏移地址,因此再点击add offset,然后填入我们找到的基址与偏移地址

最终我们可以看到,这个地址内,存的就是当前阳光的数值,修改后,游戏内的阳光也随之改变,且重启游戏后,该地址仍然存的是阳光的数值

实现无限阳光的功能

的到进程空间中阳光的地址,并向阳光地址处写入所需阳光数,即可实现无限阳光的功能,具体实现细节就不做赘述,给出核心代码

1
2
3
4
5
6
7
8
// 将寻找地址功能封装成GetThirdLevelAddress()函数,方便后续寻找金币地址
DWORD sunAddress = GetThirdLevelAddress()

// 自定义阳光数量
DWORD dwSun = 9999;

//写入
WriteProcessMemory(hProcess, (LPVOID)sunAddress, (LPCVOID)&dwSun, sizeof(DWORD), &pid)

金币地址的寻找大同小异,这里也不再赘述,这样我们就完成了无限阳光与无限金币的功能