PatchGuard, officially known as Kernel Patch Protection (KPP), is a Windows security feature introduced in Windows Vista x64 that protects critical kernel structures from unauthorized modification. When tampering is detected, PatchGuard triggers a bug check (BSOD) with code CRITICAL_STRUCTURE_CORRUPTION (0x109).
PatchGuard initializes during the late stages of kernel boot, specifically during Phase 1 initialization in ntoskrnl.exe. The initialization process:
- Context Allocation: A large structure (
PG_CONTEXT, typically 4KB-64KB) is allocated from the NonPagedPool with a specific pool tag. - Baseline Capture: Checksums are computed for all protected structures (SSDT, IDT, GDT, critical code sections, MSR values).
- Timer Setup: A kernel timer with an associated DPC (Deferred Procedure Call) is created with a randomized interval.
- Encryption: The entire PG context is XOR-encrypted with an obfuscation key before being stored in memory.
PatchGuard monitors the following kernel structures:
| Structure | Description | Check Method |
|---|---|---|
| SSDT | System Service Descriptor Table | Checksum of entire table |
| Shadow SSDT | Win32k system call table | Checksum (Win10+) |
| IDT | Interrupt Descriptor Table | Per-entry validation |
| GDT | Global Descriptor Table | Critical entry checks |
| MSR LSTAR | SYSCALL entry point | Value comparison |
| MSR CSTAR | SYSENTER compat entry | Value comparison |
| ntoskrnl .text | Kernel code section | Sampled page checksums |
| HalDispatchTable | HAL function table | Pointer validation |
| CI.dll | Code Integrity module | Code checksum |
| KdDebuggerEnabled | Debug state variables | Value validation |
| KPRCB fields | Processor block critical fields | Checksum |
Each PatchGuard check follows this sequence:
Timer fires -> DPC executes -> Decrypt PG_CONTEXT -> Perform checks ->
-> If OK: Re-encrypt context, re-arm timer with new random interval
-> If Modified: KeBugCheckEx(0x109, ...)
The DPC routine:
- Acquires necessary locks
- Decrypts the PG_CONTEXT using the stored XOR key
- Iterates through each protected region
- Recomputes checksums and compares against baselines
- If all checks pass, re-encrypts the context and re-arms the timer
- If any check fails, calls
KeBugCheckExwith detailed parameters
PatchGuard uses kernel timers (KTIMER) with associated DPCs to schedule its checks. Key characteristics:
- Randomized intervals: Between 5 seconds and 10 minutes (Windows 10+)
- Multiple trigger mechanisms: Timer DPCs, work items, APCs, and exception-based triggers
- Anti-debugging: Timer intervals change when a debugger is detected
- Per-processor: Some checks are scheduled on specific processors
The PG context is encrypted when not in active use:
- Windows Vista/7: Simple single-key XOR (same key for all blocks)
- Windows 8/8.1: Rolling key XOR (key advances per block)
- Windows 10: Multi-key XOR with block-index-dependent sub-keys
- Windows 11: Hybrid encryption with AES-like substitution rounds
Key storage: The primary key is derived from a combination of:
- RDTSC value at initialization time
- Address of the PG context itself
- ntoskrnl base address
- A constant seed embedded in the kernel binary
PatchGuard makes extensive use of Structured Exception Handling (SEH):
- The verification DPC is wrapped in multiple nested
__try/__exceptblocks - Exception filters check for specific exception codes
- PG installs vectored exception handlers as backup detection
- Some PG code paths intentionally trigger exceptions to transfer control flow (anti-analysis technique)
PatchGuard employs several techniques to resist analysis:
- Code obfuscation: PG code uses indirect calls, encrypted function pointers, and junk instructions
- Context encryption: The PG context is encrypted when not in use
- Timer randomization: Check intervals are unpredictable
- Multiple entry points: PG checks can be triggered via DPCs, work items, APCs, or exceptions
- Integrity self-checking: PG verifies its own code has not been modified
- Decoy structures: False PG contexts may be placed in memory to mislead analysis
- Anti-debugging: PG behavior changes when a kernel debugger is attached
When PatchGuard triggers a crash, KeBugCheckEx is called with:
- Bug Check Code:
0x109(CRITICAL_STRUCTURE_CORRUPTION) - Parameter 1: Address of the modified structure
- Parameter 2: Type of modification detected
- Parameter 3: Expected value
- Parameter 4: Actual value found
PatchGuard uses specific pool tags for its allocations:
MkPg: Main PG contextMkTm: Timer-related structuresMkWi: Work item allocationsMkGr: Generic PG allocations
Starting with Windows 11 23H2, pool tags may be obfuscated with a per-boot XOR mask.
- Microsoft documentation on Kernel Patch Protection
- Windows Internals, 7th Edition (Yosifovich, Ionescu, Russinovich, Solomon)
- Public research papers on KPP analysis