Browse Source

重要:注意注入微信的DLL路径,必须是宽字符的。如果项目是UNICODE的字符编码则没有问题,但如果是多字节编码的,要注意将多字节转成UNICODE。

Jeff 6 years ago
parent
commit
fe511e6461
2 changed files with 91 additions and 23 deletions
  1. 84 21
      source/hook/WeChats/CWxObject.cpp
  2. 7 2
      source/hook/WeChats/CWxObject.h

+ 84 - 21
source/hook/WeChats/CWxObject.cpp

@@ -8,6 +8,25 @@
 #define WX_LOGIN_WND_NAME _T("登录")
 #define WX_LOGIN_WND_CLASS_NAME _T("WeChatLoginWndForPC")
 
+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)
@@ -18,6 +37,7 @@ CWxObject::CWxObject()
 	, m_hInjectThread(NULL)
 	, m_hEjectThread(NULL)
 	, m_dwPathLen(0)
+	, m_bAttached(FALSE)
 {
 
 }
@@ -32,19 +52,9 @@ CWxObject::CWxObject(DWORD dwProcId, LPCTSTR lpDynamicLibraryPath)
 	, m_hInjectThread(NULL)
 	, m_hEjectThread(NULL)
 	, m_dwPathLen(0)
+	, m_bAttached(FALSE)
 {
-	ASSERT(dwProcId != 0);
-	ASSERT(lpDynamicLibraryPath != NULL);
-
-	memset(m_szDllPath, 0, sizeof(m_szDllPath));
-	_tcscpy_s(m_szDllPath, lpDynamicLibraryPath);
-
-	m_hWxProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_dwWxProcId);
-	if (m_hWxProcess == NULL)
-	{
-		WriteTextLog(_T("打开WeChat.exe进程失败"));
-	}
-	//m_hWxProcess = OpenProcess(PROCESS_CREATE_THREAD	| PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, m_dwWxProcId);
+	setInjectionObj(dwProcId, lpDynamicLibraryPath);
 }
 
 CWxObject::~CWxObject()
@@ -79,22 +89,28 @@ 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);
-	m_dwWxProcId = dwProcId;
-	m_hWxProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_dwWxProcId);
+#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进程失败"));
 	}
-	//m_hWxProcess = OpenProcess(PROCESS_CREATE_THREAD	| PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, m_dwWxProcId);
 }
 
 BOOL CWxObject::InjectDynamicLibrary()
 {
 	ASSERT(m_hWxProcess != NULL);
-
-	m_dwPathLen = _tcslen(m_szDllPath) * sizeof(TCHAR) + 1;
+	m_dwPathLen = wcslen(m_wszDllPath) * sizeof(WCHAR) + 1;
 	m_lpInjectData = VirtualAllocEx(m_hWxProcess, NULL, m_dwPathLen, MEM_COMMIT, PAGE_READWRITE);
 	if (NULL == m_lpInjectData)
 	{
@@ -102,7 +118,7 @@ BOOL CWxObject::InjectDynamicLibrary()
 		return FALSE;
 	}
 
-	if (WriteProcessMemory(m_hWxProcess, m_lpInjectData, m_szDllPath, m_dwPathLen, NULL) == 0)
+	if (WriteProcessMemory(m_hWxProcess, m_lpInjectData, m_wszDllPath, m_dwPathLen, NULL) == 0)
 	{
 		// 注意:MEM_RELEASE释放时第三参数一定要为0,请查看MSDN;
 		VirtualFreeEx(m_hWxProcess, m_lpInjectData, 0, MEM_RELEASE);
@@ -112,7 +128,6 @@ BOOL CWxObject::InjectDynamicLibrary()
 	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)
 	{
@@ -179,7 +194,7 @@ BOOL CWxObject::FindWxMainWnd()
 	if (::EnumWindows(&EnumWindowsProc, (LPARAM)&wnd) == FALSE)
 	{
 		m_hWxMainWnd = wnd.hWxWnd;
-		m_rcWnd = wnd.rcWnd;
+		m_rcWxWnd = wnd.rcWnd;
 		return TRUE;
 	}
 
@@ -196,13 +211,61 @@ BOOL CWxObject::FindWxLoginWnd()
 	if (::EnumWindows(&EnumWindowsProc, (LPARAM)&wnd) == FALSE)
 	{
 		m_hWxLoginWnd = wnd.hWxWnd;
-		m_rcWnd = wnd.rcWnd;
+		m_rcWxWnd = wnd.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(&m_rcWxWnd);
+		::MoveWindow(hWxWnd, m_rcWxWnd.left, m_rcWxWnd.top, m_rcWxWnd.right, m_rcWxWnd.bottom, true);
+		//ClientToScreen(&rect);
+		//ScreenToClient(&rect);
+		//::SetWindowPos(hWxWnd, NULL, rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW | SWP_HIDEWINDOW);
+		//窗口重绘,(因创建exe时,设置为SW_HIDE,导致exe窗口会被父窗口覆盖一部分)
+		//Invalidate();
+		::UpdateWindow(hWxWnd);
+		::ShowWindow(hWxWnd, SW_SHOW);
+
+		m_bAttached = TRUE;
+	}
+	return 0;
+}
+
+BOOL CWxObject::DetachWxWnd()
+{
+	if (m_hWxMainWnd)
+		::SetParent(m_hWxMainWnd, NULL);
+
+	if (m_hWxLoginWnd)
+		::SetParent(m_hWxLoginWnd, NULL);
+
+	m_bAttached = FALSE;
+	return 0;
+}
+
 BOOL CWxObject::EnumWindowsProc(HWND hwnd, LPARAM lParam)
 {
 	DWORD dwProcId = 0, dwThreadId;

+ 7 - 2
source/hook/WeChats/CWxObject.h

@@ -35,11 +35,14 @@ public:
 	HWND			m_hWxMainWnd;
 	HWND			m_hWxLoginWnd;
 	// 窗口大小;
-	CRect			m_rcWnd;
+	CRect			m_rcWxWnd;
+	// 是否附加到主窗口;
+	BOOL			m_bAttached;
 
 private:
 	// 动态库路径;
-	TCHAR			m_szDllPath[MAX_PATH];
+	WCHAR			m_wszDllPath[MAX_PATH];
+	CHAR			m_szDllPath[MAX_PATH];
 	// 路径分配的内存;
 	LPVOID			m_lpInjectData;
 	LPVOID			m_lpEjectData;
@@ -60,6 +63,8 @@ public:
 	BOOL EjectDynamicLibrary();
 	BOOL FindWxMainWnd();
 	BOOL FindWxLoginWnd();
+	BOOL Attach2MainWnd(CWnd *pMainWnd, BOOL bLoginWnd = FALSE);
+	BOOL DetachWxWnd();
 
 	static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam);
 };