Systems project / C17 + Windows kernel

Observe the registry.
Make the decision.

A standalone WDM driver that watches a dedicated registry subtree, rejects selected operations, and explains its decisions through a secure command-line controller.

Educational, scoped, and monitoring-only by default.
Load the native driver only in a disposable Windows test VM.

REGISTRY / PRE-OPERATIONDESIGN VIEW

Watched lab root

HKLM\SOFTWARE\RegDriverTest
  1. 01 / An application makes a requestWindows registry API
    RegSetValueEx
  2. 02 / Configuration Manager calls usInspect the operation
    PreSetValue
  3. 03 / Match scope and snapshot policyAllow or deny this attempt
    NTSTATUS
  4. 04 / Record bounded metadataReport through the controller
    IOCTL
Architecture sketch, not a captured execution. An allow decision is not proof the operation ultimately succeeded.
Handled notifications
10pre-operation classes
Independent deny flags
7one scoped policy
Event ring capacity
128oldest overwritten when full
Records per read
16bounded buffered IOCTL

01 / Why this exists

From a registry request
to an explainable policy decision.

A practical exercise in callbacks, ownership, synchronization, and the boundary between user mode and kernel mode.

The Windows registry stores configuration used by applications and the operating system. Programs can query values, enumerate keys, write settings, and delete or rename entries.

This project places a callback in that flow. It resolves the requested key, checks whether it falls inside the selected lab subtree, and applies an operation-specific deny mask. Registry applications do not need to open the driver's device or change how they call Windows.

The useful outcome is not a claim of complete protection. It is a readable implementation of where a policy decision happens, how it reaches the caller, and what can safely be reported afterward.

02 / Policy desk

Change the rule.
Understand the consequence.

Browser-only explanation

Use fixed examples to explore the documented deny bits. This is not a live driver, not a native trace, and not a complete Windows registry emulator. It never opens a device, executes a command, or touches your registry.

Deny policy for the Demo subtree

Scope: HKLM\SOFTWARE\RegDriverTest\Demo

An application attempts to set a value on the selected Demo key.

Key / source
HKLM\SOFTWARE\RegDriverTest\Demo
Requested operation
RegNtPreSetValueKey
Scope rule
Inside the watched subtree
Predicted filter decisionAllow this attemptSTATUS_SUCCESS

No deny flags are selected. Windows and other filters still decide whether the operation completes.

Equivalent controller command

.\RegDriverCtl.exe policy 'HKLM\SOFTWARE\RegDriverTest\Demo' 'none' on

For an elevated terminal in your configured test VM. A policy command replaces all settings; it does not merge them. Copying does not execute it.

What this model leaves out: real callback timing, Unicode namespace resolution, Windows permissions, driver-loading rules, other filters, and queue contention. The C implementation and VM results are authoritative.

03 / Architecture

Two paths.
One shared contract.

Registry activity drives the callback. The controller configures it over a separate, secured IOCTL path.

DATA PATH

Observe → decide → report

  1. Registry applicationMakes normal Windows registry calls.
  2. Configuration ManagerInvokes RegDriverCallback with typed notification information.
  3. Common reporting helperRegDrvReportIfWatched resolves names, snapshots policy, decides, records, and releases resources.
  4. Return the filter decisionA denial returns STATUS_ACCESS_DENIED; an allow lets normal processing continue.
CONTROL PATH

Configure → inspect → recover

  1. Elevated C controllerOpens \\.\RegDriver. The device defaults to administrators and SYSTEM.
  2. Buffered IOCTLFixed-width, versioned structures; no kernel pointers in the wire contract.
  3. Kernel dispatchRegDrvDispatch validates lengths, flags, and scope. The I/O manager enforces handle access bits.
  4. Shared state and repliesReplace policy, read counters, or consume events. reset restores monitoring-only policy.
KERNEL / C

RegDriver.c

The original teaching-oriented driver, extended in place. One callback, readable operation cases, common name helpers, controlled state, and ordered cleanup.

Inspect the driver
USER MODE / C

RegDriverCtl

A command-line operator interface, not a service. It can change policy and print JSON events. The driver continues running after the controller exits.

Inspect the controller
VERIFICATION / C

RegDriverTests

Checks shared policy logic and controller helpers locally. Separate, explicit VM modes exercise the real device and registry operations.

Inspect the tests

04 / Inside the implementation

Small boundaries.
Important engineering decisions.

01 / NAMES

Counted strings, not substring guesses.

Kernel names are counted UNICODE_STRING values. The driver resolves objects, joins relative create/open names, and requires an exact-key or subkey boundary. Rename checks also consider destinations and relevant lab ancestors.

02 / CONCURRENCY

A coherent policy snapshot.

A fast mutex protects shared state. Each callback takes one policy and generation snapshot, then performs matching outside the lock. An in-flight request can finish under an older generation.

03 / OWNERSHIP

Acquire, use, release.

Names acquired from Configuration Manager are released on the helper's exit paths. Temporary joined names have explicit ownership. The callback does not read registry value-data buffers for logging.

04 / TELEMETRY

Bounded, useful, deliberately lossy.

The ring stores 128 records, each 824 bytes. Reads consume up to 16. Records include key/name text, PID/TID, time, decision, sequence, and policy generation—not payloads or kernel pointers.

103 KiB

Event-ring storage only, excluding other state and temporary names. Not a total-memory benchmark.

BEST-EFFORT

Oldest records are overwritten on overflow. Readers share one destructive queue. Sequence and drop counts expose loss, not replay.

PRE-OPERATION

An event reports this filter's decision. It does not claim the final Windows operation succeeded.

05 / Run it yourself

Build on the host.
Experiment in a test VM.

The website needs no driver. The native project needs the Windows development tools and a deliberate test-signing setup.

  1. 01

    Build the C solution and run local checks

    Use Visual Studio 2026, MSVC v145, a compatible SDK/WDK, and the kernel-driver toolset. All three native projects compile as C17. Run from the repository root in Developer PowerShell.

    HOST / NO DRIVER LOAD
    msbuild .\RegDriver\RegDriver.slnx /m /p:Configuration=Debug /p:Platform=x64
    .\artifacts\x64\Debug\RegDriverTests.exe
  2. 02

    Prepare a disposable Windows VM

    Use a matching architecture and Windows 10 version 2004 or later, subject to your WDK's target requirements. Take a snapshot, configure test signing and certificate trust, and stage the freshly built binaries. Keep the matching PDB on the host for WinDbg.

    Do not change host boot/security settings or load the driver on a daily-use machine. This site does not supply a trusted production driver binary.

    Full signing, service, and WinDbg setup
  3. 03

    Observe, deny a write, then reset

    After the driver is loaded, use an elevated VM terminal in the staging directory. Use a disposable Demo key containing no valuable data. These are native commands to review and run yourself—not actions executed by this page.

    VM ONLY / DRIVER ALREADY LOADED
    .\RegDriverCtl.exe policy 'HKLM\SOFTWARE\RegDriverTest\Demo' none on
    reg.exe add 'HKLM\SOFTWARE\RegDriverTest\Demo' /v Example /t REG_DWORD /d 1 /f /reg:64
    .\RegDriverCtl.exe policy 'HKLM\SOFTWARE\RegDriverTest\Demo' set on
    reg.exe add 'HKLM\SOFTWARE\RegDriverTest\Demo' /v Example /t REG_DWORD /d 2 /f /reg:64
    .\RegDriverCtl.exe events
    .\RegDriverCtl.exe reset

    Expected: the second value write is denied. Confirm its actual result and inspect events. Reset changes policy, not counters or queued records. Close controller handles before unloading; delete only your disposable lab keys.

06 / Evidence, not assumptions

Different checks answer
different questions.

LOCAL CHECKS

Build and shared logic

The native project has been built locally in x64 Debug and Release. Local checks cover ABI sizes, path boundaries, independent masks, controller parsing, and JSON escaping.

A build and unit run do not prove kernel runtime enforcement.

REQUIRES A TEST VM

Actual driver behavior

--integration-test-vm exercises policy denial, existing handles, relative paths, rename checks, malformed IOCTLs, and queue behavior.

--expect-access-denied checks the control device from a non-elevated terminal.

These runtime results are not demonstrated or certified by this website.

SEPARATE WEBSITE CHECKS

Presentation and interaction

The browser walkthrough is tested against the header's operation IDs and deny bits. Site checks cover assets and links; browser smoke tests cover controls, keyboard use, mobile layouts, and no-JavaScript reading.

Website checks are not native-driver tests.

07 / Honest limits

A learning project.
Not a security product.

The strongest part of a systems project is knowing what it does not guarantee.

  • Not complete registry mediation. Metadata/security queries, hive and transaction operations, aliases, and redirected views are not comprehensively covered.
  • Resolution can fail open. Failure before a decision is counted but leaves the operation allowed. An already-selected denial is retained if reporting later fails.
  • No durable audit or policy store. State is in memory, events can be lost, and a reload starts fresh. An administrator can change policy or unload the driver.
  • No performance or certification claim. ARM64 runtime, concurrency stress, fault injection, and production hardening require separate validation.

08 / Go deeper

Follow the design
all the way to the C.

The implementation keeps its original function names, detailed commentary, and nine spaced learning sections in one active driver file.