宝峰科技

 找回密码
 注册

QQ登录

只需一步,快速开始

智能终端设备维修查询系统注册会员邮箱认证须知!
查看: 1508|回复: 0

如何编写Windows消息钩子

[复制链接]
  • TA的每日心情
    奋斗
    2020-6-5 22:18
  • 签到天数: 22 天

    [LV.4]偶尔看看III

    潇潇 发表于 2009-10-29 20:04:11 | 显示全部楼层 |阅读模式

    欢迎您注册加入!这里有您将更精采!

    您需要 登录 才可以下载或查看,没有账号?注册

    x
    Windows钩子是使用DLL编写的。在高层,钩子由需要监视其他应用程序或系统活动的应用程序使用;在低层,钩子是windows消息传递中的点,函数根据这个路径被注入或附加,以过滤某些类型的消息,使之达到目的地。一旦捕获了这些消息,就可以对其进行修改、记录或丢弃。函数本身称为过滤器。这些过滤器是按照正在过滤的事件的类型进行分类的。当一个过滤函数被附加到一个钩子时,称为“sethook”。肯定有些时候设置了同一类型的多个钩子。为了处理这种情况,Windows记录着过滤函数链的情况。最近添加的过滤函数是链中的第一个函数,因此,它最先有机会过滤任何消息通信量。然后,这个函数执行它的工作并把消息发送到链中的下个钩子过程,后者完全放弃该消息。下面先列出Wondows钩子的类型:
    WH_CALLWNDPROC 在消息被发送到其目的窗口例程之前监视所有的Windows消息
    WH_CALLWNDPROCRET 监视已经被目的Windows例程处理后的消息
    WH_CBT 监视Computer-Base-Training应用程序所用的消息
    WH_DEBUG 辅助调试其他钩子函数
    WH_GETMESSAGE 监视投递到消息队列中的Windows消息
    WH_JOURNALPLAYBACK 投递以前由

    WH_JOURNALRECORD异常分支例程处理的消息
    WH_JOURNALRECORD 记录投递到系统消息队列的输入消息
    WH_KEYBOARD 监视键盘的活动
    WH_KEYBOARD_LL 监视低层键盘输入事件(只适用于Windows 2000/XP)
    WH_MOUSE 监视鼠标消息
    WH_MOUSE_LL 监视低层鼠标输入事件(只适用于Windows 2000/XP)
    WH_MSGFILTER 监视作为对话框、消息框、菜单或滚动条中输入事件的结果而生成的消息
    WH_SHELL 接受对外壳应用程序有意义的事件通知
    WH_SYSMSGFILTER 类似于WH_MSGFILTER,监视作为对话框、消息框、菜单或滚动条中输入事件的结果而生成的消息。然而WH_SYSMSGFILTER为所有活动的应用程序监视这些消息
    现在要来讲解 SetWindowsHookEx函数
    为了设置一个钩子,必须调用SetWindowsHookEx函数,原型如下:
    HHOOK
    SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId)
    第一个参数 IdHook代表一个常量,该常量标识了正要设置的钩子的类型。

    第二个参数 lpfn 指向一个函数的HOOKPROC类型的指针。
    第三个参数hMod包含过滤函数的模块的HINSTANCE 。
    第四个参数为线程ID。返回值是一个钩子的句柄,如果函数没有成功则返回值为NULL,需要调用GetLastError函数,以确定失败的原因。
    UnhookWindowsHookEx函数
    如果应用程序设置了windows钩子,那么在该程序终止前也需要由它从钩子链中去掉一个钩子。这是通过UnhookWindowsHookEx函数来实现。原型如下
    BOOL UnhookWindowsHookEx(HHOOK hHook)
    CallNextHook函数
    当为给定钩子类型设置了一个过滤函数后,该过滤函数放在钩子类型的过滤函数的链头。过滤函数完成其任务后,就可以通过CallNextHook函数调用链中
    下一个过滤函数。如果不想继续进行处理,例如编写了一个键盘钩子并且想放弃某次击键,就不要调用该函数。然而,如果简单地记录一个事件,并且想让消息
    继续沿其消息路径前进,应用程序则需要在处理完消息后调用CallNextHook函数,否则其他消息将得不到处理。如果这种类型的钩子没有其他过滤函数,Windows会把这个消息传递到适当的消息队列中。
    下面来举一个简单的例子来说明钩子的运用,我们来编写一个键盘钩子程序,在这个例子中所有按下“F1”键将要被捕捉,大家熟悉以后可以试着学习捕获消息队列中的windows消息,这对于编写辅助程序非常有用,当然有些消息是程序中自定义的,然而你仍然可以通过一写技巧来捕捉到其中的某些消息。这是后话。
    首先为键盘钩子创建将包含过滤函数的DLL,在项目工程中创建一个名为KeybdHook的MFC的常规DLL。打开KeybdHook.h文件,在CkeybdHookApp类声明之前加入一些声明:
    #define EXPORTED_DLL_FUNCTION _declspec(dllexport) _stdcall   //提供一种导出具有_stdcall调用机制的函数的简单方式
    LRESULT _stdcall KbdHookProc(int nCode, WPARAM wParam , LPARAM lParam); //实际的过滤函数
    在KeybdHook.cpp中声明一些全局变量如下:
    #pragma data_seg(".SHARDAT")
    static HWND
    ghWndMain = 0;
    static HHOOK
    ghKeyHook = NULL;
    #pragma data_seg()
    HIINSTANCE
    ghInstance = 0;
    HOOKPROC  glpfnHookProc = 0;
    好了,KbdHookProc函数的实现是这样的:
    LRESULT EXPORTED_DLL_FUNCTION KbdHookProc(int nCode, WPARAM wParam , LPARAM lParam)
    {
        BOOL bHandledKeyStroke = FALSE;
        if(((DWORD)lParam & 0x40000000) && (HC_ACTION == nCode))
        {
    switch(wParam)
    {
    case VK_F1:
               AfxMessageBox("捕捉到了 F1 按键!");
               bHandleKeyStroke = TRUE;
    break;
    default:
    break;
           }
         }
        return (bHandledKeystroke ? TRUE: ::CallNextHookEx(ghKeyHook,nCode,wParam,lParam));
    }
    nCode可能包含的值之一是HC_ACTION常量。实际上这个参数只能是两个值之一 :HC_ACTION 和 HC_NOREMOVE。 在这两种情况下,WPARAM 和 LPARAM变量将包含关于击键的信息。如果nCode小于0,该过滤函数不应该处理击键,而是该调用CallNextHookEx函数。
    接下来导出DLL函数。首先打开KeybdHook.h文件,声明一个用于安装或设置键盘钩子的函数:
    BOOL _stdcall InstallKeyBoardHook(HWND hWnd);
    实现如下:
    BOOL EXPORTED_DLL_FUNCTION InstallKeyBoardHook(HWND hWnd)
    {
       BOOL bSuccess = FALSE;
       if(!ghKeyHook)
       {
          ghWndMain
    = hWnd;
          glpfnHookProc
    = (HOOKPROC) KbdHookProc;
          bSuccess = (NULL!=(ghKeyHook = ::SetWindowsHookEx(WH_KEYBOARD,glpfnHookProc,ghInstance,NULL)));
        }
       return bSuccess;
    }
    还要导出一个函数来释放钩子:
    BOOL EXPORTED_DLL_FUNCTION DeInstallKeyboardHook()
    {
       if(ghKeyHook)
       {
    if (TRUE ==(0 != ::UnhookWindowsHookEx(ghKeyHook)))
    {
       ghKeyHook = NULL;
    }
       }
      return (NULL == ghKeyHook);
    }
    如果大家看一看由MFC生成的DLL的代码很容易看出来,DLL类是从CWinApp 类派生来的,并且实现了InitInstance成员函数,应该在这里提供DLL所需的初试化代码。
    使用CWinApp类的优势是可以像对其他任何CWinApp派生类那样进行DLL编程。例如,可以重载DLL的CWinApp::InitInstance函数,并提供全局初始化。虽然MFC提供了
    默认的DllMain实现,但一般还是建议用户在DLL的CWinApp派生类的InitInstance函数中自己进行初始化,在很多情况下是必须这么做的。
    BOOL CKeybdHookApp::InitInstance()
    {
       AFX_MANAGE_STATE(AfxGetStaticModuleState());
       ghInstance = AfxGetInstanceHandle();
       return TRUE;
    }
    int CKeybdHookApp::ExitInstance()
    {
       DeInstallKeyboardHook();
       return CWinApp::ExitInstance();
    }
    这样一个对键盘按键消息捕捉的钩子函数就全部建立好了。之所以用DLL是方便客户(指应用程序或其他DLL)导出调用。以后为了测试键盘钩子,可以创建一个基于对话框
    的应用程序KeybdHookClient。假定为单击OK按扭事件创建一个消息处理程序,在处理程序中调用DLL的InstallKeyboardHook导出函数:
    void CkeybdHookClientDlg::OnOK()
    {
       InstallKeyboardHook(GetSafeHwnd());
    }
    重载对话框OnCancel函数
    void CkeybdHookClientDlg::OnCancel()
    {
       DeInstallKeyboardHook();
       CDialog::OnCancel();
    }
    别忘记在KeybdClientDlg.cpp文件前加上 #include "KeybdHook.h"
    要测试这个钩子程序,可以找一个使用F1的程序即可。当你启动你的KeybdHookClient应用程序,再在其他的软件程序中按"F1"时,就会弹出一个消息框,系统告诉你捕捉了按键消息。

    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    免责声明

    本站中所有被研究的素材与信息全部来源于互联网,版权争议与本站无关。本站所发布的任何软件编程开发或软件的逆向分析文章、逆向分析视频、补丁、注册机和注册信息,仅限用于学习和研究软件安全的目的。全体用户必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。学习编程开发技术或逆向分析技术是为了更好的完善软件可能存在的不安全因素,提升软件安全意识。所以您如果喜欢某程序,请购买注册正版软件,获得正版优质服务!不得将上述内容私自传播、销售或者用于商业用途!否则,一切后果请用户自负!

    QQ|Archiver|手机版|小黑屋|联系我们|宝峰科技 ( 滇公网安备 53050202000040号 | 滇ICP备09007156号-2 )

    Copyright © 2001-2023 Discuz! Team. GMT+8, 2024-12-22 21:38 , File On Powered by Discuz! X3.49

    快速回复 返回顶部 返回列表