内核驱动 之 手动映射注入写法(附实例代码)

摘要

手动映射注入是一种不依赖系统标准 DLL 加载流程的进程注入方式。它不会直接调用 LoadLibrary,也不要求目标进程按照普通模块加载方式登记 DLL,而是将 PE 文件数据复制到目标进程内存,再由自定义 Loader 完成映像初始化和执行。

本工程采用内核驱动辅助方式,通过 PsSetLoadImageNotifyRoutine 监听目标进程加载模块,在目标进程加载 ntdll.dll 后执行注入逻辑。其设计目标是降低传统 DLL 注入产生的模块、文件和线程痕迹

 

一、传统 DLL 注入的问题

常规 DLL 注入通常依赖以下流程:

OpenProcess
VirtualAllocEx
WriteProcessMemory
CreateRemoteThread
LoadLibrary

这种方式会产生较多可观测行为:

  • 目标进程出现高权限远程句柄;
  • 调用 VirtualAllocEx 分配远程内存;
  • 调用 WriteProcessMemory 写入 DLL 路径;
  • 创建远程线程;
  • 线程入口通常为 LoadLibraryA/W
  • DLL 文件需要存在于磁盘;
  • DLL 通常会进入目标进程的 PEB 模块链;
  • 内存区域通常可以通过 VAD 和模块枚举发现。

因此,反作弊或安全软件可以从 API、调用栈、线程入口、模块链和内存属性等多个角度进行检测。

 

手动映射的隐蔽性

1. 不调用 LoadLibrary

手动映射最重要的隐蔽性来自于绕过标准加载器。

目标进程不会按照普通 DLL 加载流程执行:

LdrLoadDll
LoadLibrary
模块登记
DLL 文件路径解析

这意味着:

  • 不需要 DLL 文件路径;
  • 不一定产生标准 DLL 加载事件;
  • DLL 不一定出现在 PEB 的模块链;
  • 普通模块枚举工具可能无法发现它;
  • 不会自动生成标准模块引用关系。

这是手动映射相对于传统 DLL 注入的主要优势。

 

2. 不依赖磁盘文件

DLL 数据通过 INJECT_DATA.InjectData 传入驱动

驱动将数据复制到内核缓存,再写入目标进程。

因此目标进程可以直接获得内存中的 PE 数据,而不需要出现:

C:\xxx\payload.dll

这种磁盘文件痕迹。

不过,当前工程的 DLL 数据仍然可能出现在:

  • 用户态调用者内存;
  • 驱动内核池;
  • 注册表通信缓冲区;
  • 目标进程内存;
  • 内存取证结果。

所以它只是减少磁盘痕迹,不是完全消除载荷痕迹。

 

3. 不一定出现标准模块信息

正常 DLL 会在模块链和内存查询中体现:

MEM_IMAGE
Mapped Image
模块名
文件路径
PEB Ldr 链表

手动映射区域通常表现为:

MEM_PRIVATE

并且没有对应文件映像。

这可以规避只依赖以下信息的检测:

  • PEB 模块枚举;
  • EnumProcessModules;
  • CreateToolhelp32Snapshot;
  • DLL 文件路径扫描;
  • 普通 MEM_IMAGE 模块列表。

 

4. Loader 与载荷可以分离

本工程将 Loader、PE 映像和清理代码分开放置:

AllocCache[0]:映像区域
AllocCache[1]:Loader
AllocCache[2]:后续代码或清理区域

这种布局便于:

  • Loader 完成初始化后清除自身;
  • 载荷数据和执行代码分离;
  • 减少常见 Shellcode 特征;
  • 让目标进程中不出现明显的 DLL 路径字符串。

 

本内容需要登录后查看
上一篇 关于如何实现 驱动改变设备真实机器码 从而绕过反作弊检测 (附实例代码)