《Windows内核安全与驱动编程》-第十一章文件系统的过滤与监控-day2

文件系统的过滤与监控

文件系统的分发函数

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_PIPEIRP_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分发函数的了解。

明日计划

驱动编程-设备的绑定前期工作

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章