关于DLL多次加载、卸载后。dll中创建窗口崩溃问题的解决。

时间:2024-02-19 09:55:07

  问题是这样的。 我做了一个外挂,把dll注入到目标程序,让目标程序启动两个线程,其中一个线程启动时会创建一个windows的窗口。

   创建窗口的代码是这样。

    

typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);


void CreateWnd()
{
    HWND parent_hWnd = GetForegroundWindow();
    g_hInnst = ::GetModuleHandle(NULL);
    HMODULE hModuleDLL = ::GetModuleHandle(L"InjectD.DLL");
    //
    AndroidSay("CreateWnd:WndProc:[%08x]", WndProc);
    WNDCLASS wc = { 0 };
    wc.style = 0;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = g_hInnst;
    wc.hIcon = NULL;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = TEXT("InjectDllWindow");
    RegisterClass(&wc);
    g_hWndMsg = CreateWindowEx(0, TEXT("InjectDllWindow"),TEXT("交易监控精灵"),
                               WS_VISIBLE, 0, 0, 200, 200, NULL, NULL, NULL, 0);
    if (!g_hWndMsg)
    {
        MessageBox(NULL, L"子窗口创建失败", L"Error", MB_OK);
    }
}

 

   当我的目标程序第一次加载,创建窗口是这样的。然后我给我创建的窗口发送一个窗口消息,来结束窗口,并卸载dll

LRESULT CALLBACK WndProc(HWND hWnd,UINT Msg, WPARAM wParam, LPARAM lParam)//
{
    if (Msg == WM_HAPPY_GAY)
    {
        AndroidSay("I\'m a happy gay!");
    }
    if (Msg == WM_USER_UNLOAD_DLL)
    {
        // 这里会出错,因为虽然创建的新进程退出了,但是这个Window还没退出。所以先发消息,wm_close
        LRESULT lresult = ::SendMessage(hWnd, WM_CLOSE, 0L, 0L);
        HANDLE hThread = CreateThread(NULL, 0, UnloadProc, NULL, 0, NULL);
        CloseHandle(hThread);
    }
    return DefWindowProc(hWnd, Msg, wParam, lParam);
}

 

   以下是卸载窗口退出线程的代码。

DWORD WINAPI UnloadProc(PVOID param)
{
    MessageBox(NULL, TEXT("Press ok to unload me."),
               TEXT("MsgBox in dll"), MB_OK);
    //UnregisterClass(TEXT("InjectDllWindow"), g_hInnst);
    FreeLibraryAndExitThread(g_AlbertData.hModule,0L);
    // oops!
    return 0;
}

 

  退出线程是正常,DLL卸载也完全正常。

   那么问题发生在,第二次加载这个DLL时,(注意:此时目标程序还没关闭。),加载代码运行都正常,但是当我的代码准备创建窗口时,dll程序崩溃了,崩溃地址如下:

   

以下是崩溃地址的堆栈。

 
user32.dll!__InternalCallWinProc@20 ()    未知
     user32.dll!UserCallWinProcCheckWow()    未知
     user32.dll!DispatchClientMessage()    未知
     user32.dll!___fnINOUTLPPOINT5@4 ()    未知
     ntdll.dll!772fad56()    未知
     user32.dll!_NtUserCreateWindowEx@68 ()    未知
     user32.dll!VerNtUserCreateWindowEx()    未知
     user32.dll!CreateWindowInternal()    未知
     user32.dll!_CreateWindowExW@48 ()    未知
>    InjectD.dll!CreateWnd() 行 115    C++
     InjectD.dll!ThreadMsg(wParam=0x00000000) 行 183    C++
     kernel32.dll!@BaseThreadInitThunk@12 ()    未知
     ntdll.dll!772e9e54()    未知
     ntdll.dll!772e9e1f()    未知

 

  废话不多说,为了解决这个问题,我在网上找了很多帖子,唯一相关的只有这篇 

http://www.cnblogs.com/terminator-studio/archive/2012/04/12/2444465.html  和http://blog.csdn.net/whitebird99/article/details/17759271

我一度是以为DLL加载时,函数WndProc调用的地址出错,经过反复验证,发现是没错的,也就是上文中的第一个地址,讲的是不对的。那么问题在哪里呢? 接着我偶然Google看到了老外的一个帖子。 《Don’t forget to unregister your window classes when your DLL shuts down dynamically》 https://blogs.msdn.microsoft.com/oldnewthing/20060920-07/?p=29663

 说的是如果你DLL卸载前,记得要把你注册的窗口类 注销掉。

 所以我在退出窗口和线程的代码加了一句话:

UnregisterClass(TEXT("InjectDllWindow"), g_hInnst);

 

经过测试发现果然可以。

  

-----------这个帖子留在这,如果后人遇到相同的问题可以找我,

我的联系 方式: qq 281656070