【Day 14】- 今天来实作一个键盘监听器

Agenda

  • 资安宣言
  • 测试环境与工具
  • 技术原理与程序码
  • References
  • 下期预告

资安宣言


撰写本系列文章目的在於提升资讯安全之实务能力,
并透过实作体悟到资讯安全领域的重要性,
本系列所有文章之内容皆有一定技术水平,
不得从事非法行为、恶意攻击等非法活动,
「一切不合法规之行为皆受法律所约束」,
为了避免造成公司、厂商或玩家之间困扰,
所有实作不会拿已上市产品、Online Game 等等来作范例学习,
且部分具有深度、价值之内容,将会提升一定阅读门槛(不对该技术做分析、解说),
请勿透过本系列文章所学,从事任何非法活动,请不要以身试法!!!


测试环境与工具

技术原理与程序码

首先开始前要先说一下,
小弟我目前还属於菜鸟阶段,正不断努力学习中,
若有发现错误或不妥之处还请不吝赐教。
欢迎大家多多留言,互相交流交流。

那就开始今天的主题吧~~
/images/emoticon/emoticon07.gif
/images/emoticon/emoticon39.gif

今天来讲讲关於 PS/2 的键盘过滤驱动,
简称为:「键盘监听/侧录器」

首先,按下键盘按键後的流程大致上是这样的:

  1. 按下实体键盘按键
  2. 产生 IRQL
  3. 键盘驱动:i8042prt
  4. 处理讯息:KbdClass
  5. 开始进入 User mode,发送讯号到对应的视窗中

中断要求层级 Interrupt Request Level (IRQL)
在电脑系统中,无时无刻都在大量处理着资讯、讯息、程序...,
这个中断要求层级就是要让一些更重要的事情来「插队的」,
意思就是说,当有一个优先顺序较高的「中断要求」来临时,
它就能被优先执行,因此优先顺序较低的就会被打断,
所以你有想到什麽东西中断层级是最高的?当然是按下电源按钮、拔插头...。


图片内容取自 WIKI:https://zh.wikipedia.org/wiki/IRQL

当按下键盘,会产生「硬体中断」,中断层级很高,也是因为这样系统才能捕捉到讯息,
所以当我们按下键盘,User mode 是有那麽一瞬间都停了下来,在等待键盘讯息的处理,
同时 IRP 讯息正在由下而上一层一层的传递,最终会到 User mode 应用程序中,
也就是大家打出来的文字。

所以~
要如何拦截键盘讯息呢?

有两种方法:
作法一:
自己建立一个虚拟的 Device,让这个虚拟的 Device Attach 上去 KbdClass。

作法二:
想办法拿到键盘所使用的虚拟设备(KbdClass),然後 HOOK 它!

先来讲第一种较脚踏实地的作法,
使用 IoCreateDevice 建立虚拟的 Device,
要怎麽知道现在有几个虚拟的 Device?
使用 WinObj.exe
然後你就会看到:KeyboardClass0

这是在 VMWare 上的结果,若在实体机结果就不相同。

所以将建立好的虚拟 Device Attach 上去 KbdClass0,
当然,键盘可能很多个,所以 KbdClass0 可能不只一个,
KbdClass0、KbdClass1... ...要自己列举,然後通通 Attach 上去!!
Attach 函数就用 IoAttachDevice

再来,我们不应该在读取 IRP 时做一些耗时的动作,例如更改按键...等,
因为这样会耽误 IRP 传递的速度,所以要在读 IRP 这个动作完之後,
再来做一些其他操作,不然会完蛋!

大概就是设定 IoSetCompletionRoutine

最後拿到 IRP,此时就是设一个 FUNC 来做想做的事情拉~
把 IRP 读进来放进指向 PKEYBOARD_INPUT_DATA 结构的变数中,

typedef struct _KEYBOARD_INPUT_DATA {
  USHORT UnitId;
  USHORT MakeCode;
  USHORT Flags;
  USHORT Reserved;
  ULONG  ExtraInformation;
} KEYBOARD_INPUT_DATA, *PKEYBOARD_INPUT_DATA;

来源:KEYBOARD_INPUT_DATA

其中的 MakeCode 就是键盘按键编号了,可以把它改成别的,也可以直接印出来...等等,

效果图:

再来讲一下第二种作法,这种作法相当简单,实作起来也很容易,
直接想办法拿到键盘所使用的虚拟设备(KbdClass0),
然後把 IRP_MJ_READ 改成自己写好的 FUNC,

使用 ObReferenceObjectByName 拿到虚拟设备(KbdClass0),
保存一份原本的 IRP_MJ_READ FUNC Address,
然後就是:xxxDriver->MajorFunction[IRP_MJ_READ] = MyHookDispatch;
这样应该很清楚惹吧 XD

以上所讲仅限用於 PS/2 的键盘~
不支援 USB 键盘,可直接在 VMWare 中使用,因为 VMWare 预设就是跑 i8042prt。

有空再来写一篇支援 USB 键盘的文章,因为 USB 键盘和 PS/2 差很大,
它没有固定的 Device Name,只有 Driver Name,而且是走 kbdhid.sys,
很难搞定,难度大幅提升,要自己从 USB Driver Stack 中列举,
所以假设有哪天忽然很闲,我应该就会再发一篇 XD,订阅起来,文章不漏接。

好了,这篇就讲到这结束了,
大家若有发现哪里写得不好或错误的地方,都留个言讨论一下吧 XD
那我们下期见 o( ̄▽ ̄)ブ

References

下期预告

  • 【Day 15】- 今天来实作一个 Kernel mode Thread
  • 如果你/你喜欢我的文章,请记得订阅按赞分享并且打开小铃铛哦
  • 这样就能在第一时间收到通知,也不会错过任何文章啦~~

<<:  第11章:控制背景运行服务介绍

>>:  015-登入

[Day 18]所以我说那个酱汁呢(前端篇)

挑战目标: MockNative Camp 这次的挑战应该就止步於此了,在前端上我太弱小LA,没有事...

Day 5 ( 入门 ) 指北针

指北针 教学原文参考:指北针 这篇文章会介绍如何使用「方位感测」搭配「显示箭头数字」积木,实作指北针...

Day 6 ( 入门 ) 抽奖轮盘

抽奖轮盘 教学原文参考:抽奖轮盘 这篇文章会介绍,如何在 Scratch 3 里使用绘制角色造型、变...

Day19 - 使用Django进行自动化测试 (1)

今天的实作内容主要根据教学网站进行。 在软件开发流程的测试,以阶段角度来看可以分为: 单元测试:测试...

iPhone黑屏并且无法打开,如何修复?

iPhone黑屏是设备的常见问题。 案例1:“我的iPhone 7 Plus 摔倒地上後屏幕黑屏了。...