鉤子能夠用來截獲系統中的消息流 經過SetWindowsHookEx函數定義了監視函數的位置和監視消息的類型,這樣,每當發生咱們感興趣的消息時,Windows就會將消息發送給監視函數,監視函數是一個處理消息的回調函數,也稱爲「鉤子函數」。(會影響系統的性能)shell
局部鉤子僅鉤掛屬於自身進程的事件;(SetWindowsHook)windows
遠程鉤子分兩種:基於線程的和系統範圍的(包括自身)。ide
1 基於線程的遠程鉤子用來捕獲其餘進程中某一特定線程的事件;函數
2 系統範圍的遠程鉤子將捕捉系統中全部進程中發生的事件消息。性能
鉤 子 名 稱spa |
監視消息的類型和時機線程 |
WH_CALLWNDPROC調試 |
每當調用SendMessage函數時,函數將消息發送給目標窗口過程前首先調用鉤子函數日誌 |
WH_CALLWNDPROCRETcode |
每當調用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
<HookDll.def>文件中包括了它們的名稱:
EXPORTS HookProc
InstallHook
UninstallHook
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
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
因爲再也不須要動態連接庫了,鉤子回調函數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)