Covert Kernel/User Communication Channels on Windows: Rootkits, Game Cheats, and Detection

Covert Kernel/User Communication Channels on Windows: Rootkits, Game Cheats, and Detection

Original text: “Covert Kernel/User Communication Channels on Windows: Rootkits, Game Cheats, and Detection”kernullist, Kernullist’s Blog (Jun 10, 2026). Classification tables, ASCII flow diagrams, and C-language structure declarations below are reproduced verbatim with attribution captions.

Executive Summary

Covert Kernel/User Communication Channels on Windows: Rootkits, Game Cheats, and Detection
Covert Kernel/User Communication Channels on Windows: Rootkits, Game Cheats, and Detection

A modern Windows kernel-assisted threat is almost never a single user-mode binary doing all the work. It is a stack — a user-mode controller, a kernel-mode component loaded through a Bring-Your-Own-Vulnerable-Driver (BYOVD) chain or an abused signed driver, and sometimes an external auxiliary such as a PCIe DMA card, a coupled hypervisor, or a microcontroller HID emulator. The component defenders consistently underestimate is the communication channel between these pieces. A custom DeviceCheat IOCTL would solve every engineering problem, and it would also be inventoried by any competent EDR or anti-cheat on day one. Mature rootkits, BYOVD malware, and high-end game cheats therefore hide the channel inside Windows features that are already noisy, under-monitored, version-dependent, or hard to attribute to a specific driver after the fact.

This long-form surface map follows that landscape from the defender side. It walks sixteen surfaces, from ordinary user-mode IPC down through documented kernel mediation, callback registries, dispatch tables, writable .data control pointers, memory-backed mailboxes, GPU and DXGK primitives, execution-flow triggers, CPU and hypervisor exits, persistent storage and firmware, and external hardware. The treatment is anti-cheat-flavoured because anti-cheat work forces detection on live consumer machines under near-zero false-positive tolerance, but the same surfaces apply to rootkits, malicious signed drivers, boot-time loaders, and stealthy post-exploitation implants. Reference posture: 2026-06-10. Private structure, callback-list, system-information-class, graphics, and syscall-provider claims are build-sensitive and should be validated against the target kernel image, symbols, and clean baselines before they become production enforcement logic.

The article’s central insight is that mature covert channels are not single APIs but small protocols assembled from six Windows-native planes — rendezvous surface, trigger edge, selector plane, payload plane, reply plane, lifecycle/cleanup. Reading every technique in those terms reveals why shallow single-surface checks fail: a registry write may only carry an opcode while the payload sits in an MDL-backed heap buffer; an ALPC message may only advance an epoch while the real data moves through a shared view; a firmware-table query may look like hardware inventory while the handler is actually a request/reply dispatcher; a thread-pool completion may not contain data at all but only make a normal worker consume a mailbox that was prepared earlier.

1. Threat Model

A modern Windows kernel-assisted threat is rarely a single user-mode module doing all the work. It is a stack: a user-mode controller, a kernel-mode component loaded through a vulnerable-driver chain or a signed-but-abusive driver, and sometimes an external auxiliary such as DMA hardware, a hypervisor, or an input emulator. The component defenders often underestimate is the communication channel between these pieces. DeviceIoControl against a custom device object would solve every engineering problem; it would also be inventoried quickly by a competent anti-cheat, EDR, or incident-response tool. Mature rootkits, BYOVD malware, and high-end game cheats therefore hide the channel inside Windows features that are already noisy, under-monitored, version-dependent, or hard to attribute to a specific driver after the fact.

Original article, opening paragraph

1.1 The Kernel-Assisted Threat Stack

A kernel-assisted threat usually splits three concerns: access (reading, writing, hiding, or brokering privileged state), control (deciding what to do with that state), and delivery (overlay, input, persistence, configuration, proxying, payload execution, or cleanup). Game cheats, rootkits, and BYOVD malware emphasize different outcomes, but the stack shape is similar: a user-mode controller inside, adjacent to, or merely correlated with the protected process (in cheat cases an injected module, overlay helper, launcher-side service, or configuration UI; in malware cases a service, broker process, updater, injected payload, or short-lived staging process); a kernel-mode component loaded through a vulnerable-driver chain, an abused signed driver, an OEM-looking helper, or a custom mapper, providing privilege the user-mode side cannot legitimately obtain (kernel reads, callback registration, page-table manipulation, MSR access, object routing, or hidden persistence); and optional external support — a PCIe DMA card, a coupled hypervisor, a second machine running screen capture and computer vision, an input emulator, or external virtualization — whose existence is driven by the host becoming increasingly hostile to on-machine code.

The boundary defenders need to understand is the one between user-mode control and kernel-mode authority. The threat does not simply load a driver and forget about it; it needs a continuous command-and-control path. User mode asks kernel to read protected memory, write a small patch, hide an object, register a callback, route an I/O path, or perform a privileged scan. Kernel asks user mode to render overlay state, update aim logic, decrypt configuration, fetch licensing or operator state, invoke a user-mode payload, or ship telemetry. Both sides need synchronization, watchdogs, health checks, and state exchange. If that boundary is IOCTL 0xDEAD_BEEF against \.CheatDevice, the defender wins on day one. Modern stacks instead choose boundaries that look like ordinary operating-system activity.

1.2 Why Hide the Channel

Three properties make a channel attractive to attackers. Noise means the OS itself or a popular vendor product already uses this surface so often that an extra subscriber, port, or pointer write does not stand out. Under-monitoring means EDR, anti-cheat, and incident-response tooling developed during one Windows era often miss surfaces that came online afterward (WNF, ALPC private ports, Filter Manager ports, ETW providers, MSI-X provisioning). Attribution friction means the surface ties activity to an object — such as a port, section, or callback — rather than directly to the attacker’s driver image; when defenders find the artifact, it points to a legitimate-looking owner or to “something” without a clean trace back to the attacker module. A channel that hits all three is a P0 problem for the defender; a channel that hits one is still operationally useful for the attacker because the cost of finding the channel and the cost of acting on it without false positives dominate detection economics.

SignalImplication
A protected process, game, service, or helper talks to an ALPC/RPC/pipe/socket endpoint whose owner has no product roleHidden control plane behind ordinary IPC
A callback, dispatch entry, or writable control pointer lands outside a valid owner functionKernel redirection or manual-mapped code
A firmware provider, registry callback, WFP callout, or minifilter appears only during protected workload activityRegistered OS surface being used as a rendezvous or trigger
A section, MDL-backed buffer, GPU resource, or WNF state has command-shaped cadencePayload plane split from the visible wake edge
Handle tables, object namespace, ETW, VADs, or file-object routing disagreeCross-view spoofing, path confusion, or per-object route substitution
The recurring signals that mark a covert KM/UM channel. Source: original article, §1.2.

1.3 Attacker Layers

A consistent taxonomy makes the rest of the document tractable. Channels live in layers, and defender visibility depends almost entirely on the layer the channel inhabits.

LayerSurfaceTypical Defender Visibility
L1Ordinary user-mode IPC and storage (pipes, mailslots, registry, atoms)High if defender watches protected workload’s object namespace and IPC handles
L2Legitimate kernel API and driver communication (FltMgr port, WSK loopback/egress, WMI, custom device interface)Medium: needs a kernel inventory and object telemetry
L3Kernel .data, callback, process-structure, or other non-code control pointers (HalPrivateDispatchTable, ObTypeIndexTable, callback arrays)Medium-to-hard: needs baseline integrity and version-aware parsing
L4Hypervisor, EPT, syscall path, CPU state manipulationHard: requires platform or hypervisor visibility
L5External hardware (DMA, microcontroller HID emulators)Very hard: defense moves to policy and hardware attestation
L6External virtualization, visual capture, off-machine computeNearly impossible from inside the protected process
Attacker layers and defender visibility. Source: original article, §1.3.

Market shape depends on the defender. For competitive games, mid-2026 planning still puts most software cheats in L1–L3 (commodity engines, BYOVD loaders, sections, registry, ALPC, WSK, dispatch pointers, and callback abuse), a smaller but important population in L4 (custom hypervisors), and a high-impact FPS-focused population in L5/L6 (DMA hardware, visual capture, VMI, or off-machine compute). For malware and rootkits, L1–L4 overlap heavily with signed-driver abuse, callback misuse, network proxying, persistence, and object-hiding tradecraft. L1–L4 are still partly software-defender territory. L5 and L6 push the problem into hardware policy, IOMMU/DMAr enforcement, server-side behavioral detection, attestation, and controlled hardware environments.

1.4 PatchGuard Safety Tags

Where this surface map discusses kernel modification, the relevant question is not “does it work” but “does it survive PatchGuard.” A consistent labeling helps:

TagMeaning
PG-SafeOutside known PatchGuard coverage. Reads are generally safe; writes may still be blocked by HVCI/KDP, object invariants, reference counting, or ordinary kernel correctness rules.
PG-CautionReading is usually safe, but writes or hooks against the same surface can be risky on some builds.
PG-RiskyWorks only by racing or by restoring state between PatchGuard checks. Long-running attacker tooling needs a watchdog and replay loop.
PG-ConflictReliably triggers a PatchGuard bugcheck on modern systems. Treat as non-viable for production attacker tooling.
PG-BypassUses a legitimate or alternate mechanism that PatchGuard’s classic checks do not cover.
PatchGuard exposure classes used across the surface map. Source: original article, §1.4.

Attacker selection bias is heavy: PG-Conflict techniques have largely been abandoned, PG-Risky techniques persist where the channel value justifies a restore loop, and PG-Safe / PG-Bypass surfaces are where active engineering happens. Defenders should weight detection investment the same way.

1.5 Defender Position

The most demanding practical defender in this document is still a production anti-cheat, because it must inspect consumer machines during live gameplay without breaking legitimate drivers. A comparable EDR or incident-response stack may have different policy power, but the evidence problem is similar. A production anti-cheat realistically has a signed kernel driver loaded at boot or at protected workload launch, a user-mode service for orchestration and telemetry, ETW consumers (generally for kernel-process, image-load, and registry providers, sometimes for security-relevant providers), a game-process module that sees PEB, TEB, loaded modules, and the IPC namespace, baseline snapshots captured at boot, at driver load, and at protected workload launch, and vendor allowlists for security products, GPU drivers, input drivers, overlays, and anti-malware.

It generally does not have full PatchGuard-equivalent coverage of arbitrary kernel state, visibility into SMM or external DMA, or a malicious hypervisor running below it; zero false-positive freedom when inspecting kernel .data; or stable undocumented offsets across every Windows build it must support. These gaps determine which sections of this document are P0 (production must cover), which are P1 (high-value but harder to operationalize), and which are policy concerns where software detection alone cannot win.

1.6 Channel Design Properties

Each channel is evaluated on six axes. Bandwidth distinguishes mailbox-style shared memory (megabytes per second) from MSR-based one-bit storage (a handful of bits per query). Direction — KM→UM only, UM→KM only, or bidirectional — influences whether the channel needs a back-channel object both sides can observe. Trigger model (polling, callback, exception, object event, or hardware event) determines what the attacker’s runtime looks like in CPU and ETW telemetry. PatchGuard exposure comes from the table above. Attribution difficulty measures whether a normal driver or application can plausibly produce the same signal — a signal that is unique to unauthorized tooling is more actionable than one that overlaps with five legitimate products. Build fragility captures whether offsets, structures, or object layouts shift across Windows builds, which drives the cost of a robust detector.

1.7 Attacker Channel Construction Model

The most useful way to read every following technique is to treat it as a protocol assembled from Windows primitives, not as a single API trick. Mature kernel-assisted threats rarely rely on “call this one function and send bytes.” They split the channel into pieces so that each artifact looks mundane in isolation.

  • Rendezvous surface. The place where UM and KM agree that a channel exists: an ALPC port name, firmware provider signature, registry path, section handle, file object, WNF state name, device stack, or callback registration.
  • Trigger edge. The operation that wakes the hidden logic: a registry set, firmware table query, IRP dispatch, ALPC message, thread-pool completion, page fault, event signal, object open, or VM exit.
  • Selector plane. Small fields that identify the command family: registry value type, firmware TableID, IOCTL code, file create options, ALPC message type, WNF state name, completion key, status code, buffer length, or timing slot.
  • Payload plane. Where bytes actually move: a section view, MDL-locked user buffer, ALPC view, pipe body, socket stream, firmware output buffer, mapped GPU resource, or external hardware mailbox.
  • Reply plane. The observable result: output buffer contents, returned size, NTSTATUS, completion status, shared-memory status word, event state, callback side effect, or delayed thread-pool work item.
  • Lifecycle and cleanup. How the channel appears, rotates, idles, and disappears: registration at boot, activation only during protected-session runtime, pointer restore after use, generation counters, heartbeat/timeout, and teardown when defender pressure is detected.

The attacker-side state machine usually has the same shape across surfaces: bootstrap establishes the hidden endpoint and proves both sides are present (one-time pointer transfer, provider registration, section duplication, callback registration, borrowed handle placement); capability negotiation exchanges build number, feature mask, protocol version, pointer size, encryption/compression flags, and supported command classes (size-probe APIs and “buffer too small” replies are often repurposed for this phase); operational epochs carry generation, sequence number, command ID, flags, input length, output length, status, and optional integrity value; synchronization chooses between polling, event signaling, ALPC replies, completion queues, WaitOnAddress, APC delivery, thread-pool callbacks, or hardware traps; error and fallback may switch from ALPC to registry, from a section to MDL pages, from a socket to firmware-table replies, or from a visible helper to a broker process; and teardown restores patched pointers, unregisters providers/callbacks, zeroes headers, rotates names, drops handles, or goes read-only when inspection is detected.

Several protocol fields are worth calling out because they reappear everywhere: magic/version, build guard, channel ID, role, generation, sequence, command ID, flags, input length, output length, status, heartbeat, timeout, cancellation bit, feature mask, nonce, and checksum or MAC. The transport changes; the grammar does not. When reverse-engineering a suspected channel, identify these fields first. The moment a “random” registry value, firmware table ID, ALPC payload, shared memory page, or completion status starts behaving like this grammar, the object stops being ordinary OS traffic and becomes a covert protocol candidate.

1.8 Defender Strategy

Use a layered strategy. Inventory the normal communication surfaces at boot and at protected workload launch: device objects and IOCTL paths, sections, ALPC ports, named pipes, RPC endpoints, COM local servers, named objects, WNF state names, Filter Manager communication ports, WFP providers and callouts, virtual HID stacks, Cloud Files / ProjFS provider roots, I/O rings, CLFS logs, and transaction-backed file/registry activity. Baseline high-risk kernel pointers (HalPrivateDispatchTable, ObTypeIndexTable, callback arrays, dispatch tables) under known-clean conditions. Correlate cross-layer behavior — a suspicious callback plus a suspicious user-mode mapping is stronger than either signal alone. Treat unknown signed drivers as untrusted until their objects, callbacks, sections, and memory mappings are accounted for. Prefer version-aware parsers and symbol-backed validation over hard-coded offsets — the most common reason a production detector regresses is not a missed technique but a Windows build that shifted a structure by 8 bytes.

2. The User-Mode IPC Namespace Surface

The most accessible covert channels live in user-mode IPC primitives that Windows ships and that overlays, launchers, anti-malware, and accessibility tools have been using for decades. A defender’s first inventory pass is the object namespace as observed when the protected workload starts: what exists that should not, what was created after the suspect driver loaded, what is owned by an unknown image, what name is fresh enough to have rotated since the last scan. In anti-cheat deployments, the protected workload is the game plus launcher and helper processes; in malware response, it may be a service, browser, EDR-adjacent process, or injected host. This section walks the primitives in roughly increasing order of subtlety.

2.1 Mailslots

Mailslots are an old single-direction message-based IPC: a process creates a mailslot with CreateMailslotW and other processes write to it via \\.\mailslot\Name. The Win32 path is a DOS-device view over the NT mailslot device namespace; a kernel component should be modeled as opening \Device\Mailslot\... or a resolved local DOS-device alias through native file APIs, not as relying on the literal Win32 string. The classic covert-channel layout reverses the usual direction: a KM writer opens \Device\Mailslot\X_name from the kernel component, and a UM reader creates \\.\mailslot\X_name and reads messages. A reply path requires a second mailslot or another IPC primitive: mailslots are one-way per slot. Windows mailslots support domain-style broadcast, but that is a network fan-out feature, not a useful buffered reply path for a same-host KM-UM channel.

Why attackers still use it: mailslots are old. Many modern telemetry pipelines treat them as legacy and either skip them or down-prioritize alerting. Commodity cheat loaders and lightweight malware stagers favor them because they require no custom driver device object and the user-mode side is two API calls. The bandwidth is poor: remote/network mailslot messages are limited to 424 bytes, while local mailslots can be configured with larger per-slot limits but remain one-way, queue-like, and weakly synchronized. They therefore tend to appear for command framing and configuration, not for memory dumps. The protocol shape is usually simple: fixed-size command records, a sequence number, a command ID, and a small payload or pointer to another channel. Because there is no natural reply on the same slot, mature stacks pair a mailslot with a section/event pair, a registry trigger, or a second reverse-direction slot. A one-way mailslot that only appears during the handshake and then goes quiet is often a rendezvous channel, not the final bus.

Detection: enumerate \Device\Mailslot\ when the protected workload starts and at intervals during runtime; alert on mailslots created after launch by workload-adjacent or unknown processes. Store creator PID, server handle owner, slot path, first/last write time, message-size distribution, writer processes, and whether the slot is paired with a second IPC object. Random-looking, cheat-style, or service-mimicking names (“MsiSync”, “WinSec”, “GpuCacheW”) that resolve to unsigned or unknown image owners are the signal. Legitimate mailslot use is rare on consumer gaming systems; most positive matches in production telemetry are enterprise software that has no business on a gaming machine.

2.2 ALPC and LPC Private Ports

ALPC is the native local IPC mechanism behind a large fraction of Windows service plumbing. LPC-era APIs are effectively legacy vocabulary; on modern Windows the interesting object is ALPC: named connection ports, per-client communication ports, request/reply messages, optional shared views, handle attributes, completion integration, and security context. CSRSS, LSASS, RPCSS, audio, brokered COM, UWP infrastructure, EDR, anti-malware, browser sandboxes, game launchers, DRM, and overlay stacks all use ALPC or sit above a local RPC/COM layer that may lower into ALPC. That makes the surface common enough that “ALPC exists” is worthless as a finding, but it also makes ALPC one of the most practical L2 command channels in kernel-assisted threat stacks. The object model matters: a server creates a connection port under a namespace such as \RPC Control\...; a client connects; the kernel gives each side connected communication-port handles. The connection port is the advertised rendezvous object. The communication ports are the actual per-client endpoints. A detector that records only the advertised name misses the handle topology that proves who talked to whom.

ALPC Structural Model: Ports, Queues, Messages, and Attributes

ALPC should be modeled as a small object graph, not as one named object. The minimum graph has three port roles and several optional side structures: a server connection port (the named rendezvous object, discovered through a raw \RPC Control\... name or via Local RPC / COM activation); a client communication port (the unnamed endpoint handle held by the client after a successful connection — the client’s session object); a server communication port (the per-client endpoint on the server side — a server with many clients has many per-client relationships even if it advertises only one connection port); message queues (request, reply, wait, and unwait states associated with the port graph); section/view state (a small message can point at a much larger data plane); handle and context state (per-message metadata can flow without a namespace name); and completion state (asynchronous replies observable through completion-list, event, or I/O-completion style behavior).

Server setup:
    server creates / registers connection port
        |
        v
Client bind:
    client connects to the named endpoint
        |
        v
Kernel session state:
    client communication port <-> server communication port
        |
        v
Exchange:
    request / reply messages
    optional view, handle, context, security, token, or completion attributes
        |
        v
Teardown:
    disconnect, close, queue drain, view/handle lifetime cleanup

The advertised connection port is only the first node. The evidence usually lives in the session graph: which client holds which communication-port handle, which server owns the matching side, whether the message queue behavior matches the claimed service, and which side objects appeared immediately after the connection. A port name that looks ordinary but creates a new page-file-backed section, event, completion port, or process handle in the protected process is not ordinary. The message itself has two layers. The visible body may look like a small opaque binary blob, but the effective message includes header-like metadata, message type, request/reply relationship, sender identity, timeout/cancel behavior, attributes, and side-object lifetime — that is why message-size histograms alone are weak. A 16-byte message can be the entire command, a wake edge for a section mailbox, a handle-transfer envelope, or an RPC method dispatch.

Attacker Mechanics: ALPC as a Brokered Control Plane

A practical ALPC attacker model looks like this. First, advertise or borrow a connection surface — a helper, broker service, injected module, or legitimate-looking local server exposes a connection port (often under \RPC Control\... or behind an RPC/COM activation path). More subtle designs do not expose a fresh obvious name; they reuse a broker that already has a reason to speak ALPC. Second, bind and create per-client state — after connection, the meaningful evidence moves from the named connection port to the connected communication-port handles, per-client context, and side objects. Third, negotiate a small protocol: early messages typically carry magic, version, build number, feature mask, process identity, session nonce, and a descriptor for the real payload channel. Fourth, broker side objects: ALPC message attributes can carry handles, views, security context, or per-message context, letting the channel pass or reference unnamed sections, events, completion ports, jobs, process/thread handles, or other rendezvous objects without placing a stable object name in the namespace. Fifth, separate payload from wake edge: the message body stays tiny while an ALPC data view, page-file-backed section, GPU shared resource, or MDL-backed private buffer carries the real data. Sixth, retire aggressively: mature stacks close the connection port, leave only connected handles, rotate the advertised name, or move from a visible helper to a broker-owned endpoint after bootstrap.

The common cheat shapes are: a private service-looking port created shortly before the protected workload starts; a section-view transport where ALPC messages only carry epochs; a handle shuttle where the message broker-passes section/event/completion/job handles into the game or helper; broker camouflage behind local RPC or COM (lower transport is ALPC, method payloads are opaque blobs); a notification-only channel where arrival order, reply status, timeout, cancellation, disconnect, or thread-terminate port notification carries the state; and kernel-assisted endpoint insertion where a kernel driver duplicates, inherits, or plants a connected ALPC handle into the protected process so the endpoint appears without a clean user-mode parent path. ALPC has attributes especially useful to attackers and especially important to defenders: view/data attributes turn ALPC into shared-memory rendezvous; handle attributes are the unnamed-object broker; context attributes store sequence IDs, correlation IDs, client role, or state-machine phase; security/QoS and token state reveal role mismatches; and direct event and completion state integrate ALPC with thread-pool work (§10.12). Public Windows-internals material exposes ALPC-specific status values such as STATUS_ALPC_CHECK_COMPLETION_LIST, which is a reminder that high-throughput ALPC can look like asynchronous queue traffic rather than a simple blocking loop.

Kernel-Assisted Endpoint Insertion, Spoofing, and Blinding

A kernel component does not have to respect the user-mode story of an ALPC connection. Recent ALPC research (ALPChecker, HITB 2023, arXiv 2024) demonstrates that driver-level manipulation of ALPC structures can create mismatched or illegitimate connection graphs: one side believes it is connected to one peer while messages are routed elsewhere, or a legitimate peer is blinded because messages no longer arrive on the expected queue. Three attacker-relevant variants: endpoint insertion (a connected ALPC handle appears in the protected process without a plausible launcher, broker, COM activation, or handle-duplication lineage); graph spoofing (client-side and server-side views of the connection disagree); and blinding or selective diversion (a legitimate endpoint remains visible but selected messages are consumed, redirected, delayed, or made to arrive at another queue). The defender response is cross-view consistency. For each suspicious ALPC connection, compare namespace port, server process, client process, connection-port object, client communication port, server communication port, handle table entries, message send/receive ETW, wait/reply ETW, VAD/section deltas, and side-object handle transfers. A single view can be spoofed. A coherent graph across all of those views is harder to fake.

Public ALPC/RPC presentations are useful because they show how the same primitive appears in real Windows services, not only in theoretical rootkits. REcon 2008 LPC/ALPC privilege-escalation work framed LPC/ALPC endpoints as security boundaries; HITB 2014 ALPC Fuzzing Toolkit framed ALPC as the substrate below RPC, DCOM, custom raw endpoints, and common Windows services; PacSec 2017 “A view into ALPC-RPC” emphasized RPC-over-ALPC reduction (a suspicious call may be visible as an RPC interface UUID and method number rather than a raw ALPC opcode); DEF CON 32 “ALPC security features against RPC services” reframed ALPC/RPC security metadata as the attack surface. The detection mantra across all of them: capture endpoint name, interface UUID, opnum distribution, NDR payload shape, impersonation behavior, and the handle/view graph together; treat ALPC as a state machine, not a list of names.

2.3 Custom Symbolic Links and Path Identity Confusion

Drivers create object-manager symbolic links via IoCreateSymbolicLink pointing at devices, sections, directories, or other links. A symbolic link is a rendezvous primitive more than a data primitive. Useful tricks: rotating targets, encoding state in link existence/target/open result, or chaining links (visible link → second link with rotating target). Attacker interest centres on namespace placement (per-session \Sessions\...\DosDevices\..., private directories), invisibility to naive resolution, and target rotation. Black Hat Asia 2024 MagicDot research demonstrates that DOS-to-NT path conversion, trailing dots/spaces, short names, and tool-specific path views can create rootkit-like concealment and process identity confusion. The defender’s path inventory must therefore be multi-view: raw input path, normalized NT path, resolved link target, handle-final path, file ID, short-name expansion, section-object path, and process-image path. A scanner that records only one of these will be fooled by a target that presents different identities to different observers.

2.4 Anonymous Named Objects and Private Namespaces

Events, sections, mutants, semaphores, and directories with GUID or random names encode state in presence, name, or wait state. Private namespaces (CreatePrivateNamespace) with boundary descriptors add ambiguity because their visibility depends on an out-of-band agreement. Anonymous handles can be shared via inheritance, duplication, or broker handoff, so the object is real but has no namespace anchor. The high-signal pattern is a protected process receiving an inherited event/section handle from a launcher or unrelated helper after an unknown driver loads. The detector should track handle source (inheritance, duplication, broker), grantor process, grantee process, granted access, and whether the unnamed object subsequently behaves as a wake source or mailbox.

2.5 Symlink Farm Rotation

A rotating set of links defeats single snapshots. Farms maintain stable hidden features even as individual links rotate: same target driver, same parent, same ACL, same name length, same character alphabet, same deletion delay, same target-chain pattern. Evidence is therefore family-level: parent directory, creator, target class, ACL hash, name-shape features, lifetime distribution, creation cadence. Operational signal: high-frequency create/delete rates, transient links during protected workload, only one valid link at a time.

2.6 Hidden Window Properties and Message-Only Windows

SetProp/GetProp attach arbitrary properties to windows. Message-only windows (parent HWND_MESSAGE) carry state in property names, values, class name, or window-class extra bytes. RegisterWindowMessage creates a system-unique message ID for a string, which means registered-message strings double as rendezvous names. The attacker pattern is a service-looking message-only window class, registered message strings that resemble vendor telemetry, and properties as backing state. KM triggers via APC, callback injection, or GUI callback manipulation; UM responds. Suspicious markers: unknown-process-owned hidden or message-only windows, non-standard properties, registered messages with opaque or hex names on windows adjacent to the protected workload.

2.7 Clipboard Custom Format

RegisterClipboardFormatW registers named custom clipboard formats shared UM-to-UM. KM cannot drive the clipboard directly but can trigger via APC, callback, or a foreground-process helper. Custom formats persist per session; the format name itself becomes a rendezvous. AddClipboardFormatListener wakes a window on clipboard changes. Protocol variants: single-slot overwrite, sequence-number-only, delayed rendering, dual-format handoff. Suspicious markers: custom format registration during protected workload, unknown process registering or opening the format, high-entropy data blobs, empty-content formats whose listeners wake in step with helper activity.

2.8 Global Atom Table

GlobalAddAtomW stores up to 255-byte strings in a system-wide atom table and returns a 16-bit atom ID. UM-to-UM by construction; KM drives via APC. Atom names can carry base64/hex/compact commands. Atoms persist until deleted; reference-count behavior encodes presence. The channel is weak but cheap, and a good fit for low-bandwidth configuration and discovery. Markers: base64/hex/compact strings in the atom table, opaque names, per-session-aligned atom churn, correlation with clipboard or window-message names from the same helper.

2.9 Registry as Storage and Trigger

The registry is two channels in one. Storage: values guarded by SACL tricks, restricted SIDs, symbolic-link keys, unusual Unicode (combining, BIDI, NUL-prefix), volatile keys, blocking ACLs. Trigger: UM writes a key, KM callback (CmRegisterCallback) fires, the callback executes a command. The registry is attractive because it is ubiquitous and trivially attributable to legitimate processes. Signal: registry callbacks from unknown drivers (trigger), writes by the protected process outside product scope (channel), ACL/symlink anomalies (storage). Correlating all three signals is what makes the case — the three by themselves are noisy.

2.10 Job Object Limit Notification

Job objects deliver notifications via I/O completion port for limits and lifecycle events: process-start, process-exit, active-process-limit, memory-limit, end-of-job-time. The association is set with JOBOBJECT_ASSOCIATE_COMPLETION_PORT. This is a low-bandwidth lifecycle signaling primitive — the launcher learns the helper is alive, a watchdog confirms heartbeat. Nested jobs create ambiguity. Suspicious: unexpected job membership, completion-port ownership by a non-launcher service, job policy that does not match the baseline for the protected workload.

2.11 Named Pipes (and the Anonymous-Pipe Broker Variant)

One-way or duplex pipes; CreateNamedPipeW creates the server, CreateFile connects the client. Supports multiple instances, overlapped I/O, impersonation, and local or remote reachability. KM opens pipes via native file APIs or through a privileged service translator. The protocol is usually a fixed header, opcode, sequence number, and payload (encrypted, compressed, padded). Attackers reverse the usual direction: KM writer, UM reader. The Black Hat USA 2020 Windows rootkit work documents the more subtle anonymous-pipe broker variant: the kernel brokers a user-mode process, the channel rides on inherited or duplicated unnamed pipe handles used as standard I/O, and there is no \Device\NamedPipe entry to inventory. The evidence fields are inherited-handle source, duplicated-handle source, standard-handle object type, pipe file-object name, helper command line, lineage, byte count, exit status, and any next-stage rendezvous text in the helper’s output. The high-signal pattern across both variants is pipes created after launch by unknown helpers, game-process clients to unrelated-vendor pipe servers, remote-capable local-only pipes, fixed-size packets, high-entropy payloads, and handle duplication immediately before pipe traffic.

2.12 Local RPC, COM, and Endpoint-Mapper Camouflage

RPC adds a structured client/server model with interface UUID, endpoints, authentication, impersonation, and an endpoint mapper. COM adds activation, class registration, local servers, and brokers. Local RPC may ride ALPC, named pipes, or other transports. The lowering converts a suspicious binary protocol into normal-looking method calls. Five layers matter: interface contract (UUID/version/method identity), stub/NDR (marshaling), binding (handle describing endpoint location), endpoint (transport-specific), and security (authentication/impersonation/permissions).

Server:
    define interface UUID/version and methods
    register protocol sequence and endpoint
    register interface and optional security callback
    optionally register binding vector with endpoint mapper
    listen / dispatch calls

Client:
    discover endpoint directly, through COM activation, or through endpoint mapper
    create binding handle
    optionally set authentication and security QoS
    call interface method through client stub
    receive output parameters and return status

Endpoint mapper and dynamic endpoints are the classic trick: a stable interface UUID with a rotating endpoint per launch defeats static IOC matching. The helper looks like a service registering a normal local RPC endpoint; suspicious data lives inside method payloads. Late binding lets a protected-workload-adjacent module discover the endpoint at runtime. Multi-transport fallback and short-lived endpoint windows during launch, license, or session further reduce evidence. RPC security/impersonation can itself be the channel surface — role mismatch is the tell: a service-looking endpoint accepting anonymous, low-integrity, or unexpected callers; impersonation enabled without a documented reason; a port name that claims system ownership but is created by a per-user helper. Six protocol shapes recur in the wild: opaque method blob, method-number protocol, context-handle session, endpoint-map rendezvous, COM local-server disguise, and privilege-broker helper. Signals: per-user helper registering a private port before the game connects; protected-workload clients to unrelated service endpoints; endpoint-map churn; role mismatch (authentication level, impersonation, broad local callers); fixed-size or high-entropy method payloads; newly reachable lower transport (ALPC, pipe, socket) appearing after the RPC bind.

2.13 IPC Deep-Dive Matrix: State, Lifetime, and Evidence

Every IPC channel passes through a five-stage state machine: advertise (create name/object), discover (probe by name or enumerate), bind (open handle, connect, register), exchange (state moves), and retire or rotate (delete, rename, orphan). Detectors store all five stages, not single snapshots. The strongest evidence packages combine a short-lived per-user helper registering a private port, a protected-process or helper endpoint handle, a connection that follows driver load by milliseconds, fixed binary message cadence, section or handle transfer near connection, and no vendor manifest that explains the mimicked namespace.

3. System-Information and Kernel-Reflection Channels

The OS exposes a lot of itself to user mode. Firmware tables, system performance counters, big-pool metadata, kernel-shared data, ETW providers, WNF state, performance counter providers: all of these are normal surfaces that normal tools query constantly. A cheat that hides command and data inside these queries inherits both the volume of legitimate traffic and the OS’s own implementation noise.

3.1 Firmware Table Provider Hijacking

Windows lets user mode query firmware-backed data (ACPI, SMBIOS, raw firmware tables) through EnumSystemFirmwareTables, GetSystemFirmwareTable, and the native NtQuerySystemInformation(SystemFirmwareTableInformation) path. Internally the kernel maintains a list of firmware-table provider handlers, addressable by a 4-byte provider signature. A driver can register a new provider, replace an expected provider’s handler, or simply hook the dispatch in nt!NtSetSystemInformation and use ordinary user-mode firmware-table queries as a command-dispatch path. The SYSTEM_INFORMATION_CLASS values are concrete on current Windows 10/11: SystemFirmwareTableInformation is the query class for NtQuerySystemInformation and equals 76 (0x4C); SystemRegisterFirmwareTableInformationHandler is the set class for NtSetSystemInformation and equals 75 (0x4B). Both numeric identifiers should be build-validated.

 typedef NTSTATUS (__cdecl *PFNFTH)(
    IN OUT PSYSTEM_FIRMWARE_TABLE_INFORMATION SystemFirmwareTableInfo);

typedef struct _SYSTEM_FIRMWARE_TABLE_HANDLER
{
    ULONG       ProviderSignature;
    BOOLEAN     Register;
    PFNFTH      FirmwareTableHandler;
    PVOID       DriverObject;
} SYSTEM_FIRMWARE_TABLE_HANDLER;

typedef struct _SYSTEM_FIRMWARE_TABLE_INFORMATION
{
    ULONG       ProviderSignature;
    SYSTEM_FIRMWARE_TABLE_ACTION Action;
    ULONG       TableID;
    ULONG       TableBufferLength;
    UCHAR       TableBuffer[ANYSIZE_ARRAY];
} SYSTEM_FIRMWARE_TABLE_INFORMATION;

Registered Firmware-Table Provider Command Channel

Microsoft documents the normal provider signatures as ACPI, FIRM, and RSMB. The abuse pattern relies on the private kernel registration path behind SystemRegisterFirmwareTableInformationHandler: a driver registers a new provider handler, then user mode queries that provider through the ordinary firmware-table API or through the native system-information path. The registration is the part that often gets missed — a driver does not need to patch GetSystemFirmwareTable, create a device object, or hook NtQuerySystemInformation. It calls ZwSetSystemInformation with class SystemRegisterFirmwareTableInformationHandler and a SYSTEM_FIRMWARE_TABLE_HANDLER record containing the attacker-chosen provider signature, the Register flag, the handler pointer, and an owner-looking DriverObject. The surface looks like a normal firmware-table provider rather than a hook; the command channel only appears later when the user-mode control module queries the provider.

A critical detector trap: the DriverObject field is easy to overinterpret. In current Windows 10/11 observations, the registration path does not make DriverObject a strong proof that the handler belongs to a legitimate, live driver stack. The value is used internally more like an owner key for provider registration/removal and association than like a complete trust anchor. A registration can be made with a borrowed, stale, spoofed, or otherwise non-authoritative DriverObject value even when the real communication logic lives in a different handler target. Production detectors must treat the supplied DriverObject as attacker-controlled metadata until independently validated — the handler pointer and its first-hop/chain target are the evidence; the DriverObject is only a claimed owner.

Attacker Mechanics: Firmware Query as Mini RPC

A firmware-table provider works like a small RPC endpoint hidden behind hardware-inventory vocabulary. The provider signature is the service name, EnumSystemFirmwareTables is discovery, GetSystemFirmwareTable is the request, the table ID is the method selector, the requested size is a negotiation field, and the returned blob is the reply. Nothing in that model requires a user-openable device object or a custom IOCTL path. The semantic borrowing is the attacker benefit: the call stack, API name, and object category all say “platform inventory,” while the handler’s private interpretation says “command bus.” The command grammar is compact but expressive: provider signature as namespace, enumeration as handshake, table ID as opcode, buffer length as side channel (the normal two-call ask-size then ask-data pattern gives a request/response rhythm where required and returned sizes encode readiness, error class, or result length), output table as reply buffer. For larger UM→KM uploads, firmware queries usually become the trigger and reply path while a section, registry value, WNF state, or MDL-backed buffer carries the input payload.

3.2 SystemFirmwareTable Handler Inline Hook

A close variant of §3.1: rather than registering a new provider, the cheat patches an existing legitimate firmware-table handler (a SMBIOS or ACPI handler) and forwards all but the magic requests. The UM side continues to call the standard firmware-table API, with a magic provider signature, table ID, or buffer pattern in the request. Trade-off: provider registration is a clean data-side modification visible to a provider-list inventory but not to code-integrity checks; inline hooking is harder to enumerate from the provider list because the provider entry still looks normal, but it is detectable by code-integrity checks against the handler’s prologue and is more likely to collide with PatchGuard or HVCI. The hook can live at several depths: entry prologue patch, interior branch patch, data-side handler pointer swap, or table-data tamper.

3.3 NtQuerySystemInformation Return-Value Manipulation

NtQuerySystemInformation returns dozens of structures with reserved fields, alignment padding, tag bytes, counters, and address-like metadata. A kernel component can intercept the path or modify the underlying data so that selected fields on selected classes carry command material. Signal-to-noise is favourable: these classes are queried by every system inventory tool, launcher, anti-cheat, and EDR. Abusable classes: SystemPerformanceInformation (0x02) — spare and reserved fields in SYSTEM_PERFORMANCE_INFORMATION; SystemProcessInformation (0x05) — reserved fields inside SYSTEM_PROCESS_INFORMATION; SystemPoolTagInformation (0x16) — 4-byte pool tags as direct payload; SystemExtendedHandleInformation (0x40) — reserved or layout-dependent fields; SystemBigPoolInformation (0x42) — tag and address metadata. Three independent detection checks: direct hook integrity on nt!NtQuerySystemInformation and its inner class dispatchers; return-buffer consistency against an independent kernel view (compare returned SYSTEM_PROCESS_INFORMATION against PsLookupProcessByProcessId for each PID; mismatches in reserved fields are a direct signal); and value plausibility (reserved fields should be zero in current build encodings; non-zero values, especially with high entropy or game-specific magic constants, are the channel payload).

3.4 SystemBigPoolInformation Metadata Channel

A driver allocates Big Pool memory with a distinctive tag (XCHT, DvSc, anything four bytes) and user mode calls NtQuerySystemInformation(SystemBigPoolInformation) to enumerate Big Pool allocations. The tag acts as a lookup key; the returned address-like metadata describes the rendezvous structure. This is most commonly used to announce the endpoint of another channel rather than to carry payload directly. The channel can encode more than the tag: tag as family ID, size as selector, presence as state, churn as clock, address-like metadata as descriptor. The most robust designs use Big Pool only for rendezvous — once UM discovers the tag and size, it switches to a section, GPU resource, firmware-table provider, registry trigger, or driver dispatch path for actual payload transfer.

3.5 Windows Notification Facility (WNF)

WNF is a kernel-backed publish-subscribe state notification system. Components publish state changes; subscribers receive notifications without polling. It is used heavily inside Windows itself, including shell, networking, power, Store, and accessibility paths, and remains the hardest covert IPC surface for traditional anti-cheat to inventory because subscriptions and publishers do not live in the object namespace the same way named objects do. The cheat can publish a state name and have UM subscribe, subscribe to a state name and have the UM side publish, or use the presence and version increments of a state as a one-bit signal. The Black Hat USA 2018 WNF research is the reason this surface deserves more than a footnote: WNF is not just a notification bit but a kernel-backed state system with producer/consumer relationships, payload storage, security descriptors, per-state lifetime, and kernel/user boundary crossing. A published state can carry a payload up to the WNF implementation’s small-blob limit, can be read by consumers after publication, and may be permanent. That gives attackers three useful dimensions: notification as trigger, state version as sequence number, payload bytes as data.

Channel shapes: volatile state mailbox (UM publishes a private state name, KM or another UM component subscribes and treats updates as commands); kernel-consumer trigger (KM owns a consumer path, UM publication wakes the kernel side without opening a custom device object); persistent state rendezvous (a permanent state stores configuration or rendezvous data across restarts); system-state mimicry (names chosen to look like shell, Store, power, network, or feature-management state); payload parser abuse (some legitimate consumers parse WNF payloads as structured data, which is a reminder that a 4 KB-ish opaque blob inside WNF can be a real payload, not just a notification). Obfuscation: WNF state names are encoded rather than stored as plain strings. Public reversing documents XOR-style decoding with the historical key 0x41C64E6DA3BC0074 on older Windows 10 builds, but this is private implementation detail, not a stable contract.

3.6 KUSER_SHARED_DATA Field Manipulation

KUSER_SHARED_DATA is mapped read-only into user mode at 0x7FFE0000 (x64 and x86 alike) and is mapped writable in kernel mode at the system shared-data address. It carries time, version, mitigation, processor, and system state used by user-mode paths that want to avoid syscall overhead. Some fields are spare or reserved across builds and are not consistency-checked by anything observable to user mode. A driver writes a selected field; user mode reads the shared page at 0x7FFE0000 + offset. No object, no handle, no socket, no section. Limits: bandwidth is low and the surface is brittle. The viable command shapes are tiny: one-bit gate, epoch counter, selector nibble, or timing distortion. Detection: baseline fields that should remain stable on a given build, monitor reserved fields for non-zero or high-entropy values, cross-check semantic fields against independent sources.

3.7 ETW Provider and Session Abuse

ETW is designed for high-throughput event delivery. The documented model is provider→session→consumer: user-mode and kernel-mode components register as providers, controllers configure sessions, consumers receive events in real time or from trace files. That makes ETW a natural KM→UM or UM→UM data channel. It is not, by itself, a clean documented UM→KM command channel unless the driver abuses an enable/control callback. Abuse patterns split by direction: KM-provider-to-UM-consumer emits command replies or memory snapshots; UM-provider-to-UM/KM-aware-helper emits events to a private session; enable-callback triggers fire on enable/disable cadence; trace-file persistence turns ETW into a durable queue. Stealth comes from role confusion — security products, game engines, GPU profilers, crash reporters, and launchers all create sessions and providers. Inventory active ETW sessions during protected workload runtime: session name, logger mode, controller PID, consumer PID, provider GUIDs, provider image, keywords, level, stackwalk flags, buffer size, dropped-event count, private-vs-system session, file destination.

3.8 PcwRegister Performance Counter Channel

PcwRegister registers a kernel-side performance counter provider. User mode reads counters through normal performance-query paths; the values returned are whatever the provider chooses to publish. A cheat can encode low-bandwidth state in counter values and have UM read it as if it were ordinary system telemetry. This is a slow surface; performance counter queries are not high-frequency. It is still a legitimate metric channel, which makes attribution difficult. The practical channel is low-frequency control state: enable flag, current epoch, target process ID, shared-section generation, last scan result, or license status.

3.9 Process Mitigation Policy as Storage

Process mitigation policy structures contain reserved or weakly validated bit fields. The documented user-mode API is SetProcessMitigationPolicy / GetProcessMitigationPolicy with PROCESS_MITIGATION_POLICY values such as ProcessDEPPolicy, ProcessPayloadRestrictionPolicy, and ProcessSideChannelIsolationPolicy. Carrying capacity: PROCESS_MITIGATION_DEP_POLICY is 8 bytes (DWORD Flags + BOOLEAN Permanent with natural alignment padding); PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY is 4 bytes; PROCESS_MITIGATION_SIDE_CHANNEL_ISOLATION_POLICY is 4 bytes. The reserved-bit surface for storage is the union bitfields of the 4-byte policies and the BOOLEAN Permanent tail of the 8-byte DEP policy.

3.10 Reflection Deep-Dive Matrix

System-reflection channels are attractive because they invert the usual detector mindset. The user-mode side appears to be asking Windows ordinary questions: “what firmware table exists?”, “what big pool allocations exist?”, “what WNF state changed?”, “what counters are available?” The covert protocol is hidden in the answer, in the side effects of asking, or in the kernel callback the question triggers. Treat every technique in this section as a protocol with four fields: selector, caller identity, returned buffer, and kernel-side producer. Cross-view comparison is what closes most cases — if user mode sees one process/module/handle view while a kernel walker, ETW, or hypervisor view sees another, the channel or hide path becomes visible.

4. Documented KM-UM Mediation Surfaces

The surfaces in §2 and §3 reuse OS primitives that were never intended as a driver’s primary IPC. The surfaces in this section are the official or contract-adjacent KM-UM paths Microsoft documents and supports: Filter Manager communication ports, device-interface GUIDs, WMI providers, Winsock Kernel, WFP callouts, virtual HID / VHF, keyboard and mouse class-filter callback paths, eBPF-style maps, user-mode file-system provider callbacks, and the NLS file-section trick. Cheats favor them because the surface is legitimate by construction.

4.1 Filter Manager Communication Ports

A file-system minifilter creates a communication port via FltCreateCommunicationPort. User mode connects through FilterConnectCommunicationPort and exchanges structured messages. Filter Manager handles serialization, security, and message-buffer lifetime: the driver gets a clean message API without having to ship its own IRP-level IPC. The cheat plays the role of a minifilter without any plausible file-system function. The driver may register a callback for a frequently fired operation (open, create, query) so the surface looks busy, or it may register only the port and treat the port itself as the only artifact. The channel has two planes: the registration plane (minifilter name, altitude, instance attachment, operation callbacks, port name/security descriptor) and the data plane (connection, message buffers, replies, timeouts, disconnects). Altitude matters: a file-security product at an expected altitude with matching install provenance is normal; a driver choosing a security-like altitude but registering no meaningful file operation callbacks, or registering only a port with a vague name, is role-mismatched.

4.2 IoRegisterDeviceInterface Custom GUID

A driver can register a device interface with IoRegisterDeviceInterface using a custom GUID, then expose it to user mode by enabling the returned symbolic-link name with IoSetDeviceInterfaceState. User mode discovers the enabled interface through SetupAPI (SetupDiGetClassDevs, SetupDiEnumDeviceInterfaces, SetupDiGetDeviceInterfaceDetail) and opens the resulting device path with CreateFile. This is still a device channel, but it is hidden behind interface discovery rather than a hand-written symbolic link, and the GUID can be chosen to resemble a vendor or OEM device class. An attacker can also keep the interface registered but disabled until protected-session runtime, then enable it only long enough for the helper to discover and open it.

4.3 WMI Registration

Drivers register WMI providers via IoWMIRegistrationControl and WmiSystemControl, exposing one or more GUIDs and handling query, set, and event-notification requests. User mode queries through WQL or subscribes to provider events. An attacker hides a command channel inside provider queries, event notifications, or custom data blocks. Microsoft’s driver WMI model explicitly supports custom data, configuration through a standard interface, driver-defined events, and consumer-visible data/event blocks — exactly the cover an attacker wants.

4.4 WSK Loopback and External Egress

Winsock Kernel lets kernel components use socket APIs. An attacker driver opens a WSK socket and connects to (or accepts from) 127.0.0.1 / ::1; the user-mode side uses ordinary Winsock APIs against the same loopback endpoint. Compared to a custom device IOCTL path, this looks like network activity, supports reliable or datagram semantics, and can be proxied through helper processes for additional indirection. It is one of the most operationally common L2 channels in commodity cheat ecosystems, and the same ownership problem applies to malware loaders and rootkits. Voice chat, telemetry collectors, web UIs, and debugging tools all open loopback sockets. Variants include simple UM-listens / KM-connects setups, reverse setups (kernel listener, UM connects), datagram mode that encodes commands in packet size and source port, and helper-side proxying to a named pipe, section, or remote controller.

Kernel-Resident License, REST-Like, and Configuration Fetch

Recent game-cheat stacks sometimes move licensing, subscription state, hardware-profile checks, and user configuration into the kernel side; malware and rootkit families use the same shape for C2 policy, module retrieval, proxy state, and kill switches. Instead of asking a user-mode loader to fetch configuration and pass it down, the driver opens an outbound socket itself and talks to an external server. The wording “REST API from kernel” is usually imprecise. Windows gives kernel drivers WSK, a socket-style network programming interface. It does not give arbitrary kernel drivers the same high-level WinHTTP/WinINet/Schannel convenience stack that normal user-mode REST clients use. A kernel cheat tends to choose one of: raw TCP control plane (compact binary protocol carrying license token, HWID hash, build ID, feature bitmask, encrypted config blob); HTTP-shaped request over WSK (a minimal GET or POST built by the driver — the static artifact can be very plain code that appends header strings such as Content-Type: application/json, calculates their length with strlen-style helpers, then concatenates a JSON body with license/HWID/product/build/feature fields); TLS-in-kernel or pseudo-TLS; UM-resolver/KM-connector split; and kernel egress as watchdog. The channel is not just C2 but a configuration authority that changes how the kernel driver behaves — a single outbound request can return offsets, encrypted strings, callback altitudes, provider signatures, WFP filter IDs, feature masks, or target process names which the driver then uses to arm other channels.

4.5 NLS File Page Sharing

This surface is not an official IPC API, but it uses official file mapping behavior. NLS files are mapped into many processes by Windows itself; a kernel-side attacker can modify the underlying section pages so that a normal user-mode mapping of an NLS file becomes a covert payload buffer. The suspicious event is not a game mapping an NLS file at startup but a writable or modified view of a protected NLS-backed section, especially if the dirty page is later observed by the game or helper.

4.6 Windows Filtering Platform Callout Channels

WFP is Windows’s documented packet/flow filtering surface. Providers register, sublayers contain filters, filters carry conditions and weights, and callouts let a driver inspect, modify, drop, inject, or absorb packets at well-defined classification layers. WFP defense requires both management-plane and dataplane evidence. Management-plane inventory covers providers, sublayers, filters, conditions, weights, provider contexts, callout GUIDs, dynamic sessions, and persistence. Dataplane evidence covers classify layer, flow key, ALE endpoint, packet tuple, action, pend/complete behavior, injection/absorb behavior, and target driver. A WFP command channel usually has a management-plane artifact that looks like a security product and a dataplane pattern that only touches game or loopback traffic. If an unknown callout classifies only the game’s loopback flow and never behaves like a firewall, VPN, or EDR, the role mismatch is the evidence.

4.7 Virtual HID, VHF, and Class-Input Callback Channels

Virtual HID Framework (VHF) drivers expose synthetic input devices. From the host’s perspective, a microcontroller-emulated mouse and a VHF-backed virtual mouse can look very similar. Three identities matter: PnP identity (VID/PID/container/serial/INF/service/signer); HID descriptor identity (usage page, usage, report IDs, feature/output/input report lengths, logical min/max, units, vendor-defined collections); and behavioral identity (report cadence, axis/button plausibility, entropy in unused bits, feature-report traffic). A VHF-backed device that claims to be a simple mouse but exposes large vendor-defined feature reports should not be treated as normal input hardware.

Class-Service Callback Hijack: MouClass / KbdClass

The class-input side has a different evidence model: keyboard/mouse device stack, class upper filters, IOCTL_INTERNAL_*_CONNECT handling, cached CONNECT_DATA, callback target, callback context, packet cadence, and whether the target lands in Kbdclass/Mouclass or a documented filter function. UnknownCheats-style discussions show driver-level mouse and keyboard injection through Mouclass-style callbacks gaining traction as an alternative to VHF or user-mode SendInput. A hidden callback swap in an existing stack may leave no new HID device at all, so virtual-device inventory and class-service callback validation must be separate checks.

4.8 eBPF for Windows Maps and Ring Buffers

The runtime should be inventoried only when present, but when present it deserves WFP-level treatment. Record loaded programs, attach types, links, maps, map types, key/value sizes, ring/perf buffers, pinned objects, controller process, service identity, verifier/log state, and driver/runtime version. A map is not a finding; a map with opaque fixed-size values updated by a workload-adjacent controller and consumed by a kernel-resident program is a channel.

4.9 Cloud Files, ProjFS, and User-Mode File-System Provider Callbacks

Treat provider-backed file paths as callback endpoints. Microsoft documents Cloud Files CfConnectSyncRoot as a bidirectional provider/filter channel and ProjFS as a callback-driven virtualization provider model. Record sync root or virtualization root, provider image, callback table registration time, reparse tag, placeholder state, triggering process, callback type, byte range, status, and returned-data shape. A path read is not just a file read if it crosses into a provider callback.

4.10 Mediation Deep-Dive Matrix

Official KM-UM mediation surfaces are easier to defend than private hooks because they create registration artifacts. Do not stop at “the primitive exists.” Store the tuple that explains the channel: registered surface, owner image, security descriptor, user-mode consumer, payload shape, teardown behavior. For each surface (FltMgr ports, device-interface GUIDs, WMI providers, WSK egress, NLS, WFP callouts, virtual HID, eBPF, Cloud Files/ProjFS), the high-signal pattern is consistent: a workload-adjacent driver or service with no plausible product role registers the primitive, the protected workload consumes it during runtime, and the message/data shape is more fixed-size or opaque than ordinary traffic.

5. Kernel Callback Infrastructure

Windows exposes a rich set of kernel callback APIs for security products, anti-malware, debuggers, and instrumentation tools. Each of them is a signal channel: a UM operation reaches a kernel code path that calls a registered callback. An attacker registers in the same slot, treats the event as a command trigger, and either takes action in kernel mode or returns a value that influences the operation. The defender’s problem is that legitimate registrations look identical to malicious ones at the API level — what changes is the owner driver, the callback target, and the response behavior.

5.1 PsSetCreate Process/Thread/LoadImage Notify Arrays

Windows maintains arrays of registered notify routines for process creation (PsSetCreateProcessNotifyRoutineEx), thread creation (PsSetCreateThreadNotifyRoutine), and image-load events (PsSetLoadImageNotifyRoutine). Each is an array of slots; each slot is an EX_FAST_REF-wrapped pointer to a callback block. The expansion from 8 slots to 64 slots landed in Windows 8 (NT 6.2, build 9200), not in Windows 10 1507 (build 10240). Detection code that uses 10240 as the cutoff will undercount callbacks on Windows 8 and 8.1. The correct cutoff is ULONG max = (osBuildNumber >= 9200) ? 64 : 8;. The EX_FAST_REF mask is ~15 on x64 and ~7 on x86; the lower bits are reference counts. The same arrays are also a tamper surface — an attacker may not register its own callback but instead overwrite a legitimate slot’s pointer with its own trampoline, forwarding the original on the way out. The strong detection signal is “callback target outside any signed module” or “callback target inside a signed module but at an address that does not match the on-disk function bytes”; the second pattern catches in-place hot-patching of a legitimate callback.

5.2 CmRegisterCallback Registry Callbacks

CmRegisterCallback and CmRegisterCallbackEx give drivers a registry-operation notification path. The attacker uses it as a command-trigger surface (UM writes a value, KM receives a callback and decodes the path or data), as a defensive shield (KM denies access to registry keys that defenders inspect), or both. A registry callback channel is easiest to understand as a private syscall ABI built out of a normal configuration write: the key path is the service selector, the value name is the stream selector, the value type is an opcode field, the data buffer is the argument block, and the callback return path is the status. The protocol usually splits into four layers: a path gate that activates only for one normalized key path or hive; selector fields (value name, raw type, data size, transaction state, optional desired final status); an argument block that carries inline arguments or a pointer/handle/nonce identifying a companion payload channel; and a reply and acknowledgement path that uses the callback’s returned status, a modified value, a second registry read, a size mismatch, an event signal, or a later write to a paired value.

Undocumented Registry Value-Type Command Channel

One particularly quiet variant uses the registry value type as part of the protocol. RegSetValueExW and ZwSetValueKey both take a caller-supplied type field (dwType / Type). Microsoft documents the normal REG_* values in winnt.h, but the registry callback path passes the attempted write to the filter as a raw ULONG Type inside REG_SET_VALUE_KEY_INFORMATION, along with ValueName, Data, and DataSize. A filter registered with CmRegisterCallbackEx can therefore treat a write that uses a non-standard or undocumented type value as a command, even if the value name and data look boring. The pre-operation callback consumes the attempt before it is committed, so a registry scanner that examines only committed values will miss the channel entirely.

Callback-Context Gadget Masking

The more sophisticated version hides the callback source itself. A registry callback routine has the generic EX_CALLBACK_FUNCTION shape: the first argument is the callback context supplied at registration time, the second argument identifies the registry operation, and the third argument points to the operation-specific structure. On x64 Windows, the first argument is delivered in RCX. If a cheat registers a callback routine pointer that lands on a tiny kernel-resident gadget such as jmp rcx, the callback list appears to point into ntoskrnl or another trusted kernel image. At invocation time, the gadget transfers execution to the callback context value, which can point at the cheat’s real handler. That breaks the common detector shortcut “callback function pointer inside ntoskrnl == safe.” For this pattern the registered function pointer is intentionally safe-looking; the suspicious object is the pair: registered callback function points to a trusted-image gadget, callback context points to an untrusted executable target or dispatcher. Detection must inspect more than the callback routine address: disassemble the registered callback routine target even when it is inside ntoskrnl; flag one-instruction or short gadget targets such as register-indirect jumps/calls; record the callback context pointer and classify it; and pair gadget detection with altitude and owner attribution.

5.3 ObRegisterCallbacks

ObRegisterCallbacks registers pre-operation and post-operation filters on handle creation and duplication for specific object types. Cheats use it three ways: defensive (strip PROCESS_VM_READ, PROCESS_QUERY_INFORMATION, or THREAD_GET_CONTEXT when anti-cheat opens the cheat process); offensive (enumerate existing callbacks and re-register so the cheat’s callback runs first); communication (intercept handle requests that match a magic shape and decode as a command). The supported object types are narrower than older documentation suggests: on Windows 7 and later, ObRegisterCallbacks supports PsProcessType and PsThreadType; Windows 10 1607 and later add ExDesktopObjectType. File, Section, Event, and most other object types are not supported and the registration fails outright.

5.4 Minifilter Callback Registration

A minifilter registers pre- and post-operation callbacks via FltRegisterFilter. The cheat can use a fake or low-altitude minifilter and treat a magic file path, extension, operation type, or buffer length as a command trigger. When the magic operation appears, the callback handles the command and returns FLT_PREOP_COMPLETE_REQUEST so that the underlying file I/O never happens: the file path is purely a trigger string, not a real file. The trigger can be surprisingly rich: normalized file name, stream name, create disposition, desired access, share mask, file attributes, EA length, reparse point behavior, read/write length, or final status. A UM helper can issue a create against a path like C:\ProgramData\Vendor\cache\{opcode} and the file never needs to exist. The callback sees the path and metadata, decodes the command, completes the operation with a synthetic status, and the helper interprets that status as the reply.

5.5 PoRegisterPowerSetting and PnP Notifications

Power-setting callbacks (PoRegisterPowerSettingCallback) and PnP notifications (IoRegisterPlugPlayNotification) deliver system lifecycle, device arrival/removal, and power-state changes. A cheat uses these as low-frequency signals or to coordinate initialization and teardown around anti-cheat startup. Low frequency is the attraction — an IOCTL loop is loud; a power-state notification fires once when the system enters or leaves a state, which is plenty for “anti-cheat is starting” or “the DMA device just arrived.” This channel is often invisible if defenders only look for continuous IPC — it fires at launch, device plug, display wake, lid/power events, docking transitions, or interface arrival and then goes quiet.

5.6 KeRegisterBugCheckCallback

Bugcheck callbacks run during crash processing. They are not a viable runtime channel; by the time the bugcheck callback runs, normal kernel services are gone. They are still useful for cleanup, anti-forensics, and persistence hints. A driver may register a bugcheck callback that wipes evidence, marks a state file, or alters crash-time artifacts before the dump is written. KeRegisterBugCheckReasonCallback is more operationally interesting than the older raw callback form because it carries a reason and component string and can add secondary dump data. A driver that combines bugcheck callbacks with registry shielding, dispatch patching, or large-page shellcode is building an anti-forensics package rather than a normal telemetry feature.

5.7 KeRegisterBoundCallback

Bound callbacks are an obscure, undocumented callback path used by the kernel to deliver #BR (Bound Range Exceeded) exceptions. They are legacy, rarely used by legitimate software, and useful to cheats as a fallback trigger surface: a place to put a callback that is unlikely to collide with any well-known security product’s monitoring. The legitimate population is essentially empty on modern Windows; any registration during protected workload runtime should be treated as high-confidence unauthorized activity until proven otherwise.

5.8 Callback Deep-Dive Matrix

Callbacks are powerful because they make the cheat look event-driven instead of polling. A detector needs to preserve three things for every callback: where the callback is registered, what order it runs in, and what user-mode action can trigger it. For Ps process/thread/image callbacks, correlate callback firing with process/thread/image events and downstream actions. For registry callbacks, store altitude, owner, target function, target function-entry classification, gadget classification, callback context pointer, operation classes observed, raw value type, value data size, blocked paths, modified output parameters, and per-process deny behavior. For Ob callbacks, controlled handle-open probing reveals access-mask rewriting. For minifilter callbacks, capture the file path and final status when workload-adjacent processes touch unusual names. For power and PnP callbacks, the detection value is in pairing with hardware events. For bugcheck and bound callbacks, the legitimate population is small and registration alone is meaningful evidence.

6. Driver Object and Dispatch Surface

A DRIVER_OBJECT is a small struct with very specific abuse value: it carries the MajorFunction dispatch table, the FastIoDispatch pointer, the device-object list, and a few other fields that influence how every I/O request reaches the driver. Patching any of them gives an attacker the ability to redirect entire categories of user-mode operations into its own code.

6.1 IRP MajorFunction Patch

Every DRIVER_OBJECT carries a 28-entry MajorFunction table. An attacker patches one or more entries in an existing legitimate driver object so that file operations or IOCTLs against that driver are diverted into attacker-controlled code. The user-mode side opens the legitimate device and sends what looks like an ordinary file or IOCTL request. Common targets are IRP_MJ_CREATE, IRP_MJ_CLOSE, IRP_MJ_DEVICE_CONTROL, IRP_MJ_READ, and IRP_MJ_WRITE. The traffic appears to target a legitimate driver; no new suspicious device object is required. The protocol fields can be spread across normal IRP metadata: create path and options encode a selector; IOCTL code and transfer shape supply opcode, input length, output length, transfer method, and output status; read/write length and offset encode command IDs while the actual payload lives in a shared buffer; MDL and buffer provenance give a one-time bootstrap; completion status, IoStatus.Information, and output-buffer length form a compact reply plane.

Existing-Driver Stack Proxy and IRP_MJ_INTERNAL_DEVICE_CONTROL

UnknownCheats-style discussions often frame this as “do not expose your own IOCTL device; proxy through something that already exists.” Windows uses IRP_MJ_INTERNAL_DEVICE_CONTROL for communication between paired or layered kernel-mode drivers, especially class/port stacks such as keyboard, mouse, storage, video, and bus drivers. User mode does not normally send internal IOCTLs directly, but a cooperating or hijacked kernel component can build an internal-device-control IRP to a legitimate lower driver and encode state in the IOCTL code, input buffer shape, MDL, completion timing, or output status. Camouflage options: external-looking user-mode trigger with internal kernel path; class/port stack piggybacking; completion-status mailbox where the attacker-owned filter rewrites IoStatus.Status or Information and uses the completion as a small reply path. “No suspicious device handle” is not proof that driver communication is absent — a UM event can be only the front door; the real protocol runs between drivers after the first hook fires.

File-Object DeviceObject Swap and AFD Socket Channels

Black Hat USA 2020’s “Demystifying Modern Windows Rootkits” describes a more selective alternative to patching a global dispatch table: redirect the DeviceObject pointer inside a specific FILE_OBJECT. The rootkit-focused example targets socket handles backed by AFD, the Ancillary Function Driver for Winsock. Instead of changing \Driver\Afd‘s MajorFunction table or placing a code hook in AFD, the attacker changes the per-file-object routing so I/O for one chosen socket reaches attacker-controlled device/driver state first. The communication technique is per-handle route substitution. A normal-looking socket handle becomes the rendezvous object, the FILE_OBJECT->DeviceObject relationship becomes the control edge, and ordinary socket IRPs, completion status, packet timing, or stream bytes become the selector/reply plane. This removes the obvious artifacts defenders usually hunt: no custom device handle, no global AFD dispatch patch, no suspicious listening port required, per-socket selectivity, protocol camouflage. The detection mistake is to validate only driver-object dispatch pointers; the corrupted pointer is in a FILE_OBJECT, not the global DRIVER_OBJECT.

6.2 FastIoDispatch Pointer Patch

File-system and storage-related drivers expose a FastIoDispatch table: a parallel dispatch path for high-frequency operations that bypass the IRP dispatch. An attacker patches entries (fast read, fast write, fast query, fast device control) to divert operations through attacker-controlled code without going through IRP_MJ_*. This is checked less often than MajorFunction. Many anti-cheat drivers validate MajorFunction entries but skip FastIoDispatch, while the I/O manager and file systems may consult fast I/O paths for cache-friendly operations — a patched fast I/O routine gives the attacker a less-watched trigger tied to ordinary file activity.

6.3 Driver Object Extension

IoAllocateDriverObjectExtension attaches extension data to a DRIVER_OBJECT under a client identification address. An attacker attaches data to a legitimate-looking driver object and later retrieves it using the same client ID. The data can hold keys, pointers, state flags, or a rendezvous descriptor: anything the attacker wants to keep associated with an existing kernel object rather than in its own driver’s globals. Microsoft documents that the extension is resident storage, accessible from any IRQL, keyed by ClientIdentificationAddress, and automatically freed when the driver object is deleted. The abuse becomes stronger when the target driver object is not the attacker’s own object — attaching state to a system, storage, GPU, null, ACPI, or vendor driver creates misleading locality.

6.4 ntoskrnl Multi-Stage Chain Hook

Naive MajorFunction and .data pointer validation checks ask “is the target inside ntoskrnl?” A multi-stage chain hook satisfies that check on the first hop while ultimately branching to attacker-owned code. The intermediate stages stay within legitimate-looking kernel ranges; the final stage branches out.

   patched dispatch entry
            |
            v
   trampoline 1   <- inside ntoskrnl .text alignment slack
            |
            v
   trampoline 2   <- inside hal .text or a signed driver
            |
            v
   attacker code  <- outside any signed module

For high-risk pointers, disassemble the target’s first few instructions and chase short branch chains. Compare target bytes and short-range control-flow against a clean build. Randomize scan timing: an attacker that restores the chain between scans can be caught when the scan windows are not predictable. HVCI plus Memory Integrity reduce the available alignment slack and constrain the attacker to using legitimate function ranges as trampoline anchors. The signature shifts from “target outside any signed module” to “target inside a signed module but not at any function entry point that the on-disk image declares.”

6.5 Dispatch Deep-Dive Matrix

Driver-object abuse is the most production-relevant kernel channel family because it converts ordinary user-mode opens, reads, writes, and IOCTLs into attacker-controlled execution. The defender must answer four questions for every dispatch-like pointer: who owns the object, where does the pointer land, is that address a valid entry point, and what does the first control-flow chain do.

7. Kernel .data Pointer Surface

PatchGuard’s classic coverage is over kernel .text (code) and a specific list of structures: the SSDT, KdpStub, the IDT, the GDT, and selected critical pointers. A great deal of the kernel’s behavior is also controlled by writable function pointers in .data sections, and most of those pointers are not on PatchGuard’s coverage list. Replacing one of them with a trampoline gives an attacker a normal-looking OS path that ends in attacker-controlled code, with no code modification and no SSDT trace.

7.1 Generic .data Function Pointer Hooks

Many kernel and driver structures hold function pointers in writable data sections. The pattern is identical regardless of which structure: the cheat replaces a pointer with a trampoline, stores the original, and forwards normal calls. The choice of pointer determines what user-mode operation acts as the trigger. The important distinction is registration semantics: a static pointer initialized during boot or driver load should never change after initialization; a registration-backed pointer may change but only through a documented API that produces a visible registration record, cookie, object, altitude, GUID, or provider entry; a cache pointer may change as part of normal OS operation but must still point into a narrow set of expected modules and object lifetimes; a callback array entry looks like arbitrary data but is conceptually a callback list with owner, order, context pointer, and unregister path.

Field-Observed: “Data Ptr Called Function” Channels

UnknownCheats threads repeatedly describe this family as “driver communication using a data pointer called function.” The attacker is not trying to hook a famous exported routine; they are looking for any writable pointer that is indirectly called by a user-triggerable kernel path. The UM side then calls a normal syscall or Win32k/D3DKMT wrapper whose kernel path eventually dereferences that pointer. The pointer target becomes a dispatcher, and one of the syscall arguments carries a pointer to a command structure, a magic value, or a shared-memory descriptor. Common trigger families: ntoskrnl/HAL data-pointer calls (the canonical public example is NtConvertBetweenAuxiliaryCounterAndPerformanceCounter reaching a HAL dispatch slot); Win32k / session-state pointer calls; Dxgkrnl / graphics dispatch tables; existing-driver data pointers in vendor and system drivers. The defender should build a “callable writable pointer” manifest rather than a “known bad slot” list.

7.2 HalPrivateDispatchTable

HalPrivateDispatchTable is a kernel data structure containing HAL-related function pointers. One historically named slot, xKdEnumerateDebuggingDevices, is reachable from user mode via NtConvertBetweenAuxiliaryCounterAndPerformanceCounter, which makes it a particularly clean trigger surface: UM issues an ordinary syscall, KM walks nt!NtConvertBetweenAuxiliaryCounterAndPerformanceCounter, the dispatch lands on a HalPrivateDispatchTable slot, and the slot dereference reaches the cheat trampoline. The slot name is historical — on modern Windows the function stored in that slot is commonly related to auxiliary counter conversion (something like HalpTimerConvertAuxiliaryCounterToPerformanceCounter). The mismatch between the old slot name and the actual function is one reason cheat developers identified this slot as an interesting target.

7.3 SeSiCallback and Security Callback Pointers

Security subsystem callback pointers live in kernel .data and are reachable through privilege-check, audit, or token-related code paths. Replacing one of them lets an attacker either intercept a sensitive operation or trigger a UM-driven event whose payload is encoded as part of a security check. The same validation rules apply as for any other .data pointer surface: the pointer should land at a documented function entry in the expected security subsystem image, and any deviation should be classified by chain-walked first-hop.

7.4 ObTypeIndexTable Method Hijack

ObTypeIndexTable indexes object-type procedures by type. An attacker that can write the procedure pointers can hook OkayToClose, Close, Delete, Parse, SecurityProcedure, QueryName, or Dump for a chosen object type. A critical decode subtlety: on Windows 10 and later, _OBJECT_HEADER->TypeIndex is obfuscated. Detection code must XOR with nt!ObHeaderCookie and the second byte of the object header address before indexing ObTypeIndexTable. Detection code that omits this step will produce silent false negatives or bugchecks.

7.5 ApiSetSchema Redirection

The ApiSet schema redirects logical API set DLL names to concrete host DLLs. The schema is reachable from user mode through normal loader paths; a writable schema pointer in process or system context can redirect imports to attacker-supplied targets without modifying any disk file. Validation: schema pointer must be inside the expected loader/ntdll region and its content must match a known clean baseline for the build.

7.6 .data Deep-Dive Matrix

For every writable control pointer, store section, symbol/RVA, expected mutability class, expected target image, expected target function entry, observed target after change, first-hop disassembly, and the user-mode trigger path that reaches it. A pointer that changes without a corresponding documented registration event should be investigated even if the new target lands inside a signed module. A pointer that remains inside the expected module but is paired with a jmp rcx / call rcx-style gadget and attacker-controlled context should be classified with the callback-context gadget pattern from §5.2.

8. Memory-Backed Bidirectional Channels

The channels in §2 to §7 are predominantly signal channels. Real attacker stacks need payload channels too: places to move multi-kilobyte memory dumps, render buffers, process state, configuration, and scan results. The natural answer is shared memory, and Windows offers many varieties of it. The attacker’s choice among them is driven by attribution friction and integrity coverage, not by raw bandwidth.

8.1 Kernel-Created Section

A kernel driver creates a section object with ZwCreateSection (or MmCreateSection for variants) and maps it into the protected process address space via ZwMapViewOfSection. Both sides then share memory directly. The driver implements a ring buffer, mailbox, or command structure inside the section; user mode reads and writes the same buffer. This is high bandwidth, simple, bidirectional, and requires no repeated syscalls after the initial map. It is also, when the attacker is careless, one of the most visible artifacts in the protected process: an unnamed section with RW protection appearing in the VAD list. Mature implementations treat it as a shared-memory transport with a small control header (magic value, protocol version, total size, generation, producer index, consumer index, current command, status, flags, heartbeat, optional nonce or integrity field) and one or more data regions. Design choices: single mailbox, ring buffer, split control/data, double-buffered snapshots, descriptor mailbox. Synchronization is where many channels reveal themselves: a simple implementation polls a status field at frame rate; a quieter one pairs the section with an event, ALPC message, WaitOnAddress, thread-pool wait, APC, or completion queue.

8.2 EPROCESS and ETHREAD Reserved Field Storage

EPROCESS and ETHREAD contain padding, reserved fields, build-dependent fields, and rarely used flags. A driver stores small state in fields that documented APIs do not expose. This is low-bandwidth state hiding more than a primary IPC channel — useful for flags, hiding markers, and rendezvous metadata, but the structures are version-fragile and may collide with PatchGuard or kernel consistency checks. The danger to defenders is layout drift. Use build-aware symbol layouts and compare critical process/thread fields against independent lifecycle telemetry.

8.3 PEB and TEB Field Mirroring

The kernel driver mirrors state into user-visible PEB / TEB / TLS-expansion / loader-metadata fields. UM reads the state via ordinary memory reads against the PEB or TEB: no IOCTL, no handle, no API call. The KM side attaches to the process (via KeStackAttachProcess), resolves PEB/TEB addresses, and writes selected fields. An attacker can store a pointer in a rarely used TLS slot, mirror an epoch into loader metadata padding, or add a fake loader entry that only its own code reads. The narrow pattern that matters is kernel writes into PEB by an unknown driver while a known anti-cheat is loaded; the legitimate population for that specific pattern is essentially empty.

8.4 Direct PspCidTable Manipulation

PspCidTable maps process and thread IDs to kernel objects. On modern x64 Windows builds, _HANDLE_TABLE_ENTRY is commonly represented as a 16-byte packed entry with object-pointer bits rather than a plain pointer:

 typedef struct _HANDLE_TABLE_ENTRY
{
    union
    {
        ULONG_PTR VolatileLowValue;
        ULONG_PTR LowValue;
        struct
        {
            ULONG_PTR Unlocked          : 1;
            ULONG_PTR RefCnt            : 16;
            ULONG_PTR Attributes        : 3;
            ULONG_PTR ObjectPointerBits : 44;
        };
    };
    union
    {
        ULONG_PTR HighValue;
        ULONG     GrantedAccessBits : 25;
    };
} HANDLE_TABLE_ENTRY;

Object pointer recovery typically uses: drop Unlocked (1) + RefCnt (16) + Attributes (3) = 20 lower bits, shift the remaining object bits left by 4 to restore 16-byte alignment, sign-extend per the platform’s canonical-address model. The representative pattern is ULONG_PTR rawPtr = ((LowValue >> 20) << 4) | 0xFFFF000000000000ULL;. This is not EX_FAST_REFEX_FAST_REF applies to notify arrays and fast-referenced objects and uses 3 or 4 lower bits depending on architecture, not the 20-bit lower band of _HANDLE_TABLE_ENTRY.LowValue. Detection code that confuses the two will misparse handle table entries silently.

8.5 KernelCallbackTable

Every GUI process stores a pointer to the user-mode callback dispatch table in PEB->KernelCallbackTable when user32.dll is loaded. On the x64 Windows builds commonly targeted by public research this field is observed at PEB + 0x58. win32k.sys uses this table when KeUserModeCallback calls back into user mode: to deliver window messages, paint events, hook callbacks, and a long list of GUI-related kernel-to-user transitions. The table user32 exports under the name apfnDispatch is the actual array KernelCallbackTable points to. Modern Windows 11 builds expose more than 100 entries. A cheat that controls one of these pointers gets kernel-triggered user-mode code execution without injecting a thread, queueing an APC, or modifying any code section.

Abuse patterns: direct entry replacement; duplicate table (MITRE ATT&CK T1574.013); wrapper trampoline. A production check has three components: pointer validity (PEB->KernelCallbackTable should be inside user32.dll or a known-good mapped region); table content (hash the entire apfnDispatch array against a clean baseline computed from user32!apfnDispatch on the same build — modern cheats hijack rarely-used slots, not the canonical __fn* ones); post-initialization change (normal processes set the field once when user32 loads and do not modify it afterwards). MITRE ATT&CK DET0577 (revised May 2026) provides production-grade detection guidance.

8.6 GdiSharedHandleTable

GUI processes expose GDI handle metadata through PEB->GdiSharedHandleTable, historically at x64 PEB offset 0xF8. Older Windows builds leaked kernel addresses through pKernelAddress in cross-process views. On Windows 10 1607 and later, pKernelAddress is nulled in cross-process views. The owning process can still see meaningful information about its own GDI objects. For covert-channel usage, utility is now limited; the remaining value is correlation — a GUI callback-table hijack, hidden-window property channel, or swap-chain/capture path often changes GDI/User object behavior.

8.7 LargePageDrivers Shellcode Injection

LargePageDrivers abuse relies on large-page driver mapping behavior and alignment slack. A cheat hides shellcode or a trampoline in unused alignment space associated with a legitimate driver mapping, then redirects execution into that area. The target address appears to belong to a legitimate large-page-mapped driver, which causes naive module-range checks to pass. The trick is range laundering: a pointer-integrity check that only asks “does this target fall inside a loaded signed module range?” will approve a branch into alignment slack, padding, or unused large-page-mapped space. The fix is to classify the target, not just the range — a pointer into a signed module is meaningful only if it lands at a valid function entry, known thunk, hotpatch-compatible prologue, or compiler-generated control-flow target.

8.8 MDL-Backed User-Buffer and Locked-Page Mailbox

The simplest high-bandwidth channel does not always need a section object. A user-mode helper allocates ordinary virtual memory, passes the pointer once through any bootstrap path (IOCTL, registry callback, .data pointer trigger, APC, firmware table request, or WFP/filter callback), and the kernel component converts that buffer into stable physical memory by building an MDL and locking the pages. After setup, both sides treat the same user pages as a mailbox, ring buffer, or command/result area. The important distinction from §8.1 is provenance. A kernel-created section creates a visible section mapping. An MDL-backed mailbox can look like normal private committed memory in the helper process. The kernel side has the MDL, PFN array, and possibly a system-space mapping; user mode just sees a heap/VirtualAlloc region.

The usual setup at the protocol level: allocation (UM creates a page-aligned buffer with guard pages, initializes a header); bootstrap (UM sends pointer and size through a low-bandwidth trigger); pinning (KM probes and locks the pages with an MDL); mapping (KM either accesses the locked pages through a system-space mapping or attaches to the process); synchronization (cache-line-aligned sequence counters, interlocked flags, WaitOnAddress, events, APCs, fence-like counters, or polling); teardown. The MDL mailbox is the section channel’s stealthier cousin. Pointer transfer is one-time; the mailbox survives the trigger; ownership is ambiguous; synchronization can be objectless; failure is informative (locked-page leaks are common implementation scars). There is also a physical-page flavor where a vulnerable signed driver maps a physical page range with MMIO-style helpers, exposes a user-mode mapping or compact physical-page descriptor to the helper, and uses that page as a mailbox.

8.9 Windows I/O Ring Queue Abuse

Windows I/O rings arrived for client systems in build 22000 and expose a user-mode API for creating an I/O ring submission/completion queue pair. CreateIoRing returns a handle to an I/O ring; the caller builds operations such as asynchronous reads, submits entries to the kernel queue with SubmitIoRing, and receives completion queue entries. Three realistic abuse patterns: opaque completion channel (UM submits benign-looking I/O requests whose userData, offsets, lengths, or request ordering encode commands; a cooperating kernel component influences which requests complete, when they complete, or what status code is returned); registered-buffer rendezvous (UM registers buffers and handles, then uses the I/O ring as the synchronization and completion mechanism around a separate shared-memory payload); internal object tampering (a kernel cheat with build-specific offsets writes into I/O ring internal state or completion structures directly).

8.10 Memory-Channel Deep-Dive Matrix

Memory-backed channels are the payload workhorses. A detector needs to focus on setup artifacts and buffer semantics: who created the memory, who mapped it, what backs it, what protection it has, how it is synchronized, and whether the contents look like a protocol rather than normal application data. For each surface (kernel-created sections, EPROCESS/ETHREAD reserved fields, PEB/TEB mirroring, PspCidTable manipulation, KernelCallbackTable, LargePageDrivers shellcode, MDL-backed mailboxes, I/O rings), capture provenance, layout, synchronization, and content shape.

9. GPU, DXGK, and D3DKMT Surfaces

The Windows graphics stack is large, performance-critical, and full of cross-process memory primitives that look exactly like ordinary GPU programming. Every modern game allocates GPU memory, every overlay creates shared resources, every recording tool inspects swap-chain output. A cheat that uses the same primitives blends into the noisiest part of the system.

9.1 The Graphics Stack as a Communication Substrate

The Windows graphics stack is layered — user-mode display driver (UMD) DLLs above D3D runtimes; D3DKMT / NtGdi entry points that cross into kernel mode; dxgkrnl as the graphics kernel; the kernel-mode display miniport driver (KMD); the graphics scheduler and adapter abstraction; vendor utility processes; overlays; capture clients. Every layer has a documented memory or signaling primitive: shared resources, monitored fences, swap chains, adapter-local mappings, escapes, residency hints.

9.2 D3DKMT Shared Resources

Shared resources are normal in overlays and capture stacks, so the detector needs handle relationship, not just API presence. Store creator process, opened-by process, NT handle, allocation size, format, flags, adapter LUID, resource lifetime, and synchronization object pairing. A suspicious resource is opened by a helper with no overlay/capture role, has fixed-size updates, and is synchronized by a fence whose values look like sequence counters rather than frame numbers.

9.3 Monitored Fences

Fences are natural low-bandwidth signals because they are supposed to be monotonic and cheaply visible. Record fence creator, shared handle, current value, waiters, signalers, adapter, and value deltas over time. Normal frame pacing produces values tied to render cadence. A command fence often advances in bursts around memory operations or helper activity, independent of frame submission.

9.4 DXGI Swap-Chain Backing Memory

Swap chains are visually meaningful and high-volume. Abuse usually hides in extra shared surfaces, unexpected duplication clients, or off-screen resources rather than the primary present path. Capture swap-chain owners, output-duplication clients, capture APIs, overlays, present cadence, format changes, and unusual shared backing handles.

9.5 Adapter-Local System Memory and GPU-Visible Mappings

The core challenge is that adapter-local memory may not be trivially visible to CPU scanners. Defenders should record residency transitions, map/unmap events where visible, allocation residency queries, ETW graphics events, and whether resources are shared back into CPU-visible memory. A cheat that stages data in GPU-visible memory still needs a CPU-side control path, fence, escape, or copy operation.

9.6 GPU Scheduling Hooks and D3DKMT_ESCAPE

Escapes are vendor-defined, so semantic parsing is hard. The defensive record should include adapter LUID, escape type/flags, input/output buffer sizes, caller process, UM driver module, KMD owner, return status, and frequency. A vendor control panel issuing occasional known escapes is normal. A game helper issuing high-frequency opaque escapes with fixed-size payloads to a display miniport is not. If the escape path reaches a handler pointer outside the expected KMD image, elevate to pointer-integrity severity.

9.7 WDDM 3.x GPU DMA Remapping

GPU DMA remapping changes the policy floor but not the channel problem. Record whether remapping is supported and enabled for the adapter, driver model, Windows build, HVCI/VBS state, and any fallback path. For ranked modes, include this in hardware trust posture rather than in covert-channel telemetry alone.

9.8 Detection Surface and Practical Limits

Public D3DKMT APIs expose adapter and resource metadata, not a complete per-process allocation ledger. When a finding depends on deep dxgkrnl state, isolate it behind build-specific parsers and treat it as high-risk engineering. Prefer cross-view evidence first.

9.9 GPU Deep-Dive Matrix

A useful GPU detector does not try to understand every vendor allocation; it builds ownership and timing evidence around handles, resources, fences, contexts, processes, and escapes. Capture the loaded display miniport driver, user-mode display driver DLLs, graphics kernel clients, GPU scheduler state visible through public APIs, vendor utility processes, overlay processes, capture clients, and adapter identity.

10. Signal and Execution-Flow Channels

The channels in §2 through §9 are object-backed: a port, a section, a callback, a fence. The channels in this section are flow-backed: a thread state transition, an exception, a syscall path. The cheat does not need a data structure to hide in; it needs an event that fires when something happens. The KM side arranges the event; the UM side reacts to it.

10.1 Trapped User-Mode Thread

A cheat parks a user-mode thread in a wait, exception, syscall, or controlled loop, then uses kernel actions to release, modify, or signal that thread. The KM side manipulates wait state, memory state, or thread context; the UM side waits for the state transition and treats it as a command. No named IPC object is required. The channel is encoded in resume cause rather than object content: a thread waits on an event that KM signals after updating a shared section; a thread sleeps in an alertable wait and receives APCs; a thread loops on a guard page or debug register trap; a thread blocks in a syscall whose return timing or status is influenced by a kernel hook; a thread’s context is modified while suspended, and resume becomes the command edge.

10.2 APC Queueing and Alertable Wait

APCs are delivered when a thread enters an alertable state. Microsoft documents the user-mode shape as QueueUserAPC(pfnAPC, hThread, dwData). Pending user-mode APCs are handled in FIFO order after the thread enters an alertable state. Three cheat layouts: dedicated receiver thread (UM creates a thread whose only job is to sit in an alertable wait loop); hijacked legitimate completion thread (the cheat chooses a thread that already uses alertable I/O completion); pointer-staged command (dwData does not carry the whole command but points to a shared section, guarded page, heap slot, or compact command descriptor). The case becomes interesting when the target routine lives in a private executable mapping, the APC cadence lines up with cheat commands rather than I/O completion, or the same unknown driver repeatedly releases a game thread from alertable waits.

10.3 Hardware Breakpoint Channels

Debug registers DR0DR3 hold watched addresses, DR6 records breakpoint status, and DR7 controls enablement, access type, and length. An attacker sets debug registers per-thread and uses the resulting #DB / STATUS_SINGLE_STEP exception as a low-slot-count trigger channel without patching any code bytes. Attractive because it is exact and byte-invisible — no inline hook, no import rewrite, no guard-page bit to enumerate. Constraints are strong: four architectural address slots per thread, state is thread-scoped — better as a trigger or selector than as a bulk channel.

10.4 Page Fault Handler Interception

Three variants exist. 10.4.a Direct KiPageFault Hook (PG-Conflict). PatchGuard detects this rapidly and bugchecks the system. 10.4.b VEH plus PAGE_GUARD Trigger (the practical version). The attacker sets PAGE_GUARD protection on selected user memory from KM. UM touches the page, raising STATUS_GUARD_PAGE_VIOLATION. The attacker’s VEH handles the event, reads the faulting address as the command, and resumes. PAGE_GUARD is one-shot. A covert channel built on this primitive must explicitly re-arm the page inside the handler: VirtualProtect(addr, size, oldProt | PAGE_GUARD, &oldProt);. The re-arm pattern is itself a useful detection signal — repeated STATUS_GUARD_PAGE_VIOLATION exceptions plus repeated VirtualProtect(... PAGE_GUARD ...) calls plus a private-memory VEH handler is the canonical signature. 10.4.c Hardware Watchpoint Read (DR-based).

10.5 VEH Chain Injection

Vectored Exception Handlers are process-wide user-mode exception callbacks registered via AddVectoredExceptionHandler. An attacker injects a handler and uses exceptions as command triggers. Microsoft documents that the First parameter controls ordering — non-zero inserts the handler at the front. An attacker wants first look at STATUS_GUARD_PAGE_VIOLATION, STATUS_SINGLE_STEP, STATUS_BREAKPOINT, STATUS_ACCESS_VIOLATION, or deliberately generated illegal-instruction faults before the application’s own handlers or crash reporter see them. A dangling or stale VEH entry pointing into freed, remapped, or private memory is a strong sign of injected control flow.

10.6 NMI and IPI Hijack

A driver registers an NMI callback via KeRegisterNmiCallback or triggers cross-core activity via KeIpiGenericCall; the resulting interruption gives a high-privilege observation or signaling path that user-mode defenders cannot directly observe. This is mostly used for anti-debug, anti-inspection, and sampling state outside normal scheduling, not as a primary data channel. Operational constraints are severe — NMI context cannot tolerate pageable code, blocking, locks, or long work.

10.7 Process Instrumentation Callback

ProcessInstrumentationCallback is process information class 40 (0x28) for NtSetInformationProcess. It lets a privileged caller install a user-mode callback that the kernel invokes on selected kernel-to-user transitions. In the classic x64 model the kernel stores the original return address in R10, changes the trap-frame return RIP to the callback, and expects the callback to return to the saved address. The attacker installs the callback (via a driver or vulnerable signed driver path) and runs payload code on every syscall return. This is powerful: kernel-triggered UM code execution without injecting a thread, without code modification, and without queueing APCs.

10.8 AltSyscall

Alternative syscall routing on Windows 11 has evolved beyond the simple PsAltSystemCallHandlers array that older research described. Newer builds involve syscall-provider dispatch state and more complex per-process / per-thread routing. An attacker that influences alternative syscall routing can intercept selected syscalls without classic SSDT modification. The defensive mistake is treating this as one legacy global pointer. On current Windows 11 builds, the relevant question is “which provider state and process/thread routing decisions can cause this syscall to take a different path on this build?” That requires PDB-backed or reverse-engineered baselines per build.

10.9 PerfInfoLogSysCallEntry Stack Replacement

PerfInfoLogSysCallEntry is an internal syscall tracing function. A pattern observed in some security software replaces a syscall-handler address stored on the kernel stack at a precise tracing point, allowing a wrapper to run before forwarding to the original path. The UM side simply issues syscalls. As a covert channel, the interesting property is the narrow moment where syscall metadata, stack-resident dispatch state, and performance tracing logic intersect.

10.10 NtRegisterThreadTerminatePort

NtRegisterThreadTerminatePort is an undocumented syscall that registers an LPC/ALPC port to receive LPC_CLIENT_DIED-style notification when the calling thread terminates. The attacker creates or connects to an ALPC port, registers threads, and treats thread exits as signals — useful for watchdogs, teardown signaling, and lifecycle state. It pairs well with §2.2 ALPC ports and §10.1 trapped threads.

10.11 WaitOnAddress and Keyed-Event Rendezvous

WaitOnAddress is a Windows 8+ user-mode synchronization primitive that waits until a value at an address changes. Microsoft documents that the wake is process-local; shared memory alone does not let a helper process wake a waiter in the protected process. The primitive becomes interesting only when the shared value is paired with a same-process wake surrogate, injected helper thread, timeout/spurious-wake loop, keyed-event style runtime primitive, or another trigger path. The attraction is absence of objects — no named event, no semaphore, no pipe, no alertable APC; the wait target is just an address.

10.12 Thread-Pool Work Items, WorkerFactory, and Completion-Queue Triggers

Black Hat Europe 2023’s Pool Party research changes how defenders should think about “normal” user-mode execution triggers. An attacker that already has a kernel write primitive, duplicated handle path, or injected helper does not need to create a suspicious remote thread — it can arrange for existing thread-pool workers in the protected process or a trusted helper process to execute a queued callback as a consequence of an ordinary-looking event. The work item is usually not the payload; it is the wake edge that tells a legitimate worker to consume a section, MDL mailbox, ALPC view, heap buffer, or COM/RPC method result. Useful channel shapes: WorkerFactory wake trigger; TP_IO completion trigger; TP_ALPC trigger; TP_JOB trigger; TP_WAIT trigger; TP_TIMER trigger (delayed timers let the visible helper exit before the payload executes); direct completion-queue trigger.

Attacker Mechanics: Laundering the Wake Edge

The thread-pool pattern is attractive because defenders often key on new thread creation, suspicious thread start addresses, and obvious remote-thread injection. A thread-pool channel changes that question: the worker thread already exists, its start address belongs to ntdll or a runtime library, and the suspicious transition is not “thread started” but “work became ready.” The attacker composes three pieces: a wake source; a callback target; a mailbox consumer. The protocol rhythm is: arm a work item, update the mailbox header, trigger the wake source, let the worker consume one epoch, write status back, and re-arm or retire the wake source.

10.13 Flow Deep-Dive Matrix

Execution-flow channels are difficult because the channel is often a transition rather than an object. A detector needs to capture where a thread waits, what wakes it, and what it does immediately after wake. For each surface (trapped threads, APC channels, hardware breakpoints, page-fault/guard-page, VEH chains, NMI/IPI, Process Instrumentation Callback, AltSyscall, PerfInfo paths, thread terminate ports, WaitOnAddress, thread-pool triggers), capture wait/wake artifacts and post-wake memory access.

11. CPU and Hypervisor Channels

The channels in this section sit below the kernel: they use page-table state, MSRs, descriptor tables, or hypervisor-managed memory views. They are the highest-value attacker surfaces and the highest-cost defender surfaces. Software anti-cheat alone cannot close the upper bound — at L4 the defender’s strongest move is usually platform attestation, not behavioral detection.

11.1 EPT MMIO Channel

A malicious hypervisor creates EPT (Extended Page Table) mappings where selected guest physical accesses trap to the hypervisor. The trapped access acts like MMIO. Three common shapes: trap-on-read, trap-on-write, dual-view memory. There is also a hypercall-style mailbox variant using CPUID, VMCALL / VMMCALL, selected MSR reads/writes, I/O port accesses, or a deliberately faulting instruction. Black Hat USA 2018 Hyper-V architecture research broadens this beyond raw CPUID / VMCALL thinking: in a Hyper-V environment, the highest-value communication path may be a root-partition service, VMBus channel, synthetic device, virtual switch, virtual storage path, MMIO interception path, or user-mode VM worker process mapping. The guest-side anti-cheat can be perfectly clean while the root-side component sees memory, input, and timing from outside the guest trust boundary.

Attacker Mechanics: Guest Stub, VM-Exit Contract, Hidden State

An EPT or hypercall channel splits the implementation across trust boundaries. The guest stub is the visible code in the game, helper, or driver. The exit condition is the hypervisor decision about which access pattern causes a VM exit. Hidden state — the hypervisor stores the real command table, memory translations, entity cache, feature flags, and output data outside the guest’s normal kernel memory view. Reply injection — the result is returned by changing register values, emulating a memory read, modifying a guest page, completing a synthetic-device message, changing timing, or updating a shared page that the guest believes is ordinary memory. Platform attestation is the durable defense — a TPM-anchored Quote that includes PCR[17] (DRTM, via Intel TXT or AMD SKINIT) and VBS-related measurements proves the secure execution environment was established correctly.

11.2 CR3 and Page-Table Walk

CR3 manipulation and direct page-table walks are more often used for memory access and hiding than for high-bandwidth command traffic. The privileged component reads CR3, walks page tables, or switches address spaces to access memory without using ordinary handles or copy APIs. The UM side receives results through another channel. Practical variants: kernel walker (a signed or vulnerable driver walks page tables directly); CR3 switcher; hypervisor split view. Cross-view validate VADs, PTEs, working sets, and image-load telemetry; a region with no VAD entry but valid PTEs and resident pages is suspicious.

11.3 MSR Manipulation

MSRs store CPU state. Some are aggressively PatchGuard-protected; others are not. The cheat can encode a few bits in writable MSRs or use MSR changes as triggers.

MSRNamePatchGuard ClassCheat Use
IA32_LSTAR (0xC0000082)Syscall handler basePG-ConflictChanging it bugchecks rapidly. Read-only monitoring only.
IA32_KERNEL_GS_BASE (0xC0000102)Per-CPU kernel GSNot generally PG-protectedLow practical value.
IA32_DEBUGCTL (0x1D9)Debug controlNot generally PG-protectedLow-bandwidth side channel.
IA32_PERF_GLOBAL_CTRL (0x38F)Performance counter controlNot generally PG-protectedLow-bandwidth side channel.
IA32_CLOCK_MODULATION (0x19A)Clock modulationNot generally PG-protectedVery low bandwidth.
IA32_STAR (0xC0000081)Legacy syscallPG-ConflictNot used on x64 for this purpose.
MSR candidates by PatchGuard risk class. Source: original article, §11.3.

11.4 IDT and GDT Entry Hijack

Interrupt Descriptor Table and Global Descriptor Table entries redirect exception, interrupt, or segmentation-related control flow. On modern Windows x64, direct IDT/GDT hijacking is generally PG-Conflict and highly unstable; this surface has largely been retired by mainstream attacker tooling. Baseline IDT/GDT entries per CPU at boot; validate handler targets against expected kernel ranges; treat any modified descriptor path as critical unless explained by a trusted hypervisor or platform component.

11.5 CPU/Hypervisor Deep-Dive Matrix

The L4 boundary is where local software certainty breaks down. Split evidence into “guest-visible anomaly” and “platform-attested state.” For EPT/MMIO, guest-visible signals include timing anomalies, inconsistent CPUID/MSR behavior, unexpected hypervisor leaves; platform evidence includes Secure Boot, DRTM, VBS/HVCI, IOMMU, and TPM quote material. For hypercall mailboxes, record instruction family, register tuple, caller module, frequency, timing distribution, and whether the tuple contains a stable private key. For CR3/page-table walks, software checks can compare VADs, PTEs, working sets, image-load events, and section mappings. For MSR manipulation, separate catastrophic MSRs from low-bit side-channel MSRs and require owner attribution. For IDT/GDT, retail systems should be stable; any unexplained descriptor target should be escalated as platform compromise.

12. Persistent Storage and Firmware Channels

The channels here persist across reboot. They are not high-bandwidth command paths during a session; they are configuration, license-state, and bootkit-coordination surfaces. The defender’s question is rarely “what is moving through this channel right now” but “what is stored here that should not be.”

12.1 Registry Hidden Values

Registry values can be hidden with SACL tricks, restricted SIDs, symbolic-link keys, unusual Unicode names (combining characters, BIDI overrides, NUL-prefixed names that bypass naive enumeration), volatile keys, or ACLs that block the most common enumeration tools. The attacker uses the registry for configuration, license state, reboot-persistent command state, and defensive tripwires, often paired with CmRegisterCallbackEx to detect when defenders enumerate the path. Detection combines cadence, enumeration with backup/restore privileges, symbolic-link resolution before trusting any path, and callback correlation. Cadence, path ownership, and ACL abnormality matter more than presence.

12.2 UEFI Runtime Variables

UEFI runtime variables are firmware-backed key-value entries that persist across reboot. Windows exposes them through GetFirmwareEnvironmentVariableExW / SetFirmwareEnvironmentVariableExW in user mode (with SE_SYSTEM_ENVIRONMENT_NAME privilege) and ExGetFirmwareEnvironmentVariable / ExSetFirmwareEnvironmentVariable in kernel mode at PASSIVE_LEVEL. The namespace is (VariableName, VendorGuid, Attributes) — two variables with the same visible name but different vendor GUIDs are different variables; a familiar-looking name under an attacker-controlled GUID is not familiar. Attributes also matter (non-volatile, boot-service-access, runtime-access, authenticated-write, append-write). The attacker uses UEFI variables for boot-persistent storage: HWID spoofers, license state, bootkit coordination, delayed activation flags, “last known good” rollback state. The stealth pattern is GUID laundering.

12.3 TPM NV Indices

TPM 2.0 Non-Volatile indices store small blobs inside the TPM. Depending on index policy, they can be read and written through TBS (TPM Base Services) or platform TPM stacks. The relevant unit is the NV index handle plus its public area: size, attributes, name algorithm, authorization policy, read/write permissions, and whether the index can be extended, counter-like, bit-like, or ordinary. Tbsip_Submit_Command is the important low-level tell because it submits raw TPM command buffers through a TBS context. A workload-adjacent helper that repeatedly submits NV_Read, NV_Write, NV_DefineSpace, NV_UndefineSpace, Policy*, or authorization commands near protected workload launch is much more suspicious than a one-time Windows Hello or BitLocker operation.

12.4 Common Log File System (CLFS) Streams

CLFS is a general-purpose logging service available to user-mode and kernel-mode clients. User mode can create or open logs with paths such as LOG:c:\path\name, which materialize as .blf files and associated containers. Kernel clients can write and read records through the CLFS library. That makes CLFS a natural persistent rendezvous surface: a real OS logging subsystem, not an ad hoc file format. An attacker uses CLFS with a log path chosen to look like a telemetry, crash, update, or service log; records carry encrypted configuration, license state, hardware profile deltas, kernel scan results, or reboot-to-reboot command state; LSN ordering becomes an epoch counter.

12.5 ACPI Control-Method Evaluation

Microsoft documents IOCTL_ACPI_EVAL_METHOD and IOCTL_ACPI_EVAL_METHOD_EX as requests that evaluate ACPI namespace methods for a device. Acpi.sys handles the request for devices described by ACPI tables, and the request carries a method name, input buffer, output buffer, and target device object. Starting with Windows 8, UMDF drivers can use these requests as well. Many laptops and motherboards expose vendor ACPI methods for thermal policy, performance mode, keyboard backlight, fan curves, battery, sensors, embedded controller access, and device-specific configuration. A malicious or cooperating driver can send ACPI method-evaluation requests to a legitimate ACPI PDO and encode command state in method name, integer/string/custom arguments, output size, returned package values, or status.

12.6 KTM, TxF, and Transacted Registry Channels

Kernel Transaction Manager is the kernel component behind transactional resources such as Transactional NTFS and the Transacted Registry. The important defensive consequence is that an operation can have a dirty transaction view, a committed view, and a rollback path. A scanner that observes only final committed file/registry state can miss command state that existed long enough to trigger a callback, map a section, or feed a cooperating process, then rolled back. The attacker value is ephemeral committed-state avoidance: transacted registry trigger, transacted file staging, minifilter transaction context, rollback as acknowledgement, TxF metadata artifact.

12.7 Persistence Deep-Dive Matrix

Persistent channels are rarely live command buses. Their value is survivability. Treat them like forensic artifacts with provenance and retention. For each surface (hidden registry values, UEFI variables, TPM NV indices, CLFS, ACPI control methods, KTM/TxF/Transacted Registry), record the relevant identity, ownership, timing, and caller fields rather than trying to live-block.

13. External and Hardware-Assisted Channels

When the cheat surface lives outside the gaming PC, software anti-cheat is structurally outmatched. The cheat code does not run on the protected host. The host sees only the side effects: PCIe devices it does not control, HID inputs that look like user activity, capture cards on the display path. Defense is policy, server-side behavioral detection, and platform attestation, not on-device software detection.

13.1 DMA Cards

External DMA hardware reads or writes system memory without normal in-OS APIs. PCIe DMA cards installed in the gaming PC (typically M.2 NVMe slots) issue Memory Read TLPs against game memory, transferring contents to a second machine over USB or network. There is no in-game module, or only a small overlay/input component on the host. This is the dominant high-end FPS cheat surface. Detection: enumerate PCIe topology and flag suspicious devices; enforce IOMMU / Kernel DMA Protection policy; monitor Thunderbolt, USB4, CFexpress, M.2, and other DMA-capable device changes; use hardware allowlists for competitive environments; correlate impossible in-game knowledge with the absence of local memory-access indicators; require DMA-remapping-compatible storage and PCIe drivers in hardened modes.

13.2 VMI and VIC

Virtual Machine Introspection moves cheat logic outside the guest OS. The 2025 VIC paper (arXiv:2502.12322) formalized this surface and reported working radar, wall-hack, and trigger-bot prototypes against multiple titles and anti-cheats. Visual Input Capture (VIC) is a related approach: a capture pipeline observes the game’s display output and returns decisions through input emulation. The local system may receive only input events; no memory access happens. The practical defense is layered: host evidence, behavioral evidence, policy evidence.

13.3 KMBox and Arduino HID Input Separation

Hardware cheats often separate memory acquisition from input delivery. A second PC or DMA controller computes aim movement, then sends the movement to a microcontroller that emulates a USB HID mouse on the game PC. KMBox, RP2040 boards, Arduino-class devices, and similar HID emulators all fit this pattern. The gaming PC sees a USB HID mouse. Ordinary mouse deltas and clicks reach the game. There may be no cheat process on the game PC at all. Evidence splits into three layers: descriptor evidence, topology evidence, behavior evidence.

13.4 External Capture Card Screen Separation

The game PC’s HDMI or DisplayPort output is split to a capture card on a second machine. The second machine runs computer vision and sends input back through a HID emulator. There may be no memory-reading component at all: the cheat is entirely vision-based. The host evidence is weak because the capture device may be electrically outside the PC’s control path. The computer-vision loop has measurable behavior even when hardware identity is ambiguous — vision cheats must wait for a frame, process it, decide, and inject input, which produces latency and correction shapes that differ from both human aim and memory-based aimbots.

13.5 CXL, PCIe IDE, SPDM, and TDISP Boundary Drift

PCIe security is moving from “enumerate the device and hope IOMMU policy is enough” toward device authentication, link encryption/integrity, trusted device assignment, and coherent memory fabrics. SPDM provides device authentication, measurement, confidentiality, and integrity primitives. PCIe IDE provides Integrity and Data Encryption for PCIe traffic. TDISP builds on SPDM and IDE for trusted I/O virtualization. CXL extends PCIe into coherent device and memory-expansion fabrics. The 2025 PCI-SIG IDE vulnerability disclosure is the warning sign: posted requests can be delayed by malicious programmable PCIe switches until a trusted device interface is rebound.

13.6 External-Channel Deep-Dive Matrix

External channels cannot be handled like local malware. The protected host may never execute cheat code. Evidence must be split into host-visible artifacts, server-side behavior, and explicit hardware policy.

14. 2024–2026 Trends and Research Updates

Channels do not stand still. Microsoft hardens surfaces, defenders widen coverage, and attackers move into surfaces the defender has not yet inventoried.

14.1 Riot Vanguard PCIe and DMAr Enforcement

Current public Riot support material from January 23, 2026 confirms Vanguard uses DMA Remapping to isolate PCIe devices and blocks VALORANT launch when storage drivers are not DMAr-compatible. DMA defense is moving from passive PCIe inventory to active IOMMU / DMAr policy enforcement. Storage and PCIe driver compatibility now matters for anti-cheat launch policy, not just for detection. Anti-cheat products need a clear recovery and user-support path because legitimate OEM drivers can fail DMAr requirements.

14.2 Microsoft Kernel DMA Protection and IOMMU Direction

Microsoft documentation confirms Kernel DMA Protection uses the system IOMMU to block or isolate DMA-capable peripherals, and that supporting systems enable it automatically. Microsoft also documents GPU IOMMU DMA remapping as introduced in Windows 11 22H2 (WDDM 3.0). IOMMU / DMAr should be treated as a competitive-mode policy control, not only as a detection signal.

14.3 HVCI, kCFG, and the Vulnerable Driver Blocklist

Memory Integrity (HVCI) runs kernel-mode code integrity in a VBS-isolated environment, requires executable kernel pages to pass code integrity, and prevents executable pages from being writable. The vulnerable driver blocklist is enabled by default on Windows 11 2022 Update and later. BYOVD loading remains a moving target: the blocklist lags new vulnerable-driver disclosures, and cheat ecosystems track disclosures faster than the blocklist tracks them. HVCI eliminates unsigned and writable-executable kernel payload options but does not close .data pointer abuse, legitimate callback abuse, or signed-but-malicious driver loading. The right framing is “stack four independent platform controls” (Secure Boot, TPM 2.0, HVCI, IOMMU/DMAr).

14.4 KernelCallbackTable Detection Has Matured

MITRE ATT&CK DET0577, last revised May 12, 2026, documents detection for KernelCallbackTable hijacking through unexpected PEB modification followed by invocation through Windows message callbacks. The technique is no longer obscure. Game-process PEB callback-table validation belongs in the P0 or P1 GUI-process integrity layer. Detection should correlate PEB modification, table entries outside user32, suspicious GUI message dispatch, and post-change code execution.

14.5 AltSyscall and Windows 11 Syscall Provider Evolution

Public Windows 11 AltSyscall research shows the older PsAltSystemCallHandlers model is not the full story on newer Windows 11 builds. AltSyscall detection must be build-specific. A detector written against the Windows 10 model misses newer Windows 11 routing. Validate provider dispatch context and per-thread syscall-provider state, not only one global handler pointer.

14.6 Academic 2025 Cheat and Covert-Channel Research

  • VIC (arXiv:2502.12322) formalizes virtual-machine introspection cheats and reports working radar, wall-hack, and trigger-bot prototypes against multiple games and anti-cheats. The structural lesson is that on-device detection cannot close L6.
  • AntiCheatPT (arXiv:2508.06348) reports a transformer model for Counter-Strike 2 behavioral cheat detection, with 89.17% accuracy and 93.36% AUC on its test set. Evidence that server-side behavioral models are reaching production-grade thresholds.
  • Page-fault covert-channel research (arXiv:2509.20398) demonstrates timer-free, hardware-agnostic covert communication with under 4% bit error rate.
  • GPU-based host memory integrity validation (IEEE CoG 2025 preprint) proposes monitoring protected game objects from GPU execution to resist kernel-level tampering.

14.7 UnknownCheats Field-Observation Pass

A June 2026 pass over UnknownCheats forum indexes shows attackers are no longer arguing only about “IOCTL vs. shared memory.” The more relevant question is which legitimate OS path can be turned into a trigger or rendezvous while the payload moves elsewhere. Concrete additions: “data ptr called function” as a named attacker workflow; hookable function pointers for UM-KM on modern Windows including Win32k, HAL, dxgkrnl, and existing drivers; shared buffer with system thread (deeper than a named section); recommended communication method churn; vulnerable-driver primitive catalogs; input-return path migration; syscall trigger hygiene; hypervisor trigger keys.

14.8 Black Hat 2016–2026 Windows Research Pass

The best channel ideas rarely arrive as “game cheat IPC.” They arrive as Windows internals research on rootkits, IPC, path parsing, virtualization, update trust, or kernel object ownership. The defensive task is to translate those primitives into evidence that works for anti-cheat, EDR, and incident-response workflows. Key carry-throughs: ALPC/RPC research (REcon 2008, HITB 2014, PacSec 2017, DEF CON 32, ALPChecker-style work); WNF as a state system; AFD socket channels (Black Hat USA 2020); anonymous pipes; path identity multi-view (Black Hat Asia 2024 MagicDot); thread pools as wake-edge launderers (Black Hat Europe 2023 Pool Party); Hyper-V channels beyond hypercalls (Black Hat USA 2018); downgrade attacks change trust floors (Black Hat USA 2024 Windows Downdate).

14.9 Additional Web-Document Gap Pass

A broader June 2026 pass identified five missing or under-integrated families: Cloud Files / ProjFS provider callbacks; ACPI control-method evaluation; KTM / TxF / Transacted Registry; kernel-resident license/config egress over WSK; signed-driver rootkit analogues (Netfilter/Retliften, FiveSys, Mustang Panda / ToneShell, Group-IB signed-driver ecosystem). The kernel-egress item stays on the §4.4 P0 network-ownership path because a non-network driver contacting remote infrastructure during protected workload runtime is high-value telemetry.

14.10 Presented Case-to-Channel Map

CaseCommunication primitiveEvidence translation
REcon 2008 LPC/ALPC interfacesLPC/ALPC endpoint as security boundaryPort owner, accepted client identity, message class, token/security context
HITB 2014 ALPC Fuzzing ToolkitRaw ALPC and RPC/DCOM over ALPCPer-process destination ports, connection graph, message cadence
PacSec 2017 ALPC-RPCRPC interface over ALPCInterface UUID/version, opnum, NDR payload shape, endpoint string
DEF CON 32 ALPC/RPC securityALPC/RPC security metadataAuth level, impersonation level, QoS, direct-event/completion behavior
ALPChecker / HITB 2023 / arXiv 2024ALPC spoofing and blindingCross-view mismatch: namespace, handle table, ETW, communication ports
Black Hat USA 2018 WNFWNF state as communication frameworkState name, scope/lifetime, security descriptor, version, payload size
Black Hat USA 2020 Windows rootkitsAnonymous pipe broker / AFD file-object route swapStandard-handle pipe graph, socket FILE_OBJECT/DeviceObject, endpoint tuple
Black Hat Europe 2023 Pool PartyThread-pool work items as wake edgeWorkerFactory handle, completion queue/key, TP_ALPC/TP_JOB/TP_WAIT source
Black Hat Asia 2024 MagicDotPath identity confusion for rendezvousRaw path, normalized NT path, handle-final path, file ID, section path
Black Hat USA 2018 Hyper-V architectureRoot-partition / VMBus / synthetic-device channelVMBus channel, synthetic-device ring, MMIO/port access, VM worker identity
Netfilter / RetliftenSigned driver remote authority and proxy stateDriver egress, HTTP/root-cert/proxy writes, trust-store mutation
FiveSys and companion driversProxy/PAC/download/injection control planePAC-serving component, proxy domain list, downloader, KM-assisted staging
Mustang Panda / ToneShell signed rootkitSigned kernel loader + fake-TLS C2Driver/minifilter owner, injected process, TCP/443 protocol compliance
Group-IB signed-driver ecosystemLoader/proxy/registry/disk/network task mixC2 retrieval, registry/local-disk staging, proxy, signed-driver provenance
Case-to-channel map. Source: original article, §14.10.

15. Detection Engineering Program

The chapters above describe the what of detection. This chapter is the how: the operational structure that turns the catalog into a production detector.

15.1 Baseline First, Then Hunt

The single most common reason a kernel detector regresses is “the legitimate population shifted and the detector did not.” A production detector must build clean baselines for at least: driver objects and dispatch tables; callback arrays and callback registrations; HalPrivateDispatchTable and other high-risk .data pointers; Ob object-type procedure pointers (with cookie correction); protected process PEB fields, ApiSet schema pointer, and KernelCallbackTable; sections, ALPC ports, WNF subscriptions, named objects, and loopback sockets; minifilters, filter communication ports, and device symbolic links; Cloud Files sync roots, ProjFS virtualization roots, reparse tags; MDL-backed user buffers, long-lived locked private pages; thread-pool worker factories, I/O completion queues, timer queues; transaction object activity; HID/VHF devices, Mouclass/Kbdclass filter stacks; D3DKMT allocations, vendor-utility processes, capture/duplication clients. Baselines must be per-build, per-vendor-driver-version, and per-product configuration.

15.2 Cross-View Validation

Single-source checks are easy to bypass. Robust checks compare multiple independent views of the same fact: process list vs. PspCidTable vs. ETW process lifecycle; module list vs. VADs vs. image-load callbacks; handle table vs. object callbacks vs. access-denied patterns; shared memory objects vs. VADs vs. handle ownership; locked user pages / MDLs vs. VADs vs. owning driver role; GUI callback pointers vs. user32!apfnDispatch clean baseline; D3DKMT allocations vs. vendor KMD allocation ledger vs. expected overlay clients.

15.3 Prioritization

IDTechniqueLayerFrequencyDetection DifficultyPriority
§3.1Firmware provider hijackL3Very highMediumP0
§6.1IRP MajorFunction patchL2-L3Very highMediumP0
§7.2HalPrivateDispatchTableL3Very highMediumP0
§8.1Kernel-created sectionL2HighMediumP0
§8.5KernelCallbackTableL3HighMediumP0
§4.4WSK loopback / external egressL2Very highLow-mediumP0
§2.2ALPC private / section-view channelsL2Very highLow-mediumP0
§6.1AFD file-object DeviceObject swapL3Medium-highMedium-highP0
§13.1DMA cardsL5High in FPSVery highP0 policy
§2.11Named pipesL1-L2HighLow-mediumP1
§2.11Anonymous pipe broker variantL1-L2MediumMediumP1
§2.12Local RPC / COM endpointsL1-L2MediumMediumP1
§4.6WFP calloutsL2Medium-high (network)MediumP1
§4.7Virtual HID / class-input callbacksL2/L5MediumMediumP1 + behavior
§10.7Process Instrumentation CallbackL3MediumLowP1
§10.8AltSyscallL3-L4Low-mediumVery highP1
§10.2APC queue + alertable waitL3MediumMediumP1
§10.5VEH exception trigger chainL3MediumMediumP1
§10.12Thread-pool trigger launderingL2-L3MediumMedium-highP1
§7.4ObTypeIndexTable hijackL3MediumMediumP1
§5.2CmRegisterCallbackL2HighMediumP1
§5.2Undocumented registry value-type channelL2Medium-highMediumP1
§5.2Registry callback-context gadget maskingL3MediumMedium-highP1
§8.8MDL-backed user-buffer mailboxL2-L3Medium-highMediumP1
§3.5WNFL3Medium-highVery highP1
§4.1FltCreateCommunicationPortL2MediumLowP1
§3.3NtQuerySystemInformation manipulationL3MediumMediumP1
§9.2D3DKMT shared resourcesL2-L3MediumHighP1
§9.5Adapter-local GPU memoryL3Low-mediumVery highP1
§2.3MagicDot-style path identity confusionL1-L3MediumMediumP1
§4.8eBPF for Windows maps / ringsL2Low todayMediumP2
§4.9Cloud Files / ProjFS provider callbacksL1-L2Low-mediumMediumP2
§8.9Windows I/O ringsL2-L3Low-mediumMediumP2
§10.11WaitOnAddress rendezvousL2-L3MediumHighP2
§10.3Hardware breakpoint triggerL3Low-mediumMediumP2
§12.2UEFI runtime variablesL3/L5Low-mediumMediumP2
§12.3TPM NV indicesL5Low todayHighP2
§12.4CLFS streamsL2-L3Low-mediumMediumP2
§12.5ACPI control-method evaluationL2-L5LowMedium-highP2
§12.6KTM / TxF / Transacted RegistryL1-L3Low-mediumMediumP2
§7.1Generic .data pointerL3MediumHighP2
§7.5ApiSetSchemaL3LowMediumP2
§11.1EPT MMIOL4LowNearly impossiblePolicy
§13.2VMI / VICL6Very lowNearly impossiblePolicy
§13.3KMBox / HID emulatorL5Medium (HW-assisted)Medium-highPolicy + behavior
§13.4External capture card visionL6RisingNearly impossible locallyServer-side
§13.5PCIe IDE / SPDM / TDISP / CXLL5EmergingVery highPolicy
Detection priority across the catalog. Source: original article, §15.3.

15.4 First Production Pass Checklist

  • Driver-dispatch-pointer validation for all loaded drivers, including internal-device-control stack-proxy attribution and high-risk per-handle FILE_OBJECT->DeviceObject validation for AFD sockets.
  • Shared section, suspicious VAD, MDL-backed user-buffer, and locked-page inventory for the protected process and helper processes.
  • IPC endpoint ownership correlation: ALPC connection/communication ports, named pipes, anonymous pipe handle graphs, RPC endpoints, COM local servers, named objects, WNF, Filter Manager ports.
  • WSK loopback, TCP loopback, and kernel-originated external egress ownership correlation.
  • Firmware-provider and suspicious system-information-path monitoring, including NtSetSystemInformation class-75 provider-registration telemetry.
  • KernelCallbackTable pointer and entry validation.
  • HalPrivateDispatchTable high-risk slot validation with chain walking.
  • Callback inventory for Ob, registry, process / thread, and image-load callbacks, including raw registry value-type telemetry, function-entry validation, register-indirect gadget classification, and callback-context pointer classification.
  • WFP provider / sublayer / callout inventory, virtual HID stack inventory, and Mouclass/Kbdclass callback-target validation.
  • PCIe and DMA policy checks if the protected workload is high-risk, extended to IDE / SPDM / TDISP / CXL capability state where the platform exposes it.
  • GPU surface inventory at protected workload launch.
  • Multi-view path identity capture for high-risk processes, sections, symbolic links, and device paths.
  • Observe-only execution-flow telemetry for APC delivery, VEH chain changes, debug-register state, page-guard exception cadence, and thread-pool worker/callback wakeups.
  • Observe-only provider/persistence telemetry for Cloud Files / ProjFS callbacks, transacted registry/file handles, KTM commit/rollback outcomes, and ACPI method-evaluation requests.

15.5 False-Positive Control

Every block-grade detection must carry, at minimum: owning module path, signer and certificate chain, load time, object name or pointer address, process context, call cadence or trigger pattern, known-good vendor classification, Windows build and symbol profile. Do not ban on “unknown” alone. Ban-quality cases require either a direct integrity violation (modified code page, modified .data pointer with no documented registration path) or multiple correlated suspicious signals across independent views. The economics are unforgiving: a single false-positive ban consumes more support-team time than a hundred true positives. A contain-before-verdict pattern works well: degrade the cheat’s effectiveness (clear an MSI provisioning, re-protect a region, force a section unmap) without committing to a ban.

16. Synthesis: Realistic Limits

The practical limit is simple: defenders cannot rely on IOCTL inspection or suspicious device names. Mature kernel-assisted threats move through legitimate OS mechanisms — sections backed by dxgkrnl, callbacks registered through documented APIs, fences indistinguishable from frame-pacing primitives, escape paths that look exactly like vendor utilities. The defender’s wins come from owner attribution, pointer integrity, object inventory, process behavior, and version-aware baselines. Where the surface lives below the kernel or outside the host entirely, software detection alone cannot close the gap. The required moves are platform attestation, IOMMU enforcement, workload-specific policy, and behavior-side detection that operates independently of on-device telemetry.

Key Takeaways

  • Channels are protocols assembled from six planes (rendezvous, trigger, selector, payload, reply, lifecycle) — not single APIs. Single-surface checks fail because the wake edge, payload bus, and reply path can each live in a different Windows primitive.
  • The grammar repeats across surfaces. Magic, version, channel ID, role, generation, sequence, command ID, flags, lengths, status, heartbeat, timeout, nonce, checksum/MAC — transports change, the grammar does not. Identify these fields first when triaging a suspected channel.
  • Owner attribution beats name matching. A familiar variable name under an attacker-chosen GUID is not familiar. A familiar callback pointer reaching a jmp rcx gadget with attacker-controlled context is not safe. A familiar AFD socket whose FILE_OBJECT->DeviceObject points to an unknown driver is not normal.
  • PatchGuard exposure is the technique filter. PG-Conflict techniques are dead; PG-Risky persist with watchdogs; PG-Safe and PG-Bypass surfaces are where active engineering happens.
  • Cross-view validation defeats spoofing. ALPC connection-port views, handle tables, ETW, VAD/section deltas, and kernel object walks rarely all lie consistently. The combination is what makes evidence durable.
  • Hardware/external (L4–L6) cannot be closed by on-device software. DMA cards, VMI, and capture-card vision must be answered with IOMMU/DMAr policy, server-side behavioral detection, and platform attestation.
  • Baselines must be per-build. The most common production regression is not a missed technique; it is a Windows build that shifted a structure by 8 bytes.
  • Provider/persistence surfaces are forensic, not live. Treat UEFI, TPM, CLFS, KTM, and ACPI evidence as artifacts with provenance and retention rather than live command buses.
  • The thread pool is a wake edge, not a thread spawner. A normal worker waking on a TP_ALPC/TP_JOB/TP_WAIT/TP_TIMER trigger and immediately consuming a suspicious mailbox is the pattern.
  • Static .data pointer manifests are stronger than slot allowlists. Build a “callable writable pointer” manifest with expected target, expected mutability class, and user-mode trigger path.

Defensive Recommendations

  • Enforce a layered platform floor. Stack four independent controls — Secure Boot, TPM 2.0, HVCI/Memory Integrity, and IOMMU/Kernel DMA Protection — rather than relying on any single switch.
  • Inventory the legitimate communication surfaces at boot and at protected-workload launch. Device objects, IOCTL paths, sections, ALPC ports, named pipes, RPC endpoints, COM local servers, WNF state names, FltMgr ports, WFP providers/callouts, virtual HID stacks, Cloud Files / ProjFS roots, I/O rings, CLFS logs, transactional file/registry activity.
  • Validate dispatch and .data pointer integrity. Every MajorFunction, FastIoDispatch, callback array entry, HalPrivateDispatchTable slot, and writable control pointer must land at a documented function entry inside an expected module — not merely inside the module’s mapped range. Chase short branch chains for multi-stage hooks.
  • Validate PEB->KernelCallbackTable end-to-end. Confirm the pointer is inside user32.dll, hash the entire apfnDispatch array against a per-build clean baseline, and treat post-init changes as integrity anomalies.
  • Treat unknown signed drivers as untrusted until every object, callback, section, and memory mapping they own is accounted for.
  • Capture WSK and kernel-originated egress. Non-network drivers contacting remote endpoints during protected-workload runtime are high-value telemetry. Look for hand-assembled HTTP/JSON request builders, hard-coded license/config endpoints, and parse-and-arm response handling.
  • Decode private surface formats correctly. WNF state names need a build-validated decoder; _OBJECT_HEADER->TypeIndex is obfuscated on Windows 10+ and must be XORed with nt!ObHeaderCookie and the second byte of the header address; _HANDLE_TABLE_ENTRY on modern x64 uses bitfield encoding, not EX_FAST_REF.
  • Correlate cross-view. ALPC namespace vs. handle table vs. ETW vs. communication-port relationships; process list vs. PspCidTable vs. ETW lifecycle; section objects vs. VADs vs. handle ownership; GUI callback pointers vs. user32!apfnDispatch baseline.
  • Add MDL and locked-page provenance to memory telemetry. A small one-time trigger followed by a long-lived locked private buffer with command cadence (and no matching hardware/direct-I/O role) is the MDL mailbox signature.
  • For competitive or high-trust workloads, write hardware policy. No unknown programmable PCIe switches, no unexplained CXL devices, no development boards; require DMA-remapping-compatible storage/PCIe drivers; restrict capture and KVM topology in tournament environments.
  • Track AFD socket file-object provenance. For high-risk processes, resolve socket handles to their FILE_OBJECT and validate FILE_OBJECT->DeviceObject against the expected AFD stack — per-handle route substitution leaves no global dispatch artifact.
  • Inventory thread-pool wake sources. WorkerFactory handles, I/O completion handles, timer queues, TP_IO/TP_ALPC/TP_JOB/TP_WAIT/TP_TIMER associations, callback target modules, and post-wake memory access.
  • Contain before you ban. A degrade-effectiveness response (clear MSI provisioning, re-protect a region, force a section unmap, drop a WFP filter) preserves evidence and avoids irreversible false positives.

Conclusion

The covert KM/UM channel landscape on Windows in 2026 is wide, mature, and heavily entangled with legitimate OS behavior. No single check defeats it. The defender’s leverage comes from treating every artifact as a small protocol assembled from documented Windows primitives, capturing the six protocol planes for each surface, baselining per-build and per-vendor, and forcing the attacker to lie consistently across independent views. Where on-device software cannot reach — CPU and hypervisor below the kernel, DMA hardware and visual capture outside the host — the answer is IOMMU/DMAr policy, server-side behavioral detection, and platform attestation. The catalog will keep growing as Windows ships new primitives and attackers discover new ways to misuse them, but the grammar of magic-version-channel-id-role-generation-sequence-command-flags-lengths-status-heartbeat-nonce-checksum stays the same. Reverse engineers should look for that grammar first; detectors should build inventories and baselines that make it impossible to hide.

Original text: “Covert Kernel/User Communication Channels on Windows: Rootkits, Game Cheats, and Detection” by kernullist at Kernullist’s Blog.

Comments are closed.