无法卸载注入的 DLL

Unable to unload injected DLL

我用 C 编写了一个 dll,我通过 CreateRemoteThread() 将其注入到 C 控制台程序中。

C 程序只是调用 Sleep(INFINITE),基本上充当注入的 dll 的宿主。

这是 DllMain:

HINSTANCE thisDllHandle = NULL;

BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD entryReason, void *impLoad)
{
    switch (entryReason)
    {
        case DLL_PROCESS_ATTACH:
        {
            thisDllHandle = hInstance;
            HANDLE thread = (HANDLE)_beginthreadex(NULL, 0, Boss, NULL, 0, NULL);
            if (thread) CloseHandle(thread);
        }
    }
    return TRUE;
}

通过CreateRemoteThread()然后returns创建的线程,而我的Boss线程是唯一的线程运行这个dll的代码。

如果我随后告诉 Boss 退出,清理后它会调用 FreeLibraryAndExitThread(thisDllHandle, 0); - 线程退出但 dll 仍然加载在我的主机进程中。

使用 Brandon 在 here 上的回答中的想法,我让主机程序告诉我加载了哪些模块并显示模块的 GlblcntUsageProccntUsage。 注入 dll 后,计数为 1。在 FreeLibraryAndExitThread() 后,计数为零 - 但 dll 仍在加载!为什么?

顺便说一句,如果我改为调用 FreeLibrary(thisDllHandle),主机程序会崩溃(正如预期的那样),但 dll 会被卸载。

编辑

总结一下我正在尝试做的事情:我试图通过创建一个加载我的 dll 的远程线程来在远程进程中注入一个 dll;该 dll 生成另一个线程,该线程运行相同的 dll 代码并一直存在,并且原始线程退出;然后我希望该线程卸载 dll 并退出。

在尝试减少代码以便 post 它以响应@David Heffernan 的评论时,我设法让它工作 - 通过在调用 FreeLibrary 之前调用退出线程 FreeLibrary =20=]。但是我想了解为什么我必须两次释放它 - 我对这些东西不太了解。我认为这不需要代码,因为它非常简单:

  1. 获取远程进程的句柄。
  2. 在自己的 kernel32 模块中获取 LoadLibraryW 的地址。
  3. 在远程进程中分配内存,将[dll的路径]写入所述内存。
  4. 在远程进程句柄上调用 CreateRemoteThread,传入第 2 步的地址作为起始地址,传入第 3 步的地址作为参数。

这会导致远程进程中的线程使用 LoadLibraryW 加载我的 dll。当我的 Dll 被加载时,它会启动一个新线程(参见前面的 DllMain 代码),它在我的 dll 中运行一些其他函数(这个其他函数中的内容并不重要 - 我可以让它休眠 10 秒然后调用 FreeLibraryAndExitThread,行为相同)。我远程创建的原始线程死于 LoadLibraryW returns。所以现在只有一个线程 运行 我的 dll 代码。

当该线程调用 FreeLibraryAndExitThread 时,我希望我的 dll 从远程进程中卸载,因为该线程已释放库并退出。但 dll 仍处于加载状态,只有释放两次才能卸载它。

由于您在注入的 DllMain 函数中,并且由于您没有通过调用 _endthreadex() 函数退出线程,因此您可能应该使用 CreateThread() 而不是 _beginthreadex() 来启动新线程。避免使用 any C 运行时库函数也可能是明智的,尤其是当您无法确保您的 C 库与目标进程的库匹配时。

[我不清楚运行时库为何以及在什么情况下以所描述的方式运行,但 OP 报告说使用 CreateThread() 纠正了问题。我最好的猜测是它与 _onexit() 支持有关。]