返回介绍

5.3 其他 IDA 显示窗口

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

最后,我们讨论默认情况下 IDA 不会打开的窗口。这里讨论的每一个窗口都可通过 View▶Open Subviews 命令打开。但是,它们提供的并不是你当前需要的信息,因此,IDA 一开始并不打开这些窗口。

5.3.1 Strings 窗口

Strings 窗口是 IDA 中内置的,功能等同于 strings 及其他一些实用工具。在 IDA 5.1 及之前的版本中,桌面默认打开 Strings 窗口。但是,从 5.2 版开始,IDA 不再默认打开 Strings 窗口,不过用户仍然可以通过 View▶Open Subviews▶Strings 命令打开该窗口。

Strings 窗口中显示的是从二进制文件中提取出的一组字符串,以及每个字符串所在的地址。与双击 Names 窗口中的名称得到的结果类似,双击 Strings 窗口中的任何字符串,反汇编窗口将跳转到该字符串所在的地址。将 Strings 窗口与交叉引用(第 9 章将介绍)相结合,可迅速定位你感兴趣的字符串,并追踪到程序中任何引用该字符串的位置。例如,你可能会看到 SOFTWARE\Microsoft\ Windows\CurrentVersion\Run 这个字符串,并想知道应用程序为什么会引用这个特殊的 Windows 注册表项。在下一章中你会发现,导航到引用这个字符串的程序位置,只需要单击 4 下鼠标。掌握 Strings 窗口的操作,是高效应用这个窗口的基础能力。IDA 并不会永久保存它从二进制文件中提取出的字符串。因此,每次打开 Strings 窗口,IDA 都会扫描或重新扫描整个数据库,查找其中的字符串。扫描字符串的操作遵照 Strings 窗口的设置来完成,右击该窗口,在出现的菜单中选择 Setup,即可开始设置。如图 5-7 所示,Setup Strings 窗口用于指定 IDA 应扫描的字符串类型。IDA 默认扫描的字符串类型为至少包含 5 个字符的 C 风格、以 null 结尾的 7 位 ASCII 字符串。

enter image description here

图 5-7 Setup Strings 窗口

如果希望在字符串窗口中显示除 C 风格字符串以外的字符串,你需要重新配置 Setup Strings 窗口,从中选择 IDA 扫描的相应字符串类型。例如,Windows 程序通常会使用 Unicode 字符串,而 Borland Delphi 二进制文件则往往使用 2 个字节长的 Pascal 字符串。每次你单击 OK 按钮关闭 Setup Strings 窗口后,IDA 都会根据新的设置重新扫描数据库,查找相应的字符串。有两个设置选项值得特别注意。

Display only defined strings(仅显示已定义的字符串) 。这个选项使 Strings 窗口仅显示 IDA 自动创建或用户手动创建的已命名字符串数据项。在选中这个选项的同时禁用所有其他选项,IDA 将不会自动扫描其他类型的字符串。

Ignore instructions/data definitions (忽略指令/ 数据定义) 。这个选项会使 IDA 扫描指令和现有数据定义中的字符串。使用这个选项,可以让 IDA 扫描二进制代码中错误地转换成指令的字符串,或扫描数据中非字符串格式(如字节数组或整数)的字符串。这个选项还会导致 IDA 生成许多垃圾字符串,即那些由 5 个或更多 ASCII 字符构成的字符串(无论其是否合法)。使用这个选项的效果类似于使用 strings –a 命令。

如图 5-8 所示,如果没有正确配置字符串设置,IDA 不一定会显示二进制文件中的所有字符串。在这种情况下,用户并没有选中 Ignore instructions/data definitions 选项。

enter image description here

图 5-8 不扫描字符串数据的情况

结果,IDA 并不扫描位置 .rdata:0040C19C 处的字符串(“Please guess a number between 1 and %d.”)。这个选项的作用是确保 IDA 会在所有可能发现字符串的地方扫描各种类型的字符串。

5.3.2 Names 窗口

Names 窗口如图 5-9 所示,它简要列举了一个二进制文件的所有全局名称。名称是指对一个程序虚拟地址的符号描述。在最初加载文件的过程中,IDA 会根据符号表和签名分析派生出名称列表。名称可以按字母排序,也可以按虚拟地址排序(升序或降序)。用户可通过 Names 窗口迅速导航到程序列表中的已知位置。双击 Names 窗口中的名称,可立即跳转到显示该名称的反汇编视图。

enter image description here

图 5-9 Names 窗口

Names 窗口中显示的名称采用了颜色和字母编码。其编码方案总结如下。

  • F ,常规函数。IDA 认为这些函数不属于库函数。

  • L ,库函数。IDA 通过签名匹配算法来识别库函数。如果某个库函数的签名并不存在,则该函数将被标记为常规函数。

  • I ,导入的名称,通常为共享库导入的函数名称。它与库函数的区别在于:导入的名称没有代码,而库函数的主体将在反汇编代码清单中显示。

  • C ,命名代码。这些是已命名的程序指令位置,IDA 认为它们不属于任何函数。当 IDA 在程序的符号表中找到一个名称,但没发现对程序位置的任何调用时,就会出现这种情况。

  • D ,数据。已命名数据的位置通常表示全局变量。

  • A ,字符串数据。这是一个被引用的数据位置,其中包含的一串字符符合 IDA 的某种已知的字符串数据类型,如以 '\0' 字节结束的 ASCIIC 字符串。

浏览反汇编代码清单时,你会注意到,其中许多已命名的位置在 Named 窗口中并没有对应的名称。在对一个程序进行反汇编的过程中,IDA 会为所有直接作为代码(分支或调用目标)或数据(读取的、写入的或使用的地址)引用的位置生成名称。如果一个位置已在程序符号表中命名,IDA 将采用该名称。如果符号表中某一程序位置没有名称,则 IDA 会生成一个默认的名称,以在反汇编过程中使用。在 IDA 给某个位置命名时,它会使用该位置的虚拟地址和一个表示该位置的类型的前缀进行命名。将虚拟地址合并到生成的名称中,可确保生成的所有名称的唯一性,因为没有两个位置的虚拟地址是相同的。这种自动生成的名称并不在 Names 窗口中显示。用于自动生成名称的一些常用前缀包括以下这些。

  • sub_xxxxxx :地址xxxxxx 处的子例程。

  • loc_xxxxxx :地址xxxxxx 处的一个指令。

  • byte_xxxxxx :位置xxxxxx 处的 8 位数据。

  • word_xxxxxx :位置xxxxxx 处的 16 位数据。

  • dword_xxxxxx :位置xxxxxx 处的 32 位数据。

  • unk_xxxxxx :位置xxxxxx 处的大小未知的数据。

在本书的剩余部分,我们还将介绍 IDA 用于为程序数据位置选择名称的其他算法。

5.3.3 段窗口

段窗口显示的是在二进制文件中出现的段的简要列表。需要注意的在,在讨论二进制文件的结构时,IDA 术语 (segment)常称为 (section )。请不要将这里的术语段与实施分段内存体系结构的 CPU 中的内存段混淆。该窗口中显示的信息包括段名称、起始和结束地址以及许可标志。起始和结束地址代表程序段在运行时对应的虚拟地址范围。下面是 IDA 在分析一个 Windows 二进制文件时显示的段窗口:

Name   Start    End      R W X D L Align Base Type   Class  AD es   ss   ds   fs       gs
UPX0   00401000 00407000 R W X . L para  0001 public CODE   32 0000 0000 0001 FFFFFFFF FFFFFFFF
UPX1   00407000 00408000 R W X . L para  0002 public CODE   32 0000 0000 0001 FFFFFFFF FFFFFFFF
UPX2   00408000 0040803C R W . . L para  0003 public DATA   32 0000 0000 0001 FFFFFFFF FFFFFFFF
.idata 0040803C 00408050 R W . . L para  0003 public XTRN   32 0000 0000 0001 FFFFFFFF FFFFFFFF
UPX2   00408050 00409000 R W . . L para  0003 public DATA   32 0000 0000 0001 FFFFFFFF FFFFFFFF

从上面的例子可以立即发现这个特殊的二进制文件有点奇怪,因为它使用了非标准的段名称,并包含两个可写入的可执行代码段,这表示它们可能是自修改代码(更多内容将在第 21 章讨论)。即使 IDA 知道段的大小,也不能表明它知道该段的内容。由于各种原因,段占用的磁盘空间比内存空间小得多。在这些情况下,IDA 会显示它已经确定能够从磁盘文件中提取的段部分的值,至于段的其他部分,它会以问号显示。

双击段窗口中的任何条目,IDA 将跳转到反汇编窗口中该段的起始位置。右击一个条目,IDA 将显示一个上下文菜单,你可以选择添加新段、删除现有段、或者编辑现有段的属性。在对非标准格式的文件进行逆向工程时,这些功能特别有用,因为二进制文件的段结构可能还没有被 IDA 加载器检测出来。

段窗口所对应的命令行工具包括 objdump (-h)readelf (-s)dumpbin (/HEADERS)

5.3.4 签名窗口

IDA 利用一个庞大的签名库来识别已知的代码块。签名用于识别由编译器生成的常用启动顺序,以确定可能已被用来构建给定二进制文件的编译器。签名还可用于将函数划归为由编译器插入的已知库函数,或者因为静态链接而添加到二进制文件中的函数。在 IDA 为你识别库函数时,你可以将更多精力放在分析 IDA 无法识别的代码上(对你而言,这可能比对 printf 的内部工作机制进行逆向工程更加有趣)。

签名窗口显示的是 IDA 对打开的二进制文件所使用的签名。Windows PE 文件的签名窗口的示例如下所示:

File      State     #func  Library name
vc32rtf   Applied   501    Microsoft VisualC 2-8/net runtime

这个例子表明,IDA 已对该二进制文件应用了 vc32rtf 签名(来自/sigs 目录),并在这个过程中将 501 个函数识别为库函数。你不需要对这 501 个函数进行逆向工程处理。

至少在两种情况下,你需要知道如何对二进制文件应用其他签名。第一种情况:IDA 无法识别用于构建二进制文件的编译器,因而无法选择所需的相应签名。这时,你需要根据自己的初步分析,确认 IDA 应尝试使用的签名,并迫使 IDA 使用一个或几个签名。第二种情况:IDA 中没有针对某些库的现成签名,这时你需要为这些库创建你自己的签名。例如,为 FreeBSD 8.0 自带的 OpenSSL 静态库创建签名就是如此。DataRescue 提供一个工具包,可用于生成供 IDA 的签名匹配引擎使用的自定义签名。我们将在第 12 章中讨论如何生成自定义签名。无论你出于什么原因想要应用新签名,在签名窗口中按下 INSERT 键或右击窗口,IDA 都会为你提供 Apply new signature(应用新签名)选项。这时,你可以从你所安装的 IDA 版本包含的所有签名中选择你需要的签名。

5.3.5 类型库窗口

类型库窗口在概念上与签名窗口类似。类型库保存 IDA 积累的一些信息,即 IDA 从最常用的编译器的头文件中搜集到的有关预定义数据类型和函数原型的信息。通过处理头文件,IDA 可确定常用库函数所需的数据类型,并为反汇编代码提供相应的注释。同样,IDA 还可从这些头文件中了解复杂数据结构的大小和布局。所有这些信息都收集在 TIL 文件(< IDADIR/til 目录 > )中,并可在任何时候应用于你分析的二进制文件。与应用签名时一样,在选择加载一组适当的 TIL 文件之前,IDA 必须首先确定一个程序所使用的库。要请求 IDA 加载其他类型库,可以在类型库窗口中按下 INSERT 键,或右击窗口并在出现的菜单中选择 Load Type Library (加载类型库)。类型库将在第 13 章详细讨论。

5.3.6 函数调用窗口

在任何程序中,一个函数可以调用其他函数,也可以被其他函数调用。实际上,建立一个图形来说明调用方与被调用方之间的关系,是一个相当简单的任务。这样的图形叫做函数调用图形或函数调用树(我们将在第 9 章介绍如何在 IDA 中生成这类图形)。有时候,我们并不需要查看程序的完整调用图形,而只对指定函数的“近邻”感兴趣。如果 Y 直接调用 X,或者 X 直接调用 Y,则称 Y 是 X 的近邻。

函数调用窗口提供了这类“近邻”的问题的答案。打开函数调用窗口时,IDA 会确定光标所在位置的函数的“近邻”,并生成如图 5-10 所示的窗口。

enter image description here

图 5-10 函数调用窗口

在这个例子中,我们看到,函数 sub_40182C_main 从 6 个不同的位置调用,而这个函数又调用了另外 15 个函数。双击函数调用窗口中的任何一行,IDA 将立即跳转到反汇编窗口中对应的调用或被调用函数(即调用方或被调用方)。IDA 交叉引用(xrefs )是用于生成函数调用窗口的机制。我们将在第 9 章详细讨论 xrefs 。

5.3.7 问题窗口

IDA 在问题窗口中显示它在反汇编二进制文件时遇到的困难,以及它如何处理这些困难。有些时候,你可以操纵反汇编代码,帮助 IDA 解决问题,但情况并非总是如此。即使在反汇编最简单的二进制文件时,你也可能会遇到问题。许多时候,忽略这些问题并不是坏事。为了处理问题,你需要比 IDA 更深入地理解二进制文件,但我们大多数人都无法做到这一点。下面是一组问题:

Address          Type       Instruction
.text:0040104C   BOUNDS     call    eax               
.text:004010B0   BOUNDS     call    eax               
.text:00401108   BOUNDS     call    eax               
.text:00401350   BOUNDS     call    dword ptr [eax]   
.text:004012A0   DECISION   push    ebp               
.text:004012D0   DECISION   push    ebp               
.text:00401560   DECISION   jmp     ds:__set_app_type 
.text:004015F8   DECISION   dd 0FFFFFFFFh             
.text:004015FC   DECISION   dd 0                      

可以看到,每个问题都注明了问题发生的地址、问题的类型以及问题所在位置的指令。在这个例子中,我们看到一个 BOUNDS 问题和一个 DECISION 问题。如果无法确定调用或跳转的目标(例如在上例中,IDA 无法获得 eax 的值),或者该目标明显不在程序的虚拟地址范围内,这时就会发生 BOUNDS 问题。许多时候, DECISION 问题根本不是问题。 DECISION 问题通常表示 IDA 决定将一个地址上的字节作为指令而非数据进行反汇编,即使这个地址在递归下降指令遍历(参见第 1 章)过程中从未被引用也是如此。有关问题类型及其处理建议的完整内容,请参阅 IDA 的内部帮助文档(请查阅 Problem List 问题列表这一主题)。

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

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

发布评论

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