windows消息钩子注册底层机制浅析

Posted 狂客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了windows消息钩子注册底层机制浅析相关的知识,希望对你有一定的参考价值。

标 题: 【原创】消息钩子注册浅析
作 者: RootSuLe
时 间: 2011-06-18,23:10:34
链 接: http://bbs.pediy.com/showthread.php?t=135702

windows消息钩子很古老,但目前仍有很多地方需要用到,简单跟踪了一下函数执行流程,函数用法如下(MSDN):

函数功能:该函数将一个应用程序定义的挂钩处理过程安装到挂钩链中去,您可以通过安装挂钩处理过程来对系统的某些类型事件进行监控,这些事件与某个特定的线程或系统中的所有事件相关.
函数原形:
代码:
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 系统
对于一个特定的挂钩类型,现成的挂钩先被调用,然后才是系统挂钩被调用.
系统挂钩作为共享资源,安装一次就对所用应用程序产生影响.所有的系统挂钩函数必须在库中.系统挂钩应当被限制用于一些特殊用途的应用程序或者用来作为应用程序调试的辅助工具.不再需要挂钩的库应当将相应的挂钩处理过程删除掉.

代码:
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);

代码:
.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
伪代码:
代码:
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
////////////////////////////////内核下

代码:
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_B

以上是关于windows消息钩子注册底层机制浅析的主要内容,如果未能解决你的问题,请参考以下文章

钩子注入的原理机制

windows钩子函数

钩子教程 - 原理

Spark Core任务运行机制和Task源代码浅析1

钩子的编写与使用

Hook(钩子技术)基本知识讲解,原理