这是一个《windows环境下32位汇编语言程序设计》中的例子,在动态链接库和钩子那章,作为一个钩子的示例程序。原理很简单,装个全局钩子,然后钩住所有的键盘信息即可。但是这里存在两个问题,一是装什么类型的全局钩子才能钩住所有进程的键盘信息,二是钩住的键盘信息的翻译。大家都知道,钩子函数钩住的信息是以扫描码和虚拟码,不是我们现实中看到的键盘信息,因此如何翻译也是个问题。当然,说穿了一点都不稀奇,第一个问题的答案是,需要安装一个日志记录钩子,即WH_JOURNALRECORD,书山还有个钩子例子,是用WM_KEYBOARD,但是,至少在例子上只能显示本进程的键盘信息。第二个答案是API函数ToAscii。完整代码如下,在XP+SP3下测试通过。
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
CON_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