来上海有一周的时间了,一直没有更新自己的博客,一来是还没怎么适应环境,二来就是上海的天气很热,其实这些都是给自己找理由,找借口,我不应该就此沉沦下去,还是应该向之前那样抱有梦想,不想当将军的士兵不是好士兵,我应该继续发奋,趁现
在的这段时间继续学习,虽然在这里,看不到很多的东西,其实也是个好事,自己已经不需要那样的学习了,有更多的时间,去提高
自己。
用户可以通过卷的驱动名,来指定卷进行过滤,用户的命令一般是通过IRP_MJ_DEVICE_CONTROL请求的参数进行传递给文件系统过滤驱动的。
文件系统过滤驱动可以通过监听文件系统的IRP_MJ_FILE_SYSTEM_CONTROL和IRP_MN_MOUNT_VOLUME请求,来附加在文件系统需要绑定的卷上面。
注意:通常你应该假定卷的驱动盘的映射是一对多的,不是一对一的,因为这是高级存储设备的功能,比如动态卷和卷的挂载 点。
你也不应该认为文件系统驱动是同步处理IRP_MN_MOUNT_VOLUME请求的,比如,一个软盘卷的文件系统的挂载在没有软盘插入的时候就是异步的,所以你的过滤驱动应该在绑定的完成例程中,就PendingReturned标志进行传递
文件系统过滤驱动可以过滤任何文件系统卷上的IO操作,但是它们不能直接附加在存储设备之上,比如磁盘驱动和分区,也不能直接附加在独立的目录或文件上。
创建过滤设备对象:
我们可以调用IoCreateDevice创建过滤驱动的设备附加在卷或者文件系统堆栈上.
status = IoCreateDevice(
gFileSpyDriverObject, //DriverObject
sizeof(MYLEGACYFILTER_DEVICE_EXTENSION), //DeviceExtensionSize
NULL, //DeviceName
DeviceObject->DeviceType, //DeviceType
0, //DeviceCharacteristics
FALSE, //Exclusive
&newDeviceObject); //DeviceObject
这里,DeviceObject->DeviceType这里的设备对象是指需要过滤的目标设备对象,而newDeviceObject指的是过滤驱动自己的设 备对象。 和其他的对象一样,这里也可以为过滤驱动的设备对象创建对象的上下文空间,这里指定的大小是sizeof (MYLEGACYFILTER_DEVICE_EXTENSION),新创建的过滤驱动的设备对象的DeviceExtension域指向这个上下文空间,文件系统过滤驱动 一般都是通过这种方法为每一个过滤设备对象的设备扩展分配内存,这个设备扩展的结构和内容,驱动可以自己指定。不过在XP系统 之后,在这个设备扩展的结构中必须包含以下域:
PDEVICE_OBJECT AttachedToDeviceObject;
我们在上面看到有把设备名设置为NULL,一般我们从不为文件系统过驱动的设备对象进行命名,因为这个设备对象是用来附加 在文件系统或卷的堆栈上面的,如果为设备命名,就为系统留下一个安全漏洞。
下面,我们来看一下,DeviceType这个参数,这个参数非常重要,它指的是,过滤驱动要附加的目标文件系统的设备对象的类 型,以这种方式传递的设备类型非常重要,IO管理器根据它返回给应用程序。
文件系统和文件系统过滤驱动不应该设置DeviceType参数为FILE_DEVICE_FILE_SYSTEM,这不是一个有效的参数值。 (FILE_DEVICE_FILE_SYSTEM常量只用于定义FSCTL的类型的)
这个参数重要的另外的一个原因是很多过滤驱动只对特定类型的文件系统进行过滤,比如,有些过滤驱动,只附加在本地的文 件系统上,不附加在CD-ROM或者远程文件系统上,这些过滤驱动通过检测在文件系统或卷驱动堆栈最上层设备对象的类型从而来确定 需要过滤的文件系统的类型。在大多数的情况下,在堆栈的最上层的设备对象就是一个过滤驱动的设备对象。更为重要的是,所有的 过滤驱动的设备对象都有相同的设备类型对于文件或者卷设备对象来说。
将过滤设备对象附加在目标的设备对象上。
调用IoAttachDeviceToDeviceStackSafe例程,将过滤设备对象附加在目标文件系统或者卷的驱动堆栈上进行过滤。
devExt = myLegacyFilterDeviceObject->DeviceExtension;
status = IoAttachDeviceToDeviceStackSafe(
myLegacyFilterDeviceObject, //SourceDevice
DeviceObject, //TargetDevice
&devext->AttachedToDeviceObject); //AttachedToDeviceObject
注意:这里的myLegacyFilterDeviceObject设备对象,就是我们创建的过滤设备对象,而DeviceObject和devext- >AttachedToDeviceObject指向我们要附加其的设备对象,一般来说,这个域应该是一致,当我们已经附加在其上面的话,但是如果 有另外的过滤设备对象已经附加在其上面,这两个值就不一样。
通过名字附加在文件系统上面。
我们在前面已经知道,每一个文件系统驱动都需要创建一个或者多个命名的控制设备对象,为了直接附加在一个指定的文件系 统上面,文件系统过滤驱动调用IoGetDeviceObjectPointer并传递文件系统控制设备对象的名字作为参数,而得到一个设备对象的指 针。
RtlInitUnicodeString(&nameString, L"\\Device\\RawDisk");
status = IoGetDeviceObjectPointer(
&nameString, //ObjectName
FILE_READ_ATTRIBUTES, //DesiredAccess
&fileObject, //FileObject
&rawDeviceObject); //DeviceObject
if (NT_SUCCESS(status)) {
ObDereferenceObject(fileObject);
}
在上面的代码中,我们返回了一个代表中用户模式的设备对象,文件对象,因为文件系统本身不需要,所以我们调用 ObDereferenceObject将其关闭,需要指出的是,当我们递减文件对象的引用计数的时候,也将导致其设备对象的引用计数减少。所 以我们应该在调用 ObDereferenceObject后检查问及爱你对象和原始设备对象是否还是有效的,除非在调用 ObDereferenceObject之 前已经调用 ObRereferenceObject,增加了引用计数。
当过滤设备对象已经附加在相应的文件系统或者卷上之后,我们首先应该确认驱动堆栈的下一层的设备对象DO_BUFFERED_IO 和DO_DIRECT_IO,从而将过滤设备对象的标志和其设置一致。
if (FlagOn( DeviceObject->Flags, DO_BUFFERED_IO )) {
SetFlag( myLegacyFilterDeviceObject->Flags, DO_BUFFERED_IO );
}
if (FlagOn( DeviceObject->Flags, DO_DIRECT_IO )) {
SetFlag(myLegacyFilterDeviceObject->Flags, DO_DIRECT_IO );
}
我们同样需要注意当我们是附加在一个文件系统上面,而不是一个卷的时候,我们需要确认是否需要设置过滤设备对象的 FILE_DEVICE_SECURE_OPEN标志位,而和在驱动堆栈的下一层的设备对象保持一致。
if (FlagOn( DeviceObject->Characteristics, FILE_DEVICE_SECURE_OPEN )) {
SetFlag(myLegacyFilterDeviceObject->Characteristics, FILE_DEVICE_SECURE_OPEN );
}
清除DO_DEVICE_INITIALIZING标志。
在成功将过滤设备对象附加在指定的文件系统或者卷之后,我们要确定调用ClearFlag宏来清除DO_DEVICE_INITIALIZIN标志。
ClearFlag(NewDeviceObject->Flags, DO_DEVICE_INITIALIZING);
当我们调用IoCreateDevice创建了过滤设备对象,函数将过滤设备对象的状态设置为DO_DEVICE_INITIALIZING,当我们成功将 其附加到指定的文件系统或者卷之后,我们确保将其这个标志清除,如果这个标志不清除,其他的过滤驱动不能附加在过滤链上,因 为调用IoAttachDeviceToDeviceStackSafe会失败。
如果我们在DriverEntry中创建的设备,不需要清除DO_DEVICE_INITIALIZING 这个标志位,因为IO管理器会自动清楚其标志, 但是我们驱动仍然应该清除在其创建的另外设备对象的DO_DEVICE_INITIALIZING 标志。
今天我们来看一下,怎样将文件系统过滤驱动附加在文件系统或者卷的上面。
用户可以通过卷的驱动名,来指定卷进行过滤,用户的命令一般是通过IRP_MJ_DEVICE_CONTROL请求的参数进行传递给文件系统过滤驱动的。
文件系统过滤驱动可以通过监听文件系统的IRP_MJ_FILE_SYSTEM_CONTROL和IRP_MN_MOUNT_VOLUME请求,来附加在文件系统需要绑定的卷上面。
注意:通常你应该假定卷的驱动盘的映射是一对多的,不是一对一的,因为这是高级存储设备的功能,比如动态卷和卷的挂载 点。
你也不应该认为文件系统驱动是同步处理IRP_MN_MOUNT_VOLUME请求的,比如,一个软盘卷的文件系统的挂载在没有软盘插入的时候就是异步的,所以你的过滤驱动应该在绑定的完成例程中,就PendingReturned标志进行传递
文件系统过滤驱动可以过滤任何文件系统卷上的IO操作,但是它们不能直接附加在存储设备之上,比如磁盘驱动和分区,也不能直接附加在独立的目录或文件上。
创建过滤设备对象:
我们可以调用IoCreateDevice创建过滤驱动的设备附加在卷或者文件系统堆栈上.
status = IoCreateDevice(
gFileSpyDriverObject, //DriverObject
sizeof(MYLEGACYFILTER_DEVICE_EXTENSION), //DeviceExtensionSize
NULL, //DeviceName
DeviceObject->DeviceType, //DeviceType
0, //DeviceCharacteristics
FALSE, //Exclusive
&newDeviceObject); //DeviceObject
这里,DeviceObject->DeviceType这里的设备对象是指需要过滤的目标设备对象,而newDeviceObject指的是过滤驱动自己的设 备对象。 和其他的对象一样,这里也可以为过滤驱动的设备对象创建对象的上下文空间,这里指定的大小是sizeof (MYLEGACYFILTER_DEVICE_EXTENSION),新创建的过滤驱动的设备对象的DeviceExtension域指向这个上下文空间,文件系统过滤驱动 一般都是通过这种方法为每一个过滤设备对象的设备扩展分配内存,这个设备扩展的结构和内容,驱动可以自己指定。不过在XP系统 之后,在这个设备扩展的结构中必须包含以下域:
PDEVICE_OBJECT AttachedToDeviceObject;
我们在上面看到有把设备名设置为NULL,一般我们从不为文件系统过驱动的设备对象进行命名,因为这个设备对象是用来附加 在文件系统或卷的堆栈上面的,如果为设备命名,就为系统留下一个安全漏洞。
下面,我们来看一下,DeviceType这个参数,这个参数非常重要,它指的是,过滤驱动要附加的目标文件系统的设备对象的类 型,以这种方式传递的设备类型非常重要,IO管理器根据它返回给应用程序。
文件系统和文件系统过滤驱动不应该设置DeviceType参数为FILE_DEVICE_FILE_SYSTEM,这不是一个有效的参数值。 (FILE_DEVICE_FILE_SYSTEM常量只用于定义FSCTL的类型的)
这个参数重要的另外的一个原因是很多过滤驱动只对特定类型的文件系统进行过滤,比如,有些过滤驱动,只附加在本地的文 件系统上,不附加在CD-ROM或者远程文件系统上,这些过滤驱动通过检测在文件系统或卷驱动堆栈最上层设备对象的类型从而来确定 需要过滤的文件系统的类型。在大多数的情况下,在堆栈的最上层的设备对象就是一个过滤驱动的设备对象。更为重要的是,所有的 过滤驱动的设备对象都有相同的设备类型对于文件或者卷设备对象来说。
将过滤设备对象附加在目标的设备对象上。
调用IoAttachDeviceToDeviceStackSafe例程,将过滤设备对象附加在目标文件系统或者卷的驱动堆栈上进行过滤。
devExt = myLegacyFilterDeviceObject->DeviceExtension;
status = IoAttachDeviceToDeviceStackSafe(
myLegacyFilterDeviceObject, //SourceDevice
DeviceObject, //TargetDevice
&devext->AttachedToDeviceObject); //AttachedToDeviceObject
注意:这里的myLegacyFilterDeviceObject设备对象,就是我们创建的过滤设备对象,而DeviceObject和devext- >AttachedToDeviceObject指向我们要附加其的设备对象,一般来说,这个域应该是一致,当我们已经附加在其上面的话,但是如果 有另外的过滤设备对象已经附加在其上面,这两个值就不一样。
通过名字附加在文件系统上面。
我们在前面已经知道,每一个文件系统驱动都需要创建一个或者多个命名的控制设备对象,为了直接附加在一个指定的文件系 统上面,文件系统过滤驱动调用IoGetDeviceObjectPointer并传递文件系统控制设备对象的名字作为参数,而得到一个设备对象的指 针。
RtlInitUnicodeString(&nameString, L"\\Device\\RawDisk");
status = IoGetDeviceObjectPointer(
&nameString, //ObjectName
FILE_READ_ATTRIBUTES, //DesiredAccess
&fileObject, //FileObject
&rawDeviceObject); //DeviceObject
if (NT_SUCCESS(status)) {
ObDereferenceObject(fileObject);
}
在上面的代码中,我们返回了一个代表中用户模式的设备对象,文件对象,因为文件系统本身不需要,所以我们调用 ObDereferenceObject将其关闭,需要指出的是,当我们递减文件对象的引用计数的时候,也将导致其设备对象的引用计数减少。所 以我们应该在调用 ObDereferenceObject后检查问及爱你对象和原始设备对象是否还是有效的,除非在调用 ObDereferenceObject之 前已经调用 ObRereferenceObject,增加了引用计数。
当过滤设备对象已经附加在相应的文件系统或者卷上之后,我们首先应该确认驱动堆栈的下一层的设备对象DO_BUFFERED_IO 和DO_DIRECT_IO,从而将过滤设备对象的标志和其设置一致。
if (FlagOn( DeviceObject->Flags, DO_BUFFERED_IO )) {
SetFlag( myLegacyFilterDeviceObject->Flags, DO_BUFFERED_IO );
}
if (FlagOn( DeviceObject->Flags, DO_DIRECT_IO )) {
SetFlag(myLegacyFilterDeviceObject->Flags, DO_DIRECT_IO );
}
我们同样需要注意当我们是附加在一个文件系统上面,而不是一个卷的时候,我们需要确认是否需要设置过滤设备对象的 FILE_DEVICE_SECURE_OPEN标志位,而和在驱动堆栈的下一层的设备对象保持一致。
if (FlagOn( DeviceObject->Characteristics, FILE_DEVICE_SECURE_OPEN )) {
SetFlag(myLegacyFilterDeviceObject->Characteristics, FILE_DEVICE_SECURE_OPEN );
}
清除DO_DEVICE_INITIALIZING标志。
在成功将过滤设备对象附加在指定的文件系统或者卷之后,我们要确定调用ClearFlag宏来清除DO_DEVICE_INITIALIZIN标志。
ClearFlag(NewDeviceObject->Flags, DO_DEVICE_INITIALIZING);
当我们调用IoCreateDevice创建了过滤设备对象,函数将过滤设备对象的状态设置为DO_DEVICE_INITIALIZING,当我们成功将 其附加到指定的文件系统或者卷之后,我们确保将其这个标志清除,如果这个标志不清除,其他的过滤驱动不能附加在过滤链上,因 为调用IoAttachDeviceToDeviceStackSafe会失败。
如果我们在DriverEntry中创建的设备,不需要清除DO_DEVICE_INITIALIZING 这个标志位,因为IO管理器会自动清楚其标志, 但是我们驱动仍然应该清除在其创建的另外设备对象的DO_DEVICE_INITIALIZING 标志。