Minifilter 是一种文件过滤驱动,该驱动简称为微过滤驱动,相对于传统的sfilter文件过滤驱动来说,微过滤驱动编写时更简单,其不需要考虑底层RIP如何派发且无需要考虑兼容性问题,微过滤驱动使用过滤管理器FilterManager提供接口,由于提供了管理结构以及一系列管理API函数,所以枚举过滤驱动将变得十分容易。

通常文件驱动过滤是ARK重要功能之一,如下是一款闭源ARK工具的输出效果图。

由于MiniFilter提供了FltEnumerateFilters函数,所以只需要调用这些函数即可获取到所有的过滤器地址,我们看下微软公开的信息。

NTSTATUS FLTAPI FltEnumerateFilters(
[out] PFLT_FILTER *FilterList,
[in] ULONG FilterListSize,
[out] PULONG NumberFiltersReturned
);

此函数需要注意,如果用户将FilterList设置为NULL则默认是输出当前系统中存在的过滤器数量,而如果传入的是一个内存地址,则将会枚举系统中所有的过滤器信息。

使用FltEnumerateFilters这个API,它会返回过滤器对象FLT_FILTER的地址,然后根据过滤器对象的地址,加上一个偏移,获得记录过滤器PreCall、PostCall、IRP等信息的PFLT_OPERATION_REGISTRATION结构体指针。

上文之所以说要加上偏移,是因为FLT_FILTER的定义在每个系统都不同,比如WIN10 X64中的定义以下样子,这里我们需要记下+0x1a8 Operations因为他指向的就是_FLT_OPERATION_REGISTRATION结构的偏移地址。

lyshark: kd> dt fltmgr!_FLT_FILTER
+0x000 Base : _FLT_OBJECT
+0x030 Frame : Ptr64 _FLTP_FRAME
+0x038 Name : _UNICODE_STRING
+0x048 DefaultAltitude : _UNICODE_STRING
+0x058 Flags : _FLT_FILTER_FLAGS
+0x060 DriverObject : Ptr64 _DRIVER_OBJECT
+0x068 InstanceList : _FLT_RESOURCE_LIST_HEAD
+0x0e8 VerifierExtension : Ptr64 _FLT_VERIFIER_EXTENSION
+0x0f0 VerifiedFiltersLink : _LIST_ENTRY
+0x100 FilterUnload : Ptr64 long
+0x108 InstanceSetup : Ptr64 long
+0x110 InstanceQueryTeardown : Ptr64 long
+0x118 InstanceTeardownStart : Ptr64 void
+0x120 InstanceTeardownComplete : Ptr64 void
+0x128 SupportedContextsListHead : Ptr64 _ALLOCATE_CONTEXT_HEADER
+0x130 SupportedContexts : [7] Ptr64 _ALLOCATE_CONTEXT_HEADER
+0x168 PreVolumeMount : Ptr64 _FLT_PREOP_CALLBACK_STATUS
+0x170 PostVolumeMount : Ptr64 _FLT_POSTOP_CALLBACK_STATUS
+0x178 GenerateFileName : Ptr64 long
+0x180 NormalizeNameComponent : Ptr64 long
+0x188 NormalizeNameComponentEx : Ptr64 long
+0x190 NormalizeContextCleanup : Ptr64 void
+0x198 KtmNotification : Ptr64 long
+0x1a0 SectionNotification : Ptr64 long
+0x1a8 Operations : Ptr64 _FLT_OPERATION_REGISTRATION
+0x1b0 OldDriverUnload : Ptr64 void
+0x1b8 ActiveOpens : _FLT_MUTEX_LIST_HEAD
+0x208 ConnectionList : _FLT_MUTEX_LIST_HEAD
+0x258 PortList : _FLT_MUTEX_LIST_HEAD
+0x2a8 PortLock : _EX_PUSH_LOCK

解析FLT_OPERATION_REGISTRATION结构体,可以看到这就是我们需要枚举的过滤器,只要拿到它输出即可:

lyshark: kd> dt fltmgr!_FLT_OPERATION_REGISTRATION
+0x000 MajorFunction : UChar
+0x004 Flags : Uint4B
+0x008 PreOperation : Ptr64 _FLT_PREOP_CALLBACK_STATUS
+0x010 PostOperation : Ptr64 _FLT_POSTOP_CALLBACK_STATUS
+0x018 Reserved1 : Ptr64 Void

枚举过滤器代码如下所示,需要配置连接器增加fltMgr.lib头文件。

  • 配置属性 > 连接器 > 输入> 附加依赖 -> fltMgr.lib
  • 配置属性 > C/C++ > 常规 > 设置 警告等级2级 (警告视为错误关闭)
#include <fltKernel.h>
#include <dontuse.h>
#include <suppress.h> // 设置默认回调
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;
} VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
} NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
DbgPrint("hello lyshark \n"); NTSTATUS status = STATUS_SUCCESS;
pDriverObject->DriverUnload = DriverUnload;
for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
pDriverObject->MajorFunction[i] = DriverDefaultHandle;
} 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)
{
return FALSE;
} // 获取 Minifilter 中所有过滤器Filter 的信息
status = FltEnumerateFilters(ppFilterList, ulFilterListSize, &ulFilterListSize);
if (!NT_SUCCESS(status))
{
return FALSE;
} DbgPrint("过滤器数量: %d \n", ulFilterListSize); // 获取 PFLT_FILTER 中 Operations 偏移
lOperationsOffset = 0x1A8; // 开始遍历 Minifilter
__try
{
for (i = 0; i < ulFilterListSize; i++)
{
// 获取 PFLT_FILTER 中 Operations 成员地址
pFltOperationRegistration = (PFLT_OPERATION_REGISTRATION)(*(PVOID *)((PUCHAR)ppFilterList[i] + lOperationsOffset)); __try
{
// 同一过滤器下的回调信息
while (IRP_MJ_OPERATION_END != pFltOperationRegistration->MajorFunction)
{
if (IRP_MJ_MAXIMUM_FUNCTION > pFltOperationRegistration->MajorFunction)
{
// 显示
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));
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
} // 释放内存
ExFreePool(ppFilterList);
ppFilterList = NULL; return status;
}

运行代码输出枚举效果如下:

6.6 Windows驱动开发:内核枚举Minifilter微过滤驱动的更多相关文章

  1. 驱动开发:内核枚举Minifilter微过滤驱动

    Minifilter 是一种文件过滤驱动,该驱动简称为微过滤驱动,相对于传统的sfilter文件过滤驱动来说,微过滤驱动编写时更简单,其不需要考虑底层RIP如何派发且无需要考虑兼容性问题,微过滤驱动使 ...

  2. [Windows驱动开发](三)基础知识——驱动例程

    一.NT式驱动的基本例程 1. 驱动入口函数——DriverEntry // 驱动程序的一般性定义 NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObje ...

  3. Minifilter微过滤框架:框架介绍以及驱动层和应用层的通讯

    minifilter是sfilter后微软推出的过滤驱动框架.相比于sfilter,他更容易使用,需要程序员做的编码更简洁. 系统为minifilter专门制作了一个过滤管理器,这个管理器本身其实是一 ...

  4. C++第四十篇 -- 研究一下Windows驱动开发(三)-- NT式驱动的基本结构

    对于NT式驱动来说,主要的函数是DriverEntry例程.卸载例程及各个IRP的派遣例程. 一.驱动加载过程与驱动入口函数(DriverEntry) 和编写普通应用程序一样,驱动程序有个入口函数,也 ...

  5. C++第三十八篇 -- 研究一下Windows驱动开发(二)--WDM式驱动的加载

    基于Windows驱动开发技术详解这本书 一.简单的INF文件剖析 INF文件是一个文本文件,由若干个节(Section)组成.每个节的名称用一个方括号指示,紧接着方括号后面的就是节内容.每一行就是一 ...

  6. Linux驱动开发学习笔记(1):LINUX驱动版本的hello world

    1.关于目录    /lib/modules/2.6.9-42.ELsmp/build/   这个是内核源码所在的目录    一般使用这样的命令进入这个目录:cd /lib/modules/$(una ...

  7. 嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)

    这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...

  8. linux驱动开发—基于Device tree机制的驱动编写

    前言Device Tree是一种用来描述硬件的数据结构,类似板级描述语言,起源于OpenFirmware(OF).在目前广泛使用的Linux kernel 2.6.x版本中,对于不同平台.不同硬件,往 ...

  9. linux驱动开发之九鼎板载蜂鸣器驱动测试【转】

    本文转载自:http://whylinux.blog.51cto.com/10900429/1932491 字符设备驱动用的fileopretion结构体. 1.板载蜂鸣器的驱动测试 我手里有一个BS ...

  10. Windows驱动开发-内核常用内存函数

    搞内存常用函数 C语言 内核 malloc ExAllocatePool memset RtlFillMemory memcpy RtlMoveMemory free ExFreePool

随机推荐

  1. 【已解决】:Original error: Could not extract PIDs from ps output. PIDS: [], Procs: [“ps: uiautomator”]

    报错截图 因为appium服务用的是1.4.x版本,使用的是 uiatumator1.0在android7.0得不到支持,所以获取PIDS得到空. 解决办法 找到Appium安装目录下node_mod ...

  2. HDU - 1560:DNA sequence ( 迭代加深搜索基础题 )

    Problem Description The twenty-first century is a biology-technology developing century. We know tha ...

  3. L2-020 功夫传人 (25分)

    分析: ⽤⼆维数 组v存储师⻔谱系关系,v[i]表示编号为i的师傅所拥有的徒弟,如果徒弟个数等于0, 也就是说这是个得道者,那么v[i][0]保存放⼤的倍数,⽽且⽤visit[i] = true标记当 ...

  4. 2.5D 组态案例合集 | 智慧园区、数据中心、SMT 生产线、汽车制造

    在阅读文章之前,大家可以思考下 2.5D 设计属于哪种界定? 2.5D 是通过二维的元素来呈现出三维的效果.其实在国外并没有 2.5D 这样的称呼,标准说法是 Isometric 风格,翻译过来就是等 ...

  5. 十三、docker的四种网络类型

    系列导航 一.docker入门(概念) 二.docker的安装和镜像管理 三.docker容器的常用命令 四.容器的网络访问 五.容器端口转发 六.docker数据卷 七.手动制作docker镜像 八 ...

  6. 【驱动】SPI驱动分析(一)-SPI协议简介

    1. 什么是SPI SPI全拼Serial Peripheral interface(串行外围设备接口),是由Motorola(摩托罗拉)在MC68HCXX系列处理器上定义的,主要应用于EEPROM( ...

  7. C#将汉字转换为拼音

    首先上效果图 方法调用 private void txt_Chinese_TextChanged(object sender, EventArgs e) { txt_PinYIn.Text = //调 ...

  8. 每天学五分钟 Liunx 0110 | 服务篇:守护进程 systemd

    有些进程会在系统上运行较长时间,如前面的 Hello World 程序运行时产生的进程.有些进程运行瞬间就结束了,如执行 ps 命令产生的进程,也有的进程会常驻在内存中,提供相应的服务,这样的进程称为 ...

  9. Nacos源码 (7) Nacos与Spring

    SpringCloud工程可以使用Nacos作为注册中心和配置中心,配置和使用非常简单,本文将简单介绍使用方式,并分析其实现方式. SpringCloud工程集成Nacos SpringCloud工程 ...

  10. 浏览器兼容 : IE10

    <script> /*@cc_on @*//*@ if (document.documentMode == 10) { // 只在 IE10 文档模式下运行,例如 IE10 浏览器或 IE ...