hook使用指南(一) (轉)

worldblog發表於2007-12-12
hook使用指南(一) (轉)[@more@]

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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章