Kernel โ User Interface
This document specifies the communication protocol between the kernel-mode minifilter driver and the user-mode monitor application, including port setup, message format, and connection lifecycle.
Related: Communication Architecture ยท Kernel Driver Module ยท Monitor Module ยท Data Types Reference
1. Protocol Overview
flowchart LR
subgraph Kernel
Driver["Driver\n(message producer)"]
end
subgraph Protocol["Filter Communication Port Protocol"]
Port["\\FsMinifilterPort"]
direction TB
end
subgraph User
Monitor["Monitor\n(message consumer)"]
end
Driver -->|"FltSendMessage\n(MINIFILTER_MESSAGE)"| Port
Port -->|"FilterGetMessage\n(FILTER_MESSAGE)"| Monitor
style Protocol fill:#4361ee,color:#fff
Direction: Unidirectional (kernel โ user only). The driver does not register a MessageNotifyCallback, so the monitor cannot send messages to the driver.
2. Port Configuration
Driver Side (Server)
FltCreateCommunicationPort(
g_minifilterHandle, // Filter handle
&g_serverPort, // [out] Server port handle
&objectAttributes, // Port name + security
NULL, // No server cookie
PortConnectCallback, // Called on client connect
PortDisconnectCallback,// Called on client disconnect
NULL, // No message callback (unidirectional)
1 // MaxConnections = 1
);
| Parameter |
Value |
Notes |
| Port Name |
\FsMinifilterPort |
NT object namespace |
| Security |
FLT_PORT_ALL_ACCESS via FltBuildDefaultSecurityDescriptor |
Default ACL |
| Max Connections |
1 |
Single monitor at a time |
| Message Direction |
Kernel โ User |
No MessageNotifyCallback |
User Side (Client)
FilterConnectCommunicationPort(
L"\\FsMinifilterPort", // Port name
0, // Options
NULL, // Connection context
0, // Context size
NULL, // Security attributes
&port // [out] Port handle
);
3. Message Structures
Kernel-Side Message (Sent)
classDiagram
class MINIFILTER_MESSAGE {
+ULONG MessageType
+ULONG ProcessId
+WCHAR FilePath[520]
}
note for MINIFILTER_MESSAGE "Defined in: FsMinifilterCommon.h\nSize: 1048 bytes\nSent via FltSendMessage()"
| Field |
Offset |
Size |
Description |
MessageType |
0 |
4 bytes |
Operation type (see message types below) |
ProcessId |
4 |
4 bytes |
PID of the process that initiated the I/O |
FilePath |
8 |
1040 bytes |
Null-terminated NT file path (max 520 WCHARs) |
| Total |
ย |
1048 bytes |
ย |
User-Side Message (Received)
classDiagram
class FILTER_MESSAGE {
+FILTER_MESSAGE_HEADER Header
+MINIFILTER_MESSAGE Message
}
class FILTER_MESSAGE_HEADER {
+ULONG ReplyLength
+ULONGLONG MessageId
}
FILTER_MESSAGE --> FILTER_MESSAGE_HEADER
FILTER_MESSAGE --> MINIFILTER_MESSAGE
note for FILTER_MESSAGE "Defined in: FsMinifilterMonitor/main.cpp\nFilter Manager prepends the header"
The monitor receives FILTER_MESSAGE which includes a FILTER_MESSAGE_HEADER prepended by Filter Manager, followed by the MINIFILTER_MESSAGE payload.
4. Message Types
| Constant |
Value |
Trigger |
Filtered To |
MSG_TYPE_FILE_CREATE |
1 |
IRP_MJ_CREATE completed successfully |
.exe, .dll only |
MSG_TYPE_FILE_READ |
2 |
IRP_MJ_READ with non-zero length |
.exe, .dll only |
MSG_TYPE_FILE_MODIFY |
3 |
IRP_MJ_WRITE with non-zero length |
.exe, .dll only |
MSG_TYPE_FILE_DELETE |
4 |
IRP_MJ_CLEANUP confirms deletion |
All files with stream context |
flowchart LR
subgraph KernelEvents["Kernel IRP Events"]
CREATE["IRP_MJ_CREATE"]
READ["IRP_MJ_READ"]
WRITE["IRP_MJ_WRITE"]
CLEANUP["IRP_MJ_CLEANUP\n(delete confirmed)"]
end
subgraph Messages["Message Types"]
M1["MSG_TYPE_FILE_CREATE (1)"]
M2["MSG_TYPE_FILE_READ (2)"]
M3["MSG_TYPE_FILE_MODIFY (3)"]
M4["MSG_TYPE_FILE_DELETE (4)"]
end
CREATE --> M1
READ --> M2
WRITE --> M3
CLEANUP --> M4
style Messages fill:#4361ee,color:#fff
5. Send Semantics
FltSendMessage Call
FltSendMessage(
g_minifilterHandle, // Filter handle
&g_clientPort, // Client port pointer
&message, // MINIFILTER_MESSAGE buffer
sizeof(MINIFILTER_MESSAGE), // Message size
NULL, // No reply buffer
&replyLength, // Reply length = 0
&timeout // 100ms timeout
);
| Behavior |
Detail |
| Blocking |
Waits up to 100ms for the monitor to receive |
| Timeout handling |
STATUS_TIMEOUT is silently converted to STATUS_SUCCESS |
| No reply |
Reply buffer is NULL, replyLength = 0 |
| Disconnected |
Returns STATUS_PORT_DISCONNECTED if g_clientPort == NULL |
| Thread context |
Called from the I/O thread; 100ms timeout limits impact |
FilterGetMessage Call
FilterGetMessage(
port, // Port handle
&message.Header, // Output buffer (FILTER_MESSAGE)
sizeof(FILTER_MESSAGE), // Buffer size
NULL // No overlapped (synchronous)
);
| Behavior |
Detail |
| Blocking |
Blocks until a message arrives |
| Synchronous |
No overlapped I/O (NULL parameter) |
| Error |
Returns HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE) on disconnection |
6. Connection Lifecycle Callbacks
PortConnectCallback
Called by Filter Manager when a user-mode client connects.
| Action |
Code |
| Store client port |
g_clientPort = ClientPort |
| Record monitor PID |
g_clientProcessId = HandleToULong(PsGetCurrentProcessId()) |
| Set connection cookie |
*ConnectionCookie = NULL |
PortDisconnectCallback
Called by Filter Manager when the client disconnects or the port is closed.
| Action |
Code |
| Clear monitor PID |
g_clientProcessId = 0 |
| Close client port |
FltCloseClientPort(g_minifilterHandle, &g_clientPort) |
| Clear port pointer |
g_clientPort = NULL |
7. Error Codes
| Status |
Meaning |
Handling |
STATUS_SUCCESS |
Message delivered |
Continue |
STATUS_TIMEOUT |
Monitor didnโt receive within 100ms |
Ignored (treated as success) |
STATUS_PORT_DISCONNECTED |
No client connected |
Early return, no send attempt |
HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE) |
(User-side) Driver disconnected |
Monitor exits message loop |
Next Steps