Windows驱动_文件系统过滤驱动之六

来源:互联网 发布:vc access数据库 编辑:程序博客网 时间:2024/05/18 14:46

            不知道自己的选择是否正确,其实选择本没有正确好坏而言,因为你不清楚将来会发生什么,也许是好的,也许是坏的,但是正因为它的不确定性,使自己的成功多了一份可能,我不敢说改变意味着成功,但我知道固守成规,永远在自己的一亩三分地,绝对没有成功的可能性。对于30岁左右的自己来说,我需要更多的名企经验,来给自己增加砝码,不管是对以后找工作,还是创业,都是有好处的。

 

           今天我们来看一下,文件系统过滤驱动的初始化,前面,我们详述了关于文件系统过滤驱动的INF文件,这里有些特殊的节,比如ClassGuid,Load Order Groups在微软的MSDN上面都有介绍,因为它不是我要了解的主干,所以暂且省略它的介绍。

 

           像设备驱动一样,文件系统过滤驱动的入口函数也是DriverEntry,当驱动装载以后,系统就会调用DriverEntry,到底是IO管理器调用,还是服务管理器调用DriverEntry,取决于你驱动加载的方式。

 

          我们知道DriverEntry例程工作在PASSIVE_LEVEL线程上下文中,所以它是可分页的而且在初始化段中,它是可丢弃的。
      
         NTSTATUS
        (*PDRIVER_INITIALIZE) (
        IN PDRIVER_OBJECT DriverObject,
        IN PUNICODE_STRING RegistryPath
        );

         它的两个参数,跟一般的驱动都是一样的,这里不解释。
 
         一般在文件系统过滤驱动的DriverEntry例程中,创建控制设备对象,控制设备对象被应用程序用来跟驱动直接进行交互。即
使在过滤驱动已经附加在文件系统或者卷设备对象的上面,交互还是可以进行。

 

         文件系统也会创建控制设备,文件系统过滤驱动将自己附加在文件系统上而不是在独立的卷的文件系统上,它这样做是通过将自己附加在文件系统控制设备对象上。

 

         RtlInitUnicodeString(&nameString, MYLEGACYFILTER_FULLDEVICE_NAME);
         status = IoCreateDevice(
         DriverObject,                  //DriverObject
         0,                             //DeviceExtensionSize
         &nameString,                   //DeviceName
         FILE_DEVICE_DISK_FILE_SYSTEM,  //DeviceType
         FILE_DEVICE_SECURE_OPEN,       //DeviceCharacteristics
         FALSE,                         //Exclusive
         &gControlDeviceObject);        //DeviceObject

         RtlInitUnicodeString(&linkString, MYLEGACYFILTER_DOSDEVICE_NAME);
         status = IoCreateSymbolicLink(&linkString, &nameString);

 

         不像文件系统驱动,文件系统过滤驱动不需要为其控制设备对象进行命名,对于控制设备对象,IoRegisterDeviceInterface这个例程不再有效,所以应用程序不能和一个没有设备名的过滤驱动进行交互。如果指向DeviceName这个参数的指针不为空,这个值就变成了控制设备对象的名字。我们可以通过调用IoCreateSymbolicLink例程为内核的对象名生成一个连接,用户模式的应用程序可以通过这个名访问驱动。

 

 

         控制设备对象是唯一一种可以安全命名的设备对象,因为它是唯一一种不会附加在驱动堆栈上的设备对象,所以文件系统过滤驱动可以选择命名或者不命名,注意,对于文件系统驱动的控制设备对象是必须要命名的,文件系统过滤驱动的控制设备对象应不命名。

 

          DeviceType参数的值应该取自ntifs.h中的一种,比如FILE_DEVICE_DISK_FILE_SYSTEM.

          如果指向DeviceName参数的指针不为空,DeviceCharacteristics标志必须包含FILE_DEVICE_SECURE_OPEN,这个标志进行了设置,IO管理器将对所有的发送给控制设备对象的请求进行安全检查。这些安全检查包括对于命名设备对象的ACL。

 

          对于文件系统过滤驱动来说,一种有效的方式在派遣例程中标识和比较是它自己的控制设备对象是将其保存在预前定义好的指向控制设备对象的全局指针。

 

 

          下一步我们来设置驱动对象中指向各派遣函数的函数指针,我们用一个For循环来包含处理所有IRP的函数指针,而不应该只设置,我们感兴趣的派遣函数,这是因为有可能下层驱动需要处理这个IRP。下面就是注册IRP派遣例程的示例代码:

 

          for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
                DriverObject->MajorFunction[i] = MyLegacyFilterDispatch;
          }
          DriverObject->MajorFunction[IRP_MJ_CREATE] = MyLegacyFilterCreate;
          DriverObject->MajorFunction[IRP_MJ_CLOSE] = MyLegacyFilterClose;
          DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = MyLegacyFilterFsControl;

 

          下面来注册跟文件系统相关的Fast I/O 派遣函数:

 

           我们之前知道驱动对象中包含了一个指向文件系统Fast I/O 派遣函数指针列表地址的指针,所以我们要设置这个域,只需要首先初始化这个列表,然后依次填入相关的派遣函数的入口指针,然后将驱动对象的这个域设置即可。

 

          RtlZeroMemory(fastIoDispatch, sizeof(FAST_IO_DISPATCH));
          fastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
          fastIoDispatch->FastIoCheckIfPossible = MyLegacyFilterIoCheckIfPossible;
          fastIoDispatch->FastIoRead = MyLegacyFilterIoRead;
          fastIoDispatch->FastIoWrite = MyLegacyFilterIoWrite;
          fastIoDispatch->FastIoQueryBasicInfo = MyLegacyFilterIoQueryBasicInfo;
          fastIoDispatch->FastIoQueryStandardInfo = MyLegacyFilterIoQueryStandardInfo;
          fastIoDispatch->FastIoLock = MyLegacyFilterIoLock;
          fastIoDispatch->FastIoUnlockSingle = MyLegacyFilterIoUnlockSingle;
          fastIoDispatch->FastIoUnlockAll = MyLegacyFilterIoUnlockAll;
          fastIoDispatch->FastIoUnlockAllByKey = MyLegacyFilterIoUnlockAllByKey;
          fastIoDispatch->FastIoDeviceControl = MyLegacyFilterIoDeviceControl;
          fastIoDispatch->FastIoDetachDevice = MyLegacyFilterIoDetachDevice;
          fastIoDispatch->FastIoQueryNetworkOpenInfo = MyLegacyFilterIoQueryNetworkOpenInfo;
          fastIoDispatch->MdlRead = MyLegacyFilterIoMdlRead;
          fastIoDispatch->MdlReadComplete = MyLegacyFilterIoMdlReadComplete;
          fastIoDispatch->PrepareMdlWrite = MyLegacyFilterIoPrepareMdlWrite;
          fastIoDispatch->MdlWriteComplete = MyLegacyFilterIoMdlWriteComplete;
          fastIoDispatch->FastIoReadCompressed = MyLegacyFilterIoReadCompressed;
          fastIoDispatch->FastIoWriteCompressed = MyLegacyFilterIoWriteCompressed;
          fastIoDispatch->MdlReadCompleteCompressed = MyLegacyFilterIoMdlReadCompleteCompressed;
          fastIoDispatch->MdlWriteCompleteCompressed = MyLegacyFilterIoMdlWriteCompleteCompressed;
          fastIoDispatch->FastIoQueryOpen = MyLegacyFilterIoQueryOpen;

          DriverObject->FastIoDispatch = fastIoDispatch;

 

          下面再来注册和文件系统过滤驱动相关的例程,这些例程一般都是成对出现,可以在文件系统指向某些操作前面和后面进行调用,为了注册这些回调函数,首先必须分配并初始化FS_FILTER_CALLBACKS结构体,并装入相关函数例程的地址,最后将这个结构体的地址做为参数调用FsRtlRegisterFileSystemFilterCallbacks这个函数。

 

          fsFilterCallbacks.SizeOfFsFilterCallbacks = sizeof(FS_FILTER_CALLBACKS);
          fsFilterCallbacks.PreAcquireForSectionSynchronization = MyLegacyFilterPreFsFilterOperation;
          fsFilterCallbacks.PostAcquireForSectionSynchronization = MyLegacyFilterPostFsFilterOperation;
          fsFilterCallbacks.PreReleaseForSectionSynchronization = MyLegacyFilterPreFsFilterOperation;
          fsFilterCallbacks.PostReleaseForSectionSynchronization = MyLegacyFilterPostFsFilterOperation;
          fsFilterCallbacks.PreAcquireForCcFlush = MyLegacyFilterPreFsFilterOperation;
          fsFilterCallbacks.PostAcquireForCcFlush = MyLegacyFilterPostFsFilterOperation;
          fsFilterCallbacks.PreReleaseForCcFlush = MyLegacyFilterPreFsFilterOperation;
          fsFilterCallbacks.PostReleaseForCcFlush = MyLegacyFilterPostFsFilterOperation;
          fsFilterCallbacks.PreAcquireForModifiedPageWriter = MyLegacyFilterPreFsFilterOperation;
          fsFilterCallbacks.PostAcquireForModifiedPageWriter = MyLegacyFilterPostFsFilterOperation;
          fsFilterCallbacks.PreReleaseForModifiedPageWriter = MyLegacyFilterPreFsFilterOperation;
          fsFilterCallbacks.PostReleaseForModifiedPageWriter = MyLegacyFilterPostFsFilterOperation;

          status = FsRtlRegisterFileSystemFilterCallbacks(DriverObject, &fsFilterCallbacks);

          文件系统过滤驱动可以调用IoRegisterFsRegistrationChange 注册一个回调函数,当文件系统驱动调用

IoRegisterFileSystem和IoUnregisterFileSystem去注册或者卸载文件系统的时候,回调函数将被调用。这样做的目的是,文件系统过滤驱动可以有选择的过滤文件系统,当一个新的文件系统装入到系统中的时候。

 

          IoRegisterFileSystem和IoUnregisterFileSystem是给文件系统驱动使用的,文件系统过滤驱动禁止使用。

 

          附加在卷上的过滤驱动除非明确指定(比如,应用程序指定),一般不应该调用IoRegisterFsRegistrationChange 。但是使用该例程的过滤器有能力附加在任何刚被文件系统绑定的卷上。使用该例程,过滤器也不能直接附加在卷设备对象上,但是可以优先于任何等待用户模式的应用程序的命令的过滤驱动之前进行附加过滤,因为过滤器仅仅只能在当前文件系统卷设备对象的上层进行过滤

 

 

           如果文件系统过滤驱动在DriverEntry以后需要使用注册表,我们可以先将其保存起来,

\Registry\Machine\System\CurrentControlSet\Services\DriverName,我们可以使用 RtlCopyUnicodeString 将RegistryPath进行拷贝复制到目标字符串里。

 

            如果DriverEntry成功,一般返回STATUS_SUCCESS,如果初始化失败,也应该返回相应的错误值,但是在返回之前,我们先应该释放掉所有,我们先前分配的资源,比如DriverObject等。