標 題: 【原創】消息鉤子註冊淺析
做 者: RootSuLe
時 間: 2011-06-18,23:10:34
鏈 接: http://bbs.pediy.com/showthread.php?t=135702
windows消息鉤子很古老,但目前仍有不少地方須要用到,簡單跟蹤了一下函數執行流程,函數用法以下(MSDN):
函數功能:該函數將一個應用程序定義的掛鉤處理過程安裝到掛鉤鏈中去,您能夠經過安裝掛鉤處理過程來對系統的某些類型事件進行監控,這些事件與某個特定的線程或系統中的全部事件相關.
函數原形:php
HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId);
參數:
idHook:指示欲被安裝的掛鉤處理過程之類型,此參數能夠是如下值之一:
WH_CALLWNDPROC(4): 安裝一個掛鉤處理過程,在系統將消息發送至目標窗口處理過程以前,對該消息進行監視,詳情參見CallWndProc掛鉤處理過程.
WH_CALLWNDPROCRET(12) :安裝一個掛鉤處理過程,它對已被目標窗口處理過程處理過了的消息進行監視,詳情參見 CallWndRetProc 掛鉤處理過程.
WH_CBT(5) :安裝一個掛鉤處理過程,接受對CBT應用程序有用的消息 ,詳情參見 CBTProc 掛鉤處理過程.
WH_DEBUG(9):安裝一個掛鉤處理過程以便對其餘掛鉤處理過程進行調試, 詳情參見DebugProc掛鉤處理過程.
WH_FOREGROUNDIDLE(11):安裝一個掛鉤處理過程,該掛鉤處理過程當應用程序的前臺線程即將進入空閒狀態時被調用,它有助於在空閒時間內執行低優先級的任務.
WH_GETMESSAGE(3):安裝一個掛鉤處理過程對寄送至消息隊列的消息進行監視,詳情參見 GetMsgProc 掛鉤處理過程.
WH_JOURNALPLAYBACK(1):安裝一個掛鉤處理過程,對此前由WH_JOURNALRECORD 掛鉤處理過程紀錄的消息進行寄送.詳情參見 JournalPlaybackProc掛鉤處理過程.
WH_JOURNALRECORD(0):安裝一個掛鉤處理過程,對寄送至系統消息隊列的輸入消息進行紀錄.詳情參見JournalRecordProc掛鉤處理過程.
WH_KEYBOARD(2):安裝一個掛鉤處理過程對擊鍵消息進行監視. 詳情參見KeyboardProc掛鉤處理過程.
WH_KEYBOARD_LL(13):此掛鉤只能在Windows NT中被安裝,用來對底層的鍵盤輸入事件進行監視.詳情參見LowLevelKeyboardProc掛鉤處理過程.
WH_MOUSE(7):安裝一個掛鉤處理過程,對鼠標消息進行監視. 詳情參見 MouseProc掛鉤處理過程.
WH_MOUSE_LL(14):此掛鉤只能在Windows NT中被安裝,用來對底層的鼠標輸入事件進行監視.詳情參見LowLevelMouseProc掛鉤處理過程.
WH_MSGFILTER(-1):安裝一個掛鉤處理過程, 以監視由對話框、消息框、菜單條、或滾動條中的輸入事件引起的消息.詳情參見MessageProc掛鉤處理過程.
WH_SHELL(10):安裝一個掛鉤處理過程以接受對外殼應用程序有用的通知, 詳情參見 ShellProc掛鉤處理過程.
WH_SYSMSGFILTER(6):安裝一個掛鉤處理過程,以監視由對話框、消息框、菜單條、或滾動條中的輸入事件引起的消息.這個掛鉤處理過程對系統中全部應用程序的這類消息都進行監視.詳情參見 SysMsgProc掛鉤處理過程.
lpfn:指向相應的掛鉤處理過程.若參數dwThreadId爲0或者指示了一個其餘進程建立的線程之標識符,則參數lpfn必須指向一個動態連接中的掛鉤處理過程.不然,參數lpfn能夠指向一個與當前進程相關的代碼中定義的掛鉤處理過程.
hMod:指示了一個動態連接的句柄,該動態鏈接庫包含了參數lpfn 所指向的掛鉤處理過程.若參數dwThreadId指示的線程由當前進程建立,而且相應的掛鉤處理過程定義於當前進程相關的代碼中,則參數hMod必須被設置爲NULL(0).
dwThreadId:指示了一個線程標識符,掛鉤處理過程與線程相關.若此參數值爲0,則該掛鉤處理過程與全部現存的線程相關.
返回值:若此函數執行成功,則返回值就是該掛鉤處理過程的句柄;若此函數執行失敗,則返回值爲NULL(0).若想得到更多錯誤信息,請調用GetLasError函數.
備註:若參數hMod爲NULL,而參數dwThreadld爲0或者指示了一個其餘進程建立的線程標識符,則會產生錯誤.
對函數CallNextHookEx進行調用如下連接下一個掛鉤處理過程是可選的,但也是被推薦的不然,其餘安裝了此掛鉤的應用程序將沒法得到此掛鉤通知,從而可能致使錯誤的行爲.除非您確實但願防止其餘應用程序看到此掛鉤通知,您應當調用函數CallNextHookEx.
在終止一個應用程序以前,必須調用函數UnhookWindowsHookEx以釋放與此掛鉤相關的系統資源.
掛鉤的做用域依賴與掛鉤的類型.一些掛鉤只能被設置成系統做用域,其餘掛鉤(以下所示)還能夠被設置爲某一特定線程的做用域:
WH_CALLWNDPROC 線程或系統
WH_CALLWNDPROCRET 線程或系統
WH_CBT 線程或系統
WH_DEBUG 線程或系統
WH_FOREGROUNDIDLE 線程或系統
WH_GETMESSAGE 線程或系統
WH_JOURNALPLAYBACK 系統
WH_JOURNALRECORD 系統
WH_KEYBOARD 線程或系統
WH_KEYBOARD_LL 線程或系統
WH_MOUSE 線程或系統
WH_MOUSE_LL 線程或系統
WH_MSGFILTER 線程或系統
WH_SHELL 線程或系統
WH_SYSMSGFILTER 系統
對於一個特定的掛鉤類型,現成的掛鉤先被調用,而後纔是系統掛鉤被調用.
系統掛鉤做爲共享資源,安裝一次就對所用應用程序產生影響.全部的系統掛鉤函數必須在庫中.系統掛鉤應當被限制用於一些特殊用途的應用程序或者用來做爲應用程序調試的輔助工具.再也不須要掛鉤的庫應當將相應的掛鉤處理過程刪除掉.
windows
HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId ); .text:77D31211 ; HHOOK __stdcall SetWindowsHookExA(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId) .text:77D31211 public _SetWindowsHookExA@16 .text:77D31211 _SetWindowsHookExA@16 proc near ; DATA XREF: .text:off_77D13928.o .text:77D31211 .text:77D31211 idHook = dword ptr 8 .text:77D31211 lpfn = dword ptr 0Ch .text:77D31211 hModule = dword ptr 10h .text:77D31211 dwThreadId = dword ptr 14h .text:77D31211 .text:77D31211 mov edi, edi .text:77D31213 push ebp .text:77D31214 mov ebp, esp .text:77D31216 push 2 ;DWORD dwFlags .text:77D31218 push [ebp+dwThreadId] .text:77D3121B push [ebp+hModule] .text:77D3121E push [ebp+lpfn] .text:77D31221 push [ebp+idHook] .text:77D31224 call _SetWindowsHookExAW@20 ; SetWindowsHookExAW(x,x,x,x,x) .text:77D31229 pop ebp .text:77D3122A retn 10h .text:77D3122A _SetWindowsHookExA@16 endp HHOOK __stdcall SetWindowsHookExAW(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId,DWORD dwFlags .text:77D28157 ; int __stdcall SetWindowsHookExAW(int idHook, int lpfn, HMODULE hModule, int dwThreadId, DWORD dwFlags .text:77D28157 _SetWindowsHookExAW@20 proc near ; CODE XREF: SetWindowsHookExW(x,x,x,x)+13.p .text:77D28157 ; SetWindowsHookExA(x,x,x,x)+13.p .text:77D28157 .text:77D28157 Filename = word ptr -20Ch .text:77D28157 var_4 = dword ptr -4 .text:77D28157 idHook = dword ptr 8 .text:77D28157 lpfn = dword ptr 0Ch .text:77D28157 hModule = dword ptr 10h .text:77D28157 dwThreadId = dword ptr 14h .text:77D28157 Mod = dword ptr 18h .text:77D28157 .text:77D28157 mov edi, edi .text:77D28159 push ebp .text:77D2815A mov ebp, esp .text:77D2815C sub esp, 20Ch ; 爲局部變量分配內存空間0x20Ch = 524字節,此爲雙字節數組,共261個元素,因此最大元素下標是260[MAX_PATH] .text:77D28162 mov eax, ___security_cookie .text:77D28167 push esi ; 保存esi .text:77D28168 mov esi, [ebp+hModule] .text:77D2816B test esi, esi .text:77D2816D push edi .text:77D2816E mov edi, [ebp+lpfn] .text:77D28171 mov [ebp+var_4], eax .text:77D28174 jz short loc_77D2818D ; hmod爲NULL .text:77D28176 push 104h ; nSize .text:77D2817B lea eax, [ebp+Filename] .text:77D28181 push eax ; lpFilename .text:77D28182 push esi ; hModule .text:77D28183 call ds:__imp__GetModuleFileNameW@12 ; GetModuleFileNameW(x,x,x) .text:77D28189 test eax, eax .text:77D2818B jz short loc_77D281AC ; 獲取模塊句柄失敗 .text:77D2818D .text:77D2818D loc_77D2818D: ; CODE XREF: SetWindowsHookExAW(x,x,x,x,x)+1D.j .text:77D2818D push [ebp+dwFlags] .text:77D28190 mov eax, esi ;esi也擁有模塊句柄 .text:77D28192 push edi ;lpfn入棧 .text:77D28193 push [ebp+idHook] .text:77D28196 neg eax ;取反操做,若是eax爲NULL的話,CF位爲0,不然CF置1 .text:77D28198 push [ebp+dwThreadId] .text:77D2819B sbb eax, eax ;若CF爲0,eax = 0,不然eax爲-1 .text:77D2819D lea ecx, [ebp+Filename] .text:77D281A3 and eax, ecx ;sbb後,若eax爲0,則結果爲0,不然爲ecx .text:77D281A5 push eax ;判斷結果 .text:77D281A6 push esi ;esi擁有模塊句柄 .text:77D281A7 call __SetWindowsHookEx@24 ; _SetWindowsHookEx(x,x,x,x,x,x) .text:77D281AC .text:77D281AC loc_77D281AC: ; CODE XREF: SetWindowsHookExAW(x,x,x,x,x)+34.j .text:77D281AC mov ecx, [ebp+var_4] .text:77D281AF pop edi .text:77D281B0 pop esi .text:77D281B1 call @__security_check_cookie@4 ; __security_check_cookie(x) .text:77D281B6 leave .text:77D281B7 retn 14h .text:77D281B7 _SetWindowsHookExAW@20 endp
僞代碼:SetWindowsHookExAW數組
HHOOK __stdcall SetWindowsHookExAW(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId,DWORD dwFlags) { WCHAR Filename[MAX_PATH]; if (hmod != NULL) { //獲取文件名 if (!GetModuleFileNameW(hmod,Filename,MAX_PATH)) { //該參數雖然存在,但經驗證是僞造的,返回NULL return NULL; } } return _SetWindowsHookEx(hmod,(hmod == NULL) ? NULL:Filename,dwThreadId,idHook,lpfn,dwFlags); }
HHOOK __stdcall _SetWindowsHookEx(HMODULE hmod,LPCWSTR Filename,DWORD dwThreadId,int idHook,HOOKPROC lpfn,DWORD dwFlags);
cookie
.text:77D281BF ; int __stdcall _SetWindowsHookEx(HMODULE hmod, LPCWSTR Filename, DWORD dwThreadId, int idHook, HOOKPROC lpfn, DWORD dwFlags) .text:77D281BF __SetWindowsHookEx@24 proc near ; CODE XREF: SetWindowsHookExAW(x,x,x,x,x)+50.p .text:77D281BF .text:77D281BF usFileName = byte ptr -10h .text:77D281BF usModuleName = dword ptr -8 .text:77D281BF var_4 = dword ptr -4 .text:77D281BF hmod = dword ptr 8 .text:77D281BF Filename = dword ptr 0Ch .text:77D281BF dwThreadId = dword ptr 10h .text:77D281BF idHook = dword ptr 14h .text:77D281BF lpfn = dword ptr 18h .text:77D281BF Flags = dword ptr 1Ch .text:77D281BF .text:77D281BF mov edi, edi .text:77D281C1 push ebp .text:77D281C2 mov ebp, esp .text:77D281C4 sub esp, 10h ; 分配16字節大小堆棧空間 .text:77D281C7 push [ebp+Filename] ; Filename入棧 .text:77D281CA and [ebp+var_4], 0 ; .text:77D281CE lea eax, [ebp+usFileName] .text:77D281D1 push eax .text:77D281D2 mov [ebp+usModuleName], eax .text:77D281D5 call ds:__imp__RtlInitUnicodeString@8 ; RtlInitUnicodeString(x,x) .text:77D281DB push [ebp+dwFlags] .text:77D281DE push [ebp+lpfn] .text:77D281E1 push [ebp+idHook] .text:77D281E4 push [ebp+dwThreadId] .text:77D281E7 push [ebp+usModuleName] .text:77D281EA push [ebp+hmod] .text:77D281ED call _NtUserSetWindowsHookEx@24 ; NtUserSetWindowsHookEx(x,x,x,x,x,x) .text:77D281F2 leave .text:77D281F3 retn 18h .text:77D281F3 __SetWindowsHookEx@24 endp
僞代碼:app
HHOOK __stdcall _SetWindowsHookEx(HMODULE hmod,LPCWSTR Filename,DWORD dwThreadId,int idHook,HOOKPROC lpfn,DWORD dwFlags) { UNICODE_STRING usFileName; //初始化UNICODE字符串結構 RtlInitUnicodeString(&usFileName,Filename); return NtUserSetWindowsHookEx(hmod,&usFileName,dwThreadId,idHook,lpfn,dwFlags); } .text:77D281FB ; __stdcall NtUserSetWindowsHookEx(x, x, x, x, x, x) .text:77D281FB _NtUserSetWindowsHookEx@24 proc near ; CODE XREF: _SetWindowsHookEx(x,x,x,x,x,x)+2E.p .text:77D281FB mov eax, 1225h .text:77D28200 mov edx, 7FFE0300h .text:77D28205 call dword ptr [edx] .text:77D28207 retn 18h .text:77D28207 _NtUserSetWindowsHookEx@24 endp
////////////////////////////////內核下
ide
HHOOK NTAPI NtUserSetWindowsHookEx( HINSTANCE Mod, PUNICODE_STRING ModuleName, DWORD ThreadId, int HookId, HOOKPROC HookProc, DWORD dwFlags); .text:BF85EA67 ; START OF FUNCTION CHUNK FOR _NtUserSetWindowsHookEx@24 .text:BF85EA67 .text:BF85EA67 loc_BF85EA67: ; CODE XREF: NtUserSetWindowsHookEx(x,x,x,x,x,x)+1C.j .text:BF85EA67 push 57h ; 錯誤碼:87 ,參數不正確 .text:BF85EA69 call _UserSetLastError@4 ; UserSetLastError(x) .text:BF85EA6E jmp short loc_BF85EAAE ; 準備退出 .text:BF85EA6E ; END OF FUNCTION CHUNK FOR _NtUserSetWindowsHookEx@24 .text:BF85EA75 ; int __stdcall NtUserSetWindowsHookEx(HINSTANCE Mod, PUNICODE_STRING ModuleName, DWORD ThreadId, int HookId, HOOKPROC HookProc, BOOL Ansi) .text:BF85EA75 _NtUserSetWindowsHookEx@24 proc near ; DATA XREF: .data:BF99E094.o .text:BF85EA75 .text:BF85EA75 Mod = dword ptr 8 .text:BF85EA75 ModuleName = dword ptr 0Ch .text:BF85EA75 ThreadId = dword ptr 10h .text:BF85EA75 HookId = dword ptr 14h .text:BF85EA75 HookProc = dword ptr 18h .text:BF85EA75 Ansi = dword ptr 1Ch .text:BF85EA75 .text:BF85EA75 ; FUNCTION CHUNK AT .text:BF85EA67 SIZE 00000009 BYTES .text:BF85EA75 .text:BF85EA75 mov edi, edi .text:BF85EA77 push ebp .text:BF85EA78 mov ebp, esp .text:BF85EA7A push esi .text:BF85EA7B call _EnterCrit@0 ; EnterCrit() .text:BF85EA80 xor esi, esi .text:BF85EA82 cmp [ebp+ThreadId], esi .text:BF85EA85 jz short loc_BF85EABA ; 進程ID爲0,說明是系統全局消息鉤子 .text:BF85EA87 push [ebp+ThreadId] .text:BF85EA8A call _PtiFromThreadId@4 ; 經過線程ID獲取PTHREADINFO指針 .text:BF85EA8F cmp eax, esi .text:BF85EA91 jz short loc_BF85EA67 ; 沒有獲取 .text:BF85EA93 .text:BF85EA93 loc_BF85EA93: ; CODE XREF: NtUserSetWindowsHookEx(x,x,x,x,x,x)+47.j .text:BF85EA93 push [ebp+dwFlags] .text:BF85EA96 push [ebp+HookProc] .text:BF85EA99 push [ebp+HookId] .text:BF85EA9C push eax .text:BF85EA9D push [ebp+ModuleName] .text:BF85EAA0 push [ebp+Mod] .text:BF85EAA3 call _zzzSetWindowsHookEx@24 ; zzzSetWindowsHookEx(x,x,x,x,x,x) .text:BF85EAA8 cmp eax, esi ; 判斷結果爲NULL .text:BF85EAAA jz short loc_BF85EAAE ; 失敗則跳轉 .text:BF85EAAC mov esi, [eax] ; 暫存結果 .text:BF85EAAE .text:BF85EAAE loc_BF85EAAE: ; CODE XREF: NtUserSetWindowsHookEx(x,x,x,x,x,x)-7.j .text:BF85EAAE ; NtUserSetWindowsHookEx(x,x,x,x,x,x)+35.j .text:BF85EAAE call _LeaveCrit@0 ; LeaveCrit() .text:BF85EAB3 mov eax, esi .text:BF85EAB5 pop esi .text:BF85EAB6 pop ebp .text:BF85EAB7 retn 18h .text:BF85EABA ; --------------------------------------------------------------------------- .text:BF85EABA .text:BF85EABA loc_BF85EABA: ; CODE XREF: NtUserSetWindowsHookEx(x,x,x,x,x,x)+10.j .text:BF85EABA xor eax, eax .text:BF85EABC jmp short loc_BF85EA93 .text:BF85EABC _NtUserSetWindowsHookEx@24 endp
HHOOK __stdcall NtUserSetWindowsHookEx(HINSTANCE Mod, PUNICODE_STRING ModuleName, DWORD ThreadId, int HookId, HOOKPROC HookProc, DWORD dwFlags) { HHOOK hRet; PTHREADINFO pti; HHOOK TempHandle; EnterCrit(); hRet = NULL; if ( ThreadId ) { pti = PtiFromThreadId(ThreadId); if ( !pti ) { //設置用戶模式錯誤碼:87 ,參數不正確 UserSetLastError(87); } } else { pti = NULL; } //zzzSetWindowsHookEx返回的是PHOOK類型,強制轉換成HHOOK TempHandle = (HHOOK)zzzSetWindowsHookEx(Mod, ModuleName, pti, HookId, HookProc, dwFlags); if ( TempHandle ) { hRet = TempHandle; } LeaveCrit(); return hRet; }
.text:BF85EABE ; START OF FUNCTION CHUNK FOR _zzzSetWindowsHookEx@24 .text:BF85EABE .text:BF85EABE loc_BF85EABE: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+21.j .text:BF85EABE push 593h ; 錯誤碼:1427,無效的掛接程序。 .text:BF85EAC3 jmp loc_BF85ED2A .text:BF85EAC8 ; --------------------------------------------------------------------------- .text:BF85EAC8 .text:BF85EAC8 loc_BF85EAC8: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+3F.j .text:BF85EAC8 push 595h ; 錯誤碼:1429,此掛接程序只可總體設置。 .text:BF85EACD jmp loc_BF85ED2A .text:BF85EAD2 ; --------------------------------------------------------------------------- .text:BF85EAD2 .text:BF85EAD2 loc_BF85EAD2: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+6B.j .text:BF85EAD2 push 20h ; 錯誤碼:32,另外一個程序正在使用此文件,進程沒法訪問。 .text:BF85EAD4 jmp loc_BF85EC31 .text:BF85EAD9 ; --------------------------------------------------------------------------- .text:BF85EAD9 .text:BF85EAD9 loc_BF85EAD9: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+64.j .text:BF85EAD9 push 10h ; 錯誤碼:16,沒法刪除目錄。 .text:BF85EADB jmp loc_BF85EC31 .text:BF85EAE0 ; --------------------------------------------------------------------------- .text:BF85EAE0 .text:BF85EAE0 loc_BF85EAE0: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+8C.j .text:BF85EAE0 mov eax, [edi+3Ch] .text:BF85EAE3 mov eax, [eax+10h] .text:BF85EAE6 test byte ptr [eax+10h], 4 ; ptiCurrent->rpdesk->rpwinstaParent->dwWSF_Flags .text:BF85EAEA jz loc_BF85EC50 .text:BF85EAF0 push 5B3h ; 錯誤碼:1459,該操做須要交互式窗口工做站。 .text:BF85EAF5 jmp loc_BF85ED2A .text:BF85EAFA ; --------------------------------------------------------------------------- .text:BF85EAFA .text:BF85EAFA loc_BF85EAFA: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+C1.j .text:BF85EAFA push 7Eh ; 錯誤碼:126,找不到指定的模塊。 .text:BF85EAFC call _UserSetLastError@4 ; UserSetLastError(x) .text:BF85EB01 push esi .text:BF85EB02 call _HMFreeObject@4 ; HMFreeObject(x) .text:BF85EB07 jmp loc_BF85ED2F ; 返回NULL .text:BF85EB0C ; --------------------------------------------------------------------------- .text:BF85EB0C .text:BF85EB0C loc_BF85EB0C: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+100.j .text:BF85EB0C push dword ptr [ecx] .text:BF85EB0E call ds:__imp__KeAttachProcess@4 ; KeAttachProcess(x) .text:BF85EB14 mov eax, [ebp+pti] .text:BF85EB17 mov [ebp+HookId], 1 .text:BF85EB1E jmp loc_BF85ECC8 ; 判斷是否HOOK成功 .text:BF85EB23 ; --------------------------------------------------------------------------- .text:BF85EB23 .text:BF85EB23 loc_BF85EB23: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+11A.j .text:BF85EB23 call ds:__imp__KeDetachProcess@0 ; 解除綁定進程 .text:BF85EB29 mov eax, [ebp+pti] .text:BF85EB2C jmp loc_BF85ECDE ; 記錄哪一個線程被HOOK了 .text:BF85EB31 ; --------------------------------------------------------------------------- .text:BF85EB31 .text:BF85EB31 loc_BF85EB31: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+D9.j .text:BF85EB31 mov eax, [edi+40h] .text:BF85EB34 or dword ptr [esi+20h], 1 .text:BF85EB38 lea ecx, [ebx+1] .text:BF85EB3B lea eax, [eax+ebx*4+14h] .text:BF85EB3F shl edx, cl .text:BF85EB41 mov [ebp+ModuleName], eax .text:BF85EB44 mov eax, [edi+40h] .text:BF85EB47 or [eax+0Ch], edx .text:BF85EB4A and dword ptr [esi+28h], 0 .text:BF85EB4E jmp loc_BF85ECE1 .text:BF85EB53 ; --------------------------------------------------------------------------- .text:BF85EB53 .text:BF85EB53 loc_BF85EB53: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+11.j .text:BF85EB53 ; zzzSetWindowsHookEx(x,x,x,x,x,x)+16.j .text:BF85EB53 push 592h ; 錯誤碼:1426,無效的掛接程序類型。 .text:BF85EB58 jmp loc_BF85ED2A .text:BF85EB5D ; --------------------------------------------------------------------------- .text:BF85EB5D .text:BF85EB5D loc_BF85EB5D: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+14F.j .text:BF85EB5D test ds:abHookFlags[ebx], 10h .text:BF85EB64 jz loc_BF85ED13 ; 無效的鉤子類型,返回 .text:BF85EB6A or byte ptr [edi+4Ah], 4 .text:BF85EB6E push 0Eh ; Priority .text:BF85EB70 push dword ptr [edi] ; Thread .text:BF85EB72 call ds:__imp__KeSetPriorityThread@8 ; KeSetPriorityThread(x,x) .text:BF85EB78 test ds:abHookFlags[ebx], 4 ; HKF_JOURNAL .text:BF85EB7F jz loc_BF85ED13 .text:BF85EB85 mov eax, [edi+28h] .text:BF85EB88 mov [ebp+var_C], eax .text:BF85EB8B lea eax, [ebp+var_C] .text:BF85EB8E mov [edi+28h], eax .text:BF85EB91 mov [ebp+var_8], esi .text:BF85EB94 inc dword ptr [esi+4] .text:BF85EB97 call _zzzSetFMouseMoved@0 ; zzzSetFMouseMoved() .text:BF85EB9C call _ThreadUnlock1@0 ; ThreadUnlock1() .text:BF85EBA1 cmp ebx, 1 ; 是不是WH_JOURNALPLAYBACK .text:BF85EBA4 mov esi, eax .text:BF85EBA6 jnz loc_BF85ED13 .text:BF85EBAC mov eax, [edi+2Ch] .text:BF85EBAF mov _gppiInputProvider, eax .text:BF85EBB4 jmp loc_BF85ED13 .text:BF85EBB4 ; END OF FUNCTION CHUNK FOR _zzzSetWindowsHookEx@24 .text:BF85EBB4 ; --------------------------------------------------------------------------- .text:BF85EBB9 db 5 dup(90h) .text:BF85EBBE .text:BF85EBBE ; =============== S U B R O U T I N E ======================================= .text:BF85EBBE .text:BF85EBBE ; Attributes: bp-based frame .text:BF85EBBE .text:BF85EBBE ; HHOOK __stdcall zzzSetWindowsHookEx(HINSTANCE Mod, PUNICODE_STRING ModuleName, PTHREADINFO pti, int HookId, HOOKPROC HookProc, DWORD dwFlags) .text:BF85EBBE _zzzSetWindowsHookEx@24 proc near ; CODE XREF: NtUserSetWindowsHookEx(x,x,x,x,x,x)+2E.p .text:BF85EBBE ; zzzSetWindowsHookAW(x,x,x)+1A.p .text:BF85EBBE .text:BF85EBBE var_C = dword ptr -0Ch .text:BF85EBBE var_8 = dword ptr -8 .text:BF85EBBE Mod = dword ptr 8 .text:BF85EBBE ModuleName = dword ptr 0Ch .text:BF85EBBE pti = dword ptr 10h .text:BF85EBBE HookId = dword ptr 14h .text:BF85EBBE HookProc = dword ptr 18h .text:BF85EBBE Ansi = dword ptr 1Ch .text:BF85EBBE arg_18 = dword ptr 20h .text:BF85EBBE .text:BF85EBBE ; FUNCTION CHUNK AT .text:BF85EABE SIZE 000000FB BYTES .text:BF85EBBE .text:BF85EBBE mov edi, edi .text:BF85EBC0 push ebp .text:BF85EBC1 mov ebp, esp .text:BF85EBC3 sub esp, 0Ch ; 開闢新空間 .text:BF85EBC6 push ebx .text:BF85EBC7 mov ebx, [ebp+HookId] .text:BF85EBCA cmp ebx, 0FFFFFFFFh .text:BF85EBCD push esi .text:BF85EBCE push edi .text:BF85EBCF jl short loc_BF85EB53 ; 鉤子類型小於0 .text:BF85EBD1 cmp ebx, 0Eh ; 鉤子類型是否大於15,MSDN共定義了15種鉤子類型 .text:BF85EBD4 jg loc_BF85EB53 ; 大於15了,也跳轉 .text:BF85EBDA xor edx, edx .text:BF85EBDC cmp [ebp+HookProc], edx ; HookProc是否存在 .text:BF85EBDF jz loc_BF85EABE ; 不存在,跳 .text:BF85EBE5 mov esi, [ebp+pti] .text:BF85EBE8 cmp esi, edx ; 驗證PTHREADINFO .text:BF85EBEA mov edi, _gptiCurrent ; 使用本線程的THREADINFO .text:BF85EBF0 jz loc_BF85ED1C .text:BF85EBF6 test ds:abHookFlags[ebx], 2 ; 判斷該消息鉤子是否鍵盤鉤子 .text:BF85EBFD jz loc_BF85EAC8 .text:BF85EC03 mov eax, [esi+3Ch] ; THREADINFO+3C是rpdesk .text:BF85EC06 cmp eax, [edi+3Ch] ; 判斷是否屬於同一個桌面 .text:BF85EC09 jnz loc_BF85EDCE ; 不在同一個桌面沒法設置鉤子 .text:BF85EC0F mov eax, [edi+2Ch] ; 2c地方是tagPROCESSINFO *ppi .text:BF85EC12 mov ecx, [esi+2Ch] .text:BF85EC15 cmp eax, ecx .text:BF85EC17 jnz loc_BF85ED6F ; 應用程序必須使用DLL來鉤 .text:BF85EC1D .text:BF85EC1D loc_BF85EC1D: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+161.j .text:BF85EC1D ; zzzSetWindowsHookEx(x,x,x,x,x,x)+1DC.j ... .text:BF85EC1D mov eax, ebx .text:BF85EC1F sub eax, 0 .text:BF85EC22 jz loc_BF85EAD9 ; 鉤子類型若是爲WH_JOURNALRECORD .text:BF85EC28 dec eax ; 鉤子類型數值減1,若是eax=0,則將eax置-1 .text:BF85EC29 jz loc_BF85EAD2 .text:BF85EC2F push 8 .text:BF85EC31 .text:BF85EC31 loc_BF85EC31: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)-EA.j .text:BF85EC31 ; zzzSetWindowsHookEx(x,x,x,x,x,x)-E3.j .text:BF85EC31 pop esi .text:BF85EC32 push esi ; DesiredAccess .text:BF85EC33 push dword ptr [edi+0E8h] ; GrantedAccess .text:BF85EC39 call ds:__imp__RtlAreAllAccessesGranted@8 ; RtlAreAllAccessesGranted(x,x) .text:BF85EC3F test al, al .text:BF85EC41 jz loc_BF85EDB7 ; 取當前進程EPROCESS .text:BF85EC41 ; .text:BF85EC47 .text:BF85EC47 loc_BF85EC47: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+20A.j .text:BF85EC47 cmp esi, 8 .text:BF85EC4A jnz loc_BF85EAE0 ; DESKTOP_HOOKCONTROL = 0x8L .text:BF85EC50 .text:BF85EC50 loc_BF85EC50: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)-D4.j .text:BF85EC50 push 30h ; sizeof(HOOK) .text:BF85EC52 push 5 ; 枚舉類型TYPE_HOOK .text:BF85EC54 push dword ptr [edi+3Ch] ; pti->rpdesk .text:BF85EC57 push edi ; pti .text:BF85EC58 call _HMAllocObject@16 ; 分配新的鉤子結構 .text:BF85EC5D mov esi, eax .text:BF85EC5F test esi, esi .text:BF85EC61 jz loc_BF85ED2F ; 分配失敗 .text:BF85EC67 or dword ptr [esi+24h], 0FFFFFFFFh ; -1 .text:BF85EC6B cmp [ebp+Mod], 0 .text:BF85EC6F jz short loc_BF85EC8F ; 若是模塊句柄爲NULL .text:BF85EC71 push [ebp+ModuleName] .text:BF85EC74 call _GetHmodTableIndex@4 ; GetHmodTableIndex(x) .text:BF85EC79 cmp eax, 0FFFFFFFFh ; 若是沒有找到,則返回-1 .text:BF85EC7C mov [esi+24h], eax .text:BF85EC7F jz loc_BF85EAFA ; 錯誤碼:126,找不到指定的模塊。 .text:BF85EC85 test eax, eax .text:BF85EC87 jl short loc_BF85EC8F ; 小於0則跳轉 .text:BF85EC89 push eax ; phkNew->ihmod .text:BF85EC8A call _AddHmodDependency@4 ; AddHmodDependency(x) .text:BF85EC8F .text:BF85EC8F loc_BF85EC8F: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+B1.j .text:BF85EC8F ; zzzSetWindowsHookEx(x,x,x,x,x,x)+C9.j .text:BF85EC8F mov eax, [ebp+pti] .text:BF85EC92 xor edx, edx .text:BF85EC94 inc edx .text:BF85EC95 test eax, eax .text:BF85EC97 jz loc_BF85EB31 ; 給定線程的PTHREADINFO爲空 .text:BF85EC9D lea ecx, [eax+ebx*4+0F8h] ; ptiThread.aphkStart[id] .text:BF85ECA4 mov [ebp+ModuleName], ecx .text:BF85ECA7 lea ecx, [ebx+1] .text:BF85ECAA shl edx, cl .text:BF85ECAC or [eax+98h], edx .text:BF85ECB2 cmp dword ptr [eax+44h], 0 .text:BF85ECB6 jz short loc_BF85ECDE ; pti+0x44是pClientInfo .text:BF85ECB8 mov ecx, [eax+2Ch] ; ppi .text:BF85ECBB cmp ecx, [edi+2Ch] .text:BF85ECBE jnz loc_BF85EB0C ; ppi不相等,就是說要HOOK的是別的進程 .text:BF85ECC4 and [ebp+HookId], 0 .text:BF85ECC8 .text:BF85ECC8 loc_BF85ECC8: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)-A0.j .text:BF85ECC8 cmp [ebp+HookId], 0 ; 判斷是否HOOK成功 .text:BF85ECCC mov ecx, [eax+44h] ; ptiThread->pClientInfo .text:BF85ECCF mov edx, [eax+98h] ; ptiThread->fsHooks; .text:BF85ECD5 mov [ecx+24h], edx ; ecx+24h = pClientInfo->fsHooks .text:BF85ECD8 jnz loc_BF85EB23 ; 已經HOOK了,則解除進程綁定 .text:BF85ECDE .text:BF85ECDE loc_BF85ECDE: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)-92.j .text:BF85ECDE ; zzzSetWindowsHookEx(x,x,x,x,x,x)+F8.j .text:BF85ECDE mov [esi+28h], eax ; 記錄哪一個線程被HOOK了 .text:BF85ECE1 .text:BF85ECE1 loc_BF85ECE1: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)-70.j .text:BF85ECE1 mov eax, [ebp+dwFlags] .text:BF85ECE4 and eax, 2 .text:BF85ECE7 or [esi+20h], eax .text:BF85ECEA mov eax, [ebp+HookProc] .text:BF85ECED sub eax, [ebp+Mod] .text:BF85ECF0 mov [esi+18h], ebx .text:BF85ECF3 mov [esi+1Ch], eax .text:BF85ECF6 mov eax, [ebp+ModuleName] .text:BF85ECF9 mov ecx, [eax] .text:BF85ECFB mov [esi+14h], ecx .text:BF85ECFE mov [eax], esi .text:BF85ED00 test ds:abHookFlags[ebx], 4 .text:BF85ED07 jnz short loc_BF85ED33 .text:BF85ED09 .text:BF85ED09 loc_BF85ED09: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+1AD.j .text:BF85ED09 test byte ptr [esi+20h], 1 .text:BF85ED0D jnz loc_BF85EB5D .text:BF85ED13 .text:BF85ED13 loc_BF85ED13: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)-5A.j .text:BF85ED13 ; zzzSetWindowsHookEx(x,x,x,x,x,x)-3F.j ... .text:BF85ED13 mov eax, esi .text:BF85ED15 .text:BF85ED15 loc_BF85ED15: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+173.j .text:BF85ED15 pop edi .text:BF85ED16 pop esi .text:BF85ED17 pop ebx .text:BF85ED18 leave .text:BF85ED19 retn 18h .text:BF85ED1C ; --------------------------------------------------------------------------- .text:BF85ED1C .text:BF85ED1C loc_BF85ED1C: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+32.j .text:BF85ED1C cmp [ebp+Mod], edx .text:BF85ED1F jnz loc_BF85EC1D .text:BF85ED25 .text:BF85ED25 loc_BF85ED25: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+1B4.j .text:BF85ED25 push 594h ; 錯誤碼:1428,沒有模塊句柄沒法設置非本機的掛接。 .text:BF85ED2A .text:BF85ED2A loc_BF85ED2A: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)-FB.j .text:BF85ED2A ; zzzSetWindowsHookEx(x,x,x,x,x,x)-F1.j ... .text:BF85ED2A call _UserSetLastError@4 ; UserSetLastError(x) .text:BF85ED2F .text:BF85ED2F loc_BF85ED2F: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)-B7.j .text:BF85ED2F ; zzzSetWindowsHookEx(x,x,x,x,x,x)+A3.j ... .text:BF85ED2F xor eax, eax ; 返回NULL .text:BF85ED31 jmp short loc_BF85ED15 .text:BF85ED33 ; --------------------------------------------------------------------------- .text:BF85ED33 .text:BF85ED33 loc_BF85ED33: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+149.j .text:BF85ED33 mov eax, [edi+28h] .text:BF85ED36 mov [ebp+var_C], eax .text:BF85ED39 lea eax, [ebp+var_C] .text:BF85ED3C mov [edi+28h], eax .text:BF85ED3F push 1 .text:BF85ED41 mov [ebp+var_8], esi .text:BF85ED44 inc dword ptr [esi+4] .text:BF85ED47 push edi .text:BF85ED48 call _zzzJournalAttach@8 ; zzzJournalAttach(x,x) .text:BF85ED4D test eax, eax .text:BF85ED4F jnz short loc_BF85ED62 .text:BF85ED51 call _ThreadUnlock1@0 ; ThreadUnlock1() .text:BF85ED56 test eax, eax .text:BF85ED58 jz short loc_BF85ED2F ; 返回NULL .text:BF85ED5A push esi .text:BF85ED5B call _zzzUnhookWindowsHookEx@4 ; zzzUnhookWindowsHookEx(x) .text:BF85ED60 jmp short loc_BF85ED2F ; 返回NULL .text:BF85ED62 ; --------------------------------------------------------------------------- .text:BF85ED62 .text:BF85ED62 loc_BF85ED62: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+191.j .text:BF85ED62 call _ThreadUnlock1@0 ; ThreadUnlock1() .text:BF85ED67 mov esi, eax .text:BF85ED69 test esi, esi .text:BF85ED6B jnz short loc_BF85ED09 .text:BF85ED6D jmp short loc_BF85ED2F ; 返回NULL .text:BF85ED6F ; --------------------------------------------------------------------------- .text:BF85ED6F .text:BF85ED6F loc_BF85ED6F: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+59.j .text:BF85ED6F cmp [ebp+Mod], edx .text:BF85ED72 jz short loc_BF85ED25 ; 模塊句柄爲NULL .text:BF85ED74 mov edx, [ecx+160h] ; PROCESSINFO+160h存儲進程luidSession .text:BF85ED7A cmp edx, [eax+160h] .text:BF85ED80 jnz short loc_BF85ED90 ; ptiThread->TIF_flags & TIF_ALLOWOTHERACCOUNTHOOK .text:BF85ED82 mov ecx, [ecx+164h] ; PROCESSINFO+164h存儲進程HighPart .text:BF85ED88 cmp ecx, [eax+164h] .text:BF85ED8E jz short loc_BF85ED96 .text:BF85ED90 .text:BF85ED90 loc_BF85ED90: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+1C2.j .text:BF85ED90 test byte ptr [esi+4Ah], 40h ; ptiThread->TIF_flags & TIF_ALLOWOTHERACCOUNTHOOK .text:BF85ED94 jz short loc_BF85EDCE ; 錯誤碼:5,拒絕訪問 .text:BF85ED96 .text:BF85ED96 loc_BF85ED96: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+1D0.j .text:BF85ED96 test byte ptr [esi+48h], 0Ch .text:BF85ED9A jz loc_BF85EC1D .text:BF85EDA0 test ds:abHookFlags[ebx], 10h .text:BF85EDA7 jnz loc_BF85EC1D ; 鉤子類型驗證經過 .text:BF85EDAD push 5B2h ; 錯誤碼:1458,不容許使用的掛鉤類型。 .text:BF85EDB2 jmp loc_BF85ED2A .text:BF85EDB7 ; --------------------------------------------------------------------------- .text:BF85EDB7 .text:BF85EDB7 loc_BF85EDB7: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+83.j .text:BF85EDB7 call ds:__imp__PsGetCurrentProcess@0 ; 取當前進程EPROCESS .text:BF85EDB7 ; .text:BF85EDBD cmp eax, _gpepCSRSS ; 比較是不是CSRSS.exe的進程 .text:BF85EDC3 jnz short loc_BF85EDCE ; 錯誤碼:5,拒絕訪問 .text:BF85EDC5 cmp ebx, 0FFFFFFFFh .text:BF85EDC8 jz loc_BF85EC47 .text:BF85EDCE .text:BF85EDCE loc_BF85EDCE: ; CODE XREF: zzzSetWindowsHookEx(x,x,x,x,x,x)+4B.j .text:BF85EDCE ; zzzSetWindowsHookEx(x,x,x,x,x,x)+1D6.j ... .text:BF85EDCE push 5 ; 錯誤碼:5,拒絕訪問 .text:BF85EDD0 jmp loc_BF85ED2A .text:BF85EDD0 _zzzSetWindowsHookEx@24 endp
//zzzSetWindowsHookEx容許在制定的線程中或者系統全局範圍內設置鉤子,該函數返回一個HOOK對象的句柄若是成功,若是有錯誤發生,則返回NULL函數
PHOOK zzzSetWindowsHookEx( HANDLE hmod, //模塊句柄 PUNICODE_STRING pstrLib, //庫名字 PTHREADINFO ptiThread, //線程信息 int id, //鉤子ID(類型) PROC pfnFilterProc, //鉤子回調地址 DWORD dwFlags) //版本標誌 { ACCESS_MASK amDesired; PHOOK phkNew; TL tlphkNew; PHOOK *pphkStart; PTHREADINFO ptiCurrent; //檢查鉤子類型是否容許,MSDN共定義16種鉤子 if ((nFilterType < WH_MIN) || (nFilterType > WH_MAX)) { //設置錯誤碼,1426,無效的掛接類型 UserSetLastError(1426); return NULL; } //檢驗提供的鉤子函數回調 if (pfnFilterProc == NULL) { //設置錯誤碼,1427,無效的掛接過程 UserSetLastError(1427); return NULL; } //獲取當前調用者線程的THREADINFO結構指針 ptiCurrent = PtiCurrent(); if (ptiThread == NULL) { //若是應用程序沒有使用DLL就用全局HOOK if (hmod == NULL) { //設置錯誤碼,1428,沒有模塊句柄沒法設置非本機的掛接 UserSetLastError(1428); return NULL; } } else { //若是應用程序想設置本地HOOK,但使用的只能全局的鉤子類型 if (!(abHookFlags[nFilterType + 1] & HKF_TASK)) { //設置錯誤碼,1429,此程序只可總體設置 UserSetLastError(1428); return NULL; } //不能HOOK不一樣在同一桌面的線程 if (ptiThread->rpdesk != ptiCurrent->rpdesk) { //設置錯誤碼,5,拒絕訪問 UserSetLastError(5); return NULL; } if (ptiCurrent->ppi != ptiThread->ppi) { //若是程序想HOOK別的進程,但沒有使用DLL if (hmod == NULL) { //設置錯誤碼,1428,沒有模塊句柄沒法設置非本機的掛接 UserSetLastError(1428); return NULL; } //若是要HOOK別的用戶沒有權限 if ((!RtlEqualLuid(&ptiThread->ppi->luidSession, &ptiCurrent->ppi->luidSession)) && !(ptiThread->TIF_flags & TIF_ALLOWOTHERACCOUNTHOOK)) { //設置錯誤碼,5,拒絕訪問 UserSetLastError(5); return NULL; } if ((ptiThread->TIF_flags & (TIF_CSRSSTHREAD | TIF_SYSTEMTHREAD)) && !(abHookFlags[nFilterType + 1] & HKF_INTERSENDABLE)) { //不能HOOK控制檯程序以及系統線程 //設置錯誤碼,1458,不容許使用的掛鉤類型 UserSetLastError(1458); return NULL; } } } //權限檢查都經過了 switch( id ) { //WH_JOURNALRECORD = HKF_SYSTEM | HKF_JOURNAL | HKF_INTERSENDABLE case WH_JOURNALRECORD: amDesired = DESKTOP_JOURNALRECORD; break; case WH_JOURNALPLAYBACK: amDesired = DESKTOP_JOURNALPLAYBACK; break; default: amDesired = DESKTOP_HOOKCONTROL; break; } /* //權限是否足夠 BOOLEAN NTAPI RtlAreAllAccessesGranted(ACCESS_MASK GrantedAccess, ACCESS_MASK DesiredAccess) { PAGED_CODE_RTL(); return ((GrantedAccess & DesiredAccess) == DesiredAccess); } */ if (!RtlAreAllAccessesGranted(ptiCurrent->amdesk, amDesired)) { //設置錯誤碼,5,拒絕訪問 UserSetLastError(5); return NULL; } if (amDesired != DESKTOP_HOOKCONTROL && (ptiCurrent->rpdesk->rpwinstaParent->dwWSF_Flags & WSF_NOIO)) { //錯誤碼:1459,該操做須要交互式窗口工做站。 UserSetLastError(5); return NULL; } //爲新的鉤子對象分配空間 phkNew = (PHOOK)HMAllocObject(ptiCurrent, ptiCurrent->rpdesk,TYPE_HOOK, sizeof(HOOK)); //若分配失敗,則直接返回NULL if (phkNew == NULL) { return NULL; } //若是一個DLL是本鉤子所必須的,那麼像系統註冊該DLL,註冊後,才能保證被加載到別的進程中 phkNew->ihmod = -1; if (hmod != NULL) { #if defined(WX86) phkNew->flags |= (dwFlags & HF_WX86KNOWNDLL); #endif phkNew->ihmod = GetHmodTableIndex(pstrLib); if (phkNew->ihmod == -1) { //錯誤碼:126,系統找不到指定的模塊 UserSetLastError(126); //釋放掉剛分配的HOOK對象 HMFreeObject((PVOID)phkNew); return NULL; } //爲模塊曾加一個屬性,說明這個模塊被HOOK了多少次 if (phkNew->ihmod >= 0) { AddHmodDependency(phkNew->ihmod); } } //找到鉤子鏈表,若是是全局鉤子,則設置HF_GLOBAL標誌 if (ptiThread != NULL) { //獲取本線程傳入鉤子類型開始地址 pphkStart = &ptiThread->aphkStart[id]; //設置WHF_*標誌在THREADINFO中,就知道被HOOK過了 ptiThread->fsHooks |= WHF_FROM_WH(id); if (ptiThread->pClientInfo) { BOOL fAttached; //判斷是不是要鉤其餘進程 if (ptiThread->ppi != ptiCurrent->ppi) { //附加到別的進程,這樣,就能夠訪問別的進程的內存 KeAttachProcess(&ptiThread->ppi->Process->Pcb); fAttached = TRUE; } else { fAttached = FALSE; } //是指該線程被HOOK,當被HOOK進程接受到windows消息後,會先判斷是否存在HOOK ptiThread->pClientInfo->fsHooks = ptiThread->fsHooks; if (fAttached) { KeDetachProcess(); } } //記錄哪一個線程被HOOK了 phkNew->ptiHooked = ptiThread; } //線程信息爲NULL,說明要HOOK當前系統全部線程 else { //從當前線程中找到桌面對象,只要鉤住桌面,就鉤住了全部線程 pphkStart = &ptiCurrent->pDeskInfo->aphkStart[id]; //設置全局HOOK標誌 phkNew->flags |= HF_GLOBAL; ptiCurrent->pDeskInfo->fsHooks |= WHF_FROM_WH(id); phkNew->ptiHooked = NULL; } //鉤子類型版本,ANSI或者是UNICODE phkNew->flags |= (dwFlags & HF_ANSI); phkNew->iHook = id; //模塊在不一樣的進程中回被加載到不一樣的地址空間,出於這個緣由,當設置鉤子時,須要計算出偏移,跟PE文件VA相似 phkNew->offPfn = ((ULONG_PTR)pfnFilterProc) - ((ULONG_PTR)hmod); //把這個鉤子添加的鉤子鏈表的後面 phkNew->phkNext = *pphkStart; //重置鉤子鏈表 *pphkStart = phkNew; //若是是日誌鉤子,須要對同步進行處理 if (abHookFlags[id] & HKF_JOURNAL) { ThreadLockAlwaysWithPti(ptiCurrent, phkNew, &tlphkNew); if (!zzzJournalAttach(ptiCurrent, TRUE)) { if (ThreadUnlock(&tlphkNew) != NULL) { zzzUnhookWindowsHookEx(phkNew); } return NULL; } if ((phkNew = ThreadUnlock(&tlphkNew)) == NULL) { return NULL; } } //不容許一個進程,設置了全局掛鉤,工程運行在後臺的權限,提高優先級和標記因此不能重置 if ((phkNew->flags & HF_GLOBAL) && (abHookFlags[id] & HKF_INTERSENDABLE)) { ptiCurrent->TIF_flags |= TIF_GLOBALHOOKER; KeSetPriorityThread(&ptiCurrent->pEThread->Tcb, LOW_REALTIME_PRIORITY-2); if (abHookFlags[id] & HKF_JOURNAL) { ThreadLockAlwaysWithPti(ptiCurrent, phkNew, &tlphkNew); //若是要改變HOOK,移動鼠標,這樣第一個時間老是鼠標移動時間,能夠確保光標被正確設置 zzzSetFMouseMoved(); phkNew = ThreadUnlock(&tlphkNew); //若要設置一個回放鉤子,這個進程提供輸入,這使它有SetForegroundWindow的機會 if (id == WH_JOURNALPLAYBACK) { gppiInputProvider = ptiCurrent->ppi; } } else { UserAssert(id != WH_JOURNALPLAYBACK); } } else { UserAssert(!(abHookFlags[id] & HKF_JOURNAL)); UserAssert(id != WH_JOURNALPLAYBACK); } //返回鉤子指針,以便CallNextHookEx調用 DbgValidateHooks(phkNew, phkNew->iHook); return phkNew; }
至此,假定已經註冊了一個消息鉤子,簡單查一下鉤子如何被調用,因爲windows是基於消息事件驅動的,在windows嚮應用程序發送消息以前會先檢查是否有鉤子,若是有消息鉤子存在,則會調用鉤子函數,若是鉤子函數在一個動態連接庫中,且該連接庫還沒有映射到應用程序進程空間,則系統用LoadLibrary加載該DLL到址空間中,而後調用鉤子函數
工具
LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam );
SendMessage主要調用:
LRESULT SendMessageWorker(PWND pwnd, UINT message, WPARAM wParam, LPARAM lParam, BOOL fAnsi);
/*參看win2k代碼
SendMessageWorker取得CLIENTINFO信息,並檢查fsHooks域,若是存在HOOK,return CsSendMessage(hwnd, message, wParam, lParam, 0L,
FNID_SENDMESSAGE, fAnsi);ui
#define CsSendMessage(hwnd, msg, wParam, lParam, xParam, pfn, bAnsi) \ (((msg) >= WM_USER) ? \ NtUserMessageCall(hwnd, msg, wParam, lParam, xParam, pfn, bAnsi) : \ gapfnScSendMessage[MessageTable[msg].iFunction](hwnd, msg, wParam, lParam, xParam, pfn, bAnsi))
MessageTable是一個全局的表,存在系統消息的數組,其中存在消息鉤子入口地址
*/
R3下枚舉系統中的消息鉤子,網上已有例子.
//可能用到的結構體:this
CONST BYTE abHookFlags[CWINHOOKS] = { HKF_SYSTEM | HKF_TASK | HKF_NZRET , // WH_MSGFILTER (-1) HKF_SYSTEM | HKF_JOURNAL | HKF_INTERSENDABLE , // WH_JOURNALRECORD 0 HKF_SYSTEM | HKF_JOURNAL | HKF_INTERSENDABLE , // WH_JOURNALPLAYBACK 1 HKF_SYSTEM | HKF_TASK | HKF_NZRET | HKF_INTERSENDABLE , // WH_KEYBOARD 2 HKF_SYSTEM | HKF_TASK , // WH_GETMESSAGE 3 HKF_SYSTEM | HKF_TASK , // WH_CALLWNDPROC 4 HKF_SYSTEM | HKF_TASK , // WH_CBT 5 HKF_SYSTEM , // WH_SYSMSGFILTER 6 HKF_SYSTEM | HKF_TASK | HKF_INTERSENDABLE , // WH_MOUSE 7 HKF_SYSTEM | HKF_TASK , // WH_HARDWARE 8 HKF_SYSTEM | HKF_TASK , // WH_DEBUG 9 HKF_SYSTEM | HKF_TASK , // WH_SHELL 10 HKF_SYSTEM | HKF_TASK , // WH_FOREGROUNDIDLE 11 HKF_SYSTEM | HKF_TASK , // WH_CALLWNDPROCRET 12 HKF_SYSTEM | HKF_LOWLEVEL | HKF_INTERSENDABLE , // WH_KEYBOARD_LL 13 HKF_SYSTEM | HKF_LOWLEVEL | HKF_INTERSENDABLE // WH_MOUSE_LL 14 #ifdef REDIRECTION ,HKF_SYSTEM | HKF_LOWLEVEL | HKF_INTERSENDABLE // WH_HITTEST 15 #endif }; typedef struct tagHOOK { THRDESKHEAD head; struct tagHOOK *phkNext; int iHook; // 鉤子類型 DWORD offPfn; UINT flags; // 鉤子標誌 int ihmod; PTHREADINFO ptiHooked; // 被HOOK的線程 PDESKTOP rpdesk; // 全局鉤子 #ifdef HOOKBATCH DWORD cEventMessages; DWORD iCurrentEvent; DWORD CacheTimeOut; PEVENTMSG aEventCache; #endif } HOOK, *PHOOK; typedef struct _W32PROCESS { PEPROCESS peProcess; DWORD RefCount; ULONG W32PF_flags; PKEVENT InputIdleEvent; DWORD StartCursorHideTime; struct _W32PROCESS * NextStart; PVOID pDCAttrList; PVOID pBrushAttrList; DWORD W32Pid; LONG GDIHandleCount; LONG UserHandleCount; PEX_PUSH_LOCK GDIPushLock; /* Locking Process during access to structure. */ RTL_AVL_TABLE GDIEngUserMemAllocTable; /* Process AVL Table. */ LIST_ENTRY GDIDcAttrFreeList; LIST_ENTRY GDIBrushAttrFreeList; } W32PROCESS, *PW32PROCESS; typedef struct tagTHREADINFO { W32THREAD; LIST_ENTRY PtiLink; // 當前桌面中其餘線程的鏈表 PTL ptl; // Listhead for thread lock list PTL ptlOb; // Listhead for kernel object thread lock list PTL ptlPool; // Listhead for temp pool usage int cEnterCount; struct tagPROCESSINFO *ppi; // 線程所屬進程的PROCESSINFO結構指針 struct tagQ *pq; // 鍵盤鼠標輸入隊列 PKL spklActive; // active keyboard layout for this thread MLIST mlPost; // 已投遞消息列表 USHORT fsChangeBitsRemoved;// Bits removed during PeekMessage USHORT cDeskClient; // Ref count for CSRSS desktop PCLIENTTHREADINFO pcti; // Info that must be visible from client CLIENTTHREADINFO cti; // Use this when no desktop is available HANDLE hEventQueueClient; PKEVENT pEventQueueServer; PKEVENT *apEvent; // Wait array for xxxPollAndWaitForSingleObject PDESKTOP rpdesk; HDESK hdesk; // 桌面句柄 ACCESS_MASK amdesk; // 容許桌面權限 PDESKTOPINFO pDeskInfo; // Desktop info visible to client PCLIENTINFO pClientInfo; // Client info stored in TEB DWORD TIF_flags; // TIF_ flags go here. PUNICODE_STRING pstrAppName; // 程序名 struct tagSMS *psmsSent; // Most recent SMS this thread has sent struct tagSMS *psmsCurrent; // Received SMS this thread is currently processing struct tagSMS *psmsReceiveList; // SMSs to be processed LONG timeLast; // Time, position, and ID of last message POINT ptLast; DWORD idLast; int cQuit; int exitCode; int cPaintsReady; UINT cTimersReady; PMENUSTATE pMenuState; union { PTDB ptdb; // Win16Task Schedule data for WOW thread PWINDOWSTATION pwinsta; // Window station for SYSTEM thread PDESKTOP pdeskClient; // Desktop for CSRSS thread }; PSVR_INSTANCE_INFO psiiList; // thread DDEML instance list DWORD dwExpWinVer; DWORD dwCompatFlags; // The Win 3.1 Compat flags UINT cWindows; // Number of windows owned by this thread UINT cVisWindows; // Number of visible windows on this thread struct tagQ *pqAttach; // calculation variabled used in // AttachThreadInput() int iCursorLevel; // keep track of each thread's level DWORD fsReserveKeys; // Keys that must be sent to the active // active console window. struct tagTHREADINFO *ptiSibling; // pointer to sibling thread info PMOVESIZEDATA pmsd; DWORD fsHooks; // WHF_ Flags for which hooks are installed PHOOK asphkStart[CWINHOOKS]; // 本線程已註冊的鉤子 PHOOK sphkCurrent; // Hook this thread is currently processing PSBTRACK pSBTrack; #ifdef FE_IME PWND spwndDefaultIme; // Default IME Window for this thread PIMC spDefaultImc; // Default input context for this thread HKL hklPrev; // Previous active keyboard layout #endif } THREADINFO; typedef struct _LUID { DWORD LowPart; LONG HighPart; } LUID, *PLUID; typedef struct _PROCESSINFO { W32PROCESS; PTHREADINFO ptiList; PTHREADINFO ptiMainThread; struct _DESKTOP* rpdeskStartup; PCLS pclsPrivateList; PCLS pclsPublicList; INT cThreads; DWORD dwhmodLibLoadedMask; HANDLE ahmodLibLoaded[CLIBS]; struct _WINSTATION_OBJECT *prpwinsta; HWINSTA hwinsta; ACCESS_MASK amwinsta; DWORD dwHotkey; HMONITOR hMonitor; LUID luidSession; USERSTARTUPINFO usi; DWORD dwLayout; DWORD dwRegisteredClasses; LIST_ENTRY MenuListHead; FAST_MUTEX PrivateFontListLock; LIST_ENTRY PrivateFontListHead; FAST_MUTEX DriverObjListLock; LIST_ENTRY DriverObjListHead; struct _KBL* KeyboardLayout; // THREADINFO only W32HEAP_USER_MAPPING HeapMappings; } PROCESSINFO; typedef struct _CLIENTINFO { ULONG_PTR CI_flags; ULONG_PTR cSpins; DWORD dwExpWinVer; DWORD dwCompatFlags; DWORD dwCompatFlags2; DWORD dwTIFlags; // ThreadInfo TIF_Xxx flags for User space. PDESKTOPINFO pDeskInfo; ULONG_PTR ulClientDelta; PHOOK phkCurrent; ULONG fsHooks; CALLBACKWND CallbackWnd; DWORD dwHookCurrent; INT cInDDEMLCallback; PCLIENTTHREADINFO pClientThreadInfo; ULONG_PTR dwHookData; DWORD dwKeyCache; BYTE afKeyState[8]; DWORD dwAsyncKeyCache; BYTE afAsyncKeyState[8]; BYTE afAsyncKeyStateRecentDow[8]; HKL hKL; USHORT CodePage; UCHAR achDbcsCF[2]; MSG msgDbcsCB; LPDWORD lpdwRegisteredClasses; ULONG Win32ClientInfo3[27]; PPROCESSINFO ppi; } CLIENTINFO, *PCLIENTINFO;
線程爲窗口維護一個THREADINFO結構,每一個線程有一個gptiCurrent的全局變量.可從當前線程中,枚舉出系統全部消息鉤子,若要枚舉其餘單個線程的消息鉤子,關鍵是要得到該線程的THREADINFO結構指針,經過未公開函數win32k.sys中PtiFromThreadId(HANDLE ThreadId)獲得,該函數內部使用NTSTATUS LockThreadByClientId(HANDLE ThreadId,PETHREAD pEThread)獲得線程ETHREAD,而後使用PTHREADINFO PtiFromThread(pEThread);獲得THREADINFO指針,這樣便可經過THREADINFO.asphkStart[CWINHOOKS]遍歷該線程中的消息鉤子.
#define PtiFromThread(pEThread) ((PTHREADINFO)((pEThread)->Tcb.Win32Thread)) CWINHOOKS = WH_MAX - WH_MIN + 1 #define WH_MIN (-1) #if(WINVER >= 0x0400) #if (_WIN32_WINNT >= 0x0400) #define WH_MAX 14 #else #define WH_MAX 12 #endif // (_WIN32_WINNT >= 0x0400) #else #define WH_MAX 11 #endif ForExample: VOID DumpThreadMsgHooks(HANDLE ThreadId) { PHOOK Currenthk; PTHREADINFO pti,Temppti; int HookCount = 0; pti = PtiFromThreadId(ThreadId); Temppti = pti; while(Temppti->PtiLink.FLink != pti) { for(;HookCount < CWINHOOKS;HookCount++) { Currenthk = pti->asphkStart[HookCount]; if(Currenthk) { KdPrint(("Hook id is %d\n",Currenthk->iHook)); } } Temppti = Temppti->PtiLink.FLink; } }
只能分析這麼點了,不足或錯誤之處,還請各位指正