إنتقل إلى المحتوى الرئيسي

Kernel-mode driver

What this page is

The kernel-mode minifilter driver (edr-windows-km.sys) that provides filesystem interception, process creation callbacks, registry monitoring, and EDR process protection from kernel space. This page describes the driver architecture, the IOCTL interface between user-mode and kernel-mode, and the build requirements.

Why it exists this way

A user-mode EDR sensor can be terminated by any process with SYSTEM privileges or by kernel-mode malware. The kernel-mode driver operates at a higher trust level than user-mode processes and can:

  • Intercept file operations before they reach the filesystem stack (minifilter at altitude 385000 in the Anti-Virus range).
  • Receive process creation notifications synchronously via PsSetCreateProcessNotifyRoutineEx, which can block or terminate process creation before the process initialises.
  • Protect the EDR user-mode process from handle manipulation via ObRegisterCallbacks with a pre-operation callback that strips PROCESS_TERMINATE and PROCESS_VM_WRITE from non-whitelisted handle open requests.
  • Monitor registry persistence keys via CmRegisterCallback with synchronous pre-operation notification, which can block suspicious registry writes before they are committed.

Architecture

User-mode Kernel-mode
--------- -----------
edr-windows.exe edr-windows-km.sys
│ │
├─ DeviceIoControl ──────IOCTL─────→ IO_STACK_LOCATION handler
│ │
│ ┌──┤
│ │ ├── FltRegisterFilter (minifilter)
│ │ ├── PsSetCreateProcessNotifyRoutineEx
│ │ ├── CmRegisterCallback (registry)
│ │ └── ObRegisterCallbacks (object)
│ │
│ ├── Minifilter callbacks:
│ │ - IRP_MJ_CREATE (pre-operation)
│ │ - IRP_MJ_WRITE (pre-operation)
│ │ - IRP_MJ_CLEANUP (post-operation)
│ │
└─ gRPC stream ──────────→ Collector (not shown)

IOCTL interface

The user-mode service communicates with the driver via DeviceIoControl on \\\\.\\AuroraEDRKM. Four IOCTL codes are defined:

IOCTLCodeDirectionPurpose
IOCTL_QUERY_CALLBACK_HEALTH0x8000_2200In/OutReturns CallbackHealthReport with status of all 4 callbacks
IOCTL_QUERY_MINIFILTER_STATUS0x8000_2204In/OutReturns instance count, altitude, and filter status
IOCTL_START_EVENT_STREAM0x8000_2208In/OutOpens a token-based inline event stream from kernel to user mode
IOCTL_STOP_EVENT_STREAM0x8000_220CIn/OutCloses the event stream identified by token

Callback health report

The IOCTL_QUERY_CALLBACK_HEALTH response tells the user-mode service whether each kernel callback is still registered:

pub struct CallbackHealthReport {
pub process_notify_count: u32,
pub process_notify_health: CallbackHealth,
pub registry_callback_health: CallbackHealth,
pub object_callback_health: CallbackHealth,
pub minifilter_active: bool,
}

The user-mode guard module polls this IOCTL every 30 seconds. If any callback returns NotRegistered, the guard escalates to critical alert because this indicates a kernel-mode tamper attempt.

Token-based event streaming

Tokens are 128-bit UUIDs generated by the driver at IOCTL_START_EVENT_STREAM time. The user-mode service maps each token to an overlapped I/O completion port. When a kernel callback fires, the driver writes a serialised event header into the token's output buffer and signals the completion port. This avoids user-mode polling and keeps event latency under 1 millisecond.

Minifilter configuration

The minifilter is registered at altitude 385000, which places it in the middle of the Anti-Virus range (380000-389999) per Microsoft's minifilter altitude allocation. At this altitude, the filter runs after the filesystem driver and before user-mode applications see the operation.

Monitored extensions: .exe, .dll, .sys, .bat, .ps1, .vbs, .js, .vba, .hta, .scr, .cmd, .msi

Sensitive paths: System32, SysWOW64, Program Files, Program Files (x86), Start Menu\Programs\Startup

For each monitored operation, the minifilter's pre-operation callback inspects the file name extension and path. If both match, the event is written to all active event stream tokens. If no tokens are active, the event is dropped (zero-allocation fast path).

Build requirements

The driver requires the Windows Driver Kit (WDK) and cannot be cross-compiled from Linux or macOS. The build environment is:

  • Host OS: Windows 10/11 (x86_64) or Windows Server 2019+
  • SDK: Windows 10/11 SDK 10.0.22621 or later
  • WDK: Windows Driver Kit for the matching SDK version
  • Rust: nightly-2024-12-15 with rust-src component
  • Cargo: cargo-wdk subcommand or manual WDK invocation via cargo build --target x86_64-pc-windows-msvc

The crate is a standalone workspace (not a member of the root workspace) for the same reasons as crates/edr-linux-ebpf: the no_std + custom-target constraints differ enough from the host workspace that a unified workspace would force wrong defaults.

What goes wrong

  • FltRegisterFilter fails because another minifilter already occupies altitude 385000. The driver falls back to the next available altitude in the 380000-389999 range.
  • PsSetCreateProcessNotifyRoutineEx fails with STATUS_ACCESS_DENIED if the driver is not signed with a Microsoft cross-signing certificate. This is enforced on Windows 10 1607+ with Secure Boot enabled.
  • ObRegisterCallbacks fails with STATUS_ACCESS_DENIED for the same signing requirement. The driver starts in PartialProtection mode if either process or object callbacks fail to register.
  • CmRegisterCallback is deprecated in Windows 11 24H2. The driver detects the OS version at load time and uses the replacement API (CmRegisterCallbackEx with the REG_CALLBACK_FLAG_ALTITUDE flag) when available.