0%
毅种循环

模块 69 - Syscalls - 重构 APC 注入

恶意软件开发课程 - Syscalls - 重构 APC 注入


模块 69 - Syscalls - 重构 APC 注入#

Syscalls - 重构 APC 注入#

简介#

本模块将展示如何使用直接系统调用(Direct Syscalls)实现 APC 注入 (APC Injection) 技术。对于内存分配、修改保护属性和写入 Payload,我们将继续使用之前介绍过的 NtAllocateVirtualMemoryNtProtectVirtualMemoryNtWriteVirtualMemory

本模块的核心重点是将 QueueUserAPC 替换为它的底层系统调用:NtQueueApcThread

NtQueueApcThread 详解#

NTSTATUS NtQueueApcThread(
  IN HANDLE               ThreadHandle,       // 目标线程句柄
  IN PIO_APC_ROUTINE      ApcRoutine,         // 要执行的 APC 函数地址(即我们的 Payload)
  IN PVOID                ApcRoutineContext,  // 参数 1 (通常设为 NULL)
  IN PIO_STATUS_BLOCK     ApcStatusBlock,     // 参数 2 (通常设为 NULL)
  IN ULONG                ApcReserved         // 参数 3 (通常设为 NULL)
);
c

准备环境:创建一个“可警示”线程#

根据 APC 注入的原理,目标线程必须处于 可警示状态 (Alertable State) 才能触发 APC 队列。在演示代码中,我们通过 CreateThread 创建一个牺牲线程,并让它调用 MsgWaitForMultipleObjectsEx 进入等待状态。

💡 知识扩展:Alertable 状态

只有当线程调用特定的等待函数(如 SleepEx, WaitForSingleObjectEx, MsgWaitForMultipleObjectsEx)并设置了 bAlertableTRUE 时,操作系统才会处理挂在该线程 APC 队列中的任务。

三种实现方案#

1. 动态获取地址 (GetProcAddress)#

通过解析 ntdll.dll 的导出表手动获取 NtQueueApcThread 及其它系统调用的地址。这种方法简单,但会被 EDR 的 Hook 拦截。

2. SysWhispers3 (间接系统调用)#

使用 SysWhispers3 生成绕过 Hook 的汇编入口。 命令参考: python syswhispers.py -m jumper_randomized -f NtAllocateVirtualMemory,NtProtectVirtualMemory,NtWriteVirtualMemory,NtQueueApcThread -o SysWhispers

3. 地狱之门 (Hell’s Gate)#

动态解析 ntdll 内存中的特征码来提取 NtQueueApcThread 的 SSN。

远程进程注入的思考#

虽然上述示例是在本地进程演示,但相同逻辑可以轻松移植到远程进程。对于远程注入,通常结合 Early Bird APC 技巧:

  1. 以挂起状态 (CREATE_SUSPENDED) 创建远程进程。
  2. 将 Payload 注入该进程。
  3. 使用 NtQueueApcThread 将 Payload 挂入其主线程队列。
  4. 恢复线程执行。

由于线程在启动初期会通过 NtTestAlert 等内部调用检查 APC 队列,因此 Payload 会在进程真正开始运行其合法逻辑之前就被执行。


🎯 总结#

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

  1. APC 底层原语:掌握了 NtQueueApcThread 的参数结构及调用约定。
  2. 状态触发:复习了线程“可警示状态”在 APC 注入中的决定性作用。
  3. 隐蔽性组合:将 APC 注入的隐蔽性与 Syscalls 的免杀性相结合,构建出足以应对主流 EDR 监控的注入链。

📚 下一步学习

恭喜你完成了 Syscalls 系列的实战重构!下一个模块我们将开启全新的视野:Module 70 - Anti-Analysis - Introduction。我们将学习恶意软件如何识别并反击分析环境(如虚拟机、沙箱和调试器)!