DLL卸载自己

Iro*_*ron 3 dll self-reference

DLL中的函数是否可以卸载DLL?我需要这样做,所以我可以确保DLL没有被使用,然后写入DLL的文件.

Rol*_*kas 14

据我所知,它可以完成,并且有时可以完成(例如在CreateRemoteThread和其他方法注入dll的情况下).所以,

FreeLibraryAndExitThread(hModule, 0)
Run Code Online (Sandbox Code Playgroud)

会做到这一点.

另一方面,打电话

FreeLibrary(hModule)
Run Code Online (Sandbox Code Playgroud)

这里不做 - 来自MSDN:"如果他们分别调用FreeLibrary和ExitThread,就会出现竞争条件.在调用ExitThread之前可以卸载库." 作为一个评论,除了从线程函数返回之外,ExitThread还会进行一些簿记.

所有这些假设您的Dll通过从加载的Dll内部调用LoadLibrary来获取hModule本身,或者更确切地说,通过从加载的Dll内部调用以下函数:

GetModuleHandleEx
(
    GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
    (LPCTSTR)DllMain,
    &hModule
)
Run Code Online (Sandbox Code Playgroud)

这会增加Dll的引用计数,因此您知道如果稍后使用该句柄释放库,并且如果实际卸载了库,那么您最后一次引用它.
如果您在DLL_PROCESS_ATTACH期间跳过递增Dll的引用计数并仅从DllMain的参数获取hModule,那么您不应该调用FreeLibraryAndExitThread,因为加载Dll的代码仍在使用它,并且此模块句柄实际上不是您管理的.


小智 5

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
Run Code Online (Sandbox Code Playgroud)

__ImageBase是您的dll的PE标头结构:

EXTERN_C IMAGE_DOS_HEADER __ImageBase;
Run Code Online (Sandbox Code Playgroud)

  • 这个技巧可能会有所帮助,但从理论上讲,如果调用 CreateThread 的线程在调用 CreateThread 后停留太久,它仍然可能导致竞争条件。请参阅我关于 FreeLibraryAndExitThread 函数的回答。 (3认同)

jde*_*aan 0

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

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

  • 请参阅我关于 FreeLibraryAndExitThread 函数的回答 (5认同)
  • 如果 DLL 中有后台线程,则调用 FreeLibrary 并不是最佳选择。最好使用[FreeLibraryAndExitThread](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683153(v=vs.85).aspx)。这个功能是一块石头,可以杀死2只鸟。 (2认同)