跳转至

查看和导航游戏的汇编代码

你将从 OllyDbg 的反汇编窗格导航游戏代码并控制调试的大部分方面。这个窗格显示当前模块的汇编代码,其数据整齐地显示在由四个不同列组成的表格中:地址(Address)、十六进制转储(Hex dump)、反汇编(Disassembly)和注释(Comment)。

地址列显示所附加游戏进程中每个操作的内存地址。你可以双击此列中的地址,切换它是否为显示基址。当地址被设置为显示基址时,地址列会显示所有其他地址相对于它的偏移量。

十六进制转储列显示每个操作的字节码,相应地对操作码和参数进行分组。此列左侧跨多行的黑色花括号标记已知的函数边界。有跳转指向的操作会在这些花括号内侧显示一个右向

图 2-2 OllyDbg CPU 窗口

箭头。执行跳转的操作会根据跳转方向在花括号内侧显示上向或下向箭头。例如,在图 2-2 中,地址 0x779916B1 处的指令(以灰色突出显示)有一个上向箭头,表示它是向上跳转。你可以把跳转看作一种 goto 操作符。

反汇编列显示游戏执行的每个操作的汇编代码。例如,你可以通过查看汇编代码确认图 2-2 中 0x779916B1 处的指令是跳转,它显示的是 JNZ(非零则跳转)指令。此列中的黑色花括号标记循环的边界。附着在这些花括号上的右向箭头指向控制循环继续还是退出的条件语句。图 2-2 中此列的三个右向箭头指向 CMP(比较)和 TEST 指令,汇编代码用它们来比较数值。

注释列显示关于游戏执行的每个操作的可读注释。如果 OllyDbg 遇到已知的 API 函数名,它会自动插入包含函数名的注释。同样,如果它成功检测到传给函数的参数,它会为它们添加标签(例如 Arg1、Arg2、……、ArgN)。你可以双击此列添加自定义注释。此列中的黑色花括号标记假定的函数调用参数边界。

 OllyDbg 在代码分析期间推断函数边界、跳转方向、循环结构和函数参数,所以如果这些列缺少边界线或跳转箭头,只需按 ctrl-A 对二进制运行代码分析。

反汇编窗格获得焦点时,有几个热键可以用来快速导航代码和控制调试器。使用 F2 切换断点,shift-F12 放置条件断点,-(连字符)后退,+(加号)前进(这两个的操作方式和浏览器中一样),*(星号)转到 EIP(x86 架构中的执行指针),ctrl--(连字符)转到上一个函数,ctrl-+ 转到下一个函数。

反汇编器还可以用不同类型的搜索结果填充「引用」窗口。想更改「引用」窗口的内容时,右键单击反汇编窗格,鼠标悬停在「搜索」菜单上展开它,然后选择以下选项之一:

所有模块间调用(All intermodular calls):搜索对远程模块中函数的所有调用。例如,这可以让你看到游戏调用 Sleep()、PeekMessage() 或任何其他 Windows API 函数的每个地方,让你检查这些调用或在上面设置断点。所有命令(All commands):搜索给定操作的汇编形式的所有出现位置,其中添加的操作符 CONST 和 R32 分别匹配常量值或寄存器值。这个选项的一个用途是搜索 MOV[0xDEADBEEF], CONST;MOV [0xDEADBEEF], R32;和 MOV [0xDEADBEEF], [R32+CONST] 这样的命令,列出所有修改 0xDEADBEEF 地址处内存的操作——这个地址可能是任何东西,包括你玩家生命值的地址。

所有序列(All sequences):搜索给定操作序列的所有出现位置。这与前面的选项类似,但它允许你指定多个命令。

所有常量(All constants):搜索给定十六进制常量的所有实例。例如,如果你输入角色生命值的地址,它会列出所有直接访问它的命令。

所有开关(All switches):搜索所有 switch-case 块。

所有引用的文本字符串(All referenced text strings):搜索代码中引用的所有字符串。你可以用这个选项搜索所有引用的字符串,看看哪些代码访问它们,这对于把游戏内文本显示与显示它们的代码关联起来很有用。这个选项对于定位任何调试断言或日志字符串也非常有用,可以极大地帮助确定代码部分的目的。

反汇编器还可以用当前模块中的所有标签(ctrl-N)或所有模块中的所有已知标签(搜索 → 名称 → 所有模块中的名称)填充「名称」窗口。已知的 API 函数会用它们的名称标记,你可以通过突出显示命令、按 shift-; 并在提示时输入标签来添加标签。当代码中引用带标签的命令时,会显示标签而不是地址。使用这个功能的一个方法是给你分析过的函数命名(只需在函数的第一个命令上设置标签),这样当其他函数调用它们时就能看到它们的名称。