文件系统的过滤与监控
文件系统的分发函数
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分发函数的了解。
明日计划
驱动编程-设备的绑定前期工作