hook使用指南(一)

类别:VC语言 点击:0 评论:0 推荐:

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:\\windows\\sysmsg.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);
}

未完待续。

本文地址:http://com.8s8s.com/it/it2694.htm