Fiber | 使用 Fibers 以不同且隐蔽的方式运行内存代码插图

引言

纤程是一种执行单元,需要由应用程序手动调度,而不是依赖于 Windows 内置的基于优先级的调度机制。纤程通常被称为轻量级线程。虽然纤程需要更多的手动控制,但它们对于在内存中运行代码非常有效,并且在隐藏恶意行为时非常有用。

Fiber | 使用 Fibers 以不同且隐蔽的方式运行内存代码插图1

什么是纤程

纤程允许在单个线程中有多个执行流,每个执行流都有自己的寄存器状态和堆栈。另一方面,纤程对内核是不可见的,这使得它们成为一种比生成新线程更隐秘(也更便宜)的内存代码执行方法。

如何使用纤程

一个线程可以创建多个纤程,并通过调用SwitchToFiber函数在它们之间随意切换。在此之前,当前线程本身必须通过调用ConvertThreadToFiber成为纤程,因为只有纤程才能创建其他纤程。最后,为了创建一个在调度时执行内存代码的纤程(例如,在反射加载 PE 或一些 shellcode 之后),只需要调用CreateFiber

SwitchToFiber 函数

SwitchToFiber 函数是此过程中最重要的部分,也是所有魔法发生的地方。此功能允许调度一根纤程或另一根纤程,所有这些都发生在用户空间上。这个功能非常重要,因为它允许控制过程切换到有效载荷过程,然后再次切换回来。根据官方文档,“SwitchToFiber函数保存当前纤程的状态信息,并恢复指定纤程的状态”。这意味着当调用此函数时,寄存器的值和堆栈将从当前纤程状态切换到目标纤程状态,从而允许在过程完成后“隐藏”当前纤程的堆栈。这也允许从执行停止的同一点继续执行目标纤程(与调度程序根据其自己的优先级逻辑在线程之间切换时发生的方式相同)。

纤程的优点

使用纤程可能对某些类型的有效载荷(如 C2 信标)有利。以下是使用纤程的几个优点:

  1. 纤程允许运行内存中的代码,而无需使用指令JMP或CALL从加载程序指向未支持的内存区域。
  2. 此执行是在没有创建新线程的情况下执行的,从而防止从内核生成可由 EDR 收集的回调。
  3. 当有效负载进入可警报状态或需要等待挂起的 I/O 操作时,可以隐藏有效负载纤程的堆栈。这是使用带有从磁盘运行代码的普通堆栈的控制纤程来完成的。这种“隐藏”比常规的线程堆栈欺骗过程更便宜、更容易实现。
  4. 纤程对内核是不可见的,所有切换过程都发生在用户空间,这使得它更容易躲避 EDR。

纤程的缺点

使用纤程也有缺点:

  1. 纤程上一次只能调度一个纤程,这意味着为了使用纤程获得真正的并发性,您需要生成更多线程
  2. 尽管在控制光纤切换回时有效载荷光纤的堆栈被隐藏,但它仍保留在进程内存中,并且可以通过内存检查发现。
  3. 仍然需要混淆以隐藏内存中的植入,这只是隐藏堆栈和执行方法。
Fiber | 使用 Fibers 以不同且隐蔽的方式运行内存代码插图2

总结

使用纤程在内存中运行代码的优点和缺点都非常明显。纤程提供了一种不同于线程的执行单元,在某些情况下,这种技术可以提供额外的优势。但是,由于使用纤程需要更多的手动控制,并且不是所有应用程序都支持该技术,因此使用它需要慎重考虑。

相关内容

Fiber