WindowsAPI编程核心技术-Minifilter文件监控

这节不讲Minifilter,只讲实现,入门Minifilter看驱动篇。

拦截IRP请求

本节在FLT_OPERATION_REGISTRATION中设置IRP_MJ_CREATE、IRP_MJ_READ、IRP_MJ_WRITE、IRP_MJ_SET_INFORMATION,分别对应文件创建、读取、写入、属性修改等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//  operation registration
CONST FLT_OPERATION_REGISTRATION Callbacks[] = {
{ IRP_MJ_CREATE,
0,
Minifilter_FileMonitor_TestPreOperation,
Minifilter_FileMonitor_TestPostOperation },
{ IRP_MJ_READ,
0,
Minifilter_FileMonitor_TestPreOperation,
Minifilter_FileMonitor_TestPostOperation },
{ IRP_MJ_WRITE,
0,
Minifilter_FileMonitor_TestPreOperation,
Minifilter_FileMonitor_TestPostOperation },
{ IRP_MJ_SET_INFORMATION,
0,
Minifilter_FileMonitor_TestPreOperation,
Minifilter_FileMonitor_TestPostOperation },
//没实现的略...
{ IRP_MJ_OPERATION_END }
};

文件保护

注册过滤器FltRegisterFilter和开启过滤器FltStartFiltering俩保持框架不变即可。

Minifilter注册启动后,插入到FltMgr实例队列中,关联需要过滤的卷。例如有3个Minifilter从上到下挂载到FltMgr实例上,一旦某个Minifilter返回FLT_PREOP_COMPLETE,表明这个I/O由它完成了,立即按照相反顺序调用相应操作后函数,不再继续下调。否则返回FLT_PREOP_SUCCESS_WITH_CALLBACK,文件操作继续执行。

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
/*************************************************************************
MiniFilter callback routines.
*************************************************************************/
FLT_PREOP_CALLBACK_STATUS Minifilter_FileMonitor_TestPreOperation(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID* CompletionContext) {
NTSTATUS status;
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(CompletionContext);
PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("Minifilter_FileMonitor_Test!Minifilter_FileMonitor_TestPreOperation: Entered\n"));
/*
要进行监控的话,通常在PreXXX里处理,而要进行监视的话,则通常在PostXXX里处理(当然监视在PreXXX里处理也行).
下面对监控文件的读写、删除、重命名、改属性的操作,并且禁止对指定文件520.exe做任何操作。
原理是:在传入的参数里获取文件名,并打印出来,如果发现是被保护的文件,就返回操作。
*/
// 获取文件路径
UCHAR MajorFunction = Data->Iopb->MajorFunction;
PFLT_FILE_NAME_INFORMATION lpNameInfo = NULL;
status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &lpNameInfo);
if (NT_SUCCESS(status)) {
status = FltParseFileNameInformation(lpNameInfo);
if (NT_SUCCESS(status))
{
// 创建
if (IRP_MJ_CREATE == MajorFunction) {
if (IsProtectionFile(lpNameInfo)) {
KdPrint(("[IRP_MJ_CREATE]%wZ", &lpNameInfo->Name));
return FLT_PREOP_COMPLETE;
//return FLT_PREOP_DISALLOW_FASTIO;
};
}
// 读取
else if (IRP_MJ_READ == MajorFunction) {
if (IsProtectionFile(lpNameInfo)) {
KdPrint(("[IRP_MJ_READ]%wZ", &lpNameInfo->Name));
return FLT_PREOP_COMPLETE;
//return FLT_PREOP_DISALLOW_FASTIO;
};
}
// 文件写入
else if (IRP_MJ_WRITE == MajorFunction) {
if (IsProtectionFile(lpNameInfo)) {
KdPrint(("[IRP_MJ_WRITE]%wZ", &lpNameInfo->Name));
return FLT_PREOP_COMPLETE;
//return FLT_PREOP_DISALLOW_FASTIO;
};
}
// 修改文件信息
else if (IRP_MJ_SET_INFORMATION == MajorFunction) {
if (IsProtectionFile(lpNameInfo)) {
KdPrint(("[IRP_MJ_SET_INFORMATION]%wZ", &lpNameInfo->Name));
return FLT_PREOP_COMPLETE;
//return FLT_PREOP_DISALLOW_FASTIO;
};
};
};
};
/*
// See if this is an operation we would like the operation status for. If so request it.
// NOTE: most filters do NOT need to do this. You only need to make this call if, for example, you need to know if the oplock was actually granted.
if (Minifilter_FileMonitor_TestDoRequestOperationStatus( Data )) {
status = FltRequestOperationStatusCallback( Data, Minifilter_FileMonitor_TestOperationStatusCallback, (PVOID)(++OperationStatusCtx) );
if (!NT_SUCCESS(status))
PT_DBG_PRINT( PTDBG_TRACE_OPERATION_STATUS, ("Minifilter_FileMonitor_Test!Minifilter_FileMonitor_TestPreOperation: FltRequestOperationStatusCallback Failed, status=%08x\n", status) );
};
// This template code does not do anything with the callbackData, but rather returns FLT_PREOP_SUCCESS_WITH_CALLBACK. This passes the request down to the next miniFilter in the chain.
*/
return FLT_PREOP_SUCCESS_WITH_CALLBACK;
};

判断文件路径时,要用ExAllocatePool申请非分页内存,因为FltGetFileNameInformation获取的路径信息存储在分页内存中,直接在回调函数中使用变量会蓝屏。

反Minifilter文件监控

前置芝士

FltEnumerateFilters

列举系统中所有注册的Minifilter驱动程序。

1
2
3
4
5
NTSTATUS FltEnumerateFilters(
_Out_opt_ PFLT_FILTER* FilterList, //接收不透明过滤器指针数组的缓冲区
_In_opt_ ULONG FilterListSize, //缓冲区可以容纳不透明过滤器指针数
_Out_ PULONG NumberFilterReturned //接收FilterList数组中返回的不透明过滤器指针数 当FilterListSize为0 FilterList为NULL 则这个参数接收找到的Minifilter驱动程序数
)//当FilterListSize参数太小 FilterList不为0 则返回STATUS_BUFFER_TOO_SMALL

基本原理

别忘了包含头文件fltKernel.h并导入FltMgr.lib。

首先用FltEnumerateFilters获取系统上所有注册成功的Minifilter过滤器对象指针数组PFLT_FILTER*,这个数据结构在不同系统定义不同。

例如在Windows 10 x64上用WinDBG获取FLT_FILTER结构体定义,注意Operations成员:

1
2
3
4
dt fltmgr!_FLT_FILTER
...
+0x1A8 Operations : Ptr64 _FLT_OPERATION_REGISTRATION
...

不同系统中FLT_FILTER结构中Operations成员偏移大小:

Windows 7 Windows 8.1 Windows 10
x86 CC D4 E4
x64 188 198 1A8

结构FLT_OPERATION_REGISTRATION是固定的,定义:

1
2
3
4
5
6
7
typedef struct _FLT_OPERATION_REGISTRATION {
UCHAR MajorFunction; //Minifilter驱动程序消息类型
FLT_OPERATION_REGISTRATION_FLAGS Flags;
PFLT_PRE_OPERATION_CALLBACK PreOperation; //操作前回调函数地址
PFLT_POST_OPERATION_CALLBACK PostOperation; //操作后回调函数地址
PVOID Reserved1;
} FLT_OPERATION_REGISTRATION, * PFLT_OPERATION_REGISTRATION;

枚举Minifilter系统回调函数实现代码:

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
// 遍历回调
BOOLEAN EnumCallback(VOID) {
NTSTATUS status = STATUS_SUCCESS;
ULONG ulFilterListSize = 0;
PFLT_FILTER* ppFilterList = NULL;
ULONG i = 0;
LONG lOperationsOffset = 0;
PFLT_OPERATION_REGISTRATION pFltOperationRegistration = NULL;
// 获取 Minifilter 过滤器Filter 的数量
FltEnumerateFilters(NULL, 0, &ulFilterListSize);
// 申请内存
ppFilterList = (PFLT_FILTER*)ExAllocatePool(NonPagedPool, ulFilterListSize * sizeof(PFLT_FILTER));
if (NULL == ppFilterList) {
DbgPrint("ExAllocatePool Error!\n");
return FALSE;
};
// 获取 Minifilter 中所有过滤器Filter 的信息
status = FltEnumerateFilters(ppFilterList, ulFilterListSize, &ulFilterListSize);
if (!NT_SUCCESS(status)) {
DbgPrint("FltEnumerateFilters Error![0x%X]\n", status);
return FALSE;
};
DbgPrint("ulFilterListSize=%d\n", ulFilterListSize);
// 获取 PFLT_FILTER 中 Operations 偏移
lOperationsOffset = GetOperationsOffset();
if (0 == lOperationsOffset) {
DbgPrint("GetOperationsOffset Error\n");
return FALSE;
};
// 开始遍历 Minifilter 中各个过滤器Filter 的信息
__try {
for (i = 0; i < ulFilterListSize; i++) {
// 获取 PFLT_FILTER 中 Operations 成员地址
pFltOperationRegistration = (PFLT_OPERATION_REGISTRATION)(*(PVOID*)((PUCHAR)ppFilterList[i] + lOperationsOffset));
__try {
// 同一过滤器下的回调信息
DbgPrint("-------------------------------------------------------------------------------\n");
while (IRP_MJ_OPERATION_END != pFltOperationRegistration->MajorFunction) {
if (IRP_MJ_MAXIMUM_FUNCTION > pFltOperationRegistration->MajorFunction) // MajorFunction ID Is: 0~27
// 显示
DbgPrint("[Filter=%p]IRP=%d, PreFunc=0x%p, PostFunc=0x%p\n", ppFilterList[i], pFltOperationRegistration->MajorFunction, pFltOperationRegistration->PreOperation, pFltOperationRegistration->PostOperation);
// 获取下一个消息回调信息
pFltOperationRegistration = (PFLT_OPERATION_REGISTRATION)((PUCHAR)pFltOperationRegistration + sizeof(FLT_OPERATION_REGISTRATION));
};
DbgPrint("-------------------------------------------------------------------------------\n");
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("[2_EXCEPTION_EXECUTE_HANDLER]\n");
};
};
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("[1_EXCEPTION_EXECUTE_HANDLER]\n");
};
// 释放内存
ExFreePool(ppFilterList);
ppFilterList = NULL;
return TRUE;
};

在自身驱动程序中可以用FltUnregisterFilter,但现在显然不在一个驱动程序中删除回调函数。只有两种方法:

  • 修改FLT_OPERATION_REGISTRATION中操作前回调函数和操作后回调函数地址,指向自定义空回调函数地址。
  • 修改回调函数内存前几字节为RET。

这里用第一种方法,分别声明操作前回调函数、操作后回调函数,这里直接看源代码。

源代码

Driver.h:

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef _DRIVER_H_
#define _DRIVER_H_


#include <ntddk.h>


VOID DriverUnload(PDRIVER_OBJECT pDriverObject);
NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp);


#endif

EnumRemove.h:

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
#ifndef _ENUM_REMOVE_H_
#define _ENUM_REMOVE_H_


#include <fltKernel.h>


// 遍历回调
BOOLEAN EnumCallback();

// 移除回调
NTSTATUS RemoveCallback(PFLT_FILTER pFilter);

// 获取 Operations 偏移
LONG GetOperationsOffset();

// 新的回调函数 消息处理前
FLT_PREOP_CALLBACK_STATUS
New_MiniFilterPreOperation(
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_Flt_CompletionContext_Outptr_ PVOID *CompletionContext
);
// 新的回调函数 消息处理后
FLT_POSTOP_CALLBACK_STATUS
New_MiniFilterPostOperation(
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_In_opt_ PVOID CompletionContext,
_In_ FLT_POST_OPERATION_FLAGS Flags
);


#endif

Driver.c:

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
#include "EnumRemove.h"
#include "Driver.h"


NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
DbgPrint("Enter DriverEntry\n");

NTSTATUS status = STATUS_SUCCESS;
pDriverObject->DriverUnload = DriverUnload;
for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
pDriverObject->MajorFunction[i] = DriverDefaultHandle;
}

// 遍历回调
EnumCallback();

DbgPrint("Leave DriverEntry\n");
return status;
}



VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
}


NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);

return status;
}

EnumRemove.c:

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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#include "EnumRemove.h"


VOID ShowError(PCHAR lpszText, NTSTATUS ntStatus)
{
DbgPrint("%s Error[0x%X]\n", lpszText, ntStatus);
}


// 遍历回调
BOOLEAN EnumCallback()
{
NTSTATUS status = STATUS_SUCCESS;
ULONG ulFilterListSize = 0;
PFLT_FILTER *ppFilterList = NULL;
ULONG i = 0;
LONG lOperationsOffset = 0;
PFLT_OPERATION_REGISTRATION pFltOperationRegistration = NULL;

// 获取 Minifilter 过滤器Filter 的数量
FltEnumerateFilters(NULL, 0, &ulFilterListSize);
// 申请内存
ppFilterList = (PFLT_FILTER *)ExAllocatePool(NonPagedPool, ulFilterListSize *sizeof(PFLT_FILTER));
if (NULL == ppFilterList)
{
DbgPrint("ExAllocatePool Error!\n");
return FALSE;
}
// 获取 Minifilter 中所有过滤器Filter 的信息
status = FltEnumerateFilters(ppFilterList, ulFilterListSize, &ulFilterListSize);
if (!NT_SUCCESS(status))
{
DbgPrint("FltEnumerateFilters Error![0x%X]\n", status);
return FALSE;
}

DbgPrint("ulFilterListSize=%d\n", ulFilterListSize);

// 获取 PFLT_FILTER 中 Operations 偏移
lOperationsOffset = GetOperationsOffset();
if (0 == lOperationsOffset)
{
DbgPrint("GetOperationsOffset Error\n");
return FALSE;
}

// 开始遍历 Minifilter 中各个过滤器Filter 的信息
__try
{
for (i = 0; i < ulFilterListSize; i++)
{
// 获取 PFLT_FILTER 中 Operations 成员地址
pFltOperationRegistration = (PFLT_OPERATION_REGISTRATION)(*(PVOID *)((PUCHAR)ppFilterList[i] + lOperationsOffset));

__try
{
// 同一过滤器下的回调信息
DbgPrint("-------------------------------------------------------------------------------\n");
while (IRP_MJ_OPERATION_END != pFltOperationRegistration->MajorFunction)
{
if (IRP_MJ_MAXIMUM_FUNCTION > pFltOperationRegistration->MajorFunction) // MajorFunction ID Is: 0~27
{
// 显示
DbgPrint("[Filter=%p]IRP=%d, PreFunc=0x%p, PostFunc=0x%p\n", ppFilterList[i], pFltOperationRegistration->MajorFunction,
pFltOperationRegistration->PreOperation, pFltOperationRegistration->PostOperation);
}
// 获取下一个消息回调信息
pFltOperationRegistration = (PFLT_OPERATION_REGISTRATION)((PUCHAR)pFltOperationRegistration + sizeof(FLT_OPERATION_REGISTRATION));
}
DbgPrint("-------------------------------------------------------------------------------\n");
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
DbgPrint("[2_EXCEPTION_EXECUTE_HANDLER]\n");
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
DbgPrint("[1_EXCEPTION_EXECUTE_HANDLER]\n");
}

// 释放内存
ExFreePool(ppFilterList);
ppFilterList = NULL;

return TRUE;
}


// 移除回调
NTSTATUS RemoveCallback(PFLT_FILTER pFilter)
{
LONG lOperationsOffset = 0;
PFLT_OPERATION_REGISTRATION pFltOperationRegistration = NULL;

// 开始遍历 过滤器Filter 的信息
// 获取 PFLT_FILTER 中 Operations 成员地址
pFltOperationRegistration = (PFLT_OPERATION_REGISTRATION)(*(PVOID *)((PUCHAR)pFilter + lOperationsOffset));
__try
{
// 同一过滤器下的回调信息
while (IRP_MJ_OPERATION_END != pFltOperationRegistration->MajorFunction)
{
if (IRP_MJ_MAXIMUM_FUNCTION > pFltOperationRegistration->MajorFunction) // MajorFunction ID Is: 0~27
{
// 替换回调函数
pFltOperationRegistration->PreOperation = New_MiniFilterPreOperation;
pFltOperationRegistration->PostOperation = New_MiniFilterPostOperation;

// 显示
DbgPrint("[Filter=%p]IRP=%d, PreFunc=0x%p, PostFunc=0x%p\n", pFilter, pFltOperationRegistration->MajorFunction,
pFltOperationRegistration->PreOperation, pFltOperationRegistration->PostOperation);
}
// 获取下一个消息回调信息
pFltOperationRegistration = (PFLT_OPERATION_REGISTRATION)((PUCHAR)pFltOperationRegistration + sizeof(FLT_OPERATION_REGISTRATION));
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
DbgPrint("[EXCEPTION_EXECUTE_HANDLER]\n");
}

return STATUS_SUCCESS;
}


// 获取 Operations 偏移
LONG GetOperationsOffset()
{
RTL_OSVERSIONINFOW osInfo = { 0 };
LONG lOperationsOffset = 0;

// 获取系统版本信息, 判断系统版本
RtlGetVersion(&osInfo);
if (6 == osInfo.dwMajorVersion)
{
if (1 == osInfo.dwMinorVersion)
{
// Win7
#ifdef _WIN64
// 64 位
// 0x188
lOperationsOffset = 0x188;
#else
// 32 位
// 0xCC
lOperationsOffset = 0xCC;
#endif
}
else if (2 == osInfo.dwMinorVersion)
{
// Win8
#ifdef _WIN64
// 64 位

#else
// 32 位

#endif
}
else if (3 == osInfo.dwMinorVersion)
{
// Win8.1
#ifdef _WIN64
// 64 位
// 0x198
lOperationsOffset = 0x198;
#else
// 32 位
// 0xD4
lOperationsOffset = 0xD4;
#endif
}
}
else if (10 == osInfo.dwMajorVersion)
{
// Win10
#ifdef _WIN64
// 64 位
// 0x1A8
lOperationsOffset = 0x1A8;
#else
// 32 位
// 0xE4
lOperationsOffset = 0xE4;
#endif
}

return lOperationsOffset;
}


// 新的回调函数 消息处理前
FLT_PREOP_CALLBACK_STATUS New_MiniFilterPreOperation(
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_Flt_CompletionContext_Outptr_ PVOID *CompletionContext
)
{
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(CompletionContext);

DbgPrint("[New_MiniFilterPreOperation]\n");

return FLT_PREOP_SUCCESS_WITH_CALLBACK;
}


// 新的回调函数 消息处理后
FLT_POSTOP_CALLBACK_STATUS New_MiniFilterPostOperation(
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_In_opt_ PVOID CompletionContext,
_In_ FLT_POST_OPERATION_FLAGS Flags
)
{
UNREFERENCED_PARAMETER(Data);
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(CompletionContext);
UNREFERENCED_PARAMETER(Flags);

DbgPrint("[New_MiniFilterPostOperation]\n");

return FLT_POSTOP_FINISHED_PROCESSING;
}