Windows程序设计__孙鑫C++Lesson20《HOOK和数据库访问》

Windows程序设计__孙鑫C++Lesson20《HOOK和数据库访问》

本节要点:
1.Hook编程回顾Windows消息传递机制
2.安装内部钩子
3.安装全局钩子
4.数据库访问技术初步了解
//*********************************************************************************************
1.Hook编程回顾Windows消息传递机制
Windows消息机制如下图所示:


2.安装内部钩子:和一个指定线程相关的钩子
(1)hook链(hook chain) :多个hook过程,形成一个hook链,最后安装的hook总是在链的前面。hook链允许对消息进行多个处理。
(2)安装钩子使用函数SetWindowsHookEx,该函数原型为:
HHOOK SetWindowsHookEx(
  int idHook,        // hook type
  HOOKPROC lpfn,     // hook procedure
  HINSTANCE hMod,    // handle to application instance
  DWORD dwThreadId   // thread identifier
);
parameter 1 :idHook参数指定为安装的钩子类型。
parameter 2 :lpfn 指向钩子过程的一个函数指针。如果dwThread参数被设置为0或者被指定为不同进程创建的线程ID的话,那么这个参数必须必须设置为指向一个动态链接库(DLL)中的钩子过程。否则,这个参数可以指向一个和当前进程相关的钩子过程。
parameter 3 :hMod 参数指定了由lpfn参数指定的钩子过程的Dll句柄,如果dwThread参数被指定为当前进程创建的某个线程的ID并且钩子过程的执行代码和当前线程相关的话,
这个参数必须设置为NULL。
parameter 4 :dwThreadId参数指定了钩子过程和哪个线程相关,
当参数指定为0时钩子过程将和当前调用线程处在同一个桌面上的所有的正在运行的线程相关。
注意三点:
第一:全局钩子的必须是动态链接库中的钩子函数。
第二:在调用钩子过程后,应该调用 CallNextHookEx函数将消息传递到下一个钩子过程,
除非你不想让其他其他程序接受这些消息,但是这样做可能引起其他程序安装的钩子过程出现错误的结果。
第三:在程序结束前应该调用UnhookWindowsHookEx函数来释放和钩子相关的资源。
(3)钩子函数编写 根据不同类型的钩子编写不同类型的钩子过程。
比如鼠标钩子的构成函数:
LRESULT CALLBACK MouseProc(
  int nCode,      // hook code
  WPARAM wParam,  // message identifier
  LPARAM lParam   // mouse coordinates
);
关于该MouseProc过程的返回值说明:
如果nCode小于0,钩子过程必须返回CallNextHookEx函数的返回值;
如果nCode大于或者等于0并且钩子过程没有处理这个消息的话,强烈建议调用CallNextHookEx函数并返回其值,
否则其他的安装了鼠标钩子的程序将不能正确接收这个消息可能引起错误的结果。如果钩子过程处理了这个消息,
那么返回一个非零值可以阻止系统继续传递该消息给其他程序。
比如键盘钩子过程的函数原型为:
LRESULT CALLBACK KeyboardProc(
  int code,       // hook code
  WPARAM wParam,  // virtual-key code
  LPARAM lParam   // keystroke-message information
);
对于键盘钩子过程获取的消息中,wParam表示了按键的虚键值,利用这个虚键值可以判断按键。
虚键值是一组宏(选中虚键值然后转到定义可查看),其中'0' 到'9'以及'A' 到'Z'的虚键值和ASCii码相同未作宏定义;要判断是否同时按下多个键由参数lParam 来判断。
(4)对用户ALT+F4键的判断 关键是如何判断ALT键按下
通过键盘消息的lParam参数可以判断该信息,键盘按键消息的lParam参数图解如下(由MSDN提供):
如何判断是通过移位和与操作实现的,具体过程可参见我绘制的下图:



(5)内部钩子程序主要代码(对话框程序自动添加的代码未列出)如下(注意按F6退出程序):
//*****************************************************************

  1. // InnerHookDlg.cpp  
  2. HHOOK g_hKeyHook=NULL;  
  3. HHOOK g_hMouseHook=NULL;  
  4. HWND  g_hWnd=NULL;//保存句柄  
  5. LRESULT CALLBACK MouseProc(  
  6.   int nCode,      // hook code  
  7.   WPARAM wParam,  // message identifier  
  8.   LPARAM lParam   // mouse coordinates  
  9. )  
  10. {  
  11.     return 1;  
  12.   
  13. }  
  14. LRESULT CALLBACK KeyboardProc(  
  15.   int code,       // hook code  
  16.   WPARAM wParam,  // virtual-key code  
  17.   LPARAM lParam   // keystroke-message information  
  18. )  
  19. {  
  20.        /* 
  21.        if(VK_SPACE==wParam || VK_RETURN==wParam )//屏蔽空格、回车键 
  22.     if( VK_F4==wParam && (1==( lParam>>29 & 1 )))//屏蔽Alt+F4键 
  23.        return 1; 
  24.     else 
  25.         return CallNextHookEx(hHook,code,wParam,lParam);//继续传递消息到hook链 
  26.        */  
  27.     if(VK_F6==wParam)//F6键退出  
  28.     {     
  29.         ::SendMessage(g_hWnd,WM_CLOSE,0,0);//关闭对话框  
  30.         UnhookWindowsHookEx(g_hKeyHook);  
  31.         UnhookWindowsHookEx(g_hMouseHook);  
  32.     }  
  33.      return 1;  
  34. }  
  35. BOOL CInnerHookDlg::OnInitDialog()  
  36. {  
  37.     ...  
  38.     // TODO: Add extra initialization here  
  39.     g_hWnd=m_hWnd;//获取对话框句柄  
  40.     g_hMouseHook = SetWindowsHookEx(WH_MOUSE,MouseProc,NULL,GetCurrentThreadId());//设置鼠标钩子 屏蔽当前进程的消息  
  41.     g_hKeyHook = SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,NULL,GetCurrentThreadId());//设置键盘钩子  
  42.     return TRUE;  // return TRUE  unless you set the focus to a control  
  43. }  

 

//******************************************************************
3.安装全局钩子:和所有线程相关的钩子
全局钩子过程必须为一个动态链接库(DLL)中的钩子过程。首先要编写一个钩子过程的动态链接库Hook.dll,
然后编写一个全局钩子HookTest,调用动态链接库中的钩子过程。
(1)如何获取动态链接库中函数模块句柄
在动态链接库中编写钩子过程时获取动态链接库的模块的句柄的两种方法:
方法一:使用DllMain函数传递的参数获取句柄
方法二:使用GetModuleHandle函数,函数原型为:HMODULE GetModuleHandle(
  LPCTSTR lpModuleName   // module name 缺省文件后缀为dll
);
(2)如何保存当前运行程序的句柄
在程序中定义全局变量HWND g_hWnd=NULL;当程序切换到其他窗口后按下自定义的关闭键F6无法关闭本程序。
解决方法时使用共享的数据段,将窗口句柄定义为:
#pragma data_seg("MySeg")
HWND g_hWnd=NULL;
#pragma data_seg()
设置节的读写及共享属性:
方法一:在源文件中完整书写为
//******************************************************************
#pragma data_seg("MySeg")
HWND g_hWnd=NULL;//初始化之后才会放到segment中 查看命令为 dumpbin -headers Hook.dll
#pragma data_seg()
//#pragma comment(linker,"/section:MySeg,RWS")  //设置集的读写共享属性
//******************************************************************
方法二:在模块定义文件中声明为:
//******************************************************************
SEGMENTS
MySeg read write shared
//******************************************************************
利用dumpbin.exe 查看程序数据段使用命令 dumpbin -headers Hook.dll
设置好MySeg数据段的读写和共享属性后,利用dumpbin.exe查看结果如下图:



//******************************************************************
#pragma指令还有其他用法,可参见MSDN。
更多关于数据共享的问题可参见博客:http://www.cnblogs.com/ahuo/archive/2008/04/08/1143488.html
(3)钩子Dll以及钩子测试程序的代码如下:
//******************************************************************

  1. //Hook.dll编写的代码  
  2. //Hook.def  
  3. LIBRARY Hook  
  4. EXPORTS  
  5. SetHook    
  6. SEGMENTS  
  7. MySeg read write shared  
  8. //******************************************************************  
  9. //Hook.cpp  
  10. #include <Windows.h>  
  11. HHOOK g_hMouseHook=NULL;//鼠标钩子过程句柄  
  12. HHOOK g_hKeyHook=NULL;//键盘钩子过程句柄  
  13. #pragma data_seg("MySeg")  
  14. HWND g_hWnd=NULL;//初始化之后才会放到segment中 查看命令为 dumpbin -headers Hook.dll  
  15. #pragma data_seg()  
  16. //#pragma comment(linker,"/section:MySeg,RWS")  //设置集的读写共享属性  如果在模块定义文件中已经说明时则这里不需要  
  17. //获取动态链接库模块句柄方法一 使用DllMain  
  18. /*HINSTANCE g_hInst=NULL;//全局实例句柄变量  
  19. //动态链接库入口函数  
  20. BOOL WINAPI DllMain(  
  21.   HINSTANCE hinstDLL,  // handle to the DLL module  
  22.   DWORD fdwReason,     // reason for calling function  
  23.   LPVOID lpvReserved   // reserved  
  24. )  
  25. {  
  26.    g_hInst=hinstDLL;//获取动态链接库句柄  
  27.    return true;  
  28. }*/  
  29. LRESULT CALLBACK MouseProc(  
  30.   int nCode,      // hook code  
  31.   WPARAM wParam,  // message identifier  
  32.   LPARAM lParam   // mouse coordinates  
  33. )  
  34. {  
  35.     return true;  
  36. }  
  37. LRESULT CALLBACK KeyboardProc(  
  38.   int code,       // hook code  
  39.   WPARAM wParam,  // virtual-key code  
  40.   LPARAM lParam   // keystroke-message information  
  41. )  
  42. {  
  43.     if(VK_F6==wParam)  
  44.     {  
  45.         ::SendMessage(g_hWnd,WM_CLOSE,0,0);  
  46.         UnhookWindowsHookEx(g_hMouseHook);  
  47.         UnhookWindowsHookEx(g_hKeyHook);  
  48.     }  
  49.     if('A'==wParam)  
  50.         MessageBox(g_hWnd,"按下了a!","钩子测试",MB_OK);  
  51.     return true;  
  52. }  
  53. void SetHook(HWND hWnd)  
  54. {     
  55.     g_hWnd=hWnd;//声明为全局时 切换到其他进程时将会发生改变  
  56.     //获取动态链接库模块句柄方法二 使用函数GetModuleHandle  
  57.     g_hMouseHook=SetWindowsHookEx(WH_MOUSE,MouseProc,GetModuleHandle("Hook"),0);//安装鼠标钩子  
  58.     g_hKeyHook=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,GetModuleHandle("Hook"),0);//安装键盘钩子  
  59. }  
  60. //******************************************************************  
  61. //钩子测试的对话框程序  
  62. //HookTest.cpp  
  63. _declspec(dllimport)  void SetHook(HWND hWnd);//导入函数 注入加入Hook.lib和Hook.dll文件到当前工程  
  64. BOOL CHookTestDlg::OnInitDialog()  
  65. {  
  66.     ...  
  67.     // TODO: Add extra initialization here  
  68.     //设置为顶层全屏窗口 用户无法看到其他程序窗口  
  69.     int cxScreen,cyScreen;  
  70.         cxScreen=GetSystemMetrics(SM_CXSCREEN);  
  71.     cyScreen=GetSystemMetrics(SM_CYSCREEN);  
  72.     SetWindowPos(&wndTopMost,0,0,cxScreen,cyScreen,SWP_SHOWWINDOW);  
  73.     SetHook(m_hWnd);//启动钩子  
  74.     return TRUE;  
  75. }  

//******************************************************************
程序运行(注意按F6退出程序)效果如下图所示(当然这里观察不到键盘和鼠标的屏蔽效果):


程序运行时360安全卫士提示警告信息如下图所示:


//******************************************************************
4.数据库访问技术初步了解
(1)数据库访问技术  数据库访问技术介绍如下图所示:


(2)在vc中使用ADO访问数据库
首先要导入ADO库,使用一下语句:
#import  "C:\Program Files\Common Files\System\ado\msado15.dll" no_namespace rename("EOF","rsEOF");
VC生成的文件,tlh可看做头文件,tli文件可看做源文件。获取数据库连接字符串的方便方式是建立一个txt文件将后缀改为udl,
然后打开它就可选择连接数据库,选择完毕后以txt形式打开就可获取数据库连接字符串。
由于系统安装原因,这里只是了解了一下,实验在以后的过程中再做学习。
//*********************************************************************************************
本节小结:
通过本节的学习掌握了内部钩子和全局钩子的编写,要编写不同功能的钩子可以采用不同的参数赋给创建钩子的函数SetWindowsHookEx;
同时了解了数据库访问的几种不同技术,注意在以后的编程过程中合理选择数据库的访问技术。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值