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

DLL注入与IAT挂钩后重建DLL提示路径访问被拒问题

问题分析与解决方案

核心错误:DLL卸载逻辑完全无效

你的eject函数存在致命问题:tempHM = LoadLibraryA("myDLL\\x64\\Debug\\myDLL.dll")是在当前注入器进程中加载了DLL,拿到的是当前进程的模块句柄,而非目标进程中已注入的DLL模块句柄。把这个句柄传给目标进程的FreeLibrary完全起不到卸载作用,目标进程里的DLL实例根本没被释放,这就是DLL文件仍被占用的根本原因。

正确的DLL卸载流程

要彻底释放目标进程中的DLL,需按以下步骤执行:

  1. 枚举目标进程的已加载模块,找到你的DLL在目标进程地址空间中的模块句柄
  2. 创建远程线程调用FreeLibrary,传入目标进程中的DLL句柄
  3. 等待远程线程执行完成,确保卸载操作生效
  4. 确保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,提问作者יהב

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 14:17:51