问题是这样的。 我做了一个外挂,把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