文件系统的过滤与监控
文件系统的分发函数
11.2.1 普通的分发函数
? 上一节仅仅生成了控制设备,开发文件过滤驱动的主要工作还是撰写分发函数。在 DriverEntry 函数代码中,DriverObject 是参数驱动对象指针,现在来指定几个分发函数。SfPassThrough 负责所有不需要的处理,直接下发到下层驱动的IRP。
for(i=0;i<IRP_MJ_MAXIMUM_FUNCTION;i++)DriverObject->MajorFunction[i] = SfPassThrough;
? 作为过滤,一些特殊的分发函数必须特殊处理。为此,给这些特殊的请求单独的分发函数,主要包括打开请求(IRP_MJ_CREATE,但本章中暴扣另外两种主功能号; IRP_MJ_CREATE_NAMED_PIPE 和 IRP_MJ_CREATE_MALSLOT) 、文件系统控制请求(这种控制请求仅在本章出现,主功能号为 IRP_MJ_FILE_SYSTEM_CONTROL)、清理请求(IRP_MJ_CLEANUP)和关闭请求(IRP_MJ_CLOSE),这些IRP对文件系统来说都很关键。
DriverObject->MajorFunction[IRP_MJ_CREATE] = SfCreate;DriverObject->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] = SfCreate;DriverObject->MajorFunction[IRP_MJ_CREATE_MAILSLOT] = SfCreate;DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = SfFsControl;DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SfCleanupClose;DriverObject->MajorFunction[IRP_MJ_CLOSE] = SfCleanupClose;
? 首先解决最简单的过滤,什么都不处理直接下发:
NT SfPassThrough(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp
)
{IoSkipCuttentIrpStackLocation(Irp);return IoCallDriver(((PSFILTER_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->AttachedToDeviceObject,Irp);
}
? 这里最后的 PSFILTER_DEVICE_EXTENSION 类型设备拓展下的,下层设备 AttachedToDeviceObject 都是我们自定义的过滤设备里的结构。但是还没有写出来,会在后续解决。
? 到目前为止,还没有生成任何过滤设备。只生成了一个简单的控制设备。
11.2.2 文件过滤的快速IO分发函数
? 由于该驱动需要绑定到文件系统驱动的上层,文件系统除了处理正常的IRP之外,还要处理所谓的快速IO;除了普通的分发函数以外,还需要为驱动对象撰写另一组快速IO分发函数。这组函数的指针在 driver-FastIoDispatch中,而且这里本来是没有空间的,所以为了保存这一数组,需要自己分配空间。
? 下面使用 ExAllocatePoolWhithTag 分配内存空间。快速IO分发函数表必须在非分页南村中,所以这里使用 NonPagedPool 。
PFAST_IO_DISPATCH fastIoDispatch;
fastIoDispatch = ExAllocatePoolWithTag( NonPagedPool, sizeof( FAST_IO_DISPATCH ), SFLT_POOL_TAG );if (!fastIoDispatch) {//分配失败时,删除山前生成的控制设备IoDeleteDevice( gSFilterControlDeviceObject );return STATUS_INSUFFICIENT_RESOURCES;}//内存清零并初始化该数据结构RtlZeroMemory( fastIoDispatch, sizeof( FAST_IO_DISPATCH ) );fastIoDispatch->SizeOfFastIoDispatch = sizeof( FAST_IO_DISPATCH );fastIoDispatch->FastIoCheckIfPossible = SfFastIoCheckIfPossible;fastIoDispatch->FastIoRead = SfFastIoRead;fastIoDispatch->FastIoWrite = SfFastIoWrite;fastIoDispatch->FastIoQueryBasicInfo = SfFastIoQueryBasicInfo;fastIoDispatch->FastIoQueryStandardInfo = SfFastIoQueryStandardInfo;fastIoDispatch->FastIoLock = SfFastIoLock;fastIoDispatch->FastIoUnlockSingle = SfFastIoUnlockSingle;fastIoDispatch->FastIoUnlockAll = SfFastIoUnlockAll;fastIoDispatch->FastIoUnlockAllByKey = SfFastIoUnlockAllByKey;fastIoDispatch->FastIoDeviceControl = SfFastIoDeviceControl;fastIoDispatch->FastIoDetachDevice = SfFastIoDetachDevice;fastIoDispatch->FastIoQueryNetworkOpenInfo = SfFastIoQueryNetworkOpenInfo;fastIoDispatch->MdlRead = SfFastIoMdlRead;fastIoDispatch->MdlReadComplete = SfFastIoMdlReadComplete;fastIoDispatch->PrepareMdlWrite = SfFastIoPrepareMdlWrite;fastIoDispatch->MdlWriteComplete = SfFastIoMdlWriteComplete;fastIoDispatch->FastIoReadCompressed = SfFastIoReadCompressed;fastIoDispatch->FastIoWriteCompressed = SfFastIoWriteCompressed;fastIoDispatch->MdlReadCompleteCompressed = SfFastIoMdlReadCompleteCompressed;fastIoDispatch->MdlWriteCompleteCompressed = SfFastIoMdlWriteCompleteCompressed;fastIoDispatch->FastIoQueryOpen = SfFastIoQueryOpen;DriverObject->FastIoDispatch = fastIoDispatch;
? 在介绍该快速IO分发函数的时候,可能会使我们这样的初学者感到头痛。为什么在前面的串口、键盘和硬盘这些过滤驱程序中没有这么复杂的接口呢?实际上,驱动对象结构 DRIVER_OBJECT 中既然有快速IO分发函数的设置接口,那么理论上来说,所有的驱动对象都可以有快速IO分发函数——只是它们可能不会被调用。但是在文件系统中,上层会调用这一函数,所以需要设置。
? 快速IO分发函数是独立于普通的处理IRP的分发函数之外的另一组接口。但是它们的作用是一样的,就是由驱动处理外部给予的请求,而且所请求的处理也基本相同,只是根本没有IRP,本来应该写在IRP中的参数,被直接通过函数的参数传递进来了。这可以减少分配IRP的效率消耗。
? 文件系统的普通分发函数和快速IO分发函数都随时有可能被调用,好的过滤驱动显然应该同时过滤这两套接口,但是一般资料都只介绍IRP的过滤方法,快速IO分发函数非常复杂,但是与IRP过滤基本是一一对应的,只要了解前者,后者也很容易学会。
? 在开发学习阶段,可以设置所有的快速IO分发函数都返回FALSE并不做任何事。这样所有的请求都会通过IRP重新发送并被普通分发函数捕获。有一定的效率损失,但是也可以达到功能需求。
11.2.3 快速IO分发函数的实现
BOOLEAN SfFastIoCheckIfPossible (IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER FileOffset,IN ULONG Length,IN BOOLEAN Wait,IN ULONG LockKey,IN BOOLEAN CheckForReadOperation,OUT PIO_STATUS_BLOCK IoStatus,IN PDEVICE_OBJECT DeviceObject)
{
return FALSE;
}
? 这里是设置其中一个函数的例子,可以直接返回 FALSE。具体的实现可以再单独去学习。
总结
这里主要学了过滤函数的分发函数的设置,其中文件系统中特有的一些快速IO分发函数的了解。
明日计划
驱动编程-设备的绑定前期工作