DLL注入与IAT挂钩后重建DLL提示路径访问被拒问题
问题分析与解决方案
核心错误:DLL卸载逻辑完全无效
你的eject函数存在致命问题:tempHM = LoadLibraryA("myDLL\\x64\\Debug\\myDLL.dll")是在当前注入器进程中加载了DLL,拿到的是当前进程的模块句柄,而非目标进程中已注入的DLL模块句柄。把这个句柄传给目标进程的FreeLibrary完全起不到卸载作用,目标进程里的DLL实例根本没被释放,这就是DLL文件仍被占用的根本原因。
正确的DLL卸载流程
要彻底释放目标进程中的DLL,需按以下步骤执行:
- 枚举目标进程的已加载模块,找到你的DLL在目标进程地址空间中的模块句柄
- 创建远程线程调用
FreeLibrary,传入目标进程中的DLL句柄 - 等待远程线程执行完成,确保卸载操作生效
- 确保IAT完全恢复,目标进程无任何对DLL函数的残留引用
修正后的卸载代码示例
#include <tlhelp32.h> // 辅助函数:获取目标进程中指定DLL的模块句柄 HMODULE GetRemoteModuleHandle(DWORD pid, const char* dllName) { HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid); if (hSnapshot == INVALID_HANDLE_VALUE) { return nullptr; } MODULEENTRY32 me32; me32.dwSize = sizeof(MODULEENTRY32); if (!Module32First(hSnapshot, &me32)) { CloseHandle(hSnapshot); return nullptr; } do { if (_stricmp(me32.szModule, dllName) == 0) { CloseHandle(hSnapshot); // 返回目标进程地址空间中的模块句柄 return (HMODULE)me32.modBaseAddr; } } while (Module32Next(hSnapshot, &me32)); CloseHandle(hSnapshot); return nullptr; } bool InjectorAndEject::eject(int pid) { // 1. 先确保IAT完全恢复 if (!this->reutrnOriginalFunctions(pid)) { printf("Error: Failed to restore original IAT functions.\n"); return false; } // 2. 获取目标进程句柄 HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_CREATE_THREAD, FALSE, pid); if (!process) { printf("Error: Could not open target process.\n"); return false; } // 3. 获取目标进程中myDLL.dll的模块句柄 HMODULE remoteDllHandle = GetRemoteModuleHandle(pid, "myDLL.dll"); if (!remoteDllHandle) { printf("Error: Could not find myDLL.dll in target process.\n"); CloseHandle(process); return false; } // 4. 获取FreeLibrary函数地址(kernel32.dll基址在所有进程中一致) LPVOID freeLibraryAddr = (LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "FreeLibrary"); if (!freeLibraryAddr) { printf("Error: Could not find FreeLibrary in kernel32.dll.\n"); CloseHandle(process); return false; } // 5. 创建远程线程执行FreeLibrary HANDLE threadID = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)freeLibraryAddr, remoteDllHandle, NULL, NULL); if (!threadID) { printf("Error: Could not create remote thread for FreeLibrary.\n"); CloseHandle(process); return false; } // 6. 等待远程线程执行完成,确保DLL被释放 WaitForSingleObject(threadID, INFINITE); CloseHandle(threadID); CloseHandle(process); printf("Success: myDLL.dll has been ejected from process %d.\n", pid); return true; }
其他可能的文件占用原因
- IAT恢复不彻底:若
reutrnOriginalFunctions未完全恢复所有挂钩的IAT条目,目标进程仍会引用DLL函数,导致FreeLibrary无法真正卸载(DLL引用计数不为0)。 - DLL存在未退出线程:如果挂钩DLL创建了监控线程等自定义线程,卸载前必须先终止并等待线程退出,否则
FreeLibrary会失败。 - Visual Studio缓存锁定:尝试关闭Visual Studio后清理项目输出目录,再重新打开项目重建。
- 目标进程IAT缓存未刷新:部分进程会缓存IAT条目,恢复后可尝试触发进程刷新(如窗口最小化再最大化)或调用
FlushInstructionCache清理指令缓存。
额外注意事项
- 调用
OpenProcess时避免使用PROCESS_ALL_ACCESS,改用最小必要权限(如示例中的权限组合),减少权限问题风险。 - 注入和卸载操作都要等待远程线程执行完成,确保操作真正生效。
- 可使用Process Explorer工具查看目标进程的模块加载情况,以及文件被哪个进程占用,辅助排查问题。
内容的提问来源于stack exchange,提问作者יהב
相关产品推荐
相关产品推荐

