hook使用指南(一) (轉)
1.Hooks
hook指出了訊息處理機制。利用hook,可以在應用中子程式監視系統和程式之間的訊息傳遞,這個監視過程是在訊息到達目的視窗過程之前。
下面簡述hook,並且解釋在系統下,如何使用hook。
2.About Hooks
hook將使程式降低,因為它們增加了系統必須處理的訊息總數。你應該在需要時才使用,並及時刪除它。我將以下面的主題描述hook。
Hook Chains(hook鏈)
系統支援很多不同型別的hooks;不同的hook提供不同的訊息處理機制。比如,應用程式可以使用WH_MOUSE_hook來監視滑鼠訊息的傳遞。
系統為不同型別的hook提供單獨的hook鏈。hook鏈是一個指標列表,這個列表的指標指向指定的,應用程式定義的,被hook過程的回撥。當與指定的hook型別關聯的訊息發生時,系統就把這個訊息傳遞到hook過程。一些hook過程可以只監視訊息,或者修改訊息,或者停止訊息的前進,避免這些訊息傳遞到下一個hook過程或者目的視窗。
Hook Procedures(hook過程)
為了利用特殊的hook型別,開發者提供了hook過程,使用SetHookEx函式來把hook過程安裝到關聯的hook鏈。hook過程必須按照以下的語法:
LRESULT CALLBACK HookProc(
int nCode,
WPARAM wParam,
LPARAM lParam
);
HookProc是應用程式定義的名字。
nCode引數是hook程式碼,hook過程使用這個引數來確定任務。這個引數的值依賴於hook型別,每一種hook都有自己的hook程式碼特徵字符集。wParam和lParam引數的值依賴於hook程式碼,但是它們的典型值是包含了關於傳送或者接收訊息的資訊。
SetWindowsHookEx函式總是在hook鏈的開頭安裝hook過程。當指定型別的hook監視的事件發生時,系統就呼叫與這個hook關聯的hook鏈的開頭的hook過程。每一個hook鏈中的hook過程都決定是否把這個事件傳遞到下一個hook過程。hook過程傳遞事件到下一個hook過程需要呼叫CallNextHookEx函式。
有些型別hook的hook過程只能監視訊息,不管是否呼叫了CallNextHookEx函式,系統都把訊息傳遞到每一個hook過程。
全域性hook監視同一桌面的所有執行緒。而特定執行緒的hook只能監視單獨的執行緒。全域性hook過程可以被同一桌面的任何應用程式呼叫,就象呼叫執行緒一樣,所以這個過程必須和DLL模組分開。特定執行緒hook過程只可以被相關執行緒呼叫。只有在有目的的時候才使用全域性hook,應該避免使用,全域性hook損害了系統。
Hook Types
每一種型別的hook可以使應用程式能夠監視不同型別的系統訊息處理機制。下面描述所有可以利用的hook型別。
WH_CALLWNDPROC and WH_CALLWNDPROCRET Hooks
WH_CALLWNDPROC and WH_CALLWNDPROCRET Hook使你可以監視傳送到視窗過程的訊息。系統在訊息傳送到接收視窗過程之前呼叫WH_CALLWNDPROC hook過程,並且在視窗過程處理完訊息之後呼叫WH_CALLWNDPROCRET Hook過程。
WH_CALLWNDPROCRET Hook傳遞指標到CWPRETSTRUCT結構,再傳遞到hook過程。CWPRETSTRUCT結構包含了來自處理訊息的視窗過程的返回值,同樣也包括了與這個訊息關聯的訊息引數。
WH_CHook
在以下事件之前,系統都會呼叫WH_CBT Hook過程,這些事件包括:啟用,建立,銷燬,最小化,最大化,移動,改變尺寸等視窗事件;完成系統指令;來自系統訊息佇列中的移動滑鼠,鍵盤事件;設定輸入焦點事件;同步系統訊息佇列事件。hook過程的返回值確定系統是否允許或者防止這些操作中的一個。
WH_DE Hook
在系統呼叫系統中與其他hook關聯的hook過程之前,系統會呼叫WH_DEBUG Hook過程。你可以使用這個hook來決定是否允許系統呼叫與其他hook關聯的hook過程。
WH_FOREGROUNDIDLE Hook
當應用程式的前景執行緒處於空閒狀態時,可以使用WH_FOREGROUNDIDLE Hook低優先順序的任務。當應用程式的前景執行緒大概要變成空閒狀態時,系統就會呼叫WH_FOREGROUNDIDLE Hook過程。
WH_GETMESSAGE Hook
應用程式使用WH_GETMESSAGE Hook來監視從GetMessage or PeekMessage函式返回的訊息。你可以使用WH_GETMESSAGE Hook去監視滑鼠和鍵盤輸入,以及其他傳送到訊息佇列中的訊息。
WH_JOURNALPLAYBACK Hook
WH_JOURNALPLAYBACK Hook使應用程式可以插入訊息到系統訊息佇列。可以使用這個hook回放透過使用WH_JOURNALRECORD hook記錄下來的連續的滑鼠和鍵盤事件。只要WH_JOURNALPLAYBACK hook已經安裝,正常的滑鼠和鍵盤事件就是無效的。WH_JOURNALPLAYBACK hook是全域性hook,它不能象執行緒特定hook一樣使用。WH_JOURNALPLAYBACK hook返回超時值,這個值告訴系統在處理來自回放hook當前訊息之前需要等待多長時間(毫秒)。這就使hook可以控制實時事件的回放。
WH_JOURNALRECORD Hook
WH_JOURNALRECORD Hook用來監視和記錄輸入事件。典型的,可以使用這個hook記錄連續的滑鼠和鍵盤事件,然後透過使用WH_JOURNALPLAYBACK Hook來回放。WH_JOURNALRECORD hook是全域性hook,它不能象執行緒特定hook一樣使用。
WH_KEYBOARD Hook
在應用程式中,WH_KEYBOARD Hook用來監視WM_KEYDOWN and WM_KEYUP訊息,這些訊息透過GetMessage or PeekMessage function返回。可以使用這個hook來監視輸入到訊息佇列中的鍵盤訊息。
WH_KEYBOARD_LL Hook
WH_KEYBOARD_LL Hook監視輸入到執行緒訊息佇列中的鍵盤訊息。
WH_MOUSE Hook
WH_MOUSE Hook監視從GetMessage or PeekMessage function返回的滑鼠訊息。使用這個hook監視輸入到訊息佇列中的滑鼠訊息。
WH_MOUSE_LL Hook
WH_MOUSE_LL Hook監視輸入到執行緒訊息佇列中的滑鼠訊息。
WH_MSGFILTER and WH_SYSMSGFILTER Hooks
WH_MSGFILTER and WH_SYSMSGFILTER Hooks使我們可以監視選單,捲軸,訊息框,對話方塊訊息並且發現使用ALT+TAB or ALT+ESC 組合鍵切換視窗。WH_MSGFILTER hook只能監視傳遞到選單,捲軸,訊息框的訊息,以及傳遞到透過安裝了hook過程的應用程式建立的對話方塊的訊息。WH_SYSMSGFILTER Hook監視所有應用程式訊息。
WH_MSGFILTER and WH_SYSMSGFILTER Hooks使我們可以在迴圈期間過濾訊息,這等價於在主訊息迴圈中過濾訊息。
透過呼叫CallMsgFilter function可以直接的呼叫WH_MSGFILTER hook。透過使用這個函式,應用程式能夠在模式迴圈期間使用相同的程式碼去過濾訊息,如同在主訊息迴圈裡一樣。
WH_ Hook
外殼應用程式可以使用WH_SHELL Hook去接收重要的通知。當外殼應用程式是啟用的並且當頂層視窗建立或者銷燬時,系統呼叫WH_SHELL Hook過程。
按照慣例,外殼應用程式都不接收WH_SHELL訊息。所以,在應用程式能夠接收WH_SHELL訊息之前,應用程式必須呼叫SystemParametersInfo function註冊它自己。
3.Using Hooks
Installing and Releasing Hook Procedures
可以使用SetWindowsHookEx function安裝hook過程並且指定hook型別,指定是否需要把hook過程與所有執行緒關聯,或者關聯指定的執行緒,並且指向hook過程入口點。
必須把全域性hook過程放進DLL,以和應用程式安裝的hook過程分開。在應用程式安裝hook過程之前,它必須有一個指向DLL模組的控制程式碼。為了得到這個控制程式碼,可以在呼叫LoadLibrary函式時使用DLL名字引數。在得到這個控制程式碼以後,可以呼叫GetProcAddress函式來得到hook過程的指標。最後,使用SetWindowsHookEx函式安裝hook過程地址進應用程式hook鏈。這個過程可以用下面的事例說明:
HOOKPROC hkprcSysMsg;
static HINSTANCE hinstDLL;
static HHOOK hhookSysMsg;
hinstDLL = LoadLibrary((LPCTSTR) "c:windowssysmsg.dll"); DLL
hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc"); address
hhookSysMsg = SetWindowsHookEx(WH_SYSMSGFILTER,hkprcSysMsg,hinstDLL,0); hook
當應用程式不再需要與特定執行緒相關hook時,需要呼叫UnhookWindowsHookEx函式刪除相關的hook過程。對於全域性hook,也需要呼叫UnhookWindowsHookEx函式,但是這個函式不能釋放DLL包含的hook過程。這是因為全域性hook過程是被所有應用程式程式呼叫的,這就導致了所有的程式都隱性的呼叫了LoadLibrary函式。所以必須呼叫FreeLibrary函式釋放DLL。
Monitoring System Events
下面的例子使用了不同的特定執行緒hook過程去監視系統事件。它示範了怎樣使用下面的hook過程去處理事件:
WH_CALLWNDPROC
WH_CBT
WH_DEBUG
WH_GETMESSAGE
WH_KEYBOARD
WH_MOUSE
WH_MSGFILTER
使用者可以透過使用選單安裝或者移走hook過程。當hook過程已經安裝並且過程監視的時間發生時,hook過程將在應用程式主視窗客戶區寫出事件資訊。原始碼如下:
#define NUMHOOKS 7
// Global variables
typedef struct _MYHOOKDATA
{
int nType;
HOOKPROC hkprc;
HHOOK hhook;
} MYHOOKDATA;
MYHOOKDATA myhookdata[NUMHOOKS];
LRESULT WIN MainWndProc(HWND hwndMain, UINT uMsg, WPARAM wParam,
LPARAM lParam)
{
static BOOL afHooks[NUMHOOKS];
int index;
static HMENU hmenu;
switch (uMsg)
{
case WM_CREATE:
// Save the menu handle.
hmenu = GetMenu(hwndMain);
// Initialize structures with hook data. The menu-item
// ntifiers are defined as 0 through 6 in the
// header file. They can be used to identify array
// elements both here and during the WM_COMMAND
// message.
myhookdata[IDM_CALLWNDPROC].nType = WH_CALLWNDPROC;
myhookdata[IDM_CALLWNDPROC].hkprc = CallWndProc;
myhookdata[IDM_CBT].nType = WH_CBT;
myhookdata[IDM_CBT].hkprc = CBTProc;
myhookdata[IDM_DEBUG].nType = WH_DEBUG;
myhookdata[IDM_DEBUG].hkprc = DebugProc;
myhookdata[IDM_GETMESSAGE].nType = WH_GETMESSAGE;
myhookdata[IDM_GETMESSAGE].hkprc = GetMsgProc;
myhookdata[IDM_KEYBOARD].nType = WH_KEYBOARD;
myhookdata[IDM_KEYBOARD].hkprc = KeyboardProc;
myhookdata[IDM_MOUSE].nType = WH_MOUSE;
myhookdata[IDM_MOUSE].hkprc = MouseProc;
myhookdata[IDM_MSGFILTER].nType = WH_MSGFILTER;
myhookdata[IDM_MSGFILTER].hkprc = MessageProc;
// Initialize all flags in the array to FALSE.
memset(afHooks, FALSE, sizeof(afHooks));
return 0;
case WM_COMMAND:
switch (LO(wParam))
{
// The user ed a hook command from the menu.
case IDM_CALLWNDPROC:
case IDM_CBT:
case IDM_DEBUG:
case IDM_GETMESSAGE:
case IDM_KEYBOARD:
case IDM_MOUSE:
case IDM_MSGFILTER:
// Use the menu-item identifier as an index
// into the array of structures with hook data.
index = LOWORD(wParam);
// If the selected type of hook procedure isn't
// installed yet, install it and check the
// associated menu item.
if (!afHooks[index])
{
myhookdata[index].hhook = SetWindowsHookEx(
myhookdata[index].nType,
myhookdata[index].hkprc,
(HINSTANCE) NULL, GetCurrentThreadId());
CheckMenuItem(hmenu, index,
MF_BYCOMMAND | MF_CHECKED);
afHooks[index] = TRUE;
}
// If the selected type of hook procedure is
// already installed, remove it and remove the
// check mark from the associated menu item.
else
{
UnhookWindowsHookEx(myhookdata[index].hhook);
CheckMenuItem(hmenu, index,
MF_BYCOMMAND | MF_UNCHECKED);
afHooks[index] = FALSE;
}
default:
return (DefWindowProc(hwndMain, uMsg, wParam,
lParam));
}
break;
//
// Process other messages.
//
default:
return DefWindowProc(hwndMain, uMsg, wParam, lParam);
}
return NULL;
}
/****************************************************************
WH_CALLWNDPROC hook procedure
****************************************************************/
LRESULT WINAPI CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szCWPBuf[256];
CHAR szMsg[16];
HDC hdc;
static int c = 0;
int cch;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[CALLWNDPROC].hhook, nCode,
wParam, lParam);
// Call an application-defined function that converts a message
// constant to a string and copies it to a buffer.
LookUpTheMessage((PMSG) lParam, szMsg);
hdc = GetDC(hwndMain);
switch (nCode)
{
case HC_ACTION:
cch = wsprintf(szCWPBuf,
"CALLWNDPROC - tsk: %ld, msg: %s, %d times ",
wParam, szMsg, c++);
TextOut(hdc, 2, 15, szCWPBuf, cch);
break;
default:
break;
}
ReleaseDC(hwndMain, hdc);
return CallNextHookEx(myhookdata[CALLWNDPROC].hhook, nCode,
wParam, lParam);
}
/****************************************************************
WH_GETMESSAGE hook procedure
****************************************************************/
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szMSGBuf[256];
CHAR szRem[16];
CHAR szMsg[16];
HDC hdc;
static int c = 0;
int cch;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[GETMESSAGE].hhook, nCode,
wParam, lParam);
switch (nCode)
{
case HC_ACTION:
switch (wParam)
{
case PM_REMOVE:
lstrcpy(szRem, "PM_REMOVE");
break;
case PM_NOREMOVE:
lstrcpy(szRem, "PM_NOREMOVE");
break;
default:
lstrcpy(szRem, "Unknown");
break;
}
// Call an application-defined function that converts a
// message constant to a string and copies it to a
// buffer.
LookUpTheMessage((PMSG) lParam, szMsg);
hdc = GetDC(hwndMain);
cch = wsprintf(szMSGBuf,
"GETMESSAGE - wParam: %s, msg: %s, %d times ",
szRem, szMsg, c++);
TextOut(hdc, 2, 35, szMSGBuf, cch);
break;
default:
break;
}
ReleaseDC(hwndMain, hdc);
return CallNextHookEx(myhookdata[GETMESSAGE].hhook, nCode,
wParam, lParam);
}
/****************************************************************
WH_DEBUG hook procedure
****************************************************************/
LRESULT CALLBACK DebugProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szBuf[128];
HDC hdc;
static int c = 0;
int cch;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[DEBUG].hhook, nCode,
wParam, lParam);
hdc = GetDC(hwndMain);
switch (nCode)
{
case HC_ACTION:
cch = wsprintf(szBuf,
"DEBUG - nCode: %d, tsk: %ld, %d times ",
nCode,wParam, c++);
TextOut(hdc, 2, 55, szBuf, cch);
break;
default:
break;
}
ReleaseDC(hwndMain, hdc);
return CallNextHookEx(myhookdata[DEBUG].hhook, nCode, wParam,
lParam);
}
/****************************************************************
WH_CBT hook procedure
****************************************************************/
LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szBuf[128];
CHAR szCode[128];
HDC hdc;
static int c = 0;
int cch;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[CBT].hhook, nCode, wParam,
lParam);
hdc = GetDC(hwndMain);
switch (nCode)
{
case HCBT_ACTIVATE:
lstrcpy(szCode, "HCBT_ACTIVATE");
break;
case HCBT_CLICKSKIPPED:
lstrcpy(szCode, "HCBT_CLICKSKIPPED");
break;
case HCBT_CREATEWND:
lstrcpy(szCode, "HCBT_CREATEWND");
break;
case HCBT_DESTROYWND:
lstrcpy(szCode, "HCBT_DESTROYWND");
break;
case HCBT_KEYSKIPPED:
lstrcpy(szCode, "HCBT_KEYSKIPPED");
break;
case HCBT_MINMAX:
lstrcpy(szCode, "HCBT_MINMAX");
break;
case HCBT_MOVESIZE:
lstrcpy(szCode, "HCBT_MOVESIZE");
break;
case HCBT_QS:
lstrcpy(szCode, "HCBT_QS");
break;
case HCBT_SETFOCUS:
lstrcpy(szCode, "HCBT_SETFOCUS");
break;
case HCBT_SYMMAND:
lstrcpy(szCode, "HCBT_SYSCOMMAND");
break;
default:
lstrcpy(szCode, "Unknown");
break;
}
cch = wsprintf(szBuf, "CBT - nCode: %s, tsk: %ld, %d times ",
szCode, wParam, c++);
TextOut(hdc, 2, 75, szBuf, cch);
ReleaseDC(hwndMain, hdc);
return CallNextHookEx(myhookdata[CBT].hhook, nCode, wParam,
lParam);
}
/****************************************************************
WH_MOUSE hook procedure
****************************************************************/
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szBuf[128];
CHAR szMsg[16];
HDC hdc;
static int c = 0;
int cch;
if (nCode < 0) // do not process the message
return CallNextHookEx(myhookdata[MOUSE].hhook, nCode,
wParam, lParam);
// Call an application-defined function that converts a message
// constant to a string and copies it to a buffer.
LookUpTheMessage((PMSG) lParam, szMsg);
hdc = GetDC(hwndMain);
cch = wsprintf(szBuf,
"MOUSE - nCode: %d, msg: %s, x: %d, y: %d, %d times ",
nCode, szMsg, LOWORD(lParam), HIWORD(lParam), c++);
TextOut(hdc, 2, 95, szBuf, cch);
ReleaseDC(hwndMain, hdc);
return CallNextHookEx(myhookdata[MOUSE].hhook, nCode, wParam,
lParam);
}
/****************************************************************
WH_KEYBOARD hook procedure
****************************************************************/
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szBuf[128];
HDC hdc;
static int c = 0;
int cch;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[KEYBOARD].hhook, nCode,
wParam, lParam);
hdc = GetDC(hwndMain);
cch = wsprintf(szBuf, "KEYBOARD - nCode: %d, vk: %d, %d times ",
nCode, wParam, c++);
TextOut(hdc, 2, 115, szBuf, cch);
ReleaseDC(hwndMain, hdc);
return CallNextHookEx(myhookdata[KEYBOARD].hhook, nCode, wParam,
lParam);
}
/****************************************************************
WH_MSGFILTER hook procedure
****************************************************************/
LRESULT CALLBACK MessageProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szBuf[128];
CHAR szMsg[16];
CHAR szCode[32];
HDC hdc;
static int c = 0;
int cch;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[MSGFILTER].hhook, nCode,
wParam, lParam);
switch (nCode)
{
case MSGF_DIALOGBOX:
lstrcpy(szCode, "MSGF_DIALOGBOX");
break;
case MSGF_MENU:
lstrcpy(szCode, "MSGF_MENU");
break;
case MSGF_SCROLLBAR:
lstrcpy(szCode, "MSGF_SCROLLBAR");
break;
default:
wsprintf(szCode, "Unknown: %d", nCode);
break;
}
// Call an application-defined function that converts a message
// constant to a string and copies it to a buffer.
LookUpTheMessage((PMSG) lParam, szMsg);
hdc = GetDC(hwndMain);
cch = wsprintf(szBuf,
"MSGFILTER nCode: %s, msg: %s, %d times ",
szCode, szMsg, c++);
TextOut(hdc, 2, 135, szBuf, cch);
ReleaseDC(hwndMain, hdc);
return CallNextHookEx(myhookdata[MSGFILTER].hhook, nCode,
wParam, lParam);
}
未完待續。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992167/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 淺談API HOOK技術(一) (轉)APIHook
- Hook簡介 (轉)Hook
- SQLPlus命令使用指南(一) (轉)SQL
- 對於HOOK函式的一點認識 (轉)Hook函式
- xinetd使用指南(二)(轉)
- LILO使用指南(下)(轉)
- LILO使用指南(中)(轉)
- LILO使用指南(上)(轉)
- 我的Hook學習筆記 (轉)Hook筆記
- 淺談API HOOK技術(二) (轉)APIHook
- Git submodule使用指南(一)Git
- Hook技術之Hook ActivityHook
- 如何實現一個Interval HookHook
- Portage使用者使用指南(轉)
- Linux中mount使用指南(轉)Linux
- MPlayer安裝和使用指南(轉)
- hook!Hook
- RecyclerView使用指南(一)—— 基本使用View
- GnuPG-GNU的PGP使用指南(轉)
- Linux初學者Patch使用指南(轉)Linux
- 寫一個react hook:useLoadingReactHook
- 利用HOOK攔截封包原理 (轉自it人部落)Hook
- VB.net中HOOK的應用(二) (轉)Hook
- hook初識之inline hookHookinline
- IAT HookHook
- exit hookHook
- react hookReactHook
- Hook原理Hook
- hook zwcreateprocessexHook
- Javascript HookJavaScriptHook
- MySQL DBA備份工具Xtrabackup使用指南(轉)MySql
- Instruments使用指南(一)--- 簡介
- Hook踩坑記:React Hook react-unity-webglHookReactUnityWeb
- Netfilter 是如何工作的(一):HOOK點FilterHook
- 對於HOOK函式的一點認識Hook函式
- GCC 使用指南及gcc最佳編譯引數(轉)GC編譯
- HOOK API入門之Hook自己程式的MessageBoxWHookAPI
- 以pytorch的forward hook為例探究hook機制PyTorchForwardHook