ITPub博客

首页 > 应用开发 > IT综合 > hook使用指南(一) (转)

hook使用指南(一) (转)

原创 IT综合 作者:worldblog 时间:2007-12-12 14:38:28 0 删除 编辑
hook使用指南(一) (转)[@more@]

1.Hooks

 hook指出了系统消息处理机制。利用hook,可以在应用程序安装子程序监视系统和进程之间的消息传递,这个监视过程是在消息到达目的窗口过程之前。
 下面简述hook,并且解释在win32系统下,如何使用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过程,使用SetwindowsHookEx函数来把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_Cbt Hook

   在以下事件之前,系统都会调用WH_CBT Hook过程,这些事件包括:激活,建立,销毁,最小化,最大化,移动,改变尺寸等窗口事件;完成系统指令;来自系统消息队列中的移动鼠标,键盘事件;设置输入焦点事件;同步系统消息队列事件。hook过程的返回值确定系统是否允许或者防止这些操作中的一个。

 WH_DEbug 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_shell 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"); file://loading DLL
 hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc"); file://get address
 hhookSysMsg = SetWindowsHookEx(WH_SYSMSGFILTER,hkprcSysMsg,hinstDLL,0); file://install 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 WINapi 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
  // identifiers 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 (LOword(wParam))
  {
  // The user selected 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_SYSCOMMAND:
  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/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
  • 博文量
    6241
  • 访问量
    2405053