首页
社区
课程
招聘
浅谈文件过滤原理与简单实现
发表于: 2021-11-5 16:29 31556

浅谈文件过滤原理与简单实现

2021-11-5 16:29
31556

在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;
}

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 18
支持
分享
最新回复 (11)
雪    币: 1420
活跃值: (2151)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
好棒哦
2021-11-5 16:33
0
雪    币: 43
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
牛逼666我滴宝贝
2021-11-5 16:33
0
雪    币: 889
活跃值: (4118)
能力值: ( LV6,RANK:98 )
在线值:
发帖
回帖
粉丝
4
2021-11-5 16:39
1
雪    币: 401
活跃值: (4096)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
2021-11-5 16:40
0
雪    币: 1281
活跃值: (878)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
6
2021-11-5 16:41
0
雪    币: 17
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
牛逼666我滴宝贝
2021-11-5 16:45
0
雪    币: 2134
活跃值: (3911)
能力值: ( LV4,RANK:55 )
在线值:
发帖
回帖
粉丝
8
2021-11-5 16:46
0
雪    币: 2428
活跃值: (2566)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
看起来就是sfilter
2021-11-8 11:23
0
雪    币: 401
活跃值: (4096)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
dearfuture 看起来就是sfilter
比Sfilter更底层
2021-11-8 19:40
0
雪    币: 21
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
2021-12-8 16:19
0
雪    币: 200
活跃值: (555)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
12
2022-6-28 17:25
0
游客
登录 | 注册 方可回帖
返回
//