首页
社区
课程
招聘
[翻译] 使用S2E分析基于触发器的恶意软件
发表于: 2018-9-13 16:06 7046

[翻译] 使用S2E分析基于触发器的恶意软件

2018-9-13 16:06
7046

这篇博客是上个月我在 瑞士联邦理工学院可信系统实验室做的一项工作,当时我正在用S2E分析恶意软件。尽管没有特别出彩的地方,但我希望这篇文章可以帮到那些想要用符号执行/S2E来分析恶意软件行为的人。

我之前发了2篇文章,一篇是关于 CTF challenge 的,另一篇是分析 文件解析器的。这些程序有两个共通之处:

相对来说,大多数软件:

由于这些原因,在S2E中分析恶意软件不太容易将命令行参数符号化,或者向程序输入符号文件。这篇文章会探索我们基于S2E开发的恶意软件分析工具,后面会有两个”研究实例“。像往常一样,如果你希望自己研究一下的话,可以在 Github上找到所有的代码。

直到现在,我们只用 S2E 分析过 Linux 程序。幸运的是,S2E也支持 Windows 程序的分析,所以两者的区别在哪呢?

有许多不同的技术可以实现 hook Windows API,我们会使用现有的办法而非再去发明一种新的。当我刚开始这项工作时,我想重用Cuckoo SandboxMonitor 来 实现对API 的hook(它就是为了分析恶意软件而设计的)。然而,后来我们决定用 EasyHook 的办法,主要是因为它在开始阶段需要更少的工作。

在开始深入研究代码前,先看下我们下面要做的:

现在让我们深入研究一些代码!

在 Visual Studio 中 打开 $S2EDIR/source/s2e/guest/windows/s2e.sln ,创建两个项目:

这两个项目都需要 EasyHook 的本地包, 通过 Nuget 安装。 注意在Github 上的 malware-hook 项目分为 GetLocalTime-hookwannacry-hook 两个项目 (我们的研究实例)。

malware-inject 基于 EasyHook 的样例程序 injector 。在这里,我们使用 RhCreateAndInject 而非RhInjectLibrary (将 DLL 注入已经运行的程序)。 我们使用这个函数启动处于挂起状态的应用程序,注入DLL,然后恢复挂起进程。malware-inject还会在返回之前等待注入的进程完成,这非常有用,因为它可以防止当malware-inject 进程退出时 S2E 终止状态。

创建 inject.c 文件,把下面的代码加进去:

当然,恶意软件完全可能会监视 API 的 hook(毕竟我们正在处理恶意软件),尽管这是一个重要问题,但在这里不做过多探讨。

既然我们已经编写了可以将 DLL 注入恶意软件的工具,那么让我们把注意力转向这个 DLL 实际要做的事情。

同样 ,我们将基于 EasyHook 的样例 程序 BeepHook 来 实现malware-hook ,下面是我们 hook 的 DLL 的框架, 也就是 malware-hook.cpp 的内容:

那么,我们要hook 什么呢? 我们可以从两篇关于这个主题的优秀论文中获得一些灵感:David Brumley的“自动识别恶意软件中基于触发器的行为“ 和Andreas Moser的 “探索恶意软件分析的多个执行路径”。 这两篇论文都着眼于“基于触发器的恶意软件”,即恶意软的恶意行为仅在特定场景下发生,例如,当满足特定触发条件时。举个例子,恶意软件可能只在特定日期(如 MyDoom 蠕虫那样)启动其有效负载,或者从命令和控制服务器接收特定数据。 在这两个示例中,触发源是当前日期/时间和从网络读取的数据。 其他触发源包括(如Moser的论文中所列的):

我们如何分析基于触发器的恶意软件? Brumley的论文提出了Minesweeper,用来检测基于触发器的行为的存在,并找到执行这些行为的输入。 据我所知,Minesweeper从未公开发布过。但是,我们可以通过使用 malware-hook DLL,在S2E中搭建一个非常相似的系统!因此,让我们继续为这两篇论文中讨论的一些触发源创建 hook 。

Brumley 的论文探索的第一个触发源是 GetLocalTimeGetLocalTime 的原型 如下:

在 Minesweeper 中,用户需要指定内存中的触发输入存储的位置。因此,符号执行引擎可以在执行期间正确地分配符号变量。在GetLocalTime 的例子中,需要指定GetLocalTime将其结果存储在调用GetLocalTime时由堆栈值指向的16字节结构中。 幸运的是,我们不必担心这些底层的细节。相反,我们可以在传递给GetLocalTime的变量上调用S2EMAKECONCOLIC 。下面是 malware-hook 中的实现方法:

我们来实现一下 Brumley et al 的论文中的例子(图 1.1)来看下是否和预期的一样:

确保你是在x86平台上编译的这些项目(因为使用的是32-位 的Windows 7 虚拟机)。一旦编译完成(包括虚拟机),我们就能够创建一个新项目:

注意这会直接创建一个bootstrap.sh 脚本 执行 GetLocalTime-test.exe 。我们需要修改 bootstrap.sh 以便让 malware-inject.exe 执行 GetLocalTime-test.exe。为了实现这个目的,需要有在虚拟机中访问 hook 工具的权限。通过下面的命令,创建符号链接即可:

然后编辑 bootstrap.sh

最后,可以在 s2e-config.lua 中禁止下面的插件(不是必要的):

现在准备开始分析!

可以看到,在分析过程中,fork 了四次。 如果 开启 --verbose-fork-infoKLEE 参数的话 (在 s2e-config.lua 中), 我们可以看到在这四个分叉点中生成的约束。下面的图片是这些点高亮的反汇编代码:

GetLocalTime-test fork points

ReadLSB w16 X SystemTime可以理解为 在符号变量SystemTime的偏移X处 “读取 16 位 (i.e. 一个字) 。 如果我们在MSDN上查看SYSTEMTIME的结构,可以看到这些偏移处的每个字(0x60x80x20xA)分别对应于wDaywHourwMonthwMinute字段 - 正如预期的那样。最后,可以在debug.txt中发现一行包含以下的测试用例(我重新格式化并添加了字段名称以便于阅读):

如果我们在GetLocalTime-test/test.c上交叉引用它,就能看到这次造成了 DDOS,成功了!

看起来不错,但是从2007年Minesweeper 论文写完到现在,恶意软件已经发生了很大的变化。让我们看一下最新的东西-- WannaCry 勒索软件。 WannaCry 里有一个隐藏开关,可以阻止勒索软件加密目标数据。这个开关会检查 病毒是否可以访问一个奇怪的域名时,如果访问到的话,病毒终止运行(此检查可能是为了欺骗动态分析工具,工具通常被配置为对所有网络查询返回有效的、虚拟的响应)。 考虑到这一点,让我们使用S2E来探索WannaCry 在触发条件满足和不满足时的行为。我们将重点关注 Amanda Rousseau 出色的 writeup 中的样本(SHA1 哈希值 24d004a104d4d54034dbcffc2a4b19a11f39008a575aa614ea04703480b1022c)。

看下 WannaCry killswitch 的反汇编代码:

可以看到 WinINet API用于打开与 隐藏开关 URL的连接(hxxp://www[.]iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea[.]com)。调用以下函数来执行此操作:

最小限制下,我们需要hook InternetOpenUrlA,并强制 fork 以探索 0x4081a5 处的两条路径。InternetOpenA 呢? 可以在WannaCry代码中看到InternetOpenA返回的HINTERNET句柄永远不会被检查,所以我们不必担心这个函数。 如果(正确地)检查了返回的句柄,我们可能就需要 hook 掉InternetOpenA 并强制它返回一些虚拟的非空值。类似地,如果我们对InternetOpenA失败时执行的代码感兴趣,我们也可以强制使用fork获取一些符号值。但是,为了简便起见,我们只关注 InternetOpenUrlA,下面开始我们的工作。

首先,在 malware-hook.cpp 换掉我们要 hook 的 函数,像下面这样:

然后写入实际要 hook 的函数:

在这里,我们遵循S2E的 多路径故障注入教程 中采用的方法。 returnResource符号变量强制使用 fork,导致InternetOpenUrlA成功的一个状态(通过返回虚拟资源)和InternetOpenUrlA失败的另一个状态(通过返回NULL)。 我们可以返回一个虚拟资源句柄,因为InternetOpenUrlA句柄从未实际使用过:记住,WannCry 只检查它是否为NULL。 然后,InternetCloseHandle hook 清除已分配的内存,现在让我们在S2E中 hook 并运行WannaCry。

我们可以按照与GetLocalTime-test相同的步骤为 WannaCry 建立S2E项目,记得在 bootstrap脚本中为Easystook32.dllmalware-hook.dllmalware-inject.exe创建符号链接, 并且 s2eget 它们 。

在运行S2E之前,请在s2e-config.lua中启用LibraryCallMonitor插件。 该插件监视并记录外部库函数调用,这能更好地帮助我们了解 WannaCry 正在做什么。 当您运行S2E时,您应该看到malware-hook在地址空间中的fork(可能隐藏在LibraryCallMonitor生成的大量调试输出中)。 如果您按照WannaCry可执行文件所做的库调用(而不是加载其地址空间中所有其他的DLL),您应该在状态0中看到以下库调用:

处于状态1 时,你应该看到:

这看起来不错:当隐藏开关被触发时,我们已成功探索了WannaCry的行为。 Rousseau的文章概述了WannaCry的执行流程,如果我们遵循状态1的库调用,我们应该看到执行流程是匹配的。

开始写最后一个 hook,如果我们 hook 的进程又产生一个新进程会发生什么呢? 这对于“dropper”类恶意软件来说非常常见,而 WannaCry 确实通过从资源加载可执行文件(tasksche.exe),将其写入磁盘然后运行它(通过CreateProcessA)来实现这一点。 当发生这种情况时,我们完全不知道这个新进程正在做什么:在通过我们的hook 注入符号化的数据和用S2E跟踪其行为方面(例如通过LibraryCallMonitor插件)。

我们可以通过 hook CreateProcessA 并使用 EasyHook API 将 malware-hook 注入此新进程来解决这个问题(失去将符号数据注入新进程的能力), 下面的代码实现了这一点:

这个 hook 会 启动处于 挂起状态的新进程,并将其自身注入新进程,而malware-hookNativeInjectionEntryPoint 函数就负责唤醒进程。

这解决了将符号数据注入 WannaCry 产生的新进程的问题,但如何在S2E中跟踪这个新进程的行为呢?不幸的是,这需要更多的工作。一种方法是编写一个S2E插件,用于监听OSMonitoronProcessLoad信号。如果发现新进程来自 WannaCry 进程,我们可以将新的子进程添加到ProcessExecutionDetector的跟踪模块。然后,LibraryCallMonitor将开始为这个新进程发出onLibraryCall事件,允许我们跟踪它的行为。因为我不想在这篇文章中编写S2E插件,所以我将其留作“读者练习”。

还有最后一个问题:原始的WannaCry进程在启动tasksche.exe 就结束了。这导致malware-inject也退出了(记住它调用WaitForSingleObject),导致bootstrap脚本终止当前状态(在我们的例子中,这是状态1,它对应于InternetOpenUrlA返回为NULL的状态)。这有效地杀死了S2E,因为我们只有一个活动状态。有一种简单的方法可以解决这个问题:在bootstrap脚本中执行调用之后添加一个sleep命令(不要忘记设置适当的 sleep时间)。但这也意味在状态0 时,我们会在 WannaCry 早早退出之后还在浪费时间等待。但是,如果您在launch-s2e.sh中添加 sleep 并注释掉GRAPHICS = -nographic(用来启用QEMU GUI),最终会看到下面的效果:

WannaCry infection

在这篇文章中,我们研究了使用S2E分析 Windows 恶意软件,实质上是在S2E中重新创建了 David Brumley 的Minesweeper工具。 与我们在之前的帖子中看过的程序不同,我们不得不想出一些新的技术来将符号化的数据注入到Windows程序中。 我们使用EasyHook来 hook 那些恶意软件常用来隐藏它们行为的“触发”函数。 虽然这种方法适用于我们的两个研究实例(这些案例被认为是高度人为的),但仍有许多改进途径。 这些途径包括:

希望这篇文章为您提供必要的背景和工具,以便了解其中的一些改进。也许有一天我甚至会找时间亲自看看其中的一些!

原文地址:https://adrianherrera.github.io/post/malware-s2e/

本文由 看雪翻译小组 fyb 波 编译

本文由 看雪翻译小组 银雁冰 校对

 
 
 
 
 
 
 
 

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2018-9-13 16:12 被fyb波编辑 ,原因: 格式选择错误
收藏
免费 1
支持
分享
打赏 + 1.00雪花
打赏次数 1 雪花 + 1.00
 
赞赏  junkboy   +1.00 2018/09/15
最新回复 (2)
雪    币: 3302
活跃值: (1144)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
2
另外,作者去年写的那篇关于文件解析器的 译文链接在这 https://bbs.pediy.com/thread-222349.htm
最后于 2018-9-13 16:15 被fyb波编辑 ,原因:
2018-9-13 16:14
0
雪    币: 1535
活跃值: (695)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2018-9-13 17:50
0
游客
登录 | 注册 方可回帖
返回
//