发布时间: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;
}
整个键盘过滤驱动就完成了,以后还得多多学习,多多总结。