黑夜的狼

沮丧吗,那就是一种无病呻吟!留恋它就是一种高度近视!目光应该放得更远一点! 别不想飞,只是要一步跨过太平洋!

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

今天的问题是:有没有可能让一个 DLL 自己卸载自己?
这个问题可以分成两个部分:

  1. 卸载一个 DLL。
  2. 卸载 DLL 的代码应该是放在 DLL 之中的。

当然,如果不考虑后果的话,这个代码并不难写,如下:

C++代码

 

代码
#include <Windows.h>    
   
HMODULE g_hDll 
= NULL;    
   
DWORD WINAPI UnloadProc(PVOID param)    
{    
    MessageBox(NULL, TEXT(
"Press ok to unload me."),    
        TEXT(
"MsgBox in dll"), MB_OK);    
    FreeLibrary(g_hDll);    
    
// oops!    
    return 0;    
}    
   
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, PVOID lpvReserved)    
{    
    
if (DLL_PROCESS_ATTACH == fdwReason)    
    {    
        g_hDll 
= (HMODULE)hinstDLL;    
        HANDLE hThread 
= CreateThread(NULL, 0, UnloadProc, NULL, 0, NULL);    
        CloseHandle(hThread);    
    }    
    
return TRUE;    

 

 

简单说明一下:在 DllMain 初始化的时候保存 DLL 的实例句柄(即模块句柄)供 FreeLibrary 调用,然后开启一个线程,在适当的时机调用 FreeLibrary 销毁 DLL。
但是,如果实际运行起来的话,我们会遇到一个很实际的问题:在 FreeLibrary 之后,该 DLL 的地址空间就不再可用了,但这时 EIP 指针仍然会指向 FreeLibrary 的下面一句,于是程序崩溃。
所幸,Win32 提供了另外的一个 API——FreeLibraryAndExitThread,这个函数能够在销毁 DLL 之后直接调用 ExitThread,这样一来 EIP 指针就不会指向非法的地址了。因此,我们只需要把 FreeLibrary 的一句替换为:

C++代码
  1. FreeLibraryAndExitThread(g_hDll, 0);  

这样就可以了。

实际测试一下,在 DLL 被加载后,July 的模块视图显示了这个被加载的 DLL。

大小: 5.25 K
尺寸: 296 x 70
浏览: 160 次
点击打开新窗口浏览全图

在内存视图中检查模块句柄指向的内容,证明该 DLL 的确被加载了。

大小: 23.13 K
尺寸: 484 x 223
浏览: 165 次
点击打开新窗口浏览全图

FreeLibraryAndExitThread 调用后,再查看该模块句柄指向的内存,该地址已不再可用,销毁成功。

大小: 24.18 K
尺寸: 484 x 223
浏览: 151 次
点击打开新窗口浏览全图

posted on 2010-04-06 16:14  anncesky  阅读(363)  评论(0编辑  收藏  举报