风中之歌

我是世界的光

用户操作
[即时聊天] [发私信] [加为好友]
linzhenqunID:linzhengqun
86593次访问,排名1214,好友20人,关注者28人。
程序,设计,音乐,
linzhengqun的文章
原创 51 篇
翻译 0 篇
转载 0 篇
评论 119 篇
linzhenqun的公告

我们生的时候啊,
要像夏季的花一样灿烂;
而在死的时候,
须如秋天的叶一般静美!

seo sydney
seo sydney Counter

最近评论
linzhengqun:呵,不好意思我不是底层的开发人员,所以对Ring0的东西其实知之甚少。
不过作为一个优秀的程序员,应该有能力自学这些东西。
hzfch:看了你的文章和提供的代码对我帮助很大
谢谢了
希望你写一些ring0 hook的文章
wwp3321:只能说声谢谢了,谢谢楼主的共享精神
trytobegood:好东东!!!收藏了
yunhaisoft://你的这个版本中文乱码,我参考Cnpack的代码帮着你改了一下,你看看。经测试已经没有乱码了。
procedure TConvRTF.ChangeSpeString(var S: String);
var
Str: string;
i: Integer;
Len: Integer;
tmpWide, tmpStr:……
文章分类
收藏
相册
CodeGear纪念
GDI绘制
MFC文档视图
MFC消息分派
玻璃效果
汇编与高级语言
接口的实现
增量搜索
最简单的MFC程序
友情链接
Ari
天蝎蝴蝶的专栏
还猪哥哥
醉到天亮说晚安
风中之歌-非技术Blog
存档
软件项目交易
订阅我的博客
XML聚合  FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
订阅到BlogLines
订阅到Yahoo
订阅到GouGou
订阅到飞鸽
订阅到Rojo
订阅到newsgator
订阅到netvibes

原创 钩子及其应用(二)收藏

新一篇: 钩子及其应用(三) | 旧一篇: 钩子及其应用(一)

{二}宏功能的实现

我们写程序,常将完成一个特定功能的代码写到一个函数中,以后直接调用便可实现该功能。对于宏,其实也是相同的原理,将一些键盘和鼠标的操作“录制”起来,以后如果要重复这些操作,只需要将这些操作“回放”就行了。许多编辑软件都有宏的功能,比如WordDelphi也有,按Ctrl+Shift+R进行宏录制,再按Ctrl+Shift+R结束,最后按Ctrl+Shift+P即可回放刚才的输入操作。宏的实现正是钩子的一个应用,使用WH_JOURNALRECORDWH_JOURNALPLAYBACK钩子可以完成对于键盘来鼠标动作的“录制”和“回放”,基于此技术,我们就来实现一个自己的宏。

大多数软件的宏只是记录键盘的操作,并没有鼠标的操作,但有时候记录鼠标的操作也是有好处的,比如你正在测试一个程序,需要重复地进行点击移动,这时鼠标的宏就派上用场了。前一阵子一个朋友用VC实现了一个UI自动测试工具,非常有趣,这次我也依照它用Delphi来实现一个,它可以记录所有的鼠标键盘操作,并回放出来,还可以保存这些操作。

 

先说日志钩子,日志钩子不需要动态链接库*.DLL,就能实现系统级的事件监控,它只能监视两种事件,即鼠标,键盘的操作。我们用前一节所说的APISetWindowsHookEx安装一个日志钩子,这里要重点说明日志钩子的过滤函数:

LRESULT CALLBACK JournalRecordProc(

  int code,        // 钩子编码

  WPARAM wParam,  // 没有使用

  LPARAM lParam   // 被处理的消息

);

其中Code说明如何处理消息,可以是如下的值:

HC_ACTIONlParam是指向一个EVENTMSG结构的指针,该结构包含了从系统队列中移除的消息的信息。

HC_SYSMODALOFF :一个系统模态对话框(如注销对话框)已经被销毁的时候,该钩子过程重新开始记录。

HC_SYSMODALON:一个系统模态对话框正在被销毁,直到它被销毁之前,钩子过程停止记录。

如果Code参数小于0,则要像第一部分所说的调用CallNextHookEx函数,并返回它的返回值。

lParam参数是指向一个EVENTMSG结构的指针。这个结构就是我们要记录的信息。

EVENTMSG如下声明:

typedef struct tagEVENTMSG {

    UINT  message;  //指定消息

    UINT  paramL;   //指定消息的附加信息,该信息取决于消息的值

    UINT  paramH;   //指定消息的附加信息,该信息取决于消息的值

    DWORD time;     //消息传递的时间

    HWND  hwnd;     //消息将传递到的窗口的句柄。

} EVENTMSG, *PEVENTMSG;

在这里给出paramLparamH对鼠标和键盘的意义:

ParamL:如果是键盘消息则代表虚拟码,如果是鼠标消息则代表坐标X

ParamH:如果是键盘消息则代表击键的扫描码,如果是鼠标消息则代表坐标Y

 

我们还要有一个数据结构来保存传递到日志过程中的事件结构列表,以便在回放钩子中使用。Delphi为我们提供了TList,非常方便,List的每一项存储一个EVENTMSG结构指针。不过TList并不管理事件结构指针的生命周期,为方便计,我们可以继续一个子类,并覆盖它的相应方法,即可实现指针的自动释放。

 

最后还要能将消息序列化,保存到文件中,以后可以重新加载到TList中使用。这里就称为保存和打开的功能。XML是一个不错的选择,可以用XML来保存事件结构(关于XML的使用,请查看其他资料)。

 

日志记录钩子的技术准备就这些,下面是日志回放钩子的一些知识。

下面是回放钩子的过滤函数:

LRESULT CALLBACK JournalPlaybackProc(

  int code,        // 钩子编码

  WPARAM wParam,  // 没有使用

  LPARAM lParam   // 被处理的消息

);

当回放钩子安装之后,常规的鼠标和键盘输入就无效了。注意这里的常规是指还有一些不常规的按键有效,比如Ctrl+Alt+Del

Code指定了钩子过程如何处理消息,它可以是如下的值:

HC_GETNEXT:如果准备好了(这里的准备好与否由HC_SKIP决定),则将当前鼠标和键盘消息拷贝到LParam参数中,对于我们的程序,就是将事件结构列表中的一个事件结构拷贝给Lparam

HC_SKIP:钩子过程必须准备将下一个鼠标和键盘拷贝到Lparam参数指向的EventMsg结构中。当为这个值时,表示已经准备好了,我们可以设一个全局变量,在这里标识为真,则在HC_GETEXT时,判断该全局变量 ,如果为真,则将事件拷贝给LParam

HC_SYSMODALOFFHC_SYSMODALON:和记录钩子相似。

 

回放钩子过程的返回值也必须注意,当Code值为HC_GETNEXT时,它指定系统处理当前消息之前要等多少时间,这个时间以毫秒为单位。我们可以通过当前事件结构中的时间与前一个事件结构的时间计算出这个时间值。如果Code是其他值,返回值忽略。

这里补充一点知识, Windows有一个MSG结构,其中有一个成员是Time,表示消息发送的时间,这个时间其实是个相对的值,它从操作系统启动时开始以毫秒为单位增加。调用GetTickCount可以获得该值。

 

有一种情况,就是当我们按下Alt+Ctrl+Del时,钩子会停止下来的,这个时候有什么消息来通知程序,让我们可以做一些设置工作呢,幸好系统为我们准备了WM_CANCELJOURNAL消息,记录和回放钩子在工作时,当按下那些键,系统发送该消息给应用程序的消息循环,通知钩子停止了。我们可以取得ApplicationOnMessage事件,在其中判断,如果获得了该消息,则作一些变量的设置操作。

好了,还是以代码来说明吧。

 

是否给出全部源代码,我考虑了一下,如果代码过长,则怕有臭婆娘的缠脚布之嫌。但如果不全部给出,则又怕理解不全。最后还是狠一下心,把全部代码贴出来,都封在wdMacro单元中,读者可以直接拷贝到工程中,再调用其中的API即可:

发表于 @ 2005年10月06日 21:37:00|评论(loading...)|编辑

新一篇: 钩子及其应用(三) | 旧一篇: 钩子及其应用(一)

评论

#hzfch 发表于2008-09-07 15:53:42  IP: 221.219.16.*
看了你的文章和提供的代码对我帮助很大
谢谢了
希望你写一些ring0 hook的文章
#linzhengqun 发表于2008-09-14 20:46:00  IP: 119.40.184.*
呵,不好意思我不是底层的开发人员,所以对Ring0的东西其实知之甚少。
不过作为一个优秀的程序员,应该有能力自学这些东西。
发表评论  


当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
Csdn Blog version 3.1a
Copyright © linzhenqun