网站已经改版为Wordpress版本,这里是旧版本的快照,请不要在页面中留言.

Windows键盘过滤驱动示例代码,附VS2010工程

键盘过滤

本文出自悠然品鉴原创,转载请注明出处:http://www.youranshare.com/codeorg/sid/133.html

今天研究了Windows内核的过滤驱动的写法,看着书把原理搞懂了,本想着写个实例试试看,结果进入了蓝屏的死循环中,不过还好,最后找到了错误的原因,还是编写成功了,完成了驱动对键盘的过滤,并且这个键盘驱动是可以及时卸载的,不用按下任意按键后才能完成卸载操作。

先说一下基本的原理吧

在驱动中有个设备栈的概念,类似与数据结构的堆栈,栈内的成员是设备Device,对于在同一个设备栈中的设备,IRP的路由方向是从栈顶à栈底,而对于新添加的设备总是位于设备栈的顶部。

所以,我们要想过滤键盘的信息,那么直接创建一个我们自定义的过滤驱动,然后挂载在键盘驱动之上形成设备栈,这样对于键盘操作的IRP我们就了如指掌了.

键盘过滤驱动的基本步骤:

获取到键盘设备的指针,如果失败就终止

创建自己的过滤设备,失败就终止

设置READ等例程(通过Read拦截的)

将自己的过滤设备挂载到键盘设备上,失败就终止

在READ例程中转发IRP到底层设备,并切对IRP设置完成例程,因为在底层设备中这些IRP将会被序列化,然后一个一个的被完成,所以我们这里需要记录一共向底层设备发送了多少了IRP

当底层完成了一个IRP处理后会调用我们设置的完成例程,在完成例程中可以获取到按键的信息,每当完成一个IRP,我们的IRP计数器要减少一个,这样就可以知道当前还有多少个IRP是在完成中的(挂起)

卸载过滤驱动的时候首先移除掉设备栈内的当前的设备,然后判断是否有IRP还处于完成中,因为这些IRP在完成后会调用我们设置的完成例程,所以必须要等待经过当前例程转发的IRP全部完成才能删除当前的设备,否则如果直接删除当前设备的话会照成后续的IRP无法找到完成例程,导致蓝屏

看一下基本的关键代码

//设备扩展

typedef struct DEVICE_EXTENSION 
{
         PDRIVER_OBJECT pDriverObject;//驱动对象
         PDEVICE_OBJECT pDevice;//设备对象
         PDEVICE_OBJECT pTarget;//挂载的下层
         LONG nIrpsInQueue;           //Irp 队列中剩余 未操作完成的IRP数量
         PIRP pLastIrp;              //保存每次转发的IRP,当卸载驱动的时候这个保存的是最后一个IRP
                                                                 //通过取消这个IRP 来完成所有的IRP
}*PDEVICE_EXTENSION;

//Read转发操作

NTSTATUS HandlerRead(PDEVICE_OBJECT DeviceObject,PIRP Irp){
         NTSTATUS status = STATUS_UNSUCCESSFUL;
         KdPrint(("READ:"));
         PDEVICE_EXTENSION pExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
         IoCopyCurrentIrpStackLocationToNext(Irp);
         IoSetCompletionRoutine(Irp,ReadCompleteRoutine,DeviceObject,TRUE,TRUE,TRUE);
 
         //增加IRP 队列长度
         pExt->nIrpsInQueue++;
         pExt->pLastIrp = Irp;
         return IoCallDriver(pExt->pTarget,Irp);
}

//卸载例程

void UnLoad(PDRIVER_OBJECT pDriverObject){
         PDEVICE_OBJECT pDevice = NULL;
         LARGE_INTEGER liDelay;
         pDevice = pDriverObject->DeviceObject;
         if (NULL==pDevice)
         {
                   return;
         }
         if (pDevice->DeviceExtension==NULL)
         {
                   return;
         }
         PDEVICE_EXTENSION pExt = (PDEVICE_EXTENSION)pDevice->DeviceExtension;
         //首先要移除设备栈,移除之后的IRP将不会被过滤
         IoDetachDevice(pExt->pTarget);
 
 
         //对于为完成的IRP,因为只前通过IoSetCompletionRoutine已经设置IO完成例程
         //那么对于未完成的IRP ,在完成之后会调用 该层设备的函数
         //如果 IRP队列还在,这时候直接删除设备
         //当剩余的IRP 完成之后 之前设置的IO完成例程已经不存在了
         //这样会照成 蓝屏
         //所以需要等待 IO 完成之后再去删除 该层设备
         liDelay.QuadPart = -1000000;
         while(pExt->nIrpsInQueue>0)
         {
                   KeDelayExecutionThread(KernelMode,FALSE,&liDelay);
                   KdPrint(("剩余挂起IRP:%dn",pExt->nIrpsInQueue));
                   if(pExt->nIrpsInQueue==1)
                   {
                            //取消掉最后一个IRP
                            IoCancelIrp(pExt->pLastIrp);
                   }
         }
 
         //移除设备
         KdPrint(("移除设备n"));
         IoDeleteDevice(pDevice);
         return ;
}

                                             

附上VS2010编写的示例工程

解压密码 yscode

百度网盘下载地址 http://pan.baidu.com/s/14H7Ue



  • 标签:
  • NT键盘过滤驱动
  • 键盘过滤
  • 过滤驱动
网站已经改版为Wordpress版本,这里是旧版本的快照,请不要在页面中留言.