返回介绍

21.2 反动态分析技巧

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

我们在前面几节讨论的反静态分析技巧中,没有一种技巧会给一个程序是否运行造成任何影响。实际上,虽然它们使你仅仅通过静态分析技巧难以理解一个程序的真正行为,但是它们无法阻止该程序运行,否则,它们将使一个程序失去作用,因而我们也就完全没有必要分析这个程序。

程序必须运行才能有效地工作,鉴于此,动态分析旨在观察运动中(运行中)的程序行为,而不是观察静止的程序(如果程序并未运行,则使用静态分析)。本节中,我们将简单介绍一些更加常见的反动态分析技巧。多数情况下,这些技巧一般与静态分析工具无关,但如果它们的功能有重叠的地方,我们将会指出来。从第 24 章开始,我们将回过头来讨论这些技巧对 IDA 的集成调试器的影响。

21.2.1 检测虚拟化

配置沙盒环境的一个最常见的目的是利用虚拟化软件(如 VMware)为恶意软件(或者这方面的任何其他相关软件)提供一个执行环境。这类环境的优势在于它们通常提供检查点和回滚功能,能够迅速将沙盒恢复到一个已知的“清洁”状态。使用这类环境作为沙盒基础的缺点在于程序能够相对容易地检测出(特别是在 32 位 x86 平台上),它在一个虚拟环境中运行。假设虚拟化等同于监视,那么许多希望保持隐秘的程序一旦确定自己在虚拟机中运行,将会立即关闭。

下面我们将介绍一些技巧,在虚拟环境中运行的程序使用这些技巧确定它们是在虚拟机中运行,还是在本地硬件上运行。

  • 检测虚拟化软件 。通常,用户会在虚拟机中安装帮助应用程序,以方便虚拟机与它的主机操作系统之间的通信,或者只是为了改善虚拟机的性能。VMware Tools 就是一个这样的软件。在虚拟机中运行的程序能够轻易检测到这种类型的软件。例如,如果在一个微软 Windows 虚拟机中安装 VMware Tools ,它会创建任何程序都可以读取的 Windows 注册表项。在虚拟机中运行恶意程序很少需要 VMware Tools,因此,你不应将它安装到虚拟机中,以避免在虚拟机中的程序轻易检测到虚拟机的存在。

  • 检测虚拟化硬件 。虚拟机利用虚拟硬件抽象层为虚拟机与主计算机的本地硬件提供接口。在虚拟机中运行的软件通常很容易检测到虚拟硬件的特性。例如,VMware 被分配了它自己的唯一标识符(OUI )1 ,供它的虚拟化网络适配器使用。观察到一个特定于 VMware 的 OUI 是程序在虚拟机中运行的可靠证据。注意,使用主计算机上的配置选项,通常可以修改分配给虚拟网络适配器的 MAC 地址。
    1. 网络适配器厂家分配的 MAC 地址的前 3 个字节由一个 OUI 组成。

  • 检测虚拟机的行为 。一些虚拟化平台包含后门式的通信通道,以方便虚拟机与主机软件之间的通信。例如,下面的 4 行代码可用于确定你是否在一个 VMware 虚拟机中运行2

    2. 参见 http://www.codeproject.com/KB/system/VmDetect.aspx (作者:Elias Bachaalany )。

       mov  eax, 0x564D5868    ; 'VMXh'
       mov  ecx, 10
       xor ebx, ebx
       mov  dx,  0x5658        ; 'VX'
    ➊ in   eax, dx
    
    如果你在虚拟机中,这段代码将导致 EBX 寄存器包含 0x564D5868 这个值。如果你不在虚拟机中,根据你使用的主机操作系统,这段代码将造成一个异常,或者不会改变 EBX 寄存器。这个指令序列利用了一个事实,即用户空间程序通常不使用或不允许使用 x86 in 指令(➊)。但是,在 VMware 中,这个指令序列可用于检测一个特殊的通信通道,VMware 客户操作系统使用这个通道与它们的主机操作系统进行通信。例如,VMware Tools 使用这个通道在主机与客户操作系统之间交换数据(如剪贴板内容)。
  • 检测特定于处理器的行为变化 。完美的虚拟化很难实现。理想情况下,程序应该不能检测到虚拟化环境与本地硬件之间的任何差异。但是,这种情况很少发生。观察在本地硬件与虚拟机环境中执行的 x86 sidt 指令的行为差异后,Joanna Rutkowska 开发出她的“红丸”3 (redpill )VMware 检测技巧。

3. 参见 http://www.invisiblethings.org/papers/redpill.html

虽然并不是相关主题的第一篇论文,但 Tom Liston 与 Ed Skoudis4 的论文“On the Cutting Edge: Thwarting Virtual Machine Detection”为我们简要介绍了各种虚拟机检测技巧。

4. 参见 http://handlers.sans.org/tliston/ThwartingVMDetection_Liston_Skoudis.pdf

21.2.2 检测“检测工具”

创建沙盒环境后,在执行你想要观察的任何程序之前,你都要安装检测工具,以正确收集和记录与你所分析的程序的行为有关的信息。有大量工具可用于执行这类监控任务。Process Monitor5 (来自微软 Sysinternals6 套件)和 Wireshark7 是两个被人们广泛使用的工具。Process Monitor 是一种实用工具,它能够监控与任何正在运行的 Windows 进程有关的某些行为,包括访问 Windows 注册表和文件系统活动。Wireshark 是一个网络数据包捕获和分析工具,常用于分析恶意软件生成的网络流量。

5. 参见 http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx
6. 参见 http://technet.microsoft.com/en-us/sysinternals/default.aspx
7. 参见 http://www.wireshark.org/

生性多疑的恶意软件作者可能会指挥他们的软件搜索这类监控程序的运行实例。他们采用的技巧包括:扫描活动进程列表,查找已知与这类监控软件有关的进程名称,以及扫描所有活动 Windows 应用程序的标题栏文本,从中搜索已知的字符串。你还可以进行更加深入的搜索,如使用一些软件搜索某个检测软件所使用的 Windows GUI 组件的特定特征。例如,WinLincense 模糊/ 保护程序使用下面的函数调用确定 Filemon(Process Monitor 的前身)实用工具当前是否正在运行:

if (FindWindow("FilemonClass", NULL)) {  
   //exit because Filemon is running  
}

这里, FindWindow 函数用于根据窗口的注册类名称" FilemonClass "(而非窗口标题)搜索一个顶级应用程序窗口。如果发现一个被请求类的窗口,则认为 Filemon 正在运行,程序将立即终止。

21.2.3 检测调试器

除了简单地观察程序外,分析人员还可以使用调试器完全控制需要分析的程序的执行过程。对模糊程序使用调试器的一个惯常做法是运行模糊程序足够长的时间,以完成任何解压或加密任务,然后利用调试器的内存访问功能从内存中提取出“去模糊”后的进程映像。多数情况下,使用标准的静态分析工具和技巧就能够分析提取出的进程映像。

模糊实用工具的作者清楚地知道这类调试器辅助的去模糊技巧,因此,他们已经采取许多措施,防止他人使用调试器执行他们的模糊程序。检测到调试器确实存在的程序往往会选择立即终止,而不是继续执行操作,以免分析人员更加轻松地确定程序的行为。

检测调试器是否存在的技巧包括通过常用的 API 函数(如 Windows IsDebuggerPresent 函数)直接查询操作系统,或使用较为低级的方法,即检查因为使用调试器而生成的内存或处理器项目(artifact )。例如,就后一种技巧而言,我们可以检测处理器是否设置了跟踪(单步)标志。有时,我们还可以检测到特定的调试器。例如,Windows 内核调试器 SoftIce 可以通过 \\.\NTICE 设备(用于与调试器通信)检测出来。

只要你知道自己到底想要搜索什么,那么检测调试器就并非难事,而且在静态分析过程中你也可以轻易发现这类检测尝试(除非同时使用了反静态分析技巧)。有关调试器检测的更多信息,请查阅 Nicolas Falliere 的文章“Windows Anti-Debug Reference”8 ,这篇文章全面讲述了各种 Windows 反调试技巧。另外,OpenRCE 维护着一个反逆向工程技巧数据库9 ,其中包含大量特定于调试器的技巧。

8. 参见 http://www.symantec.com/connect/articles/windows-anti-debug-reference
9. 参见 http://pferrie.tripod.com/papers/unpackers.pdf/ (作者:Peter Ferrie )。

21.2.4 防止调试

如果一个调试器设法保持住了隐秘状态(不可检测),仍然有许多技巧可以阻止它运行。这些其他的技巧尝试通过引入伪造的断点、清除硬件断点、阻碍反汇编,使选择合适的断点地址变得困难,或者通过阻止调试器依附到一个进程上,令调试器“不知所措”。Nicolas Falliere 的文章中讨论的许多技巧适用于阻止调试器正常运行。

程序可以通过有意生成异常来阻止调试。许多时候,附加的调试器将捕获这个异常,而调试器的用户则面临着两个任务:分析异常为何发生,决定是否将异常传递给被调试的程序。对于 x86 int 3 之类的软件断点,你将很难区分由基础程序生成的软件中断与由真正的调试器断点生成的软件中断。这正是模糊程序创建者希望看到的结果。在这类情况下,你可以通过仔细分析反汇编代码清单来了解程序的真正控制流,但在静态分析时,你需要付出更大的努力。

对程序的一些组成部分以某种方式编码会有双重效果:一方面,编码可以防止静态分析,因为这时反汇编并不可行;另一方面,编码可以阻止调试,因为这时很难设置断点。即使每条指令的起始地址已知,但软件断点只有在指令被完全解码后才能设置,因为以插入一个软件断点的方式来修改指令,可能会导致对模糊代码的加密失败;如果执行到这个断点,可能会导致程序崩溃。

此外,一些去模糊实用程序对进程内的字节范围计算样验和。如果在正对其计算校验和的字节范围内设置一个或多个软件断点,将会生成错误的校验和,程序也可能会终止。

Linux 平台上的 Shiva ELF 模糊工具利用一种叫做“进程互相跟踪”(mutual ptrace)的方法防止他人使用调试器分析 Shiva 的行为。

进程跟踪

进程跟踪(ptrace 或 process tracing)API 可用在许多 Unix 类型的系统中,它提供一种机制,让一个进程监视和控制另一个进程的执行。GNU 调试器(gdb)是一种利用进程跟踪 API 的常见应用程序。使用进程跟踪 API,一个进程跟踪父进程可以依附到一个进程跟踪子进程上,并控制子进程的执行。为了控制一个进程,父进程必须首先依附到它想要控制的子进程上。随后,只要收到信号,子进程就会停止运行,而父进程则通过 POSIX wait 函数得到通知,这时,它可以选择修改或检查子进程的状态,然后指示子进程继续执行。只要一个父进程已经依附一个子进程,其他进程将无法依附这个子进程,除非进程跟踪父进程脱离这个子进程。

Shiva 利用了这一点:任何时候,一个进程只能依附一个其他进程。在执行早期,Shiva 进程会进行分支,创建自己的一个副本。然后,原始的 Shiva 进程立即对新分支的子进程执行进程跟踪依附操作。反过来,新分支的子进程也立即依附到它的父进程上。如果其中的一个依附操作失败,Shiva 会认为另一个调试器被用于监控它的进程,它会立即终止。如果这两个依附操作都取得成功,则说明没有其他调试器能够依附到正在运行的 Shiva 进程对上,Shiva 将继续运行,而不用担心被监视。以这种方式运行时,任何一个 Shiva 进程都可以修改另一个进程的状态,因此,使用静态分析技巧很难确定 Shiva 二进制文件的真实控制流路径。

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

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

发布评论

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