Windows驱动开发入门-文件系统微过滤驱动

本节讲文件系统微过滤驱动Minifilter,着是sfilter的新型替代品,使用比sfilter方便,因为不需要手动构造IRP、维护设备对象等,但也有些局限性,更底层的功能完全实现不了。

本节例子是限制notepad.exe文件的操作,使其无法被双击执行、无法被复制、无法被改名、无法被删除。

微软把Minifilter框架从VS2022的WDK中删除了,从这里找:(https://learn.microsoft.com/en-us/windows-hardware/drivers/samples/file-system-driver-samples。

这里有个很好的示例:https://github.com/hkx3upper/FOKS-TROT。

编程框架

微文件系统过滤注册

用这个内核API:

1
2
3
4
5
NTSTATUS FltRegisterFilter(
IN PDRIVER_OBJECT Driver, //本驱动对象
IN CONST PFLT_REGISTRATION Registration, //微过滤器注册结构 宣告注册信息
OUT PFLT_FILTER* RetFilter //返回注册成功的微过滤器句柄
)

开启微过滤器:

1
2
3
NTSTATUS FltStartFiltering(
IN PFLT_FILTER Filter //微过滤器句柄
)//一般总会成功 失败只能放弃过滤别无他法

微过滤器注册结构

定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
typedef struct _FLT_REGISTRATION {
USHORT Size; //结构的大小 就是sizeof(FLT_REGISTRATION)
USHORT Version; //结构的版本 一般FLT_REGISTRATION_VERSION
FLT_REGISTRATION_FLAGS Flags; //标志位 当FLTFL_REGISTRATION_DO_NOT_SUPPORT_SERVICE_STOP时停止服务后Minifilter不会响应且不会调用FilterUnloadCallback 或者NULL不起作用
CONST FLT_CONTEXT_REGISTRATION *ContextRegistration; //上下文处理函数注册
CONST FLT_OPERATION_REGISTRATION *OperationRegistration; //操作回调函数集
PFLT_FILTER_UNLOAD_CALLBACK FilterUnloadCallback; //卸载回调函数 可NULL
PFLT_INSTANCE_SETUP_CALLBACK InstanceSetupCallback; //卷实例安装回调 可NULL
PFLT_INSTANCE_QUERY_TEARDOWN_CALLBACK InstanceQueryTeardownCallback; //控制实例销毁函数 在一个手工解除绑定的请求时调用 可NULL
PFLT_INSTANCE_TEARDOWN_CALLBACK InstanceTeardownStartCallback; //实例解绑定函数 可NULL
PFLT_INSTANCE_TEARDOWN_CALLBACK InstanceTeardownCompleteCallback; //实例解绑定完成函数 可NULL
//剩下这些不常用
PFLT_GENERATE_FILE_NAME GenerateFileNameCallback; //生成文件名回调
PFLT_NORMALIZE_NAME_COMPONENT NormalizeNameComponentCallback; //格式化名字组件回调
PFLT_NORMALIZE_CONTEXT_CLEANUP NormalizeContextCleanupCallback; //格式化上下文清理回调
#if FLT_MGR_LONGHORN
PFLT_TRANSACTION_NOTIFICATION_CALLBACK TransactionNotificationCallback;
PFLT_NORMALIZE_NAME_COMPONENT_EX NormalizeNameComponentExCallback;
#endif // FLT_MGR_LONGHORN
#if FLT_MGR_WIN8
PFLT_SECTION_CONFLICT_NOTIFICATION_CALLBACK SectionNotificationCallback;
#endif // FLT_MGR_WIN8
} FLT_REGISTRATION, *PFLT_REGISTRATION;

一个可行的设置例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//  This defines what we want to filter with FltMgr
const FLT_REGISTRATION FilterRegistration = {
sizeof( FLT_REGISTRATION ), // Size
FLT_REGISTRATION_VERSION, // Version
0, // Flags
NULL, // Context
Callbacks, // Operation callbacks
NPUnload, // MiniFilterUnload
NPInstanceSetup, // InstanceSetup
NPInstanceQueryTeardown, // InstanceQueryTeardown
NPInstanceTeardownStart, // InstanceTeardownStart
NPInstanceTeardownComplete, // InstanceTeardownComplete
NULL, // GenerateFileName
NULL, // GenerateDestinationFileName
NULL // NormalizeNameComponent
};

OperationRegistration域的设置例子:

1
2
3
4
5
6
7
8
9
10
//  operation registration
const FLT_OPERATION_REGISTRATION Callbacks[] = {
{ IRP_MJ_CREATE, //请求的主功能号
0, //标志位 生成请求处理用0 FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO不过滤缓冲读写请求 FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO不过滤分页读写请求
NPPreCreate, //生成预操作回调函数
NPPostCreate //生成后操作回调函数
},
//填写要过滤的定义集合
{ IRP_MJ_OPERATION_END } //最后一个必须填这个
};

卸载回调函数

1
2
3
4
5
6
7
8
NTSTATUS NPUnload(__in FLT_FILTER_UNLOAD_FLAGS Flags) {
UNREFERENCED_PARAMETER(Flags);
PAGED_CODE();
PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("NPminifilter!NPUnload: Entered\n"));
FltCloseCommunicationPort(gServerPort);
FltUnregisterFilter(gFilterHandle);
return STATUS_SUCCESS;
};

预操作回调函数

第一个参数FLT_CALLBACK_DATA为回调数据包,包含请求相关全部信息,所以不用直接读取IRP信息了。

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
FLT_PREOP_CALLBACK_STATUS NPPreCreate(__inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __deref_out_opt PVOID* CompletionContext) {
char FileName[260] = "X:"; //缓冲区 用来获得文件名
NTSTATUS status;
PFLT_FILE_NAME_INFORMATION nameInfo;
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(CompletionContext);
PAGED_CODE(); //检测可分页代码
__try {
status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); //获取文件名信息
if (NT_SUCCESS(status)) { //如果成功则解析文件名信息 比较是否有NOTEPAD.EXE子字符串
if (gCommand == ENUM_BLOCK) {
FltParseFileNameInformation(nameInfo);
if (NPUnicodeStringToChar(&nameInfo->Name, FileName)) //字符串转CHAR大写利于比对字符串
if (strstr(FileName, "NOTEPAD.EXE") > 0) {
Data->IoStatus.Status = STATUS_ACCESS_DENIED; //拒绝
Data->IoStatus.Information = 0;
FltReleaseFileNameInformation(nameInfo);
return FLT_PREOP_COMPLETE; //请求结束 不用再下传了
};
};
//release resource
FltReleaseFileNameInformation(nameInfo); //释放名字资源
};
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("NPPreCreate EXCEPTION_EXECUTE_HANDLER\n");
};
return FLT_PREOP_SUCCESS_WITH_CALLBACK;
};

其中回调数据包的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typedef struct _FLT_CALLBACK_DATA {
FLT_CALLBACK_DATA_FLAGS Flags;
PETHREAD CONST Thread;
PFLT_IO_PARAMETER_BLOCK CONST Iopb;
IO_STATUS_BLOCK IoStatus;
struct _FLT_TAG_DATA_BUFFER *TagData;
union {
struct {
LIST_ENTRY QueueLinks;
PVOID QueueContext[2];
};
PVOID FilterContext[4];
};
KPROCESSOR_MODE RequestorMode;
} FLT_CALLBACK_DATA, *PFLT_CALLBACK_DATA;

注意Iopb域,这里有我们需要的信息:

1
2
3
4
5
6
7
8
9
10
typedef struct _FLT_IO_PARAMETER_BLOCK {
ULONG IrpFlags;
UCHAR MajorFunction;
UCHAR MinorFunction;
UCHAR OperationFlags;
UCHAR Reserved;
PFILE_OBJECT TargetFileObject;
PFLT_INSTANCE TargetInstance;
FLT_PARAMETERS Parameters;
} FLT_IO_PARAMETER_BLOCK, *PFLT_IO_PARAMETER_BLOCK;

这里包括主功能号、次功能号、文件对象指针等,还有个FLT_PARAMETERS参数域,这个域根据不同主功能号而变化,比如写请求的写入位置、长度、缓冲区等参数,这个太长了,在fltkernel.h中自己去看吧。

取得一个文件或目录的文件名信息结构用FltGetFileNameInformation

1
2
3
4
5
NTSTATUS FltGetFileNameInformation(
IN PFLT_CALLBACK_DATA CallbackData,
IN FLT_FILE_NAME_OPTIONS NameOptions,
OUT PFLT_FILE_NAME_INFORMATION *FileNameInformation
)

获取含有路径名称与文件名的结构:

1
2
3
NTSTATUS FltParseFileNameInformation(
IN OUT PFLT_FILE_NAME_INFORMATION FileNameInformation
)

后操作回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
FLT_POSTOP_CALLBACK_STATUS NPPostCreate(__inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __in_opt PVOID CompletionContext, __in FLT_POST_OPERATION_FLAGS Flags) {
FLT_POSTOP_CALLBACK_STATUS returnStatus = FLT_POSTOP_FINISHED_PROCESSING;
PFLT_FILE_NAME_INFORMATION nameInfo;
NTSTATUS status;
UNREFERENCED_PARAMETER(CompletionContext);
UNREFERENCED_PARAMETER(Flags);
// If this create was failing anyway, don't bother scanning now.
if (!NT_SUCCESS(Data->IoStatus.Status) || (STATUS_REPARSE == Data->IoStatus.Status))
return FLT_POSTOP_FINISHED_PROCESSING;
// Check if we are interested in this file.
status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); //回调包中获得名字信息
if (!NT_SUCCESS(status))
return FLT_POSTOP_FINISHED_PROCESSING; //完成I/O所有处理 返回控制给过滤管理器
return returnStatus;
};

其他回调函数

一般这些回调函数都不需要实现什么功能,可直接在微过滤器注册结构中设置为NULL即可。

InstanceSetupCallback

让开发者决定哪个卷需要绑定,哪个卷不需要绑定。这个回调函数在下列情况下被调用:

  • 当一个微过滤器加载时,每个存在的卷都会导致这个调用。
  • 当一个新的卷被挂载时。
  • FltAttachVolume被内核模式调用时。
  • FltAttachVolumeAtAltitude被内核模式调用时。
  • FilterAttach被用户模式调用时。
  • FilterAttachAtAltitude被用户模式调用时。

例子:

1
2
3
4
5
6
7
8
9
NTSTATUS NPInstanceSetup(__in PCFLT_RELATED_OBJECTS FltObjects, __in FLT_INSTANCE_SETUP_FLAGS Flags, __in DEVICE_TYPE VolumeDeviceType, __in FLT_FILESYSTEM_TYPE VolumeFilesystemType) {
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(Flags);
UNREFERENCED_PARAMETER(VolumeDeviceType);
UNREFERENCED_PARAMETER(VolumeFilesystemType);
PAGED_CODE();
PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("NPminifilter!NPInstanceSetup: Entered\n"));
return STATUS_SUCCESS;
};

其中FltObjects结构含有指向微过滤器、卷和实例的指针,这个实例是将要在该函数内生成的实例。

Flags标记是什么操作出发了这个函数:

  • FLTFL_INSTANCE_SETUP_AUTOMATIC_ATTACHMENT:一个微过滤器注册时自动的绑定通知。
  • FLTFL_INSTANCE_SETUP_MANUAL_ATTACHMENT:通过调用用户态FilterAttach或用户态FilterAttachVolumeAtAltitude或内核态FltAttachVolume发起的手工请求。
  • FLTFL_INSTANCE_SETUP_NEWLY_MOUNTED_VOLUME:文件系统刚刚挂载了一个卷。

还通过得到VolumeDeviceType卷设备类型和VolumeFilesystemType卷文件系统类型来判断这个卷是否是过滤器所感兴趣的。微过滤器还可以用FltGetVolumeProperties获取卷属性、用FltSetInstanceContext在实例上设置上下文、在卷上打开关闭文件等。如果这个回调函数返回STATUS_SUCCESS或被设置为NULL时将这个实例绑定到卷上,如果返回警告或错误则不绑定。

InstanceQueryTeardownCallback

控制实例销毁函数,只有在一个手工解除绑定时被调用。手工解除绑定有两种可能:

  • 内核模式调试FltDetachVolume
  • 用户模式调试FilterDetach

如果过滤器不提供这个,不允许手工解除绑定,但卷和过滤器的卸载仍然可以。如果调用成功,那么InstanceTeardownStartCallbackInstanceTeardownCompleteCallback将会被调用。返回错误时手工解除绑定失败,推荐错误代码STATUS_FLT_DO_NOT_DETACH。

例子:

1
2
3
4
5
6
7
NTSTATUS NPInstanceQueryTeardown(__in PCFLT_RELATED_OBJECTS FltObjects, __in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags) {
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(Flags);
PAGED_CODE();
PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("NPminifilter!NPInstanceQueryTeardown: Entered\n"));
return STATUS_SUCCESS;
};

InstanceTeardownStartCallback

解除绑定回调函数,在决定解除绑定时完成这些东西:

  • 重设所有未决I/O操作,包括预操作和后操作。
  • 保证不会有新的I/O操作进入未决。
  • 对刚刚到达的操作开始最少的工作。
  • 关闭所有打开的文件。
  • 取消所有本过滤器发起的I/O请求。
  • 停止将新的工作任务排队。

该函数完成后微过滤器把控制权交还给过滤管理器来继续它的销毁过程。

例子:

1
2
3
4
5
6
7
VOID NPInstanceTeardownStart(__in PCFLT_RELATED_OBJECTS FltObjects, __in FLT_INSTANCE_TEARDOWN_FLAGS Flags) {
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(Flags);
PAGED_CODE();
PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("NPminifilter!NPInstanceTeardownStart: Entered\n"));
return;
};

FltObjects同上,有微过滤器、卷和实例。

Reason指明这次销毁原因,可能是以下标记的组合:

  • FLTFL_INSTANCE_TEARDOWN_MANUAL:这次销毁操作是一个手工的请求,即FilterDetachFltDetachVolume
  • FLTFL_INSTANCE_TEARDOWN_FILTER_UNLOAD:微过滤器执行卸载或选择把卸载请求失败掉导致的。
  • FLTFL_INSTANCE_TEARDOWN_MANDATORY_FILTER_UNLOAD:强制卸载导致的,不能把卸载请求失败掉。
  • FLTFL_INSTANCE_TEARDOWN_VOLUME_DISMOUNT:因为一个卷被解除挂载。
  • FLTFL_INSTANCE_TEARDOWN_INTERNAL_ERROR:安装实例时内部错误导致的,如内存不足。

该回调函数不能失败,过滤管理器保证运行在Passive中断级。

InstanceTeardownCompleteCallback

实例解除绑定完成函数。当所有与这个实例相关的操作都排除干净或完成时,该函数被调用。过滤管理器保证此时此实例存在的所有操作回调都完成了,这时微过滤器必须关闭这个实例打开的所有文件。

函数原型完全同上InstanceTeardownStart,例子:

1
2
3
4
5
6
7
VOID NPInstanceTeardownComplete(__in PCFLT_RELATED_OBJECTS FltObjects, __in FLT_INSTANCE_TEARDOWN_FLAGS Flags) {
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(Flags);
PAGED_CODE();
PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("NPminifilter!NPInstanceTeardownComplete: Entered\n"));
return;
};

该回调函数不能失败,过滤管理器保证运行在Passive中断级。

Minifilter与应用通信

建立通信端口

方法就是定义一个通信端口,然后用Minifilter内建支持的API提供给开发者用。

建立通信端口的方法,这一部分已经在之前DriverEntry中实现了:

1
2
3
4
5
6
7
8
PSECURITY_DESCRIPTOR sd;
OBJECT_ATTRIBUTES oa;
status = FltBuildDefaultSecurityDescriptor(&sd, FLT_PORT_ALL_ACCESS); //以这个权限产生一个安全性叙述子
if (!NT_SUCCESS(status))
goto final;
RtlInitUnicodeString(&uniString, MINISPY_PORT_NAME); //通信端口定义的名称
InitializeObjectAttributes(&oa, &uniString, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, sd);
status = FltCreateCommunicationPort(gFilterHandle, &gServerPort, &oa, NULL, NPMiniConnect, NPMiniDisconnect, NPMiniMessage, 1); //必须提供三个回调函数

其中三个回调函数具体如下:

  • NPMiniConnect:用户态与内核态建立连接时内核会调用的函数。
  • NPMiniDisconnect:用户态与内核态连接结束时内核会调用的函数。
  • NPMiniMessage:用户态与内核态传送数据时内核会调用到的函数。

用户态就不要再使用CreateFileDeviceIoControl这一系列,Minifilter有FilterConnectCommunicationPort调用我们提供的NPMiniConnect,有FilterSendMessage调用我们提供的NPMiniMessage

WDK定义的FilterConnectCommunicationPort原型:

1
2
3
4
5
6
7
8
HRESULT WINAPI FilterConnectCommunicationPort(
IN LPCWSTR lpPortName, //通信端口名字
IN DWORD dwOptions, //废弃 设为0
IN OPTIONAL LPVOID lpContext, //传入上下文数据给connect routine
IN DWORD dwSizeOfContext, //上下文数据大小 单位字节
IN OPTIONAL LPSECURITY_ATTRIBUTES lpSecurityAttributes, //通过已定义端口名称得到句柄
OUT PHANDLE hPort //返回通信端口句柄
)

WDK定义的FilterSendMessage原型:

1
2
3
4
5
6
7
8
HRESULT WINAPI FilterSendMessage(
IN HANDLE hPort, //连接端口名字
IN OPTIONAL LPVOID lpInBuffer, //输入缓冲区 自定义结构
IN DWORD dwInBufferSize, //输入缓冲区大小
IN OUT OPTIONAL LPVOID lpOutBuffer, //输出缓冲区 可传入也可获得
IN DWORD dwOutBufferSize, //输出缓冲区大小
OUT LPDWORD lpBytesReturned //调用成功时返回lpOutBuffer大小
)

通过DLL使用通信端口

一般情况下,编写一个DLL专门用来与内核层Minifilter驱动程序通信,应用程序调用这个与内核通信。其中编写这个DLL时需要包含WDK头文件FltUser.h,还要搞到fltLib.lib和fltMgr.lib。

NPdll.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
#include "windows.h"
#include <stdio.h>
#include <FltUser.h> //注意要这个

#pragma comment(lib, "user32.lib")
#pragma comment(lib, "kernel32.lib")
#pragma comment(lib, "fltLib.lib") //还有这俩
#pragma comment(lib, "fltMgr.lib")
#pragma comment(lib, "ntoskrnl.lib")
#pragma comment(lib, "hal.lib")

extern HANDLE g_hPort; //通信端口句柄
#define NPMINI_NAME L"NPminifilter" //微过滤器名字
#define NPMINI_PORT_NAME L"\\NPMiniPort" //通信端口名字

__declspec(dllexport) int InitialCommunicationPort(VOID); //导出函数
__declspec(dllexport) int NPSendMessage(PVOID InputBuffer);

typedef enum _NPMINI_COMMAND {
ENUM_PASS = 0, //不过滤
ENUM_BLOCK //过滤
} NPMINI_COMMAND;

typedef struct _COMMAND_MESSAGE {
NPMINI_COMMAND Command; //储存列举NPMINI_COMMAND命令的结构
} COMMAND_MESSAGE, *PCOMMAND_MESSAGE;

DLL主程序:

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

HANDLE g_hPort = INVALID_HANDLE_VALUE; //初始化句柄

#ifdef _MANAGED
#pragma managed(push, off)
#endif

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH: //载入DLL成功时呼叫此功能码
InitialCommunicationPort(); //初始化通信端口
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH: //卸载DLL成功时呼叫此功能码
break;
};
return TRUE;
};

#ifdef _MANAGED
#pragma managed(pop)
#endif

int InitialCommunicationPort(VOID) {
DWORD hResult = FilterConnectCommunicationPort(NPMINI_PORT_NAME, 0, NULL, 0, NULL, &g_hPort);
if (hResult != S_OK)
return hResult; //连接失败
return 0;
};

int NPSendMessage(PVOID InputBuffer) { //传送数据
DWORD bytesReturned = 0; //返回的结构大小
DWORD hResult = 0; //返回值
PCOMMAND_MESSAGE commandMessage = (PCOMMAND_MESSAGE)InputBuffer;
hResult = FilterSendMessage(g_hPort, commandMessage, sizeof(COMMAND_MESSAGE), NULL, NULL, &bytesReturned);
if (hResult != S_OK)
return hResult;
return 0;
};

应用层的编写

NPapp.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
#include "NPapp.h"
#include <iostream>
#include <tchar.h>
using namespace std;

int(__stdcall* pNPSendMessage)(PVOID pInBuffer);
int(__stdcall* pInitialCommunicationPort)(VOID);

CNPApp::CNPApp() {
m_hModule = NULL;
LoadNPminifilterDll();
};

CNPApp::~CNPApp() {
if (m_hModule)
FreeLibrary(m_hModule);
};

BOOL CNPApp::LoadNPminifilterDll(VOID) {
m_hModule = LoadLibrary(TEXT("minifilter_dll.dll"));
if (m_hModule != NULL) {
pNPSendMessage = (int(__stdcall*)(PVOID)) GetProcAddress(GetModuleHandle(TEXT("minifilter_dll.dll")), "NPSendMessage");
if (!pNPSendMessage)
return false;
return true;
};
return false;
};

VOID CNPApp::NPMessage(COMMAND_MESSAGE data) {
if (m_hModule == NULL)
if (LoadNPminifilterDll() == false)
return;
pNPSendMessage(&data);
return;
};

int _tmain(int argc,_TCHAR* argv[]) {
CNPApp ControlObj;
char input;
while (true) {
cout << "Enter 'a' for PASS MODE, 'b' for BLOCKMODE or 'q' to EXIT" << endl;
cin >> input;
if (input == 'a' || input == 'A') {
COMMAND_MESSAGE data;
data.Command = ENUM_PASS;
ControlObj.NPMessage(data);
printf("==>NOTEPAD.EXE PASS MODE\n");
}
else if (input == 'b' || input == 'B') {
COMMAND_MESSAGE data;
data.Command = ENUM_BLOCK;
ControlObj.NPMessage(data);
printf("==>NOTEPAD.EXE BLOCK MODE\n");
}
else if (input == 'q' || input == 'Q') {
printf("EXIT\n");
break;
}
else
printf("Wrong Parameter!!!\n");
};
system("pause");
return 0;
};

NPapp.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
#pragma once

#include "windows.h"
#include <vector>
#include <string>
using namespace std;

typedef enum _NPMINI_COMMAND {
ENUM_PASS = 0,
ENUM_BLOCK
} NPMINI_COMMAND;

typedef struct _COMMAND_MESSAGE {
NPMINI_COMMAND Command;
} COMMAND_MESSAGE, * PCOMMAND_MESSAGE;

class CNPApp{
public:
CNPApp();
virtual ~CNPApp();
VOID NPMessage(COMMAND_MESSAGE data);

private:
HINSTANCE m_hModule;
BOOL LoadNPminifilterDll(VOID);
};

Minifilter的安装

编译

要链接fltMgr.lib文件,方法是项目属性->链接器->输入->附加依赖项中加上flgMgr.lib。

编写INF文件

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
[Version]
Signature = "$Windows NT$"
Class = "ActivityMonitor" ;类别名称视要注册的过滤器功能而定
ClassGuid = {b86dff51-a31e-4bac-b3cf-e8cfe75c9fc2} ;这个数值视类别种类而定
Provider = %Msft%
DriverVer = 06/16/2007,1.0.0.1
CatalogFile = NPminifilter.cat

[DestinationDirs]
DefaultDestDir = 12
MiniFilter.DriverFiles = 12 ;代表%windir%\system32\drivers

[DefaultInstall]
OptionDesc = %ServiceDescription%
CopyFiles = MiniFilter.DriverFiles

[DefaultInstall.Services]
AddService = %ServiceName%,,MiniFilter.Service

[DefaultUninstall]
DelFiles = MiniFilter.DriverFiles

[DefaultUninstall.Services]
DelService = %ServiceName%,0x200 ;服务停止后才删除

[MiniFilter.Service]
DisplayName = %ServiceName%
Description = %ServiceDescription%
ServiceBinary = %12%\%DriverName%.sys ;%windir%\system32\drivers\
Dependencies = "FltMgr" ;在FltMgr服务下
ServiceType = 2 ;SERVICE_FILE_SYSTEM_DRIVER
StartType = 3 ;启动类型 3为SERVICE_DEMAND_START表示当有需求加载时才启动此驱动功能 0为SERVICE_BOOT_START表示开机启动时自动加载
ErrorControl = 1 ;SERVICE_ERROR_NORMAL
LoadOrderGroup = "FSFilter Activity Monitor"
AddReg = MiniFilter.AddRegistry

[MiniFilter.AddRegistry]
HKR,,"DebugFlags",0x00010001 ,0x0
HKR,"Instances","DefaultInstance",0x00000000,%DefaultInstance%
HKR,"Instances\"%Instance1.Name%,"Altitude",0x00000000,%Instance1.Altitude%
HKR,"Instances\"%Instance1.Name%,"Flags",0x00010001,%Instance1.Flags%

[MiniFilter.DriverFiles]
%DriverName%.sys

[SourceDisksFiles]
NPminifilter.sys = 1,,

[SourceDisksNames]
1 = %DiskId1%,,,

[Strings]
Msft = "Microsoft Corporation"
ServiceDescription = "NPminifilter Mini-Filter Driver"
ServiceName = "NPminifilter" ;服务名
DriverName = "NPminifilter" ;驱动名
DiskId1 = "NPminifilter Device Installation Disk"

DefaultInstance = "NPminifilter Instance"
Instance1.Name = "NPminifilter Instance"
Instance1.Altitude = "370030" ;层级码 决定过滤层次上下 微过滤器层级码范围如20000~429999 需要向微软申请注册 但这里暂时用370030
Instance1.Flags = 0x0 ; Allow all attachments

右键INF安装这个驱动,该.sys便安装到%windir%\\system32\\drivers下,可用OSR Driver Loader检查已安装的Minifilter在系统上的Load Group顺序。

启动安装后的Minifilter

在INF的目录下敲命令:

第一种:

1
2
net start 驱动名称
net stop 驱动名称

第二种:

1
2
fltmc load 驱动名称
fltmc unload 驱动名称