[c]minifilter文件过滤驱动--实现查看文本内容替换为指定文本
本帖最后由 白影33 于 2020-12-28 17:35 编辑0x1前言
写这篇文章不仅仅只为介绍功能的实现,也是为了作为一篇笔记来备忘,因此我会写的比较详细。
文中的注释有的来自微软官方的解释翻译,有的来自Windows内核安全与驱动开发书中的解释,也有的来自我个人的理解。
代码是在Windows内核安全与驱动开发第13章中minifilter代码的基础上完成的(我实现的功能源码中没有)。
0x2功能介绍
MyMinifilter.sys:实现根据应用层软件输入,选择是否文本内容替换,过滤readbuffer内容,禁止notepad打开。
MyDriverR3:系统驱动没有交互的界面,通过MyDriverR3与驱动进行交互。
默认情况下:安装驱动后,读取true.txt的内容会被替换为false.txt的内容。(false.txt里全为0,ture.txt全为1)
当在MyDriverR3输入52pojie:读取true.txt,就是ture.txt。
再次启动MyDriverR3输入0:读取true.txt的内容会被替换为false.txt的内容。
0x3特殊说明
大家应该注意到了,要过滤文本内容,为什么要禁止打开notepad,原因是filemap方式(解决办法我发评论),
我在实践中,使用debugview查看打印替换或的缓冲区内容,显示替换成false.txt,然而打开notepad却还是true.txt里的内容,
我又在网上下了个EditPlus测试,用EditPlus打开查看为false.txt,替换成功,我又下了个notepad++测试,也是替换成功,,所以有了这么一个折中的办法,禁止打开notepad,这个很简单对create进行过滤,是打开notepad就让它失败,(评论里我发了一个好点的办法,具体看评论)
0x4难点攻克
这里说明我遇到的难点,以及解决办法。
难点:对目标文件打开后无IRP_MJ_READ的IRP。
解决方案:通过查阅书籍,发现为window文件缓冲机制导致的问题
window文件缓冲机制是:
window读文件会首先从文件缓冲中读取,如果文件缓冲中没有,
就会触发缺页异常从而发送IRP_MJ_READ从硬盘里读取,放入文件缓冲中。
如果文件缓冲中有,那就直接从内存中读取,不会发送IRP_MJ_READ。
对于这个问题书籍里用CcPurgeCacheSection然后和一些函数清除文件缓冲,
不知道是不是因为我的是minifilter而他的是普通的文件过滤驱动的区别,我调用该函数即使返回显示成功
依然没有IRP_MJ_READ,书上的办法对于我来说,行不通。
在一次测试中发现:如果对文件内容进行修改,点击保存就会有IRP_MJ_READ,
据此猜想,window在每次对原文件的修改保存后,会发送IRP_MJ_READ从硬盘上重新读取内容
同步到文件缓冲里,这样我就有了一个大胆的想法。
在DriverEntry里用ZwWriteFile对文件写入空格(注意重入问题),这样就会触发read的irp,我就把false.txt内容替换到文件缓冲,
然后在NPMiniMessage与应用层交互的函数里,也对文件进行写入触发read的irp,根据应用层输入的字符串,来判断替换为那个文件的内容
0x4蓝屏日志
这里是记录自己在写驱动过程中遇到的问题,以及解决办法。
问题1:驱动安装蓝屏,windbg调试后发现FltRegisterFilter注册函数失败
解决办法:minifilter需要修改注册表,我用Windows内核安全与驱动开发的minifilter的inf文件右键安装后,再用drivermonitor安装FltRegisterFilter就返回成功
问题2:minifilter读后操作回调例程 里的PAGED_CODE();断下,PAGED_CODE();检查irql是否低于或等于APC_LEVEL,不成立就中断
解决办法:通过查阅微软官方文档发现minifilter后操作回调例程可以运行在高于APC_LEVEL的irql,不需要用PAGED_CODE来检查。
问题3:FltGetFileNameInformation会不时蓝屏
解决办法:通过对比官方代码,发现一些失败的情况没有直接返回,把而是失败的irp的数据给FltGetFileNameInformation会蓝屏,加上代码
if (!NT_SUCCESS( Data->IoStatus.Status ) ||(STATUS_REPARSE == Data->IoStatus.Status))
{
return FLT_POSTOP_FINISHED_PROCESSING;
}
检查,如果失败就直接返回,不调用FltGetFileNameInformation。
问题4:ZwReadFile/ZwWriteFile蓝屏
解决办法: 参数 8_In_opt_ PLARGE_INTEGER ByteOffset,不能直接给数,
例如:错误ZwReadFile(myhand2, NULL, NULL, NULL, &BLOCK2, str2, 500, 50, NULL);
正确 LARGE_INTEGER size2.QuadPart = 0;
status = ZwReadFile(myhand2, NULL, NULL, NULL, &BLOCK2, str2, 500, &size2, NULL);
(血的教训,蓝了我一下午)
问题5:RtlCopyMemory蓝屏
解决办法:我是在post回调函数中使用这个函数,post函数IRQL高一些,
微软官方的解释的意思是如果在高IRQL使用,原地址和目标地址的内存最好都是非分页内存。
问题6:DriverEntry的ZwReadFile蓝屏,
解决办法:调用ZwReadFile读取目标文件内容用于替换,而我又过滤了read的,read里面又需要用到这个ZwReadFile读取的内容
此时为空,导致蓝屏,解决办法用一个变量,读完后给它赋值,而后在read过滤时检查,如果变量没有赋值,就不过滤。
0x6驱动源码及注释
#include "minifilter.h"
NTSTATUS
DriverEntry(
__in PDRIVER_OBJECT DriverObject,//PDRIVER_OBJECT 驱动数据结构(驱动对象)的指针
__in PUNICODE_STRING RegistryPath//PUNICODE_STRING 内核字符串数组,驱动以服务的形式加载,这个字符串为驱动在注册表的路径
)
{
NTSTATUS status; //返回值状态
PSECURITY_DESCRIPTOR sd; //安全描述符。
OBJECT_ATTRIBUTES oa; //对象属性
UNICODE_STRING uniString; //用于通信端口名称
UNREFERENCED_PARAMETER(RegistryPath);//避免编译器关于未引用参数的警告
// 注册FilterRegistration,告诉系统我设置的回调例程
//第1个参数是本驱动的驱动对象,是在入口函数DriverEntry 中作为参数传入的。
//第2个参数就是一个注册信息的结构,这个结构内含描述这个过滤器的所有信息
//第3个参数 是一个返回参数,返回注册成功的微过滤器句柄,在下面调用函数FltStartFiltering时会用到
//DbgPrint("statuswww=\n");
status = FltRegisterFilter(DriverObject,
&FilterRegistration,
&gFilterHandle);
ASSERT(NT_SUCCESS(status));//检查结果是否成功,失败后触发异常被调试器接管
if (NT_SUCCESS(status)) {//检查结果是否成功,
//
//开始函数,只有一个参数为之前获取的句柄
//
status = FltStartFiltering(gFilterHandle);
if (!NT_SUCCESS(status)) {
//如果失败就取消注册,只有一个参数为之前获取的句柄
FltUnregisterFilter(gFilterHandle);
}
}
//FltBuildDefaultSecurityDescriptor构建一个默认的安全描述符,用于FltCreateCommunicationPort。
//参数1指向调用方分配的变量的指针,该变量接收到指向新创建的不透明指针
//参数2指定调用者需要对端口对象的访问类型的标志的位掩码。系统定义的DesiredAccess标志集确定了minifilter驱动程序通信端口对象的以下特定访问权限。
status = FltBuildDefaultSecurityDescriptor(&sd, FLT_PORT_ALL_ACCESS);
if (!NT_SUCCESS(status)) {//检查结果是否成功,未成功就跳向最终处理部分
goto final;
}
//函数初始化Unicode字符的计数字符串
RtlInitUnicodeString(&uniString, MINISPY_PORT_NAME);
//宏初始化不透明的OBJECT_ATTRIBUTES结构,该结构将对象句柄的属性指定给打开句柄的例程。
//参数1为要被初始化的结构体,参数2一个指向Unicode字符串的指针,该字符串包含要为其打开句柄的对象的名称。
//这必须是一个完全限定的对象名,或者由RootDirectory参数指定的对象目录的相对路径名。
//参数3标志位,此处指定为只在内核模式访问,与对大小写不区分
//参数4在ObjectName参数中指定的路径名的根对象目录句柄。如果ObjectName是完全限定的对象名称,
//则RootDirectory为空。使用ZwCreateDirectoryObject获得对象目录的句柄。
//参数5指定创建对象时应用于该对象的安全描述符。此参数是可选的。驱动程序可以指定NULL来接受对象的默认安全性。
InitializeObjectAttributes(&oa,
&uniString,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
NULL,
sd);
//创建一个通信服务器端口,minifilter驱动程序可以在该端口上接收来自用户模式应用程序的连接请求。
// 参数1调用者的不透明过滤器指针
//参数2指向调用方分配的变量的指针,该变量接收通信服务器端口的不透明端口句柄。minifilter驱动程序使用这个句柄来监听来自用户模式应用程序的连接请求。
//参数3指向OBJECT_ATTRIBUTES结构的指针,该结构指定通信服务器端口的属性。
//此结构必须由之前的InitializeObjectAttributes调用初始化。此参数是必需的,不能为空。通信端口对象的此结构的成员包括以下内容。
//参数4指向由minifilter驱动程序定义的上下文信息的指针。这个信息可以用来区分由相同的minifilter驱动程序创建的多个通信服务器端口。
//过滤器管理器将这个上下文指针作为参数传递给ConnectNotifyCallback例程。该参数是可选的,可以为NULL。
//参数5 NPMiniConneet是用户态与内核态建立连接时内核会调用到的函数。
//参数6 NPMiniDisconnect 是用户态与内核态连接结束时内核会调用到的函数。。
//参数7 NPMiniMessage是用户态与内核态传送数据时内核会调用到的函数
//参数8此服务器端口所允许的最大并发客户端连接数。此参数是必需的,且必须大于零。
status = FltCreateCommunicationPort(gFilterHandle,
&gServerPort,
&oa,
NULL,
NPMiniConnect,
NPMiniDisconnect,
NPMiniMessage,
1);
//释放分配的安全描述符
FltFreeSecurityDescriptor(sd);
if (!NT_SUCCESS(status)) {
goto final;
}
// 返回值
// 首先初始化含有文件路径的OBJECT_ATTRIBU
UNICODE_STRING mytext1;//文件名字符串
OBJECT_ATTRIBUTES ATTRIBUTES1;
IO_STATUS_BLOCK BLOCK1;//可拥有的控制权
LARGE_INTEGER size1;//写的偏移大小
str1 = ExAllocatePool(NonPagedPool, 500);//分配500的非分页内存
RtlZeroMemory(str1, 500);//清0内存
RtlInitUnicodeString(&mytext1, L"\\??\\C:\\true.txt");//初始化文件名
memset(&ATTRIBUTES1, 0, sizeof(OBJECT_ATTRIBUTES)); //对象属性清空
size1.QuadPart = 0;
InitializeObjectAttributes(&ATTRIBUTES1, &mytext1, OBJ_CASE_INSENSITIVE, NULL, NULL);//对象属性关键是文件名字 不区分大小写 ,参数意义同上
//打开目标文件获取句柄
//参数1:一个指向句柄变量的指针,该句柄用于接收文件的句柄。
//参数2:指定ACCESS_MASK值,该值确定请求对对象的访问。除了为所有类型的对象定义的访问权限之外,调用者还可以指定以下特定于文件的访问权限。
//参数3:OBJECT_ATTRIBUTES结构的指针,该结构指定对象名和其他属性。使用InitializeObjectAttributes初始化该结构。
//参数4:用于接收最终完成状态和请求操作的其他信息
//参数5:它包含创建或覆盖的文件的初始分配大小,可以为Null
//参数6:表示创建或覆盖文件时要设置的文件属性。调用者通常指定FILE_ATTRIBUTE_NORMAL,它设置默认属性
//参数7:共享访问的类型,
//参数8:指定在文件存在或不存在时执行的操作
//参数9:指定驱动程序创建或打开文件时应用的选项
//参数10:对于设备和中间驱动程序,此参数必须为空指针
//参数11:对于设备和中间驱动程序,此参数必须为零。
status = ZwCreateFile(&myhandl, GENERIC_ALL, &ATTRIBUTES1, &BLOCK1, NULL, FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ, FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE, NULL, 0);
//通过句柄读取目标文件放入str1
if (!NT_SUCCESS(status))
{
FirsT = 0;
goto final;
}
else
{
status = ZwReadFile(myhandl, NULL, NULL, NULL, &BLOCK1, str1, 500, &size1, NULL);
FirsT = 1;//防止重入
DbgPrint("status=%X\n", status);
}
//以下内容基本同上只是文件的对象不一样
UNICODE_STRING mytext2;
OBJECT_ATTRIBUTES ATTRIBUTES2;
IO_STATUS_BLOCK BLOCK2;//可拥有的控制权
LARGE_INTEGER size2;
str2 = ExAllocatePool(NonPagedPool, 500);
RtlZeroMemory(str2, 500);
RtlInitUnicodeString(&mytext2, L"\\??\\C:\\false.txt");//初始化文件名
memset(&ATTRIBUTES2, 0, sizeof(OBJECT_ATTRIBUTES)); //对象属性清空
size2.QuadPart = 0;
InitializeObjectAttributes(&ATTRIBUTES2, &mytext2, OBJ_CASE_INSENSITIVE, NULL, NULL);//对象属性关键是文件名字 不区分大小写
status = ZwCreateFile(&myhand2, GENERIC_ALL, &ATTRIBUTES2, &BLOCK2, NULL, FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ, FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE, NULL, 0);
if (!NT_SUCCESS(status))
{
FirsT = 0;
goto final;
}
else
{
status = ZwReadFile(myhand2, NULL, NULL, NULL, &BLOCK2, str2, 500, &size2, NULL);
DbgPrint("status2=%X\n", status);
}
//对目标文件进行写入,从而触发read
PVOID str3 = ExAllocatePool(PagedPool, 10);
RtlZeroMemory(str3, 6);
RtlCopyMemory(str3, "...", strlen("..."));
size1.HighPart = 0;
size1.QuadPart = 500;
status = ZwWriteFile(myhandl, NULL, NULL, NULL, &BLOCK1, str3, 6, &size1, NULL);
//关闭句柄
ZwClose(myhandl);
ZwClose(myhand2);
final ://失败处理处
if (!NT_SUCCESS(status)) {
if (NULL != gServerPort) {
//关闭过滤器驱动程序的通信服务器端口
FltCloseCommunicationPort(gServerPort);
}
if (NULL != gFilterHandle) {
//取消注册
FltUnregisterFilter(gFilterHandle);
}
}
return status;
}
FLT_PREOP_CALLBACK_STATUS
MyPostRead(
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_In_opt_ PVOID CompletionContext,
_In_ FLT_POST_OPERATION_FLAGS Flags
)
{
UNREFERENCED_PARAMETER(Flags);
UNREFERENCED_PARAMETER(CompletionContext);
char FileName = "X:";//存放解析后的文件名字
NTSTATUS status;//返回值状态
PFLT_FILE_NAME_INFORMATION nameInfo; //名称信息
//
// 对失败的irp进行过滤,如果失败了,就不用继续
if (!NT_SUCCESS(Data->IoStatus.Status) ||
(STATUS_REPARSE == Data->IoStatus.Status)) {
return FLT_POSTOP_FINISHED_PROCESSING;
}
//FltGetFileNameInformation例程返回文件或目录的名称信息。
status = FltGetFileNameInformation(Data,//PFLT_CALLBACK_DATA结构的指针,它是I/O操作的回调数据结构。此参数是必需的,不能为空。
FLT_FILE_NAME_NORMALIZED |//使nameInfo参数接收包含文件规范化名称的结构的地址。
FLT_FILE_NAME_QUERY_DEFAULT,//如果查询文件系统以获取文件名目前还不安全,则FltGetFileNameInformation将不执行任何操作。
//否则,FltGetFileNameInformation查询过滤器管理器的名称缓存以获取文件名信息。
//如果在缓存中没有找到该名称,则FltGetFileNameInformation查询文件系统并缓存结果。
&nameInfo);//包含文件名信息。
if (NT_SUCCESS(status))
{
//解析FLT_FILE_NAME_INFORMATION结构的内容。
status = FltParseFileNameInformation(nameInfo);
//参数1大小写转换,后放入参数2
if (NPUnicodeStringToChar(&nameInfo->Name, FileName))
{
//DbgPrint("FileName is %s\n", FileName);
if (strstr(FileName, "TRUE.TXT") > 0)
{
PUCHAR buf1;
if (Data->Iopb->Parameters.Read.MdlAddress != 0)
{
//如果为mdl方式读取文件,就获取地址
buf1 = MmGetSystemAddressForMdl(Data->Iopb->Parameters.Read.MdlAddress);
}
else
{
//如果为ReadBuffer就直接给指针
buf1 = Data->Iopb->Parameters.Read.ReadBuffer;
}
//判断应用层发来的指令是否为显示true.txt
if (command == 2)
{
if (FirsT == 1)
{
//复制内存,填写长度
RtlCopyMemory(buf1, str1, 500);
Data->IoStatus.Information = Data->Iopb->Parameters.Read.Length;
}
}
else
{
//DbgBreakPoint();
if (FirsT == 1)
{
//复制内存,填写长度
RtlCopyMemory(buf1, str2, 500);
Data->IoStatus.Information = Data->Iopb->Parameters.Read.Length;
}
}
DbgPrint("ReadBuffed=%s", buf1);
//释放文件名信息结构体的内存
FltReleaseFileNameInformation(nameInfo);
return FLT_POSTOP_FINISHED_PROCESSING;
}
}
FltReleaseFileNameInformation(nameInfo);
}
return FLT_POSTOP_FINISHED_PROCESSING;
}
NTSTATUS
NPMiniMessage(
__in PVOID ConnectionCookie,
__in_bcount_opt(InputBufferSize) PVOID InputBuffer,
__in ULONG InputBufferSize,
__out_bcount_part_opt(OutputBufferSize, *ReturnOutputBufferLength) PVOID OutputBuffer,
__in ULONG OutputBufferSize,
__out PULONG ReturnOutputBufferLength
)
{
//写入文件需要的各种参数,意义同dirverEntry
NTSTATUS status;
UNICODE_STRING mytext1;
OBJECT_ATTRIBUTES ATTRIBUTES1;
IO_STATUS_BLOCK BLOCK1;//可拥有的控制权
LARGE_INTEGER size1;
PVOID str4 = ExAllocatePool(PagedPool, 40);
RtlZeroMemory(str4, 40);
RtlInitUnicodeString(&mytext1, L"\\??\\C:\\true.txt");//初始化文件名
memset(&ATTRIBUTES1, 0, sizeof(OBJECT_ATTRIBUTES)); //对象属性清空
size1.QuadPart = 0;
PAGED_CODE();
//分配内存,存储字符串,用于和应用层字符串比较
PVOID test;
test = ExAllocatePool(PagedPool, 10);
RtlCopyMemory(test, "0", strlen("0"));
PVOID test2;
test2 = ExAllocatePool(PagedPool, 50);
RtlCopyMemory(test2, "52pojie", strlen("52pojie"));
UNREFERENCED_PARAMETER(ConnectionCookie);
UNREFERENCED_PARAMETER(OutputBufferSize);
UNREFERENCED_PARAMETER(OutputBuffer);
//通过应用层输入的字符串,来显示相应的文本
if (strcmp(InputBuffer, test) == 0)
{
command = 1;
}
else if (strcmp(InputBuffer, test2) == 0)
{
command = 2;
}
else
{
status = STATUS_INVALID_PARAMETER;
}
//向文件写入,来触发read,由于需要内容不同,所以通过改变ONOROFF,实现两种写入依次执行
if (ONOROFF == 0)
{
//向文件写入空格
ONOROFF = ONOROFF + 1;
InitializeObjectAttributes(&ATTRIBUTES1, &mytext1, OBJ_CASE_INSENSITIVE, NULL, NULL);//对象属性关键是文件名字 不区分大小写
status = ZwCreateFile(&myhandl, GENERIC_ALL, &ATTRIBUTES1, &BLOCK1, NULL, FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ, FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE, NULL, 0);
RtlCopyMemory(str4, " ", strlen(" "));
size1.HighPart = 0;
size1.QuadPart = 500;
status = ZwWriteFile(myhandl, NULL, NULL, NULL, &BLOCK1, str4, 8, &size1, NULL);
ZwClose(myhandl);
}
else
{
//向文件写入"****",
ONOROFF = ONOROFF - 1;
InitializeObjectAttributes(&ATTRIBUTES1, &mytext1, OBJ_CASE_INSENSITIVE, NULL, NULL);//对象属性关键是文件名字 不区分大小写
status = ZwCreateFile(&myhandl, GENERIC_ALL, &ATTRIBUTES1, &BLOCK1, NULL, FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ, FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE, NULL, 0);
RtlCopyMemory(str4, "****", strlen("****"));
size1.HighPart = 0;
size1.QuadPart = 500;
status = ZwWriteFile(myhandl, NULL, NULL, NULL, &BLOCK1, str4, 8, &size1, NULL);
ZwClose(myhandl);
}
//释放内存
ExFreePool(str4);
ExFreePool(test);
ExFreePool(test2);
return STATUS_SUCCESS;
}
BOOLEAN NPUnicodeStringToChar(PUNICODE_STRING UniName, char Name[])
{
ANSI_STRING AnsiName;
NTSTATUS ntstatus;
char* nameptr;
__try {
ntstatus = RtlUnicodeStringToAnsiString(&AnsiName, UniName, TRUE);
if (AnsiName.Length < 260) {
nameptr = (PCHAR)AnsiName.Buffer;
//转换成大写和复制到缓冲区
strcpy(Name, _strupr(nameptr));
//DbgPrint("NPUnicodeStringToChar : %s\n", Name);
}
RtlFreeAnsiString(&AnsiName);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("NPUnicodeStringToChar EXCEPTION_EXECUTE_HANDLER\n");
return FALSE;
}
return TRUE;
}
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();
return STATUS_SUCCESS;
}
NTSTATUS
NPInstanceQueryTeardown(
__in PCFLT_RELATED_OBJECTS FltObjects,
__in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
)
{
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(Flags);
PAGED_CODE();
return STATUS_SUCCESS;
}
VOID NPInstanceTeardownStart(
__in PCFLT_RELATED_OBJECTS FltObjects,
__in FLT_INSTANCE_TEARDOWN_FLAGS Flags
)
{
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(Flags);
PAGED_CODE();
}
VOID NPInstanceTeardownComplete(
__in PCFLT_RELATED_OBJECTS FltObjects,
__in FLT_INSTANCE_TEARDOWN_FLAGS Flags
)
{
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(Flags);
PAGED_CODE();
}
NTSTATUS
NPUnload(
__in FLT_FILTER_UNLOAD_FLAGS Flags
)
{
UNREFERENCED_PARAMETER(Flags);
PAGED_CODE();
ExFreePool(str1);
ExFreePool(str2);
FltCloseCommunicationPort(gServerPort);
FltUnregisterFilter(gFilterHandle);
return STATUS_SUCCESS;
}
FLT_PREOP_CALLBACK_STATUS
NPPreCreate(
__inout PFLT_CALLBACK_DATA Data,
__in PCFLT_RELATED_OBJECTS FltObjects,
__deref_out_opt PVOID *CompletionContext
)
{
char FileName = "X:";
NTSTATUS status;
PFLT_FILE_NAME_INFORMATION nameInfo;
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(CompletionContext);
PAGED_CODE();
status = FltGetFileNameInformation(Data,
FLT_FILE_NAME_NORMALIZED |
FLT_FILE_NAME_QUERY_DEFAULT,
&nameInfo);
if (NT_SUCCESS(status)) {
if (1) {
FltParseFileNameInformation(nameInfo);
if (NPUnicodeStringToChar(&nameInfo->Name, FileName)) {
if (strstr(FileName, "NOTEPAD.EXE") > 0) {
FltReleaseFileNameInformation(nameInfo);
return FLT_PREOP_COMPLETE;
}
}
}
FltReleaseFileNameInformation(nameInfo);
}
return FLT_PREOP_SUCCESS_WITH_CALLBACK;
}
NTSTATUS
NPMiniConnect(
__in PFLT_PORT ClientPort,
__in PVOID ServerPortCookie,
__in_bcount(SizeOfContext) PVOID ConnectionContext,
__in ULONG SizeOfContext,
__deref_out_opt PVOID *ConnectionCookie
)
{
DbgPrint(" NPMiniConnect");
PAGED_CODE();
UNREFERENCED_PARAMETER(ServerPortCookie);
UNREFERENCED_PARAMETER(ConnectionContext);
UNREFERENCED_PARAMETER(SizeOfContext);
UNREFERENCED_PARAMETER(ConnectionCookie);
ASSERT(gClientPort == NULL);
gClientPort = ClientPort;
return STATUS_SUCCESS;
}
VOID
NPMiniDisconnect(
__in_opt PVOID ConnectionCookie
)
{
PAGED_CODE();
UNREFERENCED_PARAMETER(ConnectionCookie);
DbgPrint(" NPMiniDisconnect");
//Close our handle
FltCloseClientPort(gFilterHandle, &gClientPort);
}
0x7应用层源码及注释
#include "windows.h"
#include <stdio.h>
#include <FltUser.h>
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "kernel32.lib")
#pragma comment(lib, "fltLib.lib")
extern HANDLE g_hPort;
#define NPMINI_NAME L"MYminifilter"
#define NPMINI_PORT_NAME L"\\MYMiniPort"
HANDLE g_hPort = INVALID_HANDLE_VALUE;
#ifdef _MANAGED
#pragma managed(push, off)
#endif
#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;
hResult = FilterSendMessage(
g_hPort,
InputBuffer,
sizeof(InputBuffer),
NULL,
NULL,
&bytesReturned);
if (hResult != S_OK) {
return hResult;
}
return 0;
}
void main()
{
int errorCode=InitialCommunicationPort();
if (errorCode!=0)
{
printf("errorCode is %x\n", errorCode);
}
printf("enter your code:");
char string = { 0 };
scanf("%s", string);
PVOID s1 = 0;
s1 = &string;
NPSendMessage(s1);
system("pause");
}
0x8文件及使用
使用我发的文件里的inf安装驱动,然后用drivermonitor启动,过滤的文件位置默认为c盘,就是c:\\,
想放在其他位置修改源码里的路径就行,true.txt和false.txt复制到这个路径就行了,当然你也可以自己创建这两个文件,
过滤目标文件也可以通过修改源码里的名字进行修改,由于版规不能发成品,所以你需要自己编译,
编译环境:vs2013+wdk8.1,测试成功系统:win7x64
所有的文件链接:https://pan.baidu.com/s/1eyOwGI7XoCok1KN00_xPEg
提取码:ras6
解压密码:52pojie In another thread within the last few months, it was pointed out that
NotePad uses memory mapping to access its files, so IRP_MJ_READ/WRITE will
never be seen. It is always safe to assume that any file, at any time,
might be memory-mapped.
joe
请楼主看看能否解决目前遇到的问题:https://community.osr.com/discussion/243780/minifilter-encrypt-vs-notepad 5omggx 发表于 2021-1-1 17:23
In another thread within the last few months, it was pointed out that
NotePad uses memory mapping t ...
能不能你自己试一下,宁外notepad是用filemaping的方式,好像是read过滤不倒,好点的办法让返回失败,看看我发的第一个评论 感谢楼主分享,支持一下! 感谢楼主分享。 感谢大牛的分享 虽然看不大懂 学习一下思路也是极好的 感谢楼主分享,支持一下!
感谢楼主分享!!!!! 感谢楼主分享,支持一下! 支持 支持 感谢分享 完善有个简单的办法,就不修改或者发新贴了,直接评论里说一下,直接让打开这个的irp返回失败就行了,映射是那个irp我还没找到。
感谢精彩原创分享。