Skip to main content

Kernel Driver Architecture

The R0 side of Xdows Security is delivered by the Xdows-Security-Driver repository. It contains two kernel components that ship in the same driver package and start and stop together with Driver Protection:

ComponentTypeRole
Xdows-Security-DriverKMDF minifilter on FltMgrProduces process, file, handle, behavior, boot, and registry events; holds protected operations until user mode decides
Xdows-Security-BootFilterSeparate WDM storage filterProtects raw system-disk boot-region writes

The main driver is registered as a file-system driver with StartType = DEMAND_START in the FSFilter Activity Monitor load-order group, depends on FltMgr, and uses the altitude 370030.

Ownership Boundary​

The driver repository owns Public.h — the protocol constants, IOCTLs, event/decision/state/authorization/process/log structures — as well as kernel event production, the pending queue and timeout behaviour, token hashing, self-protection, injection protection, and log buffering.

The main app repository mirrors Public.h in Protection\DriverProtocol.cs, owns the bridge in Protection\DriverBridgeClient.cs and the policy in Protection\DriverProtection.cs, and installs the package through DriverInstaller / DriverPackageInstaller. The model repository owns the Xdows-Model-Native.dll C ABI, the ONNX Runtime dependencies, and the ONNX model files; the driver itself never loads a model.

Any change to Public.h that alters a struct layout, enum value, IOCTL code, string buffer length, token length, or device path must update DriverProtocol.cs, DriverBridgeClient.cs when IOCTL behaviour changed, DriverProtection.cs when event or decision semantics changed, and the usage documentation in the same change.

Protocol Version​

The current main-driver protocol version is 9. BootFilter uses its own independent protocol v1. The two are not interchangeable.

Protocol 7 added the Behavior event, the shared BehaviorType payload, per-type state counters, and the R0 behavior module and capability bits. Protocol 9 added SetBootProtection (0x80E), SetRegistryProtection (0x80F), the RegistryWrite event (type 11), capability bit 0x200, and module bit 0x40.

Every later addition stayed on protocol 9 as a purely additive block, so an older app build keeps working against a newer driver and vice versa. New enum values are appended; existing values are never reused for a new meaning.

IOCTL Map​

IOCTLFunctionPurpose
IOCTL_XDOWS_SECURITY_REGISTER_CLIENT0x801Register the app bridge and return the privileged authorization token once
IOCTL_XDOWS_SECURITY_HEARTBEAT0x802Keep bridge liveness fresh
IOCTL_XDOWS_SECURITY_GET_NEXT_EVENT0x803Pull one pending protection event
IOCTL_XDOWS_SECURITY_SUBMIT_DECISION0x804Return Allow, Block, or Timeout for an event
IOCTL_XDOWS_SECURITY_GET_STATE0x805Query bridge and queue state
IOCTL_XDOWS_SECURITY_DISCONNECT_CLIENT0x806Explicit bridge disconnect
IOCTL_XDOWS_SECURITY_REGISTER_PROTECTED_PROCESS0x807Register the main app process for self-protection
IOCTL_XDOWS_SECURITY_SET_VOLUNTARY_EXIT0x808Tell the driver the app is intentionally exiting
IOCTL_XDOWS_SECURITY_AUTHORIZED_SHUTDOWN0x809Stop protection with the one-time shutdown token
IOCTL_XDOWS_SECURITY_GET_NEXT_LOG0x80APull one buffered driver log entry
IOCTL_XDOWS_SECURITY_SET_STARTUP_PROTECTION0x80BSynchronize startup-entry self-protection
IOCTL_XDOWS_SECURITY_QUERY_PROCESSES0x80CToken-authorized, paged kernel process snapshot
IOCTL_XDOWS_SECURITY_OPERATE_PROCESS0x80DSuspend, resume, or terminate a process after protected-client and token validation
IOCTL_XDOWS_SECURITY_SET_BOOT_PROTECTION0x80EConfigure EFI and BCD boot protection
IOCTL_XDOWS_SECURITY_SET_REGISTRY_PROTECTION0x80FConfigure R0 registry protection rules
IOCTL_XDOWS_SECURITY_GET_NEXT_EVENTS0x810Drain up to 16 undelivered events in one non-blocking call
IOCTL_XDOWS_SECURITY_SET_BEHAVIOR_RULES0x811Replace the declarative behavior rule set (capability 0x1000)
IOCTL_XDOWS_SECURITY_SET_INITIATOR_EXCLUSIONS0x812Replace the initiator exclusion list (capability 0x2000)

Process management requests require both the registered, self-protected main process identity and the authorization token issued during registration. The driver rejects PID 0, PID 4, the calling main process, the protected process, and critical processes.

Capability and Module Bits​

Capabilities are reported by the driver so the app can degrade gracefully instead of issuing an unsupported downcall:

CapabilityValueMeaning
CAP_PRIORITY_QUEUE0x1Priority event queue
CAP_DIRTY_WRITE_COALESCING0x2Coalesce duplicate dirty writes
CAP_BUILD_ID0x4Drivers report a build id
CAP_STARTUP_SELF_PROTECT0x8Startup-entry self-protection
CAP_USER_DECISION_HOLD0x10Hold an operation for a user decision
CAP_PROCESS_MANAGEMENT0x20Kernel process management
CAP_ENHANCED_SELF_PROTECT0x40Enhanced self-protection
CAP_R0_BEHAVIOR_PROTECTION0x80R0 behavior module
CAP_R0_BOOT_PROTECTION0x100R0 boot protection
CAP_R0_REGISTRY_PROTECTION0x200R0 registry protection
CAP_ASYNC_REVIEW0x400Non-critical events may be reviewed asynchronously
CAP_EVENT_BATCH0x800Batch event drain
CAP_RULE_INTERPRETER0x1000Declarative behavior rule interpreter
CAP_INITIATOR_EXCLUSION0x2000Initiator exclusion list

Module bits report which protection modules are live: TokenAuth 0x1, Process 0x2, File 0x4, Injection 0x8, SelfProtect 0x10, Behavior 0x20, Registry 0x40.

Events and Behavior Types​

Behavior events always carry a ThreatConfirmed flag and enter the user-decision hold before any path resolution or UI work. The behavior type values are:

ValueNameNotes
0None
1VssDeletionShadow-copy destruction
2HiddenPowerShell
3EncodedCommand
4PolicyBypassFail-open on infrastructure failure
5DownloadExecute
6LolbinAbuse
7ProcessInjectionCorrelates dangerous process handle requests
8ThreadInjectionCorrelates dangerous thread handle requests
9ParentProcessChain
10AutorunInf
11ProtectedProcessTerminate
12SensitiveProcessHandle
13DestructiveDirectoryDeleteFail-open on infrastructure failure
14OwnershipEscalationFail-open on infrastructure failure
15SystemControlCommandFail-open on infrastructure failure
16EfiMountmountvol + /s; fail-closed
17OobeResetsysprep + /oobe / /generalize / /audit; fail-closed
18SystemDirectoryRansomwareReserved: enforced purely in kernel, never reaches user mode

Decision Semantics​

  • Allow: continue the original operation.
  • Block: deny the original operation.
  • Timeout: the user-mode decision timed out; a confirmed threat maps to deny behaviour.

When the bridge or the model fails before a threat is confirmed, user mode allows and logs the failure. High-confidence command rules keep their kernel fail-closed behaviour, policy bypass stays fail-open, and injection keeps its existing fail-open infrastructure policy. When a threat is confirmed and the user refuses or times out, the decision is Block or Timeout.

Declarative Behavior Rules​

Capability 0x1000 adds a user-mode-authored rule interpreter, so new behavior coverage no longer requires a driver rebuild. A rule is the tuple Initiator × CommandLine × Target:

FieldMeaning
RuleId, BehaviorTypeBoth must be non-zero
OperationsMask of PROCESS_CREATE 0x1, FILE_CREATE 0x2, FILE_WRITE 0x4, FILE_DELETE 0x8, FILE_RENAME 0x10, ALL 0x1F
Threshold / WindowMsOptional rate limit: 0 fires on every match; otherwise the same process must match Threshold times within WindowMs (clamped to 60000)
TargetMatchKindAny 0, Suffix 1, Segment 2, Prefix 3, Contains 4
FlagsKILL_ACTOR 0x1, FAIL_CLOSED 0x2
Initiator / Target / CommandLineTerm axes, each holding up to 3 terms of 96 wide chars, NUL included

Axis semantics: TermCount == 0 leaves the axis unconstrained. An Initiator term is an image leaf name (cmd.exe) or, when it contains a backslash, a case-insensitive actor-path suffix. Every CommandLine term must appear as a substring. Target terms are interpreted with the rule's TargetMatchKind, and the rule matches when any target term matches. A rule that constrains no axis at all is rejected.

A whole request is validated before anything is applied and is rejected as a unit, so a malformed rule can never leave a partially applied set: TargetMatchKind must be in range, Operations must be non-zero and inside the supported mask, Flags must contain only known bits, Threshold must be 0..10000, and every term must be non-empty, NUL-terminated inside its fixed buffer, and free of literal * / ? wildcards — the interpreter only does literal matching, so a wildcard term would silently never match and hide a configuration mistake. A rejected request returns STATUS_INVALID_PARAMETER and leaves the previous set untouched. The swap happens under the exclusive side of an EX_PUSH_LOCK that the evaluation path holds shared.

Fail-open / fail-closed is a per-rule property rather than a per-rule-id hard-coded list: on infrastructure failure a rule without FAIL_CLOSED releases the operation and logs it, and a rule with it denies with STATUS_ACCESS_DENIED. KILL_ACTOR escalates a confirmed Block to a counter-kill of the acting process, sharing the injection guard rails (never the registered client, a critical system process, a self-protected process, or PID ≤ 4). A rate-limited rule is tracked in a fixed 32-slot sliding window keyed by (rule id, process id).

The fixed in-kernel rules are always evaluated before the declarative set, so their fail-open / fail-closed classification is unchanged and the declarative set can only add coverage, never weaken a built-in denial. The limit is 32 rules.

Initiator Exclusions​

Capability 0x2000 lets the app suppress the user-mode consultation for known-good actors: up to 32 entries of 160 wide chars, each with a ScopeMask of Process 0x1, File 0x2, Handle 0x4, Registry 0x8 (ALL 0xF). A pattern is an image leaf name (steam.exe) or, when it contains a backslash, a case-insensitive actor-path suffix. Count = 0 clears the list.

Exclusions are deliberately evaluated after every critical gate, so an over-broad list can only reduce noise, never protection:

  • the handle gate only after the sensitive-process rights-stripping gate;
  • the registry gate only after the CI-trust gate;
  • the file gate only after the built-in denials and the autorun rule;
  • the process gate only after the fixed kernel command-line rules.

They also never bypass a confirmed-threat command-line rule. Because the hot-path gates resolve only the requestor image leaf name without materializing an actor path, a path-suffix pattern applies to the Process scope only; on the File, Handle, and Registry scopes it simply does not match. Author exclusions as leaf names unless only the process gate is being targeted.

The rule set is authored in the app as Config\BehaviorRules.json and parsed by DriverBehaviorRuleCatalog. A missing file is a valid "no rules" state, while a malformed file is reported and skipped instead of aborting the attach sequence.

Protection Modules​

AreaKernel behaviour
FileSystem-binary masquerade interception in PreCreate: a write-open that creates or replaces a system binary name (svchost.exe, rundll32.exe, regsvr32.exe, dllhost.exe, lsass.exe, csrss.exe, smss.exe, winlogon.exe, wininit.exe, services.exe, spoolsv.exe, taskhostw.exe, conhost.exe, dwm.exe, dllhst3g.exe) under AppData, Downloads, Desktop (including OneDrive-redirected desktops), or ProgramData is denied synchronously with STATUS_ACCESS_DENIED — no event, no user-mode round trip. CI-trusted processes and the registered client are exempt.
RansomwareRansomwareMonitor counts destructive opens in two dimensions. User data: XDOWS_RANSOM_FILE_THRESHOLD (10) document/media writes in XDOWS_RANSOM_WINDOW_MS (3000). System directories: destructive opens by script hosts (cmd, powershell, pwsh, wscript, cscript, mshta, rundll32, regsvr32) under any \Windows\ subtree cross XDOWS_RANSOM_SYS_FILE_THRESHOLD (50) within XDOWS_RANSOM_SYS_WINDOW_MS (3000) in a separate slot table, after which further opens are denied with STATUS_VIRUS_INFECTED. The CI-trust gate is deliberately not applied to the system dimension, because the interpreter binary is always legitimately signed — the script-host identity is the discriminator.
RegistryA kernel registry callback holds create, set-value, delete-value, delete-key, rename, restore, replace, and unload operations for a user decision. The rule-path budget is XDOWS_SECURITY_MAX_REGISTRY_RULES (32); the app deploys 26 rules under Recommended. On a confirmed Block for a critical persistence key the gate honours the KillActor sentinel (0x4B494C4C) and counter-kills the actor through the shared injection guard rails.
InjectionObRegisterCallbacks strips dangerous handle rights and always reports ProcessInjection / ThreadInjection events; the counter-kill primitive is shared with the behavior and registry gates.
Self-protectionRestricts dangerous handles and injection prerequisites against the protected process, and validates controlled shutdown through the one-time token.
BootThe main driver protects EFI/BCD writes; BootFilter protects raw system-disk boot-region writes and waits for a user-mode decision before completion.

Communication Robustness​

IOCTL_XDOWS_SECURITY_GET_NEXT_EVENTS drains up to 16 events in one call and never blocks; the client paces its own loop and reads only Count entries. The batch struct is kept under the 85 KB .NET LOH threshold so the app can pool its buffers. XDOWS_SECURITY_REGISTER_FLAG_ASYNC_REVIEW queues non-critical event types for display while the origin thread returns immediately with the default Allow decision — FileRename is excluded, because it runs in PreSetInformation, can fail the operation with STATUS_VIRUS_INFECTED, and must stay synchronous so user mode can still block ransomware-style renames.

Per-type sliding-window (1 s) rate limits throttle non-critical noise types (file create 200/s, file write 300/s, driver log 100/s). Throttled events are dropped silently and counted in DroppedByType. Critical types — process create, file rename, handle and thread operations, confirmed behavior, boot writes, and registry writes — are never throttled.

Build and Installation​

The driver projects are WDK .vcxproj projects and require Visual Studio C++ MSBuild with WDK integration; the dotnet CLI alone cannot build them. See Build and Installation for the toolchain, the build command, and the installation flow.

License​

This project uses the MIT license; see LICENSE for details.