首页
社区
课程
招聘
[原创]萌新逆向学习笔记——消息钩子键盘记录
发表于: 2020-8-11 20:13 8402

[原创]萌新逆向学习笔记——消息钩子键盘记录

2020-8-11 20:13
8402

我还记得小时候——大概08年那会儿,流行玩一款叫梦幻西游的网游。那时候我尚幼小,并没有诸如电脑病毒,木马等概念,反正拿到鼠标键盘就是一顿操作,玩玩游戏就行。直到有一天电脑突然弹出一个记事本exe,上面写道:“你的马面真的是垃圾。”本沉迷网游的我一下从梦中惊醒。还没等我反应过来,鼠标不受控制,右下角退出瑞星杀毒软件。后来两个游戏号陆续被盗,让我很是沉闷一段时间。

直到现在我学习了《逆向工程核心原理》,看到了DLL注入的一种方式——消息钩子注入。才忽然恍然大悟,仿佛抓到了当年被盗号的真相的尾巴。

阅读此文需要具备以下一定的知识:

本文是笔者的学习读书笔记,用以总结记录,如有错误,多多指出。倘若读者为逆向入门,也不妨尝试阅读此文。

如果读者没看懂代码不要紧代码部分可跳过,紧记住整个的流程,对关键的API产生印象。待日后熟悉了C++和一些API,也自然看得懂了。

从代码上来看,就是利用微软官方提供的API SetWindowsHookExA/SetWindowsHookExW来设置消息钩子,拦截特定的输入(如键盘和鼠标等)。

从整个过程来看:

而调用SetWindowsHookExA/`SetWindowsHookExW事实上就是在OS message queue和application message queue之间设置了一个钩子,有了它我们就可以在键盘输入这个事件到达目标程序前处理事件。因此你可以用来偷偷记录,亦或者是更改其内容。

很神奇吧,为什么是在OS message queue和application message queue间设置了钩子而不是在其他地方呢?这不是笔者说的算的,这是本来就存在的,是微软就是这么设计的,并不是什么黑科技。

而在OS message queue和application message queue之间的钩子,实际上是一个钩链。这意味着钩子可以设置多个。他们会像排队一样按顺序的处理输入的事件,钩子的代码里也可以决定是否把事件给下一个钩子处理。

1

首先看一下SetWindowsHookExW需要的参数。

关于KeyboardProc函数:
根据文档其定义如下:

参数说明:

首先看看实际调用SetWindowsHookExW的地方。这是一个自己写的DLL。他通过__declspec(dllexport)关键字来导出函数,来给我们写的程序(EXE)调用启动:
KeyHook.dll中内容:

请注意我们需要写两个PE文件,一个是exe,一个是dll。钩子设置以及实现的内容均在dll中,exe只是一个药引子,用来启动它。至于为什么要这样,这是大概是因为SetWindowsHookEx的使用必须是在模块当中。而这里用关键字导出两个函数,是为了给药引子程序来启动它。

可以看到SetWindowsHookEx的第二个参数KeyboardProc就是我们核心的内容,它记录了键盘的输入:

这里大概逻辑是先拿到当前调用DLL的文件名,判断是否为QQ.exe,如果是则记录在list中,当按下回车时,将list中记录的内容输入到debug消息。代码不难,前提是有C++基础。

SetWindowsHookEx的第三个参数myModule可以在DLL初始化时获得:

还是说明一下,这里的DllMain方法是DLL初始化时必定会走的地方,所以这里又是一个"微软规定"。

至此,键盘记录的核心实现内容已讲解完,剩下的还有"药引子"exe程序。
ConsoleApplication1.exe

这里主要看看核心代码即可,整个过程为DLL常规的调用。载入DLL->从DLL中获取函数->调用。倘若是第一次接触相关API建议看看相关文档,这里只涉及LoadLibraryAGetProcAddress两个API。请注意GetProcAddress获取的函数必须是通过先前关键字导出的函数,否则无法获取。

最后我们就能看到:

1

ps:注意使用DebugView来查看debug输出。因为笔者调用的函数是输出到debug日志里的而不是控制台上。

有一个明显的问题就是,记录的虚拟按键值无法区分大小写。这是因为提供的虚拟按键值并没有字母大小写之分见文档

当安装钩子后,药引子程序会卡死。经过相关百度和文档查阅可得知这是因为DLL和被挂钩子的程序位不一样。
如:笔者写的DLL为32位钩子,而目标程序为64位程序。
这样就会导致按键事件分发不到具体的钩子处理函数,而事件已经被标志为已挂钩,必须找到处理函数。这就会产生事件无法得到处理,程序卡死的现象:

Because hooks run in the context of an application, they must match the "bitness" of the application. If a 32-bit application installs a global hook on 64-bit Windows, the 32-bit hook is injected into each 32-bit process (the usual security boundaries apply). In a 64-bit process, the threads are still marked as "hooked." However, because a 32-bit application must run the hook code, the system executes the hook in the hooking app's context; specifically, on the thread that called SetWindowsHookEx. This means that the hooking application must continue to pump messages or it might block the normal functioning of the 64-bit processes

一句话来说就是32位的DLL钩子只能注入32位程序,同理64位也是如此。但问题是我的药引子程序也是32位的,DLL也是32位的,虽然笔者设置的是全局钩子,但为何还会卡死呢?

值得一提的是,当把DLL和药引子程序均设为64位时,药引子程序便没有卡死。

当从书里出来,自己实现一遍遇到各种各样的问题并解决后,原本觉得是天书的代码焕然一新,仿佛觉得能信手拈来。钩子注入的核心在于对拦截事件的处理。而作为新手的我们,应该先注重如何注入钩子,再去考虑如何处理事件。当两者已了然于胸,到时候离逆向之路也会走的更远了吧。

示例及源码下载:https://share.weiyun.com/3nCWkg6z

 
 
 
 

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2020-8-11 20:47 被psycongroo编辑 ,原因: 添加下载联机
收藏
免费 3
支持
分享
最新回复 (4)
雪    币: 3496
活跃值: (749)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
钩子勾住后,如何发送文本到VBA或者c#呢,比如搞个输入法!
2020-8-12 05:47
0
雪    币: 19
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
为什么getmodulefilename可以取到qq的路径呢 楼主不是通过自己写的“药引子”.exe加载并执行dll函数吗?
2020-8-22 15:17
0
雪    币: 3523
活跃值: (3454)
能力值: ( LV9,RANK:150 )
在线值:
发帖
回帖
粉丝
4
mb_nvqwrsuv 为什么getmodulefilename可以取到qq的路径呢 楼主不是通过自己写的“药引子”.exe加载并执行dll函数吗?
根据文档记载(https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamea)
getmodulefilename的作用是获取包含它模块的完全限定路径。而文中调用getmodulefilename的地方是在被注入到QQ的DLL中,因此getmodulefilename就可以活的QQ的路径了。
2020-8-22 16:54
0
雪    币: 449
活跃值: (262)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
qq的键盘钩子真的能挂上去吗,一输入qq就卡住了,可能qq有保护程序
2020-10-2 11:07
0
游客
登录 | 注册 方可回帖
返回
//