转个文件过滤驱动的东东,总结的比较全面
文字文字
献给那些IFS Fans,挑战那些IFS大牛。(部分用英文)
1> IFS 流程图
a.生成一个控制设备.当然此前你必须给控制设置指定名称.
b.设置Dispatch Functions.
c.设置Fast Io Functions.
d.编写一个my_fs_notify回调函数,在其中绑定刚激活的FS CDO.
e.使用wdff_reg_notify调用注册这个回调函数。
f.编写默认的dispatch functions.
g.处理IRP_MJ_FILE_SYSTEM_CONTROL,在其中监控Volumne的Mount和Dismount.
h.下一步自然是绑定Volumne了.
(全路径是在 FileObject->FileName.Buffer中得到的.)
2>一些必要知识
a.几个概念的区别
1.多数的storage drivers 是PNP管理的,存在一个设备节点(DEVNODE),(It is important to note that file systems and file system filter drivers are not PnP device drivers;),每个设备节点上维护一个Storage Device Stacks,这个就是因为每个存储设备,例如磁盘设备,可能包含一个或者多个逻辑卷(分区或者动态卷),这些卷就是通过这个Storage Device Stack来保存的。该设备点的信息就是functional device object (FDO)。剩下的就是physical device objects (PDO)代表各个分区。
2.通过下面的方式可以得到卷的名称
The Mount Manager responds to the arrival of a new storage volume by querying the volume driver for the following information:
·The volume's nonpersistent device object name (or target name), located in the Device directory of the system object tree (for example: "\Device\HarddiskVolume1")
·The volume's globally unique identifier (GUID), also called the unique volume name
·A suggested persistent symbolic link name for the volume, such as a drive letter (for example, "\DosDevices\D:")
3.文件系统和卷的区别
When a file system is mounted on a storage volume, it creates a file system volume device object (VDO) to represent the volume to the file system. The file system VDO is mounted on the storage device object by means of a shared object called a volume parameter block (VPB).
File System Stacks :File system drivers create two different types of device objects: control device objects (CDO) and volume device objects (VDO).
File System Control Device Objects (CDO)
File System Volume Device Objects (VDO)
3>代码分析(详细参考Sfilter)
1: DriverEntry ()
{
status = IoRegisterFsRegistrationChange( DriverObject, SfFsNotification );
}
SfFsNotification( IN PDEVICE_OBJECT DeviceObject, ,//原始文件系统
IN BOOLEAN FsActive)
{
SfAttachToFileSystemDevice( DeviceObject, &name );
}
SfAttachToFileSystemDevice(
IN PDEVICE_OBJECT DeviceObject,//原始文件系统
IN PUNICODE_STRING DeviceName)
{
status = IoCreateDevice(...
&newDeviceObject );
status = SfAttachDeviceToDeviceStack( newDeviceObject,
DeviceObject,
&devExt->AttachedToDeviceObject );//原始的保存}
2 文件类型分为:
(((_type) == FILE_DEVICE_DISK_FILE_SYSTEM) || \ 磁盘文件系统
((_type) == FILE_DEVICE_CD_ROM_FILE_SYSTEM) || \CDROM文件系统
((_type) == FILE_DEVICE_NETWORK_FILE_SYSTEM 网络文件系统
3:当在驱动中调用了
status = IoCreateDevice( DriverObject,
0, //has no device extension
&nameString,
FILE_DEVICE_DISK_FILE_SYSTEM,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&gSFilterControlDeviceObject );
那么发向该设备对象的IRP将能在该驱动(DriverObject)中接收到,当建立多个设备对象的时候,可以通过判断设备对象来进行是哪个发出的。 同时假设建立的其中一个设备和另外的系统的设备ATTACH了,那么发向原来系统设备对象的IRP也就能在这个驱动中接收到。例如在下面的分发例程中就能得到这些IRP。
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
DriverObject->MajorFunction = SfPassThrough;
DriverObject->MajorFunction[IRP_MJ_CREATE] = SfCreate;
4:首先文件系统驱动本身往往生成一个控制设备(CDO),这个控制对象用来和外部的应用进行通讯,来配置驱动的。
另一种设备是被这个文件系统Mount的Volume。一个FS可能有多个Volume,也可能一个都没有(解释一下,如果你有C:,D:,E:,F:四个分区。C:,D:为NTFS,E:,F:为Fat32.那么C:,D:则是Fat的两个Volume设备对象. )文件系统驱动是针对每个Volume来生成一个DeviceObjec(IoCreateDevice)。
5:因为IRP是上层应用到下面内核层的,所以只要我们建立的新设备ATTACH到原始的设备上,将位于绑定的文件对象STACK的上边,这样上面来的IRP将能首先被我们新建立的设备对象捕获。但是对于下面原始设备自己发出的请求,只能使用设置CALLBACK的方法了。
6:由于你的驱动将要绑定到文件系统驱动的上边,文件系统除了处理正常的IRP之外,还要处理所谓的FastIo.FastIo是Cache Manager调用所引发的一种没有irp的请求。因为FAST IO是用于CACHE的,不和下面的BASE FILE SYSTEM直接打交道,但是对于上层来说也是文件系统的访问,所以也要设置。具体就是先分配一个空间,
PFAST_IO_DISPATCH fastIoDispatch = ExAllocatePoolWithTag()
把FAST IO的函数赋给这个结构,fastIoDispatch->FastIoRead = SfFastIoRead;
然后DriverObject->FastIoDispatch = fastIoDispatch;
7:irp是从设备栈的顶端开始,逐步向下发送。DevVolumue表示我们实际要过滤的Volume设备,我们只要在这个设备栈的顶端再绑定一个设备,那发送给Volume的请求,自然会先发给我们的设备来处理。IoAttachDeviceToDeviceStack(注意源设备未必直接绑定在目标设备上。它应绑定在目标设备的设备栈的顶端。)比如“C:”这个设备,我已经知道符号连接为“C:”,不难得到设备名。得到设备名后,又不难得到设备。这时候我们IoCreateDevice()生成一个Device Object,然后调用IoAttachDeviceToDeviceStack绑定,所有发给“C:”的irp,就必然先发送给我们的驱动,我们也可以捕获所有对文件的操作了!
8:以上的方法是静态的,,如果不想处理动态的Volume,你完全可以这样做。但是我们这里有更高的要求。当你把一个U盘插入usb口,一个“J:”之类的Volume动态诞生的时候,我们依然要捕获这个事件,并生成一个Device来绑定它。
一个新的存储媒质被系统发现并在文件系统中生成一个Volume的过程称为Mounting.其过程开始的时候,FS的CDO将得到一个IRP,其Major Function Code为IRP_MJ_FILE_SYSTEM_CONTROL,Minor Function Code为IRP_MN_MOUNT。换句话说,如果我们已经生成了一个设备绑定文件系统的CDO,那么我们就可以得到这样的IRP,在其中知道一个新的Volume正在Mount.这时候我们可以执行上边所说的操作。 这就是下面代码的含义:
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = SfFsControl;
NTSTATUS
SfFsControl (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
switch (irpSp->MinorFunction) {
case IRP_MN_MOUNT_VOLUME:
return SfFsControlMountVolume( DeviceObject, Irp );
case IRP_MN_LOAD_FILE_SYSTEM:
return SfFsControlLoadFileSystem( DeviceObject, Irp );
case IRP_MN_USER_FS_REQUEST:
{}