對於HOOK函式的一點認識
種函式是Windows訊息處理機制的一部分,透過設定“鉤子”,應用程式可以在系統級對所有訊息、事件進行過濾,訪問在正常情況下無法訪問的訊息。當然,這麼做也是需要付出一定的代價的。由於多了這麼一道處理過程,系統效能會受到一定的影響,所以大家在必要的時候才使用“鉤子”,並在使用完畢及時將其刪除。[@more@]首先讓我們看看HOOK函式是怎麼安裝、呼叫和刪除的。應用程式通常是呼叫SetWindowsHookEx()函式來進行安裝的,其函式的原型如下:
SetWindowsHookEx(
Int idHook;
HOOKPROC lpfn;
HINSTANCE hMod;
DWORD dwThreadId;
);
引數說明:
idHook 是”鉤子”的型別,”鉤子”的型別一共有13種,具體如下表:
“鉤子”型別
解釋
WH_CALLWNDPROC
系統將訊息傳送到指定視窗之前的“鉤子”
WH_CALLWNDPROCRET
訊息已經在視窗中處理的“鉤子”
WH_CBT
基於計算機培訓的“鉤子”
WH_DEBUG
差錯“鉤子”
WH_FOREGROUNDIDLE
前臺空閒視窗“鉤子”
WH_GETMESSAGE
接收訊息投遞的“鉤子”
WH_JOURNALPLAYBACK
回放以前透過WH_JOURNALRECORD“鉤子”記錄的輸入訊息
WH_JOURNALRECORD
輸入訊息記錄“鉤子”
WH_KEYBOARD
鍵盤訊息“鉤子”
WH_MOUSE
滑鼠訊息“鉤子”
WH_MSGFILTER
對話方塊、訊息框、選單或捲軸輸入訊息“鉤子”
WH_SHELL
外殼“鉤子”
WH_SYSMSGFILTER
系統訊息“鉤子”
lpfn 指向“鉤子”過程的指標。
hMod “鉤子”過程所在模組的控制程式碼。
dwThreadId “鉤子”相關執行緒的標識。
通常我們都是把”鉤子”做成動態連結庫,這樣的好處是可以是系統內的每個程式訪問。但是也可以在系統中直接呼叫,我的建議還是用動態庫。如果用動態庫的話,那麼SetWindowsHookEx()中的第三個引數就是該動態連結庫模組的控制程式碼;對於一個只供單個程式訪問的”鉤子”,可以將其”鉤子”過程放在安裝”鉤子”的同一個執行緒內,此時SetWindowsHookEx()中的第三個引數為該執行緒的hInstance。安裝”鉤子”有兩種方法:1.你可以把他做成動態連線庫檔案,和程式一起編譯。2.你可以在程式的任何地方直接呼叫。第2種的方法太麻煩,我不建議用,在這裡我就不詳細介紹啦。相比之下第1種比較簡單。其”鉤子”的過程都在動態連結庫內完成。SetWindowsHookEx()函式是一個安裝函式,如故一個由某種型別的”鉤子”監視的事件發生,系統就會呼叫相應型別的”鉤子”鏈開始處的”鉤子”過程,”鉤子”鏈的每個”鉤子”過程都要考慮是否把事件傳遞給下一個”鉤子”過程。如果要傳遞的話,就要呼叫CallNestHookEx()函式。這個函式成功時返回”鉤子”鏈中下一個”鉤子”過程的返回值,返回值的型別依賴於”鉤子”的型別。這個函式的原型如下:
LRESULT CallNextHookEx(
HHOOK hhk;
int nCode;
WPARAM wParam;
LPARAM lParam;
);
其中hhk為當前”鉤子”的控制程式碼,由SetWindowsHookEx()函式返回。NCode為傳給”鉤子”過程的事件程式碼。wParam和lParam 分別是傳給”鉤子”過程的wParam值,其具體含義與”鉤子”型別有關。
釋放”鉤子”
釋放”鉤子”比較簡單,他只有一個引數。當不在需要”鉤子”時,應及時將其釋放。他是呼叫UnhookWindowsHookEx()函式來實現的,函式原型如下:
UnhookWindowsHookEx(
HHOOK hhk;
);
函式成功返回TRUE,否則返回FALSE。
如果我這樣講您還是不明白的話,請看下面給出的一些典型“鉤子”程式碼和說明。
LRESULT WINAPI CallWndProc(int nCode,WPARAM wParam,LPARAM lParam)
{
if(nCode<0)
return CallNextHookEx(NULL,nCode,wParam,lParam);
switch(nCode)
{
case HC_ACTION:
//”鉤子”程式要處理什麼的程式碼
break;
default:
break;
}
return CallNextHookEx(NULL,nCode,wParam,lParam);
}
這是WH_CALLWNDPROC”鉤子”的程式碼,此”鉤子”允許程式監視由函式SendMessage傳送給視窗過程的訊息。系統將訊息傳送到目的視窗之前呼叫WH_CALLWNDPROC “鉤子”過程。
LRESULT WINAPI CallwndProc(int nCode,WPARAM,wParam,LPARAM lParam)
{
if(nCode<0) return callNextHookEx(NULL,nCode,wParam,lParam);
switch(nCode)
{
case HC_ACTION:
switch(wParam)
{
Case PM_REMOVE:
//某個應用程式呼叫了GetMessage函式或者是帶PM_REMOVE引數的//PeekMessage函式,從訊息佇列中移去一個訊息。
Break;
Case PM_NOREMOVE:
//某個應用程式以PM_NOREMOVE為引數呼叫PeekMessage函式
break;
default:
break;
}
break;
default:
break;
}
return CallNextHookEx(NULL,nCode,wParam,lParam);
}
這是呼叫WH_GETMESSAGE的函式,此函式允許應用程式監視函式GetMessage和 PeekMessage返回的訊息。應用程式可以用鉤子WH_GETMESSAGE來監視滑鼠和鍵盤的輸入以及其他系統傳送到訊息佇列中的訊息。
LRESULT CALLBACK CBTProc(int nCode,WPARAM wParam,LPARAM lParam)
{
If(nCode<0) Return callNextHookEx(NULL,nCode,wParam,lParam);
Switch(nCode)
{
case HCBT_ACTIVATE:
//系統將啟用一個視窗
break;
case HCBT_CLICKSKIPPED:
//系統從系統訊息佇列中移去一個滑鼠訊息
break;
case HCBT_CREATEWND:
//系統將建立一個視窗
break;
case HCBT_DESTROYWND:
//系統將關閉一個視窗
break;
case HCBT_KEYSKIPPED:
//系統從系統訊息佇列中移去一個鍵盤訊息
break;
case HCBT_MINMAX:
//系統將最大化或最小化一個視窗
break;
case HCBT_MOVESIZE:
//系統將移動一個視窗或改變一個視窗的大小
break;
case HCBT_QS:
//系統在系統訊息佇列中檢索到WM_QUEUESYNC訊息
break;
case HCBT_SETFOCUS:
//系統設定鍵盤輸入視窗
break;
case HCBT_SYSCOMMAND:
//將要執行一個系統命令
break;
default:
//可以新增其他程式碼
break;
}
return CallNextHookEx(NULL,nCode,wParam,lParam);
}
每種”鉤子”型別都有其對應的函式,這些函式的引數都是一樣的,有興趣的朋友可以在MSDN中找的他們的詳細說明。
下面我給出一個完整的”鉤子”安裝和刪除的過程的程式碼。
#include "stdafx.h"
#include "hook.h"
HINSTANCE hInstance;
HHOOK hhkKeyboard;
BOOL APIENTRY DllMain( HANDLE hModule,DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
hInstance=(HINSTANCE)hModule;
return TRUE;
}
LRESULT KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)
{
MessageBeep(-1);
return CallNextHookEx(NULL,nCode,wParam,lParam);
}
HOOK_API BOOL EnableKeyboardCapture()
{
if(!(hhkKeyboard=SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyboardProc,hInstance,0)))
return FALSE;
return TRUE;
}
HOOK_API BOOL DisableKeyboardCapture()
{
return UnhookWindowsHookEx(hhkKeyboard);
}
注意:這是一個動態連結庫檔案。
在程式中要想呼叫“鉤子”的時候,有EnableKeyboardCapture()函式就可以啦,但你按鍵的時候就回發出聲音。
SetWindowsHookEx(
Int idHook;
HOOKPROC lpfn;
HINSTANCE hMod;
DWORD dwThreadId;
);
引數說明:
idHook 是”鉤子”的型別,”鉤子”的型別一共有13種,具體如下表:
“鉤子”型別
解釋
WH_CALLWNDPROC
系統將訊息傳送到指定視窗之前的“鉤子”
WH_CALLWNDPROCRET
訊息已經在視窗中處理的“鉤子”
WH_CBT
基於計算機培訓的“鉤子”
WH_DEBUG
差錯“鉤子”
WH_FOREGROUNDIDLE
前臺空閒視窗“鉤子”
WH_GETMESSAGE
接收訊息投遞的“鉤子”
WH_JOURNALPLAYBACK
回放以前透過WH_JOURNALRECORD“鉤子”記錄的輸入訊息
WH_JOURNALRECORD
輸入訊息記錄“鉤子”
WH_KEYBOARD
鍵盤訊息“鉤子”
WH_MOUSE
滑鼠訊息“鉤子”
WH_MSGFILTER
對話方塊、訊息框、選單或捲軸輸入訊息“鉤子”
WH_SHELL
外殼“鉤子”
WH_SYSMSGFILTER
系統訊息“鉤子”
lpfn 指向“鉤子”過程的指標。
hMod “鉤子”過程所在模組的控制程式碼。
dwThreadId “鉤子”相關執行緒的標識。
通常我們都是把”鉤子”做成動態連結庫,這樣的好處是可以是系統內的每個程式訪問。但是也可以在系統中直接呼叫,我的建議還是用動態庫。如果用動態庫的話,那麼SetWindowsHookEx()中的第三個引數就是該動態連結庫模組的控制程式碼;對於一個只供單個程式訪問的”鉤子”,可以將其”鉤子”過程放在安裝”鉤子”的同一個執行緒內,此時SetWindowsHookEx()中的第三個引數為該執行緒的hInstance。安裝”鉤子”有兩種方法:1.你可以把他做成動態連線庫檔案,和程式一起編譯。2.你可以在程式的任何地方直接呼叫。第2種的方法太麻煩,我不建議用,在這裡我就不詳細介紹啦。相比之下第1種比較簡單。其”鉤子”的過程都在動態連結庫內完成。SetWindowsHookEx()函式是一個安裝函式,如故一個由某種型別的”鉤子”監視的事件發生,系統就會呼叫相應型別的”鉤子”鏈開始處的”鉤子”過程,”鉤子”鏈的每個”鉤子”過程都要考慮是否把事件傳遞給下一個”鉤子”過程。如果要傳遞的話,就要呼叫CallNestHookEx()函式。這個函式成功時返回”鉤子”鏈中下一個”鉤子”過程的返回值,返回值的型別依賴於”鉤子”的型別。這個函式的原型如下:
LRESULT CallNextHookEx(
HHOOK hhk;
int nCode;
WPARAM wParam;
LPARAM lParam;
);
其中hhk為當前”鉤子”的控制程式碼,由SetWindowsHookEx()函式返回。NCode為傳給”鉤子”過程的事件程式碼。wParam和lParam 分別是傳給”鉤子”過程的wParam值,其具體含義與”鉤子”型別有關。
釋放”鉤子”
釋放”鉤子”比較簡單,他只有一個引數。當不在需要”鉤子”時,應及時將其釋放。他是呼叫UnhookWindowsHookEx()函式來實現的,函式原型如下:
UnhookWindowsHookEx(
HHOOK hhk;
);
函式成功返回TRUE,否則返回FALSE。
如果我這樣講您還是不明白的話,請看下面給出的一些典型“鉤子”程式碼和說明。
LRESULT WINAPI CallWndProc(int nCode,WPARAM wParam,LPARAM lParam)
{
if(nCode<0)
return CallNextHookEx(NULL,nCode,wParam,lParam);
switch(nCode)
{
case HC_ACTION:
//”鉤子”程式要處理什麼的程式碼
break;
default:
break;
}
return CallNextHookEx(NULL,nCode,wParam,lParam);
}
這是WH_CALLWNDPROC”鉤子”的程式碼,此”鉤子”允許程式監視由函式SendMessage傳送給視窗過程的訊息。系統將訊息傳送到目的視窗之前呼叫WH_CALLWNDPROC “鉤子”過程。
LRESULT WINAPI CallwndProc(int nCode,WPARAM,wParam,LPARAM lParam)
{
if(nCode<0) return callNextHookEx(NULL,nCode,wParam,lParam);
switch(nCode)
{
case HC_ACTION:
switch(wParam)
{
Case PM_REMOVE:
//某個應用程式呼叫了GetMessage函式或者是帶PM_REMOVE引數的//PeekMessage函式,從訊息佇列中移去一個訊息。
Break;
Case PM_NOREMOVE:
//某個應用程式以PM_NOREMOVE為引數呼叫PeekMessage函式
break;
default:
break;
}
break;
default:
break;
}
return CallNextHookEx(NULL,nCode,wParam,lParam);
}
這是呼叫WH_GETMESSAGE的函式,此函式允許應用程式監視函式GetMessage和 PeekMessage返回的訊息。應用程式可以用鉤子WH_GETMESSAGE來監視滑鼠和鍵盤的輸入以及其他系統傳送到訊息佇列中的訊息。
LRESULT CALLBACK CBTProc(int nCode,WPARAM wParam,LPARAM lParam)
{
If(nCode<0) Return callNextHookEx(NULL,nCode,wParam,lParam);
Switch(nCode)
{
case HCBT_ACTIVATE:
//系統將啟用一個視窗
break;
case HCBT_CLICKSKIPPED:
//系統從系統訊息佇列中移去一個滑鼠訊息
break;
case HCBT_CREATEWND:
//系統將建立一個視窗
break;
case HCBT_DESTROYWND:
//系統將關閉一個視窗
break;
case HCBT_KEYSKIPPED:
//系統從系統訊息佇列中移去一個鍵盤訊息
break;
case HCBT_MINMAX:
//系統將最大化或最小化一個視窗
break;
case HCBT_MOVESIZE:
//系統將移動一個視窗或改變一個視窗的大小
break;
case HCBT_QS:
//系統在系統訊息佇列中檢索到WM_QUEUESYNC訊息
break;
case HCBT_SETFOCUS:
//系統設定鍵盤輸入視窗
break;
case HCBT_SYSCOMMAND:
//將要執行一個系統命令
break;
default:
//可以新增其他程式碼
break;
}
return CallNextHookEx(NULL,nCode,wParam,lParam);
}
每種”鉤子”型別都有其對應的函式,這些函式的引數都是一樣的,有興趣的朋友可以在MSDN中找的他們的詳細說明。
下面我給出一個完整的”鉤子”安裝和刪除的過程的程式碼。
#include "stdafx.h"
#include "hook.h"
HINSTANCE hInstance;
HHOOK hhkKeyboard;
BOOL APIENTRY DllMain( HANDLE hModule,DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
hInstance=(HINSTANCE)hModule;
return TRUE;
}
LRESULT KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)
{
MessageBeep(-1);
return CallNextHookEx(NULL,nCode,wParam,lParam);
}
HOOK_API BOOL EnableKeyboardCapture()
{
if(!(hhkKeyboard=SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyboardProc,hInstance,0)))
return FALSE;
return TRUE;
}
HOOK_API BOOL DisableKeyboardCapture()
{
return UnhookWindowsHookEx(hhkKeyboard);
}
注意:這是一個動態連結庫檔案。
在程式中要想呼叫“鉤子”的時候,有EnableKeyboardCapture()函式就可以啦,但你按鍵的時候就回發出聲音。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/79126/viewspace-984983/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 對於HOOK函式的一點認識 (轉)Hook函式
- 對高階函式的簡單認識函式
- Golang字串函式認識(一)Golang字串函式
- 關於Inlist iterator操作的一點認識
- strcat函式的基礎認識函式
- 我對C++中虛擬函式、純虛擬函式在實現多型中作用的一點淺薄認識 (轉)C++函式多型
- 認真一點學 Go:10. 函式Go函式
- Golang字串函式認識(二)Golang字串函式
- 深入認識javascript中的eval函式JavaScript函式
- 關於 Laravel 框架事件系統的一點認識Laravel框架事件
- 【Linux】關於bind_ip的一點認識Linux
- 關於建構函式的一點理解函式
- 從一道面試題認識函式柯里化面試題函式
- 深入認識 http_build_query 函式HTTPUI函式
- 基於函式index的一點簡單測試!函式Index
- 關於rand和srand函式使用的一點心得函式
- JS函式知識點梳理JS函式
- 【知識點】inline函式、回撥函式、普通函式inline函式
- 排序(對於 sort 函式的使用)排序函式
- 關於Python一等函式的一點實踐Python函式
- 對按鈕的一些認識
- react hook——你可能不是“我”所認識的useEffectReactHook
- <> 第1篇 認識C++的函式和物件C++函式物件
- 關於enqueue的一些認識ENQ
- ObjectC Hook函式的實現與實戰ObjectHook函式
- 封裝Detours用於Python中x64函式hook封裝Python函式Hook
- Frida官方手冊 - 函式Hook函式Hook
- 談談對資料架構的幾點認識架構
- zt 對C#下函式,委託,事件的一點理解!C#函式事件
- 對於計算機作業系統的認識計算機作業系統
- 教你認識AWK 使用者自定義函式函式
- C語言學習之認識exit()函式C語言函式
- 偶函式在零點的泰勒展開式相關知識點函式
- 初學 PHP 對於回撥函式的一些理解PHP函式
- 對C++的認識C++
- 函數語言程式設計(一) 認識“程式設計正規化”和“函式”函數程式設計函式
- 關於 MySQL 索引的一些認識MySql索引
- before-after-hook鉤子函式Hook函式