首页
论坛
课程
招聘
浅谈文件过滤原理与简单实现
2021-11-5 16:29 25998

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

2021-11-5 16:29
25998

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

1.文件过滤的原理

在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)--->磁盘完成实际操作

 

既然了解它们的原理,那么我们就能对文件系统的驱动做手脚,来达成过滤的目的。

2.选择过滤的方法

1.通过ObReferenceObject(“Ntfs.sys”)找到驱动对象,然后找到驱动对象下的MajorFunction数组,用我们写的函数替换掉数组的所有成员,同时,也需要替换驱动对象下的fastio成员。

 

总结:用HOOK的方式来实现文件过滤,兼容性的问题很大,即使用原子操作替换函数,稍有不慎,就会造成蓝屏。

 

2.通过ObReferenceObject(“Ntfs.sys”)找到驱动对象,然后用IoEnumerateDeviceObjectList()枚举所有设备对象,用设备挂靠的方式来实现Io过滤。

 

总结:相比HOOK的方式,设备挂靠是微软提供的接口,很安全,设备挂靠也是所有文件过滤驱动的首选方法。

3.初始化文件过滤驱动

实现文件过滤需要我们自己编写一个驱动。




第四步本来是注册一个文件系统通知回调,用来绑定所有文件系统的控制设备。(\FileSystem下的所有文件驱动)

 

但是笔者这里只想绑定Ntfs.sys所以注释掉。

4.挂靠Ntfs文件系统的设备对象

这里是对 “5.挂靠Ntfs或者Fastfat驱动的所有设备对象” 的解释。

 

 

方法很简单:先找到Ntfs的驱动对象,然后遍历它的所有设备对象(控制设备和卷设备),然后逐个用生成的匿名对象来绑定,这样做的目的是:让发给Ntfs的文件系统的请求,先通过我们的驱动的Io和FastIo函数,然后由我们决定是否转发给Ntfs文件系统。这样就达成了我们过滤的目的。

 

需要注意的细节是:笔者在这里用了一个自定义的结构,放在了生成的设备对象的拓展上,这个目的是为了把请求下发给文件系统的设备对象,不然下发不了请求,整个操作系统的所有文件操作都不能实现。

5.MajorFunction和Fastio函数

fastio 是没有irp的快速请求,笔者并不想处理这些请求,让所有的Fastio函数,全部返回FALSE。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
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即可

MajiorFunction中的函数,需要读者根据自己的需求,来编写属于自己的过滤函数。

 

在这里,笔者实现了一个读操作的函数,让所有读取文件的操作,打印出文件名,偏移量,读取的长度。

 

 

这里是编译后运行的效果:

 

 

至于其他的Io操作函数,全部下发即可。

6.总结

在后续的文件过滤进阶上,不论是Sfilter过滤框架还是Minifilter过滤框架,它们的本质都是利用设备挂靠和MajorFunction函数来过滤,只是Minifilter利用了微软编写的文件过滤驱动FltMgr.sys提供的接口进行编程,忽略了IRP的种种细节。

 

在笔者的感受中,要处理IRP的种种细节太过于繁琐,无论是缓冲IO,还是直接IO,或者是Neithor IO,还有完成IRP的种种情况处理,需要先下发请求然后在完成函数过滤的,需要先下发请求然后在分发函数过滤的,需要先发下请求然后在工作队列过滤的等等等,简而言之 fuck Sfilter bro!

 

关于本文的利用,读者可以自行实现硬盘和分区的序列号HOOK,也可以通过文件特征实现对病毒的识别等

 

需要注意的是,所有文件过滤驱动不能处理文件内存映射的文件读写操作,内存映射的文件读写基于内存,文件过滤驱动并不能拦截到。


看雪2022 KCTF 秋季赛 防守篇规则,征题截止日期11月12日!(iPhone 14等你拿!)

上传的附件:
收藏
点赞12
打赏
分享
最新回复 (11)
雪    币: 476
活跃值: 活跃值 (616)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
青丝梦 活跃值 2021-11-5 16:33
2
0
好棒哦
雪    币: 30
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
作弊者 活跃值 2021-11-5 16:33
3
0
牛逼666我滴宝贝
雪    币: 628
活跃值: 活跃值 (2613)
能力值: ( LV6,RANK:98 )
在线值:
发帖
回帖
粉丝
还我六千雪币 活跃值 2021-11-5 16:39
4
1
雪    币: 1697
活跃值: 活跃值 (3405)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
0x太上 活跃值 1 2021-11-5 16:40
5
0
雪    币: 1263
活跃值: 活跃值 (387)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
榆一 活跃值 1 2021-11-5 16:41
6
0
雪    币: 17
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
_Kernel 活跃值 2021-11-5 16:45
7
0
牛逼666我滴宝贝
雪    币: 5230
活跃值: 活跃值 (2542)
能力值: ( LV4,RANK:55 )
在线值:
发帖
回帖
粉丝
Jev0n 活跃值 2021-11-5 16:46
8
0
雪    币: 2050
活跃值: 活跃值 (1405)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
dearfuture 活跃值 2021-11-8 11:23
9
0
看起来就是sfilter
雪    币: 1697
活跃值: 活跃值 (3405)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
0x太上 活跃值 1 2021-11-8 19:40
10
0
dearfuture 看起来就是sfilter
比Sfilter更底层
雪    币: 21
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
yushusu 活跃值 2021-12-8 16:19
11
0
雪    币: 200
活跃值: 活跃值 (328)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
aas102400 活跃值 2022-6-28 17:25
12
0
游客
登录 | 注册 方可回帖
返回