引言
本文主要介绍'反射型 DLL 注入'及'柔性加载'技术在红队攻防中的应用。通过深入分析内存操作机制,探讨如何规避传统安全软件的特征检测。
反射型 DLL 注入
为什么需要反射型 DLL 注入
常规的 DLL 注入通常涉及从磁盘读取文件、写入目标进程内存、调用 LoadLibraryW 以及创建远程线程。这种模式存在多个高危特征:
- 磁盘 IO 痕迹:从磁盘读取 DLL 会留下文件访问记录,容易被静态扫描发现。优化方案是将 Payload 直接嵌入装载器并加密。
- API 调用特征:在目标内存中查找
LoadLibraryW函数地址(通过GetProcAddress)属于高特征行为,易被 EDR 归类为恶意调用。 - 线程创建行为:使用
CreateRemoteThread进行远程线程注入是经典的攻击手法,参数若指向LoadLibraryW极易触发警报。
针对上述问题,我们采用反射型 DLL 注入技术,结合创建新进程或 APC 注入方式,改变 DLL 加载的调用模式,从而降低被检测的风险。
实现思路
早期的反射型 DLL 注入原理通常包含以下步骤:
- 将 DLL 数据写入目标进程内存。
- 调用目标线程中的嵌入式引导代码(Bootstrapper Shellcode)。
- 执行 Shellcode 调用 DLL 内部的 Reflective Loader。
Reflective Loader 实际上是一个自定义实现的 LoadLibraryW 函数。它负责从内存中找到写入的 DLL 数据,修复 PE 头使其成为可正常运行的模块,最后调用 DllMain 入口点执行恶意功能。
本方案对早期思路进行了优化:不使用传统的远程进程/线程注入方式,也不需要额外的 Bootstrapper Shellcode。直接在加载器部分计算出 Reflective Loader 在内存中的地址,直接调用即可,减少了中间环节和特征暴露。
加载器部分
加载器的核心流程如下:
- 解密 Shellcode:Shellcode 在内存中使用 AES 算法解密,部分关键 C 代码也经过加密处理,防止静态分析。
- 计算偏移量:解密载入内存后,使用
GetReflectiveLoaderOffset函数计算出 Reflective Loader 函数的内存偏移。 - 调用 Loader:创建线程直接调用 Reflective Loader 函数。
DLL 部分
Reflective Loader 主要完成以下五个关键步骤:
-
解析 Kernel32.dll API 地址 由于无法依赖系统导入表,需要通过关键函数的哈希值在内存中搜索
VirtualAlloc、LoadLibraryA等 Windows API 地址。这避免了直接引用敏感符号。 -
写入 DLL 节表 将 DLL 的各个节(Section)及其相应数据写入到分配的内存空间中,模拟标准的 PE 文件加载过程。
-
建立导入表 构建 DLL 的导入表,以便 DLL 能够正确调用
ntdll.dll和kernel32.dll中的 WINAPI 函数。 -
修复重定位表 根据实际分配的内存基址,修复 PE 文件的重定位表(Relocation Table),确保所有相对地址引用正确。
-
调用入口点 最终调用 DLL 的入口点(通常是
DllMain),在此处执行实际的恶意逻辑或上线命令。
柔性加载配置
为了限制具有 RWX(读 - 写 - 执行)标记的内存使用,Cobalt Strike (CS) 4.0+ 版本支持相关配置。推荐的安全配置如下:


