Windows 反消息钩子(1)

       消息钩子在Windows编程中有着非常广泛的应用,它可以任意拦截Windows系统,这个以消息为驱动的系统中的绝大多数消息类型。一方面这给编程者带来了巨大的灵活性,另一方面也埋下了巨大隐患,大多数窃密软件都使用这种方法。此篇文章给您提供一种钩子的反拦截方法,希望对您有所帮助。文章中使用了API钩子,您之前必须对此技术有一定了解。
 
          为求完整,文章分为两部分,第一部分为消息钩子的使用,熟悉此技术的读者可以直接跳过此节。第二部分为消息钩子的反拦截。  

一、消息钩子的使用

      消息钩子分为本地(local)和远程(remote)两种(两个local   system-wide   hook例外,无关主题,不多说了)。local类型的钩子函数只能拦截本进程的消息。能够拦截本进程以外的消息的钩子,都是remote类型。remote类型的钩子必须放在DLL里面。下面以remote类型为例,通过安装键盘钩子介绍其使用。
 

     1、首先建立DLL,在头文件中添加如下代码。  

 #ifdef   KM_EXPORTS
  #define   KM_API   __declspec(dllexport)
  #else
  #define   KM_API   __declspec(dllimport)
  #endif  

  KM_API   BOOL   HookStart();//安装钩子
  KM_API   BOOL   HookStop();//卸载钩子   

     2、在.cpp文件中添加代码  

   

  #pragma   data_seg("Shared")
  HHOOK   g_hhookKey=NULL;
  #pragma   data_seg()
  #pragma   comment(linker,"/SECTION:Shared,RWS")   

    g_hhookKey为键盘钩子的句柄,为确保此数值在所有实例中均保持不变,将其存放于此模块所有实例的共享数据区,若在exe程序中按此格式添加一int   变量   appNum,在程序启动时appNum++,则可以通过访问此变量的数值,确定有多少个exe的实例,当然这种方法也可以替代同步对象用于只启动一个实例。  

  HINSTANCE   g_hinstDll=NULL;         //添加全局变量用于记录此DLL模块的句柄
  BOOL   APIENTRY   DllMain(   HANDLE   hModule,     DWORD     ul_reason_for_call,     LPVOID   lpReserved   )
  {
      switch   (ul_reason_for_call)
      {
          case   DLL_PROCESS_ATTACH:
          g_hinstDll=(HINSTANCE)hModule;//在DLL加载时对全局变量赋值
          ..................
      }
  }  

  LRESULT   KeyHookProc(int   nCode,WPARAM   wParam,LPARAM   lParam)//键盘钩子的过滤函数
  {
      .....................
      return::CallNextHookEx(g_hhookKey,nCode,wParam,lParam);//*****请留意此行代码*****
  }  

  BOOL   HookStart()//安装钩子
  {
      g_hhookKey=::SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyHookProc,g_hinstDll,
                                ::GetWindowThreadProcessId(::FindWindow(NULL,"被监视的窗口的标题"),NULL)   );
      return   (g_hhookKey!=NULL);
  }  

  BOOL   HookStop()//卸载钩子
  {
      BOOL   ret;
      if(g_hhookKey!=NULL)
      ret=::UnhookWindowsHookEx(g_hhookKey);
      g_hhookKey=NULL;
      return   ret;
  }   

   只要在exe程序中调用HookStart函数,就可以监视某一窗口的键盘消息,若此窗口为QQ的密码框,你的密码就泄漏了。  
   
         

二、消息钩子的反拦截

    请留意前面带*号注释的代码,其中传入了钩子的句柄g_hhookKey,只要使用API钩子将CallNextHookEx函数替换,并在替换函数中将其卸载,消息钩子就完蛋了。同时,还要保证本进程安装的钩子不被卸载,其中既可能有local类型的还可能有remote类型的。不要以为自己没有在程序中安装钩子,程序中就一定没有安装钩子,在MFC4版本中,MFC会自己装一个local类型的钩子,MFC7版本中好像没了。好了,下面介绍其实现。
 

    1、建立DLL,在头文件中添加如下代码。  

  #ifdef   HOOKFORBID_EXPORTS
  #define   HOOKFORBID_API   __declspec(dllexport)
  #else
  #define   HOOKFORBID_API   __declspec(dllimport)
  #endif  

  HOOKFORBID_API   int   fnHookForbid(void);//在exe程序中调用此函数,使DLL加载
  HOOKFORBID_API   bool   AddHhook(HHOOK   Hhook);//若exe中安装remote类型消息钩子,将其句柄添加
  HOOKFORBID_API   bool   DelHhook(HHOOK   Hhook);//在exe中卸载remote类型消息钩子时,删除其句柄        

    2、在.cpp文件中添加代码

  CArray<HHOOK,HHOOK>   array;//用于记录本进程安装的钩子的句柄
  //////////////////////////////////////////////////////////////////////////////
  int   fnHookForbid(void)
  {
      return   1;
  }  

  bool   AddHhook(HHOOK   Hhook)
  {
      array.Add(Hhook);
      return   true;
  }  

  bool   DelHhook(HHOOK   Hhook)
  {
      bool   ret=false;
      for(int   i=0;i<array.GetSize();i++)
      {
          if(array.GetAt(i)==Hhook)
          {
              array.RemoveAt(i);
              ret=true;
              break;
          }
      }
      return   ret;
  }
  //////////////////////////////////////////////////////////////////////////////   

下面的代码用于API替换,其中用到了CAPIHook   类,《Windows   核心编程》(Jeffrey   Richter著)一书中有源代码。使用其它开发包也可以实现此功能。  
   

  //////////////////////////////////////////////////////////////////////////////
  typedef   HHOOK   (WINAPI   *PFNSETWINDOWSHOOKEX)(
          int   idHook,
          HOOKPROC   lpfn,
          HINSTANCE   hMod,
          DWORD   dwThreadId
  );  

  typedef   LRESULT     (WINAPI   *PFNCALLNEXTHOOKEX)(
          HHOOK   hhk,
          int   nCode,
          WPARAM   wParam,
          LPARAM   lParam
  );
  //////////////////////////////////////////////////////////////////////////////  

  extern   CAPIHook   g_SetWindowsHookExA;
  extern   CAPIHook   g_SetWindowsHookExW;
  extern   CAPIHook   g_CallNextHookEx;  

  //////////////////////////////////////////////////////////////////////////////  

  //此函数用于替换SetWindowsHookEx函数的ASCII版本SetWindowsHookExA
  HHOOK   WINAPI   Hook_SetWindowsHookExA(   int   idHook,     HOOKPROC   lpfn,     HINSTANCE   hMod,     DWORD   dwThreadId   )
  {
      HHOOK   nResult   =0;  

      nResult   =   ((PFNSETWINDOWSHOOKEX)(PROC)   g_SetWindowsHookExA)(   idHook,   lpfn,     hMod,   dwThreadId     );  

      //若在本进程中安装了local类型钩子,记录其句柄
      if(hMod==NULL)
          array.Add(nResult);  

      return(nResult);
  }  

  //此函数用于替换SetWindowsHookEx函数的UNICODE版本SetWindowsHookExW
  HHOOK   WINAPI   Hook_SetWindowsHookExW(   int   idHook,   HOOKPROC   lpfn,     HINSTANCE   hMod,   DWORD   dwThreadId     )
  {
      HHOOK   nResult   =0;  

      nResult   =   ((PFNSETWINDOWSHOOKEX)(PROC)   g_SetWindowsHookExW)(   idHook,   lpfn,     hMod,     dwThreadId     );  

      //若在本进程中安装了local类型钩子,记录其句柄
      if(hMod==NULL)
          array.Add(nResult);  

      return(nResult);
  }  

  //此函数用于替换CallNextHookEx函数,此函数只有一个版本
  LRESULT     WINAPI   Hook_CallNextHookEx(   HHOOK   hhk,   int   nCode,     WPARAM   wParam,   LPARAM   lParam)
  {
      LRESULT     nResult   =0;  

      nResult   =   ((PFNCALLNEXTHOOKEX)(PROC)   g_CallNextHookEx)(   hhk,   nCode,   wParam,     lParam   );  

      //在数组中查找句柄,若找不到,将其卸载
      bool   bfind=false;
      for(int   i=0;i<array.GetSize();i++)
      {
          if(array.GetAt(i)==hhk)
          {
              bfind=true;
              break;
          }
      }
      if(!bfind)
      {
          UnhookWindowsHookEx(     hhk     );
      }
      return   (nResult);
  }  

  //////////////////////////////////////////////////////////////////////////////  

  //使用CAPIHook   类对函数进行替换
  CAPIHook   g_SetWindowsHookExA("User32.dll",   "SetWindowsHookExA",
        (PROC)   Hook_SetWindowsHookExA,   true);  

  CAPIHook   g_SetWindowsHookExW("User32.dll",   "SetWindowsHookExW",
        (PROC)   Hook_SetWindowsHookExW,   true);  

  CAPIHook   g_CallNextHookEx("User32.dll",   "CallNextHookEx",
        (PROC)   Hook_CallNextHookEx,   true);   

      到了这里,所有工作都完成了,只要在exe程序中调用fnHookForbid函数,并在安装remote类型钩子时调用AddHhook函数记录其句柄,卸载时调用DelHhook函数删除句柄就万事ok了。  
       一点不足:这种方法可以有效屏蔽消息钩子对信息安全的威胁。可以使Spy++失效。然而,由于是在CallNextHookEx函数中卸载钩子,因此,钩子函数总是会被调用一次。还有一件非常费解的事,金山词霸总能够正常取词,不知道词霸是怎么做到的。  
      本人并非专业程序员,   若此方法存在任何错误或隐患,敬请批评指出,请不要在帖子上损我。  

     呵呵!假如我的钩子是这么用的:  
   

  FUN_SETWINDOWSHOOKA   *pFn   =   (FUN_SETWINDOWSHOOKA   *)
  ::GetProcAddress(::GetModuleHandle("kernel32.dll"),   "SetWindowsHookA");  

  pFn(...);   

  你的方法还是屏蔽不了哦!不信试验一下!记得给分哦!(该法为:“反反API钩子大法”)  
   
  当然!同理也可以绕过API钩子!有同样兴趣的人记得发消息给我哦!  
   
  首先声明一下:我拦截的是消息钩子,如果安装钩子时考虑到了反卸载则不在讨论之内。  
  其次:上述方法不可靠,对CAPIHook类进行更改,可以实时对地址进行替换,就象消息钩子被调用次序的不确定性一样,到时候没法确定那个替换函数被调用了。

时间: 2024-11-16 20:32:24

Windows 反消息钩子(1)的相关文章

Windows 反消息钩子(2)

     Windows消息钩子一般都很熟悉了.它的用处很多,耳熟能详的就有--利用键盘钩子获取目标进程的键盘输入,从而获得各类密码以达到不可告人的目的.朋友想让他的软件不被别人的全局钩子监视,有没有办法实现呢?答案是肯定的,不过缺陷也是有的.   一.全局钩子如何注入别的进程       消息钩子是由Win32子系统提供,其核心部分通过NtUserSetWindowsHookEx为用户提供了设置消息钩子的系统服务,用户通过它注册全局钩子.当系统获取某些事件,比如用户按键,键盘driver将扫描

Windows Mobile 消息钩子(1)

    在Windows中,设置键盘钩子很多人都做过,但是在windows Mobile系统中并没有直接的函数支持.但是我们可以通过使用undocument api来实现. 一.定义参数 #define WH_KEYBOARD_LL           20  #define HC_ACTION        0  typedef LRESULT(CALLBACK* HOOKPROC)(int code, WPARAM wParam, LPARAM lParam);  typedef HHOOK

Windows Mobile 消息钩子(2)

Windows Mobile 触摸屏(Touch Panel)消息截获(pwinuser.h) ,在pwinuser.h的头文件里,有hook的API. 一.实现代码 #ifndef _PRIV_WINUSER_ #define _PRIV_WINUSER_ #ifdef __cplusplus extern "C" { #endif #include <keybd.h> // Non-Standard CE internal messages. #define WM_QM

Windows窗口消息实例详解_C 语言

本文实例总结了Windows窗口消息.分享给大家供大家参考.具体如下: 复制代码 代码如下: //////////////////////////////////////////////////////////////////////////    #include "AFXPRIV.H"//消息值的定义来源    #include "Dde.h"//DDE消息值的定义来源    #include "CPL.H"//控制面板消息值的定义来源   

消息钩子使用教程

基本概念钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的.当消息到达后,在目标窗口处理函数之前处理它.钩子机制允许应用程序截获处理window消息或特定事件.钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统.每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权.这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束

【VB.NET】也谈跨进程消息钩子

写给VB.NET程序员^_^ 老生常谈了:子类化. 我们都知道在VB6里面可以用API函数来进行子类化,以处理自身的窗体过程:如果跨进程,这就麻烦了,由于我们的函数在我们的进程中(废话),而目标进程的窗口的消息处理函数在目标进程(还是废话),所以只能想办法把我们的代码放到对方进程中去执行--并且要告知我们的进程得到了什么消息.恐怕写汇编就有点吓人了,于是大家都写DLL,其原理就是把回调函数放到一个DLL里面注入到对方进程,DLL去修改目标窗口的默认处理函数--把消息发送给我们. 当然也有"另类&

使用C#编程将websphere MQ 5.3 windows客户端消息发送到linux服务器端

linux服务器|web|window|编程|客户端 首先是要安装MQ的客户端和服务器端,这是理所当然的.客户端可以到IBM网站上下载是免费的.服务器端你有盗版那当然是没有问题了,如果没有只能向IBM购买.这我也帮不上忙了. 安装完了你还需要安装

C#+低级Windows API钩子拦截键盘输入

window 一. 简介 猫和婴儿有很多共同之处.他们都喜欢吃家中养植的植物,都非常讨厌关门.他们也都爱玩弄你的键盘,结果是,你正发送给你的老板的电子邮件可能是以半截句子发送出去的,你的Excel帐户也被加入了一些乱七八糟的内容,并且你还没有注意到,当打开Windows资源管理器时,若干文件已经被移到了回收站! 其解决方案是,开发一个应用程序实现如下功能:只要键盘处于"威胁状态"你就可以进行切换,并确保任何键盘输入活动都不会造成危害.本文想展示如何使用一种低级Windows API钩子

vb中使用Windows消息控制Winamp

第一部分:得到Winamp的窗口 Winamp是一个32位的Windows应用程序.也就是说,我们可以使用32位的Windows编程的一些基础技术来实现控制Winamp,即使用Windows的消息系统.在你给Winamp发送消息之前,你必须得到Winamp窗口的句柄.这里有个方法,使用外部应用程序(例如你自己编写的VB应用)就可以达到要求. Public Declare Function FindWindow Lib "user32" Alias "FindWindowA&q