Welcome to Neehack Blogs

How to disable write event using Filesystem Mini-Filter Driver ?


A Filesystem Mini-Filter is a driver that enables you to modify Kernel event before it happens such as Create File, Write File, Open File, Delete File. This type of drivers are mostly used by Anti-Virus and Encryption tools.

Code “filter.c”:

/*
Module Name:
    Neehack.c

Summary:
	This is a simple Filesystem Mini-Filter driver that disables user to write on a file named "BLOCK.TXT"

Driver Type:
	Filesystem Mini-Filter Driver

*/

#include <fltKernel.h>
#include <dontuse.h>
#include <suppress.h>


PFLT_FILTER FilterHandle = NULL;
NTSTATUS MiniUnload(FLT_FILTER_UNLOAD_FLAGS Flags);
FLT_PREOP_CALLBACK_STATUS MiniPreCreate(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID* CompletionContext);
FLT_PREOP_CALLBACK_STATUS MiniPreWrite(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID* CompletionContext);
FLT_PREOP_CALLBACK_STATUS FLTAPI PreOperationCreate(
	_Inout_ PFLT_CALLBACK_DATA Data,
	_In_ PCFLT_RELATED_OBJECTS FltObjects,
	_Flt_CompletionContext_Outptr_ PVOID* CompletionContext
);

const FLT_OPERATION_REGISTRATION Callbacks[] = {
	{IRP_MJ_CREATE,0,PreOperationCreate,NULL},
	{IRP_MJ_WRITE,0,MiniPreWrite,NULL},
	{IRP_MJ_OPERATION_END}
};
const FLT_REGISTRATION FilterRegistration = {
	sizeof(FLT_REGISTRATION),
	FLT_REGISTRATION_VERSION,
	0,
	NULL,
	Callbacks,
	MiniUnload,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL
};
NTSTATUS MiniUnload(FLT_FILTER_UNLOAD_FLAGS Flags) {
	KdPrint(("Unloading Driver \r\n"));
	FltUnregisterFilter(FilterHandle);
	return STATUS_SUCCESS;
}

FLT_PREOP_CALLBACK_STATUS FLTAPI PreOperationCreate(
	_Inout_ PFLT_CALLBACK_DATA Data,
	_In_ PCFLT_RELATED_OBJECTS FltObjects,
	_Flt_CompletionContext_Outptr_ PVOID* CompletionContext
)
{
	DbgPrint("%wZ\n", &Data->Iopb->TargetFileObject->FileName);

	return FLT_PREOP_SUCCESS_NO_CALLBACK;
}

FLT_PREOP_CALLBACK_STATUS MiniPreWrite(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID* CompletionContext) {
	KdPrint(("Capturing Pre Write Events\n"));
	
	PFLT_FILE_NAME_INFORMATION FileNameInfo;
	NTSTATUS status;
	WCHAR Name[500] = { 0 };
	status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &FileNameInfo);
	if (NT_SUCCESS(status)) {
		status = FltParseFileNameInformation(FileNameInfo);
		if (NT_SUCCESS(status)) {

			if (FileNameInfo->Name.MaximumLength < 500) {
				RtlCopyMemory(Name, FileNameInfo->Name.Buffer, FileNameInfo->Name.MaximumLength);
				_wcsupr(Name);
				if (wcsstr(Name, L"BLOCK.TXT") != NULL) {
					KdPrint(("Write File: %ws Blocked \r\n", Name));
					Data->IoStatus.Status = STATUS_INVALID_PARAMETER;
					Data->IoStatus.Information = 0;
					FltReleaseFileNameInformation(FileNameInfo);
					return FLT_PREOP_COMPLETE;
				}
			}
		}
		FltReleaseFileNameInformation(FileNameInfo);
	}
	return FLT_PREOP_SUCCESS_NO_CALLBACK;
}


NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
	UNREFERENCED_PARAMETER(RegistryPath);

	NTSTATUS status;
	status = STATUS_SUCCESS;
	
	status = FltRegisterFilter(DriverObject, &FilterRegistration, &FilterHandle);
	if (!NT_SUCCESS(status)) {
		DbgPrint("Failed to register filter! 0x%08x\n", status);
		return status;
	}
	else {
		DbgPrint("Filter registered!\n");
	}

	status = FltStartFiltering(FilterHandle);
	if (!NT_SUCCESS(status)) {
		FltUnregisterFilter(FilterHandle);

		DbgPrint("Failed to start filter! 0x%08x\n", status);
		return STATUS_SUCCESS;
	}
	else {
		DbgPrint("Filter started!\n");
	}

	return status;
}

filter.inf”

;-------------------------------------------------------------------------
; Neehack.INF -- NDIS LightWeight Filter Driver
;
; TODO: Search for comments marked "TODO:", and follow their instructions to
; customize this INF for your driver.  Then delete the "TODO:" comments.
;-------------------------------------------------------------------------

[version]
; Do not change these values "NetService"
Signature       = "$Windows NT$"
Class           = NetService
ClassGUID       = {4D36E974-E325-11CE-BFC1-08002BE10318}
; TODO: Customize this string for your company name
Provider        = "Neehack"
DriverVer       = 06/06/2022,1.0.0.1
CatalogFile     = Neehack.cat


;-------------------------------------------------------------------------
; Installation Section
;-------------------------------------------------------------------------
[Install]
AddReg=Inst_Ndi
; All LWFs must include the 0x40000 bit (NCF_LW_FILTER). Unlike miniports, you
; don't usually need to customize this value.
Characteristics=0x40000

; This must be a random, unique value.
; FILTER_UNIQUE_NAME in filter.h must match this GUID identically.
; Both should have {curly braces}.
NetCfgInstanceId="{33e89230-1de5-44cf-959b-bba7ed0e72d1}"

Copyfiles = Neehack.copyfiles.sys

[SourceDisksNames]
1=%Neehack_Desc%,"",,

[SourceDisksFiles]
; TODO: Include any related files that should be installed with your driver.
Neehack.sys=1

[DestinationDirs]
DefaultDestDir=12
Neehack.copyfiles.sys=12
Neehack.DriverFiles = 12

[Neehack.copyfiles.sys]
Neehack.sys,,,2

[DefaultInstall.ntamd64]
OptionDesc = %Neehack_Desc%
CopyFiles = Neehack.DriverFiles

[Neehack.DriverFiles]
Neehack.sys

[DefaultInstall.Services]
AddService = %Msft%,,Neehack.Service

[Neehack.Service]
DisplayName    = %Msft%
Description    = %Neehack_Desc%
ServiceBinary  = %12%\Neehack.sys
ServiceType    = 2 ;    SERVICE_FILE_SYSTEM_DRIVER
StartType      = 1 ;    SERVICE_SYSTEM_START
ErrorControl   = 1 ;    SERVICE_ERROR_NORMAL
LoadOrderGroup = "FSFilter Activity Monitor" ; File System
AddReg         = MiniFilter.AddRegistry

[MiniFilter.AddRegistry]
;HKR,,"DebugFlags",0x00010001,0x0
;HKR,,"SupportedFeatures",0x00010001,0x3
;HKR,"Instances","DefaultInstance",0x00000000,%DefaultInstance%
;HKR,"Instances\"%Instance1.Name%,"Altitude",0x00000000,%Instance1.Altitude%
;HKR,"Instances\"%Instance1.Name%,"Flags",0x00010001,%Instance1.Flags%
HKR,,"SupportedFeatures",0x00010001,0x3
HKR,"Instances","DefaultInstance",0x00000000,%DefaultInstance%
HKR,"Instances\"%Instance1.Name%,"Altitude",0x00000000,%Instance1.Altitude%
HKR,"Instances\"%Instance1.Name%,"Flags",0x00010001,%Instance1.Flags%

;-------------------------------------------------------------------------
; Ndi installation support
;-------------------------------------------------------------------------
[Inst_Ndi]
HKR, Ndi,Service,,"Neehack"
HKR, Ndi,CoServices,0x00010000,"Neehack"
HKR, Ndi,HelpText,,%Neehack_HelpText%
; TODO: Set the FilterClass here.  The FilterClass controls the order in which
; filters are bound to the underlying miniport.  Possible options include:
;     Custom, Diagnostic, Failover, Loadbalance, Vpn, Compression, Encryption, Scheduler
; See MSDN for a description of each.
HKR, Ndi,FilterClass,, compression
; TODO: Specify whether you have a Modifying or Monitoring filter.
; For a Monitoring filter, use this:
;     HKR, Ndi,FilterType,0x00010001, 1 ; Monitoring filter
; For a Modifying filter, use this:
;     HKR, Ndi,FilterType,0x00010001, 2 ; Modifying filter
HKR, Ndi,FilterType,0x00010001,2
; Do not change these values
HKR, Ndi\Interfaces,UpperRange,,"noupper"
HKR, Ndi\Interfaces,LowerRange,,"nolower"
; TODO: Ensure that the list of media types below is correct.  Typically,
; filters include "ethernet".  Filters may also include "ppip" to include
; native WWAN stacks, but you must be prepared to handle the packet framing.
; Possible values are listed on MSDN, but common values include:
;     ethernet, wan, ppip, wlan
HKR, Ndi\Interfaces, FilterMediaTypes,,"ethernet, wan, ppip"
; TODO: Specify whether you have a Mandatory or Optional filter.
; For a Mandatory filter, use this:
;     HKR, Ndi,FilterRunType,0x00010001, 1 ; Mandatory filter
; For an Optional filter, use this:
;     HKR, Ndi,FilterRunType,0x00010001, 2 ; Optional filter
HKR, Ndi,FilterRunType,0x00010001, 1 ; Mandatory filter


[Install.Remove.Services]
; The SPSVCINST_STOPSERVICE flag instructs SCM to stop the NT service
; before uninstalling the driver.
DelService=Neehack,0x200 ; SPSVCINST_STOPSERVICE

[Common.Params.reg]
; TODO: You can add any sort of NDIS parameters here.  Filter drivers
; don't always need NDIS parameters, so it's okay to have nothing here.

; TODO: Remove the sample parameters below.

; Sample 1: "DriverParam" is a per-driver parameter.
HKR, FilterDriverParams\DriverParam,     ParamDesc,   , "Driverparam for lwf"
HKR, FilterDriverParams\DriverParam,     default,     , "5"
HKR, FilterDriverParams\DriverParam,     type,        , "int"

; Sample 2: "AdapterParam" is a per-module parameter.
HKR, FilterAdapterParams\AdapterParam,   ParamDesc,   , "Adapterparam for lwf"
HKR, FilterAdapterParams\AdapterParam,   default,     , "10"
HKR, FilterAdapterParams\AdapterParam,   type,        , "int"

[NdisImPlatformBindingOptions.reg]
; By default, when an LBFO team or Bridge is created, all filters will be
; unbound from the underlying members and bound to the TNic(s). This keyword
; allows a component to opt out of the default behavior
; To prevent binding this filter to the TNic(s):
;   HKR, Parameters, NdisImPlatformBindingOptions,0x00010001,1 ; Do not bind to TNic
; To prevent unbinding this filter from underlying members:
;   HKR, Parameters, NdisImPlatformBindingOptions,0x00010001,2 ; Do not unbind from Members
; To prevent both binding to TNic and unbinding from members:
;   HKR, Parameters, NdisImPlatformBindingOptions,0x00010001,3 ; Do not bind to TNic or unbind from Members
HKR, Parameters, NdisImPlatformBindingOptions,0x00010001,0 ; Subscribe to default behavior



[Strings]
; TODO: Customize these strings.
Msft = "Neehack" ;TODO: Replace with your manufacturer name
Neehack_Desc = "Neehack NDIS LightWeight Filter"
Neehack_HelpText = "Neehack NDIS LightWeight Filter"

DefaultInstance = "Neehack Instance"
Instance1.Name = "Neehack Instance"
Instance1.Altitude = "371000"
Instance1.Flags = 0x0

In summary, this driver, captures PreFileCreate and PreFileWrite events and if the write event was on file called “block.txt”, this event should be blocked by our mini-filter driver.

To run and debug this:

  1. Make sure you choose “Debug” mode for solution configurations on visual studio and build it (CTRL+SHIFT+B).
  2. On the VM that you will run this, enable local kernel debugging and disable Driver signing security check for windows.
  3. Download DbgView for debugging and OSRLoader for registering and starting your driver.
  4. Open DBGView and Enable Capture Kernel and Enable Verbose Kernel Output. This will enable the debugger to receive our driver’s KdPrint calls.
  5. Open OSRLoader, select Neehack.sys file under Driver Path, choose the driver type as MiniFilter and set the Altitude to 371000. First click on Register Service, then Start Service.

If you were successful, you should be receiving dozens of “Capturing Pre Write Events” on DebugView. Now to test that the driver works, simply open a text file under Desktop called “block.txt” and try to write some data and save the file. You should not be able to save your contents on the file.

High Level Explanation:

DriverEntry function is the main function of a driver, This is where we start coding our driver. A Filesystem Mini-Filter driver first require the driver to be registered with Kernel Driver Manager. This, in our sample is achieved by calling FltRegisterFilter which takes 3 parameters.

  1. DriverObject
  2. Driver registration which includes events that needs to be captured I.e CreateFile/WriteFile and etc…
  3. A FileHandle which will be returned if the driver was successfully registered.
status = FltRegisterFilter(DriverObject, &FilterRegistration, &FilterHandle);

MiniUnload is responsible to unregister the driver, if something went wrong.

PreOperationCreate is the function called by Driver manager Before the file is created. For us, it simply sends the filename to the debugger and returns to driver manager with status of success without callback for PostCreate.

MiniPreWrite is the function, we call before writing the data on disk, this is the function we use to lookup the file name and if the file name contains “block.txt”, the event should be prevented.

More articles on “How to develop Filesystem Mini-Filter driver” is coming.


Leave a Reply

Your email address will not be published.