win32汇编-Windows钩子(七)

钩子可以用来截获系统中的消息流 通过SetWindowsHookEx函数定义了监视函数的位置和监视消息的类型,这样,每当发生我们感兴趣的消息时,Windows就会将消息发送给监视函数,监视函数是一个处理消息的回调函数,也称为“钩子函数”。(会影响系统的性能)

局部钩子仅钩挂属于自身进程的事件;(SetWindowsHook)

远程钩子分两种:基于线程的和系统范围的(包括自身)。

                    1 基于线程的远程钩子用来捕获其他进程中某一特定线程的事件;

                    2  系统范围的远程钩子将捕捉系统中所有进程中发生的事件消息。

 

钩 子 名 称

监视消息的类型和时机

WH_CALLWNDPROC

每当调用SendMessage函数时,函数将消息发送给目标窗口过程前首先调用钩子函数

WH_CALLWNDPROCRET

每当调用SendMessage函数时,函数将消息发送给目标窗口过程后再调用钩子函数

WH_GETMESSAGE

每当调用GetMessage或PeekMessage函数时,函数从程序的消息队列中获取一个消息后调用钩子函数

WH_KEYBOARD

每当调用GetMessage或PeekMessage函数时,如果从消息队列中得到的是WM_KEYUP或WM_KEYDOWN消息,则调用钩子函数(键盘消息)

WH_MOUSE

每当调用GetMessage或PeekMessage函数时,如果从消息队列中得到的是鼠标消息,则调用钩子函数(鼠标消息)

WH_HARDWARE

每当调用GetMessage或PeekMessage函数时,如果从消息队列中得到的是非鼠标和键盘消息,则调用钩子函数

WH_MSGFILTER

当用户对对话框、菜单和滚动条有所操作时,系统在发送对应的消息之前调用钩子函数,这种钩子只能是局部

WH_SYSMSGFILTER

同WH_MSGFILTER,不过是系统范围的

WH_SHELL

当Windows shell程序准备接收一些通知事件前调用钩子函数,如shell被激活和重画等

WH_DEBUG

用来给其他钩子函数除错(调试)

WH_CBT

当基于计算机的训练(CBT)事件发生时调用钩子函数 

WH_JOURNALRECORD

日志记录钩子,用来记录发送给系统消息队列的所有消息 只能全局

WH_JOURNALPLAYBACK

日志回放钩子,用来回放日志记录钩子记录的系统事件   只能全局

WH_FOREGROUNDIDLE

系统空闲钩子,当系统空闲的时候调用钩子函数,这样就可以在这里安排一些优先级很低的任务

程钩子的钩子函数必须位于一个动态链接库中,而且必须是共享数据段的动态链接库

钩子程序一般包括3个功能模块:

(1)主程序——用来实现界面或者其他功能。

(2)钩子回调函数——用来接收系统发过来的消息。

(3)钩子的安装和卸载程序。

键盘钩子示例 -(链接库)

<HookDll.asm>

                   .386

                    .model flat, stdcall

                    option casemap :none

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; Include 文件定义

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

include         windows.inc

include         user32.inc

includelib      user32.lib

include         kernel32.inc

includelib      kernel32.lib

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                    .data

hInstance       dd      ?

 

                    .data?

hWnd                dd      ?

hHook           dd      ?

dwMessage       dd      ?

szAscii         db      4 dup (?)

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                    .code

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

DllEntry            proc        _hInstance,_dwReason,_dwReserved

 

                    Push        _hInstance

                pop     hInstance

                mov     eax,TRUE

                ret

 

DllEntry            Endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 键盘钩子回调函数

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

HookProc            proc        _dwCode,_wParam,_lParam

                    local   @szKeyState[256]:byte

 

                    invoke  CallNextHookEx,hHook,_dwCode,_wParam,_lParam

                    invoke  GetKeyboardState,addr @szKeyState

                    invoke  GetKeyState,VK_SHIFT

                    mov     @szKeyState + VK_SHIFT,al

                    mov     ecx,_lParam

                    shr     ecx,16

                    invoke  ToAscii,_wParam,ecx,addr @szKeyState,addr szAscii,0

                    mov     byte ptr szAscii [eax],0

                    invoke  SendMessage,hWnd,dwMessage,dword ptr szAscii,NULL

                    xor     eax,eax

                    ret

 

HookProc            endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 安装钩子

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

InstallHook     proc        _hWnd,_dwMessage

 

                push        _hWnd

                pop     hWnd

                    push        _dwMessage

                pop     dwMessage

                invoke  SetWindowsHookEx,WH_KEYBOARD,addr HookProc,\

                        hInstance,NULL

                mov     hHook,eax

                ret

 

InstallHook endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 卸载钩子

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

UninstallHook   proc

 

                invoke  UnhookWindowsHookEx,hHook

                ret

 

UninstallHook   endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                End     DllEntry
View Code

<HookDll.def>文件中包括了它们的名称:

 

EXPORTS     HookProc

                InstallHook

                UninstallHook
View Code
   invoke  SetWindowsHookEx,idHook,lpHookProc,hInstance,dwThreadID

   .if     eax

           mov     hHook,eax

   .endif

idHook参数指定钩子的类型 

 hInstance 指定钩子回调函数所在DLL的实例句柄

 dwThreadID是安装钩子后想监控的线程的ID号 指定为NULL会被解释成系统范围的

 <Main.asm>

 .386

                    .model flat, stdcall

                    option casemap :none

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; Include 文件定义

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

include         windows.inc

include         user32.inc

includelib      user32.lib

include         kernel32.inc

includelib      kernel32.lib

include         Hookdll.inc

includelib      Hookdll.lib

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; Equ 等值定义

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

ICO_MAIN            equ     1000

DLG_MAIN            equ     1000

IDC_TEXT            equ     1001

WM_HOOK         equ     WM_USER + 100h

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 代码段

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                    .code

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_ProcDlgMain        proc        uses ebx edi esi hWnd,wMsg,wParam,lParam

                    local   @dwTemp

 

                mov     eax,wMsg

;********************************************************************

                    .if     eax ==  WM_CLOSE

                            invoke  UninstallHook

                            invoke  EndDialog,hWnd,NULL

;********************************************************************

                    .elseif eax ==  WM_INITDIALOG

                            invoke  InstallHook,hWnd,WM_HOOK

                            .if     ! eax

                                    invoke  EndDialog,hWnd,NULL

                            .endif

;********************************************************************

                    .elseif eax ==  WM_HOOK

                            mov     eax,wParam

                            .if     al == 0dh

                                    mov     eax,0a0dh

                            .endif

                            mov     @dwTemp,eax

                            invoke  SendDlgItemMessage,hWnd,IDC_TEXT,\

                                    EM_REPLACESEL,0,addr @dwTemp

                    .else

                            mov     eax,FALSE

                            ret

                    .endif

                    mov eax,TRUE

                    ret

 

_ProcDlgMain        endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

start:

                    invoke  GetModuleHandle,NULL

                    invoke  DialogBoxParam,eax,DLG_MAIN,NULL,\

                            offset _ProcDlgMain,NULL

                    invoke  ExitProcess,NULL

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                    end start
View Code

 

2. 钩子回调函数

 

现在回过头来看HookDll.asm程序中的钩子回调函数,回调函数的写法一般如下:

 

HookProc            proc        dwCode,wParam,lParam

 

                invoke  CallNextHookEx,hHook,_dwCode,_wParam,_lParam

 

                   ;处理消息的代码

 

                   mov     eax,返回值

 

                   ret

 

HookProc    endp

 

对于键盘钩子来说,参数的定义如下所示。

   dwCode——键盘消息的处理方式。如果是HC_ACTION,表示收到一个正常的击键消息;如果是HC_NOREMOVE,表示对应消息并没有从消息队列中移去(当某个进程用指定PM_NOREMOVE 标志的PeekMessage函数获取消息时就是如此)。

   wParam——按键的虚拟码(即Windows.inc中定义的VK_xxx值)。

   lParam——按键的重复次数、扫描码和标志等数据,不同数据位的定义如下:

   位0~15:按键的重复次数。

   位16~23:按键的扫描码。

   位24:按键是否是扩展键(F1与F2等Fx键,小键盘数字键等),如果此位是1表示按键是扩展键。

   位25~28:未定义。

   位29:如果Alt键在按下状态,此位置1,否则置0。

   位30:按键的原先状态,消息发送前按键原来是按下的,此位被设置为1,否则置0。

   位31:按键的当前动作,如果是按键按下,那么此位被设置为0;按键释放的话被设置为1

 

日志记录钩子

 

日志记录钩子是一种特殊的钩子,说它特殊是因为它是远程钩子,却不用放在动态链接库中,这就为监视系统范围的消息提供了方便。

 

 日志钩子HOOK键盘<RecHook.asm>

 .386

                    .model flat, stdcall

                    option casemap :none

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; Include 文件定义

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

include         windows.inc

include         user32.inc

includelib      user32.lib

include         kernel32.inc

includelib      kernel32.lib

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; Equ 等值定义

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

ICO_MAIN            equ     1000

DLG_MAIN            equ     1000

IDC_TEXT            equ     1001
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 数据段

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                    .data?

hInstance       dd      ?

hWinMain            dd      ?

hHook           dd      ?

szAscii         db      32 dup (?)

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 代码段

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                    .code

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 钩子回调函数

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

HookProc            proc        _dwCode,_wParam,_lParam

                    local   @szKeyState[256]:byte

 

            invoke  CallNextHookEx,hHook,_dwCode,_wParam,_lParam

            pushad

            .if     _dwCode == HC_ACTION

                    mov     ebx,_lParam

                    assume  ebx:ptr EVENTMSG

                    .if     [ebx].message == WM_KEYDOWN

                            invoke  GetKeyboardState,addr @szKeyState

                            invoke  GetKeyState,VK_SHIFT

                            mov     @szKeyState + VK_SHIFT,al

                            mov     ecx,[ebx].paramH

                            shr     ecx,16

                            invoke  ToAscii,[ebx].paramL,ecx,\

                                    addr @szKeyState,addr szAscii,0

                            mov     byte ptr szAscii [eax],0

                            .if     szAscii == 0dh

                            mov     word ptr szAscii+1,0ah

                            .endif

                            invoke  SendDlgItemMessage,hWinMain,IDC_TEXT,\

                                    EM_REPLACESEL,0,addr szAscii

                    .endif

                    assume  ebx:nothing

            .endif

            popad

            ret

 

HookProc            endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_ProcDlgMain        proc        uses ebx edi esi hWnd,wMsg,wParam,lParam

 

                    mov     eax,wMsg

;********************************************************************

                    .if     eax ==  WM_CLOSE

                            invoke  UnhookWindowsHookEx,hHook

                            invoke  EndDialog,hWnd,NULL

;********************************************************************

                    .elseif eax ==  WM_INITDIALOG

                            push        hWnd

                            pop     hWinMain

                            invoke  SetWindowsHookEx,WH_JOURNALRECORD,\

                                    addr HookProc,hInstance,NULL

                            .if     eax

                                    mov     hHook,eax

                            .else

                                    invoke  EndDialog,hWnd,NULL

                            .endif

;********************************************************************

                    .else

                            mov     eax,FALSE

                            ret

                    .endif

                    mov eax,TRUE

                    ret

 

_ProcDlgMain        endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

start:

                    invoke  GetModuleHandle,NULL

                    mov     hInstance,eax

                    invoke  DialogBoxParam,eax,DLG_MAIN,NULL,\

                            offset _ProcDlgMain,NULL

                    invoke  ExitProcess,NULL

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                    end     start
View Code

由于不再需要动态链接库了,钩子回调函数HookProc被移到了主程序中,也取消了InstallHook和UninstallHook两个子程序,相应的内容直接放在WM_INITDIALOG和WM_CLOSE消息中完成。在WM_INITDIALOG消息中用下面的语句完成对钩子的安装:

invoke  SetWindowsHookEx,WH_JOURNALRECORD,addr HookProc,hInstance,NULL

 

程序比较重要的一个不同点在于日志钩子回调函数的参数定义不同,在这里dwCode的参数定义如下:

 

   HC_ACTION——系统准备从消息队列中移去一条消息,消息的具体信息由lParam参数中指定的EVENTMSG结构定义。

 

   HC_SYSMODALOFF——某个系统模态对话框准备被关闭。

 

   HC_SYSMODALON——某个系统模态对话框准备被建立

我们关心的是HC_ACTION标志,这时lParam参数指向一个EVENTMSG结构,其定义为:

 

EVENTMSG STRUCT

  message   DWORD      ?     ;消息队列中将要移去的消息ID

  paramL    DWORD      ?     ;消息的wParam参数

  paramH    DWORD      ?     ;消息的lParam参数

  time      DWORD      ?     ;消息发生的事件

  hwnd      DWORD      ?     ;消息对应的窗口句柄

EVENTMSG ENDS

 

由于日志记录钩子可以截获的不仅是键盘消息,也有鼠标等其他消息,所以需要有个地方指定消息类型,通过检测EVENTMSG结构中的消息ID字段就可以得知截获的究竟是什么消息。(如按键消息ID WM_KEYDOWN)

 

 

 

 

 

 

 

 

 

posted @ 2014-04-12 16:06  xuanku  阅读(1120)  评论(0编辑  收藏  举报