每天在JSOC CERT,我们都会遇到来自各种沙盒的事件,这些沙盒是客户的AntiAPT解决方案的一部分,并让来自Web和电子邮件流量的成千上万个文件通过它们。 值得注意的是,现代沙盒系统的发展远不止是在内核模式下拦截系统调用和在用户模式下拦截API函数。 他们越来越多地使用自己的虚拟机管理程序,该系统用于模拟用户活动,动态检测,对代码段进行散列和群集,对代码覆盖率进行分析等。 如此多种多样的技术产生了一种幻觉,即如果某个文件无法在沙箱中工作并且无法显示其“真实面孔”,那么这可能是APT或一种用于检测虚拟环境的创新技术,IB社区尚未意识到这一点。 但是...
由于我们不了解商业沙箱的内部功能,因此在某些情况下,我们会进行仔细检查-手动分析通过测试的样本。 最近,我们多次遇到一些商业沙箱(出于客观原因,我们无法说出哪个沙箱)在动态分析期间未检测到某些恶意文件,并且如果静态分析器也保持沉默,则该文件将被完全跳过。
沙盒扫描成功绕过了Pony,Loki和Hawkeye等著名的恶意软件家族。 只有一件事将它们结合在一起-它们被Visual Basic编写的打包器覆盖。
鉴于这些HPE系列一直以来都不是什么新鲜事物,因此“积极的”沙盒判决非常令人沮丧。 因此,我们决定描述此封隔器的一般工作原理以及我们在一段时间内所做的观察。
包装工的总体工作方案有条件地分为四个阶段,如下图所示。

恶意文件的入口点看起来是Visual Basic应用程序的典型代表:

我们遇到了这个打包程序的各种选项,并且VB包装程序代码经常更改,但是执行的任务仍然相同:将控制转移到第1阶段代码。在较早的示例中,使用Enum *类API函数(例如EnumWindows,EnumCalendarInfo等)转移了控制权。 e)将代码的地址阶段1指示为参数。 最近,我们观察到控制权是直接转移的。
第一阶段
管理层收到代码1。此代码未加密,但被混淆。 混淆方法因样本而异,但是常规运算算法不会改变:
- 具有许多(包括垃圾)指令的循环,该指令生成解码第2阶段代码所需的密钥。 这段代码的独特之处在于没有睡眠功能,但是由于迭代次数众多,其执行平均需要1-2分钟。
- 解密(常规XOR)并将控制权转移到第2阶段代码。
下面的屏幕截图显示了使用的混淆方法的示例:

2阶段
第2阶段代码的主要任务是检查环境并实现反调试方法。 代码的某些部分被加密(在执行之前解密,然后在执行之后,使用相同的XOR算法加密回去),从而使签名难以检测。 解密后,可以看到特征,根据这些特征,可以通过手动分析识别第2阶段代码。

检查列表很大,并且在不同版本的打包程序中有所不同,因此我们将提供一些在所有版本中都带有屏幕快照的方法,最后在表中列出整个列表。
1)GetTickCount +睡眠
获取当前时间戳,调用Sleep 2秒钟,然后立即获取另一个时间戳。
之后,检查标记之间的差异(是否实际经过了2秒)。

2)SetErrorMode
检查SetErrorMode API调用的正确操作。 使用参数0x800和0x0连续调用该函数两次,然后检查第二次调用的结果:它必须等于0x800。

3)SetLastError
首先,调用参数为0x5的SetLastError,然后检查是否正确设置了TEB中的Last error code值(即为0x5)。

4)检查光标移动
代码进入一个无限循环,等待鼠标移动。

5)DbgBreakPoint和DbgUiRemoteBreakin
修改了这些功能,以防止调试器连接到进程。

技术
| 评注
|
GetTickCount +睡眠
| 检查时间戳
|
SetErrorMode
| 检查功能是否正常
|
SetLastError
| 检查功能是否正常
|
GetCursorPos
| 检查光标移动
|
dbgbreakpoint
| 功能修改以防止调试器附加
|
DbgUiRemoteBreakin
| 功能修改以防止调试器附加
|
挂钩删除
| 万一有钩子,函数的前5个字节将在ntdll.dll中恢复
|
NtSetInformationThread
| 参数0x11(ThreadHideFromDebugger)
|
GetThreadContext +检查DR
| 检查调试寄存器DR0-DR3,DR6,DR7。
|
检查断点
| 检查某些功能开头的指令INT3(0xCC),int 3(0xCD 0x03)和ud2(0x0F 0x0B)
|
cpuid(EAX = 0x0)
| 检查寄存器EAX,ECX,EDX
|
cpuid(EAX = 0x40000000)
| 检查寄存器EAX,ECX,EDX
|
cpuid(EAX = 0x1)
| 第31个ECX位已检查
|
PEB(已调试)
| 检查值0x1
|
PEB(NtGlobalFlag)
| 检查值0x70
|
NtQueryInformationProcess
| 通过标志ProcessDebugPort(0x7),ProcessDebugFlags(0x1F),ProcessDebugObjectHandle(0x1E)进行调用
|
进程名称检查
| 检查字符串“样本”,“沙盒”,“病毒”,“恶意软件”,“自我”。
|
如果完成了阶段2的所有技术,则将检查命令行是否符合特殊格式。 如果检查失败,则执行以下操作:
1)使用CREATE_SUSPENDED标志调用CreateProcess函数以重新启动当前进程。 在这种情况下,命令行具有必需的格式。
2)使用GetContextThread和SetContextThread函数,将入口点更改为位于阶段1代码中的新入口点。
3)重复步骤1和2(包括长周期和所有检查)。 这次,命令行检查成功,并且过程继续进行到下一步。
3阶段
在此阶段,将对主要病毒的主体进行解密,并对当前进程执行过程中空技术,然后将控制权转移到主要病毒的入口点。
经验教训
在这种情况下,我们无法确切说明是什么原因导致了这个或那个沙箱,但我想相信,供应商已经为使用恶意软件中的文章中描述的技术提供了很长一段时间的可能性,而问题仅在于打包程序第一阶段的长时间延迟。
尽管事实上,现代沙箱在很大程度上是作为针对APT攻击的保护系统的一部分,但我们的观察结果表明,即使是社区众所周知的恶意家庭也以令人羡慕的稳定性渗透到基础架构中。 由于无法保证绕过沙箱的样本在其军械库中不会使用几种防病毒绕过技术,因此您不能依靠这一系列保护性解决方案。 在这种情况下,适当构建的监视过程(包括来自最终主机的信息安全事件)可以确保及时响应并最大程度地减少潜在损害。