| name | windows-kernel-security |
| description | Guide for Windows kernel internals and security mechanisms used in game protection and low-level research. Use this skill when working with drivers, IRQL-sensitive callbacks, EPROCESS, ETHREAD, MMVAD internals, IOCTL paths, DSE, PatchGuard, HVCI, PiDDBCache, MmUnloadedDrivers, or kernel memory inspection. |
Windows Kernel Security
Overview
This skill covers Windows kernel internals that matter for game security research: object callbacks, process and image notifications, APC behavior, driver loading, trust enforcement, memory manager structures, and the bookkeeping anti-cheats inspect to detect hostile drivers or hidden executable code.
README Coverage
Cheat > PatchGuard-related
Cheat > Driver Signature enforcement
Cheat > Windows Kernel Explorer
Cheat > EFI Driver (cross-reference with game-hacking skill)
Cheat > Vulnerable Driver
Anti Cheat > Detection:Attach
Anti Cheat > Detection:Hide
Anti Cheat > Detection:Vulnerable Driver
Anti Cheat > Detection:Spoof Stack
Anti Cheat > Windows Ring3 Callback
Anti Cheat > Windows Ring0 Callback
Anti Cheat > Information System & Forensics
Some Tricks > Windows Ring0
Windows Security Features
Core Kernel Concepts
Important Structures
- EPROCESS / ETHREAD
- KTHREAD / KAPC / KAPC_STATE
- MMVAD / VAD tree nodes
- PEB / TEB
- DRIVER_OBJECT
- DEVICE_OBJECT
- IRP (I/O Request Packet)
Key Tables
- SSDT (System Service Descriptor Table)
- IDT (Interrupt Descriptor Table)
- GDT (Global Descriptor Table)
- PspCidTable (Process/Thread handle table)
- PiDDBCacheTable / MmUnloadedDrivers / PoolBigPageTable
User-Mode Kernel Symbol Walking
Methodology
- Load local ntoskrnl image (typically C:\Windows\System32\ntoskrnl.exe)
- Use dbghelp + symbol server path (srv*cache*https://msdl.microsoft.com/download/symbols)
to resolve exported symbol RVAs and type information
- Build structure-aware field lookup:
- Query field offset directly (e.g., _EPROCESS.Token)
- Enumerate all members of a target struct (_TOKEN, _EPROCESS, etc.)
- Search a field name across all known structs (useful when parent type is unknown)
- Keep symbol path configurable for offline/private symbol repositories
Why It Matters in Game Security
- Reduces hardcoded-offset fragility across Windows builds
- Helps map kernel object layouts used by anti-cheat and drivers
- Supports rapid adaptation when anti-cheat-relevant fields shift
(EPROCESS, ETHREAD, token/handle/security-related members)
Gadget Scanning Workflow
- Map executable sections of ntoskrnl image in user mode
- Scan for short control-flow gadgets (e.g., pop rcx ; ret, jmp rax)
- Use as a research primitive for:
- ROP chain feasibility analysis
- Kernel exploit mitigation evaluation
- Anti-cheat hardening review against gadget-dependent attack paths
Security Features
PatchGuard (Kernel Patch Protection)
- Protects critical kernel structures
- Periodic verification checks
- BSOD on tampering detection
- Multiple trigger mechanisms
Driver Signature Enforcement (DSE)
- Requires signed drivers
- CI.dll verification
- Test signing mode
- WHQL certification
Virtualization-Based Security (VBS)
Architecture:
- Uses the Windows hypervisor to create an isolated execution environment
- Splits the system into Virtual Trust Levels (VTLs)
- VTL0: Normal world — standard Windows kernel and user-mode processes
- VTL1: Secure world — Secure Kernel, security policy enforcement
- Even if VTL0 kernel is fully compromised, VTL1 remains isolated
- Three main buckets:
- Memory-protection features (HVCI)
- Virtual Trust Levels (VTL0/VTL1 separation)
- VBS enclaves (isolated execution for selected workloads)
Hypervisor-Enforced Code Integrity (HVCI)
- Also known as Memory Integrity
- Ensures only trusted, validated code executes in kernel mode
- Combines Windows hypervisor + Secure Kernel (VTL1) for enforcement
- Key mechanism: W→X transition restriction
- Executable kernel pages cannot become writable
- Writable pages cannot become executable without re-validation
- Enforcement pipeline:
- Code integrity policy defines what is trusted
- Hypervisor memory enforcement via second-stage address translation (EPT/SLAT)
- Once a kernel page is validated, strict execution rules are enforced
- Driver compatibility requirements: drivers must be HVCI-compatible
Secure Boot
- UEFI-based boot verification
- Boot loader chain validation
- Kernel signature checks
- DBX (forbidden signatures)
- Foundation for attestation and DMA-hardening assumptions
Kernel Callbacks
Process Callbacks
PsSetCreateProcessNotifyRoutine
PsSetCreateProcessNotifyRoutineEx
PsSetCreateProcessNotifyRoutineEx2
Thread Callbacks
PsSetCreateThreadNotifyRoutine
PsSetCreateThreadNotifyRoutineEx
Image Load Callbacks
PsSetLoadImageNotifyRoutine
PsSetLoadImageNotifyRoutineEx
Object Callbacks
ObRegisterCallbacks
APC / Execution Context
KeInitializeApc
KeInsertQueueApc
KeStackAttachProcess
RtlWalkFrameChain
Registry Callbacks
CmRegisterCallback
CmRegisterCallbackEx
Minifilter Callbacks
FltRegisterFilter
Driver Development
Basic Structure
NTSTATUS DriverEntry(
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath
) {
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl;
return STATUS_SUCCESS;
}
Communication Methods
- IOCTL (DeviceIoControl)
- Direct I/O
- Buffered I/O
- Shared memory
Vulnerable Driver Exploitation
Common Vulnerability Types
- Arbitrary read/write primitives
- IOCTL handler vulnerabilities
- Pool overflow
- Use-after-free
Notable Vulnerable Drivers
- gdrv.sys (Gigabyte)
- iqvw64e.sys (Intel)
- MsIo64.sys
- Mhyprot2.sys (Genshin Impact)
- dbutil_2_3.sys (Dell)
- RTCore64.sys (MSI)
- Capcom.sys
Exploitation Steps
- Load vulnerable signed driver
- Trigger vulnerability
- Achieve kernel read/write
- Disable DSE or load unsigned driver
- Execute arbitrary kernel code
PatchGuard Bypass Techniques
Timing-Based
- Predict PG timer
- Modify between checks
Context Manipulation
- Exception handling
- DPC manipulation
- Thread context tampering
Hypervisor-Based
- EPT manipulation
- Memory virtualization
- Intercept PG checks
Kernel Hooking
ETW (Event Tracing for Windows)
- InfinityHook technique
- HalPrivateDispatchTable
- System call tracing
ETW Internals
Provider / Consumer Model
Architecture:
- Providers: kernel or user-mode components that emit events
- Manifest-based providers (registered via wevtutil)
- TraceLogging providers (self-describing, no manifest)
- MOF providers (legacy WMI-based)
- Consumers: tools that subscribe to and process events
- Real-time consumers (ETW sessions)
- Log file consumers (.etl files)
- Controllers: manage sessions (xperf, tracelog, logman)
Key kernel providers:
Microsoft-Windows-Kernel-Process (process/thread lifecycle)
Microsoft-Windows-Kernel-File (file I/O)
Microsoft-Windows-Kernel-Audit-API-Calls (security-sensitive APIs)
ThreatIntel ETW Provider
- Microsoft-Windows-Threat-Intelligence
- Available to PPL (Protected Process Light) and above
- Events: NtReadVirtualMemory, NtWriteVirtualMemory, NtMapViewOfSection on protected processes
- Used by EDR and anti-cheat for detecting memory access to protected processes
- Attackers target: patch EtwThreatIntProvRegHandle or EtwpEventWriteFull
Common ETW Bypass Patterns
- Patch EtwEventWrite in ntdll.dll (user-mode ETW silencing)
- Patch nt!EtwpEventWriteFull in kernel (kernel-mode ETW silencing)
- NtSetInformationThread(ThreadHideFromDebugger) — hides thread from ETW
- Remove provider registration by walking EtwRegistration list
- EPT-based protection can defend ETW structures from tampering
Kernel Segment Heap Architecture
Timeline
Windows NT ~ 1809 : Legacy NT Pool Manager (ExAllocatePoolWithTag)
Windows 10 19H1 : Kernel Segment Heap introduced (March 2019, build 1903)
└─ User-mode Segment Heap ported to the kernel
Windows 10 2004 : ExAllocatePool2 / ExAllocatePool3 added
└─ ExAllocatePoolWithTag officially deprecated
Windows 10 20H2~ : Dynamic KDP (Kernel Data Protection) stabilized
Windows 11 : VBS/HVCI enabled by default; Secure Pool usage expanded
Common misconception: Many sources claim "the Segment Heap was introduced
in Windows 10 2004," but the kernel segment heap was actually introduced
in 19H1 (1903). Windows 10 2004 added the new Pool APIs built on top of it.
Legacy NT Pool Structure (_POOL_HEADER, pre-19H1)
_POOL_HEADER (16 bytes, x64):
Offset Field Size Description
0x00 PoolIndex 1 B Pool descriptor index
0x01 PreviousSize 1 B Previous chunk size
0x02 PoolType 1 B Pool type (Paged, NonPaged, etc.)
0x03 BlockSize 1 B Current chunk size (>> 4)
0x04 PoolTag 4 B 4-byte ASCII tag
0x08 ProcessBilled 8 B KPROCESS pointer (valid only with PoolQuota)
Memory layout:
[POOL_HEADER 16B][user data ...][POOL_HEADER 16B][user data ...]
↑ plaintext, predictable ↑ adjacent → overwritable
Security weaknesses:
- Pool Walking: traverse chunks linearly via BlockSize
- Pool Overflow: corrupt adjacent header for arbitrary write on free
- PoolIndex Overwrite: OOB dereference into pool descriptor array
- ProcessBilled Overwrite: arbitrary address dereference on free path
Windows 8 partial mitigation:
ProcessBilled = KPROCESS_PTR ^ ExpPoolQuotaCookie ^ CHUNK_ADDR
But plaintext _POOL_HEADER remained until 19H1.
_SEGMENT_HEAP Core Structure
Each pool type is managed by its own independent _SEGMENT_HEAP instance.
_SEGMENT_HEAP (kernel offsets, based on 20H2):
0x000 EnvHandle (10 B) — heap environment handle
0x010 Signature (4 B) — always 0xDDEEDDEE
0x028 UserContext (8 B)
0x048 AllocatedBase (8 B) — LFH structure allocation base
0x058 SegContexts[2] (0x180 B) — segment context array
0x100 VsContext (0xC0 B) — VS allocator context
0x280 LfhContext (0x4C0 B) — LFH allocator context
higher LargeAllocMetadata — large allocation metadata
higher LargeReservedPages / LargeCommittedPages
Per pool type instances (nt!PoolVector / HEAP_POOL_NODES):
├── NonPagedPool (NP) → _SEGMENT_HEAP instance #1
├── NonPagedPoolNx (NPNx) → _SEGMENT_HEAP instance #2 ← primary target
├── PagedPool (PP) → _SEGMENT_HEAP instance #3
├── PagedPoolSession → _SEGMENT_HEAP stored in current thread
└── (other special pools)
Allocation Routing Flow
ExAllocatePoolWithTag / ExAllocatePool2 / ExAllocatePool3
│
▼
ExAllocateHeapPool (internal)
│
├─ size ≤ 0x200 AND LFH activated ──▶ kLFH
│ └─ RtlpHpLfhContextAllocate
│
├─ 0x1e1 ≤ size ≤ 0xfe0 ──▶ VS Allocator
│ └─ RtlpHpVsContextAllocateInternal
│
├─ page-aligned (0x20000~0x7f0000) ──▶ Segment Allocator
│ └─ RtlpHpSegAlloc
│
└─ large (> 0x7f0000) ──▶ Large Allocator
└─ RtlpHpLargeAlloc
kLFH (Low Fragmentation Heap)
Size range: ≤ 0x200 bytes (512 B), when LFH activated for that size class
Activation: After 18 consecutive allocations of the same size
Key function: RtlpHpLfhContextAllocate
Chunk header: _POOL_HEADER (16 B, still present)
Metadata: _HEAP_LFH_SUBSEGMENT (isolated, not inline)
Bucket count: 129 (Buckets[129])
Bucket structure:
_HEAP_LFH_CONTEXT
└── Buckets[129]
├── Bucket #0: size 1~8 B
├── Bucket #1: size 9~16 B
├── ...
└── Bucket #128: size ~0x1FF B
(each bucket has AffinitySlots → _HEAP_LFH_SUBSEGMENT)
Security properties:
- Block placement within subsegment is randomized
- Next allocation position managed through FreeHint, encoded with LfhKey
- Adjacent chunk overflow cannot directly corrupt management structure
VS Allocator (Variable Size)
Size range: (a) ≤ 0x1e0 && LFH inactive; (b) 0x1e1~0xfe0;
(c) 0x1001~0xffff && non-page-aligned
Key function: RtlpHpVsContextAllocateInternal
Chunk header: _HEAP_VS_CHUNK_HEADER (16 B, HeapKey XOR encoded)
Free management: Red-Black Tree (FreeChunkTree)
Algorithm: Best-fit
_HEAP_VS_CHUNK_HEADER (allocated state):
┌──────────────────────────────────────────────────────────┐
│ Sizes (8 B) — XOR encoded: HeaderBits ^ self_addr ^ HeapKey
│ ├─ UnsafeSize : chunk size / 16
│ ├─ UnsafePrevSize : previous chunk size / 16
│ ├─ MemoryCost : pages occupied
│ └─ UnusedBytes : whether unused bytes exist
│ EncodedSegmentPageOffset (1 B)
│ — (self_addr ^ self ^ HeapKey) & 0xFF
│ — page distance to VS subsegment start
└──────────────────────────────────────────────────────────┘
Memory layout:
[_HEAP_VS_CHUNK_HEADER 16B][_POOL_HEADER 16B][user data ...]
↑ HeapKey XOR ↑ PoolTag etc. still present
VS subsegment structure (_HEAP_VS_SUBSEGMENT):
├── ListEntry — subsegment linked list
├── CommitBitmap — page commit state bitmap
├── CommitLock — lock used during commit
├── Size (2 B) — subsegment size (>> 4)
└── Signature (15 bit) + FullCommit (1 bit) — integrity check
Segment Allocator (Backend)
Size range #1: 0x20000 < size ≤ 0x7f000 (128 KB ~ 508 KB)
Size range #2: 0x7f000 < size ≤ 0x7f0000 (508 KB ~ ~7 MB)
Core structure: _HEAP_PAGE_SEGMENT + 256 page descriptors
Segment mask: 0xFFFFFFFFFFF00000
The kernel uses two independent SegContexts (unlike user-mode's single context).
Page segment signature encoding:
check = page_segment ^ page_segment->Signature
^ 0xA2E64EADA2E64EAD ^ RtlpHpHeapGlobals.HeapKey
Large Allocator
Size range: > 0x7f0000 (typically page-aligned)
Key function: RtlpHpLargeAlloc
Metadata: _SEGMENT_HEAP.LargeAllocMetadata
Tracking: BigPagePoolTable (PoolTrackTable)
No inline header; metadata recorded externally.
Header Layout Per Allocation Path
Path Memory layout (chunk start → user data)
────────────────────────────────────────────────────────────────
kLFH [_POOL_HEADER 16B] [data]
VS [_HEAP_VS_CHUNK_HEADER 16B] [_POOL_HEADER 16B] [data]
Segment [_HEAP_PAGE_SEGMENT header] ... [page descriptors]
Large Metadata in BigPagePoolTable; no inline header
CacheAligned [_POOL_HEADER #1] ... [_POOL_HEADER #2 (CacheAligned)] [data]
Residual _POOL_HEADER Under Segment Heap
_POOL_HEADER was not fully removed. Remaining usage:
Field Status under Segment Heap
PoolTag Still recorded (for debugging/tracing)
PoolType Recorded, not used for allocator selection on free
BlockSize Unused in VS path; still present in kLFH
PreviousSize Unused, set to 0
PoolIndex Unused, set to 0
ProcessBilled Valid only with PoolQuota flag (encoded with ExpPoolQuotaCookie)
Pointer Encoding Mechanisms
Global key structure: _RTLP_HP_HEAP_GLOBALS (nt!RtlpHpHeapGlobals)
Generated randomly at boot time; global in ntoskrnl.
{
UINT64 HeapKey; // VS Allocator + Segment Allocator header encoding
UINT64 LfhKey; // LFH callback pointer encoding
}
Encoding formulas:
VS chunk header — Sizes field:
encoded = (real Sizes) ^ (address of vs_chunk_header) ^ HeapKey
VS chunk — EncodedSegmentPageOffset:
encoded = ((real page distance) ^ vs_chunk_header ^ HeapKey) & 0xFF
Segment context signature:
check = page_segment ^ page_segment->Signature
^ 0xA2E64EADA2E64EAD ^ HeapKey
LFH callback function pointer:
encoded = real function address ^ HeapKey ^ address of LfhContext
ProcessBilled (POOL_HEADER, Windows 8+):
encoded = KPROCESS_PTR ^ ExpPoolQuotaCookie ^ CHUNK_ADDR
Implications for attackers:
- Must leak HeapKey and LfhKey from RtlpHpHeapGlobals
- Must know chunk's own virtual address (self-referential XOR)
- Failing encoding validation triggers:
BugCheck 0x139 (KERNEL_SECURITY_CHECK_FAILURE) or
BugCheck 0x13A (KERNEL_MODE_HEAP_CORRUPTION)
Dynamic Lookaside and Delay Free
Dynamic Lookaside:
_HEAP_VS_CONTEXT
└── Lookaside buckets (_RTL_DYNAMIC_LOOKASIDE)
├── Per-size singly-linked lists
├── Depth (2 B) — current list depth
└── NextEntry (8 B) — pointer to next cached chunk
Rebalancing (every 3 Balance Set Manager scans):
- alloc count < 25 → Depth decreases by 10
- miss ratio ≥ 0.5% → Depth increases
- miss ratio < 0.5% → Depth decreases by 1
- Range: minimum 4 ~ MaximumDepth
Delay Free (VS Allocator):
- size < 1 KB AND Config.Flags bit 4 == 1:
→ stored in DelayFreeContext list
→ batch freed after 32 entries accumulate
- Otherwise: inserted immediately into FreeChunkTree
- Security: disrupts UAF timing (cannot immediately reuse freed chunk)
New Pool APIs: ExAllocatePool2 / ExAllocatePool3
Evolution:
ExAllocatePool (legacy, no tag)
ExAllocatePoolWithTag (pre-19H1 standard, deprecated in 2004)
ExAllocatePoolWithTagPriority (priority support)
ExAllocatePoolWithQuotaTag (quota tracking)
↓
ExAllocatePool2 (general case, zero-initialized by default)
ExAllocatePool3 (extended parameters, priority + Secure Pool)
ExAllocatePool2:
PVOID ExAllocatePool2(POOL_FLAGS Flags, SIZE_T NumberOfBytes, ULONG Tag);
- Zero-initialized by default (no RtlZeroMemory needed)
- Returns NULL on failure by default
- POOL_FLAG_RAISE_ON_FAILURE converts to exception
- POOL_FLAG_USE_QUOTA integrates legacy PoolQuota
ExAllocatePool3:
PVOID ExAllocatePool3(POOL_FLAGS Flags, SIZE_T NumberOfBytes, ULONG Tag,
PCPOOL_EXTENDED_PARAMETER ExtendedParameters, ULONG Count);
Extended parameter types:
- PoolExtendedParameterPriority: allocation priority (e.g., HighPoolPriority)
- PoolExtendedParameterSecurePool: KDP Secure Pool (VTL0 write-protected)
Down-level compatibility:
#define POOL_ZERO_DOWN_LEVEL_SUPPORT
ExInitializeDriverRuntime(DriversRuntimeInitSupportFlags);
→ ExAllocatePool2 internally falls back to alloc + memset on older OS
Kernel Data Protection (KDP) and Secure Pool
KDP leverages Segment Heap's Secure Pool feature to allocate
read-only kernel memory that cannot be modified from VTL0.
Virtual address space layout:
Dedicated 512 GB Secure Pool region (1 PML4 entry)
Base address: randomized at boot
Managed by: Secure Kernel (VTL1)
VTL0 writes: blocked via NAR (Node Address Range)
Initialization flow:
1. NT Memory Manager boot Phase 1
2. Randomly calculate 512 GB Secure Pool virtual address
3. INITIALIZE_SECURE_POOL Secure Call → Secure Kernel
4. Secure Kernel creates NAR + initializes NTE (Node Table Entry)
Anti-cheat usage:
// Create Secure Pool context
ExCreatePool(POOL_FLAG_NON_PAGED, tag, &securePoolHandle);
// Allocate detection rule table (immutable after init)
POOL_EXTENDED_PARAMS_SECURE_POOL sp = {
.Cookie = MY_COOKIE,
.SecurePoolHandle = securePoolHandle,
.Buffer = &detectionRuleTable,
.SecurePoolFlags = SECURE_POOL_FLAGS_FREEABLE
// MODIFIABLE flag omitted → write-protected after init
};
g_DetectionRules = ExAllocatePool3(POOL_FLAG_NON_PAGED,
sizeof(detectionRuleTable), 'DRul', &extParams, 1);
// g_DetectionRules is now immutable — no VTL0 code can modify it
Attack Technique Evolution (Segment Heap Era)
Technique comparison:
Technique NT Pool (pre-19H1) Segment Heap (19H1+)
─────────────────────────────────────────────────────────────────────────
Adjacent header overwrite Easy Blocked by encoding
Pool Walking Possible Impossible (metadata isolation)
ProcessBilled overwrite Requires Win8+ cookie Requires cookie + HeapKey
kLFH pool spray Predictable Possible but needs precise control
VS FreeChunkTree corruption N/A Requires HeapKey bypass
Large chunk BigPool tracking PoC exists PoC exists (PoolTrackTable)
Modern kLFH exploit requirements:
1. Find target object of same size (same kLFH bucket)
2. Target must contain exploitable members (pointer, function table)
3. Target allocation must be triggerable from user mode
4. Vulnerable and target objects must be in same pool type
(NonPagedPoolNx and PagedPool use separate _SEGMENT_HEAP instances)
VS chunk overflow recovery (must restore to avoid BugCheck):
ghost_chunk->Sizes.HeaderBits =
(real_sizes) ^ (ULONG_PTR)ghost_chunk ^ HeapKey;
ghost_chunk->EncodedSegmentPageOffset =
((real_page_offset) ^ (ULONG_PTR)ghost_chunk ^ HeapKey) & 0xFF;
// Failure → BugCheck 0x13A
Required pre-exploit leak values:
Symbol Purpose Source
nt!RtlpHpHeapGlobals HeapKey, LfhKey Pattern scan ExFreePoolWithTag
nt!ExpPoolQuotaCookie Decode ProcessBilled Pattern scan ExAllocatePoolWithQuotaTag
nt!PsInitialSystemProcess EPROCESS chain ntoskrnl import analysis
Chunk's own virtual address Self-referential XOR Requires info-leak primitive
BugCheck Codes (Segment Heap Related)
Code Name Trigger
0x139 KERNEL_SECURITY_CHECK_FAILURE VS/LFH header integrity check failure
0x13A KERNEL_MODE_HEAP_CORRUPTION Heap metadata corruption detected
0xC5 DRIVER_CORRUPTED_EXPOOL Pool accessed at incorrect IRQL
0x19 BAD_POOL_HEADER _POOL_HEADER validation failure (LFH path)
Pool Allocation & Forensics
Pool Forensics Artifacts
PiDDBCacheTable:
- Tracks historically loaded drivers by hash + timestamp
- Anti-cheat inspects this to detect BYOVD or test-signed driver loads
- Attackers attempt to remove entries post-load
MmUnloadedDrivers:
- Circular buffer of recently unloaded drivers (name + address range)
- Cannot be cleared from user mode
- Anti-cheat uses to detect load-unload-reload patterns
PoolBigPageTable:
- Maps large pool allocations (>= PAGE_SIZE) to owning driver tag
- Used for: identifying hidden drivers, finding leaked pool allocations
- Anti-cheat walks this to detect manually mapped driver memory
Pool Tag Forensics
- ExAllocatePoolWithTag / ExAllocatePool2: every allocation carries a 4-byte tag
- Pool tag scanning: identify driver presence by known tags
- Tool: pooltag.txt (Microsoft), PoolMon, WinDbg !poolfind
- Anti-cheat technique: scan pool tags for known cheat driver signatures
Modern Pool Scanning (Segment Heap Era)
Legacy method (pre-19H1) — NO LONGER WORKS:
Follow BlockSize in inline header to traverse linearly.
PPOOL_HEADER h = startAddr;
while (h->BlockSize != 0) {
if (h->PoolTag == TARGET_TAG) { /* ... */ }
h += h->BlockSize; // Invalid under segment heap
}
Modern alternatives:
BigPool detection (Large Alloc path):
Reference nt!PoolBigPageTable (or nt!PoolTrackTable)
└─ Traverse BigPagePoolTable entries
└─ Find allocations without corresponding driver objects
Small allocation detection:
_SEGMENT_HEAP → VsContext → SubsegmentList traversal
_SEGMENT_HEAP → LfhContext → Buckets[] → AffinitySlots → Subsegments
VS Chunk Header decoding (requires HeapKey):
real_sizes = encoded_header ^ chunk_address ^ HeapKey
→ Decode to determine chunk size, PoolTag, allocation legitimacy
Anti-cheat scanning targets:
- Suspicious PoolTags: cheat drivers use custom/rare tags; maintain blacklist
- Executable permission pages: NonPagedPool chunks with X permission
from suspicious sources (no corresponding loaded module)
- Shellcode patterns: scan decoded chunk contents for known cheat signatures,
ROP gadgets, specific syscall sequences
- kLFH allocation pattern anomalies: unusual allocation patterns in
specific size buckets can indicate pool grooming
WinDbg commands:
dt nt!_RTLP_HP_HEAP_GLOBALS nt!RtlpHpHeapGlobals // HeapKey, LfhKey
dt nt!_SEGMENT_HEAP <address>
dt nt!_HEAP_VS_CHUNK_HEADER <address>
dt nt!_HEAP_LFH_CONTEXT <address>
!pool <address>
!poolfind <Tag> [pool_type]
!poolused [flags] // stats by PoolTag
dt nt!_POOL_TRACKER_BIG_PAGES nt!PoolBigPageTable
VS chunk header decode (manual):
HeaderBits_raw = poi(<chunk_addr>)
real Sizes = HeaderBits_raw ^ <chunk_addr> ^ HeapKey
Driver Development Migration Checklist
□ ExAllocatePoolWithTag → ExAllocatePool2
□ ExAllocatePool (without tag) → Remove or ExAllocatePool2
□ ExAllocatePoolWithTagPriority → ExAllocatePool3 + Priority param
□ ExAllocatePoolWithQuotaTag → ExAllocatePool2 + POOL_FLAG_USE_QUOTA
□ RtlZeroMemory after alloc → Remove (ExAllocatePool2 zero-initializes)
□ Review POOL_FLAG_RAISE_ON_FAILURE (NULL check vs exception)
□ Critical read-only data → ExAllocatePool3 + Secure Pool
SSDT Hooking (Legacy)
- Modify service table entries
- Requires PG bypass
- High detection risk
IRP Hooking
- Hook driver dispatch routines
- Less monitored than SSDT
- Per-driver targeting
Memory Manipulation
Physical Memory Access
MmMapIoSpace
MmCopyMemory
\\Device\\PhysicalMemory
Virtual Memory
ZwReadVirtualMemory
ZwWriteVirtualMemory
KeStackAttachProcess
MmCopyVirtualMemory
MDL Operations
IoAllocateMdl
MmProbeAndLockPages
MmMapLockedPagesSpecifyCache
Research Tools
Analysis
- WinDbg / WinDbg Preview
- Process Hacker / System Informer
- OpenArk
- WinArk
Utilities
- KDU (Kernel Driver Utility)
- OSR Driver Loader
- DriverView
Monitoring
- Process Monitor
- API Monitor
- ETW consumers
EFI/Boot-Time Threats
EFI Driver Cross-Reference
The README's > EFI Driver subcategory (under Cheat) contains 30+ projects:
- EFI bootkit frameworks: UEFI DXE drivers that persist across boots
- Boot-time memory mappers: inject code before Windows kernel initializes
- ExitBootServices hooks: intercept Windows boot handoff
- EFI runtime service abuse: GetVariable/SetVariable for kernel ↔ EFI comm
See also: game-hacking skill for EFI cheat workflows
Boot-Time Access
- EFI runtime services persist after ExitBootServices
- DXE (Driver Execution Environment) phase: full hardware access
- Pre-kernel execution: no DSE, no PatchGuard, no HVCI enforcement
- Secure Boot is the primary mitigation (firmware signature verification)
Memory Access
- GetVariable/SetVariable: pass data between EFI and OS runtime
- Runtime memory mapping via EFI memory map
- Physical memory access before Windows memory manager initializes
- ACPI table injection for persistent low-level modifications
Hypervisor Development
Hypervisor Types
Type 1 (bare-metal):
- Runs directly on hardware
- Examples: VMware ESXi, Microsoft Hyper-V, Xen
- Used for VBS, production security enforcement
Type 2 (hosted):
- Runs on top of a host operating system
- Examples: Oracle VirtualBox, VMware Workstation
- Common for research, development, and testing
Hardware Virtualization Platforms
Intel VT-x:
- Introduced 2005, widely supported on modern Intel CPUs
- Foundation for VMCS, EPT, VM exits
AMD-V (SVM):
- AMD's counterpart to VT-x, also introduced 2005
- VMCB structure, NPT (Nested Page Tables)
ARM Virtualization Extensions:
- EL2 (hypervisor mode) and stage-2 memory translation
- Used on ARM platforms for mobile and embedded security
Intel VT-x Core Concepts
VMCS (Virtual Machine Control Structure)
Central data structure for Intel VT-x:
- Describes guest state, host state, and virtualization controls
- Tells the processor:
- What state to restore on VM entry
- What state to save on VM exit
- Which events transfer control back to the hypervisor
Guest/Host State Areas:
- Control registers (CR0, CR3, CR4)
- Segment registers (CS, SS, DS, ES, FS, GS)
- Debug registers (DR7 — hardware breakpoints)
- Descriptor-table registers (GDTR, IDTR)
- Key fields:
- CR3: root of guest page tables, central to virtual memory
- GDTR/IDTR: Global/Interrupt Descriptor Tables
- CS/SS: code and stack segments
- DR7: hardware breakpoint control
Control Fields:
- Pin-based controls
- Primary processor-based controls
- Secondary processor-based controls
- Events that cause VM exits:
- CPUID interception
- INVLPG interception
- Control-register access
- EPT violations
- MSR access
EPT (Extended Page Tables)
Intel's implementation of SLAT (Second-Level Address Translation):
- Gives the hypervisor independent control over guest memory
- Two-stage address translation pipeline:
1. GVA → GPA: Guest Virtual → Guest Physical (via guest page tables, rooted at CR3)
2. GPA → HPA: Guest Physical → Host Physical (via EPT, rooted at EPTP in VMCS)
- Guest believes it owns its own memory mappings
- Hypervisor has a second, independent layer controlling:
- What physical memory is reachable
- What permissions apply (read/write/execute)
EPT Hierarchy:
- PML4 → PDPT → PD → PT (4-level page table)
- Each entry carries read/write/execute permissions
- EPT violations trigger VM exits when access permissions are violated
Page Table Entries (PTE):
- Maps GVA to GPA
- Carries: read/write, supervisor-only, caching, software-defined bits
- Guest PTEs and EPT serve different roles:
- Guest PTE: controls guest's view of memory
- EPT: controls hypervisor's view of the guest
VM Exits & VMCALL
VM Exits:
- Occur when configured events happen in the guest
- Triggers: CPUID, CR access, I/O instructions, EPT violations, MSR access
- On exit: processor saves guest state (per VMCS), restores host state,
records exit reason for hypervisor handler
VMCALL:
- Guest intentionally transfers control to hypervisor
- Similar in concept to a system call (guest → hypervisor)
- Used for guest-hypervisor communication interfaces
Nested Virtualization
- Running a hypervisor inside a VM managed by another hypervisor
- Useful for research, testing, and development
- Adds complexity: multiple layers participate in the same virtualization flow
- Relevant for testing hypervisor-based defense under VMware/Hyper-V
AMD-V (SVM)
- VMCB (Virtual Machine Control Block) structure
- NPT (Nested Page Tables) — AMD's SLAT equivalent
- SVM operations (VMRUN, VMSAVE, VMLOAD)
Use Cases
- Memory hiding
- Syscall interception
- Security monitoring
- Anti-cheat evasion
- EPT-based memory protection and introspection
Windows Hypervisor Platform (WHP) API
User-mode hypervisor interface (Windows 10+):
- WHvCreatePartition / WHvSetupPartition: create VM partition
- WHvCreateVirtualProcessor: add vCPU
- WHvMapGpaRange: map host memory into guest physical address space
- WHvRunVirtualProcessor: enter guest execution, blocks until VM exit
- WHvGetVirtualProcessorRegisters / Set: read/write guest CPU state
Key capability:
- Enables hypervisor-assisted analysis from user mode (no kernel driver)
- Page-level trap handling: set R/W/X permissions per guest page
- VM exit reasons: memory access violation, CPUID, MSR access, I/O port, syscall
- Deterministic execution: host controls all guest state and memory
Prerequisites:
- Enable Windows features: Microsoft-Hyper-V-Hypervisor + HypervisorPlatform
- Hardware: VT-x or AMD-V support
- Note: WHP coexists with Hyper-V but conflicts with some third-party hypervisors
See also: reverse-engineering skill → User-Mode Hypervisor-Assisted Tracing
for analysis workflows built on WHP
Hypervisor-Based Defense
Concept
- Security approach using virtualization primitives to enforce protections
from a higher privilege level than the guest kernel
- Moves security decisions into an isolated execution environment
that a compromised kernel cannot easily tamper with
- Present across major OS platforms:
- Windows: Virtualization-Based Security (VBS)
- Android: Android Virtualization Framework (AVF)
- Apple: Secure execution environments, hardware-backed isolation
EPT Hooks as Defensive Primitives
Mechanism:
- Instead of patching the guest kernel, modify EPT permissions
- Specific memory accesses trigger EPT violations → VM exit
- Hypervisor inspects the access and decides: allow, deny, or log
Example: Watching writes to a sensitive region
1. Remove write permission from the EPT entry for target region
2. Guest runs normally until it attempts a write to that region
3. EPT violation → VM exit → hypervisor receives control
4. Hypervisor evaluates context:
- Which module performed the access
- What memory was touched
- Whether the access is authorized
5. Decision: allow write, deny and return, or log and continue
Advantages over traditional kernel hooks:
- Operate outside the guest OS
- Remain effective even if guest kernel is compromised
- Transparent to guest-level detection
- Cannot be removed by kernel-level rootkits
Protectable Assets via EPT
- Executable pages of EPP (Endpoint Protection Platform) drivers
→ Prevents silent patching of security software
- ETW-related structures
→ Unauthorized writes fault into hypervisor
- Callback/callout/routine lists (PsSetCreateProcessNotifyRoutine, etc.)
→ Write authorization moved outside the guest kernel
- Critical kernel data structures
→ PatchGuard-protected regions, SSDT, IDT
Threat Model for Hypervisor Defense
Assumes kernel compromise has already happened:
- Attacker has kernel code execution
- Attacker can load vulnerable drivers (BYOVD)
- Attacker can modify kernel memory
- Traditional kernel-resident protections are untrustworthy
Hypervisor advantage:
- Sits above the guest kernel in privilege hierarchy
- Enforces policies from a higher privilege layer
- Kernel-level rootkits cannot disable hypervisor-level enforcement
Attack Scenario: BYOVD vs EPT Protection
Without hypervisor defense:
1. Attacker loads vulnerable signed driver
2. Gains kernel R/W primitives
3. Patches callback list to remove EPP callbacks
4. EPP is blinded — attacker operates undetected
With EPT-based defense:
1. Attacker loads vulnerable signed driver
2. Gains kernel R/W primitives
3. Attempts to patch callback list
4. EPT violation triggers VM exit
5. Hypervisor catches the write, evaluates context
6. Write is denied — callback list remains intact
Resource Organization
The README contains categorized links for:
- PatchGuard research and bypasses
- DSE bypass techniques
- Vulnerable driver exploits
- Kernel callback enumeration
- ETW/PMI/NMI handlers
- Intel PT integration
Data Source
Important: This skill provides conceptual guidance and overview information. For detailed information use the following sources:
1. Project Overview & Resource Index
Fetch the main README for the full curated list of repositories, tools, and descriptions:
https://raw.githubusercontent.com/gmh5225/awesome-game-security/refs/heads/main/README.md
The main README contains thousands of curated links organized by category. When users ask for specific tools, projects, or implementations, retrieve and reference the appropriate sections from this source.
2. Repository Code Details (Archive)
For detailed repository information (file structure, source code, implementation details), the project maintains a local archive. If a repository has been archived, always prefer fetching from the archive over cloning or browsing GitHub directly.
Archive URL format:
https://raw.githubusercontent.com/gmh5225/awesome-game-security/refs/heads/main/archive/{owner}/{repo}.txt
Examples:
https://raw.githubusercontent.com/gmh5225/awesome-game-security/refs/heads/main/archive/ufrisk/pcileech.txt
https://raw.githubusercontent.com/gmh5225/awesome-game-security/refs/heads/main/archive/000-aki-000/GameDebugMenu.txt
How to use:
- Identify the GitHub repository the user is asking about (owner and repo name from the URL).
- Construct the archive URL: replace
{owner} with the GitHub username/org and {repo} with the repository name (no .git suffix).
- Fetch the archive file — it contains a full code snapshot with file trees and source code generated by
code2prompt.
- If the fetch returns a 404, the repository has not been archived yet; fall back to the README or direct GitHub browsing.
3. Repository Descriptions
For a concise English summary of what a repository does, the project maintains auto-generated description files.
Description URL format:
https://raw.githubusercontent.com/gmh5225/awesome-game-security/refs/heads/main/description/{owner}/{repo}/description_en.txt
Examples:
https://raw.githubusercontent.com/gmh5225/awesome-game-security/refs/heads/main/description/00christian00/UnityDecompiled/description_en.txt
https://raw.githubusercontent.com/gmh5225/awesome-game-security/refs/heads/main/description/ufrisk/pcileech/description_en.txt
How to use:
- Identify the GitHub repository the user is asking about (owner and repo name from the URL).
- Construct the description URL: replace
{owner} with the GitHub username/org and {repo} with the repository name.
- Fetch the description file — it contains a short, human-readable summary of the repository's purpose and contents.
- If the fetch returns a 404, the description has not been generated yet; fall back to the README entry or the archive.
Priority order when answering questions about a specific repository:
- Description (quick summary) — fetch first for concise context
- Archive (full code snapshot) — fetch when deeper implementation details are needed
- README entry — fallback when neither description nor archive is available