Vectored Overloading PE Injection

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

技术概述

Vectored Overloading 是一种 Windows PE 注入原语,它将经典的 Module Overloading 与 Vectored Exception Handlers (VEHs) 和 hardware breakpoints 结合在一起。与其修改 LoadLibrary 或自行实现加载器,攻击者会:

  1. 创建一个以合法 DLL(例如 wmp.dll)为后备的 SEC_IMAGE section。
  2. 用一个已完成重定位的恶意 PE 覆盖映射视图,但保持 section 对象仍指向磁盘上的良性映像。
  3. 注册 VEH 并编程调试寄存器,使得每次调用 NtOpenSectionNtMapViewOfSection,以及可选的 NtClose 都触发用户模式断点。
  4. 调用 LoadLibrary("amsi.dll")(或任何其他良性目标)。当 Windows loader 调用这些 syscall 时,VEH 会跳过内核转换并返回事先准备好的恶意映像的句柄和基址。

因为 loader 仍然认为它映射了请求的 DLL,仅查看 section 后备文件的工具会看到 wmp.dll,即使内存现在包含攻击者的 payload。与此同时,imports/TLS callbacks 仍由真实的 loader 解析,这大大减少了攻击者需要维护的自定义 PE 解析逻辑量。

Stage 1 – Build the disguised section

  1. Create and map a section for the decoy DLL
NtCreateSection(&DecoySection, SECTION_ALL_ACCESS, NULL,
0, PAGE_READWRITE, SEC_IMAGE, L"\??\C:\\Windows\\System32\\wmp.dll");
NtMapViewOfSection(DecoySection, GetCurrentProcess(), &DecoyView, 0, 0,
NULL, &DecoySize, ViewShare, 0, PAGE_READWRITE);
  1. 按 section 把恶意 PE 复制进该视图,遵循 SizeOfRawData/VirtualSize 并在之后更新保护(如 PAGE_EXECUTE_READPAGE_READWRITE 等)。
  2. 应用重定位并解析 imports,与 reflective loader 完全相同。因为视图已经以 SEC_IMAGE 映射,section 对齐和 guard 页面与之后 Windows loader 的预期一致。
  3. 规范化 PE 头部
  • 如果 payload 是 EXE,设置 IMAGE_FILE_HEADER.Characteristics |= IMAGE_FILE_DLL 并将入口点清零,以防 LdrpCallTlsInitializers 跳转到 EXE 专用的桩代码。
  • DLL payload 可以保持头部不变。

至此,进程拥有一个可 RWX 的视图,其后备对象仍为 wmp.dll,但内存中的字节由攻击者控制。

Stage 2 – Hijack the loader with VEHs

  1. 注册 VEH 并设置 hardware breakpoints:将 Dr0(或其它调试寄存器)编程为指向 ntdll!NtOpenSection 的地址,并设置 DR7,使每次执行都触发 STATUS_SINGLE_STEP。随后对 NtMapViewOfSection(以及可选的 NtClose)重复此过程。
  2. 触发 DLL 加载,例如调用 LoadLibrary("amsi.dll")LdrLoadDll 最终会调用 NtOpenSection 来获取真实的 section 句柄。
  3. 用于 NtOpenSection 的 VEH hook
  • 找到栈上用于 [out] PHANDLE SectionHandle 参数的位置。
  • 将之前创建的 DecoySection 句柄写入该位置。
  • RIP/EIP 前进到 ret 指令,以便永远不调用内核。
  • 重新设置硬件断点以监视下一步的 NtMapViewOfSection
  1. 用于 NtMapViewOfSection 的 VEH hook
  • 覆盖 [out] PVOID *BaseAddress(以及大小/保护相关的输出)为已经映射的恶意视图的地址。
  • 像之前一样跳过 syscall 主体。
  1. (可选)用于 NtClose 的 VEH hook 验证伪造的 section 句柄已被清理,防止资源泄漏并提供最终的完整性检查。

因为这些 syscall 从未真正执行,内核回调(如 ETWti、minifilter 等)不会观察到可疑的 NtOpenSection/NtMapViewOfSection 事件,从而大幅降低遥测。从 loader 的视角一切都成功,amsi.dll 在内存中,因此它会对攻击者的字节继续进行 import/TLS 解析。

Stage 3 – Execute the payload

  • EXE payload:注入器在完成重定位后直接跳转到原始入口点。当 loader 认为它会调用 DllMain 时,自定义代码反而执行 EXE 风格的入口。
  • DLL payload / Node.js addon:解析并调用目标导出(Kidkadi 向 JavaScript 暴露了一个具名函数)。因为该模块已在 LdrpModuleBaseAddressIndex 中注册,后续查找会将其视为良性 DLL。

当与 Node.js 本地 addon(.node 文件)结合使用时,所有复杂的 Windows 内部细节都保留在 JavaScript 层之外,帮助威胁行为者将相同的 loader 与多个不同的混淆 Node 包装器一起分发。

References

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks