- 献词
- 致谢
- 前言
- 第一部分 IDA 简介
- 第 1 章 反汇编简介
- 第 2 章 逆向与反汇编工具
- 第 3 章 IDA Pro 背景知识
- 第二部分 IDA 基本用法
- 第 4 章 IDA 入门
- 第 5 章 IDA 数据显示窗口
- 第 6 章 反汇编导航
- 第 7 章 反汇编操作
- 第 8 章 数据类型与数据结构
- 第 9 章 交叉引用与绘图功能
- 第 10 章 IDA 的多种面孔
- 第三部分 IDA 高级应用
- 第 11 章 定制 IDA
- 第 12 章 使用 FLIRT 签名来识别库
- 第 13 章 扩展 IDA 的知识
- 第 14 章 修补二进制文件及其他 IDA 限制
- 第四部分 扩展 IDA 的功能
- 第 15 章 编写 IDA 脚本
- 第 16 章 IDA 软件开发工具包
- 第 17 章 IDA 插件体系结构
- 第 18 章 二进制文件与 IDA 加载器模块
- 第 19 章 IDA 处理器模块
- 第五部分 实际应用
- 第 20 章 编译器变体
- 第 21 章 模糊代码分析
- 第 22 章 漏洞分析
- 第 23 章 实用 IDA 插件
- 第六部分 IDA 调试器
- 第 24 章 IDA 调试器
- 第 25 章 反汇编器/ 调试器集成
- 第 26 章 其他调试功能
- 附录 A 使用 IDA 免费版本 5.0
- 附录 B IDC/SDK 交叉引用
7.4 基本数据转换
在了解程序行为的过程中,格式正确的数据可能和格式正确的代码一样重要。IDA 会收集不同来源的信息,并使用许多算法来决定对反汇编代码清单中的数据进行格式化的最佳方法。下面的一些例子说明了 IDA 如何选择数据格式。
通过了解寄存器的使用方式,可以推断出数据类型和大小。如果一条指令从内存加载了一个 32 位寄存器,我们可以据此推断,相关内存位置保存有一个 4 字节的数据类型(虽然我们无法判断其到底是一个 4 字节整数,还是一个 4 字节指针)。
函数原型可用于为函数参数分配数据类型。为此,IDA 维护着一个庞大的函数原型库。我们可以对传递给函数的参数进行分析,尝试将一个参数与某个内存位置关联起来。如果可以确定这种关系,就可以对相关内存位置应用一种数据类型。以一个函数为例,该函数仅有的参数是一个指向
CRITICAL_SECTION
(一种 Windows API 数据类型)的指针。如果 IDA 能够确定调用这个函数时传递的地址,它就可以将这个地址标记为CRITICAL_SECTION
对象。分析字节序列可以知道可能的数据类型。扫描二进制文件以从中查找字符串内容即是如此。如果发现较长的 ASCII 字符序列,即可认为它们属于字符数组。
在下面的几节中,我们将讨论可以对反汇编代码清单中的数据执行的一些基本转换。
7.4.1 指定数据大小
调整数据的大小是修改该数据的最简单方法。IDA 提供了许多数据大小/类型说明符。最常见的说明符包括 db
、 dw
和 dd
,分别代表 1 字节、2 字节和 4 字节数据。第一种更改数据大小的方法是使用如图 7-8 所示的 Options▶Setup Data Types(选项▶设置数据类型)对话框。
图 7-8 数据类型设置对话框
这个对话框分为两个部分。对话框的左侧是一组按钮,用于立即更改当前选中的项目的数据大小。对话框的右侧是一组复选框,用于配置 IDA 中所谓的 数据转盘 (data carousel)。值得注意的是,左侧的每一个按钮,在右侧都有一个对应的复选框。数据转盘是一个不断循环的数据类型列表,其中仅包含选中的复选框所代表的数据类型。修改数据转盘的内容并不会立即影响 IDA 的显示。而当我们右击一个数据项时,数据转盘中列出的每一种数据类型都会在上下文菜单中出现。因此,将数据重新格式化为数据转盘中的类型比格式化为数据转盘以外的类型要简单。根据图 7-8 中选择的数据类型,右击一个数据项,你可将这个数据项重新格式化为字节、字或双字数据。
数据转盘这一名称源自于相关的数据格式化热键 D 的行为。按下 D 键后,当前选中地址所在的数据项被重新格式化为数据转盘列表中的下一种数据类型。以前面包含 3 个数据项的列表为例,当前格式为 db
的项被切换为 dw
,格式为 dw
的项被切换为 dd
,格式为 dd
的项被切换为 db
,从而完成了转盘的循环过程。对一个非数据项(如代码)使用格式化热键,该项将被格式化为转盘列表中的第一种数据类型(本例中为 db
)。
切换数据类型会使数据项目变大、缩小或保持不变。如果一个项目的大小保持不变,那么,你能够观察到的唯一变化是格式化数据的方式的变化。如果你缩小某个项,例如,由 dd
(4 字节)转换成 db
(1 字节),则额外的字节(这里为 3 字节)将变成未定义字节。如果你增大某个项,且该项之后的字节为已定义字节,这时,IDA 会委婉地提醒你:是否希望取消下一个项的定义,以扩大当前的项。这时,IDA 显示的消息为:“直接转换成数据吗?”通常,这条消息表示 IDA 会取消随后足够多的项目的定义,以满足你的要求。例如,将字节数据( db
)转换为双字数据( dd
)时,还需要另外 3 字节才能构成新的数据项。
你可以对任何描述数据(包括栈变量)的位置指定数据类型和大小。要更改栈分配的变量的大小,首先双击你希望修改的变量,打开详细栈帧视图,然后修改变量的大小。
7.4.2 处理字符串
IDA 能够识别大量字符串格式。默认情况下,IDA 会搜索并格式化 C 风格、以空字符结尾的字符串。要强制将数据转换为字符串,可以通过 Edit▶Strings 菜单中的选项,选择一种字符串风格。如果当前选中地址开始部分的字节构成了一个选定风格的字符串,IDA 会将这些字节合并在一起,组成一个单字符串变量。任何时候,你都可以使用热键 A 以默认的字符串风格对当前选中的位置进行格式化。
有两个对话框可用于配置字符串数据。第一个对话框如图 7-9 所示,通过 Options▶ASCII String Style 命令即可打开该对话框,ASCII 在这里有些用词不当,因为 IDA 能够理解许多其他字符串风格。
与“数据类型配置”对话框类似,左侧的按钮用于在当前选中的位置创建一个指定风格的字符串。只有当前位置的数据符合指定的字符串格式,才能创建字符串。对于以字符结尾的字符串,可以在对话框的底部指定两个终止符。对话框右侧的单选按钮用于指定字符串热键(A)的默认字符串风格。
图 7-9 字符串数据配置
第二个用于配置字符串操作的对话框如图 7-10 所示,通过 Options▶General 可打开该对话框,再单击上面的 Strings 选项卡即可在这里配置其他与字符串有关的选项。虽然你可以使用下拉框指定默认的字符串类型,但是,这里的绝大多数选项主要与字符串数据的命名和显示有关。对话框右侧的 Name generation(名称生成)区只有在你选择了 Generation names(生成名称)选项后才会显示。如果关闭“名称生成”,则 IDA 会为字符串变量提供以 asc_
为前缀的哑名。
图 7-10 IDA 字符串选项
如果启用名称生成,Name generation 选项将控制 IDA 如何为字符串变量生成名称。如果没有选择 Generate serial names(生成序列名,默认设置),IDA 将使用指定的前缀和从字符串中提取出的字符,生成一个长度不超过当前最大名称长度的名称,下面的字符串即是一个例子:
.rdata:00402069 aThisIsACharact db 'This is a Character array',0
名称的首字母要大写,在生成名称时,任何禁止用在名称中的字符(如空格)将被省略。选择 Mark as autogenerated (标记为自动生成)选项,生成的名称(默认为深蓝色)将以一种不同于用户指定的名称(默认为蓝色)的颜色显示。Preserve case(保留大小写)强制名称在字符串中出现时使用字符,而不是把它们转换成首字母大写。最后,Generate serial names 会使 IDA 通过在名称后附加数字后缀(以数字开头),对名称进行序列化。生成的后缀中的数字由 Width 字段控制。根据图 7-10 中的配置,生成的前 3 个名称分别为 a000
、 a001
和 a002
。
7.4.3 指定数组
由高级语言生成的反汇编代码清单的一个缺点在于,它们极少提供有关数组大小方面的信息。在反汇编代码清单中,如果数组中的每一个元素都必须在它自己的反汇编行上指定,那么,指定一个数组可能需要大量空间。下面是位于已命名变量 unk_402060
之后的数据声明。其中只有第一个项被指令引用,表明它可能是某个数组中的第一个元素。通常,数组中的其他元素并不直接引用,而是需要经过更加复杂的索引计算,通过其与数组开头之间的偏移量来引用。
.rdata:00402060 unk_402060 db 0 ; DATA XREF: sub_401350+8↑o .rdata:00402060 ; sub_401350+18↑ o .rdata:00402061 db 0 .rdata:00402062 db 0 .rdata:00402063 db 0 .rdata:00402064 db 0 .rdata:00402065 db 0 .rdata:00402066 db 0 .rdata:00402067 db 0 .rdata:00402068 db 0 .rdata:00402069 db 0 .rdata:0040206A db 0
IDA 提供一些工具,可将连续的数据定义结合起来,组成一个单独的数组定义。要创建数组,首先选择数组中的第一个元素(这里我们选择的是 unk_402060
),然后通过 Edit▶Array 命令打开如图 7-11 所示的“创建数组”对话框。如果指定位置的一个数据项已经被定义,那么,当你右击该项时,上下文菜单中将显示 Array 选项。要创建的数组类型由你选择作为数组第一个元素的项的数据类型决定。在这里,我们创建了一个字节数组。
说明 在创建数组之前,请确保将数组中第一个元素的大小更改为适当的值,从而为数组的元素选择适当的大小。
图 7-11 创建数组对话框
下面是该对话框中用于创建数组的字段。
Array element Width(数组元素宽度) 。这个值表示各数组元素的大小(这里为 1 字节), 它由你在打开对话框时选择的数据值的大小决定。
Maximum possible size(最大可能大小) 。这个值由自动计算得出,它决定在遇到另一个 已定义的数据项之前,可包含在数组中的元素(不是字节)的最大数目。你可以指定一 个更大的值,但这需要随后的数据项为未定义数据项,以将它们吸收到数组中。
Number of elements (元素数量) 。你可以在这里指定数组的具体大小。数组占用的总字 节数可通过“ 元素数量×数组元素宽度 ”计算得出。
Items on a line (行中的项目) 。指定在每个反汇编行显示的元素的数量。通过它可以减 少显示数组所需的空间。
Element width(元素宽度) 。这个值仅用于格式化。当一行显示多个项目时,它控制列宽。
Use “dup” construct (使用重复结构) 。这个选项可将相同的数据值合并起来,用一个重 复说明符组合成一项。
Signed elements(有符号元素) 。表示将数据显示为有符号还是无符号的值。
Display indexes (显示索引) 。使数组索引以常规注释的形式显示。如果你需要定位大型 数组中的特定数据,可以使用这个选项。选择该选项还将启用 Indexes 单选按钮,这样就 可以选择每个索引值的显示格式。
Create as array (创建为数组) 。不选择这个选项似乎有悖于本对话框的目的,该选项默 认处于选中状态。如果你只希望指定一定数量的连续项目,而不是将它们组合成一个数 组,即可取消该选项。
接受图 7-11 中指定的选项,可以得到下面的简单数组声明,它是一个名为 byte_402060
的字节 数组( db
),由 416(1A0h)
个 0 值构成。
.rdata:00402060 byte_402060 db 1A0h dup(0) ; DATA XREF: sub_401350+8 ↑o .rdata:00402060 ; sub_401350+18↑o
这段代码唯一的作用就是将这 416 行反汇编代码合并成单独一行(主要是因为使用了重复结构)。在下一章中,我们将讨论如何在栈帧中创建数组。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论