Kernel Driver Module

Detailed documentation of the WindowsFileSystemMinifilter.sys kernel driver β€” source files, callback implementations, context management, and communication port handling.

Related: Driver Architecture Β· File Interception Flow Β· Driver Lifecycle Β· Kernel ↔ User Interface


1. Source Files

File Purpose
Windows File System Minifilter/main.cpp DriverEntry β€” initialization, registration, port creation
Windows File System Minifilter/FsMinifilter.cpp All callback implementations (860+ lines)
Windows File System Minifilter/FsMinifilter.h Stream context struct, function declarations, globals
Windows File System Minifilter/FsMinifilterCommon.h Shared message types and structures (kernel ↔ user)
WindowsFileSystemMinifilter.inf Driver installation INF file

2. Module Architecture

classDiagram
    class DriverEntry {
        +FltRegisterFilter()
        +FltCreateCommunicationPort()
        +FltStartFiltering()
    }

    class CallbackHandlers {
        +PreOperationCreate()
        +PostOperationCreate()
        +PreOperationRead()
        +PreOperationWrite()
        +PreOperationSetInfo()
        +PostOperationSetInfo()
        +PreOperationCleanup()
        +PostOperationCleanup()
    }

    class InstanceCallbacks {
        +InstanceFilterUnloadCallback()
        +InstanceSetupCallback()
        +InstanceQueryTeardownCallback()
    }

    class PortCallbacks {
        +PortConnectCallback()
        +PortDisconnectCallback()
    }

    class Helpers {
        +IsTargetExtension()
        +SendMessageToUserMode()
        +GetOrSetStreamContext()
        +StreamContextCleanupCallback()
    }

    class Globals {
        +PFLT_FILTER g_minifilterHandle
        +PFLT_PORT g_serverPort
        +PFLT_PORT g_clientPort
        +ULONG g_clientProcessId
    }

    DriverEntry --> CallbackHandlers : registers
    DriverEntry --> InstanceCallbacks : registers
    DriverEntry --> PortCallbacks : registers
    CallbackHandlers --> Helpers : calls
    CallbackHandlers --> Globals : reads/writes
    PortCallbacks --> Globals : reads/writes

3. Global State

Variable Type Initialized Modified By
g_minifilterHandle PFLT_FILTER DriverEntry InstanceFilterUnloadCallback (set to NULL after unregister)
g_serverPort PFLT_PORT DriverEntry InstanceFilterUnloadCallback (closed)
g_clientPort PFLT_PORT PortConnectCallback PortDisconnectCallback (set to NULL)
g_clientProcessId ULONG PortConnectCallback PortDisconnectCallback (set to 0)

Thread Safety: g_clientPort is read by all callback threads and written only by the single-threaded port callbacks. The driver assumes atomic pointer reads on the target architecture. g_clientProcessId is similarly safe because it’s a 32-bit value on all platforms.


4. Callback Implementation Details

4.1 PreOperationCreate / PostOperationCreate

Purpose: Detect new file opens and track FILE_DELETE_ON_CLOSE.

Pre-op logic:

  1. Check if FILE_DELETE_ON_CLOSE flag is set in Create.Options
  2. If yes: allocate a FS_STREAM_CONTEXT, pass it via CompletionContext, return FLT_PREOP_SYNCHRONIZE
  3. If no: return FLT_PREOP_SUCCESS_WITH_CALLBACK

Post-op logic:

  1. Skip if create failed or returned STATUS_REPARSE
  2. Get normalized file name via FltGetFileNameInformation
  3. If target extension and not self-PID β†’ SendMessageToUserMode(MSG_TYPE_FILE_CREATE)
  4. If stream context was passed from pre-op β†’ attach it via FltSetStreamContext, mark DeleteOnClose = TRUE

4.2 PreOperationRead

Purpose: Monitor read access to .exe/.dll files.

Single pre-op callback, no post-op needed:

  1. Quick rejection: no client, zero-length read, self-PID
  2. Get file name, check extension
  3. Send MSG_TYPE_FILE_READ

4.3 PreOperationWrite

Purpose: Monitor write/modification of .exe/.dll files.

Identical structure to PreOperationRead, sends MSG_TYPE_FILE_MODIFY.

4.4 PreOperationSetInfo / PostOperationSetInfo

Purpose: Track delete disposition changes for accurate delete detection.

Pre-op logic:

  1. Only handle FileDispositionInformation and FileDispositionInformationEx
  2. Get or create stream context via GetOrSetStreamContext
  3. Increment NumOps atomically for race detection
  4. If NumOps == 1: pass context to post-op via FLT_PREOP_SYNCHRONIZE
  5. If NumOps > 1: racing operations detected, release context

Post-op logic:

  1. If operation succeeded, update SetDisp or DeleteOnClose based on the info class
  2. Handle both legacy FileDispositionInformation and modern FileDispositionInformationEx with FILE_DISPOSITION_ON_CLOSE flag
  3. Decrement NumOps atomically

4.5 PreOperationCleanup / PostOperationCleanup

Purpose: Confirm actual file deletion and send notification.

Pre-op: Attempt to get existing stream context. If found, synchronize for post-op.

Post-op:

  1. Check if SetDisp, DeleteOnClose, or NumOps > 0
  2. If delete candidate β†’ FltQueryInformationFile(FileStandardInformation)
  3. If returns STATUS_FILE_DELETED β†’ confirm deletion
  4. InterlockedIncrement(IsNotified) β€” only send notification if this is the first increment (value becomes 1)
  5. Send MSG_TYPE_FILE_DELETE with file path and PID

5. Helper Functions

IsTargetExtension

BOOLEAN IsTargetExtension(PCUNICODE_STRING FileName)

Case-insensitive check for .exe and .dll extensions. Operates directly on the UNICODE_STRING buffer without allocating memory.

Algorithm: Check last 4 characters of the filename against .exe and .dll using character-by-character comparison with upper/lower variants.

SendMessageToUserMode

NTSTATUS SendMessageToUserMode(ULONG MessageType, PCUNICODE_STRING FilePath, ULONG ProcessId)

Sends a MINIFILTER_MESSAGE to the connected user-mode monitor.

  • Timeout: 100ms (relative) β€” prevents blocking the I/O path
  • No reply expected: replyLength = 0, reply buffer is NULL
  • Timeout tolerance: STATUS_TIMEOUT is silently converted to STATUS_SUCCESS
  • Disconnection check: Returns STATUS_PORT_DISCONNECTED immediately if g_clientPort == NULL

GetOrSetStreamContext

NTSTATUS GetOrSetStreamContext(PCFLT_RELATED_OBJECTS, PFILE_OBJECT, PFS_STREAM_CONTEXT*)

Race-safe context acquisition pattern:

  1. Try FltGetStreamContext β€” if found, return existing
  2. If STATUS_NOT_FOUND β†’ allocate new context
  3. Try FltSetStreamContext with FLT_SET_CONTEXT_KEEP_IF_EXISTS
  4. If STATUS_FLT_CONTEXT_ALREADY_DEFINED β†’ another thread beat us, use the existing one

6. Port Callbacks

PortConnectCallback

Called when FsMinifilterMonitor.exe connects:

  • Stores the client port handle in g_clientPort
  • Records the monitor’s PID via PsGetCurrentProcessId() into g_clientProcessId
  • Sets *ConnectionCookie = NULL (no cookie needed)

PortDisconnectCallback

Called when the monitor disconnects or exits:

  • Resets g_clientProcessId = 0
  • Closes client port via FltCloseClientPort
  • Sets g_clientPort = NULL

7. Build Configuration

Setting Value
Driver Type KMDF (file system minifilter)
Target OS Windows 10+
Architectures ARM64, x64
Configurations Debug, Release
Dependencies FltMgr (Filter Manager)
INF Class Bottom
Catalog windowsfilesystemminifilter.cat

Next Steps