MiniFilter内核回调
字数 4119
更新时间 2026-03-19 12:03:09
MiniFilter 微过滤器内核回调技术教学文档
第一章:MiniFilter 基础概念与原理
1.1 微过滤器内核回调定义
微过滤器内核回调是专门的回调例程,用于在不同阶段监控和拦截文件系统操作,例如在创建文件阶段监控和拦截,在修改文件内容阶段进行监控和拦截。
1.2 EDR 中的应用
终端检测与响应(EDR)系统利用这些回调来捕获有关恶意文件系统活动的遥测数据,例如:
- 检测攻击者何时将恶意文件落地到磁盘
- 识别短时间内大量文件被加密的情况
第二章:MiniFilter 工作原理
2.1 回调注册机制
微过滤器回调通过 FltRegisterFilter API 函数进行注册。函数原型如下:
NTSTATUS FLTAPI FltRegisterFilter(
[in] PDRIVER_OBJECT Driver, // 程序对象的指针
[in] const FLT_REGISTRATION *Registration, // 指向调用方分配的微过滤器驱动程序注册结构
[out] PFLT_FILTER *RetFilter
);
2.2 FLT_REGISTRATION 结构体
这是微过滤器配置的核心结构,关键字段包括:
- Callback:指向操作注册数组,定义了针对不同I/O操作(如创建、写入、删除、读取等)的回调函数
- Unload:指向卸载例程的指针,当微过滤器被卸载时系统会调用该例程
2.3 CALLBACK_NODE 与双向链表
- 存储结构:微过滤器回调存储在由 CALLBACK_NODE 结构组成的双向链表中
- 实例管理:每一个微过滤器实例都维护着这样一个列表,用于处理不同的文件系统操作
- 回调类型:
- 操作前回调 (Pre-Operation Callback):在文件操作发生之前调用
- 操作后回调 (Post-operation Callback):在文件系统操作完成之后调用
2.4 分层架构
微过滤器驱动程序采用分层架构来拦截和监控文件系统操作:
- 分层原理:驱动程序在系统堆栈中垂直排列顺序
- 处理流程:当文件操作请求(如"文件写入")从应用层发出时,会从最高海拔(Altitude)的过滤器依次向下流动
- 拦截机制:每一层都有机会查看、修改或拦截这个请求
2.5 实例机制
每个微过滤器驱动可以拥有一个或多个实例(Instance),使其能够挂钩到不同的文件系统卷或操作:
- 实例化示例:C盘和D盘分别对应
InstanceC和InstanceD实例 - 回调触发:在C盘创建文件触发
Instance C回调,在D盘创建文件触发Instance D回调
2.6 回调节点结构
在每一个实例内部,针对特定的文件系统操作注册了多个回调节点结构:
- 专业化处理:一个回调节点处理一种特定的文件系统操作
Create节点:处理创建文件操作Read节点:处理读取文件操作
- 回调位置:
- 操作前内核回调:位于回调节点偏移 0x18 处
- 操作后内核回调:位于回调节点偏移 0x20 处
第三章:静态与动态分析技术
3.1 IDA Pro 静态分析
- 定位关键函数:在驱动程序的导入表中搜索
FltRegisterFilter函数 - 分析参数:重点关注第二个参数(包含回调函数的
FLT_REGISTRATION结构体地址) - 查看回调数组:通过
Callbacks成员定位FLT_OPERATION_REGISTRATION数组 - 分析回调函数:查看针对不同I/O操作(CREATE、READ、WRITE等)的微过滤器操作前和操作后内核回调
3.2 Windbg 动态分析
3.2.1 查看已加载微过滤器
使用 !fltkd.filters 命令显示所有已注册的 FLT_FILTER 结构列表
3.2.2 分析实例结构
- 查看实例:使用
!instance <实例地址> 4命令 - 理解实例关系:每个微过滤器可以包含一个或多个实例,代表附加到不同磁盘卷的过滤器实例
- 实例数量含义:例如,
WdFilter有五个实例表示它正在同时监控五个不同的卷
3.2.3 分析回调节点
- 查看CALLBACK_NODE结构:使用
dt _CALLBACK_NODE <Address>命令 - 结构成员:
CallbackLinks:指向回调节点双向链表中上一个和下一个节点的指针Instance:实例指针,指向关联的FLT_INSTANCE结构PreOperation:操作前回调函数指针PostOperation:操作后回调函数指针
3.2.4 查看实例详细信息
使用 dt _FLT_INSTANCE <实例地址> 命令查看过滤器实例的详细信息
第四章:自定义微过滤器开发
4.1 基本框架代码
#include <fltKernel.h>
// 声明全局句柄
PFLT_FILTER gFilterHandle = NULL;
// 操作前回调函数
extern "C" FLT_PREOP_CALLBACK_STATUS PreOperationCallback(
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_Flt_CompletionContext_Outptr_ PVOID* CompletionContext
)
{
UNREFERENCED_PARAMETER(CompletionContext);
UNREFERENCED_PARAMETER(FltObjects);
// 获取执行文件系统操作的进程PID
HANDLE processId = PsGetCurrentProcessId();
// 获取执行文件系统操作的线程TID
HANDLE threadId = PsGetCurrentThreadId();
// 判断I/O请求的操作类型
if (Data->Iopb->MajorFunction == IRP_MJ_READ) {
DbgPrintEx(0, 0, "[Minifilter] Read Operation: PID: %p, TID: %p\n", processId, threadId);
}
else if (Data->Iopb->MajorFunction == IRP_MJ_WRITE) {
DbgPrintEx(0, 0, "[Minifilter] Write Operation: PID: %p, TID: %p\n", processId, threadId);
}
else if (Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION) {
FILE_INFORMATION_CLASS fileInfoClass = Data->Iopb->Parameters.SetFileInformation.FileInformationClass;
if (fileInfoClass == FileDispositionInformation || fileInfoClass == FileRenameInformation) {
DbgPrintEx(0, 0, "[Minifilter] Delete/Rename: PID: %p\n", processId);
}
}
return FLT_PREOP_SUCCESS_NO_CALLBACK;
}
// 操作后回调函数
extern "C" FLT_POSTOP_CALLBACK_STATUS PostOperationCallback(
_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);
return FLT_POSTOP_FINISHED_PROCESSING;
}
// Unload例程
extern "C" NTSTATUS Unload(_In_ FLT_FILTER_UNLOAD_FLAGS Flags) {
UNREFERENCED_PARAMETER(Flags);
if (gFilterHandle != NULL) {
FltUnregisterFilter(gFilterHandle);
DbgPrintEx(0, 0, "[Minifilter] Unloaded Successfully\n");
}
return STATUS_SUCCESS;
}
// 注册列表
CONST FLT_OPERATION_REGISTRATION CallbackList[] = {
{ IRP_MJ_READ, 0, PreOperationCallback, PostOperationCallback },
{ IRP_MJ_WRITE, 0, PreOperationCallback, PostOperationCallback },
{ IRP_MJ_SET_INFORMATION, 0, PreOperationCallback, PostOperationCallback },
{ IRP_MJ_OPERATION_END }
};
// 注册结构
CONST FLT_REGISTRATION FilterRegister = {
sizeof(FLT_REGISTRATION), // 结构体大小
FLT_REGISTRATION_VERSION, // 微过滤器注册版本
0,
NULL,
CallbackList, // 指向操作回调数组的指针
Unload, // 卸载回调
NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
// 驱动程序入口点
extern "C" NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) {
UNREFERENCED_PARAMETER(RegistryPath);
// 注册微过滤器
NTSTATUS status = FltRegisterFilter(DriverObject, &FilterRegister, &gFilterHandle);
if (NT_SUCCESS(status)) {
status = FltStartFiltering(gFilterHandle);
if (!NT_SUCCESS(status)) {
FltUnregisterFilter(gFilterHandle);
}
}
return status;
}
4.2 遥测数据收集
微过滤器内核回调可收集的关键遥测数据包括:
- 文件系统执行的操作类型(创建、写入、删除文件等)
- 发起操作的进程PID
- 发起操作的线程TID
4.3 注册表配置
加载微过滤器驱动前需要在Windows注册表中手动配置:
# 在 Services(服务)下创建主键 MiniFilterDriver
$MiniFilterDriverPath = "HKLM:\SYSTEM\CurrentControlSet\Services\MiniFilterDriver"
New-Item -Path $MiniFilterDriverPath -Force
# 设置驱动文件路径、类型、启动方式和错误控制
Set-ItemProperty -Path $MiniFilterDriverPath -Name "ImagePath" -Value "\??\C:\Users\Public\MiniFilterDriver.sys"
Set-ItemProperty -Path $MiniFilterDriverPath -Name "Type" -Value 0x00000001
Set-ItemProperty -Path $MiniFilterDriverPath -Name "Start" -Value 0x00000003
Set-ItemProperty -Path $MiniFilterDriverPath -Name "ErrorControl" -Value 0x00000001
# 创建 Instances(实例)键及其子键
$instancesPath = "$MiniFilterDriverPath\Instances"
New-Item -Path $instancesPath -Force
# 在 Instances 键中设置默认实例名称
Set-ItemProperty -Path $instancesPath -Name "DefaultInstance" -Value "MiniFilterDriver Instance"
# 在 Instances 下创建具体的 "MiniFilterDriver Instance" 键
$instancePath = "$instancesPath\MiniFilterDriver Instance"
New-Item -Path $instancePath -Force
# 在该实例键下设置海拔高度 (Altitude) 和标志位 (Flags)
Set-ItemProperty -Path $instancePath -Name "Altitude" -Value "370000"
Set-ItemProperty -Path $instancePath -Name "Flags" -Value 0x00000000
关键参数说明:
- Altitude:海拔高度,决定微过滤器驱动何时接收到I/O请求,数值越大层级越高,接收请求越早
- ImagePath:驱动程序文件路径
4.4 加载与测试
- 查看已加载过滤器:使用
fltmc命令 - 加载自定义过滤器:
fltmc load <过滤器名称> - 查看调试输出:在Windbg中查看DbgPrintEx输出的遥测数据
- 验证过滤器注册:使用
!fltkd.filter命令
第五章:回调节点移除技术
5.1 双向链表结构
每个回调节点都是回调链表结构的一部分,类型为 LIST_ENTRY,包含 Flink 和 Blink 字段。
5.2 断链操作原理
- 链表结构:双向链表包含前向指针(
Flink)和后向指针(Blink) - 断链目标:从链表中断开特定节点的连接
- 操作步骤:
- 让目标节点的前一个节点的
Flink指向目标节点的下一个节点 - 让目标节点的下一个节点的
Blink指向目标节点的前一个节点 - 将目标节点自身的
Flink和Blink指向自身
- 让目标节点的前一个节点的
5.3 具体操作命令
// 假设当前节点地址: 0xffff8f8d`b31802c0
// 前一个节点地址: 0xffff8f8d`b30e32d0
// 后一个节点地址: 0xffff8f8d`b5768f00
// 第一步:前一个节点的Flink指向后一个节点
eq 0xffff8f8d`b30e32d0 0xffff8f8d`b5768f00
// 第二步:后一个节点的Blink指向前一个节点
eq 0xffff8f8d`b5768f00+0x8 0xffff8f8d`b30e32d0
// 第三步:当前节点的Flink和Blink指向自身
eq 0xffff8f8d`b31802c0 0xffff8f8d`b31802c0
eq 0xffff8f8d`b31802c0+0x8 0xffff8f8d`b31802c0
5.4 移除Sysmon微过滤器内核回调实战
5.4.1 准备工作
- 安装Sysmon工具:参考相关安装文档
- 验证日志记录:打开事件查看器查看Sysmon操作日志
- 定位Sysmon过滤器:在Windbg中使用
!fltkd.filters查找SysmonDrv
5.4.2 操作步骤
- 查看实例:针对所有Sysmon实例执行操作
- 定位CREATE节点:找到与文件创建操作相关的回调节点
- 获取指针信息:列出节点的
Flink和Blink指针 - 执行断链操作:对每个实例的CREATE节点执行上述断链操作
- 验证效果:尝试创建新文件,验证Sysmon是否不再记录相关事件
5.4.3 安全影响
通过断开回调连接,可以使恶意文件直接落地到磁盘而不被EDR检测,因为回调无法感知文件操作。
第六章:系统微过滤器枚举技术
6.1 核心API函数
6.1.1 FltEnumerateFilters函数
NTSTATUS FltEnumerateFilters(
[out] PFLT_FILTER *FilterList, // 指向缓冲区数组的指针,存放微过滤器句柄
[in] ULONG FilterListSize, // 缓冲区能容纳的句柄数量
[out] PULONG NumberFiltersReturned // 实际存入缓冲区的句柄数量
);
使用模式:需要调用两次
- 第一次调用:获取系统中实际存在的过滤器总数
- 第二次调用:填充FilterList缓冲区
6.1.2 FltGetFilterInformation函数
NTSTATUS FltGetFilterInformation(
[in] PFLT_FILTER Filter, // 目标过滤器的句柄
[in] FILTER_INFORMATION_CLASS InformationClass, // 请求的信息类型
[out] PVOID Buffer, // 接收数据的缓冲区
[in] ULONG BufferSize, // 缓冲区大小
[out] PULONG BytesReturned // 实际写入或需要的字节数
);
使用模式:需要调用两次
- 第一次调用:返回过滤器信息所需的字节数
- 第二次调用:真正获取微过滤器的基本信息
6.2 数据结构定义
6.2.1 自定义数据结构
typedef struct _MinifilterData {
WCHAR FilterName[256]; // 存储过滤器名称的宽字符数组
WCHAR FilterAltitude[256]; // 存储过滤器海拔(Altitude)的宽字符数组
} MinifilterData, *PMinifilterData;
6.2.2 系统结构体
typedef struct _FILTER_AGGREGATE_BASIC_INFORMATION {
ULONG NextEntryOffset;
ULONG Flags;
union {
struct {
ULONG FrameID;
ULONG NumberOfInstances;
USHORT FilterNameLength;
USHORT FilterNameBufferOffset;
USHORT FilterAltitudeLength;
USHORT FilterAltitudeBufferOffset;
} MiniFilter;
struct {
USHORT FilterNameLength;
USHORT FilterNameBufferOffset;
} LegacyFilter;
} Type;
} FILTER_AGGREGATE_BASIC_INFORMATION, *PFILTER_AGGREGATE_BASIC_INFORMATION;
关键字段说明:
FilterNameLength:过滤器名称的长度FilterNameBufferOffset:名称字符串偏移地址FilterAltitudeLength:海拔高度字符串的长度FilterAltitudeBufferOffset:海拔高度字符串偏移地址
6.3 驱动程序层实现
6.3.1 内存分配与枚举
// 第一次调用:获取过滤器总数
status = FltEnumerateFilters(NULL, bufferSize, &filterCount);
if (status != STATUS_BUFFER_TOO_SMALL) {
return status;
}
// 计算所需缓冲区大小
bufferSize = filterCount * sizeof(PFLT_FILTER);
filterList = (PFLT_FILTER*)ExAllocatePool2(POOL_FLAG_NON_PAGED, bufferSize, DRIVER_TAG);
// 第二次调用:填充过滤器句柄列表
status = FltEnumerateFilters(filterList, bufferSize, &filterCount);
if (!NT_SUCCESS(status)) {
ExFreePool(filterList);
return status;
}
6.3.2 获取过滤器信息
// 遍历所有微过滤器
for (ULONG i = 0; i < filterCount; i++) {
PFLT_FILTER filter = filterList[i];
PFILTER_AGGREGATE_BASIC_INFORMATION filterInfo = NULL;
ULONG filterInfoSize = 0;
ULONG filterInfoBufferSize = 0;
// 第一次调用:获取所需缓冲区大小
status = FltGetFilterInformation(filter, FilterAggregateBasicInformation,
NULL, 0, &filterInfoBufferSize);
// 分配内存
filterInfo = (PFILTER_AGGREGATE_BASIC_INFORMATION)ExAllocatePool2(
POOL_FLAG_NON_PAGED, filterInfoBufferSize, DRIVER_TAG);
if (!filterInfo) {
continue;
}
// 第二次调用:获取实际数据
status = FltGetFilterInformation(filter, FilterAggregateBasicInformation,
filterInfo, filterInfoBufferSize, &filterInfoSize);
if (!NT_SUCCESS(status)) {
ExFreePool(filterInfo);
continue;
}
// 通过偏移量获取名称和海拔高度
PWCHAR filterNameAddr = (PWCHAR)((PCHAR)filterInfo + filterInfo->Type.MiniFilter.FilterNameBufferOffset);
PWCHAR filterAltitudeAddr = (PWCHAR)((PCHAR)filterInfo + filterInfo->Type.MiniFilter.FilterAltitudeBufferOffset);
// 复制到输出缓冲区
wcsncpy(filtersData[i].FilterName, filterNameAddr,
min(filterInfo->Type.MiniFilter.FilterNameLength / sizeof(WCHAR), 255));
filtersData[i].FilterName[min(filterInfo->Type.MiniFilter.FilterNameLength / sizeof(WCHAR), 255)] = L'\0';
wcsncpy(filtersData[i].FilterAltitude, filterAltitudeAddr,
min(filterInfo->Type.MiniFilter.FilterAltitudeLength / sizeof(WCHAR), 255));
filtersData[i].FilterAltitude[min(filterInfo->Type.MiniFilter.FilterAltitudeLength / sizeof(WCHAR), 255)] = L'\0';
ExFreePool(filterInfo);
}
6.4 用户层实现
6.4.1 打开设备句柄
HANDLE Hdevice = CreateFileA("\\\\.\\LCKDriver",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
6.4.2 发送IOCTL请求
// 在堆栈分配64KB内存
DWORD lpBytesReturned = 0;
BYTE buffer[1 << 16]; // 分配64KB缓冲区
memset(buffer, 0, sizeof(buffer));
BOOL success = DeviceIoControl(
Hdevice,
IOCTL_LIST_MINIFILTERS, // 控制码,需与驱动程序匹配
NULL, 0, // 输入缓冲区
buffer, sizeof(buffer), // 输出缓冲区
&lpBytesReturned, // 实际返回长度
NULL
);
6.4.3 处理并显示结果
if (success) {
DWORD count = lpBytesReturned / sizeof(MinifilterData);
MinifilterData* data = (MinifilterData*)buffer;
wprintf(L"\n成功获取到 %lu 个微过滤器信息:\n", count);
wprintf(L"--------------------------------------------------\n");
wprintf(L"%-4s | %-20s | %s\n", L"ID", L"Filter Name", L"Altitude");
wprintf(L"--------------------------------------------------\n");
for (DWORD i = 0; i < count; i++) {
wprintf(L"[%02lu] | %-20ls | %ls\n",
i,
data[i].FilterName,
data[i].FilterAltitude);
}
wprintf(L"--------------------------------------------------\n");
} else {
printf("IOCTL 请求失败,错误代码: %lu\n", GetLastError());
}
第七章:调试技巧与问题解决
7.1 Windbg调试技巧
- 强制开启符号解析:
.symopt- 100命令解决符号文件找不到的问题 - 查看链表结构:使用
dt nt!_LIST_ENTRY <地址>命令 - 实例分析:使用
!instance <实例地址> 4查看详细信息 - 结构解析:使用
dt命令解析各种内核结构
7.2 常见问题处理
- 符号问题:确保正确加载符号文件
- 内存访问:注意指针偏移计算
- 权限问题:确保以管理员权限运行相关工具
- 注册表配置:确保Altitude值设置合理,避免冲突
第八章:安全应用与防御
8.1 攻击视角应用
- 绕过EDR检测:通过移除特定微过滤器的回调节点,使恶意文件操作不被监控
- 持久化隐藏:修改微过滤器链表,隐藏特定文件操作
- 权限提升:通过控制微过滤器实现权限绕过
8.2 防御视角应用
- 检测回调移除:监控微过滤器链表的完整性
- 完整性校验:定期检查关键微过滤器的回调函数
- 行为监控:检测异常的微过滤器操作
- 深度防御:采用多层微过滤器防护
8.3 最佳实践
- 最小权限原则:微过滤器只监控必要的操作
- 错误处理:完善的错误处理机制
- 性能考虑:回调函数应尽可能高效
- 兼容性测试:确保与系统和其他过滤器的兼容性
- 安全审计:定期审计微过滤器配置和实现
总结
本教学文档详细介绍了MiniFilter微过滤器内核回调技术的完整知识体系,从基础概念、工作原理、开发实现到高级攻防技术。重点内容包括:
- 核心机制:回调注册、双向链表、分层架构
- 分析技术:静态分析与动态调试方法
- 开发实践:自定义微过滤器开发与部署
- 攻防技术:回调节点移除与防御检测
- 系统枚举:完整的内核与用户态实现
通过掌握这些技术,安全研究人员可以深入理解Windows文件系统过滤机制,开发安全监控工具,或进行相关的安全测试与研究。在实际应用中,应遵守相关法律法规,仅将技术用于合法的安全研究和防御目的。
相似文章
相似文章