Windows file systems are responsible for managing how data is stored and retrieved on storage devices. Devices often need to monitor, control, or enhance file system behaviour without modifying the file system itself. That's where Minifilter
drivers come in.
Core Components of a Minifilter
1 DriverEntry()
: The Entry Point
The DriverEntry()
function is the standard entry point for all Windows drivers.
NTSTATUS DriverEntry(
_IN_ PDRIVER_OBJECT DriverObject,
_IN_ PUNICODE_STRING RegistryPath
){
NTSTATUS status;
// Register minifilter
status = FltRegisterFilter(
DriverObject,
&FilterRegistration,
&gFilterHandle);
if (!NT_SUCCESS(status)) {
return status;
}
// Start filtering
status = FltStartFiltering(gFilterHandle);
if (!NT_SUCCESS(status)) {
FltUnregisterFilter(gFilterHandle);
}
return status;
}
FltRegisterFilter()
registers the Minifilter with the Filter Manager.gFilterHandle
is a global variable used to refer to the registered filter in start/stop/unload routines.
2 Filter Registration Structure
Defines what operations your filter will intercept:
const FLT_OPERATION_REGISTRATION Callbacks[] = {
{ IRP_MJ_CREATE, 0, PreCreateCallback, PostCreateCallback },
{ IRP_MJ_WRITE, 0, PreWriteCallback, PostWriteCallback },
{ IRP_MJ_READ, 0, PreReadCallback, PostReadCallback },
{ IRP_MJ_OPERATION_END }
};
- Each entry maps to an IRP major function code.
- You can register Pre, Post, or both.
- The
Flags
field is usually set to 0 unless using fast I/O or specific context needs.
3 Filter Structure
Connects your callback table and lifecycle routines to the Filter Manager.
const FLT_REGISTRATION FilterRegistration = {
sizeof(FLT_REGISTRATION), // Size
FLT_REGISTRATION_VERSION, // Version
0, // Flags
Callbacks, // IRP callback table
UnloadCallback, // Unload routine
InstanceSetup, // Setup per volume
InstanceQueryTeardown, // Query teardown
InstanceTeardownStart, // Start teardown
InstanceTeardownComplete, // Complete teardown
NULL, // GenerateFileName
NULL, // NormalizeNameComponent
NULL // NormalizeContextCleanup
};
4 Callback Functions
These are the handlers you define to process I/O operations. Here's simple PreCreate
that blocks .exe
files:
FLT_PREOP_CALLBACK_STATUS
PreCreateCallback(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID *CompletionContext) {
PFLT_FILE_NAME_INFORMATION nameInfo;
if (!NT_SUCCESS(FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED, &nameInfo))) {
return FLT_PREOP_SUCCESS_NO_CALLBACK;
}
FltParseFileNameInformation(nameInfo);
if (wcsstr(nameInfo->Name.Buffer, L".exe")) {
Data->IoStatus.Status = STATUS_ACCESS_DENIED;
Data->IoStatus.Information = 0;
return FLT_PREOP_COMPLETE;
}
return FLT_PREOP_SUCCESS_NO_CALLBACK;
}
Leave a comment
Your email address will not be published. Required fields are marked *