CLOSE
Updated on 27 Jul, 202511 mins read 15 views

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 *