键盘过滤驱动(键盘过滤驱动「终于解决」)

发布时间:2025-12-10 19:23:04 浏览次数:12

键盘过滤驱动「终于解决」-键盘过滤驱动怎么安装

键盘过滤驱动「终于解决」在笔者接触驱动到现在以来一以后大半个月的时间,从中让我深深的体会到了万事开头难,以及学习持之以恒的重要性。笔者也是个驱动新人,开始接触驱动的时候看着张帆的《Windows驱动开发技术详解》讲的挺细,对新手来说是个不错的学习资料,但是更重要的还是自己要多动手练习,笔者在学习到同步操作的相关知识的时候,实在是看天书。最后还是放弃了学习本书。再找了本楚狂人的资料学习,感觉本书对新手来说还是比较吃力的,其中笔者就是这样,很多知识点不是很明白,只能凭借自己的感觉去做,不过造成的后果就是无情的蓝屏^_^。最终要的是笔者

在笔者接触驱动到现在以来一以后大半个月的时间,从中让我深深的体会到了万事开头难,以及学习持之以恒的重要性。笔者也是个驱动新人,开始接触驱动的时候看着张帆的《Windows驱动开发技术详解》讲的挺细,对新手来说是个不错的学习资料,但是更重要的还是自己要多动手练习,笔者在学习到同步操作的相关知识的时候,实在是看天书。最后还是放弃了学习本书。再找了本楚狂人的资料学习,感觉本书对新手来说还是比较吃力的,其中笔者就是这样,很多知识点不是很明白,只能凭借自己的感觉去做,不过造成的后果就是无情的蓝屏^_^。最终要的是笔者坚持下来了。

今天来分享下学习过程中,编写键盘过滤的心得。关于工作原理因为笔者也是一知半解,就不在阐述。

我们的目的就是将自己的驱动设备挂接/driver/kbdclass驱动下的所有设备,如图所示:

然后通过处理来达到过滤我们想要的按键信息。挂接后的驱动中的第一个设备就是我们的过滤设备,当有按键触发,按键信息首先会被我们自己写的设备所拦截,但是这时候拦截到的是没有处理的按键信息,那改怎么处理呢?我们去问键盘驱动,当我们拦截到按键IRP的时候先不做处理,给IRP设置完成回调函数并传递给键盘驱动的设备。这样一来,当按键IRP被键盘驱动处理完毕之后就会执行我们的回调函数,这时我们在处理按键信息。当卸载我们的过滤设备的时候会有个麻烦就是会有个IRP已经设备了回调例程,并且在等待按键触发。如果这个IRP在没有处理之前就卸载掉我们的过滤驱动,就会引发按键蓝盘。为什么会蓝屏呢?因为这个IRP是已经被设置了回调函数,当IRP被处理完成之后去找我们设置的回调函数,因为我们在IRP没有处理之前已经卸载了,所以这时IRP已经找不到回调函数了,所以导致蓝屏。大部分都的解决方案是在处理IRP的时候放置个计数器,当计数器不为0的时候说明还有IRP未完成,这是卸载的时候就用while来一直等待这个IRP完成,如果我们要是不按键盘的话,它会无休止的等待下去,并且也影响系统性能。
笔者通过相关资料的查阅,另个解决方案就是做个代理IRP,然后保存原来的IRP,因为我们可以取消自己的IRP。在卸载的时候先卸载我们的代理IRP,然后在发送原来保存的IRP,这样就很好的解决了无限的等待的BUG…但是笔者也没有找到相关代码,只好自己动手试。经过一下午的测试,笔者发现我们只需要做一个代理IRP即可,并不需要保存原来的IRP,卸载的时候直接取消我们的IRP,并不需要重新发送个IRP。下面我们来通过具体代码学习一下键盘过滤驱动。

首先:

[c-sharp]view plaincopy

//驱动入口

extern“C”NTSTATUSDriverEntry(INPDRIVER_OBJECTpDriverObject,INPUNICODE_STRINGpRegistryPath)

{

NTSTATUSstatus;

DbgPrint(“驱动加载开始…/n”);

pDriverObject->DriverUnload=FilterUnload;

//设置读取派遣函数

pDriverObject->MajorFunction[IRP_MJ_READ]=FilterDispatchRoutin;

BindDevice(pDriverObject);

DbgPrint(“驱动加载结束…/n”);

returnSTATUS_SUCCESS;

}

[c-sharp]view plaincopy

//驱动入口

extern“C”NTSTATUSDriverEntry(INPDRIVER_OBJECTpDriverObject,INPUNICODE_STRINGpRegistryPath)

{

NTSTATUSstatus;

DbgPrint(“驱动加载开始…/n”);

pDriverObject->DriverUnload=FilterUnload;

//设置读取派遣函数

pDriverObject->MajorFunction[IRP_MJ_READ]=FilterDispatchRoutin;

BindDevice(pDriverObject);

DbgPrint(“驱动加载结束…/n”);

returnSTATUS_SUCCESS;

}

在主函数中,调用BindDevice来实现过滤驱动的创建与绑定,代码如下:

[cpp]view plaincopy

//设备类型

extern“C”POBJECT_TYPEIoDriverObjectType;

NTSTATUSBindDevice(PDRIVER_OBJECTpDriverObject)

{

NTSTATUSstatus;

UNICODE_STRINGuniNtNameString;

//要打开的驱动对象

PDRIVER_OBJECTKbdDriverObject=NULL;

//驱动对象的设备

PDEVICE_OBJECTkbdDeviceOjbect;

//初始化一个字符串,就是kbdclass驱动的名子

RtlInitUnicodeString(&uniNtNameString,KBD_DRIVER_NAME);

//根据名字打开驱动对象

status=ObReferenceObjectByName(

&uniNtNameString,

OBJ_CASE_INSENSITIVE,

NULL,

0,

IoDriverObjectType,

KernelMode,

NULL,

(PVOID*)&KbdDriverObject);

//如果失败了就直接返回

if(!NT_SUCCESS(status))

{

DbgPrint(“打开设备失败…/n”);

returnstatus;

}

//调用ObReferenceObjectByName会导致对驱动对象的引用计数增加

//必须响应的调用解引用ObDereferenceObject

ObDereferenceObject(pDriverObject);

DbgPrint(“打开成功,解除引用…/n”);

//键盘驱动的第一个设备

kbdDeviceOjbect=KbdDriverObject->DeviceObject;

while(kbdDeviceOjbect!=NULL)

{

//创建并绑定过滤设备

CreateDevice(pDriverObject,kbdDeviceOjbect);

//下一个设备

kbdDeviceOjbect=kbdDeviceOjbect->NextDevice;

}

returnstatus;

}

[cpp]view plaincopy

//设备类型

extern“C”POBJECT_TYPEIoDriverObjectType;

NTSTATUSBindDevice(PDRIVER_OBJECTpDriverObject)

{

NTSTATUSstatus;

UNICODE_STRINGuniNtNameString;

//要打开的驱动对象

PDRIVER_OBJECTKbdDriverObject=NULL;

//驱动对象的设备

PDEVICE_OBJECTkbdDeviceOjbect;

//初始化一个字符串,就是kbdclass驱动的名子

RtlInitUnicodeString(&uniNtNameString,KBD_DRIVER_NAME);

//根据名字打开驱动对象

status=ObReferenceObjectByName(

&uniNtNameString,

OBJ_CASE_INSENSITIVE,

NULL,

0,

IoDriverObjectType,

KernelMode,

NULL,

(PVOID*)&KbdDriverObject);

//如果失败了就直接返回

if(!NT_SUCCESS(status))

{

DbgPrint(“打开设备失败…/n”);

returnstatus;

}

//调用ObReferenceObjectByName会导致对驱动对象的引用计数增加

//必须响应的调用解引用ObDereferenceObject

ObDereferenceObject(pDriverObject);

DbgPrint(“打开成功,解除引用…/n”);

//键盘驱动的第一个设备

kbdDeviceOjbect=KbdDriverObject->DeviceObject;

while(kbdDeviceOjbect!=NULL)

{

//创建并绑定过滤设备

CreateDevice(pDriverObject,kbdDeviceOjbect);

//下一个设备

kbdDeviceOjbect=kbdDeviceOjbect->NextDevice;

}

returnstatus;

}

在这里说一下ObReferenceObjectByName函数,该方法没有被导出,知我我们在头文件中声明一下即可使用,声明如下:

[cpp]view plaincopy

//根据名字获取设备对象,此函数没有公开,声明一下就可以直接使用了

extern“C”NTSTATUSObReferenceObjectByName(

PUNICODE_STRINGobjectName,

ULONGAttributes,

PACCESS_STATEAccessState,

ACCESS_MASKDesiredAccess,

POBJECT_TYPEobjectType,

KPROCESSOR_MODEaccessMode,

PVOIDParseContext,

PVOID*Object);

[cpp]view plaincopy

//根据名字获取设备对象,此函数没有公开,声明一下就可以直接使用了

extern“C”NTSTATUSObReferenceObjectByName(

PUNICODE_STRINGobjectName,

ULONGAttributes,

PACCESS_STATEAccessState,

ACCESS_MASKDesiredAccess,

POBJECT_TYPEobjectType,

KPROCESSOR_MODEaccessMode,

PVOIDParseContext,

PVOID*Object);

在BindDevice方法中,调用了一个CreateDevice方法,该方法负责创建过滤设备,并且附加在目标设备上,具体代码如下:

[cpp]view plaincopy

//创建设备

NTSTATUSCreateDevice(INPDRIVER_OBJECTpDriverObject,INPDEVICE_OBJECToldDevObj)

{

NTSTATUSstatus;

PDEVICE_OBJECTpDevObj;

//谁被扩展

PDEVICE_EXTENSIONpDevExt;

status=IoCreateDevice(pDriverObject,

sizeof(PDEVICE_EXTENSION),

NULL,

oldDevObj->DeviceType,//设备类型需要和被附加的设备类型相等

0,

FALSE,//如果指定设备是独占的,大部分驱动程序设置这个值为FALSE,如果不是独占的话设置为TRUE.

&pDevObj);

if(!NT_SUCCESS(status))

{

DbgPrint(“创建设备失败…./n”);

returnNULL;

}

pDevExt=(PDEVICE_EXTENSION)pDevObj->DeviceExtension;

//存储设备对象

pDevExt->pDevice=pDevObj;

//绑定前原设备

pDevExt->poldDevice=oldDevObj;

//标志位

pDevObj->Flags|=oldDevObj->Flags&(DO_BUFFERED_IO|DO_DIRECT_IO|DO_POWER_PAGABLE);

//该标识指示I/O管理器对所有发送到控制设备对象的Open请求进行安全检测

pDevObj->Characteristics=oldDevObj->Characteristics;

//绑定设备

PDEVICE_OBJECTtopDev=IoAttachDeviceToDeviceStack(pDevObj,oldDevObj);

if(topDev==NULL)

{

//如果绑定失败,销毁设备

IoDeleteDevice(pDevObj);

status=STATUS_UNSUCCESSFUL;

returnstatus;

}

//将绑定的设备和原始设备放入设备扩展中

pDevExt->poldDevice=oldDevObj;

pDevExt->pbindDevice=topDev;

pDevObj->Flags=pDevObj->Flags&~DO_DEVICE_INITIALIZING;

KdPrint((“绑定成功../n”));

returnSTATUS_SUCCESS;

}

[cpp]view plaincopy

//创建设备

NTSTATUSCreateDevice(INPDRIVER_OBJECTpDriverObject,INPDEVICE_OBJECToldDevObj)

{

NTSTATUSstatus;

PDEVICE_OBJECTpDevObj;

//谁被扩展

PDEVICE_EXTENSIONpDevExt;

status=IoCreateDevice(pDriverObject,

sizeof(PDEVICE_EXTENSION),

NULL,

oldDevObj->DeviceType,//设备类型需要和被附加的设备类型相等

0,

FALSE,//如果指定设备是独占的,大部分驱动程序设置这个值为FALSE,如果不是独占的话设置为TRUE.

&pDevObj);

if(!NT_SUCCESS(status))

{

DbgPrint(“创建设备失败…./n”);

returnNULL;

}

pDevExt=(PDEVICE_EXTENSION)pDevObj->DeviceExtension;

//存储设备对象

pDevExt->pDevice=pDevObj;

//绑定前原设备

pDevExt->poldDevice=oldDevObj;

//标志位

pDevObj->Flags|=oldDevObj->Flags&(DO_BUFFERED_IO|DO_DIRECT_IO|DO_POWER_PAGABLE);

//该标识指示I/O管理器对所有发送到控制设备对象的Open请求进行安全检测

pDevObj->Characteristics=oldDevObj->Characteristics;

//绑定设备

PDEVICE_OBJECTtopDev=IoAttachDeviceToDeviceStack(pDevObj,oldDevObj);

if(topDev==NULL)

{

//如果绑定失败,销毁设备

IoDeleteDevice(pDevObj);

status=STATUS_UNSUCCESSFUL;

returnstatus;

}

//将绑定的设备和原始设备放入设备扩展中

pDevExt->poldDevice=oldDevObj;

pDevExt->pbindDevice=topDev;

pDevObj->Flags=pDevObj->Flags&~DO_DEVICE_INITIALIZING;

KdPrint((“绑定成功../n”));

returnSTATUS_SUCCESS;

}

通过以上代码可以实现过滤设备的绑定,绑定了之后还是主要处理派遣函数,功能如下:

[cpp]view plaincopy

//派遣函数

NTSTATUSFilterDispatchRoutin(INPDEVICE_OBJECTpDevObj,INPIRPpIrp)

{

PIO_STACK_LOCATIONcurrentIrpStack;

PDEVICE_EXTENSIONpDevExt;

//得到设备扩展

pDevExt=(PDEVICE_EXTENSION)pDevObj->DeviceExtension;

//得到当前irp包

currentIrpStack=IoGetCurrentIrpStackLocation(pIrp);

//将当前irp复制到下层设备irp堆栈

IoCopyCurrentIrpStackLocationToNext(pIrp);

//保存原来的irp

//pDevExt->tagIrp=pIrp;

//代理irp

pDevExt->proxyIrp=pIrp;

//设置当irp完成时的回调例程

IoSetCompletionRoutine(pDevExt->proxyIrp,CallBackKbdFilter,pDevObj,TRUE,TRUE,TRUE);

DbgPrint(“irp回调例程设置完毕…/n”);

returnIoCallDriver(pDevExt->poldDevice,pDevExt->proxyIrp);

}

[cpp]view plaincopy

//派遣函数

NTSTATUSFilterDispatchRoutin(INPDEVICE_OBJECTpDevObj,INPIRPpIrp)

{

PIO_STACK_LOCATIONcurrentIrpStack;

PDEVICE_EXTENSIONpDevExt;

//得到设备扩展

pDevExt=(PDEVICE_EXTENSION)pDevObj->DeviceExtension;

//得到当前irp包

currentIrpStack=IoGetCurrentIrpStackLocation(pIrp);

//将当前irp复制到下层设备irp堆栈

IoCopyCurrentIrpStackLocationToNext(pIrp);

//保存原来的irp

//pDevExt->tagIrp=pIrp;

//代理irp

pDevExt->proxyIrp=pIrp;

//设置当irp完成时的回调例程

IoSetCompletionRoutine(pDevExt->proxyIrp,CallBackKbdFilter,pDevObj,TRUE,TRUE,TRUE);

DbgPrint(“irp回调例程设置完毕…/n”);

returnIoCallDriver(pDevExt->poldDevice,pDevExt->proxyIrp);

}

注意的是在处理派遣函数的时候我们将IRP换成我们自己的IRP,这样就能达到取消IRP的目的,我们给IRP设置了回调函数,当IRP处理完成的时候就去执行回调函数,回调函数如下:

[cpp]view plaincopy

//flagsforkeyboardstatus

#defineS_SHIFT1

#defineS_CAPS2

#defineS_NUM4

staticintkb_status=S_NUM;

void__stdcallprint_keystroke(UCHARsch)

{

UCHARch=0;

intoff=0;

if((sch&0x80)==0)//make

{

if((sch<0x47)||

((sch>=0x47&&sch<0x54)&&(kb_status&S_NUM)))//NumLock

{

ch=asciiTbl[off+sch];

}

switch(sch)

{

case0x3A:

kb_status^=S_CAPS;

break;

case0x2A:

case0x36:

kb_status|=S_SHIFT;

break;

case0x45:

kb_status^=S_NUM;

}

}

else//break

{

if(sch==0xAA||sch==0xB6)

kb_status&=~S_SHIFT;

}

if(ch>=0x20&&ch<0x7F)

{

DbgPrint(“%C/n”,ch);

}

}

NTSTATUSCallBackKbdFilter(INPDEVICE_OBJECTDeviceObject,INPIRPIrp,INPVOIDContext)

{

PIO_STACK_LOCATIONcurrentIrp;

PKEYBOARD_INPUT_DATAkeyData;

currentIrp=IoGetCurrentIrpStackLocation(Irp);

if(NT_SUCCESS(Irp->IoStatus.Status))

{

keyData=(PKEYBOARD_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer;

//DbgPrint(“扫描码:%x”,keyData->MakeCode);

DbgPrint(“键盘:%s”,keyData->Flags?”弹起”:”按下”);

print_keystroke((UCHAR)keyData->MakeCode);

}

if(Irp->PendingReturned)

{

IoMarkIrpPending(Irp);

}

returnIrp->IoStatus.Status;

}

[cpp]view plaincopy

//flagsforkeyboardstatus

#defineS_SHIFT1

#defineS_CAPS2

#defineS_NUM4

staticintkb_status=S_NUM;

void__stdcallprint_keystroke(UCHARsch)

{

UCHARch=0;

intoff=0;

if((sch&0x80)==0)//make

{

if((sch<0x47)||

((sch>=0x47&&sch<0x54)&&(kb_status&S_NUM)))//NumLock

{

ch=asciiTbl[off+sch];

}

switch(sch)

{

case0x3A:

kb_status^=S_CAPS;

break;

case0x2A:

case0x36:

kb_status|=S_SHIFT;

break;

case0x45:

kb_status^=S_NUM;

}

}

else//break

{

if(sch==0xAA||sch==0xB6)

kb_status&=~S_SHIFT;

}

if(ch>=0x20&&ch<0x7F)

{

DbgPrint(“%C/n”,ch);

}

}

NTSTATUSCallBackKbdFilter(INPDEVICE_OBJECTDeviceObject,INPIRPIrp,INPVOIDContext)

{

PIO_STACK_LOCATIONcurrentIrp;

PKEYBOARD_INPUT_DATAkeyData;

currentIrp=IoGetCurrentIrpStackLocation(Irp);

if(NT_SUCCESS(Irp->IoStatus.Status))

{

keyData=(PKEYBOARD_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer;

//DbgPrint(“扫描码:%x”,keyData->MakeCode);

DbgPrint(“键盘:%s”,keyData->Flags?”弹起”:”按下”);

print_keystroke((UCHAR)keyData->MakeCode);

}

if(Irp->PendingReturned)

{

IoMarkIrpPending(Irp);

}

returnIrp->IoStatus.Status;

}

函数就不说明了,主要就是对makecode的处理,不过在回调函数中引用了对照表,如下:

[c-sharp]view plaincopy

unsignedcharasciiTbl[]={

0x00,0x1B,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x30,0x2D,0x3D,0x08,0x09,//normal

0x71,0x77,0x65,0x72,0x74,0x79,0x75,0x69,0x6F,0x70,0x5B,0x5D,0x0D,0x00,0x61,0x73,

0x64,0x66,0x67,0x68,0x6A,0x6B,0x6C,0x3B,0x27,0x60,0x00,0x5C,0x7A,0x78,0x63,0x76,

0x62,0x6E,0x6D,0x2C,0x2E,0x2F,0x00,0x2A,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x38,0x39,0x2D,0x34,0x35,0x36,0x2B,0x31,

0x32,0x33,0x30,0x2E,

0x00,0x1B,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x30,0x2D,0x3D,0x08,0x09,//caps

0x51,0x57,0x45,0x52,0x54,0x59,0x55,0x49,0x4F,0x50,0x5B,0x5D,0x0D,0x00,0x41,0x53,

0x44,0x46,0x47,0x48,0x4A,0x4B,0x4C,0x3B,0x27,0x60,0x00,0x5C,0x5A,0x58,0x43,0x56,

0x42,0x4E,0x4D,0x2C,0x2E,0x2F,0x00,0x2A,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x38,0x39,0x2D,0x34,0x35,0x36,0x2B,0x31,

0x32,0x33,0x30,0x2E,

0x00,0x1B,0x21,0x40,0x23,0x24,0x25,0x5E,0x26,0x2A,0x28,0x29,0x5F,0x2B,0x08,0x09,//shift

0x51,0x57,0x45,0x52,0x54,0x59,0x55,0x49,0x4F,0x50,0x7B,0x7D,0x0D,0x00,0x41,0x53,

0x44,0x46,0x47,0x48,0x4A,0x4B,0x4C,0x3A,0x22,0x7E,0x00,0x7C,0x5A,0x58,0x43,0x56,

0x42,0x4E,0x4D,0x3C,0x3E,0x3F,0x00,0x2A,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x38,0x39,0x2D,0x34,0x35,0x36,0x2B,0x31,

0x32,0x33,0x30,0x2E,

0x00,0x1B,0x21,0x40,0x23,0x24,0x25,0x5E,0x26,0x2A,0x28,0x29,0x5F,0x2B,0x08,0x09,//caps+shift

0x71,0x77,0x65,0x72,0x74,0x79,0x75,0x69,0x6F,0x70,0x7B,0x7D,0x0D,0x00,0x61,0x73,

0x64,0x66,0x67,0x68,0x6A,0x6B,0x6C,0x3A,0x22,0x7E,0x00,0x7C,0x7A,0x78,0x63,0x76,

0x62,0x6E,0x6D,0x3C,0x3E,0x3F,0x00,0x2A,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x38,0x39,0x2D,0x34,0x35,0x36,0x2B,0x31,

0x32,0x33,0x30,0x2E

};

[c-sharp]view plaincopy

unsignedcharasciiTbl[]={

0x00,0x1B,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x30,0x2D,0x3D,0x08,0x09,//normal

0x71,0x77,0x65,0x72,0x74,0x79,0x75,0x69,0x6F,0x70,0x5B,0x5D,0x0D,0x00,0x61,0x73,

0x64,0x66,0x67,0x68,0x6A,0x6B,0x6C,0x3B,0x27,0x60,0x00,0x5C,0x7A,0x78,0x63,0x76,

0x62,0x6E,0x6D,0x2C,0x2E,0x2F,0x00,0x2A,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x38,0x39,0x2D,0x34,0x35,0x36,0x2B,0x31,

0x32,0x33,0x30,0x2E,

0x00,0x1B,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x30,0x2D,0x3D,0x08,0x09,//caps

0x51,0x57,0x45,0x52,0x54,0x59,0x55,0x49,0x4F,0x50,0x5B,0x5D,0x0D,0x00,0x41,0x53,

0x44,0x46,0x47,0x48,0x4A,0x4B,0x4C,0x3B,0x27,0x60,0x00,0x5C,0x5A,0x58,0x43,0x56,

0x42,0x4E,0x4D,0x2C,0x2E,0x2F,0x00,0x2A,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x38,0x39,0x2D,0x34,0x35,0x36,0x2B,0x31,

0x32,0x33,0x30,0x2E,

0x00,0x1B,0x21,0x40,0x23,0x24,0x25,0x5E,0x26,0x2A,0x28,0x29,0x5F,0x2B,0x08,0x09,//shift

0x51,0x57,0x45,0x52,0x54,0x59,0x55,0x49,0x4F,0x50,0x7B,0x7D,0x0D,0x00,0x41,0x53,

0x44,0x46,0x47,0x48,0x4A,0x4B,0x4C,0x3A,0x22,0x7E,0x00,0x7C,0x5A,0x58,0x43,0x56,

0x42,0x4E,0x4D,0x3C,0x3E,0x3F,0x00,0x2A,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x38,0x39,0x2D,0x34,0x35,0x36,0x2B,0x31,

0x32,0x33,0x30,0x2E,

0x00,0x1B,0x21,0x40,0x23,0x24,0x25,0x5E,0x26,0x2A,0x28,0x29,0x5F,0x2B,0x08,0x09,//caps+shift

0x71,0x77,0x65,0x72,0x74,0x79,0x75,0x69,0x6F,0x70,0x7B,0x7D,0x0D,0x00,0x61,0x73,

0x64,0x66,0x67,0x68,0x6A,0x6B,0x6C,0x3A,0x22,0x7E,0x00,0x7C,0x7A,0x78,0x63,0x76,

0x62,0x6E,0x6D,0x3C,0x3E,0x3F,0x00,0x2A,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x38,0x39,0x2D,0x34,0x35,0x36,0x2B,0x31,

0x32,0x33,0x30,0x2E

};

就是卸载函数,在卸载的时候我们要删除设备和附加的设备,然后取消最后一个IRP,代码如下:

[cpp]view plaincopy

//卸载例程

voidFilterUnload(INPDRIVER_OBJECTpDriverObject)

{

//得到设备

PDEVICE_OBJECTpDevObj=pDriverObject->DeviceObject;

while(pDevObj!=NULL)

{

//设备扩展

PDEVICE_EXTENSIONpDevExt=(PDEVICE_EXTENSION)pDevObj->DeviceExtension;

PDEVICE_OBJECTpTagObj=pDevExt->pbindDevice;

//解除绑定

if(pDevExt->pbindDevice!=NULL)

{

IoDetachDevice(pDevExt->pbindDevice);

}

//删除设备

if(pDevExt->pDevice!=NULL)

{

IoDeleteDevice(pDevExt->pDevice);

}

if(pDevExt->proxyIrp!=NULL)

{

if(CancelIrp(pDevExt->proxyIrp))

{

DbgPrint(“取消成功。。。/n”);

}

else

{

DbgPrint(“取消失败。。。/n”);

}

}

//下一个设备

pDevObj=pDevObj->NextDevice;

}

}

[cpp]view plaincopy

//卸载例程

voidFilterUnload(INPDRIVER_OBJECTpDriverObject)

{

//得到设备

PDEVICE_OBJECTpDevObj=pDriverObject->DeviceObject;

while(pDevObj!=NULL)

{

//设备扩展

PDEVICE_EXTENSIONpDevExt=(PDEVICE_EXTENSION)pDevObj->DeviceExtension;

PDEVICE_OBJECTpTagObj=pDevExt->pbindDevice;

//解除绑定

if(pDevExt->pbindDevice!=NULL)

{

IoDetachDevice(pDevExt->pbindDevice);

}

//删除设备

if(pDevExt->pDevice!=NULL)

{

IoDeleteDevice(pDevExt->pDevice);

}

if(pDevExt->proxyIrp!=NULL)

{

if(CancelIrp(pDevExt->proxyIrp))

{

DbgPrint(“取消成功。。。/n”);

}

else

{

DbgPrint(“取消失败。。。/n”);

}

}

//下一个设备

pDevObj=pDevObj->NextDevice;

}

}

载函数中调用了个取消IRP的方法,代码如下:

[cpp]view plaincopy

BOOLEANCancelIrp(PIRPpIrp)

{

if(pIrp==NULL)

{

DbgPrint(“取消irp错误…/n”);

returnFALSE;

}

if(pIrp->Cancel||pIrp->CancelRoutine==NULL)

{

DbgPrint(“取消irp错误…/n”);

returnFALSE;

}

if(FALSE==IoCancelIrp(pIrp))

{

DbgPrint(“IoCancelIrptoirp错误…/n”);

returnFALSE;

}

//取消后重设此例为空

IoSetCancelRoutine(pIrp,NULL);

returnTRUE;

}

[cpp]view plaincopy

BOOLEANCancelIrp(PIRPpIrp)

{

if(pIrp==NULL)

{

DbgPrint(“取消irp错误…/n”);

returnFALSE;

}

if(pIrp->Cancel||pIrp->CancelRoutine==NULL)

{

DbgPrint(“取消irp错误…/n”);

returnFALSE;

}

if(FALSE==IoCancelIrp(pIrp))

{

DbgPrint(“IoCancelIrptoirp错误…/n”);

returnFALSE;

}

//取消后重设此例为空

IoSetCancelRoutine(pIrp,NULL);

returnTRUE;

}

整个键盘过滤驱动就完成了,以后还得多多学习,多多总结。

需要做网站?需要网络推广?欢迎咨询客户经理 13272073477