0%
毅种循环

模块 74 - 反虚拟环境技术 - 多种延迟执行技术

恶意软件开发课程 - 反虚拟环境技术 - 多种延迟执行技术


模块 74 - 反虚拟环境技术 - 多种延迟执行技术#

反虚拟环境技术 - 多种延迟执行技术#

简介#

延迟执行 (Delay Execution) 是躲避沙箱环境的一种通用技术。沙箱通常具有时间限制,无法长时间监控二进制程序的行为。因此,恶意软件可以在关键代码执行前引入长时间的停顿,迫使沙箱在还没来得及执行恶意逻辑时就因超时而被迫终止。

如果沙箱的分析上限为 2 分钟,而恶意软件在解密和运行 Payload 前先等待了 3 分钟,那么该样本在沙箱眼中就是安全的。

本模块将介绍在探测到沙箱环境后可用于延迟执行的多种函数。

💡 初学者提示:为什么要延迟执行?

类比理解: 想象你是一颗定时炸弹(恶意软件)。如果你被送进一个排爆室(沙箱),排爆专家只会被授权观察你 5 分钟。

  • 策略一:立即引爆。专家会立刻看到你的所有行为,你的目的就暴露了。
  • 策略二:延迟执行。你设定一个 10 分钟的闹钟,在此之前你只是一块普通的石头。由于专家只有 5 分钟时间,时间一到,他就得把你放回普通的堆场。等到了第 10 分钟,你在普通堆场(真实机器)里才开始执行你的真正任务。

1. 探测“快进”欺骗 (Fast-Forwards)#

大多数现代沙箱已经意识到这种延迟战术,并实现了相应的对策:时间快进。沙箱会通过 API Hook 修改传递给延迟函数的参数(如将 Sleep(10000) 改为 Sleep(0)),从而瞬间跳过等待。

为了对抗这种欺骗,我们在延迟结束后必须核实流逝的时间。这可以通过 GetTickCount64 WinAPI 来实现。

BOOL DelayFunction(DWORD dwMilliSeconds){

  DWORD T0 = GetTickCount64();
  
  // 这里放置延迟 dwMilliSeconds 毫秒的逻辑
  
  DWORD T1 = GetTickCount64();
  
  // 如果实际经过的时间少于要求的时间,说明发生了快进,函数返回失败
  if ((DWORD)(T1 - T0) < dwMilliSeconds)
    return FALSE;
  else
    return TRUE;
}
c

2. 利用 WaitForSingleObject 延迟执行#

我们经常使用 WaitForSingleObject 等待事件变得有信号。在这里,我们可以利用它等待一个由 CreateEvent 产生的空事件。由于该事件永远不会变的有信号,函数将不得不等待超时发生,从而达到延迟的目的。

3. 利用 MsgWaitForMultipleObjectsEx 延迟执行#

MsgWaitForMultipleObjectsEx 的功能与 WaitForSingleObject 类似,但它还能响应输入事件,常用于 GUI 程序。

4. 利用 NtWaitForSingleObject 延迟执行#

我们可以直接使用系统调用 NtWaitForSingleObject。它是 WaitForSingleObject 的底层内核版本。

[!IMPORTANT] Nt 系列函数中的时间单位是 100 纳秒间隔(Ticks)。1 个 Ticks 等于 0.0001 毫秒。传递给 Timeout 的值应为:-(dwMilliSeconds * 10000)

5. 利用 NtDelayExecution 延迟执行#

NtDelayExecution 系统调用专门用于同步延迟。它类似于内核版的 Sleep

6. 演示#

下图演示了这些技术的运行效果。执行被设定延迟 6 秒(0.1 分钟)。可以看到即使使用了底层调用,依然能正确捕捉快进行为。

延迟执行演示
延迟执行演示


🎯 总结#

在本模块中,我们学习了:

  1. 时间差校验: 实战应用 GetTickCount64 来识破沙箱引擎对 Sleep 类函数的修改。
  2. 内核原语: 理解了 Ticks 时间单位及其在 Nt 系列 Native API 中的应用。
  3. 替代 API: 学会使用多种看似合法的 WinAPI 实现长时间隐蔽挂起程序。

📚 下一步学习

下一个模块将探讨 Module 75 - Anti-Virtual Environments - API Hammering。学习如何通过大量的 I/O 操作进行另一种形式的“密集型”延迟。