windows消息钩子注册底层机制浅析
Posted 狂客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了windows消息钩子注册底层机制浅析相关的知识,希望对你有一定的参考价值。
标 题: 【原创】消息钩子注册浅析
作 者: RootSuLe
时 间: 2011-06-18,23:10:34
链 接: http://bbs.pediy.com/showthread.php?t=135702
windows消息钩子很古老,但目前仍有很多地方需要用到,简单跟踪了一下函数执行流程,函数用法如下(MSDN):
函数功能:该函数将一个应用程序定义的挂钩处理过程安装到挂钩链中去,您可以通过安装挂钩处理过程来对系统的某些类型事件进行监控,这些事件与某个特定的线程或系统中的所有事件相关.
函数原形:
参数:
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 系统
对于一个特定的挂钩类型,现成的挂钩先被调用,然后才是系统挂钩被调用.
系统挂钩作为共享资源,安装一次就对所用应用程序产生影响.所有的系统挂钩函数必须在库中.系统挂钩应当被限制用于一些特殊用途的应用程序或者用来作为应用程序调试的辅助工具.不再需要挂钩的库应当将相应的挂钩处理过程删除掉.
伪代码:SetWindowsHookExAW
HHOOK __stdcall _SetWindowsHookEx(HMODULE hmod,LPCWSTR Filename,DWORD dwThreadId,int idHook,HOOKPROC lpfn,DWORD dwFlags);
伪代码:
////////////////////////////////内核下
作 者: 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
代码:
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); }
代码:
.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消息钩子注册底层机制浅析的主要内容,如果未能解决你的问题,请参考以下文章