C++ Hook(钩子)编程,通过内联汇编,使类成员函数代替全局函数(静态函数)

来源:互联网 发布:怎样做淘宝客赚钱手机 编辑:程序博客网 时间:2024/06/05 20:41

编程语言:C/C++

编译环境:Visual Studio 2008

核心方法::通过内联汇编,构造类对象独享的函数(委托),完成了类成员函数到普通全局函数的转化,并在Windows Hook(钩子)编程中得到成功的实践。

关键字:C++,委托,内联汇编,Hook,成员函数

 

 

引文:

前段时间曾编写了一个自认为很完善的.NET平台上的Hook(钩子)动态链接库(DLL),并进一步完成了GUI界面,但是在部署时却发现的其局限性,很多用户都没有安装.NET平台,其平台的最小安装(.NET 2.0)也需要21M,如果使用NOMO(2.0)免安装发布的话也需要小10M(而且使用NOMO在自动运行和兼容性上也有待商榷)。

因此,我下定决心,准备彻底和托管代码决裂,回归C/C++,再次实现上述功能,然而真正编写时才发现,经典的C++果然不是盖的,昔日被C的各种调试不通过折磨的记忆还未消退,今日又在开始时陷入苦战,正如前人所说,C++这种强类型语言,喜欢在繁琐的符号和语法上做文章。如果处理不好这些,大概做不了大项目,还是去.NET或Java的快乐平台逍遥去吧~微微感慨,赶快进入正题。

 

正文:

本文的目的是研究类成员函数与普通函数之区别,以及不同调用方式之间的区别,进而通过内联汇编语句模仿特定的调用,从而完成通过普通函数指针调用类成员函数的功能。因此主要部分为研究和尝试的过程,如希望直接查看Hook编程的结果,可直接查看尾部代码。

使用过Windows Hook编程的同志们都知道,在程序中是通过如下语句来加载钩子,卸载钩子。

 

C/C++ Code:

[cpp] view plain copy
  1. HHOOK SetWindowsHookEx( //加载钩子  
  2.   int idHook,  
  3.     HOOKPROC lpfn,          //钩子函数的指针  
  4.     HINSTANCE hMod,  
  5.     DWORD dwThreadId  
  6. );  
  7. BOOL UnhookWindowsHookEx( //卸载钩子  
  8.   HHOOK hhk  
  9. );  
 

其中最重要的就是HOOKPROC lpfn这个函数指针,查看此函数的形式,为:


C/C++ Code:

 

[cpp] view plain copy
  1. LRESULT CALLBACK HookProcess( //钩子函数  
  2.     int nCode,  
  3.     WPARAM wParam,  
  4.     LPARAM lParam  
  5. );  
 

//其中CALLBACK 的定义为 #define CALLBACK    __stdcall

 

其中,值得注意的是,这个钩子函数需要是一个普通__stdcall调用的C函数,而在C++中可以理解为某个全局函数(非类成员函数,全局访问)或者是一个类的静态函数(static,全局访问)。

让我们再观察一个类成员函数和全局函数的区别,我建立了一个简单的演示代码,如下代码:

 

C/C++ Code:

[cpp] view plain copy
  1. #include <windows.h>  
  2.    
  3. LRESULT CALLBACK HookProcess1( // HookProcess1是一个全局函数  
  4.                              int nCode,  
  5.                              WPARAM wParam,  
  6.                             LPARAM lParam){ return NULL;}  
  7.    
  8. class WinHook  
  9. {  
  10. public:  
  11. int value; //定义一个成员变量,以便于测试访问  
  12. LRESULT CALLBACK HookProcess2(// HookProcess2是一个类的成员函数  
  13.                              int nCode,  
  14.                              WPARAM wParam, LPARAM lParam) {  
  15.         this->value++;        //检查成员变量的访问性  
  16.        return NULL;  
  17. }  
  18. };  
  19.    
  20. int main(){  
  21.      //定义一个函数指针HookProcess,它可以成功作为参数传递给SetWindowsHookEx  
  22.      LRESULT (CALLBACK * HookProcess)  
  23.                     (int nCode, WPARAM wParam, LPARAM lParam);  
  24.      //试图将HookProcess指向HookProcess1  
  25.      HookProcess = HookProcess1; //赋值成功,这个指针能够指向全局函数  
  26.      HookProcess (0,0,0);//尝试调用之.  
  27.      //试图将HookProcess指向HookProcess2  
  28.      WinHook *myHook = new WinHook();  
  29.      HookProcess = myHook->HookProcess2; //编译失败,提示类型不能转化  
  30.                                                                 //此句将在之后修改  
  31.      HookProcess (0,0,0);//尝试调用之.  
  32.      return 0;  
  33. }  
 

 

 

查看错误代码,终于发现类的成员函数和普通的全局函数是不一样的,


// error C2440:

//“=”: 无法从“LRESULT (__stdcall WinHook::* )(int,WPARAM,LPARAM)”转换为“LRESULT (__stdcall *)(int,WPARAM,LPARAM)”


关键问题就在于“WinHook::”的区别,可以看到,无论如何,一个类的成员函数(非静态)是不能与普通的C全局函数转化的。这点在后面再详细的说明。

然而,当我们使用C++编程的时候,往往不希望使用全局函数;如果使用类的静态函数,那么一个类只能实现一个钩子,且不能利用C++中类的继承,多态等特性,从实质上沦落为普通C编程。

在网上查找了很多方法,发现可以通过内联汇编语句强制将指针转化,如下:


C/C++ Code:

[cpp] view plain copy
  1. //修改上述main中代码,将类成员函数指针强制转化为一般函数指针  
  2. WinHook *myHook = new WinHook();  
  3. //HookProcess = myHook->HookProcess2;  
  4. __asm  //NEW: 内联汇编语句  
  5. {  
  6.      push eax  
  7.      lea eax, WinHook::HookProcess2  
  8.      mov HookProcess, eax  
  9.      pop eax  
  10. }  
  11.        HookProcess (0,0,0);//尝试调用之.  
 

 

然而在使用这种方法时,却发现了问题,即在底层调用WinHook 的HookProcess2中,其中的this指针为0,因此所有this相关的操作均不可行(即不能访问本对象的其他成员)。此外,在HookProcess2结束后,底层也发现了堆栈不平衡而导致的错误。

 

继续阅读网上的文章,如

(成员函数指针与高性能的C++委托)

http://www.cnblogs.com/jans2002/archive/2006/10/13/528160.html

(普通函数指针变量可以保存成员函数地址吗?)

http://topic.csdn.net/u/20100905/21/0bfacc26-cdd5-463b-8724-98c626e2b3dc.html

(使非MFC窗口程序的窗口回调过程成为C++类的成员函数)

http://www.systhinker.com/html/90/n-1990.html

等等

 

我终于理解的类成员函数与普通函数的区别,那就是this指针,当一个类的成员函数被调用时,如:


C/C++ Code:

[cpp] view plain copy
  1. WinHook *myHook = new WinHook();  
  2. HookProcess = myHook->HookProcess2(…);  
 

 

此时,当HookProcess2的参数被传送之后,myHook的地址也被传送在CPU寄存器中(或堆栈中,这要看传调用方式的不同,在之后说明),并在之后在HookProcess2函数中赋值给this,使得类成员函数能够知道调用的是哪个类的对象。

为了测试这一点,我们可以在强制转化了HookProcess2指针之后,在HookProcess2中修复this指针,看函数的this功能是否正常。如下代码:


C/C++ Code:

[cpp] view plain copy
  1. class WinHook //修改WinHook类的函数HookProcess2  
  2. {  
  3. public:  
  4. int value; //定义一个成员变量,以便于测试访问  
  5. LRESULT CALLBACK HookProcess2(// HookProcess2是一个类的成员函数  
  6.                              int nCode,  
  7.                              WPARAM wParam, LPARAM lParam) {  
  8.   //假设主函数中的myHook指针指向0x003d3450,修复this指针  
  9.               __asm  //内联汇编语句  
  10. {  
  11.       push eax                   //保护eax  
  12.       mov eax, 0x003d3450     
  13.       mov this, eax              //设置本类的this指针(__asm不检查访问性)  
  14.       pop eax                    //还原eax  
  15. }  
  16.  //此时查看this指针,就能够发现this正常工作  
  17.   this->value++;  
  18.        return NULL;  
  19. }  
  20. };  
 

 

注:虽然this指针能够运行成功,但是函数结束会产生如下错误:

C++ Hook(钩子)编程-编译错误提示

 

这是由于__stdcall的this传送方式是堆栈,强制访问HookProcess2却未将this压栈会导致堆栈不平衡。因此,将CALLBACK这个修饰符注销掉,即:


C/C++ Code:

[cpp] view plain copy
  1. class WinHook //进一步修改WinHook类的函数HookProcess2  
  2. {  
  3. public:  
  4. int value; //定义一个成员变量,以便于测试访问  
  5. LRESULT /*CALLBACK*/ HookProcess2(// HookProcess2是一个类的成员函数  
  6.                              int nCode,  
  7.                              WPARAM wParam, LPARAM lParam) {  
  8.   //假设主函数中的myHook指针指向0x003d3450,修复this指针  
  9.               __asm  //内联汇编语句  
  10. {  
  11.       push eax                   //保护eax  
  12.       mov eax, 0x003d3450     
  13.       mov this, eax              //设置本类的this指针(__asm不检查访问性)  
  14.       pop eax                    //还原eax  
  15. }  
  16.  //此时查看this指针,就能够发现this正常工作  
  17.   this->value++;  
  18.        return NULL;  
  19. }  
  20. };  
 


此时,发现整个函数能够顺利运行。(注意,在实际测试时,需要在main中加断点检查myHook的地址,并动态的修改mov eax, 0x003d3450的数值。否则不能测试通过)

 

这是因为,注销掉CALLBACK的修饰符(即__stdcall)之后,函数采用默认的__thiscall调用方式,此时,this指针是通过CUP寄存器的ecx传送,此时就不会产生堆栈不平衡的错误了。

进一步的,我们遇到的新的问题,尽管能够成功模拟一个类成员函数的调用,修复了this指针,但是对于SetWindowsHookEx来说,每个类的所有成员是共享一个函数空间的。即如下图所示。

C++ Hook(钩子)编程-原始结构


因此,如果使用HookProcess2的程序入口(内存首地址)作为SetWindowsHookEx的参数传入,在引发钩子事件的时候就不能够区分到底引发了哪个类的HookProcess2函数,即不能设定this指针。

为了解决这个问题,我们需要生成一个动态的函数入口,这个入口是每个对象独享的,因此不同的对象将引发不同的函数,这就能够区分类的不同对象。根据其他语言对它的描述,我们将这个函数入口暂称为委托(Delegate)。

在实际上,我们是通过定义一个成员变量(如byte类型的数组,可便于的赋值)来实现这个委托的,其中实际上保存了一段机器码,这段机器码(根据汇编语法)可以动态的设定this指针,并实现到真正函数首地址的跳转。这个委托的示意过程如下:

C++ Hook(钩子)编程-委托结构


 

下面说明这个委托的声明和设定代码:


C/C++ Code:

[cpp] view plain copy
  1. class WinHook //进一步修改WinHook类的函数HookProcess2  
  2. {  
  3. public:  
  4.        byte DelegateThisCall[10]; //定义委托  
  5.        WinHook(void){  
  6.                //初始化委托  
  7.                      byte * DelegatePoint = DelegateThisCall;  
  8.     DelegateThisCall[0] = 0xb9; //0-4:__asm mov ecx, this  
  9.     DelegateThisCall[5] = 0xe9; //5-9:__asm jmp, CoreHookProcess  
  10.     __asm  
  11.     {  
  12.          push eax                        //保护eax  
  13.          push ebx                        //保护ebx  
  14.          mov eax, this                   //取得this地址  
  15.          mov ebx, DelegatePoint        //获取DelegateThisCall地址  
  16.          mov dword ptr [ebx+1], eax   //this 地址, 双字(DWORD)  
  17.     }  
  18.     //计算jmp地址参考:http://zhidao.baidu.com/question/105950930.html  
  19.     __asm  
  20.     {  
  21.          lea eax, HookProcess2         //取得HookProcess2地址  
  22.          mov ebx, DelegatePoint        //获取jmp地址= DelegatePoint + 5  
  23.          add ebx, 5  
  24.          add ebx, 5       //JMP地址=目标地址-(本句地址+本句指令字节数)  
  25.          sub eax, ebx     //JMP地址= HookProcess2 – [(DelegatePoint+5) + 5]  
  26.          mov dword ptr [ebx-4], eax   //HookProcess2地址, 双字(DWORD)  
  27.          pop ebx                         //还原ebx  
  28.          pop eax                         //还原eax  
  29.     }  
  30.        }  
  31.       int value; //定义一个成员变量,以便于测试访问  
  32.   LRESULT /*CALLBACK*/ HookProcess2(// HookProcess2是一个类的成员函数  
  33.                               int nCode,  
  34.                               WPARAM wParam, LPARAM lParam) {  
  35.       //查看this指针,就能够发现this正常工作  
  36.          this->value++;  
  37.          return NULL;  
  38.   }  
  39. };  
 

 

进一步的,修改主函数:

C/C++ Code:

[cpp] view plain copy
  1. int main(){  
  2.        //定义一个函数指针HookProcess,它可以成功作为参数传递给SetWindowsHookEx  
  3.        LRESULT (CALLBACK * HookProcess)  
  4.                       (int nCode, WPARAM wParam, LPARAM lParam);  
  5.        //将HookProcess指向HookProcess2  
  6.        WinHook *myHook = new WinHook();  
  7.        //HookProcess = myHook->HookProcess2; //赋值失败,提示类型不能转化  
  8.        byte * DelegatePoint = myHook->DelegateThisCall; //获取委托首地址  
  9.      __asm  //内联汇编语句  
  10.      {  
  11.          push eax  
  12.          mov eax, DelegatePoint  
  13.          mov HookProcess, eax         //强制将委托的地址赋值给函数指针  
  14.          pop eax  
  15.      }  
  16.        HookProcess (0,0,0);//尝试调用之. 调用成功    
  17.        return 0;  
  18. }  
 

 

以上,就成功的完成了类成员函数的钩子过程,通过一个委托,完成了此功能。

 

最后,为了演示上述方法在建立Windows Hook编程上的使用,特给出编写的动态链接库的实现WinHook功能的BaseHook类的代码,此类完成了成员函数的Hook加载卸载等管理,用户通过继承此类,并重写HookProcess函数(如下),便可完成所有Hook功能。


C/C++ Code:

[cpp] view plain copy
  1. //BaseHook 类的虚函数,当Hook事件发生时会调用此函数。  
  2. //用户通过继承并重写此函数完成Hook功能  
  3. virtual LRESULT /*CALLBACK*/ HookProcess  
  4.                                                  (int nCode, WPARAM wParam, LPARAM lParam);  
 

 

 

源码部分:

C/C++ Code: BaseHook.h

[cpp] view plain copy
  1. /********************************************************* {COPYRIGHT-TOP} * 
  2. * RealZYC Confidential 
  3. * OCO Source Materials 
  4. * 
  5. * (C) Copyright RealZYC Corp. 2011 All Rights Reserved. 
  6. * 
  7. * The source code for this program is not published or otherwise 
  8. * divested of its trade secrets, irrespective of what has been 
  9. * deposited with the China Copyright Office. 
  10. ********************************************************** {COPYRIGHT-END} */  
  11. #pragma once  
  12. #include <windows.h>  
  13. /*************************************** 
  14. *The basic defination of windows hook 
  15. ****************************************/  
  16. class BaseHook  
  17. {  
  18.     /*************************************** 
  19.     * Enum 
  20.     ****************************************/  
  21. #pragma region Enum  
  22. public:  
  23.     /*************************************** 
  24.     *The available types of windows hook 
  25.     ****************************************/  
  26.     enum HookTypes: int  
  27.     {  
  28.         //Message filter hook - WH_MSGFILTER = -1  
  29.         MsgFilter = -1,  
  30.         //Journal record hook - WH_JOURNALRECORD = 0  
  31.         JournalRecord = 0,  
  32.         //Journal playback hook - WH_JOURNALPLAYBACK = 1  
  33.         JournalPlayback = 1,  
  34.         //Keyboard hook - WH_KEYBOARD = 2  
  35.         Keyboard = 2,  
  36.         //Get message hook - WH_GETMESSAGE = 3  
  37.         GetMessage = 3,  
  38.         //Call wnd proc hook - WH_CALLWNDPROC = 4  
  39.         CallWndProc = 4,  
  40.         //CBT hook - WH_CBT = 5  
  41.         CBT = 5,  
  42.         //System message filter hook - WH_SYSMSGFILTER = 6  
  43.         SysMsgFilter = 6,  
  44.         //Mouse hook - WH_MOUSE = 7  
  45.         Mouse = 7,  
  46.         //Hardware hook - WH_HARDWARE = 8  
  47.         Hardware = 8,  
  48.         //Debug hook - WH_DEBUG = 9  
  49.         Debug = 9,  
  50.         //Shell hook - WH_SHELL = 10  
  51.         Shell = 10,  
  52.         //Fore ground idle hook - WH_FOREGROUNDIDLE = 11  
  53.         ForeGroundIdle = 11,  
  54.         //Call wnd proc ret hook - WH_CALLWNDPROCRET = 12  
  55.         CallWndProcRet = 12,  
  56.         //Keyboard low level hook - WH_KEYBOARD_LL = 13  
  57.         KeyboardLL = 13,  
  58.         //Mouse low level hook - WH_MOUSE_LL = 14  
  59.         MouseLL = 14  
  60.     };  
  61. #pragma endregion  
  62.     /*************************************** 
  63.     * Value 
  64.     ****************************************/  
  65. #pragma region Value  
  66. protected:  
  67.     //The hook type  
  68.     HookTypes int_HookType;   
  69.     //The hook object thread id, give 0 for all thread  
  70.     DWORD dword_ThreadId;  
  71.     //The hook id, give 0 for not set  
  72.     HHOOK point_HookID;  
  73.     //Dll entrance  
  74.     static HINSTANCE hangle_HinstDLL;  
  75. protected:  
  76.     //The this call delegate for CoreHookProcess  
  77.     byte DelegateThisCall[10];  
  78. #pragma endregion  
  79.     /*************************************** 
  80.     * New 
  81.     ****************************************/  
  82. #pragma region New  
  83. public:  
  84.     /*************************************** 
  85.     ''' <summary> 
  86.     ''' Initial function 
  87.     ''' </summary> 
  88.     ''' <param name="HookType">The hook type</param> 
  89.     ''' <param name="ThreadId">The hook object thread id, give 0 for all thread</param> 
  90.     ****************************************/  
  91.     BaseHook(HookTypes HookType, DWORD ThreadId);  
  92.     //Dispose function  
  93.     ~BaseHook(void);  
  94. #pragma endregion  
  95.     /*************************************** 
  96.     * Property 
  97.     ****************************************/  
  98. #pragma region Property  
  99. public:  
  100.     //Set / get the hook type  
  101.     inline HookTypes GetHookType();  
  102.     inline void SetHookType(HookTypes HookType);  
  103.     //Set / get the hook object thread id, give 0 for all thread  
  104.     inline DWORD GetThreadId();  
  105.     inline void SetThreadId(DWORD ThreadId);  
  106.     //Set / get whether the hook is running  
  107.     bool GetEnabled();  
  108.     void SetEnabled(bool Enabled);  
  109.     //Set / get dll hinst  
  110.     static HINSTANCE GetHinstDll();  
  111.     static void SetHinstDll(HINSTANCE HinstDLL);  
  112. #pragma endregion  
  113.     /*************************************** 
  114.     * Sub / Function 
  115.     ****************************************/  
  116. #pragma region Sub / Function  
  117. protected:  
  118.     /*************************************** 
  119.     ///<summary> 
  120.     /// The defination of core hook process 
  121.     ///</summary> 
  122.     ///<param name="nCode">Specifies the hook code passed to the current hook procedure. The next hook procedure uses this code to determine how to process the hook information</param> 
  123.     ///<param name="wParam">Specifies the wParam value passed to the current hook procedure. The meaning of this parameter depends on the type of hook associated with the current hook chain</param> 
  124.     ///<param name="lParam">Specifies the lParam value passed to the current hook procedure. The meaning of this parameter depends on the type of hook associated with the current hook chain</param> 
  125.     ///<returns>The nCode, use 0 to pass the information to next hook, others to ignore the current information</returns> 
  126.     ///<remarks>Use for SetWindowsHookEx</remarks> 
  127.     ****************************************/  
  128.     LRESULT /*CALLBACK*/ CoreHookProcess(int nCode, WPARAM wParam, LPARAM lParam);  
  129. public:  
  130.     /*************************************** 
  131.     /// <summary> 
  132.     /// Set the hook data 
  133.     /// </summary> 
  134.     /// <param name="HookType">The hook type</param> 
  135.     /// <param name="ThreadId">The hook object thread id, give 0 for all thread</param> 
  136.     /// <remarks>Restart the hook after the hook data changed</remarks> 
  137.     ****************************************/  
  138.     void SetHook(HookTypes HookType, DWORD ThreadId);  
  139.     /*************************************** 
  140.     /// <summary> 
  141.     /// Start the hook 
  142.     /// </summary> 
  143.     /// <remarks>Check the Enabled for operation result</remarks> 
  144.     ****************************************/  
  145.     void Start();  
  146.     /*************************************** 
  147.     /// <summary> 
  148.     /// Stop the hook 
  149.     /// </summary> 
  150.     /// <remarks>Check the Enabled for operation result</remarks> 
  151.     ****************************************/  
  152.     void Stop();  
  153.     /*************************************** 
  154.     /// <summary> 
  155.     /// The user defined hook process 
  156.     /// </summary> 
  157.     /// <param name="nCode">Specifies the hook code passed to the current hook procedure. The next hook procedure uses this code to determine how to process the hook information</param> 
  158.     /// <param name="wParam">Specifies the wParam value passed to the current hook procedure. The meaning of this parameter depends on the type of hook associated with the current hook chain</param> 
  159.     /// <param name="lParam">Specifies the lParam value passed to the current hook procedure. The meaning of this parameter depends on the type of hook associated with the current hook chain</param> 
  160.     /// <returns>The nCode, use 0 to pass the information to next hook, others to ignore the current information</returns> 
  161.     /// <remarks>Use for CoreHookProcess</remarks> 
  162.     ****************************************/  
  163.     virtual LRESULT /*CALLBACK*/ HookProcess(int nCode, WPARAM wParam, LPARAM lParam);  
  164. #pragma endregion  
  165. };  
 

 

C/C++ Code: BaseHook.cpp

[cpp] view plain copy
  1. /********************************************************* {COPYRIGHT-TOP} * 
  2. * RealZYC Confidential 
  3. * OCO Source Materials 
  4. * 
  5. * (C) Copyright RealZYC Corp. 2011 All Rights Reserved. 
  6. * 
  7. * The source code for this program is not published or otherwise 
  8. * divested of its trade secrets, irrespective of what has been 
  9. * deposited with the China Copyright Office. 
  10. ********************************************************** {COPYRIGHT-END} */  
  11. #include "BaseHook.h"  
  12. /*************************************** 
  13. *class BaseHook 
  14. ****************************************/  
  15. /*************************************** 
  16. * Static 
  17. ****************************************/  
  18. #pragma region Static  
  19. HINSTANCE BaseHook::hangle_HinstDLL = NULL;  
  20. #pragma endregion  
  21. /*************************************** 
  22. * Property 
  23. ****************************************/  
  24. #pragma region Property  
  25. //Set / get the hook type  
  26. BaseHook::HookTypes BaseHook::GetHookType(){return int_HookType;}  
  27. void BaseHook::SetHookType(HookTypes HookType){int_HookType = HookType;}  
  28. //Set / get the hook object thread id, give 0 for all thread  
  29. DWORD BaseHook::GetThreadId(){return dword_ThreadId;}  
  30. void BaseHook::SetThreadId(DWORD ThreadId){dword_ThreadId = ThreadId;}  
  31. //Set / get whether the hook is running  
  32. bool BaseHook::GetEnabled(){return ( point_HookID != NULL );}  
  33. void BaseHook::SetEnabled(bool Enabled)  
  34. {  
  35.     if(Enabled != GetEnabled())  
  36.     {  
  37.         if(Enabled)Start();  
  38.         else Stop();  
  39.     }  
  40. }  
  41. //Set / get dll hinst  
  42. HINSTANCE BaseHook::GetHinstDll()  
  43. {  
  44.     try  
  45.     {  
  46.         return (hangle_HinstDLL != NULL)? hangle_HinstDLL:   
  47.                         GetModuleHandle((LPCTSTR)"WinHook");  
  48.     }  
  49.     catch(...)  
  50.     {  
  51.         return NULL;  
  52.     }  
  53. }  
  54. void BaseHook::SetHinstDll(HINSTANCE HinstDLL){hangle_HinstDLL = HinstDLL;}  
  55. #pragma endregion  
  56. /*************************************** 
  57. * New 
  58. ****************************************/  
  59. #pragma region New  
  60. /*************************************** 
  61. /// <summary> 
  62. /// Initial function 
  63. /// </summary> 
  64. /// <param name="HookType">The hook type</param> 
  65. /// <param name="ThreadId">The hook object thread id, give 0 for all thread</param> 
  66. ****************************************/     
  67. BaseHook::BaseHook(BaseHook::HookTypes HookType, DWORD ThreadId)  
  68. {  
  69.     point_HookID = NULL;  
  70.       
  71.     //******************************************//  
  72.     //初始化委托  
  73.     byte * DelegatePoint = DelegateThisCall;  
  74.     DelegateThisCall[0] = 0xb9; //__asm mov ecx, this  
  75.     DelegateThisCall[5] = 0xe9; //__asm jmp, CoreHookProcess  
  76.     __asm  
  77.     {  
  78.         push eax                //保护eax  
  79.         push ebx                //保护ebx  
  80.         mov eax, this           //取得this地址  
  81.         mov ebx, DelegatePoint  //获取DelegateThisCall地址  
  82.         mov dword ptr [ebx+1], eax  //this 地址, 双字(DWORD)  
  83.     }  
  84.     __asm //计算jmp地址参考:http://zhidao.baidu.com/question/105950930.html  
  85.     {  
  86.         lea eax, CoreHookProcess        //取得CoreHookProcess地址  
  87.         mov ebx, DelegatePoint          //获取jmp地址= DelegatePoint + 5  
  88.         add ebx, 5  
  89.         add ebx, 5  
  90.         sub eax, ebx                    //JMP地址=目标地址-(本句地址+本句指令字节数)  
  91.         mov dword ptr [ebx-4], eax      //CoreHookProcess 地址, 双字(DWORD)  
  92.         pop ebx                 //还原ebx  
  93.         pop eax                 //还原eax  
  94.     }  
  95.     //******************************************//  
  96.     SetHook(HookType, ThreadId);  
  97. }  
  98. //Dispose function  
  99. BaseHook::~BaseHook(void)  
  100. {  
  101.     SetEnabled(false);  
  102. }  
  103. #pragma endregion  
  104. /*************************************** 
  105. * Sub / Function 
  106. ****************************************/  
  107. #pragma region Sub / Function  
  108. /*************************************** 
  109. ///<summary> 
  110. /// The defination of core hook process 
  111. ///</summary> 
  112. ///<param name="nCode">Specifies the hook code passed to the current hook procedure. The next hook procedure uses this code to determine how to process the hook information</param> 
  113. ///<param name="wParam">Specifies the wParam value passed to the current hook procedure. The meaning of this parameter depends on the type of hook associated with the current hook chain</param> 
  114. ///<param name="lParam">Specifies the lParam value passed to the current hook procedure. The meaning of this parameter depends on the type of hook associated with the current hook chain</param> 
  115. ///<returns>The nCode, use 0 to pass the information to next hook, others to ignore the current information</returns> 
  116. ///<remarks>Use for SetWindowsHookEx</remarks> 
  117. ****************************************/  
  118. LRESULT /*CALLBACK*/ BaseHook::CoreHookProcess(int nCode, WPARAM wParam, LPARAM lParam)  
  119. {  
  120.     //调用模式:如果使用__stdcall (即加入CALLBACK关键字),  
  121.     //                                  那么this指针是通过push this来传送的, 非法调用时会产生堆栈的不平衡, 会在函数返回时出错  
  122.     //                       如果使用__thiscall,那么this指针是通过ecx来来传送的, 不会产生堆栈变化, 测试成功  
  123.     //参考自:http://wenku.baidu.com/view/ad102ccf05087632311212ad.html  
  124.     LRESULT Result = this->HookProcess(nCode, wParam, lParam); //此时访问时, 由于设置了this指针,成功运行  
  125.     if(Result == NULL)  
  126.         Result = CallNextHookEx(point_HookID, nCode, wParam, lParam);  
  127.     return Result; //由于注释掉CALLBACK,不会产生堆栈不平衡的问题,函数返回后无报错  
  128. }  
  129. /*************************************** 
  130. /// <summary> 
  131. /// Set the hook data 
  132. /// </summary> 
  133. /// <param name="HookType">The hook type</param> 
  134. /// <param name="ThreadId">The hook object thread id, give 0 for all thread</param> 
  135. /// <remarks>Restart the hook after the hook data changed</remarks> 
  136. ****************************************/  
  137. void BaseHook::SetHook(BaseHook::HookTypes HookType, DWORD ThreadId)  
  138. {  
  139.     int_HookType = HookType;  
  140.     dword_ThreadId = ThreadId;  
  141. }  
  142. /*************************************** 
  143. /// <summary> 
  144. /// Start the hook 
  145. /// </summary> 
  146. /// <remarks>Check the Enabled for operation result</remarks> 
  147. ****************************************/  
  148. void BaseHook::Start()  
  149. {  
  150.     try  
  151.     {  
  152.         if(GetEnabled())SetEnabled(false);  
  153.         HINSTANCE hMod = NULL;  
  154.         if(GetThreadId() == 0)  
  155.         {  
  156.             hMod = GetHinstDll();  
  157.         }  
  158.         else  
  159.         {  
  160.             if(GetCurrentThreadId() == GetThreadId())  
  161.             {  
  162.                 hMod = NULL;  
  163.             }  
  164.             else hMod = GetHinstDll();  
  165.         }  
  166.         //===============================================================  
  167.         //将类成员函数指针转化为一般函数指针  
  168.         LRESULT (CALLBACK * PCoreHookProcess)(int nCode, WPARAM wParam, LPARAM lParam);  
  169.         byte * DelegatePoint = DelegateThisCall;  
  170.         __asm  //内联汇编语句  
  171.         {  
  172.             push eax                                            //保护eax  
  173.             mov eax, DelegatePoint  
  174.             mov PCoreHookProcess, eax                           //将委托地址强制转化给PCoreHookProcess  
  175.             pop eax                                             //还原eax  
  176.         }  
  177.         //===============================================================  
  178.         point_HookID = SetWindowsHookEx(GetHookType(),   
  179.             PCoreHookProcess,  
  180.             hMod,   
  181.             GetThreadId());  
  182.     }  
  183.     catch(...)  
  184.     {  
  185.         point_HookID = NULL;  
  186.     }  
  187. }  
  188. /*************************************** 
  189. /// <summary> 
  190. /// Stop the hook 
  191. /// </summary> 
  192. /// <remarks>Check the Enabled for operation result</remarks> 
  193. ****************************************/  
  194. void BaseHook::Stop()  
  195. {  
  196.     try  
  197.     {  
  198.         UnhookWindowsHookEx(point_HookID);  
  199.     }  
  200.     catch(...)  
  201.     {  
  202.     }  
  203.     point_HookID = NULL;  
  204. }  
  205. /*************************************** 
  206. /// <summary> 
  207. /// The user defined hook process 
  208. /// </summary> 
  209. /// <param name="nCode">Specifies the hook code passed to the current hook procedure. The next hook procedure uses this code to determine how to process the hook information</param> 
  210. /// <param name="wParam">Specifies the wParam value passed to the current hook procedure. The meaning of this parameter depends on the type of hook associated with the current hook chain</param> 
  211. /// <param name="lParam">Specifies the lParam value passed to the current hook procedure. The meaning of this parameter depends on the type of hook associated with the current hook chain</param> 
  212. /// <returns>The nCode, use 0 to pass the information to next hook, others to ignore the current information</returns> 
  213. /// <remarks>Use for CoreHookProcess</remarks> 
  214. ****************************************/  
  215. LRESULT /*CALLBACK*/ BaseHook::HookProcess(int nCode, WPARAM wParam, LPARAM lParam)  
  216. {  
  217.     return NULL;  
  218. }  
  219. #pragma endregion  
0 0
原创粉丝点击