DLL自我卸载

7

一个在DLL内部的函数是否可以卸载DLL?我需要这样做以确保DLL未被使用,然后写入DLL文件。

4个回答

22

据我理解,这是可以做到的,有时甚至是必须这样做的(例如在使用CreateRemoteThread和其他方法进行dll注入时)。所以,

最初的回答:

FreeLibraryAndExitThread(hModule, 0)

"最初的回答"
另一方面,调用

将正好做到这一点。

FreeLibrary(hModule)

"最初的回答"在这里行不通-根据MSDN的说法:“如果它们分别调用FreeLibrary和ExitThread,则存在竞态条件。在调用ExitThread之前,库可能已经被卸载。” 作为一条备注,除了从线程函数返回之外,ExitThread还执行一些簿记工作。
所有这些都假设您的DLL通过从加载的DLL内部调用LoadLibrary或者通过从加载的DLL内部调用以下函数来获取hModule:".
GetModuleHandleEx
(
    GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
    (LPCTSTR)DllMain,
    &hModule
)

这会增加Dll的引用计数,这样如果您稍后使用该句柄释放库并且该库确实被卸载,则说明您是最后一个对其的引用。
如果您跳过增加Dll的引用计数并仅从DLL_PROCESS_ATTACH期间 DllMain 的参数中获取hModule,则不应调用 FreeLibraryAndExitThread ,因为加载Dll的代码仍在使用它,而此模块句柄真的不是您要管理的。

这根本没有任何意义...当你使用LoadLibrary加载DLL时,它会将引用计数加1。它永远不会减少它。然后,你调用GetModuleHandleEx,它再次将其增加1(顺便说一下,句柄与DllMain参数中的相同)。现在你调用FreeLibraryAndExitThread,它将计数减1。你最终得到一个引用计数为1的结果,而DLL永远不会被卸载! - ScienceDiscoverer
@ScienceDiscoverer,你可以使用LoadLibraryGetModuleHandleEx中的任意一个,不需要同时使用两者。我在上面的帖子中所说的是另一件事情。我是指如果你从DllMain参数中获取了句柄,则不应该使用此句柄进行卸载,因为从DllMain获取句柄根本不会增加引用计数。 - Roland Pihlakas

8

当dll完成其工作时,请使用此方法:

    CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, &__ImageBase, 0, NULL);
    // terminate if dll run in a separate thread ExitThread(0); 
    // or just return out the dll

而 __ImageBase 是你的 dll 的 PE 头结构:

EXTERN_C IMAGE_DOS_HEADER __ImageBase;

3
这个技巧可能有所帮助,但理论上如果调用CreateThread的线程在调用CreateThread后停留时间过长,仍然可能导致竞态条件。请查看我有关FreeLibraryAndExitThread函数的答案。 - Roland Pihlakas

1
如果你想知道是否可以从DLL本身的代码中安全地卸载/取消映射一个已加载到进程中的DLL,答案是不行 - 实际上没有一种安全的方式来实现这个。
这样考虑一下:通过使用FreeLibrary()函数将DLL的引用计数减少来卸载一个DLL。问题当然是,一旦DLL的引用计数达到零,该模块就会被取消映射。这意味着调用FreeLibrary()的DLL中的代码消失了。
即使你能够做到这一点,你仍然需要确保没有其他线程在执行DLL的任何导出函数。

0

我认为这不会起作用。使用来自外部的句柄调用FreeLibrary(LoadLibrary将从DLL外部调用),因为代码运行在一个将不再有效的内存位置。

即使这是可能的,它看起来像是一个糟糕的设计。也许你想制作一些更新程序或类似的东西。请解释一下你期望的结果是什么。从自身内部卸载DLL不是正确的方法。


5
请查看我关于FreeLibraryAndExitThread函数的答案。 - Roland Pihlakas
2
如果您的DLL中有后台线程,调用FreeLibrary并不是最佳选择。最好使用FreeLibraryAndExitThread函数。这个函数就像一块石头,可以杀死两只鸟。 - Hao Nguyen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接