WINDOWS PROCESS MONITORING DRIVER BASELINE

Project purpose:
A legitimate, security-oriented Windows kernel driver baseline for process and thread monitoring in an authorized environment.
This project intentionally does not hide or remove processes. It is meant to provide process telemetry and alerting for defensive monitoring.

--- FILE 1: src/process_monitor_driver.c ---
#include <ntddk.h>
#include <ntstrsafe.h>

#include "process_monitor_driver.h"

PROCESS_MONITOR_CONFIG g_ProcessMonitorConfig = {
    .Enabled = PROCESS_MONITOR_ENABLED_DEFAULT,
    .LogLevel = PROCESS_MONITOR_LOG_LEVEL_DEFAULT,
    .AllowList = { 0 },
    .BlockList = { 0 }
};

static
BOOLEAN IsProcessAllowed(_In_opt_ PCUNICODE_STRING ImageName)
{
    UNREFERENCED_PARAMETER(ImageName);

    if (g_ProcessMonitorConfig.AllowList.Length == 0)
    {
        return TRUE;
    }

    return TRUE;
}

static
BOOLEAN IsProcessBlocked(_In_opt_ PCUNICODE_STRING ImageName)
{
    UNREFERENCED_PARAMETER(ImageName);

    if (g_ProcessMonitorConfig.BlockList.Length == 0)
    {
        return FALSE;
    }

    return FALSE;
}

NTSTATUS ReadProcessMonitorConfig(_In_ PUNICODE_STRING RegistryPath)
{
    NTSTATUS status = STATUS_SUCCESS;
    RTL_QUERY_REGISTRY_TABLE queryTable[4] = { 0 };
    UNICODE_STRING enabledName = RTL_CONSTANT_STRING(L"Enabled");
    UNICODE_STRING logLevelName = RTL_CONSTANT_STRING(L"LogLevel");
    UNICODE_STRING allowListName = RTL_CONSTANT_STRING(L"AllowList");
    UNICODE_STRING blockListName = RTL_CONSTANT_STRING(L"BlockList");

    g_ProcessMonitorConfig.Enabled = PROCESS_MONITOR_ENABLED_DEFAULT;
    g_ProcessMonitorConfig.LogLevel = PROCESS_MONITOR_LOG_LEVEL_DEFAULT;

    queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
    queryTable[0].Name = enabledName.Buffer;
    queryTable[0].EntryContext = &g_ProcessMonitorConfig.Enabled;
    queryTable[0].DefaultType = REG_DWORD;
    queryTable[0].DefaultData = &g_ProcessMonitorConfig.Enabled;
    queryTable[0].DefaultLength = sizeof(g_ProcessMonitorConfig.Enabled);

    queryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
    queryTable[1].Name = logLevelName.Buffer;
    queryTable[1].EntryContext = &g_ProcessMonitorConfig.LogLevel;
    queryTable[1].DefaultType = REG_DWORD;
    queryTable[1].DefaultData = &g_ProcessMonitorConfig.LogLevel;
    queryTable[1].DefaultLength = sizeof(g_ProcessMonitorConfig.LogLevel);

    queryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
    queryTable[2].Name = allowListName.Buffer;
    queryTable[2].EntryContext = &g_ProcessMonitorConfig.AllowList;
    queryTable[2].DefaultType = REG_SZ;
    queryTable[2].DefaultData = L"";
    queryTable[2].DefaultLength = sizeof(WCHAR);

    queryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
    queryTable[3].Name = blockListName.Buffer;
    queryTable[3].EntryContext = &g_ProcessMonitorConfig.BlockList;
    queryTable[3].DefaultType = REG_SZ;
    queryTable[3].DefaultData = L"";
    queryTable[3].DefaultLength = sizeof(WCHAR);

    status = RtlQueryRegistryValues(
        RTL_REGISTRY_SERVICES,
        PROCESS_MONITOR_SERVICE_NAME,
        queryTable,
        NULL,
        RegistryPath);

    if (!NT_SUCCESS(status))
    {
        DbgPrintEx(
            DPFLTR_IHVDRIVER_ID,
            DPFLTR_ERROR_LEVEL,
            "[ProcessMonitor] Failed to read registry configuration: 0x%08X\n",
            status);
        return status;
    }

    DbgPrintEx(
        DPFLTR_IHVDRIVER_ID,
        DPFLTR_ERROR_LEVEL,
        "[ProcessMonitor] Config loaded: Enabled=%lu LogLevel=%lu\n",
        g_ProcessMonitorConfig.Enabled,
        g_ProcessMonitorConfig.LogLevel);

    return STATUS_SUCCESS;
}

VOID NTAPI ProcessNotifyRoutineEx(
    _Inout_ PEPROCESS Process,
    _In_ HANDLE ProcessId,
    _Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo
)
{
    UNREFERENCED_PARAMETER(Process);

    if (!g_ProcessMonitorConfig.Enabled)
    {
        return;
    }

    if (CreateInfo == NULL)
    {
        DbgPrintEx(
            DPFLTR_IHVDRIVER_ID,
            DPFLTR_ERROR_LEVEL,
            "[ProcessMonitor] Process created: PID=%llu (CreateInfo unavailable)\n",
            HandleToULong(ProcessId));
        return;
    }

    if (IsProcessBlocked(CreateInfo->ImageFileName))
    {
        DbgPrintEx(
            DPFLTR_IHVDRIVER_ID,
            DPFLTR_ERROR_LEVEL,
            "[ProcessMonitor] Blocked process: PID=%llu Image=%ws\n",
            HandleToULong(ProcessId),
            CreateInfo->ImageFileName ? CreateInfo->ImageFileName->Buffer : L"<n/a>");
        return;
    }

    if (!IsProcessAllowed(CreateInfo->ImageFileName))
    {
        DbgPrintEx(
            DPFLTR_IHVDRIVER_ID,
            DPFLTR_ERROR_LEVEL,
            "[ProcessMonitor] Disallowed process: PID=%llu Image=%ws\n",
            HandleToULong(ProcessId),
            CreateInfo->ImageFileName ? CreateInfo->ImageFileName->Buffer : L"<n/a>");
    }

    DbgPrintEx(
        DPFLTR_IHVDRIVER_ID,
        DPFLTR_ERROR_LEVEL,
        "[ProcessMonitor] Process created: PID=%llu Image=%ws CommandLine=%ws\n",
        HandleToULong(ProcessId),
        CreateInfo->ImageFileName ? CreateInfo->ImageFileName->Buffer : L"<n/a>",
        CreateInfo->CommandLine ? CreateInfo->CommandLine->Buffer : L"<n/a>");
}

VOID NTAPI ThreadNotifyRoutine(
    _In_ HANDLE ProcessId,
    _In_ HANDLE ThreadId,
    _In_ BOOLEAN Create
)
{
    if (!g_ProcessMonitorConfig.Enabled)
    {
        return;
    }

    DbgPrintEx(
        DPFLTR_IHVDRIVER_ID,
        DPFLTR_ERROR_LEVEL,
        "[ProcessMonitor] Thread %s: PID=%llu TID=%llu\n",
        Create ? "created" : "exited",
        HandleToULong(ProcessId),
        HandleToULong(ThreadId));
}

NTSTATUS DriverEntry(
    _In_ PDRIVER_OBJECT DriverObject,
    _In_ PUNICODE_STRING RegistryPath
)
{
    UNREFERENCED_PARAMETER(RegistryPath);

    NTSTATUS status = STATUS_SUCCESS;

    DriverObject->DriverUnload = DriverUnload;

    status = ReadProcessMonitorConfig(RegistryPath);
    if (!NT_SUCCESS(status))
    {
        DbgPrintEx(
            DPFLTR_IHVDRIVER_ID,
            DPFLTR_ERROR_LEVEL,
            "[ProcessMonitor] Registry config initialization failed: 0x%08X\n",
            status);
    }

    status = PsSetCreateProcessNotifyRoutineEx(ProcessNotifyRoutineEx, FALSE);
    if (!NT_SUCCESS(status))
    {
        DbgPrintEx(
            DPFLTR_IHVDRIVER_ID,
            DPFLTR_ERROR_LEVEL,
            "[ProcessMonitor] PsSetCreateProcessNotifyRoutineEx failed: 0x%08X\n",
            status);
        return status;
    }

    status = PsSetCreateThreadNotifyRoutine(ThreadNotifyRoutine);
    if (!NT_SUCCESS(status))
    {
        DbgPrintEx(
            DPFLTR_IHVDRIVER_ID,
            DPFLTR_ERROR_LEVEL,
            "[ProcessMonitor] PsSetCreateThreadNotifyRoutine failed: 0x%08X\n",
            status);
        PsSetCreateProcessNotifyRoutineEx(ProcessNotifyRoutineEx, TRUE);
        return status;
    }

    DbgPrintEx(
        DPFLTR_IHVDRIVER_ID,
        DPFLTR_ERROR_LEVEL,
        "[ProcessMonitor] Driver loaded successfully.\n");

    return STATUS_SUCCESS;
}

VOID DriverUnload(_In_ PDRIVER_OBJECT DriverObject)
{
    UNREFERENCED_PARAMETER(DriverObject);

    PsSetCreateProcessNotifyRoutineEx(ProcessNotifyRoutineEx, TRUE);
    PsRemoveCreateThreadNotifyRoutine(ThreadNotifyRoutine);

    DbgPrintEx(
        DPFLTR_IHVDRIVER_ID,
        DPFLTR_ERROR_LEVEL,
        "[ProcessMonitor] Driver unloaded.\n");
}

--- FILE 2: src/process_monitor_driver.h ---
#pragma once

#define PROCESS_MONITOR_SERVICE_NAME L"ProcessMonitor"
#define PROCESS_MONITOR_REGISTRY_PATH L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\ProcessMonitor"
#define PROCESS_MONITOR_LOG_LEVEL_DEFAULT 3
#define PROCESS_MONITOR_ENABLED_DEFAULT 1

#define PROCESS_MONITOR_ALLOWLIST_VALUE L"AllowList"
#define PROCESS_MONITOR_BLOCKLIST_VALUE L"BlockList"
#define PROCESS_MONITOR_ENABLED_VALUE L"Enabled"
#define PROCESS_MONITOR_LOGLEVEL_VALUE L"LogLevel"

typedef struct _PROCESS_MONITOR_CONFIG {
    ULONG Enabled;
    ULONG LogLevel;
    UNICODE_STRING AllowList;
    UNICODE_STRING BlockList;
} PROCESS_MONITOR_CONFIG, *PPROCESS_MONITOR_CONFIG;

extern PROCESS_MONITOR_CONFIG g_ProcessMonitorConfig;

NTSTATUS ReadProcessMonitorConfig(_In_ PUNICODE_STRING RegistryPath);
VOID DriverUnload(_In_ PDRIVER_OBJECT DriverObject);

VOID NTAPI ProcessNotifyRoutineEx(
    _Inout_ PEPROCESS Process,
    _In_ HANDLE ProcessId,
    _Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo
);

VOID NTAPI ThreadNotifyRoutine(
    _In_ HANDLE ProcessId,
    _In_ HANDLE ThreadId,
    _In_ BOOLEAN Create
);

--- FILE 3: config/process_monitor_config.json ---
{
  "Enabled": true,
  "LogLevel": 3,
  "AllowList": [
    "powershell.exe",
    "cmd.exe",
    "explorer.exe",
    "svchost.exe"
  ],
  "BlockList": [
    "rundll32.exe",
    "mshta.exe",
    "regsvr32.exe"
  ],
  "Telemetry": {
    "Mode": "jsonl",
    "Path": "C:/Logs/process_monitor_events.jsonl",
    "FlushIntervalSeconds": 5
  }
}

--- FILE 4: driver/ProcessMonitor.inf ---
;-------------------------------------------------------------------------------
; ProcessMonitor.inf
;-------------------------------------------------------------------------------

[Version]
Signature = "$WINDOWS NT$"
Class = SecurityDevices
ClassGuid = {d1d3f6a6-2e44-4d88-bf1e-7b6af1577d5a}
Provider = %ManufacturerName%
DriverVer = 08/13/2026,1.0.0.0
CatalogFile = ProcessMonitor.cat

[DestinationDirs]
DefaultDestDir = 12

[SourceDisksNames]
1 = %DiskName%,,,

[SourceDisksFiles]
ProcessMonitor.sys = 1,,

[Manufacturer]
%ManufacturerName% = Standard,NTamd64

[Standard.NTamd64]
%ProcessMonitor.DeviceDesc% = ProcessMonitor_Device, Root\ProcessMonitor

[ProcessMonitor_Device.NT]
CopyFiles = @ProcessMonitor.sys

[ProcessMonitor_Device.NT.Services]
AddService = ProcessMonitor,0x00000002,ProcessMonitor_Service_Install

[ProcessMonitor_Service_Install]
DisplayName = %ProcessMonitor.DeviceDesc%
ServiceBinary = %12%\ProcessMonitor.sys
ServiceDll = %12%\ProcessMonitor.sys
ServiceDependencies = 
StartType = 0 ; SERVICE_BOOT_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
LoadOrderGroup = Extended Base

[Strings]
ManufacturerName = "Contoso Security"
DiskName = "Process Monitor Installation Media"
ProcessMonitor.DeviceDesc = "Process Monitor Driver"

--- FILE 5: scripts/install_driver.ps1 ---
$ErrorActionPreference = 'Stop'

$driverPath = Join-Path $PSScriptRoot '..\driver\ProcessMonitor.sys'
$infPath = Join-Path $PSScriptRoot '..\driver\ProcessMonitor.inf'

if (-not (Test-Path $driverPath)) {
    throw "Driver binary not found: $driverPath. Build the driver first."
}

if (-not (Test-Path $infPath)) {
    throw "INF file not found: $infPath"
}

pnputil /add-driver $infPath /install | Out-Null

$serviceName = 'ProcessMonitor'

if (-not (Get-Service -Name $serviceName -ErrorAction SilentlyContinue)) {
    New-Service -Name $serviceName -BinaryPathName $driverPath -DisplayName 'Process Monitor Driver' -StartupType Manual | Out-Null
}

Start-Service -Name $serviceName

Write-Host 'ProcessMonitor driver installed and started.'

--- FILE 6: scripts/uninstall_driver.ps1 ---
$ErrorActionPreference = 'Stop'

$serviceName = 'ProcessMonitor'

if (Get-Service -Name $serviceName -ErrorAction SilentlyContinue) {
    Stop-Service -Name $serviceName -ErrorAction SilentlyContinue
    sc.exe delete $serviceName | Out-Null
}

$infPath = Join-Path $PSScriptRoot '..\driver\ProcessMonitor.inf'
if (Test-Path $infPath) {
    pnputil /delete-driver ProcessMonitor.inf /uninstall /force | Out-Null
}

Write-Host 'ProcessMonitor driver uninstalled.'

--- FILE 7: service/telemetry_service.py ---
import json
import time
from pathlib import Path

CONFIG_PATH = Path(__file__).resolve().parent.parent / 'config' / 'process_monitor_config.json'


def load_config():
    with CONFIG_PATH.open('r', encoding='utf-8') as handle:
        return json.load(handle)


def main():
    config = load_config()
    print('Process monitor telemetry relay started.')
    print(json.dumps(config, indent=2))

    while True:
        time.sleep(5)
        print(f"[relay] Still monitoring. logLevel={config.get('LogLevel', 3)}")


if __name__ == '__main__':
    main()

--- FILE 8: README.md ---
# Windows Process Monitoring Driver Project

This project is a legitimate Windows security-monitoring driver baseline for process telemetry and defensive analysis. It is designed to observe process creation and thread activity in a transparent, authorized environment.

## Included components

- Kernel driver for process and thread monitoring
- Registry-backed configuration model
- Driver install / uninstall scripts
- User-mode telemetry relay prototype
- Example configuration file

## Safety and scope

This project intentionally does not hide, remove, or obscure processes. It is meant for:

- internal monitoring
- process telemetry
- allowlist / blocklist experimentation
- endpoint security research in authorized environments

## Project layout

- `src/process_monitor_driver.c` — kernel driver implementation
- `src/process_monitor_driver.h` — shared definitions and config structure
- `driver/ProcessMonitor.inf` — INF installer template
- `config/process_monitor_config.json` — user-mode config sample
- `scripts/install_driver.ps1` — installs and starts the driver service
- `scripts/uninstall_driver.ps1` — stops and removes the service
- `service/telemetry_service.py` — example user-mode telemetry relay

## Recommended build workflow

1. Install the Windows Driver Kit (WDK)
2. Open the driver project in Visual Studio with the WDK toolchain
3. Build the x64 driver package
4. Sign the driver with an appropriate certificate
5. Install in a lab VM or authorized Windows environment

## Driver features in this baseline

- process creation callback via `PsSetCreateProcessNotifyRoutineEx`
- thread creation/exit callback via `PsSetCreateThreadNotifyRoutine`
- registry-based configuration for enabled state and logging level
- clean unload routine
- user-mode telemetry relay concept for secure event collection

## Deployment notes

- Test only on a lab VM or a machine you own and are authorized to monitor
- Use a proper code-signing workflow before deployment outside a lab
- Ensure the environment meets Windows driver security requirements

## Next improvements

- allowlist and blocklist enforcement
- parent-process correlation
- abuse detection heuristics
- ETW or event-log integration
- signed installer package
- admin and security policy controls

This file is ready to paste into ChatGPT or another model as a single export bundle.
