WIN32汇编语言教程:第11章 动态链接库和钩子 · 11.2 Windows钩子(2)

NAME = Main
DLL = Hookdll
 
ML_FLAG = /c /coff
LINK_FLAG = /subsystem:windows
DLL_LINK_FLAG = /subsystem:windows /section:.bss,S
 
$(DLL).dll $(NAME).exe:
$(DLL).dll: $(DLL).obj $(DLL).def
         Link $(DLL_LINK_FLAG) /Def:$(DLL).def /Dll $(DLL).obj
$(NAME).exe: $(NAME).obj $(NAME).res
       Link $(LINK_FLAG) $(NAME).obj $(NAME).res
.asm.obj:
           ml $(ML_FLAG) $<
.rc.res:
           rc $<
clean:
           del *.obj
           del *.res
           del *.exp
           del *.lib

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

需要共享的变量被放在 .data?段中,如钩子句柄和钩住的按键内容等,仅dll程序的实例句柄不需要共享,不需要共享的变量放在 .data段中。动态链接库的入口函数例行公事地返回了一个TRUE来表示允许被装入。程序中只写了3个函数,HookProc是钩子回调函数,InstallHook和 UninstallHook函数是供主程序使用的钩子安装函数和卸载函数。这3个函数是需要导出的,所以HookDll.def文件中包括了它们的名称:

EXPORTS    HookProc
             InstallHook
              UninstallHook

InstallHook子程序用来安装钩子,程序为它设计了两个参数:窗口句柄和自定义消息ID。动态链接库保存这两个参数,以便在钩子回调函数收到消息的时候将截获的按键通过自定义消息ID转发给父窗口,这样父窗口在初始化完成后只需要等待自定义消息ID就可以了。

在子程序中,通过SetWindowsHookEx函数安装钩子。SetWindowsHookEx函数的用法是:

  invoke SetWindowsHookEx,idHook,lpHookProc,hInstance,dwThreadID
  .if    eax
         mov    hHook,eax
  .endif

idHook参数指定钩子的类型,它就是表11.1中列出的钩子名称。例子中要安装的是键盘钩子,所以使用WH_KEYBOARD。lpHookProc参数指出钩子回调函数的地址。

hInstance 指定钩子回调函数所在DLL的实例句柄。如果安装的是局部钩子的话,由于局部钩子的回调函数并不需要放在动态链接库中,这时这个参数就使用NULL。

dwThreadID是安装钩子后想监控的线程的ID号。该参数可以决定钩子是局部的还是系统范围的。如果参数指定的是自己进程中的某个线程ID号,那么该钩子是一个局部钩子;如果指定的线程ID是另一个进程中某个线程的ID,那么安装的钩子是一个局部的远程钩子;如果想要安装系统范围的全局钩子的话,可以将这个参数指定为NULL,这样钩子就会被解释成系统范围的,可以用来监控所有的进程及它们的线程。

上页:第11章 动态链接库和钩子 · 11.2 Windows钩子(1) 下页:第11章 动态链接库和钩子 · 11.2 Windows钩子(3)

第11章 动态链接库和钩子

版权所有 © 中山市飞娥软件工作室 证书:粤ICP备09170368号