在时间旅行调试(TTD)追踪记录上使用 YARA 规则
一个简单的启动 calc.exe 的二进制程序,使用 UPX 加壳。
yara-ttd 在线程创建期间,在模块内存中找到了 calc.exe 字符串。
calc.exe 的简单混淆 shellcode被测试的二进制程序解密一段 shellcode,并在新线程中运行它。
当在 ntdll!NtCreateThreadEx 函数上挂钩时,yara-ttd 成功在堆上找到了 calc.exe 字符串。
YARA 是一款强大的二进制模式匹配工具。
YARA 是一款旨在(但不限于)帮助恶意软件研究人员识别和分类恶意软件样本的工具。借助 YARA,你可以基于文本或二进制模式创建恶意软件家族(或任何你想要描述的内容)的描述。
-- YARA 文档
借助 YARA,我们可以在分析恶意软件样本之前,通过流水线自动分类,从而节省大量时间。
遗憾的是,大多数恶意软件样本都受到不同种类加壳程序的保护。像 UPX 或 VMProtect 这样的经典运行时加壳方案,包括自解压并运行经过混淆、有时甚至是加密的代码。
因此,YARA 无法处理加壳的二进制程序,因为它在加壳代码中找不到任何匹配项。
Time Travel Debugging(时间旅行调试)(简称 TTD)是 Windows 原生调试器 WinDbg 的一项功能。
时间旅行调试是一种工具,允许你捕获进程执行时的追踪记录,并在之后向前和向后重放。时间旅行调试(TTD)可以让你“倒回”调试器会话,而不是必须反复重现问题直到找到缺陷,从而更轻松地调试问题。
-- Microsoft 文档
对于恶意软件分析而言,TTD 是一个强大的工具,因为它允许在沙箱中记录恶意软件的追踪。因此,我们可以在沙箱之外安全地重放和共享记录文件来分析恶意软件。
此外,TTD 并不是调试器,因此不会被诸如 PEB.BeingDebugged 之类的经典反调试技术检测到。
若想从安全角度更深入地分析 TTD,请查看这篇文章:深入剖析 TTD 生态系统
当然,TTD 是专有软件,如果没有 commial 开发的 ttd-bindings,这项工作就不可能存在。
yara-ttd 背后的想法是使用 TTD 记录的追踪文件,结合 yara 本身来击败加壳程序。
由于 yara 无法直接扫描已加壳的二进制程序,yara-ttd 提供了一种分析包含所有运行时信息(包括脱壳过程)的追踪文件的方法。
使用 yara-ttd,你可以选择追踪文件中的一组位置,在这些位置用你的 yara 规则扫描内存。
因此,你可以用你的 yara 规则在任意想要的位置挂钩已加壳的二进制程序!
yara-ttd 提供了多种内存扫描策略,例如在模块加载时、或虚拟内存被分配时(这些时机常被用于存放脱壳后的恶意代码)。
目前,yara-ttd 仅支持 Windows,因为它需要与 TTD API 交互。
首先构建项目:
mkdir build
cd build
cmake ..
cmake --build .
然后,将 TTDReplay.dll 和 TTDReplayCPU.dll 文件放到可执行文件所在的相同目录中。
你可以在 %LocalAppData%\Microsoft\WindowsApps\Microsoft.WinDbg_X\TTD 中找到这些 DLL 文件。
首先,你需要记录程序的追踪(.run 文件)。
有关如何记录 TTD 追踪的详细帮助,请参阅本教程。
然后直接运行:
.\yara-ttd path\to\rule path\to\trace\file
有三种扫描内存的模式:
你可以使用 -m 选择模式:
.\yara-ttd -m 1 path\to\rule path\to\trace\file
与官方 yara 命令行工具一样,你可以使用 -s 标志打印匹配详情,例如内存地址和具体匹配的规则子项。
因为 TTD 不存储内存结构,yara-ttd 会在扫描前计算每个时间位置的堆地址结构。
它会在与追踪文件相同的路径下创建一个扩展名为 .tmp 的缓存文件,用于存储堆结构。
如果你想在追踪上重新运行 yara-ttd,并从生成的缓存文件加载堆结构,可以简单地执行:
.\yara-ttd -m 1 --cache=path\to\cache\file path\to\rule path\to\trace\file
我们可以通过 TTD 访问进程的完整内存范围,该范围对应于 GetSystemInfo 返回的最小和最大地址。然而,大多数时候,这个范围太大了,不经任何优化就无法扫描。
默认将扫描以下时间位置:
使用 -t 和 -f 标志,你可以选择其他位置或函数调用进行扫描:
.\yara-ttd -m 1 -t 3C1:A -t 5FF:22 -f ntdll!FreeVirtualMemory -f ntdll!NtCreateThreadEx path\to\rule path\to\trace\file
-t 标志期望 TTD 位置采用 major:minor 格式(均为十六进制,不带 0x)。
-f 标志期望 module_name!function_name 形式的字符串。
你也可以将一个文件中所有想要挂钩的函数添加进来:
> cat .\functions.txt
ntdll!FreeVirtualMemory
ntdll!NtCreateThreadEx
> .\yara-ttd -m 1 -F functions.txt path\to\rule path\to\trace\file
如果你有多个文件需要用 yara-ttd 扫描,你也可以扫描整个目录。
yara-ttd 将忽略文件夹中以下所有扩展名:
.tmp(由 yara-ttd 生成的缓存文件).idx(由 ttd 生成的索引文件).err(由 ttd 生成的错误文件).out(由 ttd 生成的日志文件)在以下示例中,yara-ttd 将仅扫描 trace01.run 和 trace02.run 文件。
> dir .\traces
trace01.run
trace01.out
trace01.idx
trace02.run
trace01.run.err
trace01.tmp
> .\yara-ttd path\to\rule .\traces
或者,你可以将想要扫描的所有追踪记录指定在一个文件中,并使用 --scan-list 或 -l 标志。它将逐行扫描列出的文件:
> cat .\scan_me.txt
.\traces\trace01.run
.\traces\trace02.run
> .\yara-ttd -l path\to\rule .\scan_me.txt
当扫描多个文件时,
yara-ttd一个一个地顺序执行扫描,而不是像原始的yara命令行工具那样使用线程同时扫描。