返回介绍

8.2 创建 IDA 结构体

发布于 2024-10-11 21:05:42 字数 4593 浏览 0 评论 0 收藏 0

在上一章中,我们见识了 IDA 的数组聚合能力,它通过将一长串的数据声明变成一个反汇编行,简化了反汇编代码清单。在下面几节中,我们将讨论 IDA 如何使用各种工具来改善操纵结构体的代码的可读性。我们的目标是用更具可读性的 [edx+ch8_struct.field5] 替换 [edx+10h] 之类的结构体引用。

只要发现一个程序正操纵某种数据结构,你就需要确定:你是否希望将结构体的字段名称合并到反汇编代码清单中,或者你是否理解分散在代码清单中的所有数字偏移量。有时候,IDA 能够确定程序在调用 C 标准库或 Windows API 的过程中定义了一个结构体。这时,IDA 了解该结构体的具体布局,并且能够将数字偏移量转换成更加符号化的字段名称。这是一种理想化的情形,因为你并没有多少工作要做。在我们初步了解 IDA 如何处理通常的结构体定义后,我们将继续讨论这种情形。

8.2.1 创建一个新的结构体(或联合)

如果程序正使用某个结构体,而 IDA 并不了解其布局,这时,IDA 会提供实用工具以设置该结构体的布局,并将新定义的结构体包含到反汇编代码清单中。IDA 使用 Structures 窗口(如图 8-2 所示)来创建新的结构体。除非结构体已经在 Structures 窗口中列出,否则就无法将结构体包含到反汇编代码清单中。IDA 将自动在 Structures 窗口中列出任何它能够识别、并确定已被一个程序使用的结构体。

图 8-2 Structures 窗口

IDA 之所以在分析阶段无法识别结构体,可能源于两个原因。首先,虽然 IDA 了解某个结构体的布局,但它并没有足够的信息,能够判断程序确实使用了结构体。其次,程序中的结构体可能是一种 IDA 对其一无所知的非标准结构体。在这两种情况下,问题都可以得到解决,且首先从 Structures 窗口下手。

Structures 窗口的前 4 行文本用于提醒用户该窗口中可能进行的操作。我们使用的主要操作包括添加、删除和编辑结构体。添加结构体使用热键 INSERT 启动,它打开如图 8-3 所示的 Create structure/union(创建结构体/联合)对话框。

图 8-3 Create structure/union 对话框

为了创建一个新的结构体,你必须首先在 Structure name(结构体名称)字段中指定结构体的名称。前两个复选框用于决定新结构体在 Structures 窗口中的显示位置,或者是否在窗口中显示新结构体。第三个复选框 Creat union (创建联合),指定你定义的是否为 C 风格联合1 结构体。结构体的大小是它所包含的字段大小的总和,而联合的大小则等于其中最大字段的大小。Add standard structure(添加标准结构体)按钮用于访问 IDA 当前能够识别的全部结构体数据类型。这个按钮的作用将在 8.5 节讨论。指定结构体的名称并单击 OK 按钮后,IDA 将在 Structures 窗口中创建一个空结构体定义,如图 8-4 所示。

1. 联合类似于结构体,其中可能包含许多类型各不相同的具名字段。二者的区别在于,联合中的字段相互重叠,因此,联合的大小等于其中最大字段的大小

图 8-4 空结构体定义

你必须对这个结构体定义进行编辑,以完成对结构体布局的定义。

8.2.2 编辑结构体成员

为了给新结构体添加字段,你必须利用字段创建命令 D、A 和数字键盘上的星号键(*)。最初,你只需要使用 D 命令。不过,它的行为非常依赖于光标的位置。为此,我们建议采用下面的步骤给结构体添加字段。

  1. 要给结构体添加新字段,将光标放在结构体定义的最后一行(包含 ends 的那一行)并按下 D 键。这时,IDA 就会在结构体的末尾添加一个新字段。新字段的大小取决于你在数据转盘(参见第 7 章)上选择的第一个大小。最初,字段的名称为 field_N ,这里的 N 为结构体开头到新字段(如 field_0 )开头的数字偏移量。

  2. 如果需要修改字段的大小,首先将光标放在新字段的名称上,然后重复按下 D 键,使数据转盘上的数据类型开始循环,从而为新字段选择正确的数据大小。另外,你还可以使用 Options▶ Setup Data Types 来指定一个在数据转盘上不存在的大小。如果新字段是一个数组,右击其名称并在上下文菜单中选择 Array,将打开“数组规范”对话框(参见第 7 章)。

  3. 要更改一个结构体字段的名称,单击字段名称并按下 N 键,或者右击该名称并在上下文菜单中选择 ReName,然后在输入框中输入一个名称即可。

在你定义自己的结构体时,下面的提示可能会有所帮助。

  • 一个字段的字节偏移量以一个 8 位十六进制值在 Structures 窗口的左侧显示。

  • 每次你添加或删除一个结构体字段,或更改一个现有字段的大小时,结构体的新大小都会在结构体定义的第一行反映出来。

  • 你可以给一个结构体字段添加注释,就像给任何反汇编行添加注释一样。右击(或使用热键)你希望为其添加注释的字段,在上下文菜单中选择一个注释选项即可。

  • 与 Structures 窗口顶部的说明不同的是,只有当一个字段是结构体中的最后一个字段时,使用 U 键才能删除该字段。对于所有其他字段,按下 U 键将取消该字段的定义,这样做仅仅删除了该字段的名称,并没有删除分配给该字段的字节。

  • 你必须对一个结构体定义中的所有字段进行适当的对齐。IDA 并不区分已压缩和未压缩的结构体。为将字段适当对齐,如果你需要填补字节,那么你必须负责添加这些字节。填补字节最好作为适当大小的哑字段添加。在添加额外的字段后,你可以选择取消或保留这些字段的定义。

  • 分配到结构体中间的字节只有在取消关联字段的定义后才能删除,使用 Edit ▶ Shrink Struct Type (缩小结构体类型)即可删除被取消定义的字节。

  • 你也可以在结构体的中间添加新的字节:选择新字节后面的一个字段,然后使用 Edit ▶ Expand Struct Type (扩大结构体类型)在选中的字段前插入一定数量的字节。

  • 如果知道结构体的大小,而不了解它的布局,你需要创建两个字段。第一个字段为一个数组,它的大小为结构体的大小减去 1 个字节( size-1 );第二个字段应为 1 个字节。创建第二个字段后,取消第一个(数组)字段的定义。这样,结构体的大小被保留下来,随后,当你进一步了解该结构体的布局后,你可以回过头来定义它的字段及其大小。

通过重复应用这些步骤(添加字段,设置字段大小,添加填补字节等),你就可以在 IDA 中创建 ch8_struct 结构体(未压缩版本),如图 8-5 所示。

在这个例子中,IDA 使用了填补字节对字段进行适当对齐,并根据前面例子中的名称重命名字段。值得注意的是,每个字段的偏移量和结构体的总大小(24 字节)仍与前面的例子中的值相同。

图 8-5 手动生成的 ch8_struct 结构体定义

如果你觉得结构体定义在 Structures 窗口中占用了太多空间,你可以选择结构体中的任何字段并按下数字键盘中的减号键,将结构体的定义折叠成一行摘要。一旦结构体获得完整的定义,并且不需要进一步编辑,你就可以将它折叠起来。 ch8_struct 的折叠版本如图 8-6 所示。

图 8-6 折叠版本的结构体定义

绝大多数 IDA 能够识别的结构体都以这种单行方式显示,因为你不需要编辑它们。折叠式显示提供一个提示,即你可以使用数字键盘上的加号键打开结构体定义。另外,双击结构体名称也可以打开该定义。

8.2.3 用栈帧作为专用结构体

你可能已经注意到,结构体定义看起来与函数的详细栈帧视图有些类似。这并非巧合,因为在 IDA 内部,IDA 处理它们的方式完全相同。它们都属于相邻的内存块,能够细分成若干已命名字段,并且每个字段都拥有一个数字偏移量。它们之间的细微区别在于,栈帧以一个帧指针或返回地址为中心,同时使用正值和负值字段偏移量,而结构体仅使用正值偏移量(以结构体开头位置为起始点)。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文