【轉】消息鉤子註冊淺析

標 題: 【原創】消息鉤子註冊淺析
做 者: 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;
  }
  
}

只能分析這麼點了,不足或錯誤之處,還請各位指正

相關文章
相關標籤/搜索