一、简介
本文是对16年的blackhat大会上PinDemonium通用动态脱壳工具介绍。
1. 通用脱壳工具简介
通用脱壳工具可以通过以下方法实现:
- -debuggers
- -kernel modules
- -hypervisor modules
- -Dynamic Binary Instrumentation (DBI) frameworks
其中PinDemonium采用的就是DB的方法。
采用DBI主要原因是:
- DBI 提供了对待分析二进制文件非常细粒度的控制,可以全面控制程序执行的代码,深入分析程序做了什么
- 对反调试和反汇编技术免疫
- 有丰富且文档完备的API集合用于从运行的程序中提取出信息,能改变程序运行时的行为
2. PinDemonium原理
通常,程序的一个内存地址要么可写,要么可执行,满足Write xor Execution (WxorX)规则。但是加了壳的软件会违反这条规则。
通用脱壳工具原理:加壳的可执行文件必需在运行时脱壳。脱壳过程中会向内存中写入新的代码,然后执行写入的代码。利用上述特性来构建通用脱壳工具。
通用脱壳工具必须解决的两个问题:
- 找到Original Entry Point(OEP);
- 修复Import Directory来重构可执行的版本。
***个问题只能通过启发式的方法解决,因为脱壳过程什么时候结束是不可判定的。PinDemonium 综合多个文献中提出的启发式方法来增加找到OEP的可能性,并且重新构建一个可执行的版本。
第二个问题要找到Import Address Table(IAT),从而找到相关的API。
PinDemonium 也是利用通用脱壳工具的原理。记录被写过的地址来发现写后执行的内存区域,当被写过的内存区域要被执行时触发转储和分析功能,然后尝试找到程序所有的导入函数来重构一个可执行的程序。
3. PinDemonium特点
PinDemonium 先进性:
- 考虑了堆上的代码;
- 解决一些IAT混淆技术;
- 综合多种OEP检测启发式方法来找到***的可执行的去混淆后的程序。
PinDemonium 主要特点:
(1) PinDemonium 的核心模块记录写过的地址(包括对远程进程的写),当发现写后执行的情况,就用 Scylla 对程序进行dump。
(2) 对 Scylla 进行了改进:
- PE重构模块:增加了对动态内存区域(例如堆)的考虑
- IAT搜索和重构模块:允许分析人员编写自己的去混淆代码并集成到 PinDemonium 中
(3) 为了保持性能和简化识别写后执行代码的过程,忽略和脱壳无关的指令,如写栈和写Process Environment Block(PEB)
(4) 通过设置 PinDemonium 的一些标志可以开启 PinDemonium 相应的功能来对付某些壳所使用的技巧
二、构成
PinDemonium 使用了两个第三方工具:插桩工具Intel PIN和Scylla。
1. Intel PIN
PinDemonium 选择插桩来实现通用脱壳工具, 因为:
- 插桩提供了对待分析二进制文件非常细粒度的控制,可以全面控制程序执行的代码,深入分析程序做了什么;
- 插桩对反调试和反汇编技术免疫;
- 插桩有丰富且文档完备的API集合用于从运行的程序中提取出信息,能改变程序运行时的行为。
选择Intel PIN,因为PIN功能全面,文档丰富。
PIN 插桩的粒度可以是:
- Instruction:一条汇编指令;
- Basic blocks:以条件跳转结尾的指令序列;
- Trace:以无条件跳转结尾的基本块序列。
PIN插桩粒度如图1所示
图1
利用插桩可以实现多种功能,如图2所示,一个利用插桩计算程序指令数的例子。
图2
pintool是用户开发的dll来实现想要的功能。pintool 必须包含两个部分:
- Instrumentation routines:代码收集完毕后执行的回调函数,可以用于分析代码属性和在适当位置插入Analysis routines。
- Analysis routines:可以在当前指令执行前或执行后执行的函数。
如图3所示,显示了PIN的流程。
图3
2. Scylla
Scylla的两个主要功能是IAT搜索和Import Directory重构。其中,IAT搜索部分,Scylla使用两种技术搜索IAT:基本IAT搜索和高级IAT搜索。
(1)基本IAT搜索
- Scylla 接受一个开始地址作为输入,从开始地址开始搜索IAT;
- 扫描包含开始地址的可执行页面中的call和jump指令,这些指令的每个目标地址作为可能的IAT入口指针;
- 目标地址中的值和所有导入函数地址进行比较,如果没有一致的,目标地址就被淘汰;
- 从上述步骤找到的IAT入口地址开始扫描内存,直到遇到4个0字节,这样就找到 IAT 的结束地址。同样,反向扫描就可以找到开始地址。
(2)高级IAT搜索
对所有可执行页面而不是仅仅对包含开始地址的可执行页面来搜索IAT。
三、系统结构
PinDemonium系统结构如图4所示:
图4
从图中可以看出,PinDemonium主要包括5个模块:
- WxorX handler module
- Hooking Module
- Dumping module
- IAT search and reconstruction Module
- IAT Fixing and Import Directory Reconstruction
1. WxorX handler module
WxorX handler module是PinDemonium的核心模块。WxorX handler module记录写过的地址(包括对远程进程的写),当发现写后执行的情况,就用Scylla对程序进行转储。
为了检测写后执行,实现的两个重要功能:
(1) Written addresses tracking:记录被写过的每个内存地址来创建 Write Interval(WI)。WI 是一个结构体,记录一片被写过的连续内存,包含以下信息:开始地址,结束地址,是否已分析的布尔标志,对 WI 所有启发式方法的结果。图5显示了对2个WI进行合并的三种情况。为了保持性能和简化识别写后执行代码的过程,忽略和脱壳无关的指令,如写栈和写Process Environment Block(PEB)。
图5
(2) Write xor Execution (WxorX) addresses notifier:检查现在执行的指令是否在WI中,如果是,执行以下分析:
- Dump 违反 WxorX 规则的内存区域。内存区域的位置包含3种情况:PE 文件主模块,堆上的内存,其他程序的内存中;
- 重构 IAT 并生成正确的 Import Directory;
- 运用一系列启发式方法(熵,长跳转等)来评估目前的指令是否是 OEP。
WxorX addresses notifier 用于触发转储功能,当某个WI***次被违反WxorX规则进行转储。为了解决图6的情况,当同一个WI中的跳转大于阈值时也会进行转储。
图6
PinDemonium hook系统调用来发现对远程进程的写,用hashmap将pid映射为WI,监控用于执行注入载荷的相关函数,当发现对远程线程的写后执行时,PinDemonium转储远程进程被写过的内存并调用启发式方法对转储结果进行评价。
2. Hooking Module
Hooking Module 利用 Intel PIN 的功能对API和系统调用进行hook以达到跟踪程序行为的目的。图7显示的是对API的hook。
图7
图8显示的是对系统调用的hook。
图8
3. Dumping module
许多内存转储工具,只会转储目标程序的主模块,遗漏了动态内存区域(例如堆)上的代码,如图9所示。
图9
Dumping Module依赖于 Scylla。PinDemonium对 Scylla 进行了改进:将Scylla的PE重构模块增加了对动态内存区域(例如堆)的考虑。PinDemonium将堆上的WI标记为heap write interval,当heap write interval违反WxorX规则,不仅转储程序主模块,还向转储中添加新的节来包含heap write interval的内容并将Entry Point设在这个节内,如图10所示。
图10
图11显示的是利用Scylla来转储。
图11
4. IAT search and reconstruction Module
为了获得更好的结果,PinDemonium综合运用Scylla的基本IAT搜索和高级IAT搜索功能,如图12所示。
图12
5. IAT Fixing and Import Directory Reconstruction
没有能解决IAT混淆的通用技术,所以PinDemonium对Scylla进行改进,让分析人员能自己编写去混淆代码并集成到 PinDemonium 中。PinDemonium 实现了一种能够解决图13所使用的IAT混淆技术的算法。
图13
6. Heuristics implementation
PinDemonium 使用启发式方法对获得的转储进行评估,每个启发式方法可以在最终生成的报告中设置一个标志位,所有的的标志位帮助识别***的转储。有4种启发式方法:
(1) 熵:图14显示了加壳前后MessageBox程序的熵的情况。加壳后熵明显增加。所以可以对比脱壳前后熵的变化大小是否超过阈值来对脱壳结果进行判定。
图14
(2) 跳到节外:程序脱壳完毕后,调到OEP执行时通常会从一个节跳到另一个节,利用这一特点来对脱壳结果进行判定。
(3) 长跳转:如图15,程序脱壳完毕后,跳到原始代码去执行的情况通常不是(a)和(b)那种短跳转而是(c)那种长跳转,利用这一特点来对脱壳结果进行判定。
图15
(4) pushad popad:脱壳的过程中是否出现了pushad和popad这两条指令,如果都出现了就在报告中设置对应的标志位。
四、实验效果
实验一,已知加壳类型的实验,实验结果如图16:
图16
实验二,未知加壳类型,样本来源于virustotal,实验结果如图17:
图17
五、使用
本人由于实验需求,利用vmware搭建了PinDemonium环境,实现批量脱壳。
- pin -t PINdemonium.dll -- path-of-smaples\name-malwr.exe
通过这个指令可以实现样本的脱壳,脱壳结果截图如图18:
图18
设置 PinDemonium 的一些命令行参数可以开启PinDemonium相应的功能来对付某些壳所使用的技巧。