123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- #include "stdafx.h"
- #include "CWxObject.h"
- #include <math.h>
- #define WX_MAIN_WND_NAME _T("微信")
- #define WX_MAIN_WND_CLASS_NAME _T("WeChatMainWndForPC")
- #define WX_LOGIN_WND_NAME _T("登录")
- #define WX_LOGIN_WND_CLASS_NAME _T("WeChatLoginWndForPC")
- HHOOK CWxObject::m_hook = NULL;
- BOOL ASCII2UNICODE(IN LPCCH lpASCIIStr, OUT PWCH pUNICODEStr, IN CONST INT& nUNICODEStrLen)
- {
- if (lpASCIIStr == NULL)
- return FALSE;
- // 获取宽字符字节数;
- int cchWideChar = MultiByteToWideChar(CP_ACP, 0, lpASCIIStr, -1, NULL, 0);
- if (cchWideChar == 0 || cchWideChar >= nUNICODEStrLen)
- return FALSE;
- // 转换成宽字符串;
- memset(pUNICODEStr, 0, sizeof(WCHAR)*nUNICODEStrLen);
- int nWriteNum = MultiByteToWideChar(CP_ACP, 0, lpASCIIStr, -1, pUNICODEStr, cchWideChar);
- if (nWriteNum != cchWideChar)
- return FALSE;
- return TRUE;
- }
- CWxObject::CWxObject()
- :m_dwWxProcId(0)
- , m_hWxProcess(NULL)
- , m_hWxMainWnd(NULL)
- , m_hWxLoginWnd(NULL)
- , m_lpInjectData(NULL)
- , m_lpEjectData(NULL)
- , m_hInjectThread(NULL)
- , m_hEjectThread(NULL)
- , m_dwPathLen(0)
- , m_bAttached(FALSE)
- //, m_hook(NULL)
- {
- memset(&m_WxMainWndInfo, 0, sizeof(WNDINFO));
- }
- CWxObject::CWxObject(DWORD dwProcId, LPCTSTR lpDynamicLibraryPath)
- :m_dwWxProcId(dwProcId)
- , m_hWxProcess(NULL)
- , m_hWxMainWnd(NULL)
- , m_hWxLoginWnd(NULL)
- , m_lpInjectData(NULL)
- , m_lpEjectData(NULL)
- , m_hInjectThread(NULL)
- , m_hEjectThread(NULL)
- , m_dwPathLen(0)
- , m_bAttached(FALSE)
- //, m_hook(NULL)
- {
- memset(&m_WxMainWndInfo, 0, sizeof(WNDINFO));
- setInjectionObj(dwProcId, lpDynamicLibraryPath);
- }
- CWxObject::~CWxObject()
- {
- // 卸载dll;
- EjectDynamicLibrary();
- // 释放所有资源;
- if (m_hInjectThread)
- CloseHandle(m_hInjectThread);
- m_hInjectThread = NULL;
- if (m_hEjectThread)
- CloseHandle(m_hEjectThread);
- m_hEjectThread = NULL;
- if (m_lpInjectData)
- VirtualFreeEx(m_hWxProcess, m_lpInjectData, m_dwPathLen, MEM_RELEASE);
- m_lpInjectData = NULL;
- if (m_lpEjectData)
- VirtualFreeEx(m_hWxProcess, m_lpEjectData, m_dwPathLen, MEM_RELEASE);
- m_lpEjectData = NULL;
- if (m_hWxProcess)
- CloseHandle(m_hWxProcess);
- m_hWxProcess = NULL;
- // 退出主窗口;
- // 注:必须在主窗口销毁前分离;
- if (!m_bAttached)
- DetachWxWnd();
- if (m_hook)
- UnhookWindowsHookEx(m_hook);
- }
- void CWxObject::setInjectionObj(DWORD dwProcId, LPCTSTR lpDynamicLibraryPath)
- {
- ASSERT(dwProcId != 0);
- ASSERT(lpDynamicLibraryPath != NULL);
- m_dwWxProcId = dwProcId;
- memset(m_szDllPath, 0, sizeof(m_szDllPath));
- memset(m_wszDllPath, 0, sizeof(m_wszDllPath));
- #ifdef UNICODE
- _tcscpy_s(m_szDllPath, lpDynamicLibraryPath);
- #else
- _tcscpy_s(m_szDllPath, lpDynamicLibraryPath);
- ASCII2UNICODE(lpDynamicLibraryPath, m_wszDllPath, MAX_PATH);
- #endif
- //m_hWxProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_dwWxProcId);
- m_hWxProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, m_dwWxProcId);
- if (m_hWxProcess == NULL)
- {
- WriteTextLog(_T("打开WeChat.exe进程失败"));
- }
- }
- BOOL CWxObject::InjectDynamicLibrary()
- {
- ASSERT(m_hWxProcess != NULL);
- m_dwPathLen = wcslen(m_wszDllPath) * sizeof(WCHAR) + 1;
- m_lpInjectData = VirtualAllocEx(m_hWxProcess, NULL, m_dwPathLen, MEM_COMMIT, PAGE_READWRITE);
- if (NULL == m_lpInjectData)
- {
- WriteTextLog(_T("创建WeChat.exe进程虚拟内存失败"));
- return FALSE;
- }
- if (WriteProcessMemory(m_hWxProcess, m_lpInjectData, m_wszDllPath, m_dwPathLen, NULL) == 0)
- {
- // 注意:MEM_RELEASE释放时第三参数一定要为0,请查看MSDN;
- VirtualFreeEx(m_hWxProcess, m_lpInjectData, 0, MEM_RELEASE);
- return FALSE;
- }
- HMODULE hk32 = GetModuleHandle(_T("kernel32.dll"));
- // 注意:微信使用的是W版本;
- LPVOID lpAddr = GetProcAddress(hk32, "LoadLibraryW");
- m_hInjectThread = CreateRemoteThread(m_hWxProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpAddr, m_lpInjectData, 0, NULL);
- if (NULL == m_hInjectThread)
- {
- // 注意:MEM_RELEASE释放时第三参数一定要为0,请查看MSDN;
- VirtualFreeEx(m_hWxProcess, m_lpInjectData, 0, MEM_RELEASE);
- return FALSE;
- }
- WaitForSingleObject(m_hInjectThread, INFINITE);
- if (m_hInjectThread)
- CloseHandle(m_hInjectThread);
- m_hInjectThread = NULL;
- /* 注入成功后,不能释放内存否则微信会挂;
- if (m_lpInjectData != NULL)
- VirtualFreeEx(m_hWxProcess, m_lpInjectData, 0, MEM_RELEASE);
- */
- return TRUE;
- }
- BOOL CWxObject::EjectDynamicLibrary()
- {
- if (m_hWxProcess == NULL)
- return TRUE;
- // 获取模块句柄;
- HANDLE hModule = FindModuleEx(m_szDllPath, m_dwWxProcId);
- if (hModule == NULL)
- {
- WriteTextLog(_T("获取WeChat.exe进程模块hook.dll失败"));
- return FALSE;
- }
- LPVOID lpAddr = GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "FreeLibraryAndExitThread");//FreeLibraryAndExitThread//FreeLibrary
- if (lpAddr == NULL)
- {
- WriteTextLog(_T("获取kernel32.dll中的FreeLibraryAndExitThread失败"));
- return FALSE;
- }
- m_hEjectThread = CreateRemoteThread(m_hWxProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpAddr, hModule, 0, NULL);
- if (m_hEjectThread == NULL)
- {
- WriteTextLog(_T("创建WeChat.exe远程线程(FreeLibraryAndExitThread)失败"));
- return FALSE;
- }
- WaitForSingleObject(m_hEjectThread, INFINITE);
- if (m_hEjectThread)
- CloseHandle(m_hEjectThread);
- m_hEjectThread = NULL;
- return TRUE;
- }
- BOOL CWxObject::FindWxMainWnd()
- {
- m_WxMainWndInfo.hWxWnd = NULL;
- m_WxMainWndInfo.dwWxProcId = m_dwWxProcId;
- _stprintf_s(m_WxMainWndInfo.szWndName, WX_MAIN_WND_NAME);
- _stprintf_s(m_WxMainWndInfo.szClassName, WX_MAIN_WND_CLASS_NAME);
- if (::EnumWindows(&EnumWindowsProc, (LPARAM)& m_WxMainWndInfo) == FALSE)
- {
- m_hWxMainWnd = m_WxMainWndInfo.hWxWnd;
- m_rcWxWnd = m_WxMainWndInfo.rcWnd;
- return TRUE;
- }
- return FALSE;
- }
- BOOL CWxObject::FindWxLoginWnd()
- {
- m_WxLoginWndInfo.hWxWnd = NULL;
- m_WxLoginWndInfo.dwWxProcId = m_dwWxProcId;
- _stprintf_s(m_WxLoginWndInfo.szWndName, WX_LOGIN_WND_NAME);
- _stprintf_s(m_WxLoginWndInfo.szClassName, WX_LOGIN_WND_CLASS_NAME);
- if (::EnumWindows(&EnumWindowsProc, (LPARAM)& m_WxLoginWndInfo) == FALSE)
- {
- m_hWxLoginWnd = m_WxLoginWndInfo.hWxWnd;
- m_rcWxWnd = m_WxLoginWndInfo.rcWnd;
- return TRUE;
- }
- return FALSE;
- }
- BOOL CWxObject::Attach2MainWnd(CWnd *pMainWnd, BOOL bLoginWnd)
- {
- HWND hWxWnd = bLoginWnd ? m_hWxLoginWnd : m_hWxMainWnd;
- if (hWxWnd != NULL)
- {
- // 获取微信窗口的样式;
- DWORD dwStyle = ::GetWindowLong(hWxWnd, GWL_STYLE);
- // WS_CLIPSIBLINGS告诉父窗口不要绘制子窗口出现的区域;
- //dwStyle |= WS_CLIPSIBLINGS;
- // 如果窗口隐藏的,显示出来;
- dwStyle |= WS_VISIBLE;
- // 重新设置窗口样式 ;
- ::SetWindowLong(hWxWnd, GWL_STYLE, dwStyle);
- CRect rect;
- pMainWnd->GetWindowRect(&rect);
- // 设置父窗口;
- ::SetParent(hWxWnd, pMainWnd->m_hWnd);//set parent of ms paint to our dialog.
- // 擦除背景;
- //SetWindowLong(hWxWnd, GWL_STYLE, WS_VISIBLE);//eraze title of ms paint window.
- //Positioning ms paint.
- // 将屏幕坐标转在窗口坐标;
- pMainWnd->ScreenToClient(&rect);
- // 居中显示;
- CRect rcDisplay = rect;
- if (bLoginWnd)
- {// 居中显示;
- if (m_rcWxWnd.Width() >= rect.Width())
- {
- rcDisplay.left = 0;
- rcDisplay.right = rect.right;
- }
- else
- {
- rcDisplay.left = (rect.Width() - m_rcWxWnd.Width()) / 2;
- rcDisplay.right = rcDisplay.left + m_rcWxWnd.Width();
- }
- if (m_rcWxWnd.Height() >= rect.Height())
- {
- rcDisplay.top = 0;
- rcDisplay.bottom = rect.bottom;
- }
- else
- {
- rcDisplay.top = (rect.Height() - m_rcWxWnd.Height()) / 2;
- rcDisplay.bottom = rcDisplay.top + m_rcWxWnd.Height();
- }
- // 注意:MoveWindow/SetWindowPos使用的是父窗口的坐标,如果父窗口为NULL,则使用的是屏幕坐标;
- ::MoveWindow(hWxWnd, rcDisplay.left, rcDisplay.top, rcDisplay.Width(), rcDisplay.Height(), true);
- //::SetWindowPos(hWxWnd, NULL, rcDisplay.left, rcDisplay.top, rcDisplay.Width(), rcDisplay.Height(), WM_WINDOWPOSCHANGING|SWP_SHOWWINDOW | SWP_HIDEWINDOW);
- }
- else
- {//最大化显示并固定;
- // 注意:MoveWindow/SetWindowPos使用的是父窗口的坐标,如果父窗口为NULL,则使用的是屏幕坐标;
- ::MoveWindow(hWxWnd, rcDisplay.left, rcDisplay.top, rcDisplay.Width(), rcDisplay.Height(), true);
- if (!bLoginWnd)
- ::PostMessage(hWxWnd, WM_SYSCOMMAND, SC_MAXIMIZE, NULL);
- //::SetWindowPos(hWxWnd, NULL, rcDisplay.left, rcDisplay.top, rcDisplay.Width(), rcDisplay.Height(), WM_MOVE| WM_SIZE| WM_WINDOWPOSCHANGING| WM_NCCALCSIZE | SWP_SHOWWINDOW);
- }
- //窗口重绘,(因创建exe时,设置为SW_HIDE,导致exe窗口会被父窗口覆盖一部分)
- pMainWnd->Invalidate();
- ::UpdateWindow(hWxWnd);
- ::ShowWindow(hWxWnd, SW_SHOW);
- m_bAttached = TRUE;
- }
- return 0;
- }
- BOOL CWxObject::DetachWxWnd()
- {
- if (m_bAttached)
- {
- //if (m_hWxMainWnd && GetParent(m_hWxMainWnd))
- if (m_hWxMainWnd) // 使用GetParent可能返回NULL
- ::SetParent(m_hWxMainWnd, NULL);
- if (m_hWxLoginWnd)
- ::SetParent(m_hWxLoginWnd, NULL);
- m_bAttached = FALSE;
- #ifdef _DEBUG
- WriteTextLog(_T("DetachWxWnd:分离微信窗口"));
- #endif
- }
- return 0;
- }
- BOOL CWxObject::SetHook()
- {
- if (m_hook == NULL)
- m_hook = SetWindowsHookEx(WH_CBT, HookProc, NULL, ::GetCurrentThreadId());
- return 0;
- }
- BOOL CWxObject::EnumWindowsProc(HWND hwnd, LPARAM lParam)
- {
- DWORD dwProcId = 0, dwThreadId;
- TCHAR szWndName[MAX_PATH] = { 0 };
- TCHAR szClassName[MAX_PATH] = { 0 };
- WNDINFO* pWndInfo = (WNDINFO*)lParam;
- dwThreadId = GetWindowThreadProcessId(hwnd, &dwProcId);
- if (dwProcId == pWndInfo->dwWxProcId)
- {
- pWndInfo->hWxWnd = hwnd;
- pWndInfo->dwThreadId = dwThreadId;
- ::GetWindowText(hwnd, szWndName, MAX_PATH);
- ::GetClassName(hwnd, szClassName, MAX_PATH);
- #ifdef _DEBUG
- WriteTextLog(_T("窗口名称:%s, 窗口类名:%s, 线程ID:%d,句柄:%p"), szWndName, szClassName, dwThreadId, hwnd);
- #endif
- if (_tcscmp(szWndName, pWndInfo->szWndName) == 0 && _tcscmp(szClassName, pWndInfo->szClassName) == 0)
- {
- ::GetWindowRect(hwnd, &pWndInfo->rcWnd);
- return FALSE;
- }
- }
- return TRUE;
- }
- LRESULT CWxObject::HookProc(int nCode, WPARAM wParam, LPARAM lParam)
- {
- WriteTextLog(_T("HookProc被调用"));
- if (nCode == HCBT_MINMAX)
- {
- WriteTextLog(_T("窗口HCBT_MINMAX"));
- return 1;
- }
- return CallNextHookEx(m_hook, nCode, wParam, lParam);
- }
- BOOL CWxObject::OpenWeChat()
- {
- return 0;
- }
|