“无忌,我教你的还记得多少?”
“回太师傅,我只记得一大半。”
“那,现在呢?”
“已经剩下一小半了。”
“那,现在呢?”
“我已经把所有的全忘记了!”
“好,你可以上了!”
羡慕张无忌,忘记了武功,打败了敌人;而我自己,忘记了武功,菜哭了自己。
已经一年多没有接触这个了,忘得干干净净,幸亏肌肉记忆还在,学起来十分亲切,废话不多说,进入正题。
SetWindowsHookEx制作键盘记录器
前言
Hook是程序设计中最为灵活多变的技巧之一,在windows下,Hook有两种含义:
1、系统提供的消息Hook机制,也就是我们今天要实现的hook,在后面会讲到。
2、自定义的Hook编程技巧
自定义的Hook编程技巧则是基于特定系统结构、文件结构、汇编语言的一种高级技术,运用自如后犹如手握屠龙刀倚天剑。
操作环境:
visual studio 2015
Windows 10
消息Hook
Windows消息hook主要通过SetWindowsHookEx去下钩,通过UnhookWindowsHookEx()去断钩,所以我们接下来主要学会用这俩个函数。
我们之所以可以进行消息Hook,是因为Windows的消息机制;简单来说:
Windows系统是建立在事件驱动的机制上的,每一个事件就是一个消息,每个运行中的程序,也就是所谓的进程,都维护者一个或多个消息队列,消息队列的个数取决于进程内包含的线程的个数。由于一个进程至少要拥有一个线程,所以进程至少要有一个消息队列。虽然Windows系统的消息分派是以线程为单位的,但并不是所有的线程都有消息队列,一个新创建的线程是没有消息队列的,只有当线程第一次调用GDI或USER32库函数的时候Windows才为线程创建消息队列。消息最终由属于线程的窗口来处理,普通的应用程序只能获取本线程的消息队列中的消息,也就是只能获得系统分派的、属于本线程的消息,换句话说,一个线程在运行过程中是不知道其它线程发生了什么事情的。但是有一类特殊的程序却可以访问其他线程的消息队列,那就是钩子程序。
(Windows消息机制还是十分重要的,这里我不多赘述,了解这些内容,足够咱们接下来的学习了,想要了解更多,建议看这篇文章https://zhuanlan.zhihu.com/p/42992978)
编写钩子程序是Windows系统提供给用户的一种对Windows运行过程进行干预的机制,通过钩子程序,Windows将内部流动的消息暴露给用户,使用户能够在消息被窗口管理器分派之前对其进行特殊的处理,比如在调试程序的时候跟踪消息流程。但是,任何事情都有其两面性,一些密码窃取工具就是利用系统键盘钩子截获其他程序的键盘消息,从而获取用户输入的密码,可见非法的钩子程序对计算机信息安全具有极大的危害性。
(那么我们今天就通过消息hook实现一个简单的键盘记录器,嘿嘿,知己知彼,百战不殆)!
消息Hook流程
第一步:安装钩子
最后一步:卸载钩子
中间步骤:我们要实现回调函数,实现我们自己的操作。例如获得键盘输入信息,并将其保存到txt文件中
通过setWindowsHookEx()实现键盘记录器
实现原理
当按下键盘,产生一个消息,按键消息加入到系统消息队列 操作系统从消息队列中取出消息,添加到相应的程序的消息队列中 ;
应用程序使用消息Hook从自身的消息队列中取出消息WM_KEYDOWN,调用消息处理函数。 我们可以在系统消息队列之间添加消息钩子,从而使得在系统消息队列消息发给应用程序之前捕获到消息。
可以多次添加钩子,从而形成一个钩子链,可以依次调用函数。
安装钩子
SetWindowsHookEx
WINUSERAPI
HHOOK
WINAPI
SetWindowsHookEx(
//钩子类型
_In_ int idHook,
//回调函数地址
_In_ HOOKPROC lpfn,
//实例句柄(包含有钩子函数)
_In_opt_ HINSTANCE hmod,
//线程ID,欲勾住的线程(为0则不指定,全局)
_In_ DWORD dwThreadId);
能设置的hook类型如下:
宏值 | 含义 |
---|---|
WH_MSGFILTER | 截获用户与控件交互的消息 |
WH_KEYBOARD | 截获键盘消息 |
WH_GETMESSAGE | 截获从消息队列送出的消息 |
WH_CBT | 截获系统基本消息,激活,建立,销毁,最小化,最大化,移动,改变尺寸等窗口事件 |
WH_MOUSE | 截获鼠标消息 |
WH_CALLWNDPROCRET | 截获目标窗口处理完毕的消息 |
我们这里hook键盘消息:
SetWindowsHookEx(
WH_KEYBOARD_LL, // low-level keyboard input events
HookProcedure, // 回调函数地址
GetModuleHandle(NULL), // A handle to the DLL containing the hook procedure
NULL //线程ID,欲勾住的线程(为0则不指定,全局)
);
使用API函数SetWindowsHookEx()把一个应用程序定义的钩子子程安装到钩子链表中。SetWindowsHookEx函数总是在Hook链的开头安装Hook子程。当指定类型的Hook监视的事件发生时,系统就调用与这个Hook关联的Hook链的开头的Hook子程。每一个Hook链中的Hook子程都决定是否把这个事件传递到下一个Hook子程。Hook子程传递事件到下一个Hook子程需要调用CallNextHookEx函数。
为钩子链中的下一个子程序设置钩子。在钩子子程中调用得到控制权的钩子函数在完成对消息的处理后,如果想要该消息继续传递,那么它必须调用另外一个 SDK