在windows下,从XP到Win10,一共有两个文件系统,一个叫fastfat.sys,一个叫Ntfs.sys。
在WIN7和WIN10下,大家似乎不再使用fastfat.sys(也叫fast32)这个文件系统。
笔者也是这样,无论是新买的电脑还是U盘,或者移动盘,都给他刷成Ntfs。
Ntfs.sys 和Fastfat.sys 这两个windows下的文件系统,它们的目的不是存储文件,它们的目的是监控文件的所有操作。
比如打开文件,读取文件,写入文件,重命令文件,删除文件,新建文件\目录等,所有文件和目录的操作都被这两个文件系统驱动所监控。
Ntfs.sys 和Fastfat.sys 这两个windows下的文件系统,在完成监控的操作后,把实际的文件操作再发给磁盘的卷设备,由磁盘实现文件的操作。
总结:R3下的文件操作--->文件系统(Ntfs.sys或者Fastfat.sys)--->磁盘完成实际操作
既然了解它们的原理,那么我们就能对文件系统的驱动做手脚,来达成过滤的目的。
1.通过ObReferenceObject(“Ntfs.sys”)找到驱动对象,然后找到驱动对象下的MajorFunction数组,用我们写的函数替换掉数组的所有成员,同时,也需要替换驱动对象下的fastio成员。
总结:用HOOK的方式来实现文件过滤,兼容性的问题很大,即使用原子操作替换函数,稍有不慎,就会造成蓝屏。
2.通过ObReferenceObject(“Ntfs.sys”)找到驱动对象,然后用IoEnumerateDeviceObjectList()枚举所有设备对象,用设备挂靠的方式来实现Io过滤。
总结:相比HOOK的方式,设备挂靠是微软提供的接口,很安全,设备挂靠也是所有文件过滤驱动的首选方法。
实现文件过滤需要我们自己编写一个驱动。
第四步本来是注册一个文件系统通知回调,用来绑定所有文件系统的控制设备。(\FileSystem下的所有文件驱动)
但是笔者这里只想绑定Ntfs.sys所以注释掉。
这里是对 “5.挂靠Ntfs或者Fastfat驱动的所有设备对象” 的解释。
方法很简单:先找到Ntfs的驱动对象,然后遍历它的所有设备对象(控制设备和卷设备),然后逐个用生成的匿名对象来绑定,这样做的目的是:让发给Ntfs的文件系统的请求,先通过我们的驱动的Io和FastIo函数,然后由我们决定是否转发给Ntfs文件系统。这样就达成了我们过滤的目的。
需要注意的细节是:笔者在这里用了一个自定义的结构,放在了生成的设备对象的拓展上,这个目的是为了把请求下发给文件系统的设备对象,不然下发不了请求,整个操作系统的所有文件操作都不能实现。
fastio 是没有irp的快速请求,笔者并不想处理这些请求,让所有的Fastio函数,全部返回FALSE。
MajiorFunction中的函数,需要读者根据自己的需求,来编写属于自己的过滤函数。
在这里,笔者实现了一个读操作的函数,让所有读取文件的操作,打印出文件名,偏移量,读取的长度。
这里是编译后运行的效果:
至于其他的Io操作函数,全部下发即可。
在后续的文件过滤进阶上,不论是Sfilter过滤框架还是Minifilter过滤框架,它们的本质都是利用设备挂靠和MajorFunction函数来过滤,只是Minifilter利用了微软编写的文件过滤驱动FltMgr.sys提供的接口进行编程,忽略了IRP的种种细节。
在笔者的感受中,要处理IRP的种种细节太过于繁琐,无论是缓冲IO,还是直接IO,或者是Neithor IO,还有完成IRP的种种情况处理,需要先下发请求然后在完成函数过滤的,需要先下发请求然后在分发函数过滤的,需要先发下请求然后在工作队列过滤的等等等,简而言之 fuck Sfilter bro!
关于本文的利用,读者可以自行实现硬盘和分区的序列号HOOK,也可以通过文件特征实现对病毒的识别等
需要注意的是,所有文件过滤驱动不能处理文件内存映射的文件读写操作,内存映射的文件读写基于内存,文件过滤驱动并不能拦截到。
BOOLEAN FastIoCheckIfPossible(
_In_ struct _FILE_OBJECT
*
FileObject,
_In_ PLARGE_INTEGER FileOffset,
_In_ ULONG Length,
_In_ BOOLEAN Wait,
_In_ ULONG LockKey,
_In_ BOOLEAN CheckForReadOperation,
_Pre_notnull_
_When_(
return
!
=
FALSE, _Post_equal_to_(_Old_(IoStatus)))
_When_(
return
=
=
FALSE, _Post_valid_)
PIO_STATUS_BLOCK IoStatus,
_In_ struct _DEVICE_OBJECT
*
DeviceObject
)
{
return
FALSE;
/
/
效率可能会慢百分之十,加载可能会变慢
}
BOOLEAN FastIoRead(
_In_ struct _FILE_OBJECT
*
FileObject,
_In_ PLARGE_INTEGER FileOffset,
_In_ ULONG Length,
_In_ BOOLEAN Wait,
_In_ ULONG LockKey,
_Out_ PVOID
Buffer
,
_Out_ PIO_STATUS_BLOCK IoStatus,
_In_ struct _DEVICE_OBJECT
*
DeviceObject
)
{
return
FALSE;
}
BOOLEAN FastIoWrite(
_In_ struct _FILE_OBJECT
*
FileObject,
_In_ PLARGE_INTEGER FileOffset,
_In_ ULONG Length,
_In_ BOOLEAN Wait,
_In_ ULONG LockKey,
_In_ PVOID
Buffer
,
_Out_ PIO_STATUS_BLOCK IoStatus,
_In_ struct _DEVICE_OBJECT
*
DeviceObject
)
{
return
FALSE;
}
BOOLEAN FastIoQueryBasicInfo(
_In_ struct _FILE_OBJECT
*
FileObject,
_In_ BOOLEAN Wait,
_Out_ PFILE_BASIC_INFORMATION
Buffer
,
_Out_ PIO_STATUS_BLOCK IoStatus,
_In_ struct _DEVICE_OBJECT
*
DeviceObject
)
{
return
FALSE;
}
BOOLEAN FastIoQueryStandardInfo(
_In_ struct _FILE_OBJECT
*
FileObject,
_In_ BOOLEAN Wait,
_Out_ PFILE_STANDARD_INFORMATION
Buffer
,
_Out_ PIO_STATUS_BLOCK IoStatus,
_In_ struct _DEVICE_OBJECT
*
DeviceObject
)
{
return
FALSE;
}
BOOLEAN FastIoLock(
_In_ struct _FILE_OBJECT
*
FileObject,
_In_ PLARGE_INTEGER FileOffset,
_In_ PLARGE_INTEGER Length,
_In_ PEPROCESS ProcessId,
_In_ ULONG Key,
_In_ BOOLEAN FailImmediately,
_In_ BOOLEAN ExclusiveLock,
_Out_ PIO_STATUS_BLOCK IoStatus,
_In_ struct _DEVICE_OBJECT
*
DeviceObject
)
{
return
FALSE;
}
BOOLEAN FastIoUnlockSingle(
_In_ struct _FILE_OBJECT
*
FileObject,
_In_ PLARGE_INTEGER FileOffset,
_In_ PLARGE_INTEGER Length,
_In_ PEPROCESS ProcessId,
_In_ ULONG Key,
_Out_ PIO_STATUS_BLOCK IoStatus,
_In_ struct _DEVICE_OBJECT
*
DeviceObject
)
{
return
FALSE;
}
BOOLEAN FastIoUnlockAll(
_In_ struct _FILE_OBJECT
*
FileObject,
_In_ PEPROCESS ProcessId,
_Out_ PIO_STATUS_BLOCK IoStatus,
_In_ struct _DEVICE_OBJECT
*
DeviceObject
)
{
return
FALSE;
}
BOOLEAN FastIoUnlockAllByKey(
_In_ struct _FILE_OBJECT
*
FileObject,
_In_ PVOID ProcessId,
_In_ ULONG Key,
_Out_ PIO_STATUS_BLOCK IoStatus,
_In_ struct _DEVICE_OBJECT
*
DeviceObject
)
{
return
FALSE;
}
BOOLEAN FastIoDeviceControl(
_In_ struct _FILE_OBJECT
*
FileObject,
_In_ BOOLEAN Wait,
_In_opt_ PVOID InputBuffer,
_In_ ULONG InputBufferLength,
_Out_opt_ PVOID OutputBuffer,
_In_ ULONG OutputBufferLength,
_In_ ULONG IoControlCode,
_Out_ PIO_STATUS_BLOCK IoStatus,
_In_ struct _DEVICE_OBJECT
*
DeviceObject
)
{
return
FALSE;
}
VOID AcquireFileForNtCreateSection(
_In_ struct _FILE_OBJECT
*
FileObject
)
{
return
FALSE;
}
VOID ReleaseFileForNtCreateSection(
_In_ struct _FILE_OBJECT
*
FileObject
)
{
return
FALSE;
}
VOID FastIoDetachDevice(
_In_ struct _DEVICE_OBJECT
*
SourceDevice,
_In_ struct _DEVICE_OBJECT
*
TargetDevice
)
{
return
FALSE;
}
BOOLEAN FastIoQueryNetworkOpenInfo(
_In_ struct _FILE_OBJECT
*
FileObject,
_In_ BOOLEAN Wait,
_Out_ struct _FILE_NETWORK_OPEN_INFORMATION
*
Buffer
,
_Out_ struct _IO_STATUS_BLOCK
*
IoStatus,
_In_ struct _DEVICE_OBJECT
*
DeviceObject
)
{
return
FALSE;
}
/
/
后面还有很多,一共有
20
多个fastio函数,全部返回FALSE即可
BOOLEAN FastIoCheckIfPossible(
_In_ struct _FILE_OBJECT
*
FileObject,
_In_ PLARGE_INTEGER FileOffset,
_In_ ULONG Length,
_In_ BOOLEAN Wait,
_In_ ULONG LockKey,
_In_ BOOLEAN CheckForReadOperation,
_Pre_notnull_
_When_(
return
!
=
FALSE, _Post_equal_to_(_Old_(IoStatus)))
_When_(
return
=
=
FALSE, _Post_valid_)
PIO_STATUS_BLOCK IoStatus,
_In_ struct _DEVICE_OBJECT
*
DeviceObject
)
{
return
FALSE;
/
/
效率可能会慢百分之十,加载可能会变慢
}
BOOLEAN FastIoRead(
_In_ struct _FILE_OBJECT
*
FileObject,
_In_ PLARGE_INTEGER FileOffset,
_In_ ULONG Length,
_In_ BOOLEAN Wait,
_In_ ULONG LockKey,
_Out_ PVOID
Buffer
,
_Out_ PIO_STATUS_BLOCK IoStatus,
_In_ struct _DEVICE_OBJECT
*
DeviceObject
)
{
return
FALSE;
}
BOOLEAN FastIoWrite(
_In_ struct _FILE_OBJECT
*
FileObject,
_In_ PLARGE_INTEGER FileOffset,
_In_ ULONG Length,
_In_ BOOLEAN Wait,
_In_ ULONG LockKey,
_In_ PVOID
Buffer
,
_Out_ PIO_STATUS_BLOCK IoStatus,
_In_ struct _DEVICE_OBJECT
*
DeviceObject
)
{
return
FALSE;
}
BOOLEAN FastIoQueryBasicInfo(
_In_ struct _FILE_OBJECT
*
FileObject,
_In_ BOOLEAN Wait,
_Out_ PFILE_BASIC_INFORMATION
Buffer
,
_Out_ PIO_STATUS_BLOCK IoStatus,
_In_ struct _DEVICE_OBJECT
*
DeviceObject
)
{
return
FALSE;
}
BOOLEAN FastIoQueryStandardInfo(
_In_ struct _FILE_OBJECT
*
FileObject,
_In_ BOOLEAN Wait,
_Out_ PFILE_STANDARD_INFORMATION
Buffer
,
_Out_ PIO_STATUS_BLOCK IoStatus,
_In_ struct _DEVICE_OBJECT
*
DeviceObject
)
{
return
FALSE;
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!