用 OllyDbg 找到玩家的生命值¶
本节我会带你走一遍如何追踪 health 结构,但我也在本书资源文件中包含了我要分析的二进制程序。想跟着做并动手练习,请使用 Chapter5_AdvancedMemoryForensics_Scanning.exe 文件。
首先,打开 OllyDbg 并附加到可执行文件。然后,打开 OllyDbg 的「可执行模块」窗口,双击主模块;我的示例中,主模块是模块窗口中唯一的 .exe。
CPU 窗口应该会弹出。现在,在反汇编窗格中右键单击,选择「搜索 → 所有引用的文本字符串」。这应该会打开「引用」窗口,如图 5-1 所示。
远不止四个。
从这个窗口右键单击,选择「搜索文本」。会出现一个搜索对话框。输入你要找的字符串,如图 5-2 所示,并通过禁用「区分大小写」和启用「整个作用域」让搜索尽可能宽泛。
点击「确定」执行搜索。「引用」窗口重新获得焦点,第一个匹配项被高亮。双击匹配项,在 CPU 窗口中查看使用该字


符串的汇编代码。反汇编窗格聚焦到 0x401030 处的代码行,它把格式字符串参数压入 printString()。你可以在图 5-3 中看到这一行,我高亮了整个函数调用块。
通过阅读汇编代码,你可以非常准确地理解游戏到底在做什么。左侧的黑色括号显示字符串 Health 在函数调用内部。注意该函数的参数。按顺序,它们是 EAX①、ECX②和 0x4020D0③处的格式字符串。EAX 是 0x40301C 处的值,ECX 是 0x403018 处的值,格式字符串包含 Health。由于字符串包含两个格式占位符,你可以假设其余两个参数就是这些占位符的参数。
知道参数是什么,并且它们按相反顺序压入,你可以倒推出原始代码看起来像清单 5-2。
int currentHealth; // 0x403018 处的值
int maxHealth; // 0x40301C 处的值
--snip--
someFunction("Health: %d of %d\n",
currentHealth, maxHealth);
清单 5-2:游戏黑客可能如何解读图 5-3 编译成的汇编
存储在 EAX 和 ECX 中的值在内存中相邻,这意味着它们可能是结构的一部分。但为了简单起见,这个示例只把它们显示为变量定义。无论如何,这就是用来显示玩家生命值的两个数字。因为这两个重要值都显示在游戏 UI 中,所以很容易对显示它们的底层代码做出假设。当你知道一块数据的用途时,你可以快速找到负责实现它的代码;在这种情况下,这些知识帮助我们快速找到了两个地址。

在许多情况下,找到地址可以这么容易,但有些数据的用途非常复杂,更难猜出要找什么。例如,弄清楚如何在 OllyDbg 中搜索地图数据或角色位置可能相当棘手。
字符串远不是唯一可以用来在游戏中找到要修改数据的标记,但它们绝对是最容易教授、又不需要刻意举例的。此外,一些游戏在代码中嵌入了日志或错误字符串,在 OllyDbg 的「引用的文本字符串」窗口中翻一翻,可以快速确定这些字符串是否存在。如果你熟悉游戏的日志习惯,就能更容易地找到值。