You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CreateRemoteThread卸载注入DLL时触发Access violation问题排查

DLL注入后调用函数再卸载时目标进程崩溃的问题

我尝试将DLL干净注入前台窗口进程,调用DLL内的简单函数后再卸载,但卸载时目标进程会崩溃。

注入器代码

HWND fgwnd = GetForegroundWindow();

DWORD cur_thread = GetCurrentThreadId();
DWORD fg_pid = 0;
DWORD fg_thread = GetWindowThreadProcessId(fgwnd, &fg_pid);
BOOL res = 0;


const char* inj_path = "C:\\Users\\pc\\source\\repos\\hothook\\x64\\Debug\\fground_injector.dll";
// 获取目标进程句柄
HANDLE victim = OpenProcess(PROCESS_ALL_ACCESS, FALSE, fg_pid);

// 获取kernel32.dll中LoadLibraryA和FreeLibrary的地址
PVOID llib = (LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
PVOID flib = (LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "FreeLibrary");

// 在目标进程中分配内存
LPVOID inj_path_victim = (LPVOID)VirtualAllocEx(victim, NULL, strlen(inj_path)+1,
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

// 将DLL路径写入目标进程内存
SIZE_T written;
res = WriteProcessMemory(victim, inj_path_victim, inj_path, strlen(inj_path)+1, &written);

// 创建远程线程注入DLL
HANDLE inj_llib_thread = CreateRemoteThread(
/*I*/   victim,                             // 目标进程句柄
/*I*/   NULL,                               // 线程安全属性
/*I*/   0,                                  // 初始栈大小(默认)
/*I*/   (LPTHREAD_START_ROUTINE)llib,       // 线程入口(LoadLibraryA)
/*I*/   inj_path_victim,                    // 传入参数(DLL路径)
/*I*/   0,                                  // 立即启动线程
/*O|O*/ NULL);                              // 不获取线程ID

// 等待注入完成
res = WaitForSingleObject(inj_llib_thread, INFINITE);
// 获取DLL加载后的基地址
DWORD llib_exit;
res = GetExitCodeThread(inj_llib_thread, &llib_exit);

// 释放目标进程中分配的内存
res = VirtualFreeEx(victim, inj_path_victim, 0, MEM_RELEASE);

// 调用注入DLL中的函数
HMODULE fg_inj = LoadLibraryA(inj_path);
PVOID inj_t_proc = (LPVOID)GetProcAddress(fg_inj, "injectThread");
// 创建远程线程调用函数
HANDLE inj_thread = CreateRemoteThread(
/*I*/   victim,                             // 目标进程句柄
/*I*/   NULL,                               // 线程安全属性
/*I*/   0,                                  // 初始栈大小(默认)
/*I*/   (LPTHREAD_START_ROUTINE)inj_t_proc, // 线程入口(injectThread)
/*I*/   NULL,                               // 无参数
/*I*/   0,                                  // 立即启动线程
/*O|O*/ NULL);                              // 不获取线程ID

// 等待函数执行完成
res = WaitForSingleObject(inj_thread, INFINITE);

// 创建远程线程卸载DLL
HANDLE inj_flib_thread = CreateRemoteThread(
/*I*/   victim,                             // 目标进程句柄
/*I*/   NULL,                               // 线程安全属性
/*I*/   0,                                  // 初始栈大小(默认)
/*I*/   (LPTHREAD_START_ROUTINE)flib,       // 线程入口(FreeLibrary)
/*I*/   (LPVOID)llib_exit,                  // 传入参数(DLL基地址)
/*I*/   0,                                  // 立即启动线程
/*O|O*/ NULL);                              // 不获取线程ID

// 等待卸载完成
res = WaitForSingleObject(inj_flib_thread, INFINITE);
DWORD flib_exit;
res = GetExitCodeThread(inj_flib_thread, &flib_exit);

// 释放宿主进程中加载的DLL(即使循环调用100次也无法卸载)
FreeLibrary(fg_inj);

// 关闭所有句柄
CloseHandle(victim);
CloseHandle(inj_llib_thread);
CloseHandle(inj_thread);
CloseHandle(inj_flib_thread);

注入DLL代码

BOOL APIENTRY DllMain(HMODULE hm,
                      DWORD call_reas,
                      LPVOID reserved)
{
    switch(call_reas)
    {
    case DLL_PROCESS_ATTACH:
    {
        DisableThreadLibraryCalls(hm);
        // 试过注释掉这行,崩溃情况依旧
        break;
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

DWORD injectThread(LPVOID p)
{
    //AllowSetForegroundWindow(ASFW_ANY);
    // 原本要实现让宿主进程获取前台窗口权限,但注释后还是崩溃
    return 0;
}

崩溃详情

崩溃发生在创建FreeLibrary远程线程之后,异常信息如下:

Exception thrown at 0x00007FFE598C7170 in maudswch.exe: 0xC0000005: Access violation executing location 0x00007FFE598C7170.

00007ffe598c7170()
kernel32.dll!00007ffe9ac47034()
ntdll.dll!00007ffe9c682651()

Not Flagged     50864   0   Main Thread Main Thread win32u.dll!00007ffe99e51104
Not Flagged     47548   0   Worker Thread   ntdll.dll thread    ntdll.dll!00007ffe9c6d0794
Not Flagged     41096   0   Worker Thread   ntdll.dll thread    ntdll.dll!00007ffe9c6d0794
Not Flagged     43456   0   Worker Thread   ntdll.dll thread    ntdll.dll!00007ffe9c6d0794
Not Flagged >   29820   0   Worker Thread   Win64 Thread    00007ffe598c7170

测试情况与补充信息

  • 多个目标进程(CMD、记事本、自定义GUI程序)测试结果一致:DLL成功注入,函数能执行,但卸载时必崩溃。
  • FreeLibrary远程线程完成耗时极长,有时1.5秒甚至7秒。
  • 调试发现:宿主进程和目标进程中DLL的基地址、函数地址完全一致,排除地址截断导致崩溃的可能。

问题分析与解决方案

核心问题

崩溃的根源在于:你通过远程线程调用injectThread(属于待卸载的DLL),同时又在外部启动另一个远程线程调用FreeLibrary卸载该DLL。当FreeLibrary执行时,DLL的代码段会被系统标记为可回收,而此时injectThread的线程可能还在执行返回逻辑,访问已经被释放的内存,直接触发访问违例。

另外,宿主进程中FreeLibrary无法卸载DLL,是因为GetProcAddress会增加DLL的引用计数,单次调用无法清零。

修复步骤

  1. 让DLL内部完成卸载逻辑
    修改DLL的injectThread,在业务逻辑执行完成后,主动调用FreeLibraryAndExitThread,确保线程在DLL卸载前安全退出:

    DWORD injectThread(LPVOID p)
    {
        // 执行你的业务逻辑,比如原本的AllowSetForegroundWindow(ASFW_ANY);
        
        // 获取当前DLL的模块句柄
        HMODULE hModule = NULL;
        GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
                          (LPCSTR)injectThread, &hModule);
        // 卸载DLL并退出线程
        FreeLibraryAndExitThread(hModule, 0);
        return 0; // 此行不会被执行,仅用于编译通过
    }
    
  2. 移除外部的FreeLibrary远程线程
    注入器中无需再创建卸载DLL的远程线程,只需等待injectThread的远程线程完成即可——线程会自行处理DLL卸载。

  3. 修复宿主进程DLL无法卸载的问题
    循环调用FreeLibrary直到返回FALSE,确保引用计数清零:

    while (FreeLibrary(fg_inj)) {}
    
  4. 规避ASLR风险(可选但推荐)
    不要依赖宿主与目标进程DLL基地址一致的巧合,通过DLL内部获取模块句柄的方式,能兼容ASLR地址随机化的场景。

修复后的注入器关键代码片段

// ...(注入DLL的逻辑保持不变)

// 调用注入DLL中的函数
HMODULE fg_inj = LoadLibraryA(inj_path);
PVOID inj_t_proc = (LPVOID)GetProcAddress(fg_inj, "injectThread");
HANDLE inj_thread = CreateRemoteThread(victim, NULL, 0, (LPTHREAD_START_ROUTINE)inj_t_proc, NULL, 0, NULL);

// 等待线程完成(线程内部会卸载DLL)
res = WaitForSingleObject(inj_thread, INFINITE);

// 释放宿主进程中的DLL
while (FreeLibrary(fg_inj)) {}

// 关闭句柄
CloseHandle(victim);
CloseHandle(inj_llib_thread);
CloseHandle(inj_thread);
// 移除原有的inj_flib_thread相关代码

内容的提问来源于stack exchange,提问作者ScienceDiscoverer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 06:36:22