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退出程序):
//*****************************************************************
//******************************************************************
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以及钩子测试程序的代码如下:
//******************************************************************
//******************************************************************
程序运行(注意按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;
同时了解了数据库访问的几种不同技术,注意在以后的编程过程中合理选择数据库的访问技术。