4、指针与地址:什么是指针、指针扫描的原理、多级指针的追踪、使用 Cheat Engine 的指针扫描功能
好,咱们今天聊指针。这东西在逆向工程里,可以说是「绕不开的坎」。我刚开始学的时候,也被它绕得晕头转向。但说白了,指针就是个「指向地址的地址」。你想想看,游戏里的血量、金币这些数据,它们不会永远待在同一个地方。每次重启游戏,它们的地址都会变。那怎么才能稳定地找到它们?答案就是——指针。
什么是指针?
指针,简单理解就是「存放地址的变量」。普通变量存的是值,比如血量是100。指针变量存的是地址,比如「血量这个值,在内存的0x12345678位置」。嗯,就这么简单。
举个例子:
// 普通变量
int health = 100; // health 的值是 100
// 指针变量
int* ptr = &health; // ptr 的值是 health 的地址
在 Cheat Engine 里,你搜到一个血量的地址,比如 0x017E4A20。下次重启游戏,这个地址就变了。但如果你能找到「指向这个地址的指针」,那这个指针的地址往往是固定的。这就是我们说的「基址」。
指针扫描的原理
你可能会问:「那我怎么知道哪个地址是指向血量的指针?」手动找?太慢了。Cheat Engine 提供了一个自动化的工具——指针扫描。
它的原理其实不复杂:
- 你先找到血量的动态地址(比如
0x017E4A20)。 - 然后扫描整个内存,找出所有「指向这个地址的地址」。
- 这些地址就是潜在的指针。
- 再结合偏移量,就能找到稳定的基址。
我当年第一次用这个功能时,扫描出来几千个结果,直接懵了。后来才明白,需要配合「多级指针」来缩小范围。
多级指针的追踪
什么叫多级指针?说白了就是「指针套指针」。比如:
基址 → 指针1 → 指针2 → 指针3 → 血量
每一级都有一个偏移量。你从基址出发,加上偏移,得到下一级指针的地址。再解引用,得到下一级指针的值。重复这个过程,直到拿到真正的数据。
举个例子,我在逆向一个老游戏时,遇到过这样的结构:
[[[0x00400000 + 0x1C] + 0x24] + 0x30] + 0x0C = 血量
翻译成人话就是:
- 从基址
0x00400000出发,加上偏移0x1C,得到一个地址。 - 读取这个地址的值(这是一个指针),加上偏移
0x24,得到下一个地址。 - 重复,直到最后加上
0x0C,就是血量。
嗯,看着复杂,但用 Cheat Engine 的「指针扫描」功能,它会自动帮你生成这个路径。
使用 Cheat Engine 的指针扫描功能
好,咱们来实战。假设你已经找到了血量的动态地址。接下来:
- 右键这个地址,选择「找出是什么改写了这个地址」。
- 回到游戏,让血量变化。Cheat Engine 会记录下修改血量的代码。
- 查看这条代码,它通常会显示类似
mov [eax+0x0C], edx这样的指令。 - 这里的
eax就是指针,0x0C就是偏移。
然后,你再用「指针扫描」功能:
- 点击「指针扫描」按钮。
- 输入血量的动态地址。
- 设置扫描深度(我一般设3-4级)。
- 点击扫描,等结果出来。
扫描结果里,你会看到很多路径。怎么选?我个人的习惯是:
- 优先选「基址」是绿色或黑色的(表示是模块地址,比较稳定)。
- 路径长度越短越好。
- 偏移量是整数,不要有奇怪的浮点数。
我曾经在一个网游里,扫描出来一条路径:[[[client.dll+0x1A2B3C] + 0x10] + 0x24]。这个路径用了整整两年都没失效。嗯,这就是好指针。
知识体系图
下面这张图,帮你理清指针相关的核心逻辑:
总结
指针这东西,说白了就是「找地址的地址」。你只要记住:
- 指针存的是地址,不是值。
- 多级指针就是一层层解引用。
- Cheat Engine 的指针扫描能帮你自动找路径。
- 选路径时,优先选模块基址、短路径、整数偏移。
嗯,掌握了这些,你就能稳定地定位游戏里的数据了。下次游戏更新,也不用从头再搜一遍。