延迟执行

因为沙箱对样本运行时间有限制,使用已知的windows Api(例如NtDelayExecution,CreateWaitTableTImer,SetTimer等)将恶意代码的执行延迟了一段时间。

延迟执行 - GetTickCount

检查机器运行时间,创建超过设定时间的快照即可使计算机运行更多时间,即可绕过。
反虚拟机、反沙箱技术整理汇总 - 图1

延迟执行 - API泛洪

在循环中调用垃圾API以引入延迟
反虚拟机、反沙箱技术整理汇总 - 图2
Win32/Cutwail

延迟执行 - 内联汇编

引入内联汇编代码,设置较大的计数。
反虚拟机、反沙箱技术整理汇总 - 图3

硬件检测

对硬件进行指纹识别,特别是检查总物理内存大小,可用的存储大小/类型和可用的CPU内核数量。例如通过Windows API DeviceIoControl()与特定的控制代码一起使用,以检索有关存储类型和存储大小的信息。

硬件检测 - 储存空间检查

反虚拟机、反沙箱技术整理汇总 - 图4
另外,可以通过WMI接口获取系统信息时,而hook com的资料很少。

硬件检测 - CPU温度检查

检查涉及检查执行中的处理器的温度,该检查通过系统中的WMI调用执行。因为VM系统在此调用之后将永远不会返回结果。
反虚拟机、反沙箱技术整理汇总 - 图5

硬件检测 - CPU核心数量

最初基于API来获取信息,后来都采用WMI和更隐蔽的基于PEB访问的方法。
反虚拟机、反沙箱技术整理汇总 - 图6
更隐秘的方法是访问PEB,通过引入内联汇编代码或使用inline函数来实现。

反虚拟机、反沙箱技术整理汇总 - 图7
反虚拟机、反沙箱技术整理汇总 - 图8

另一种方法,MSDN定义.aspx),“ProcessAffinityMask”是一个位向量,其中每个位代表允许进程在其上运行的处理器。系统相似性掩码是一个位向量,其中每个位代表配置到系统中的处理器。恶意软件使用这种通过获取GetProcessAffinityMask API来获取核心计数的新方法。API返回掩码,该掩码可以轻松识别正在使用的内核数。
反虚拟机、反沙箱技术整理汇总 - 图9
在上面的示例中(样本md5:53f6f9a0d0867c10841b815a1eea1468),如果核心计数小于2,则恶意软件仅终止而不执行其有效载荷:
反虚拟机、反沙箱技术整理汇总 - 图10

硬件检测 - 基于COM的DirectShow的音频检测

反虚拟机、反沙箱技术整理汇总 - 图11
上面的代码不仅在检查音频设备的存在,而且还验证API是否完全可操作(可能是为了过滤掉不完整的API仿真)。

代码 描述
CoCreateInstance(CLSID_FilterGraph,IID_IGraphBuilder) 标准DirectShow初始化,不检查错误代码
E_POINTER!= pGraph-> AddFilter(NULL,filterName) 第一次反仿真检查:如果以NULL作为第一个参数调用AddFilter,则它应返回E_POINTER错误代码。一些仿真器可能以通用方式实现未知的COM接口,因此它们可能会在此处失败。
CoCreateInstance(CLSID_AudioRender,IID_IBaseFilter) 初始化一个简单的Audio Renderer,创建失败时pBaseFilter将设置为NULL,但是这里不检查错误
pGraph-> AddFilter(pBaseFilter,filterName) 将先前创建的音频渲染器添加到“过滤器图表”,不进行错误检查
pGraph-> FindFilterByName(filterName,&pBaseFilter2) 试图找到刚刚添加的过滤器;如果以前没有检查过任何错误(或错误的仿真),则此功能将找不到过滤器,并且将成功检测到沙箱/仿真器。
pBaseFilter2-> QueryFilterInfo(&info) 检查info.achName是否等于之前添加的filterName-如果不正确-API仿真不正确
pBaseFilter2-> GetSyncSource(&pClock) 检查API是否设置正确的IReferenceClock指针
pBaseFilter2-> GetClassID(&clsID) 检查CLSID是否不同于0
pBaseFilter2-> EnumPins(&pEnum) 只是检查通话是否成功
pBaseFilter2-> AddRef() AddRef返回的引用计数必须大于0

这些只是一些随机检查,以确保恶意软件在真实系统上执行。仅在此沙箱安装了音频设备后,它才被视为真实系统。大多数仿真器都会失败,因为几乎不可能为现代操作系统中存在的每个COM接口实现适配支持。

  1. #include "stdafx.h"
  2. #include <windows.h>
  3. #include <dshow.h>
  4. #include <Strmif.h>
  5. #pragma comment(lib,"Strmiids.lib")
  6. int tmain(int argc, TCHAR* argv[])
  7. {
  8. CoInitialize(0);
  9. wchar_t * filterName= L"random_name";
  10. IGraphBuilder * pGraph;
  11. CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraph); //图形过滤对象
  12. if (E_POINTER != pGraph->AddFilter(NULL, filterName))
  13. {
  14. MessageBoxA(0, "检测到沙箱L !\n", 0, 0);
  15. }
  16. IBaseFilter* pBaseFilter = NULL;
  17. CoCreateInstance(CLSID_AudioRender, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pBaseFilter);
  18. pGraph->AddFilter(pBaseFilter, filterName);
  19. IBaseFilter* pBaseFilter2 = NULL;
  20. pGraph->FindFilterByName(filterName, &pBaseFilter2);
  21. if (NULL == pBaseFilter2)
  22. {
  23. MessageBoxA(0, "检测到沙箱2L !\n", 0, 0);
  24. }
  25. FILTER_INFO info = { 0 };
  26. pBaseFilter2->QueryFilterInfo(&info);
  27. if (0 != wcscmp(info.achName, filterName))
  28. {
  29. return 0;
  30. }
  31. IReferenceClock * pClock;
  32. if (0 != pBaseFilter2->GetSyncSource((&pClock)))
  33. {
  34. return 0;
  35. }
  36. if (0 != pClock)
  37. {
  38. return 0;
  39. }
  40. CLSID clsID;
  41. pBaseFilter2->GetClassID(&clsID);
  42. if (clsID.Data1 == 0)
  43. {
  44. exit(1);
  45. }
  46. if (NULL == pBaseFilter2)
  47. {
  48. exit(-1);
  49. }
  50. IEnumPins* pEnum = NULL;
  51. if (0 != pBaseFilter2->EnumPins(&pEnum))
  52. {
  53. exit(-1);
  54. }
  55. if (0 == pBaseFilter2->AddRef())
  56. {
  57. exit(-1);
  58. }
  59. MessageBoxA(0,"没有检测到沙箱,执行病毒代码!\n",0,0);
  60. system("pause");
  61. return 0;

}

检测用户输入

在真实的机器中,诸如键盘或鼠标活动之类的用户输入将是频繁发生的事件,或者至少是最终发生的事件。但是传统的沙箱通常不会有任何用户输入,也不会足够模拟用户的I/O活动以欺骗恶意软件。由于这些限制,高级恶意软件可以利用这种差异(缺少用户输入)来检测沙箱。

示例1 检查输入时间间隔

为了获得自上次收到用户输入以来的空闲时间,恶意软件通常会使用GetLastInputInfo.aspx)和GetTickCount.aspx)函数的组合。
样本(md5:5bd308c1b32178098c8202cff5b02a28)示例:
反虚拟机、反沙箱技术整理汇总 - 图12

对上面的代码进行检查后发现,它在无限循环内执行以下逻辑:

  1. 通过从LASTINPUTINFO.dwTime中减去当前计数来获得空闲输入计数。
  2. 如果空闲输入计数小于100且不等于最后一个空闲计数,则将其视为“正确的空闲输入时间”并将其添加到计数器中。
  3. 如果正确的空闲时间计数器次数 > 10,则跳出循环
  4. 睡眠11毫秒

为了测试代码是否在真实系统上运行,此恶意软件示例将无限期等待用户输入。如果是在实际系统上,则用户有时会按下一个键或移动鼠标,并且空闲时间将少于100个滴答声。如果发生10次以上,恶意软件将开始执行其有效负载。
但是,传统的沙箱执行和分析每个程序的时间有限,因此检测这种类型的逃逸是有问题的。此外,在评估上述恶意软件样本时,常规沙箱需要在指定时间范围内生成10次正确的输入空闲时间。如果不这样做,该恶意软件将不会执行,并且不会被检测到。我们测试的大多数沙盒无法完成此操作,并错误地得出结论该样品无害。

示例2 检测前台窗口

Win32 / Gataka变体:使用GetForeGroundWindow,并检查是否再次调用同一API会更改Windows句柄,如果用前台窗口一直没有改变,说明可能没有用户操作。在Locky勒索软件变体中发现了相同的技术。
反虚拟机、反沙箱技术整理汇总 - 图13

示例3 检测鼠标

Win32 / Sazoora恶意软件,用于检查鼠标的移动。

反虚拟机、反沙箱技术整理汇总 - 图14

示例4 vb宏

恶意软件活动采用了多种技术来检查与受感染系统的历史交互。此类传播Dridex恶意软件的活动广泛使用了仅在文档关闭时触发的“自动执行”宏。以下是此类活动的VB代码的快照。
反虚拟机、反沙箱技术整理汇总 - 图15

示例5 检查注册表项最近文档

\HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Word\User MRU
反虚拟机、反沙箱技术整理汇总 - 图16

示例6 vb脚本检查最近文件

反虚拟机、反沙箱技术整理汇总 - 图17

环境检测

恶意软件使用的另一种技术是对目标环境进行指纹识别,例如:

  • 对照通用沙箱名称或注册表检查主机名。
  • 验证安装的程序,程序数量很少的可能表明机器是假的。
  • 检查文件名以检测是否使用了哈希或关键字(例如恶意软件)
  • 检测正在运行的进程以发现潜在的监视工具并检查网络地址以检测被列入黑名单的工具,例如AV厂商。