MiniFilter file filtering lesson 1 file filtering framework and installation method

MiniFilter file filtering lesson 1 file filtering framework and installation method

I. MiniFilter file filtering framework

1.1 INTRODUCTION

MiniFilter is a new driver developed by Microsoft for us, called Filter Manager (Filter Manager or fltmgr) The main function of this driver is to notify us if there are file operations

The advantages and disadvantages of MiniFilter are as follows:

advantage:

1. Increase development speed

2. You don't need to worry about IRP processing. You can just hand it over to the Filter Manager

Insufficient:

MiniFilter development is simple, but it hides a lot of details Such as device object, etc If you use the previous way of development, it is like C language embedded assembly, which has poor compatibility and loses the meaning of MiniFilter

1.2 MiniFilter framework

The framework is as follows:

In the IO manager, our MiniFilter will register As shown in the figure above There are three a, B and C

The most important thing in MiniFilter is that altitude not only has height value, but also has grouping

For example, group A is in fsfilter activity monitor, and group B is in fsfilter anti virus, that is, anti-virus level The higher the height, the more it will be executed first Suppose you block file access, you can not send it to the next layer So B and C can't accept it So we need to apply to Microsoft for this height (but it seems that it can be used without application. As long as it does not affect it)

The altitude value is from 20000 to 429999 The height values are grouped Therefore, the height value can not be scribbled Generally, each group has a height value range

The inquiry address is as follows: Loading order group and height of the minifilter driver - Windows drivers | Microsoft Docs

II. MiniFilter programming framework

2.1 introduction

Corresponding to the program, MiniFilter is very simple Only three kernel API s are needed to use MiniFilter

The parameters required in the API are structures So we can figure out the parameters in the structure In fact, it is just to fill things in the structure

The kernel API is as follows:

NTSTATUS
  FltRegisterFilter(
    IN PDRIVER_OBJECT  Driver,                  
    IN CONST FLT_REGISTRATION  *Registration,   
    OUT PFLT_FILTER  *RetFilter
    ); 

NTSTATUS
  FltStartFiltering(
    IN PFLT_FILTER  Filter);

VOID
  FltUnregisterFilter(
    IN PFLT_FILTER  Filter
    );  


There are only three API s It is divided into registration, startup and uninstall, both of which are parameters This is the Filter handle This handle is passed out from the third parameter of FltRegisterFilter So the main learning is the first

This function has three arguments

  • Parameter 1 Driver object in DriverEntry of DDK driver

  • Parameter 2 a structure, which is the structure we want to know Let's talk about it

  • Parameter 3 outgoing handle Handle to the file manager After successful registration, the handle will be sent out to the startup and uninstall functions

2.2 FLT_REGISTRATION structure

There is a substructure in our registration function This structure is as follows:

typedef struct _FLT_REGISTRATION {
  USHORT  Size;                    @1 Points to its own size sizeof(FLT_REGISTRATION). 
  USHORT  Version;                 Version must be set to FLT_REGISTRATION_VERSION
  FLT_REGISTRATION_FLAGS  Flags;   sign   @1
  CONST FLT_CONTEXT_REGISTRATION  *ContextRegistration; context@2
  CONST FLT_OPERATION_REGISTRATION  *OperationRegistration;
  PFLT_FILTER_UNLOAD_CALLBACK  FilterUnloadCallback;
  PFLT_INSTANCE_SETUP_CALLBACK  InstanceSetupCallback;
  PFLT_INSTANCE_QUERY_TEARDOWN_CALLBACK  InstanceQueryTeardownCallback;
  PFLT_INSTANCE_TEARDOWN_CALLBACK  InstanceTeardownStartCallback;
  PFLT_INSTANCE_TEARDOWN_CALLBACK  InstanceTeardownCompleteCallback;
  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
} FLT_REGISTRATION, *PFLT_REGISTRATION;

The meaning is as follows:

member meaning explain Key ⚪ Understand the key points of √ × Little or no use
Size size Size of pointing to itself # sizeof(FLT_REGISTRATION)
Version edition Must be set to FLT_REGISTRATION_VERSION
Flags sign Two settings, NULL or fltfl_ REGISTRATION_ DO_ NOT_ SUPPORT_ SERVICE_ When STOP is set to STOP, MinniFilter will not uninstall when it stops the service, whether your uninstall function is set or not
ContextRegistration context If the function that registers the processing context is registered, the last item of the structure array must be set to FLT_CONTEXT_END
OperationRegistration Callback Suites The key point in the key point is to learn how to set this field Is an array of structures that can set callbacks of interest to us The last item is set to IRP_MJ_OPERATION_END
FilterUnloadCallback Unload function Uninstall MiniFilter callback If flags = xx_STOP then it will not be uninstalled whether you set it or not
InstanceSetupCallback Volume instance load callback When a volume is loaded, MiniFilter will generate an instance and bind it. For example, when a mobile hard disk is accessed, an instance will be generated Can be set to NULL
InstanceQueryTeardownCallback Control instance destruction function This instance will only come when you unbind it manually
InstanceTeardownStartCallback Instance destruction function When called, it means that the binding has been unbound and can be set to NULL
InstanceTeardownCompleteCallback Instance unbinding completion function When it is determined, call the unbound completion function, which can be set to NULL
GenerateFileNameCallback File name callback The generated file name can be set to callback or NULL
NormalizeNameComponentCallback Query WDK ⚪×
NormalizeContextCleanupCallback Query WDK ⚪×
TransactionNotificationCallback Query WDK ⚪×
NormalizeNameComponentExCallback Query WDK ⚪×

In fact, the essence is to learn the callback function set, which is an object array Let's take a look at its structure

typedef struct _FLT_OPERATION_REGISTRATION {
  UCHAR  MajorFunction;
  FLT_OPERATION_REGISTRATION_FLAGS  Flags;
  PFLT_PRE_OPERATION_CALLBACK  PreOperation;
  PFLT_POST_OPERATION_CALLBACK  PostOperation;
  PVOID  Reserved1;
} FLT_OPERATION_REGISTRATION, *PFLT_OPERATION_REGISTRATION;
  • Parameter 1 indicates the IRP operation you want to monitor

  • Parameter 2 is a flag

  • Parameter 3 is the monitoring callback you executed. pre means the previous callback For example, before file creation has been created, you are called.

  • Parameter 4 callback after monitoring Callback called after file creation

  • Parameter 5: leave the parameter NULL

IRP can monitor many WDK documents for this query

Here's the sign

The signs are as follows:

sign meaning
FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO Using this flag means that pre and post function operations are not performed for cached IO processing. It is applicable to fast IO because all fast IO has been cached
FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO Specifies that callback operation should not be performed for IO of paging operation All IO operations that are not based on IRP will be skipped Our function will not be called

It looks rather misty, doesn't it Let me talk about it In fact, when we write a file, we don't write it directly to disk

It is written to the cache first The cache is written to memory

The call chain is as follows:

APP->IO->FSD->Cache->MM->IO->FSD->DISk  First kind
APP->IO->FSD->DISk                      Second

The first is to write to the cache first, and then MM initiates IO request when 1024 bytes are met Then write the notification file system to disk

The second way is to write directly to the file system through IO and then to the disk

If you read and write frequently, it will affect efficiency Therefore, we can ignore the first request not initiated by IRP

So the meaning of these two signs is almost the same

2.3 pre callback and post callback

The prototype of the pre callback function is as follows:

typedef FLT_PREOP_CALLBACK_STATUS
  (*PFLT_PRE_OPERATION_CALLBACK) (
    __inout PFLT_CALLBACK_DATA Data,
    __in PCFLT_RELATED_OBJECTS FltObjects,
    __deref_out_opt PVOID *CompletionContext
    );

The post callback function is as follows:

typedef FLT_POSTOP_CALLBACK_STATUS
(FLTAPI *PFLT_POST_OPERATION_CALLBACK) (
    __inout PFLT_CALLBACK_DATA Data,
    __in PCFLT_RELATED_OBJECTS FltObjects,
    __in_opt PVOID CompletionContext,
    __in FLT_POST_OPERATION_FLAGS Flags
    );

2.3.1 pre return value and post return value

First, let's talk about the return value

The return value of pre is as follows

Return value meaning Is that the point
FLT_PREOP_SUCCESS_WITH_CALLBACK Complete the call of callback and send callbackdata down. Callbackdata can be used in post
FLT_PREOP_SUCCESS_NO_CALLBACK Complete the callback and send it down without parameters
FLT_PREOP_PENDING Hang
FLT_PREOP_DISALLOW_FASTIO Disable Fastio
FLT_PREOP_COMPLETE The callback is completed and will not be sent down
FLT_PREOP_SYNCHRONIZE synchronization

In fact, there are three common ones, FLT_PREOP_SUCCESS_WITH_CALLBACK and FLT_PREOP_COMPLETE

POST callback

Return value meaning Is it commonly used
FLT_POSTOP_FINISHED_PROCESSING When complete, the filter manager will continue to complete the processing of I/O operations.
FLT_POSTOP_MORE_PROCESSING_REQUIRED The minifilter driver has stopped the completion processing of I/O operations, but it will not return control of the operation to the filter manager.
FLT_POSTOP_DISALLOW_FSFILTER_IO The minifilter driver does not allow a fast QueryOpen operation and forces it down a slow path. Doing so causes the I/O Manager to service the request by opening / querying / closing the file. The minifilter driver should only return this state of QueryOpen.

2.3.2 PFLT_CALLBACK_DATA acquisition

This parameter is parameter 1, which is a very important parameter Its structure is as follows

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;

The thread is recorded Flags iopb and IoStatus

A thread can determine which process it belongs to

PFLT_CALLBACK_DATA Data;
PEPROCESS processObject = 
		Data->Thread ? IoThreadToProcess(Data->Thread) : PsGetCurrentProcess();

The Iopb field records the Buffer value we want to get from the IRP stack

Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess

PVOID	pQueryBuffer 	= 
		Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;
ULONG	uQueryBufferSize 	=  
		Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length

PMDL pReadMdl 		= Data->Iopb->Parameters.Read. MdlAddress;
PVOID pReadBuffer 		= Data->Iopb->Parameters.Read. ReadBuffer;
ULONG uReadLength 		= Data->Iopb->Parameters.Read.Length;

IoStatus records the length value of read and write operations

You can also determine what operation Data is There are also macros

FLT_IS_IRP_OPERATION
FLT_IS_FASTIO_OPERATION
FLT_IS_FS_FILTER_OPERATION
 example
if (FLT_IS_FASTIO_OPERATION(DATA))
{
    status = STATUS_FLT_DISALLOW_FAST_IO;
    Data->IoStatus.Status = status;
    Data->IoStatus.information = 0;
    return FLT_PREOP_DISALLOW_FASTIO;
}

2.3.3 object acquisition FltObjects

It is also a structure that records all the objects you can use

typedef struct _FLT_RELATED_OBJECTS {
  USHORT CONST  Size;
  USHORT CONST  TransactionContext;
  PFLT_FILTER CONST  Filter;
  PFLT_VOLUME CONST  Volume;
  PFLT_INSTANCE CONST  Instance;
  PFILE_OBJECT CONST  FileObject;
  PKTRANSACTION CONST  Transaction;
} FLT_RELATED_OBJECTS, *PFLT_RELATED_OBJECTS;
typedef CONST struct _FLT_RELATED_OBJECTS *PCFLT_RELATED_OBJECTS;

Common are as follows:

FltObjects->Volume,
FltObjects->Instance,
FltObjects->FileObject,
FltObjects->FileObject->DeviceObject

2.3.4 example learning

There is a MiniFilter framework under the Src directory of WDK7600 You can learn If you use VS or later, you need to select your own template for generation

Example Directory: x:\WinDDK00.16385.1\src\filesys\miniFilter

  • nullFilter

    A basic framework is useless for filtering You can see how it is written

  • passThrough

    A complete framework, so filtering has been set, but it is not used It's the best way to learn

  • scanner

An interception framework can take a look at an example

III. use of MiniFilter

MiniFilter needs to be installed in two inf installation modes and dynamic loading mode

3.1 the Inf installation mode is explained in the example of passThrough

Inf understand When using, you can copy an inf Just change your own things

Inf is as follows:

;;;
;;; PassThrough
;;;
;;;
;;; Copyright (c) 1999 - 2001, Microsoft Corporation
;;;

[Version]
Signature   = "$Windows NT$"     
Class       = "ActivityMonitor"  ;Indicates the grouping of drivers,Must specify.
ClassGuid   = {b86dff51-a31e-4bac-b3cf-e8cfe75c9fc2}  ;GUID Each group has a fixed GUID
Provider    = %Msft% ;Variable value from STRING You can see the name of the driver provider in this section 
DriverVer   = 06/16/2007,1.0.0.1 ;Version number
CatalogFile = passthrough.cat    ;inf Corresponding cat Files may not be required


[DestinationDirs]
DefaultDestDir          = 12    ;Tell us where to copy the driver. 13 means copy to%windir%
MiniFilter.DriverFiles  = 12            ;%windir%\system32\drivers

;;
;; Default install sections
;;

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

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

;;
;; Default uninstall sections
;;

[DefaultUninstall]
DelFiles   = MiniFilter.DriverFiles

[DefaultUninstall.Services]
DelService = %ServiceName%,0x200      ;Ensure service is stopped before deleting

;
; Services Section
;

[MiniFilter.Service]                 ;Some information about the service
DisplayName      = %ServiceName%
Description      = %ServiceDescription%
ServiceBinary    = %12%\%DriverName%.sys        ;%windir%\system32\drivers\
Dependencies     = "FltMgr"                     ;Service dependency
ServiceType      = 2                            ;SERVICE_FILE_SYSTEM_DRIVER
StartType        = 3                            ;SERVICE_DEMAND_START
ErrorControl     = 1                            ;SERVICE_ERROR_NORMAL
LoadOrderGroup   = "FSFilter Activity Monitor"  ;File filter grouping
AddReg           = MiniFilter.AddRegistry       ;File filtering registry needs to add height value and other information

;
; Registry Modifications
;

[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%

;
; Copy Files
;

[MiniFilter.DriverFiles]
%DriverName%.sys

[SourceDisksFiles]
passthrough.sys = 1,,

[SourceDisksNames]
1 = %DiskId1%,,,

;;
;; String Section
;;

[Strings]
Msft                    = "Microsoft Corporation"
ServiceDescription      = "PassThrough Mini-Filter Driver"
ServiceName             = "PassThrough"
DriverName              = "PassThrough"
DiskId1                 = "PassThrough Device Installation Disk"

;Instances specific information.
DefaultInstance         = "PassThrough Instance"
Instance1.Name          = "PassThrough Instance"
Instance1.Altitude      = "370030"
Instance1.Flags         = 0x0              ; Allow all attachments


In fact, the essence of INF file is the same as our normal DDK installation service It's just that he adds two more registry keys and instances to the registry

After INF installation, the driver will be copied to C:\windows\System32\driver first

Then register information under the registry

As follows:

Therefore, if we need to create two more keys when loading the driver dynamically, namely instances xxxinstance, and then add the height value

During dynamic loading, our dependency driver should be modified to FltMgr, and the packet should be written as FSFilter Activity Monitor

3.2 using drive

After inf is installed, it just registers a key to the registry Copy the driver to the system directory

We can start in two ways

net start PassThrough
fltmc load PassThrough

Either way is OK

Added by jcavard on Mon, 17 Jan 2022 03:20:20 +0200