browser icon
You are using an insecure version of your web browser. Please update your browser!
Using an outdated browser makes your computer unsafe. For a safer, faster, more enjoyable user experience, please update your browser today or try a newer browser.

让 DLL 卸载自身

Posted by on 2009 年 04 月 23 日

你可以任意转载本文,但请在转载后的文章中注明作者和原始链接。
媒体约稿请联系 titilima_AT_163.com(把“_AT_”换成“@”)。

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#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 的一句替换为:

1
FreeLibraryAndExitThread(g_hDll, 0);

这样就可以了。

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

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

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

订阅本站

9 Comments

  • At 2009.04.23 17:24, likunkun said:

    经典,学习@_@

    • At 2009.04.24 00:19, 九九归一 said:

      我的理解是:FreeLibrary后程序不能向下执行,线程不能正常退出。。。
      FreeLibraryAndExitThread就可以。。就是FreeLibrary.和exitThread的组合。。。。

      • At 2009.06.05 14:30, 路过 said:

        我在写一个东西
        没人教,没也人交流
        hook winlogon里的模块函数来获取登陆密码
        但是,哪个我自己写的dll文件,始终在winlogon进程里
        IceSword,这样的工具查到太容易了
        有空试一下你这个方法
        感谢你的无私精神,谢谢
        其实技术这个东西,就像处女膜,一捅就破了…

        • At 2010.01.27 10:43, Miracle said:

          学习了……

          • At 2010.05.25 20:50, 夜猫子 said:

            FreeLibraryAndExitThread()
            这个函数有一个问题,
            如果你这个DLL同时注入多个进程,
            那么就要等到你注入的全部DLL都执行这个函数之后,
            DLL才会真正的被卸载

            • At 2010.05.25 21:52, 李马 said:

              不太明白你的意思,愿闻其详。

              • At 2010.07.31 12:57, CJCCCHJ said:

                版主可以写一个VB版的Dll卸载自身的程序吗?我正好要用,但不懂C语言。

                • At 2010.07.31 14:01, 李马 said:

                  和 C 没什么关系,你只需要知道怎么在 VB 中使用 API 函数 FreeLibraryAndExitThread,这就够了。

                  • At 2014.06.06 13:59, 远线程DLL注入技术 _ 程序人生 said:

                    […] 3. DLL注入执行完代码之后,可以通过调用FreeLibraryAndExitThread来实现自动卸载,具体参考让DLL卸载自身一文; […]

                    (Required)
                    (Required, will not be published)