键盘过滤
《Windows内核安全与驱动开发》阅读笔记 -- 索引目录
键盘过滤
1.如何绑定需要过滤的设备
键盘在底层存在一个驱动,即 \Driver\kbdclass,我们通过ObReferenceObjectByName这个非公开函数来获取这个驱动指针,
然后遍历该驱动下面的设备对象,见到一个绑定一个,这样就最终可以实现驱动的绑定。
下面我们使用工具DeviceTree来查看一下 这个 \Driver\kbdclass,之后我们就知道如何绑定了。
现在,我们使用这个API来获取设备对象指针
之后,我们就开始while()来遍历这个设备,如果存在就像之前那样来创建过滤设备来绑定该目标设备,这很好理解。
2. 拓展设备的应用
其实我们之前在“端口过滤”中,我们使用数组来存储每个设备对象,这其实完全没有必要。
我们可以直接来使用过滤设备中的拓展设备,这样我们在派遣函数中,可以直接拿到拓展设备,直接来处理即可。
下面其拓展设备的数据结构,我们来讲解一下有关重点内容:
下面对于拓展设备这很好理解,就是底层设备、目标设备、过滤设备三者直接全部存放在这里,这样做有什么好处呢?
我们下面来看看IRP的处理,我们可以直接调用IoCallDriver将其分发到底层设备,而不用像之前那样,先For循环判断是哪个设备,然后找对应设备。
这个逻辑要理解,可以大大减少你的代码量。
3. 无关IRP请求的处理
过滤设备要处理各种IRP,这代码处理了四种:通用、IRP_MJ_POWER、IRP_MJ_PNP、IRP_MJ_READ(处理键盘过滤的)
1)通用型
这很好理解,并不需要特殊处理,直接分发给下层设备即可。
2)IRP_MJ_POWER
这个电源的派发函数,需要调用专门的处理电源的派发函数 PoStartNextPowerIrp来进行处理。
3)IRP_MJ_PNP
这个是即插即用的设备,我们需要处理MinorFuncion为 IRP_MN_REMOVE_DEVICE时的情况,
此时就需要解除过滤设备的绑定,然后删除自己的过滤设备,这顿操作很好理解,当然,这个请求也是要派发下去的。
4. 读IRP请求的处理
现在我们来处理过滤中的读请求,键盘输入的本质就是通过驱动的读请求向键盘设备中读取相关信息,其操作如下:
如上图,我们现在要过滤请求,应该怎么处理呢?是直接像COM端口过滤一样直接在派发函数中过滤么?
这当然是不行的,因为我们在派发函数中,只是获得了一个读请求,而读的信息此时还没到达键盘设备自然不能获取。
因此我们现在要设置完成回调函数,其在派发函数中设置如下:
现在我们来看看其回调函数的核心代码逻辑是什么样的:
我们现在判断IRP的返回值,只有当返回成功时,才说明里面存在信息,直接从Buffer缓冲区读取就好,读取到的数据依次打印出来。
5. 处理的细节
1)gC2pKeyCount 绑定处理个数
我们在设置回调和完成回调时,依次 gC2pKeyCount++ 和 gC2pKeyCount--,为什么这么做呢?
因此当我们卸载设备时,我们要确保这里不存在还需要处理的消息,若gC2pKeyCount不为零,则需要继续延迟等待处理。
2)打开驱动对象时的驱动类型
这里我们使用一个未导出的内部变量,注意一定要用指针类型,否则一定概率获取不到对象。(这里不清楚原因,但是确实出现过这种错误)