DLL 自行卸载
Posted
技术标签:
【中文标题】DLL 自行卸载【英文标题】:DLL unloading itself 【发布时间】:2010-08-04 21:49:23 【问题描述】:DLL 中的函数是否可以卸载 DLL?我需要这样做以确保 DLL 未在使用中,然后写入 DLL 的文件。
【问题讨论】:
【参考方案1】:据我了解,它可以完成,有时也应该完成(例如,在通过 CreateRemoteThread 和其他方法注入 dll 的情况下)。所以,
FreeLibraryAndExitThread(hModule, 0)
会做到这一点。
另一方面,调用
FreeLibrary(hModule)
不会在这里做 - 来自 MSDN:“如果他们分别调用 FreeLibrary 和 ExitThread,就会存在竞争条件。可以在调用 ExitThread 之前卸载库。” 作为备注,除了从线程函数返回之外,ExitThread 还会做一些记账。
所有这一切都假设您的 Dll 通过从已加载的 Dll 内部调用 LoadLibrary 来获取 hModule 本身,或者更确切地说,通过从已加载的 Dll 内部调用以下函数来获取 hModule:
GetModuleHandleEx
(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(LPCTSTR)DllMain,
&hModule
)
这会增加 Dll 的引用计数,因此您知道,如果您稍后使用该句柄释放库,并且如果库真的被卸载,那么您拥有对它的最后引用。 如果您在 DLL_PROCESS_ATTACH 期间跳过增加 Dll 的引用计数并仅从 DllMain 的参数获取 hModule,那么您不应调用 FreeLibraryAndExitThread,因为加载 Dll 的代码仍在使用它,这个模块句柄确实不是你来管理的。
【讨论】:
【参考方案2】:在 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;
【讨论】:
这个技巧可能会有所帮助,但从理论上讲,如果调用 CreateThread 的线程在调用 CreateThread 后逗留时间过长,它仍然可能导致竞争条件。请参阅我关于 FreeLibraryAndExitThread 函数的回答。【参考方案3】:我认为它不会起作用。当代码在不再有效的内存位置运行时,使用外部句柄调用 FreeLibrary(LoadLibrary 会从 DLL 外部的区域调用)。
即使这是可能的,但它闻起来像是一个糟糕的设计。也许您想制作一些更新程序或类似的东西。多解释一下您期望的结果是什么。从内部卸载 DLL 不是可行的方法。
【讨论】:
请看我关于 FreeLibraryAndExitThread 函数的回答 如果您的 DLL 中有后台线程,则调用 FreeLibrary 不是最佳选择。最好使用FreeLibraryAndExitThread。这个功能是一块可以杀死2只鸟的石头。【参考方案4】:如果您询问是否可以从 DLL 本身的代码中安全地卸载/取消映射进程中加载的 DLL,答案是否定的 - 没有真正安全的方法来做到这一点。
这样想:卸载 DLL 是通过使用 FreeLibrary() 减少它的引用计数来完成的。问题当然是一旦 DLL 的引用计数达到零,模块就会被取消映射。这意味着 DLL 中调用 FreeLibrary() 的代码消失了。
即使您可以这样做,您仍然需要确保没有其他线程执行任何从 DLL 导出的函数。
【讨论】:
以上是关于DLL 自行卸载的主要内容,如果未能解决你的问题,请参考以下文章