想学钩子,搜了点资料不全,想找本书看看。
请帮助。
先谢谢。

解决方案 »

  1.   

    利用键盘钩子在Windows平台下捕获键盘动作 
    --------------------------------------------------------------------------------
     
      一、引言 
    我们可以在应用程序中毫不费力的捕获在本程序窗口上所进行的键盘操作,但如果我们想要将此程序作成一个监控程序,捕获在Windows平台下任意窗口上的键盘操作,就需要借助于全局钩子来实现了。 
    二、系统钩子和DLL 
    钩子的本质是一段用以处理系统消息的程序,通过系统调用,将其挂入系统。钩子的种类有很多,每种钩子可以截获并处理相应的消息,每当特定的消息发出,在到达目的窗口之前,钩子程序先行截获该消息、得到对此消息的控制权。此时在钩子函数中就可以对截获的消息进行加工处理,甚至可以强制结束消息的传递。 
    在本程序中我们需要捕获在任意窗口上的键盘输入,这就需要采用全局钩子以便拦截整个系统的消息,而全局钩子函数必须以DLL(动态连接库)为载体进行封装,VC6中有三种形式的MFC DLL可供选择,即Regular statically linked to MFC DLL(标准静态链接MFC DLL)、Regular using the shared MFC DLL(标准动态链接MFC DLL)以及Extension MFC DLL(扩展MFC DLL)。 在本程序中为方便起见采用了标准静态连接MFC DLL。 
    三、键盘钩子程序示例 
    本示例程序用到全局钩子函数,程序分两部分:可执行程序KeyHook和动态连接库LaunchDLL。 
    1、首先编制MFC扩展动态连接库LaunchDLL.dll: 
    (1)选择MFC AppWizard(DLL)创建项目LaunchDLL;在接下来的选项中选择Regular statically linked to MFC DLL(标准静态链接MFC DLL)。 
    (2)在LaunchDLL.h中添加宏定义和待导出函数的声明: 
    #define DllExport __declspec(dllexport) 
    …… 
    DllExport void WINAPI InstallLaunchEv(); 
    …… 
    class CLaunchDLLApp : public CWinApp 

    public: 
    CLaunchDLLApp(); 
     
    //{{AFX_VIRTUAL(CLaunchDLLApp) 
    //}}AFX_VIRTUAL 
     
    //{{AFX_MSG(CLaunchDLLApp) 
    // NOTE - the ClassWizard will add and remove member functions here. 
    // DO NOT EDIT what you see in these blocks of generated code ! 
    //}}AFX_MSG 
    DECLARE_MESSAGE_MAP() 
    }; 
    (3)在LaunchDLL.cpp中添加全局变量Hook和全局函数LauncherHook、SaveLog: 
    HHOOK Hook; 
    LRESULT CALLBACK LauncherHook(int nCode,WPARAM wParam,LPARAM lParam); 
    void SaveLog(char* c); 
    (4)完成以上提到的这几个函数的实现部分: 
    …… 
    CLaunchDLLApp theApp; 
    …… 
    DllExport void WINAPI InstallLaunchEv() 

    Hook=(HHOOK)SetWindowsHookEx(WH_KEYBOARD, 
    (HOOKPROC)LauncherHook, 
    theApp.m_hInstance, 
    0); 

    在此我们实现了Windows的系统钩子的安装,首先要调用SDK中的API函数SetWindowsHookEx来安装这个钩子函数,其原型是: 
    HHOOK SetWindowsHookEx(int idHook, 
    HOOKPROC lpfn, 
    HINSTANCE hMod, 
    DWORD dwThreadId); 
    其中,第一个参数指定钩子的类型,常用的有WH_MOUSE、WH_KEYBOARD、WH_GETMESSAGE等,在此我们只关心键盘操作所以设定为WH_KEYBOARD;第二个参数标识钩子函数的入口地址,当钩子钩到任何消息后便调用这个函数,即当不管系统的哪个窗口有键盘输入马上会引起LauncherHook的动作;第三个参数是钩子函数所在模块的句柄,我们可以很简单的设定其为本应用程序的实例句柄;最后一个参数是钩子相关函数的ID用以指定想让钩子去钩哪个线程,为0时则拦截整个系统的消息,在本程序中钩子需要为全局钩子,故设定为0。 
    …… 
    LRESULT CALLBACK LauncherHook(int nCode,WPARAM wParam,LPARAM lParam) 

    LRESULT Result=CallNextHookEx(Hook,nCode,wParam,lParam); 
    if(nCode==HC_ACTION) 

    if(lParam & 0x80000000) 

    char c[1]; 
    c[0]=wParam; 
    SaveLog(c); 


    return Result; 

    虽然调用CallNextHookEx()是可选的,但调用此函数的习惯是很值得推荐的;否则的话,其他安装了钩子的应用程序将不会接收到钩子的通知而且还有可能产生不正确的结果,所以我们应尽量调用该函数除非绝对需要阻止其他程序获取通知。 
    …… 
    void SaveLog(char* c) 

    CTime tm=CTime::GetCurrentTime(); 
    CString name; 
    name.Format("c:\\Key_%d_%d.log",tm.GetMonth(),tm.GetDay()); 
    CFile file; 
    if(!file.Open(name,CFile::modeReadWrite)) 

    file.Open(name,CFile::modeCreate|CFile::modeReadWrite); 

    file.SeekToEnd(); 
    file.Write(c,1); 
    file.Close(); 

    当有键弹起的时候就通过此函数将刚弹起的键保存到记录文件中从而实现对键盘进行监控记录的目的。 
    编译完成便可得到运行时所需的键盘钩子的动态连接库LaunchDLL.dll和进行静态链接时用到的LaunchDLL.lib。 
    2、下面开始编写调用此动态连接库的主程序,并实现最后的集成: 
    (1)用MFC的AppWizard(EXE)创建项目KeyHook; 
    (2)选择单文档,其余几步可均为确省; 
    (3)把LaunchDLL.h和LaunchDLL.lib复制到KeyHook工程目录中,LaunchDLL.dll复制到Debug目录下。 
    (4)链接DLL库,即在"Project","Settings…"的"Link"属性页内,在"Object/librarymodules:"中填入"LaunchDLL.lib"。再通过"Project","Add To Project","Files…"将LaunchDLL.h添加到工程中来,最后在视类的源文件KeyHook.cpp中加入对其的引用: 
    #include "LaunchDLL.h" 
    这样我们就可以象使用本工程内的 函数一样使用动态连接库LaunchDLL.dll中的所有导出函数了。 
    (5)在视类中添加虚函数OnInitialUpdate(),并添加代码完成对键盘钩子的安装: 
    …… 
    InstallLaunchEv(); 
    …… 
    (6)到此为止其实已经完成了所有的功能,但作为一个后台监控软件,运行时并不希望有界面,可以在应用程序类CkeyHookApp的InitInstance()函数中将m_pMainWnd->ShowWindow(SW_SHOW);改为m_pMainWnd->ShowWindow(SW_HIDE);即可。 
    四、运行与检测 
    编译运行程序,运行起来之后并无什么现象,但通过Alt+Ctrl+Del在关闭程序对话框内可以找到我们刚编写完毕的程序"KeyHook",随便在什么程序中通过键盘输入字符,然后打开记录文件,我们会发现:通过键盘钩子,我们刚才输入的字符都被记录到记录文件中了。 
    小结:系统钩子具有相当强大的功能,通过这种技术可以对几乎所有的Windows系统消息进行拦截、监视、处理。这种技术广泛应用于各种自动监控系统中。 
      

  2.   

    http://www.jjhou.com/win95-a-developers-guide.pdf
      

  3.   

    这是我毕设时找的一些文章,不知道对你有没有帮助Hook使用指南1.Hookshook指出了系统消息处理机制。利用hook,可以在应用程序中安装子程序监视系统和进程之间的消息传递,这个监视过程是在消息到达目的窗口过程之前。
    下面简述hook,并且解释在Win32系统下,如何使用hook编程。2.About Hookshook将使程序效率降低,因为它们增加了系统必须处理的消息总数。你应该在需要时才使用,并及时删除它。我将以下面的主题描述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 HooksWH_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 HookWH_JOURNALPLAYBACK Hook使应用程序可以插入消息到系统消息队列。可以使用这个hook回放通过使用WH_JOURNALRECORD hook记录下来的连续的鼠标和键盘事件。只要WH_JOURNALPLAYBACK hook已经安装,正常的鼠标和键盘事件就是无效的。WH_JOURNALPLAYBACK hook是全局hook,它不能象线程特定hook一样使用。WH_JOURNALPLAYBACK hook返回超时值,这个值告诉系统在处理来自回放hook当前消息之前需要等待多长时间(毫秒)。这就使hook可以控制实时事件的回放。WH_JOURNALRECORD HookWH_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 HookWH_KEYBOARD_LL Hook监视输入到线程消息队列中的键盘消息。WH_MOUSE HookWH_MOUSE Hook监视从GetMessage or PeekMessage function返回的鼠标消息。使用这个hook监视输入到消息队列中的鼠标消息。WH_MOUSE_LL HookWH_MOUSE_LL Hook监视输入到线程消息队列中的鼠标消息。WH_MSGFILTER and WH_SYSMSGFILTER HooksWH_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 HooksInstalling 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过程将在应用程序主窗口客户区写出事件信息。原代码如下:
      

  4.   

    jjhou 网站上有两本关于windows系统程序设计的书
    对hook技术有比较详细的介绍。
      

  5.   

    Monitoring System Events
    The following example uses a variety of thread-specific hook procedures to monitor the system for events affecting a thread. It demonstrates how to process events for the following types of hook procedures: WH_CALLWNDPROC
    WH_CBT
    WH_DEBUG
    WH_GETMESSAGE
    WH_KEYBOARD
    WH_MOUSE
    WH_MSGFILTERThe user can install and remove a hook procedure by using the menu. When a hook procedure is installed and an event that is monitored by the procedure occurs, the procedure writes information about the event to the client area of the application's main window. #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  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); 

     
      

  6.   

    vck有个键盘钩子及其它的例子。你可以看一看。http://www.vckbase.com/code/listcode.asp?mclsid=13&sclsid=1309