Windows 测试构建
Drltrace 是一个用于 Windows 和 Linux 应用程序的动态 API 调用跟踪器。Drltrace 基于 DynamoRIO 动态二进制插桩框架构建。Drltrace 最初由 Derek Bruening 实现,并与 DynamoRIO 和 DrMemory 框架一起分发。此仓库包含一个独立版本的 drltrace,以及关于如何将其用于恶意软件分析的额外脚本和资料。发布版构建可在此处下载。
drltrace 的使用非常简单。用户需要按照以下方式指定日志目录和目标进程的名称:
drltrace -logdir . -- calc.exe
就这样,该工具会将所需的 DLL 注入目标进程,开始插桩,并并行记录目标进程中执行的所有库调用信息:
~~43600~~ msvcrt.dll!__wgetmainargs
arg 0: 0x010d2364
arg 1: 0x010d2368
and return to module id:0, offset:0x193a
~~43600~~ ntdll.dll!EtwEventRegister
arg 0: 0x002ff994
arg 1: 0x010d1490
and return to module id:0, offset:0x157e
~~43600~~ ntdll.dll!EtwEventSetInformation
arg 0: 0x007b4b40
arg 1: 0x00000033
and return to module id:0, offset:0x15a1
~~43600~~ SHELL32.dll!ShellExecuteW
arg 0: <null> (type=<unknown>, size=0x0)
arg 1: <null> (type=wchar_t*, size=0x0)
arg 2: calculator:// (type=wchar_t*, size=0x0)
arg 3: <null> (type=wchar_t*, size=0x0)
arg 4: <null> (type=wchar_t*, size=0x0)
arg 5: 0x1 (type=int, size=0x4)
and return to module id:0, offset:0x167d
输出格式简单,易于被外部脚本解析:
~~[线程 ID]~~ [DLL 名称]![API 调用名称]
arg [参数编号]: [值] (type=[Windows 类型名称], size=[参数大小])
and return to module id:[模块唯一 ID], offset:[内存偏移量]
使用 grep 进行解析时,可以指定 -grepable 参数;这会将函数名称和参数全部打印在一行上:
~~4824~~ KERNELBASE.dll!CreateFileW {0: C:\Windows\Fonts\staticcache.dat (type=wchar_t*, size=0x0)} {1: 0x80000000 (type=DWORD, size=0x4)} {2: 0x3 (type=DWORD, size=0x4)} {3: 0x005cde8c (type=<unknown>*, size=0x0)} {4: 0x3 (type=DWORD, size=0x4)} {5: 0x80 (type=DWORD, size=0x4)}
模块唯一标识符表会在日志文件末尾打印:
Module Table: version 3, count 70
Columns: id, containing_id, start, end, entry, checksum, timestamp, path
0, 0, 0x010d0000, 0x010da000, 0x010d1b80, 0x0000f752, 0xb5fe3575, C:\Windows\SysWOW64\calc.exe
1, 1, 0x6d4c0000, 0x6d621000, 0x6d563940, 0x00136d65, 0x59ce1b0b, C:\Users\Max\Downloads\drltrace\drltrace\dynamorio\lib32\release\dynamorio.dll
2, 2, 0x73800000, 0x73975000, 0x7380dbf7, 0x00000000, 0x59ce1b0f, C:\Users\Max\Downloads\drltrace\drltrace\bin\release/drltracelib.dll
3, 3, 0x742f0000, 0x742fa000, 0x742f2a00, 0x0000c877, 0x0adc52c1, C:\Windows\System32\CRYPTBASE.dll
4, 4, 0x74300000, 0x74320000, 0x7430c9b0, 0x0002c617, 0x245970b4, C:\Windows\System32\SspiCli.dll
5, 5, 0x74410000, 0x74431000, 0x74416900, 0x0002a940, 0x88a53c1d, C:\Windows\System32\GDI32.dll
6, 6, 0x74440000, 0x74500000, 0x7446fb20, 0x000cc410, 0xd343d532, C:\Windows\System32\RPCRT4.dll
7, 7, 0x74500000, 0x74525000, 0x745047d0, 0x00026737, 0xa39c8991, C:\Windows\System32\IMM32.DLL
8, 8, 0x74550000, 0x745c7000, 0x7456e8a0, 0x00081857, 0x73b971e1, C:\Windows\System32\advapi32.dll
9, 9, 0x748f0000, 0x74929000, 0x748febd0, 0x00045303, 0xa58be652, C:\Windows\System32\cfgmgr32.dll
10, 10, 0x74930000, 0x75c78000, 0x74aa09d0, 0x01377aa6, 0x4b39926b, C:\Windows\System32\SHELL32.dll
Drltrace 可以轻松过滤掉库间调用,只打印来自目标应用程序主模块(或堆)的 API 调用,只需指定 -only_from_app 选项,这在应用程序生成巨大日志时非常有用。为了更精细的控制,-filter 选项允许用户指定一个过滤器配置文件,以便仅包含特定的白名单函数,或忽略黑名单中的函数(参见 filter.config 文件中的示例)。Drltrace 还附带几个有用的外部脚本,用于过滤特定库的 API 调用,仅打印可能感兴趣的 API 调用和字符串。
Drltrace 主要模块采用 BSD 许可证分发。
drltrace 所需的一些文件采用 LGPL 许可证分发。详情请参阅源文件。
恶意软件分析并非易事。像 Themida 和 Armadillo 这样的复杂软件加壳工具,以及恶意软件作者编写的数十个无名加壳器,再加上代码和数据加密,极大地便利了(在某些情况下完全不可能)对此类样本进行静态逆向工程,让恶意软件分析师的生活变得复杂。在这种情况下,API 调用跟踪可以显著减少理解实际恶意意图所需的时间,并揭示关于受保护恶意代码的大量技术细节。
虽然传统的 API 挂钩技术已在多种解决方案中成功实现,但该方法已被恶意软件作者深入研究,可以轻松检测和/或绕过。此外,这些工具以独立的重量级 GUI 应用程序(作为专有产品)分发,通常难以集成到现有的恶意软件分析工作流程中。
如果将目光投向 Linux 世界,有一个出色的工具叫 ltrace。只需一个 bash 命令,我们就可以轻松获得特定可执行文件的完整 API 调用跟踪。
为什么我们在 Windows 上没有这样的工具(类似于 Linux 中的 ltrace),而且还能对现代恶意软件使用的反研究技巧透明?
事实证明,有一种技术可以帮助我们在 Windows 上拥有这样的工具,透明地跟踪 API 调用。这种技术称为动态二进制插桩(DBI)。DBI 是一种通过注入插桩代码在运行时分析二进制应用程序行为的技术。
然而,DBI 在恶意软件分析中的应用被不适当地限制在自动脱壳以及指令、基本块和函数调用跟踪的少数概念证明上。据我们所知,drltrace 是第一个基于 DBI 的 API 调用跟踪工具,可以实际用于恶意软件分析。我们在 wiki 中提供了几个恶意软件分析示例,描述了 drltrace 如何在几分钟内揭示复杂恶意样本的大量内部技术细节,甚至无需启动 IDA 或调试器。
-logdir [ .] 日志目录,用于打印库调用数据
-only_from_app [ false] 仅报告来自应用程序的库调用
-follow_children [ true] 跟踪子进程
-print_ret_addr [ false] 打印库调用的返回地址
-num_unknown_args [ 2] 要打印的未知库调用参数数量
-num_max_args [ 6] 要打印的最大参数数量
-default_config [ true] 使用默认配置文件。
-config [ ""] 自定义配置文件的路径。
-filter [filter.config] 白名单/黑名单文件的路径。
-ignore_underscore [ false] 忽略以下划线开头的库例程名称。
-help [ false] 打印此消息。
-version [ false] 打印版本号。
-verbose [ 1] 更改详细程度。
-use_config [ true] 使用配置文件
-grepable [ false] 可 grep 的输出
Drltrace 支持外部配置文件,用户可以在其中描述 drltrace 应如何打印特定 API 调用的参数。
HANDLE|CreateRemoteThread|HANDLE|SECURITY_ATTRIBUTES*|size_t|THREAD_START_ROUTINE*|VOID*|DWORD|__out DWORD*
每个函数参数应由 | 分隔。第一个参数是返回类型,第二个参数是函数名称本身,其余为函数参数。标记 __out 用于表示输出参数,___inout 用于表示输入+输出参数。
您可以在我们的 Wiki 页面 找到如何使用 drltrace 分析复杂恶意软件的示例。
为了更方便地处理日志文件,我们实现了一个名为 api_calls_viz.py 的脚本,可用于生成 RGB 图像,其中每个像素颜色代表一个唯一的 API 调用。例如,下图表示 WannaCry 恶意软件的日志文件。

图中大片的绿色区域代表 API 调用(wcscmp/wcsicmp),用于选择具有有趣扩展名(例如 docx, xls, py)的文件进行加密。紫色区域代表 API 调用(FindFirstFile/FindNextFile/CryptEncrypt),用于枚举和加密磁盘上的文件和文件夹。
该脚本还可以生成生成的 RGB 图像的 HTML 表示,其中每个元素都可以选择以显示 API 调用的名称。

有关更多详细信息,请参见 api_calls_viz 目录。
您可以在 Wiki 页面 找到详细手册。
Windows、Linux(未来支持 macOS)。
x86、x64(ARM 在列表中)。
C 和 C++ 标准库(以及用 Python 编写的日志处理脚本)。
我们决定基于动态二进制插桩框架 DynamoRIO 实现我们的 API 调用跟踪器。Drltrace 要求 DynamoRIO 对 LoadLibrary 调用进行插桩,以便能够处理目标进程加载的新库。当进程尝试加载新库时,DynamoRIO 将控制流重定向到 drltracelib.dll。反过来,drltrace 枚举新加载 DLL 中的导出函数,并为每个函数注册一个特殊的回调。因此,如果恶意软件调用了某个导出函数,drltrace 的回调将在此函数之前执行,该工具将能够记录所有必要的信息,例如函数名称和参数。还可以在函数之后注册另一个回调以保存执行结果。
为什么不用 Intel Pin?我们选择使用 DynamoRIO 的原因如下:
drrun.exe 的 -syswide_on 选项)。然而,未来有必要在 drltrace 中为这种情况实现特殊支持。我们的问题跟踪器包含更多关于 drltrace 未来的详细信息。
Maksim Shudrak https://github.com/mxmssh