过滤的基本概念
过滤的基本概念无论是NT式驱动还是WDM式驱动都可以看作是分层调用的。这里的分层有两个含义垂直的水平的垂直结构这是和过滤息息相关的结构。从第一张图片中可以看到设备对象中有一个AttachedDevice子域有它可以找到一个设备对象的上层对象。通过这样层层的附加就形成了一个类似栈的结构我们把这个栈结构称之为设备栈其中的StackSize表示从本层设备设备对象到最底层设备的距离。那么我们如何将一个设备对象附加到另一个设备对象上呢通过IoAttachDeviceToDeviceStack函数就可以做到。IoAttachDeviceToDeviceStackPDEVICE_OBJECTIoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice,IN PDEVICE_OBJECT TargetDevice);该函数将TargetDevice对象的AttachedDevice子域指向SourceDevice对象并且总是将SourceDevice附加到TargetDevice所在设备栈中对顶层的设备对象上同时返回TargetDevice所在设备栈中最顶层的那个设备对象指针SourceDevice附加之前。通常我们将该函数返回的设备对象放在SourceDevice的拓展域中这样就形成了拓展域、AttachedDevice这样的双链表结构便于我们传递IRP。水平结构水平结构比较好理解我们使用IoCreateDevice函数创建设备对象时该函数就会根据参数中的驱动对象自动完善这个单链表结构。示例代码#includentddk.h#defineNTSTRSAFE_LIB#includentstrsafe.h#ifndefSetFlag// 定义设置标志位的宏#defineSetFlag(_F,_SF)((_F)|(_SF))#endif#ifndefClearFlag// 定义清除标志位的宏#defineClearFlag(_F,_SF)((_F)~(_SF))#endif#defineCCP_MAX_COM_ID32// 最大串口数量staticPDEVICE_OBJECT s_fltobj[CCP_MAX_COM_ID]{0};staticPDEVICE_OBJECT s_nextobj[CCP_MAX_COM_ID]{0};PDEVICE_OBJECTccpOpenCom(IN ULONG id,OUT NTSTATUS*status){UNICODE_STRING name_str;staticWCHAR name[32]{0};// 初始化设备的名字memset(name,0,sizeof(WCHAR)*32);RtlStringCchPrintfW(name,32,L\\Device\\Serial%d,id);RtlInitUnicodeString(name_str,name);PFILE_OBJECT fileobjNULL;PDEVICE_OBJECT devobjNULL;// 从名字获取设备对象*statusIoGetDeviceObjectPointer(name_str,// 设备的名字FILE_ALL_ACCESS,// 期望的权限fileobj,// 返回的文件对象必须把这个文件对象解除引用devobj// 需要得到的设备对象);returndevobj;}// 附加到设备上NTSTATUSccpAttachDevice(PDRIVER_OBJECT driver,PDEVICE_OBJECT oldobj,PDEVICE_OBJECT*fltobj,PDEVICE_OBJECT*next){NTSTATUS status;PDEVICE_OBJECT topdevNULL;// 创建一个过滤设备statusIoCreateDevice(driver,0,NULL,oldobj-DeviceType,0,FALSE,fltobj);if(status!STATUS_SUCCESS){returnstatus;}// 拷贝重要标志位if(oldobj-FlagsDO_BUFFERED_IO)(*fltobj)-Flags|DO_BUFFERED_IO;if(oldobj-FlagsDO_DIRECT_IO)(*fltobj)-Flags|DO_DIRECT_IO;if(oldobj-FlagsDO_BUFFERED_IO)(*fltobj)-Flags|DO_BUFFERED_IO;if(oldobj-CharacteristicsFILE_DEVICE_SECURE_OPEN)(*fltobj)-Characteristics|FILE_DEVICE_SECURE_OPEN;(*fltobj)-Flags|DO_POWER_PAGABLE;// 将过滤设备绑定到另一个设备上如果目标设备已经被绑定了则默认绑定到最上层设备上// 返回值是最终被绑定的设备指针topdevIoAttachDeviceToDeviceStack(*fltobj,oldobj);if(topdevNULL){IoDeleteDevice(*fltobj);*fltobjNULL;statusSTATUS_UNSUCCESSFUL;returnstatus;}*nexttopdev;(*fltobj)-Flags(*fltobj)-Flags~DO_DEVICE_INITIALIZING;returnSTATUS_SUCCESS;}// 该函数绑定所有串口voidccpAttachAllComs(PDRIVER_OBJECT driver){PDEVICE_OBJECT com_ob;// 表示串口设备NTSTATUS status;for(ULONG i0;iCCP_MAX_COM_ID;i){com_obccpOpenCom(i,status);if(com_obNULL){continue;}// 绑定串口ccpAttachDevice(driver,com_ob,s_fltobj[i],s_nextobj[i]);}}#defineDELAY_ONE_MICROSECOND(-10)#defineDELAY_ONE_MILLISENCOND(DELAY_ONE_MICROSECOND*1000)#defineDELAY_ONE_SECOND(DELAY_ONE_MILLISENCOND*1000)voidccpUnload(PDRIVER_OBJECT driver){for(ULONG i0;iCCP_MAX_COM_ID;i){if(s_nextobj[i]!NULL)IoDeleteDevice(s_nextobj[i]);}LARGE_INTEGER interval;interval.QuadPart(5*1000*DELAY_ONE_MILLISENCOND);KeDelayExecutionThread(KernelMode,FALSE,interval);}NTSTATUSccpDispatch(PDEVICE_OBJECT device,PIRP pIrp){PIO_STACK_LOCATION irpspIoGetCurrentIrpStackLocation(pIrp);NTSTATUS status;for(ULONG i0;iCCP_MAX_COM_ID;i){}}NTSTATUSDriverEntry(PDRIVER_OBJECT driver,UNICODE_STRING RegPath){// 设置分发函数for(size_t i0;iIRP_MJ_MAXIMUM_FUNCTION;i){driver-MajorFunction[i]ccpDispatch;}driver-DriverUnloadccpUnload;ccpAttachAllComs(driver);returnSTATUS_SUCCESS;}上面的代码创建了一个具有2层垂直高度、CCP_MAX_COM_ID宽的设备对象树结构。上面的代码使用了s_nextobj数组来维护水平结构的关系。