CWxObject.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. #include "stdafx.h"
  2. #include "CWxObject.h"
  3. #define WX_MAIN_WND_NAME _T("微信")
  4. #define WX_MAIN_WND_CLASS_NAME _T("WeChatMainWndForPC")
  5. #define WX_LOGIN_WND_NAME _T("登录")
  6. #define WX_LOGIN_WND_CLASS_NAME _T("WeChatLoginWndForPC")
  7. BOOL ASCII2UNICODE(IN LPCCH lpASCIIStr, OUT PWCH pUNICODEStr, IN CONST INT& nUNICODEStrLen)
  8. {
  9. if (lpASCIIStr == NULL)
  10. return FALSE;
  11. // 获取宽字符字节数;
  12. int cchWideChar = MultiByteToWideChar(CP_ACP, 0, lpASCIIStr, -1, NULL, 0);
  13. if (cchWideChar == 0 || cchWideChar >= nUNICODEStrLen)
  14. return FALSE;
  15. // 转换成宽字符串;
  16. memset(pUNICODEStr, 0, sizeof(WCHAR)*nUNICODEStrLen);
  17. int nWriteNum = MultiByteToWideChar(CP_ACP, 0, lpASCIIStr, -1, pUNICODEStr, cchWideChar);
  18. if (nWriteNum != cchWideChar)
  19. return FALSE;
  20. return TRUE;
  21. }
  22. CWxObject::CWxObject()
  23. :m_dwWxProcId(0)
  24. , m_hWxProcess(NULL)
  25. , m_hWxMainWnd(NULL)
  26. , m_hWxLoginWnd(NULL)
  27. , m_lpInjectData(NULL)
  28. , m_lpEjectData(NULL)
  29. , m_hInjectThread(NULL)
  30. , m_hEjectThread(NULL)
  31. , m_dwPathLen(0)
  32. , m_bAttached(FALSE)
  33. {
  34. }
  35. CWxObject::CWxObject(DWORD dwProcId, LPCTSTR lpDynamicLibraryPath)
  36. :m_dwWxProcId(dwProcId)
  37. , m_hWxProcess(NULL)
  38. , m_hWxMainWnd(NULL)
  39. , m_hWxLoginWnd(NULL)
  40. , m_lpInjectData(NULL)
  41. , m_lpEjectData(NULL)
  42. , m_hInjectThread(NULL)
  43. , m_hEjectThread(NULL)
  44. , m_dwPathLen(0)
  45. , m_bAttached(FALSE)
  46. {
  47. setInjectionObj(dwProcId, lpDynamicLibraryPath);
  48. }
  49. CWxObject::~CWxObject()
  50. {
  51. // 卸载dll;
  52. EjectDynamicLibrary();
  53. // 释放所有资源;
  54. if (m_hInjectThread)
  55. CloseHandle(m_hInjectThread);
  56. m_hInjectThread = NULL;
  57. if (m_hEjectThread)
  58. CloseHandle(m_hEjectThread);
  59. m_hEjectThread = NULL;
  60. if (m_lpInjectData)
  61. VirtualFreeEx(m_hWxProcess, m_lpInjectData, m_dwPathLen, MEM_RELEASE);
  62. m_lpInjectData = NULL;
  63. if (m_lpEjectData)
  64. VirtualFreeEx(m_hWxProcess, m_lpEjectData, m_dwPathLen, MEM_RELEASE);
  65. m_lpEjectData = NULL;
  66. if (m_hWxProcess)
  67. CloseHandle(m_hWxProcess);
  68. m_hWxProcess = NULL;
  69. }
  70. void CWxObject::setInjectionObj(DWORD dwProcId, LPCTSTR lpDynamicLibraryPath)
  71. {
  72. ASSERT(dwProcId != 0);
  73. ASSERT(lpDynamicLibraryPath != NULL);
  74. m_dwWxProcId = dwProcId;
  75. memset(m_szDllPath, 0, sizeof(m_szDllPath));
  76. memset(m_wszDllPath, 0, sizeof(m_wszDllPath));
  77. #ifdef UNICODE
  78. _tcscpy_s(m_szDllPath, lpDynamicLibraryPath);
  79. #else
  80. _tcscpy_s(m_szDllPath, lpDynamicLibraryPath);
  81. ASCII2UNICODE(lpDynamicLibraryPath, m_wszDllPath, MAX_PATH);
  82. #endif
  83. //m_hWxProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_dwWxProcId);
  84. m_hWxProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, m_dwWxProcId);
  85. if (m_hWxProcess == NULL)
  86. {
  87. WriteTextLog(_T("打开WeChat.exe进程失败"));
  88. }
  89. }
  90. BOOL CWxObject::InjectDynamicLibrary()
  91. {
  92. ASSERT(m_hWxProcess != NULL);
  93. m_dwPathLen = wcslen(m_wszDllPath) * sizeof(WCHAR) + 1;
  94. m_lpInjectData = VirtualAllocEx(m_hWxProcess, NULL, m_dwPathLen, MEM_COMMIT, PAGE_READWRITE);
  95. if (NULL == m_lpInjectData)
  96. {
  97. WriteTextLog(_T("创建WeChat.exe进程虚拟内存失败"));
  98. return FALSE;
  99. }
  100. if (WriteProcessMemory(m_hWxProcess, m_lpInjectData, m_wszDllPath, m_dwPathLen, NULL) == 0)
  101. {
  102. // 注意:MEM_RELEASE释放时第三参数一定要为0,请查看MSDN;
  103. VirtualFreeEx(m_hWxProcess, m_lpInjectData, 0, MEM_RELEASE);
  104. return FALSE;
  105. }
  106. HMODULE hk32 = GetModuleHandle(_T("kernel32.dll"));
  107. // 注意:微信使用的是W版本;
  108. LPVOID lpAddr = GetProcAddress(hk32, "LoadLibraryW");
  109. m_hInjectThread = CreateRemoteThread(m_hWxProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpAddr, m_lpInjectData, 0, NULL);
  110. if (NULL == m_hInjectThread)
  111. {
  112. // 注意:MEM_RELEASE释放时第三参数一定要为0,请查看MSDN;
  113. VirtualFreeEx(m_hWxProcess, m_lpInjectData, 0, MEM_RELEASE);
  114. return FALSE;
  115. }
  116. WaitForSingleObject(m_hInjectThread, INFINITE);
  117. if (m_hInjectThread)
  118. CloseHandle(m_hInjectThread);
  119. m_hInjectThread = NULL;
  120. /* 注入成功后,不能释放内存否则微信会挂;
  121. if (m_lpInjectData != NULL)
  122. VirtualFreeEx(m_hWxProcess, m_lpInjectData, 0, MEM_RELEASE);
  123. */
  124. return TRUE;
  125. }
  126. BOOL CWxObject::EjectDynamicLibrary()
  127. {
  128. if (m_hWxProcess == NULL)
  129. return TRUE;
  130. // 获取模块句柄;
  131. HANDLE hModule = FindModuleEx(m_szDllPath, m_dwWxProcId);
  132. if (hModule == NULL)
  133. {
  134. WriteTextLog(_T("获取WeChat.exe进程模块hook.dll失败"));
  135. return FALSE;
  136. }
  137. LPVOID lpAddr = GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "FreeLibraryAndExitThread");//FreeLibraryAndExitThread//FreeLibrary
  138. if (lpAddr == NULL)
  139. {
  140. WriteTextLog(_T("获取kernel32.dll中的FreeLibraryAndExitThread失败"));
  141. return FALSE;
  142. }
  143. m_hEjectThread = CreateRemoteThread(m_hWxProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpAddr, hModule, 0, NULL);
  144. if (m_hEjectThread == NULL)
  145. {
  146. WriteTextLog(_T("创建WeChat.exe远程线程(FreeLibraryAndExitThread)失败"));
  147. return FALSE;
  148. }
  149. WaitForSingleObject(m_hEjectThread, INFINITE);
  150. if (m_hEjectThread)
  151. CloseHandle(m_hEjectThread);
  152. m_hEjectThread = NULL;
  153. return TRUE;
  154. }
  155. BOOL CWxObject::FindWxMainWnd()
  156. {
  157. WNDINFO wnd;
  158. wnd.hWxWnd = NULL;
  159. wnd.dwWxProcId = m_dwWxProcId;
  160. _stprintf_s(wnd.szWndName, WX_MAIN_WND_NAME);
  161. _stprintf_s(wnd.szClassName, WX_MAIN_WND_CLASS_NAME);
  162. if (::EnumWindows(&EnumWindowsProc, (LPARAM)&wnd) == FALSE)
  163. {
  164. m_hWxMainWnd = wnd.hWxWnd;
  165. m_rcWxWnd = wnd.rcWnd;
  166. return TRUE;
  167. }
  168. return FALSE;
  169. }
  170. BOOL CWxObject::FindWxLoginWnd()
  171. {
  172. WNDINFO wnd;
  173. wnd.hWxWnd = NULL;
  174. wnd.dwWxProcId = m_dwWxProcId;
  175. _stprintf_s(wnd.szWndName, WX_LOGIN_WND_NAME);
  176. _stprintf_s(wnd.szClassName, WX_LOGIN_WND_CLASS_NAME);
  177. if (::EnumWindows(&EnumWindowsProc, (LPARAM)&wnd) == FALSE)
  178. {
  179. m_hWxLoginWnd = wnd.hWxWnd;
  180. m_rcWxWnd = wnd.rcWnd;
  181. return TRUE;
  182. }
  183. return FALSE;
  184. }
  185. BOOL CWxObject::Attach2MainWnd(CWnd *pMainWnd, BOOL bLoginWnd )
  186. {
  187. HWND hWxWnd = bLoginWnd ? m_hWxLoginWnd : m_hWxMainWnd;
  188. if (hWxWnd != NULL)
  189. {
  190. // 获取微信窗口的样式;
  191. DWORD dwStyle = ::GetWindowLong(hWxWnd, GWL_STYLE);
  192. // WS_CLIPSIBLINGS告诉父窗口不要绘制子窗口出现的区域;
  193. dwStyle |= WS_CLIPSIBLINGS;
  194. // 如果窗口隐藏的,显示出来;
  195. dwStyle |= WS_VISIBLE;
  196. // 重新设置窗口样式 ;
  197. ::SetWindowLong(hWxWnd, GWL_STYLE, dwStyle);
  198. CRect rect;
  199. pMainWnd->GetWindowRect(&rect);
  200. // 设置背景透明;
  201. ::SetParent(hWxWnd, pMainWnd->m_hWnd);//set parent of ms paint to our dialog.
  202. // 擦除背景;
  203. //SetWindowLong(hWxWnd, GWL_STYLE, WS_VISIBLE);//eraze title of ms paint window.
  204. //Positioning ms paint.
  205. pMainWnd->ScreenToClient(&m_rcWxWnd);
  206. ::MoveWindow(hWxWnd, m_rcWxWnd.left, m_rcWxWnd.top, m_rcWxWnd.right, m_rcWxWnd.bottom, true);
  207. //ClientToScreen(&rect);
  208. //ScreenToClient(&rect);
  209. //::SetWindowPos(hWxWnd, NULL, rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW | SWP_HIDEWINDOW);
  210. //窗口重绘,(因创建exe时,设置为SW_HIDE,导致exe窗口会被父窗口覆盖一部分)
  211. //Invalidate();
  212. ::UpdateWindow(hWxWnd);
  213. ::ShowWindow(hWxWnd, SW_SHOW);
  214. m_bAttached = TRUE;
  215. }
  216. return 0;
  217. }
  218. BOOL CWxObject::DetachWxWnd()
  219. {
  220. if (m_hWxMainWnd)
  221. ::SetParent(m_hWxMainWnd, NULL);
  222. if (m_hWxLoginWnd)
  223. ::SetParent(m_hWxLoginWnd, NULL);
  224. m_bAttached = FALSE;
  225. return 0;
  226. }
  227. BOOL CWxObject::EnumWindowsProc(HWND hwnd, LPARAM lParam)
  228. {
  229. DWORD dwProcId = 0, dwThreadId;
  230. TCHAR szWndName[MAX_PATH] = { 0 };
  231. TCHAR szClassName[MAX_PATH] = { 0 };
  232. WNDINFO* pWndInfo = (WNDINFO*)lParam;
  233. dwThreadId = GetWindowThreadProcessId(hwnd, &dwProcId);
  234. if(dwProcId == pWndInfo->dwWxProcId)
  235. {
  236. pWndInfo->hWxWnd = hwnd;
  237. pWndInfo->dwThreadId = dwThreadId;
  238. ::GetWindowText(hwnd, szWndName, MAX_PATH);
  239. ::GetClassName(hwnd, szClassName, MAX_PATH);
  240. if (_tcscmp(szWndName, pWndInfo->szWndName) == 0 && _tcscmp(szClassName, pWndInfo->szClassName) == 0)
  241. {
  242. ::GetWindowRect(hwnd, &pWndInfo->rcWnd);
  243. return FALSE;
  244. }
  245. }
  246. return TRUE;
  247. }