A full-stack Windows kernel security laboratory for studying process hiding, driver callbacks, SSDT monitoring, LSASS protection, registry persistence, WMI reconnaissance, HVCI bypass simulation, and Bring-Your-Own-Vulnerable-Driver (BYOVD) attack patterns.
Built with Python/PySide6 (desktop UI), C (kernel drivers), C++ (driver loader), and PowerShell (VM agent). All components communicate over HTTP between a host analysis machine and a Windows 10 VMware guest.
"You can't defend what you don't understand."
This project exists to close the gap between offensive technique and defensive
visibility. Every attack scenario has a corresponding detection path β the attacker
hides a process via DKOM, the defender cross-checks the EPROCESS linked list every 3
seconds and flags the anomaly. The attacker writes to a registry Run key, the defender's
CmRegisterCallback fires and sets a PERSISTENCE flag.
The lab is designed as an observable, measurable, replayable environment. Every
single action β launching a driver, hiding a process, querying WMI, even a failed
attempt β is logged with an explicit source (defender / attacker / system) and
severity level. The activity log is the single source of truth.
No mock data. No simulation. The kernel drivers are real. The IOCTLs are real. The
DKOM unlinking actually removes the EPROCESS from ActiveProcessLinks. The defender
actually calls ZwQuerySystemInformation from a kernel DPC and diffs the results.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β HOST (Analysis Machine) β
β β
β ββββββββββββ ββββββββββββ ββββββββββββββ βββββββββββββββ β
β β Dashboard β β File Mgr β β Screenshotsβ β Terminal β β
β β CPU/GPU/ β β Dual-pane β β VM capture β β CMD + PS β β
β β Memory β β Host β VM β β + gallery β β remote β β
β βββββββ¬ββββββ βββββββ¬ββββββ ββββββββ¬βββββββ ββββββββ¬βββββββ β
β β β β β β
β βββββββ΄βββββββββββββββ΄βββββββββββββββ΄βββββββββββββββββ΄βββββββ β
β β SECURITY TAB β β
β β Drivers Β· Autoboot Β· Attacker Β· Detection Β· Device Guard β β
β β Defender Stats Β· Attacker Stats Β· Process Table Β· Log β β
β ββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββ β
β β HTTP :4444 β
β ββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββ β
β β Python Backend (6 providers, 27+ slots, 18+ signals) β β
β β StatsProvider Β· SecurityProvider Β· FileModel Β· etc. β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
HTTP :4444
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WINDOWS 10 VMware Guest β
β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββββββββββ β
β β vm_agent.ps1 β β defender.sys β β attacker.exe β β
β β PowerShell β β ObCallbacks β β Persist Β· LSASS dump β β
β β HTTP server β β CmCallbacks β β Beacon Β· WMI Β· HVCI β β
β β 19 endpoints β β PsCallbacks β β spoof Β· BYOVD bypass β β
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ ββββββββββββ¬ββββββββββββ β
β β β β β
β ββββββββ΄ββββββββββββββββββ΄βββββββββββββββββββββββ΄ββββββββββββ β
β β Kernel Space β β
β β hider.sys (DKOM) Β· filehider.sys (minifilter) β β
β β sysinfo.sys (HW info) Β· kvc.sys (BYOVD loader) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
laboratory_analyzer/
βββ sysmon/ # Main monitoring application
β βββ app/
β β βββ main.py # PySide6 entry point
β β βββ backend.py # 1582 lines β all providers & logic
β β βββ ui/ # 7 QML files
β β βββ main.qml # 5-tab layout
β β βββ Dashboard.qml # Gauges, cores, top processes
β β βββ Security.qml # Drivers, attacker, detection, log
β β βββ FileManager.qml # Dual-pane file browser
β β βββ Terminal.qml # CMD + PowerShell remote
β β βββ ScreenshotsView.qml
β β βββ CircularGauge.qml # Canvas-based gauge widget
β βββ agent/
β β βββ vm_agent_new.ps1 # PowerShell HTTP agent (438 lines)
β βββ lab.py # Unified CLI (845 lines)
β βββ tests/ # 15 test scripts
β βββ json/ # Test data & payload samples
β βββ screenshots/ # Captured VM screenshots
β
βββ drivers_lab/ # Kernel drivers (C)
β βββ 11_sysinfo/ # sysinfo.sys β IOCTL-based HW info
β βββ 12_attacker/ # attacker.exe + supporting tools
β β βββ attacker_exe/ # C source for attacker payload
β β βββ hider/ # hider.sys β DKOM process hiding
β β βββ filehider/ # filehider.sys β minifilter file hide
β β βββ hvci_hook/ # hvci_hook.dll β HVCI spoof injection
β βββ 13_defender/ # defender.sys β kernel security monitor
β βββ 14_test_payload/ # test_payload.sys β unsigned test driver
β
βββ rtcore/ # Driver loader / BYOVD utility (C++)
βββ driver_loader_cli_kvc/ # DSE bypass loader
Real-time system vitals from the VM β CPU/GPU/Memory gauges, per-core utilization bars, kernel driver status, and top processes by CPU.
ββββββββββββ ββββββββββββ ββββββββββββ
β CPU 45% β β GPU 12% β β MEM 54% β
β β gauge β β β gauge β β β gauge β
ββββββββββββ ββββββββββββ ββββββββββββ
ββββββββββββββββββββββββββββββββββββββββ
β Core 0: ββββββββββ 42% β
β Core 1: ββββββββββ 28% β
β Core 2: ββββββββββ 55% β
β Core 3: ββββββββββ 18% β
ββββββββββββββββββββββββββββββββββββββββ
Dual-pane browser β left pane shows the remote VM filesystem, right pane shows the host. Upload files from host to VM, download from VM to host, with progress tracking.
One-click VM desktop capture. Screenshots are saved locally and displayed in a scrollable gallery.
Remote CMD and PowerShell interface. Commands are wrapped to track the current working
directory (CWD), which is displayed in the UI. Output is syntax-colored: green for
success, red for errors.
The Security tab is the heart of the lab. It contains:
- Drivers panel: Start/stop
defender.sysandhider.syswith one click - Autoboot: Configure all 4 components (defender, hider, filehider, attacker) to auto-start at system boot via registry + scheduled tasks
- Attacker panel: Launch/Kill attacker.exe; DKOM hide/unhide; file hide/unhide; 8 attack modes (persist, LSASS dump, beacon, WMI recon, HVCI spoof, defender spoof, all attacks, HVCI bypass)
- Detection pills: Real-time status for defender ON/OFF, SSDT HOOKED/CLEAN, hidden process count, callback count, PERSIST detected, LSASS access, WMI activity, registry spoof
- Device Guard / VBS status: VBS state, running services, VM isolation
- Defender stats: Uptime, scan count, DKOM/LSASS/PERSIST/WMI/regspoof/stealth/ kwrite/bypass detection counters
- Tracked process table: Every process the defender monitors, with status badges (DKOM_HIDDEN, LSASS DUMP, PERSIST, WMI RECON, etc.) and per-row KILL button
- Activity log: Filterable by source (ALL/DEFENDER/ATTACKER/SYSTEM) and level (ALL/DETECT/WARN/ERROR/OK), auto-scrolling, color-coded
The host UI runs on Qt's main thread, but all HTTP calls to the VM are blocking. A custom signal bridge ensures background threads can safely update the GUI:
class _Bridge(QObject):
_sig = Signal(object)
def __init__(self):
super().__init__()
self._sig.connect(self._run) # AutoConnection β QueuedConnection
def _run(self, fn):
fn()
def post(self, fn):
self._sig.emit(fn)Background threads call _bridge.post(lambda: self.label.setText("done")) and Qt
delivers it on the main event loop via QueuedConnection.
The defender driver tracks every process by PID. Every 3 seconds a kernel DPC
cross-checks the EPROCESS linked list via ZwQuerySystemInformation. If a tracked
PID is missing from the system list but the driver's internal record still shows it as
alive β DKOM_HIDDEN.
# In SecurityProvider._on_refresh_result()
if new_hidden > self._prev_hidden:
delta = new_hidden - self._prev_hidden
self._stat_dkom_events += delta
hidden_names = [p["name"] for p in new_procs if p["status"] == "DKOM_HIDDEN"]
self._log_add(
f"DKOM HIDDEN detected: {', '.join(hidden_names)}",
"detect", "defender")The hider.sys driver unlinks an EPROCESS from the kernel's doubly-linked list:
// hider.c β unlink EPROCESS from ActiveProcessLinks
PLIST_ENTRY target = (PLIST_ENTRY)((PUCHAR)eproc + ActiveProcessLinksOffset);
PLIST_ENTRY prev = target->Blink;
PLIST_ENTRY next = target->Flink;
prev->Flink = next; // bridge over the target
next->Blink = prev; // β the process vanishes from Task Manager
target->Flink = target; // isolate the entry
target->Blink = target;The Security tab polls 3 endpoints in parallel using ThreadPoolExecutor:
def _worker():
results = [None, None, None]
def fetch(idx, path, body=None):
try:
results[idx] = _vm_post(path, body, timeout=BG_TIMEOUT)
except Exception:
results[idx] = None
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as ex:
f1 = ex.submit(fetch, 0, "/shell", {"cmd": "sc query drv_defender"})
f2 = ex.submit(fetch, 1, "/shell", {"cmd": "sc query drv_hider"})
f3 = ex.submit(fetch, 2, "/security")
concurrent.futures.wait([f1, f2, f3])The agent runs inside the VM, exposing kernel driver IOCTLs over HTTP:
# P/Invoke to communicate with kernel drivers
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public class SysInfoDriver {
[DllImport("kernel32.dll")] public static extern IntPtr CreateFile(...);
[DllImport("kernel32.dll")] public static extern bool DeviceIoControl(...);
[DllImport("kernel32.dll")] public static extern bool CloseHandle(IntPtr);
}
"@
function Get-SysInfoDriverData {
$h = [SysInfoDriver]::CreateFile("\\.\SysInfo", ...)
$outBuf = [Marshal]::AllocHGlobal(40)
[SysInfoDriver]::DeviceIoControl($h, 0x222400, [IntPtr]::Zero, 0, $outBuf, 40, ...)
# Read struct: totalKB, availKB, cpus, uptimeSeconds
[Marshal]::FreeHGlobal($outBuf)
[SysInfoDriver]::CloseHandle($h)
}Every event carries a source field enabling filtered views:
def _log_add(self, msg, level="info", source="system", _emit=True):
ts = datetime.datetime.now().strftime("%H:%M:%S")
lines = [l.strip() for l in msg.splitlines() if l.strip()]
msg = " Β· ".join(lines) if lines else msg
entry = {"level": level, "time": ts, "text": msg, "source": source}
self._log.append(entry)
if len(self._log) > 500:
self._log = self._log[-500:]
if _emit:
self.logChanged.emit()| Attack Technique | Driver Mechanism | Detection Method | Flag |
|---|---|---|---|
| DKOM process hiding | hider.sys unlinks EPROCESS | ZwQuerySystemInformation cross-check (3s DPC) | DKOM_HIDDEN |
| File hiding | filehider.sys minifilter (ZwQueryDirectoryFile) | Independent directory enumeration | FILE_HIDDEN |
| LSASS credential dump | OpenProcess(VM_READ) on lsass.exe | ObRegisterCallbacks (OB_OPERATION_HANDLE_CREATE) | LSASS_ACCESS |
| Registry persistence | RegSetValue on Run key | CmRegisterCallback bait key monitoring | PERSISTENCE |
| WMI reconnaissance | COM/WMI queries via services.exe | ObRegisterCallbacks handle open on PID 4 | WMI_ACTIVITY |
| Registry spoof (Defender/HVCI) | Tampered DeviceGuard/Defender keys | CmRegisterCallback path filter | REG_SPOOF |
| Stealth folder hide | filehider.sys folder filter | Explorer directory listing cross-check | STEALTH_HIDE |
| Kernel write / BYOVD | DCMD_KERNEL_WRITE to ci.dll g_CiOptions | Defender.sys tracks requesting PID | KERNEL_WRITE |
| SSDT hooking | Inline hook on NtQuerySystemInformation | Kernel memory integrity check | SSDT_HOOKED |
| Endpoint | Method | Purpose |
|---|---|---|
/ping |
GET | Connectivity check, returns hostname + user |
/stats |
POST | CPU, GPU, memory, processes, uptime, driver info |
/security |
POST | Defender report: processes, hidden count, SSDT, callbacks |
/shell |
POST | Execute CMD command, return output |
/ps |
POST | Execute PowerShell, return output |
/drives |
POST | List logical drives |
/listdir |
POST | Directory listing with metadata |
/open |
POST | Open file/folder with default handler |
/upload |
POST | Base64 file upload from host to VM |
/download |
POST | Base64 file download from VM to host |
/screenshot |
POST | Capture VM desktop as PNG (base64) |
/hidepid |
POST | DKOM hide process by PID via hider.sys |
/unhidepid |
POST | Restore EPROCESS link |
/hidefile |
POST | Hide file from directory listing via filehider.sys |
/unhidefile |
POST | Remove file hiding rule |
/killpid |
POST | Force-kill process via IOCTL |
/procinfo |
POST | Detailed process info (path, modules, threads) |
/deviceguard |
POST | Win32_DeviceGuard WMI data |
/attacker/bypasshvci |
POST | DSE/KMCI bypass via KERNEL_WRITE |
The project includes 15 test scripts covering every layer:
# Quick headless tests (no VM, no PySide6)
python3 sysmon/tests/test_all_headless.py # 315 assertions β pure logic
python3 sysmon/tests/test_security_comprehensive.py # 400 assertions β Security tab
# Full GUI tests (Windows + PySide6 + VM required)
python sysmon/tests/test_all.py # 155+ assertions β full stack
python sysmon/tests/test_provider.py # Stats + Security provider
python sysmon/tests/test_full.py # All providers + actions
python sysmon/tests/test_terminal.py # Terminal CWD tracking
python sysmon/tests/test_autoboot.py # Autoboot setup/disable/verify
python sysmon/tests/test_log_source.py # Log source/level filtering
python sysmon/tests/test_bridge.py # Cross-thread bridge
python sysmon/tests/test_attack_defend.py # Full attack/defend scenario
# CLI test suite
python sysmon/lab.py test-ep # All endpoint diagnostics
python sysmon/lab.py test-attack # Attack/defend scenarioPrerequisites:
- Windows 10 VMware VM at
192.168.10.128with bridged networking - Python 3.10+ with PySide6 (
pip install PySide6) - Kernel drivers built with EWDK (Enterprise WDK)
- VM agent deployed to
C:\drivers_test\on the guest
Quick start:
# On the VM β start the agent
powershell -File C:\drivers_test\vm_agent_new.ps1
# On the host β launch the GUI
python C:\laboratory_analyzer\sysmon\app\main.py
# Or use the CLI
python C:\laboratory_analyzer\sysmon\lab.pyThis project is for educational and security research purposes only. The kernel drivers and BYOVD techniques demonstrated here should only be used in isolated lab environments with explicit authorization.
"Know the attack. See the defense. Understand the kernel."