白影33 发表于 2020-12-23 14:27

[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

5omggx 发表于 2021-1-1 17:23

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

白影33 发表于 2021-1-2 17:35

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过滤不倒,好点的办法让返回失败,看看我发的第一个评论

lsz7575 发表于 2020-12-23 19:37

感谢楼主分享,支持一下!

hjthack 发表于 2020-12-24 08:36

感谢楼主分享。

红叶落尽 发表于 2020-12-25 08:07

感谢大牛的分享 虽然看不大懂 学习一下思路也是极好的

一切已过都还好 发表于 2020-12-25 19:15

感谢楼主分享,支持一下!

巴黎街头的阳光 发表于 2020-12-25 19:59


感谢楼主分享!!!!!

20000721yy 发表于 2020-12-26 14:56

感谢楼主分享,支持一下!

回的一手好帖 发表于 2020-12-28 17:19

支持 支持 感谢分享

白影33 发表于 2020-12-28 17:34

完善有个简单的办法,就不修改或者发新贴了,直接评论里说一下,直接让打开这个的irp返回失败就行了,映射是那个irp我还没找到。

fengbolee 发表于 2020-12-29 14:12

感谢精彩原创分享。
页: [1] 2 3
查看完整版本: [c]minifilter文件过滤驱动--实现查看文本内容替换为指定文本