windows键盘的过滤(HOOK分发函数)

本文深入探讨了键盘过滤与反过滤技术,重点介绍了如何通过Hook\Device\Kbdclass驱动的分发函数实现键盘输入的过滤。首先获取键盘驱动对象并替换其分发函数,接着详细讲解了在不同驱动层级中实施键盘过滤的方法,包括端口驱动和类驱动之间的协作机制。最后,文章提到了寻找和替换关键回调函数的技巧,以实现在内核层拦截键盘输入。
摘要由CSDN通过智能技术生成

         前一篇文章讲述了进行键盘过滤,截取用户输入的方法。本篇文章开始更加深入地讨论键盘的过滤与反过滤对抗。无论是过滤还是饭过滤,原理都是过滤,取胜的关键在于谁第一个得到信息。

一种方发是Hook分发函数,即将键盘驱动的分发函数替换成自己的函数用来达到过滤的目的。

一、hook“\\Device\\Kbdclass”驱动的分发函数

1.获得类驱动对象

         首先要获得键盘类驱动对象,才能去替换下面的分发函数。这个操作较为简单,因为这个驱动的名字是“\\Device\\Kbdclass”,所以可以直接用函数ObReferenceObjectByName来获取。

//驱动的名字   

#define  KBD_DRIVER_NAME L"\\Driver\\Kdbclass"   

//当我们求得驱动对象指针时,将其放到这里   

PDRIVER_OBJECT KdbDriverObject;  

UNICODE_STRING uniNtNameString;  

  

//初始化驱动的名字字符串   

RtlInitUnicodeString(&uniNtNameString,KBD_DRIVER_NAME);  

//根据名字字符串来获得驱动对象   

status = ObReferenceObjectByName(  

                    &uniNtNameString,  

                    OBJ_CASE_INSENSITIVE,  

                    NULL,  

                    0,  

                    IoDriverObjectType,  

                    KernelMode,  

                    &KdbDriverObject,  

                    );  

if (!NT_SUCCESS(status))  

{  

    //如果失败   

    DbgPrint("MyAttach:Couldn't get the kbd driver Object\n");  

    return STATUS_SUCCESS;  

}  

else  

{  

    //凡是调用了Reference系列的函数都要通过调用ObDereferenceObject来解除引用   

    ObDereferenceObject(KdbDriverObject);  

}  

这样就获得了驱动对象,然后只要替换其分发函数就行了。

2、修改类驱动的分发函数指针

         虽然驱动对象不同,但是替换的方法还是一样的。值得注意的,必须保存原有的驱动对象的分发函数;否则,第一,替换之后将无法恢复;第二,完成我们自己的处理后无法继续调用原有的分发函数。除非所有的功能我们我们都编程代替原有驱动的分发函数做了,否则windows的整个键盘输入系统会直接崩溃。

       这里用到一个原子操作:InterlockedExchangePointer.这个操作的好处是,用户设置新的函数指针是原子的,不会被打断。插入其他可能要执行到调用这些分发函数的其他代码。

这个数组用来保存所有旧的指针   

ULONG i;  

PDRIVER_DISPATCH OldDispatchFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];  

.....  

//把所有的分发函数指针替换成我们自己编写的同一个分发函数   

for (i = 0 ; i <= IRP_MJ_MAXIMUM_FUNCTION ; ++i)  

{  

    //假设MyFilterDispatch是笔者已经写好的一个分发函数   

    OldDispatchFunction[i] = KdbDriverObject->MajorFunction[i];  

    //进行原子交换操作   

    InterlockedExchangePointer(  

                &KbdDriverObject->MajorFunction[i],  

                MyFilterDispatch  

        );  

}  

3.可能存在的问题

          在替换过程中,一部分分发函数已经被替换,另一部分分发函数还没有被替换,此时又刚好有几个连续的irp处理,中间具有相关性。这种情况下可能破坏他们之间的关

联。但这种几率较小,因此要确保函数替换完成之后再有效。   

        之后就可以编写过滤分发函数MyFilterDispatch了。

二、

3.类驱动之下的端口驱动

 

前面的过滤方式是替换分发函数指针。但是这是依然比较明显,因为分发函数的指针本来是已知的,如果安全监控软件有针对性地对这个指针进行检查和保护,就容易发现这个指针已经被替换掉的情况。

 

KbdClass被称为键盘类驱动,在Windows中,类驱动通常是指统管一类设备的驱动程序。不管是USB键盘,还是PS/2键盘均进过它,所以在这一层做拦截,能获得很好的通用性,类驱动之下和实际硬件交互的驱动被称为“端口驱动”。具体到键盘,i8042prt是PS/2键盘的端口驱动,USB键盘则是Kbdhid。

 

前面提到,键盘驱动的主要工作就是,当键盘上有按键按下引发中断时,键盘驱动从端口读出按键的扫描码,最终顺利地将它交给在键盘设备栈栈顶等待的那个主功能区号为IRP_MJ_READ的IRP。为了完成这个任务,键盘驱动使用了两个循环使用的缓冲区。

 

下面以比较古老的PS/2键盘为例进行介绍,因此下面介绍的端口驱动都是i8042prt。

 

i8042prt和KbdClass各自都有一个可以循环使用的缓冲区。缓冲区的每个单元都是一个KEYBOARD_INPUT_DATA结构,用来存放扫描码及其相关信息。在键盘驱动中,把这个循环使用的缓冲区叫做输入数据队列(input data queue),i8042prt的那个键盘缓冲区被叫做端口键盘输入队列,KbdClass的那个缓冲区被叫做类输入数据队列(class input data queue)。

 

 

 

4.端口驱动和类驱动之间的协作机制

 

当键盘上一个键被按下时,产生一个Make Code,引起键盘中断;当键盘上一个键被松开时,产生一个Break Code,引发键盘中断。键盘中断导致键盘服务例程执行,导致最终i8042prt的I8042KeyboardInterruptService被执行。

 

在I8042KeyboardInterruptService中,从端口读出按键的扫描码,放在一个KEYBOARD_INPUT_DATA中。将这个KEYBORAD_INPUT_DATA放入i8042prt的输入队列中。

 

在这个调用中,会调用上层处理输入的回调函数(也就是KbdClass处理输入数据函数),取走i8042prt的输入数据队列的

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值