The Same-Privilege Paradox: Twenty-One Years of Windows Kernel Self-Defense
PatchGuard, KASLR, KDP, and the Win32k Lockdown are four answers to one paradox -- a defense at the attacker's privilege cannot succeed in principle. The 2005-2026 trajectory is migration out of the kernel.
Permalink1. If the attacker is already in the kernel, what is left to defend?
For three years, a Russian-attributed espionage rootkit called Uroburos ran on Microsoft's most heavily defended kernel -- the 64-bit Windows kernel with PatchGuard active -- and PatchGuard never made a sound [2]. The reason is the one the marketing copy will not tell you: PatchGuard is not, and was never designed to be, a security boundary; Microsoft says so in its own Security Servicing Criteria [1]. The twenty-one-year history of Windows kernel self-defense is the story of why the answer to "the kernel cannot defend itself from itself" turned out to be "stop trying to defend it from inside."
That sentence will read like editorial provocation until you see the architecture. Uroburos did not bypass PatchGuard. It side-stepped it. The rootkit shipped a signed-but-vulnerable copy of Oracle's VBoxDrv.sys, used the vulnerability to flip the g_CiEnabled flag that gates Driver Signature Enforcement, loaded its own unsigned kernel driver, and then operated alongside PatchGuard for three years (2011 -- 2014) without ever modifying anything PatchGuard checked [2] [3]. The Stage 2 evolution survey calls this the canonical refutation of the most common reader misconception about PatchGuard: not "PatchGuard was broken" but "PatchGuard's protected-structure list is, by construction, narrower than the kernel-modification surface."
A defense that shares its CPU privilege level with the attacker can in principle always be subverted by an attacker at that privilege level, because every code path and data structure the defense relies on is, by construction, mutable by the attacker. The paradox is not a formal impossibility theorem in the cryptographic sense, but it is the de facto design constraint Microsoft has acknowledged in writing through its Security Servicing Criteria [1].
A Microsoft kernel feature that periodically verifies a fixed list of kernel structures -- the SSDT, IDT, GDT, syscall MSRs, the in-memory nt and hal images, and select processor control registers -- and bug-checks the system with stop code CRITICAL_STRUCTURE_CORRUPTION (0x109) on mismatch. Introduced April 25, 2005 in Windows XP Professional x64 Edition and Windows Server 2003 x64 Edition; never shipped on x86 [4] [5]. PatchGuard is an engineering deterrent, not a security boundary.
This article covers four mitigations across twenty-one years -- April 25, 2005, when PatchGuard shipped with Windows XP Professional x64 Edition and Windows Server 2003 x64 Edition [4], through June 2026, when kCET and the VTL1-anchored stack are the front line. The four mitigations are PatchGuard (KPP), KASLR (and its 2018 successor KVA Shadow), KDP (Kernel Data Protection), and the two-stage Win32k Lockdown that began in 2012 with DisallowWin32kSystemCalls and resolved in 2017 with Win32kSystemCallFilter [6] [7]. They do not look like they belong together until you notice the direction. Each generation moves the defense one step further away from where the attacker lives: from in-kernel obfuscation, to address-space tricks, to hypervisor-anchored isolation (VTL1), to attack-surface deletion.
Every meaningful Windows kernel mitigation since 2017 has moved the enforcement to a privilege level the kernel-mode attacker cannot reach -- hypervisor (VTL1), CPU silicon (KTRR on Apple, kCET shadow stack hardware on Intel / AMD), or out of the syscall surface entirely. The reason is the same-privilege paradox: a defense that lives where the attacker lives cannot, in principle, succeed.
Four misconceptions are worth retiring before we start. First, "PatchGuard is the load-bearing kernel-rootkit defense"; in fact, Microsoft says it is not a security boundary at all, and Uroburos operated alongside it for three years. Second, "PatchGuard is x64-only"; the documentation is x64-centric, but in 2026 PatchGuard also runs on 64-bit ARM Windows -- the one architectural truth in the framing is that PatchGuard never shipped on 32-bit Windows. Third, "KASLR is dead because entropy is the variable that matters"; the Hund-Willems-Holz 2013 result and Gruss et al. 2017 generalization showed that randomness was never the load-bearing defense -- structural unreachability is [8] [9]. Fourth, "Win32k Lockdown killed half the LPE class"; the lockdown removes roughly the historically-vulnerable syscall surface from sandboxed renderers specifically, not from the operating system in general [10].
To see why Microsoft has spent twenty-one years on a problem that, by their own admission, has no in-kernel answer, we have to go back to April 25, 2005 -- and to the architectural break that made the new contract politically possible.
2. Why Microsoft built PatchGuard at all (1998 -- 2005)
Before April 2005, the Windows kernel was a public hooking surface by design. McAfee, Symantec, F-Secure, and Trend Micro patched the System Service Descriptor Table (SSDT), hooked the Interrupt Descriptor Table (IDT), and inline-patched nt!Nt* system-service routines as legitimate engineering practice. The same primitives, applied with malicious intent, became the rootkit canon of the late 1990s and early 2000s: NTRootkit, FU, Hacker Defender. From the operating system's point of view, the defender and the attacker were architecturally indistinguishable.
A kernel data structure on Windows containing function pointers to every system service routine (the Nt* functions that implement system calls). On 32-bit Windows, anti-virus vendors routinely patched the SSDT to intercept system calls before the kernel processed them. On x64, modifying the SSDT is prohibited and PatchGuard treats it as a CRITICAL_STRUCTURE_CORRUPTION event [5].
The symmetry was awkward enough in normal operation. It became politically untenable in October 2005, when Mark Russinovich discovered that Sony BMG's XCP DRM software, shipped on tens of millions of audio CDs, installed an actual cloaking rootkit on consumer Windows machines. Russinovich's October 31, 2005 Sysinternals post "Sony, Rootkits and Digital Rights Management Gone Too Far" turned a niche kernel-internals topic into national news within a week. The lawsuit settlements and CD recall that followed established, in pop-culture terms, the symmetry between "legitimate kernel hooking" and "malware kernel hooking" that the security industry had been arguing about for years. The XCP code was structurally identical to malware -- it hid files whose names began with $sys$, modified system calls, and resisted removal -- and it shipped under a Sony certificate.
What Microsoft needed was an architectural break large enough that they could rewrite the kernel contract without having to honor the old one. They got it from AMD. The x64 architecture, productised as AMD64 and adopted by Intel as EM64T, was Microsoft's once-in-a-decade chance to publish a new contract incompatible with the old. Windows XP Professional x64 Edition and Windows Server 2003 x64 Edition shipped on April 25, 2005 [4]. The new kernel-mode contract had two enforcement layers. PatchGuard was the engineering enforcement -- the code that periodically inspected the kernel's most sensitive structures and bug-checked the system on mismatch. Kernel-Mode Code Signing (KMCS) was the policy enforcement -- the rule that production x64 kernels would load only Authenticode-signed drivers.
The policy on 64-bit Windows that the kernel will load only Authenticode-signed kernel drivers in production (test-signing modes exist for development). KMCS shipped with the same April 2005 release as PatchGuard and is its policy counterpart -- KMCS controls what code enters the kernel; PatchGuard checks the kernel structures the loaded code is expected to leave alone [5].
The combination did exactly what the AV industry feared. Their entire detection methodology was, by the new contract, illegal on x64. McAfee bought a full-page ad in the Financial Times in October 2006 to call Microsoft's behaviour anti-competitive. Symantec joined the EC complaint. The verbatim industry framing was delivered by Vincent Weafer, then Symantec's senior director of security response, in a CRN report: "Either everybody has access to the kernel or nobody has access to the kernel -- and we believe in the latter" [11]. Microsoft declined to publish a signed bypass API. By the time the dust settled, the AV-vendor hooking pattern on Windows had been industrially ended.
"Either everybody has access to the kernel or nobody has access to the kernel -- and we believe in the latter." -- Vincent Weafer, Symantec, quoted in CRN, September 25, 2006 [11].
The historical record has one quirk worth flagging. No primary 2005 PatchGuard launch document is preserved in Microsoft's current documentation surface; the earliest official primary is Microsoft Security Advisory 932596 from August 2007, which describes Kernel Patch Protection as protecting "code and critical structures in the Windows kernel from modification by unknown code or data" and announces an upcoming PatchGuard update [4]. The technical detail of what PatchGuard checked was reverse-engineered by the offensive security community before Microsoft documented it.
Diagram source
gantt
title Windows kernel self-defense, 2005-2026
dateFormat YYYY-MM
section Same-privilege (CPL=0)
PatchGuard v1 :2005-04, 2008-02
PatchGuard v2-v3 :2006-11, 2010-10
PatchGuard v7-v8 :2012-08, 2026-06
KASLR (8-bit entropy) :2007-01, 2018-01
section CPU mediated
KVA Shadow :2018-01, 2026-06
kCET / shadow stack :2022-09, 2026-06
section VTL1 anchored
HVCI :2015-07, 2026-06
kCFG with VBS bitmap :2017-04, 2026-06
KDP static plus dynamic :2020-05, 2026-06
section Surface deletion
DisallowWin32kSystemCalls:2012-08, 2017-10
Win32kSystemCallFilter :2017-10, 2026-06 So the contract was published, the kernel was no longer a public hooking surface, and Microsoft shipped a feature called PatchGuard that ran inside the kernel and checked the kernel's most sensitive structures. The question Skywing and skape would publish nine months later was the question everybody in offensive security had been waiting for: how do you defend a kernel from inside the kernel?
3. PatchGuard v1 and v2: obfuscation as defense (2005 -- 2008)
PatchGuard v1 was an engineering answer to a political problem. It worked exactly the way a defense works if you do not state out loud that the attacker is in the same address space: a periodic timer fired, a checksum was recomputed, a mismatch caused the machine to bug-check with stop code CRITICAL_STRUCTURE_CORRUPTION (0x109), and the assumption was that the cost of figuring out which timer, which checksum, and which DPC handler was high enough to deter casual rootkit authors. And for nine months, that was the story.
The Windows bug-check stop code raised by PatchGuard when one of its periodic integrity checks detects an unexpected modification to a protected kernel structure. The bug-check call goes through KeBugCheckEx, which on later PatchGuard generations is itself a protected structure -- swallowing the bug-check from a hooked KeBugCheckEx was one of the four bypass classes Skywing and skape catalogued in 2005 [12].
What does PatchGuard actually check? The protected-structure list has grown across generations, but the core, as Microsoft documents it for driver authors, has been remarkably stable [5]:
- The SSDT and
KeServiceDescriptorTable[Shadow](the function-pointer tables that dispatch system calls) - The Interrupt Descriptor Table (IDT), read from the CPU via
IDTR - The Global Descriptor Table (GDT), read from the CPU via
GDTR - The syscall-related model-specific registers:
IA32_LSTAR,IA32_STAR,IA32_CSTAR, and theIA32_SYSENTER_*family - The in-memory
ntandhalkernel images (so you cannot inline-patchnt!NtCreateFile) KdpStub,KeBugCheckCallbackHead, and other kernel call-back tables- Select processor control registers and debug registers
Mechanism: a context block built by nt!KiInitializePatchGuard at boot, scattered across allocations, XOR-encrypted; a DPC-driven verifier routine that fires at randomized intervals; a per-fire recomputation of expected checksums; a KeBugCheckEx(0x109, ...) call on any mismatch. The load-bearing property of the design -- the one that drives the rest of the story -- is that the defense lives at CPL=0, alongside the attacker. The verifier, the keys, the schedule, the bug-check routine itself: all of it lives in the same address space as the rootkit it is meant to detect.
Diagram source
flowchart TD
A[Timer fires at random interval] --> B[DPC routine dispatched]
B --> C[Decrypt scattered context fragment]
C --> D[Hash protected structures]
D --> E{Hash matches expected}
E -- yes --> F[Reschedule next check]
E -- no --> G[Call KeBugCheckEx 0x109]
G --> H[System bug-check CRITICAL_STRUCTURE_CORRUPTION]
F --> A In December 2005, eight months after PatchGuard shipped, Skywing and skape published "Bypassing PatchGuard on Windows x64" in Uninformed Volume 3 [12]. The paper enumerated four architectural bypass classes that would, with minor variations, survive every PatchGuard generation Microsoft has shipped since:
- Patch the verifier timer. If you control the DPC queue, you can prevent the check from ever firing.
- Hook the verification callback. Replace the function pointer the DPC routine is dispatched through.
- Replace the DPC routine. Rewrite the bytes of
nt!KiPatchGuardCheckRoutineitself, before it executes. - Swallow the bug-check. Hook
KeBugCheckExso that the eventual mismatch call returns to the attacker's handler instead of crashing the system.
KiInitializePatchGuard initialization routine itself uses the "scattered initialization" tradition Microsoft inherited from Windows 2000 -- the context block is not allocated as a single contiguous structure but assembled from fragments at randomized offsets, each XOR-keyed against a derived value the verifier alone reconstructs at check time. The fragments are referenced through call-graph paths designed to be inaccessible to a static reader. This is exactly the engineering cost layer that Skywing's 2005 paper would later identify as raising the cost of bypass without affecting any structural bypass class.
The thesis the Uninformed paper stated in its abstract was the framing Microsoft would not formally adopt in writing for another twelve years: any defense at the same privilege as the attacker can be subverted in principle, because the attacker can do anything the defense can do -- including reading the obfuscation key and rewriting the check. The argument is structural, not empirical. Skywing's contribution was not "we broke PatchGuard"; it was "PatchGuard's class of defense has a fixed structural ceiling, and the ceiling is below 'security boundary.'"
Microsoft did exactly what you would expect a serious engineering organisation to do when an obfuscation layer is partially peeled back: they added another. PatchGuard v2 shipped in 2006 servicing updates and was inherited by Vista x64 in November 2006. It introduced an XOR-encrypted-and-scattered context, decoy DPC routines, a generalised anti-hook framework that flagged modifications to additional kernel function tables, and randomized timer phase. In January 2007 Skywing published "Subverting PatchGuard Version 2" in Uninformed Volume 6, walking through the v2 hardening in detail and demonstrating that the same four bypass classes survived [16]. The engineering cost was raised; the structural ceiling was not.
It is worth seeing the integrity check as a teaching primitive. The real implementation is hardened with anti-disassembly and anti-debugging tricks that we will not reproduce; the underlying control loop is plain.
// Conceptual demonstration only -- the real PatchGuard is far more obfuscated
const protectedStructures = {
SSDT: 'eb2f4c1abe007f29d6c910a9c66e0b21',
IDT: '7c4b48a39b22d5f0a1e4ecb0d80b1c2a',
GDT: '0d1f3a72b9aa6d8a14e88f9d22cc66ab',
KeBugCheckEx: '6677aabbccdd0011223344556677ff88',
};
const expected = {...protectedStructures};
function hashStructure(name) {
// In real KPP this is a derived hash over current memory contents
return protectedStructures[name];
}
function patchguardCheck() {
for (const name of Object.keys(expected)) {
if (hashStructure(name) !== expected[name]) {
// KeBugCheckEx(CRITICAL_STRUCTURE_CORRUPTION, ...)
console.log('BUGCHECK 0x109 on', name);
return;
}
}
console.log('All structures intact -- reschedule');
}
// Simulate one tick of the verifier
patchguardCheck();
// Simulate an attacker modifying SSDT
protectedStructures.SSDT = 'ffffffffffffffffffffffffffffffff';
patchguardCheck(); Press Run to execute.
The toy is honest about the shape: a verifier walks a fixed list, computes a hash, compares against a stored expected value, calls a bug-check on mismatch. Everything Skywing's bypass classes targeted -- the verifier's schedule, the verifier's code, the expected-hash store, the bug-check primitive -- is sitting in the address space the attacker also writes.
By January 2007, the pattern was set. Microsoft adds an obfuscation layer; Skywing peels it back; Microsoft adds another. Both sides were right. Microsoft was right that the engineering cost mattered: the AV-vendor hooking pattern was being industrially ended, signed third-party kernel drivers were a much narrower entry point than the old free-for-all, and casual rootkit authors were locked out of the bypass class. Skywing was right that engineering cost is not a security boundary. The next decade would prove both.
4. The evolution, generation by generation (2008 -- 2016)
Twelve years of cat-and-mouse ran on two parallel tracks. PatchGuard added DPC-based checks in v3 (Vista SP1 / Server 2008, February 2008) [17], HAL function-table verification and stack-context randomisation in Windows 7 -- 8 (2009 -- 2012), and a context-block ring in Windows 8.1 (2013) -- which Andrea Allievi reverse-engineered at NoSuchCon 2014, again finding four independent bypass paths [14]. Meanwhile, two quieter developments laid the groundwork for what was coming: KASLR shipped on Vista x64 in 2007 [18], and Jurczyk and Coldwind's Bochspwn project in 2013 falsified the industry's assumption that win32k LPE bugs were a tail of accidents [19].
The PatchGuard generation ladder
Each generation tightened the engineering cost without changing the structural ceiling. The table below summarises the evolution; the right-most column lists the canonical reverse-engineering primary, which in every generation came from outside Microsoft.
| Generation | Year, OS first shipped | Key delta | Canonical reverse-engineering primary |
|---|---|---|---|
| v1 | April 2005, XP x64 / Server 2003 SP1 x64 | Baseline -- single context block, fixed protected-structure list, single DPC | Skywing & skape, Uninformed v3, Dec 2005 [12] |
| v2 | 2006 servicing, inherited by Vista x64 Nov 2006 | XOR-encrypted scattered context, decoy DPCs, anti-hook framework | Skywing, Uninformed v6, Jan 2007 [16] |
| v3 | Vista SP1 / Server 2008, Feb 2008 | Multiple concurrent contexts, randomised timer phase, KeBugCheckEx self-protection | Skywing, Uninformed v8, Sep 2007 [17] |
| v7 (Windows 7) | 2009 -- 2010 | HAL function-table verification, stack-context randomisation | Community RE; no single canonical paper |
| v8 (Windows 8) | 2012 | KeServiceDescriptorTableShadow added (now covers win32k syscall table), expanded MSR list | Community RE |
| v8.1 | 2013 (Windows 8.1) | Single context block replaced by context-block ring; atomic patching of every block required; 247 protected structures (vs ~26 on Vista x64) | Andrea Allievi, NoSuchCon 2014 [14] |
Allievi's 2014 talk is the clearest single picture of what hardening looked like by the Windows 8.1 era. The single context block had become a singly-linked list (SLIST) of context blocks. The cryptographic self-integrity check now ran across the SLIST. The protected-structure set had grown from roughly twenty-six on Vista x64 to two hundred and forty-seven by Windows 8.1, including HalPrivateDispatchTable and HalpInterruptController [14]. And the four 2006 bypass classes still worked. The engineering cost of bypassing PatchGuard had risen by an order of magnitude; the architectural class of bypass had not changed.
KASLR on Vista, February -- April 2007
In parallel with the PatchGuard generation ladder, Microsoft shipped a different style of defense on the same kernel. Mark Russinovich's three-part Inside the Windows Vista Kernel series in TechNet Magazine documented the new mitigation in April 2007 [18]: the kernel image base, instead of being constant, was selected at boot from a small space of possible offsets.
Randomising the kernel image base across boots, so that an attacker with a stale or guessed kernel address cannot use it as an absolute reference. On Vista x64 the implementation had roughly eight bits of entropy (256 possible kernel base addresses), selected at boot time by winload.exe [18]. The mitigation is probabilistic by construction: it raises the cost of an unprivileged information-leak, but cannot survive a deterministic side-channel attacker.
winload.exe, was the component that picked the kernel image base at boot. The choice of selecting the offset early -- before the kernel proper executes -- was deliberate; KASLR after the kernel is mapped is harder to do because every kernel pointer recorded so far becomes invalid. The Vista bootloader was also the component PatchGuard's protected list depended on: an attacker with bootloader code execution simply chose their own offset.
The probabilistic framing held until 2013. Hund, Willems, and Holz published "Practical Timing Side Channel Attacks Against Kernel Space ASLR" at IEEE S&P 2013 [8]. Their technique exploited the shared TLB and cache state between user mode and kernel mode on every x86 / x64 CPU then shipping: an unprivileged user-mode timer could measure differential cache behaviour when accessing addresses near where the kernel mapped its image, and recover the kernel base in seconds. Eight bits of entropy collapse fast under a side-channel that gives you one bit per probe. Gruss et al. generalised the argument in 2017 with a paper whose title was the thesis: "KASLR is Dead: Long Live KASLR" [9]. The structural answer would have to be something other than entropy.
The 2012 Windows 8 attempt at attack-surface deletion
While KASLR's structural limits were being demonstrated in academia, Microsoft shipped a different style of mitigation in Windows 8: DisallowWin32kSystemCalls, a process-level option enabling the kernel to refuse every win32k system call from a process that opted in [6]. The semantics are all-or-nothing: a process either can call into win32k.sys or it cannot. Useful for non-UI broker processes (where the answer is "never"). Structurally inadequate for browser renderers, which need to draw windows, render fonts, and dispatch input through a constrained-but-non-empty subset of the win32k surface. The mitigation languished for five years, waiting for the per-syscall version that arrived in 2017.
The Bochspwn empirical surprise
In 2013, Mateusz Jurczyk and Gynvael Coldwind presented Bochspwn at SyScan and at Black Hat USA [19] [20]. The methodology was a Bochs x86 emulator instrumented to trace every memory access made by the kernel during syscall handling. The instrumentation found classes of bugs -- specifically double-fetch bugs, where the kernel reads the same user-controlled memory twice without re-validating between reads -- by tagging each user-pointer dereference and looking for repeats.
Jurczyk's empirical finding mattered because it pre-dated the design of the eventual lockdown by four years. The community knew, by mid-2013, that win32k.sys was a bug class, not a bug tail. Microsoft's eventual answer -- per-process filtering of the win32k syscall surface -- had a clean empirical motivation by the time it shipped.
The pre-Bochspwn high-profile example was already in the literature: Bruce Dang and Peter Ferrie's December 2010 talk at the 27th Chaos Communication Congress ("Adventures in Analyzing Stuxnet") had named CVE-2010-2743, awin32k.sys NtUserLoadKeyboardLayoutEx LPE that Stuxnet used to escalate from user to kernel on Windows XP [21]. Stuxnet placed one of the most consequential kernel-level malware operations on record on top of a single win32k vulnerability. Bochspwn explained why: the surface was structurally vulnerable, not accidentally so.
The intellectual surprise of this act -- Uroburos coexisted with PatchGuard
The cleanest demonstration that the same-privilege paradox is empirical, not theoretical, came in February 2014. G Data SecurityLabs published its analysis of Uroburos, a Russian-attributed espionage rootkit that had been operating in production for an estimated three years [2]. Uroburos did not bypass PatchGuard. It loaded a copy of Oracle's VBoxDrv.sys (a signed third-party driver shipped as part of VirtualBox), used a privilege-escalation vulnerability in that driver to flip the g_CiEnabled flag (the gate for Driver Signature Enforcement), loaded its own unsigned rootkit driver, and then operated for three years in production without ever modifying anything PatchGuard checked [3].
The policy on 64-bit Windows that the kernel will load only Authenticode-signed drivers in production. DSE is gated by an in-memory flag (nt!g_CiEnabled historically, nt!g_CiOptions on later builds). An attacker with arbitrary kernel write can flip the flag and load unsigned drivers -- which is precisely how the BYOVD attack pattern works [2] [22].
Three insights converged from this act. From the side-channel KASLR literature: some defenses cannot succeed at CPL=0 because the attack is below the operating system. From Allievi 2014 and Uroburos 2011 -- 2014: same-privilege obfuscation is permanently bounded by engineering cost, no matter how much engineering cost you pay. From Bochspwn: win32k is not a bug tail but a bug class -- the only structural answer is to delete the surface rather than defend it. The 2017 calendar year was about to land all three answers at once.
5. 2017's triple inflection
In a single calendar year, three mutually independent breakthroughs reshaped kernel self-defense. June 2017: CyberArk's Kasif Dekel published GhostHook, an Intel-PT-based PatchGuard bypass that forced Microsoft's first public statement that PatchGuard is not a security boundary [23]. July 2017: Gruss et al. published "KASLR is Dead: Long Live KASLR" at ESSoS, proposing kernel page-table isolation as the structural answer [9]. October 2017: Windows 10 1709 shipped Win32kSystemCallFilter, the per-process, per-syscall allow-list designed for the Chrome and Edge renderer sandboxes [7]. Three teams, three mitigations, three facets of the same paradox.
Win32kSystemCallFilter (October 17, 2017)
The Windows 8 mitigation DisallowWin32kSystemCalls had been the right idea applied as a meat-axe: an opted-in process loses access to every win32k system call. Windows 10 1709 introduced the surgical version. PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY registers a per-process bitmap of system-defined FilterId values that the process is allowed to call; everything outside the bitmap is denied [7]. The filter is applied via UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, ...) at CreateProcess time -- not at runtime.
A Windows 10 1709+ process-mitigation policy (PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY, header ntddk.h) that registers a per-process bitmap of allowed system-defined FilterId values for win32k system calls. Calls outside the bitmap terminate the calling process. Used by the Chromium sandbox to constrain the win32k surface available to a renderer process [7] [24].
The "at CreateProcess time, not at runtime" detail is load-bearing. James Forshaw and Ivan Fratric's November 2016 Project Zero post "Breaking the Chain" documented how Edge's window-broker architecture, which applied syscall restrictions to a child process after it had started, was subject to a window-of-opportunity race between the child's earliest syscall and the broker's policy application [10]. If the policy is not in place by the time the first attacker-controlled syscall fires, the policy has not happened. The lesson the Windows 10 1709 design banked: mitigations belong on the CreateProcess boundary, not on a later thread.
Diagram source
sequenceDiagram
participant R as Renderer process (VTL0 user)
participant SD as Syscall dispatcher (kernel)
participant W as win32k handler
participant EP as EPROCESS filter bitmap
R->>SD: NtUser/NtGdi syscall with FilterId N
SD->>EP: Consult per-process filter bitmap
EP-->>SD: bit N set or unset
alt FilterId allowed
SD->>W: Dispatch to win32k handler
W-->>R: Return result
else FilterId denied
SD->>R: Terminate process via fast-fail
end The cleanest way to see the two-mitigation contrast is side by side:
| Property | DisallowWin32kSystemCalls | Win32kSystemCallFilter | Chromium's actual choice |
|---|---|---|---|
| First shipped | Windows 8, 2012 [6] | Windows 10 1709, October 2017 [7] | Both, in different process types |
| Granularity | All-or-nothing | Per-syscall allow-list | Blanket-disable for non-UI; per-syscall for renderer |
| Mitigation policy struct | PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY | PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY | Composes both with LPAC privilege reduction |
| Use case | Non-UI broker processes (GPU broker, network process) | Renderer processes that draw windows | The renderer needs a constrained-but-non-zero win32k subset [24] |
The Chromium sandbox composes the two mitigations with one more: the Less Privileged AppContainer (LPAC). LPAC removes ambient access to user data, the network, and most named-object namespaces; Win32kSystemCallFilter removes the syscall surface; DisallowWin32kSystemCalls applies to processes that need no UI at all. Defense in depth at the surface level rather than the structural level.
A Windows AppContainer variant introduced in Windows 10 that further restricts the ambient capabilities available to the contained process -- no access to user files, no access to most named objects, restricted ability to enumerate the system. Combined with Win32kSystemCallFilter, LPAC gives the Chromium renderer a process model in which both what the renderer can ask the kernel to do and what the renderer can see in user mode are deliberately narrow [24].
KAISER and the page-table split
In July 2017, Gruss et al. presented "KASLR is Dead: Long Live KASLR" at ESSoS [9]. The acronym was KAISER -- Kernel Address Isolation to have Side-channels Efficiently Removed. The architecture is simple to describe, hard to engineer, and devastating to a side-channel attacker.
A modern x64 kernel runs in the same virtual address space as the calling user process, distinguished by privilege bits in page-table entries. A syscall does not change the page tables; it only changes the privilege level. The TLB is therefore shared between user and kernel mappings, and side-channel attacks like Hund 2013 work by timing the resulting cache and TLB behaviour. KAISER's answer was to give each process two sets of page tables: a "user" CR3 in which the kernel address space is not mapped, and a "kernel" CR3 in which the full virtual address space is mapped. The syscall entry path switches from user CR3 to kernel CR3; the sysret path switches back. The kernel address space is not just unknown to a user-mode attacker -- it is structurally unreachable.
A design proposed by Gruss et al. (KAISER, ESSoS 2017) [9] in which each process has two page-table hierarchies: a user CR3 that does not map the kernel and a kernel CR3 that maps both. CR3 is switched on every syscall entry and exit. The kernel is no longer just hard to find (the KASLR posture); it is unreachable from user CR3 (the structural posture). Linux shipped KAISER as KPTI in early 2018; Microsoft shipped a re-engineered variant as KVA Shadow [13].
Diagram source
sequenceDiagram
participant U as User-mode thread
participant CPU as CPU CR3
participant K as Kernel
U->>CPU: syscall (SYSCALL instruction)
CPU->>CPU: Switch CR3 from user to kernel
CPU->>K: Kernel now mapped, enter system service
K->>K: Handle request
K->>CPU: SYSRET
CPU->>CPU: Switch CR3 back to user
CPU->>U: Return to user mode, kernel unmapped The Gruss paper landed six months before anyone knew why it mattered. Then, on January 3, 2018, Jann Horn published "Reading privileged memory with a side-channel" on Project Zero [25], the same day the academic teams (Lipp et al., independently) published the Meltdown disclosure [26]. Meltdown -- CVE-2017-5754, "rogue data cache load" -- exploited transient out-of-order execution on Intel CPUs to read kernel memory from user mode. The only structural fix was to ensure the kernel pages were not present in the user-mode page table. KAISER's design, drafted as a generic side-channel countermeasure, was suddenly Meltdown's required mitigation.
GhostHook and the formal admission
In June 2017, Kasif Dekel published GhostHook [23]. The mechanism is elegant. Intel Processor Trace (Intel PT) is a CPU feature for low-overhead recording of control flow, designed for performance analysis and debugging. The trace is written to a Table of Physical Addresses (ToPA), and when a configured ToPA region fills, the CPU raises a performance-monitoring interrupt (PMI). The OS's PMI handler is a function pointer. PMI handlers run in kernel mode, with full kernel privilege. GhostHook configured Intel PT with a tiny ToPA covering an address near IA32_LSTAR (the syscall entry MSR), arranged for the buffer to fill immediately, and registered an attacker-controlled PMI handler. Every kernel transition fired the PMI; the attacker's handler ran first. PatchGuard does not enumerate Intel PT. By design.
Microsoft's response, as reported in the CyberArk write-up, was the formal end of an eleven-year ambiguity. PatchGuard is "considered an in-depth security feature" but not a security boundary; the GhostHook bypass would "be considered for a future version of Windows" but did not warrant an out-of-band fix [23]. The Microsoft position aligns with the Security Servicing Criteria: admin-to-kernel is not a security boundary, and an attacker who has already reached kernel mode (the precondition for installing a GhostHook-style PMI handler) is outside the scope of what PatchGuard exists to prevent [1].
"While the technique was found to bypass PatchGuard, Microsoft has graciously agreed to consider [the issue] for a future version of Windows. As such, no immediate risk exists for customers." -- Microsoft response to GhostHook, June 2017 [23].
The three breakthroughs of 2017 were structurally aligned. Win32kSystemCallFilter deleted the most-vulnerable syscall surface from sandboxed renderers. KAISER's page-table split made KASLR's probabilistic defense obsolete and structurally unreachable. GhostHook forced the public admission that the same-privilege class of defense has a ceiling Microsoft already knew about. And then, on the morning of January 3, 2018, the academic paper of six months earlier became an emergency engineering deliverable.
6. State of the art: KDP, KVA Shadow, kCFG, kCET, and the Secure Kernel shift (2018 -- 2026)
January 3, 2018: Meltdown's public disclosure forces every major operating system to ship page-table isolation within weeks [25]. Microsoft's response, KVA Shadow, ships in the Windows 10 1709 cumulative security update the same day. The engineering write-up is bylined to Ken Johnson of the Microsoft Security Response Center [13]. The same Ken Johnson who, twelve years earlier, co-authored Bypassing PatchGuard on Windows x64 under the name Skywing [12]. The offensive-research outsider had become the bylined Microsoft defender. The same loop was about to close on the architectural question: where, exactly, does the defense live?
The Ken Johnson / Skywing trajectory -- offensive Uninformed paper in 2005, the bylined MSRC blog post in 2018, twelve years later -- is the cleanest single illustration of the offensive-research-to-Microsoft pattern. He is engineering credit attributed to Ken Johnson on the MSRC byline; the offensive identity is widely known but not asserted by Microsoft. Either reading of the byline is valid; the structural point is that the same person whose 2005 paper identified the architectural ceiling of CPL=0 obfuscation later shipped the cross-privilege answer for Meltdown [12] [13].KVA Shadow: the productisation of KAISER
KVA Shadow is the Windows productisation of KAISER. Two CR3-loadable page tables per process: a user-mode shadow that does not map most of the kernel, and a kernel-mode page table that does. CR3 is switched on every syscall entry and exit. The kernel address space is unmapped from user CR3 [13]. The structural Meltdown fix is exact: a Meltdown-class transient read of a kernel address from user mode now hits an unmapped page-table entry and raises a fault before any cached side-channel evidence is produced.
Two things to be precise about. First, KVA Shadow addresses Variant 3 (Meltdown, CVE-2017-5754) only. Spectre Variant 1 (CVE-2017-5753), Variant 2 (CVE-2017-5715), and Variant 4 (Speculative Store Bypass) require their own mitigations (microcode updates, retpoline, IBRS / IBPB, SSBD); KVA Shadow does nothing for them [26]. Second, the performance cost of the CR3-switch on every syscall is real -- Fortinet's analysis of the KVA Shadow build measured significant slowdowns for syscall-heavy workloads, mitigated on newer CPUs by Process-Context Identifiers (PCID) that keep TLB entries valid across CR3 switches [27].
HVCI: the VTL1 enabler
Hypervisor-Protected Code Integrity (HVCI) is not, strictly, a kernel defense -- it is the foundation everything else in the modern stack stands on. HVCI uses Virtualization-Based Security (VBS) to run a small Secure Kernel in Virtual Trust Level 1 (VTL1), one privilege level above the NT kernel in VTL0. The Secure Kernel manages the Second-Level Address Translation (SLAT) page tables -- Intel EPT or AMD NPT -- that mediate physical memory access for the NT kernel. With HVCI on, kernel pages are managed W^X (writable XOR executable): a kernel-mode driver attempting to make a writable page executable triggers a SLAT fault that VTL1 catches.
A Windows architecture in which the hypervisor partitions the system into two Virtual Trust Levels. VTL0 hosts the normal NT kernel, drivers, and user-mode processes. VTL1 hosts a Secure Kernel and a small set of trustlets that enforce policy on VTL0. Cross-VTL transitions are mediated by the hypervisor; a VTL0 kernel-mode attacker cannot reach VTL1, even with arbitrary kernel write. VBS is the architectural primitive that makes HVCI, KDP, and kCFG-with-VBS-bitmap possible [15].
For this article HVCI is the cross-cutting dependency: it is what makes KDP and the VBS-protected kCFG bitmap work. Once you have a hypervisor enforcing SLAT on the NT kernel, every defense you want to anchor outside the NT kernel has a home.
KDP: static and dynamic kernel data protection
Microsoft announced Kernel Data Protection on July 8, 2020, with Windows 10 version 2004 [15]. Two flavours.
Static KDP uses the MmProtectDriverSection API, called from DriverEntry, to mark a section of the driver's image as read-only for the rest of the kernel's lifetime. The intended use is for tables of policy data the driver expects never to modify after initialisation: function-pointer arrays, configuration constants, signed policy blobs. Once MmProtectDriverSection returns, the section's pages are tagged read-only in the VTL1-managed SLAT; a VTL0 kernel-mode attempt to write them takes a hardware page fault that VTL0 has no way to relax.
Dynamic KDP is for runtime-allocated state. The canonical API is ExAllocatePool3, called with a POOL_EXTENDED_PARAMETER array containing a POOL_EXTENDED_PARAMS_SECURE_POOL extended parameter [15]. The flags SECURE_POOL_FLAGS_FREEABLE (1) and SECURE_POOL_FLAG_MODIFIABLE (2) control whether the allocation can later be freed and whether further protected modifications are permitted. The secure-pool extension routes the allocation through the Secure Kernel; the resulting memory is verified by VTL1 and protected by SLAT.
A Microsoft kernel-memory protection introduced with Windows 10 version 2004 (July 2020) that allows drivers to mark sections of kernel memory as read-only and have the protection enforced by the Secure Kernel in VTL1 via the SLAT page tables. Static KDP uses MmProtectDriverSection; Dynamic KDP uses ExAllocatePool3 with a POOL_EXTENDED_PARAMS_SECURE_POOL extended parameter passed via POOL_EXTENDED_PARAMETER. The enforcement lives at a privilege level the VTL0 attacker cannot reach [15].
The Microsoft launch blog makes the architectural point in one sentence: "the memory managed by KDP is always verified by the secure kernel (VTL1) and protected using SLAT tables by the hypervisor" [15]. This is the first kernel self-defense mitigation in the Windows lineage whose enforcement is structurally outside the NT kernel. A VTL0 attacker with arbitrary kernel write cannot relax the SLAT entry that protects a KDP-tagged page, because the SLAT entry is managed by VTL1, and VTL1 is not in VTL0's address space.
Diagram source
flowchart TD
A[VTL0 NT kernel plus attacker driver] -->|attempt write to KDP-protected page| B[CPU memory access]
B --> C[SLAT page table consulted]
C --> D{SLAT entry writable for VTL0}
D -- no, RO by VTL1 --> E[Hardware EPT or NPT fault]
D -- yes --> F[Write succeeds]
E --> G[Secure Kernel in VTL1 receives fault]
G --> H[VTL0 attacker has no path to relax SLAT entry] kCFG: forward-edge integrity
Control Flow Guard (CFG) is Microsoft's compiler-assisted forward-edge CFI. Every indirect call is replaced by a check against a bitmap of valid call targets; an invalid target raises a fast-fail [29]. The kernel variant -- kCFG -- is enabled by /guard:cf and protects indirect calls in ntoskrnl and CFG-compiled drivers. With HVCI on, the CFG bitmap is stored in VTL1-protected memory; a VTL0 attacker who can write arbitrary kernel pages still cannot tamper with the bitmap. kCFG defeats jump-oriented and call-oriented programming (JOP / COP) against the forward edge. It does nothing for the backward edge.
kCET: backward-edge integrity in hardware
Kernel-mode hardware-enforced stack protection (informally kCET, formally documented as "Kernel Mode Hardware-enforced Stack Protection") closes the backward edge using the Intel CET and AMD Shadow Stack hardware features [30]. A CPU-maintained shadow stack records every CALL return address; every RET validates the popped address against the shadow stack and fast-fails on mismatch. The shadow-stack pages are marked Shadow Stack in the kernel-mode PTE, which the CPU enforces directly; with VBS on, the Secure Kernel additionally locks the shadow-stack mappings against VTL0 write.
kCET requires Intel 11th-generation Tiger Lake or later, or AMD Zen 3 or later, plus VBS and HVCI [30]. It is off-by-default on Windows Server 2025 because enabling it system-wide requires every loaded driver to be compiled with the /CETCOMPAT flag; a single non-/CETCOMPAT driver disables kCET for the entire system at load time. As of June 2026, the rollout is gated on driver vendor adoption.
Connor McGarr's Black Hat USA 2025 deck, "Out of Control: KCFG and KCET," documents the 2026 frontier of kCET bypasses -- an iretq-frame corruption combined with a write-what-where primitive can pivot around the shadow stack [31] [32] [33]. The bypass requires the attacker to already control a kernel-mode write primitive and several CFG-clean targets, which is exactly the precondition KDP, kCFG, and HVCI are designed to make hard.
ARM64 Pointer Authentication
The recurring framing of PatchGuard as "x64-only" is documentation-accurate but deployment-incomplete. In 2026, PatchGuard, kCFG, and Pointer Authentication Codes (PAC) ship on 64-bit ARM Windows as well as x64. PAC is an ARMv8.3-A feature in which a tag computed over a pointer value and a per-process key is stored in the unused high bits of the pointer; the CPU validates the tag on dereference. PAC closes a different class of pointer-corruption attacks than kCFG/kCET. The structural point is that the kernel self-defense investment is fully cross-architecture, not x64-only.
The Microsoft Vulnerable Driver Blocklist
The reactive answer to BYOVD is the Microsoft Recommended Driver Block Rules -- a list of known-vulnerable signed third-party drivers that Windows refuses to load when App Control for Business (formerly WDAC) is enabled [34]. The list is default-on with Memory Integrity, Smart App Control, and S-mode since Windows 11 22H2 and is updated through Windows Update. Verification on a modern system: CiTool --list-policies and look for a policy whose friendly name is Microsoft Windows Driver Policy and Is Currently Enforced: true. The blocklist is the structural answer to the Uroburos pattern -- Microsoft cannot prevent any signed third-party driver from having a write-primitive bug, but they can refuse to load specific drivers known to have shipped such bugs.
The attack pattern in which an attacker, having reached administrator privilege, installs a legitimate signed third-party kernel driver known to contain a privilege-escalation vulnerability, then exploits that vulnerability to obtain arbitrary kernel-mode primitives. The Uroburos VBoxDrv abuse [2] is the canonical 2011 example; the Microsoft Recommended Driver Block Rules are the 2024+ reactive answer [34].
Synthesis
By 2026, the Windows kernel self-defense stack is no longer a single mitigation; it is a stack organised by where the defense actually runs. The 21-year trajectory now resolves into a single thesis: every generation has been a partial answer to the same-privilege paradox, and Microsoft's strategy has progressively migrated the defense out of the kernel -- first into instruction-level obfuscation, then into address-space tricks, then into VBS-anchored isolation, and finally into attack-surface deletion. Before we name that thesis formally, it is worth asking: what did the rest of the industry do?
7. What the rest of the industry did differently
The Microsoft answer to the same-privilege paradox -- twenty-one years of compounding investment in same-privilege deterrents while progressively shifting enforcement to VTL1 -- is not the only answer. Apple and the Linux mainline community took architecturally opposite paths, each correct for a different platform constraint.
Apple: push the defense into silicon
Apple's answer was to put enforcement below the kernel, into hardware Apple controls end-to-end. On Apple Silicon, the Kernel Text Read-only Region (KTRR) is hardware-enforced via the AMCC (Apple Memory Cache Controller). At boot, after the kernel is mapped and before user code runs, the kernel text region is locked read-only at the memory-controller level. Once locked, no software running at any privilege level can modify it -- not the kernel itself, not a kernel extension, not a hypothetical EL2 hypervisor [35].
Apple Silicon's hardware-enforced read-only kernel text region. After boot, the kernel image is locked via the AMCC memory controller; no software at any privilege level can write to the protected region for the lifetime of that boot [35]. Apple's architectural answer to the same-privilege paradox: push the defense below the kernel, into hardware Apple controls.
The corollary is that Apple's hardware control allows them to make a software move Microsoft cannot. Apple deprecated third-party Kernel Extensions (KEXTs) in favour of user-mode DriverKit and Endpoint Security, structurally removing the BYOVD class from the platform. Apple's deprecation of third-party KEXTs began in macOS Catalina (2019) with a deprecation warning, escalated to "system extensions" requiring user approval and reduced kernel-mode footprint, and reached a near-complete migration target on Apple Silicon. The architectural cost is that legitimate device-driver vendors and EDR products had to rebuild their stacks on top of user-mode brokers and Apple-curated APIs; the architectural benefit is that a 2024-style CrowdStrike Falcon kernel-driver outage is structurally not possible on Apple Silicon, because the EDR product runs in user mode against an Endpoint Security framework that mediates the kernel for it.
Linux mainline: privilege reduction, not integrity monitoring
The mainline Linux community's strategy is structurally the opposite of Microsoft's: do not invest in same-privilege deterrents at all; invest in privilege reduction and surface isolation instead. LKRG (Linux Kernel Runtime Guard, maintained by Openwall) is the closest functional analogue to PatchGuard [36] [37]. Its own documentation describes it as "bypassable by design" -- an openly-acknowledged same-privilege paradox. LKRG's frank framing is unusual in the security tools space. The project explicitly tells operators that LKRG is a hardening layer that raises the engineering cost of common kernel rootkit techniques, not a security boundary, and that a determined kernel-mode attacker can defeat it. This is the same architectural truth Skywing made in 2005 and that Microsoft published in the Servicing Criteria a decade later, stated upfront in a project README.
Beyond LKRG, the mainline mechanisms have a recurring structural shape. Each row of the table below is structurally a privilege-reduction or surface-removal mechanism rather than a same-privilege integrity check.
| Linux mechanism | Status (as of June 2026) | What it protects | Windows analogue |
|---|---|---|---|
| Lockdown LSM | Mainline since 5.4 (2019) | Restricts root's ability to modify the running kernel | Driver Signature Enforcement plus HVCI |
| FG-KASLR | Out-of-tree | Per-function rather than per-image randomisation | No direct analogue; closest is kASLR base randomisation |
Clang KCFI (-fsanitize=kcfi) | Mainline since 6.1 (Dec 2022) | Forward-edge CFI for the Linux kernel | kCFG |
| Shadow Call Stack (ARM64) | Mainline since 5.8 (2020) | Backward-edge integrity on ARM64 | kCET (on x64 / AMD), SCS on ARM64 Windows |
| seccomp-bpf | Mainline since 3.5 (2012) | Caller-defined per-syscall filter for any process | Win32kSystemCallFilter (system-defined IDs) |
| eBPF kernel-mode restrictions | Mainline since 5.8 (2020) | Limits unprivileged users from loading eBPF programs that touch kernel state | No direct Windows analogue |
Hypervisor-anchored alternatives at the application level
The third philosophy applies the "live at a different privilege than the attacker" answer at the application level rather than the kernel level. Bromium / HP Sure Click and Windows Defender Application Guard open every tab or document in its own micro-VM. The hypervisor is the protection boundary; the kernel inside the VM may be fully compromised without affecting the host. This is structurally the same move Microsoft makes with VBS / VTL1, applied one level up the stack.
Three philosophies, one shared admission
8. The same-privilege paradox, formally
Now we can state the paradox in a sentence: a defense that shares its CPU privilege level with the attacker can in principle always be subverted by an attacker at that privilege level, because every code path and data structure the defense relies on is, by construction, mutable by the attacker. It is not a formal impossibility theorem in the cryptographic sense -- there is no FLP-style no-go proof for kernel self-defense -- but it is the de facto design constraint Microsoft has acknowledged in writing.
Microsoft's formal admission
The Microsoft Security Servicing Criteria for Windows defines a "security boundary" as "a logical separation between the code and data of security domains with different levels of trust", with kernel-mode versus user-mode as the canonical example [1]. The document then enumerates which transitions Microsoft treats as security boundaries (kernel / user, hypervisor / kernel, VTL1 / VTL0, virtual machine / host, network), and explicitly does not enumerate admin-to-kernel or kernel-to-kernel as boundaries. The exclusion is the cleanest possible architectural admission of the paradox: no defense at CPL=0 in the attacker's kernel can be a security boundary, no matter how cleverly engineered. PatchGuard, by Microsoft's own classification, is not a boundary and never has been.
The same-privilege paradox is, formally, the observation that the reference monitor of a security policy must be tamper-resistant from the principals it monitors, and that "tamper-resistant from a co-resident kernel-mode attacker" is structurally unachievable in a single-address-space single-privilege design. Every modern Windows kernel mitigation either raises the cost of tampering (the engineering-deterrent class: PatchGuard, KASLR, kASLR variants) or moves the monitor outside CPL=0 (the structural class: KDP, kCFG-with-VBS-bitmap, kCET, the entire VTL1-anchored stack). Only the second class can claim a security boundary.
The KASLR-specific bound
The cleanest mathematical version of the paradox lives in the KASLR side-channel literature. Suppose an x64 system has bits of entropy in its kernel base address; the probabilistic floor on guessing it from one shot is . The Hund-Willems-Holz 2013 result is that a co-resident user-mode attacker with access to a shared TLB or cache state can extract bits of the kernel base at a rate of one bit per probe, recovering the address in probes -- a polynomial-time defeat of the probabilistic defense [8]. Increasing does not change the asymptotic; it only changes the constant. Gruss et al. 2017 generalised the argument across micro-architectural side channels and concluded that any operating system implementing user / kernel address-space sharing on a CPU with shared TLB / cache state must leak the kernel base address to an unprivileged user-mode timing observer [9]. The structural fix is not to add entropy: it is to remove the sharing. KVA Shadow / KPTI is the structural answer.
The shape of the bound is general. Wherever a defense's correctness reduces to the attacker not knowing X, and X leaks across a shared micro-architectural channel, the defense is asymptotically defeated.
The proper formal anchor: Anderson 1972
The right formal anchor for the same-privilege paradox is the reference-monitor concept introduced in Anderson's 1972 Computer Security Technology Planning Study for the US Air Force [38]. Anderson's "reference monitor" must satisfy three properties:
- Always invoked. Every reference of a subject to an object is mediated.
- Tamper-resistant. The reference monitor cannot be modified by the subjects it monitors.
- Small enough to be analysed. The Trusted Computing Base (TCB) is small enough to be verified.
PatchGuard fails property 2 by construction: it lives in the same address space as the subjects it monitors, and any subject with kernel-mode write can modify the verifier code, the verifier schedule, the expected-hash store, or the bug-check primitive. KDP, by contrast, satisfies property 2 because its enforcement lives in VTL1 and a VTL0 subject cannot reach VTL1.
The existence proof for what a minimal verifiable TCB looks like is seL4 (Klein et al., SOSP 2009): a roughly 8,700-line microkernel formally verified down to its C implementation against a high-level specification of access control. seL4 is the constructive counterpoint to the Microsoft-style mitigation stack: instead of adding integrity monitors to a large kernel, build a small kernel small enough to verify and put everything else in user-space servers. Windows' VBS / VTL1 architecture is a partial gesture in the same direction -- the Secure Kernel is far smaller than the NT kernel and hosts only policy-enforcement trustlets -- but it is not a from-scratch redesign.Upper and lower bounds, mitigation by mitigation
The 21-year story now lays out cleanly as a table of bounds.
| Mitigation | Upper bound achieved | Lower bound that remains | Structural reason |
|---|---|---|---|
| PatchGuard | Engineering-deterrent class; raises cost of casual kernel hooking | Zero structural lower bound; same-privilege bypass class always exists [12] [23] | Verifier lives at attacker's privilege |
| KASLR (entropy alone) | Probabilistic floor against blind-guess attacker | Zero structural lower bound against side-channel attacker [8] | TLB / cache shared between user and kernel |
| KVA Shadow / KPTI | Structural Meltdown fix (Variant 3) | Spectre Variants 1, 2, 4 require separate mitigations [26] | Address-space split addresses only the user-to-kernel transient read |
| HVCI | Structural W^X for kernel pages, enforced by VTL1 | VBS-coverage gap on systems that cannot run VBS [15] | Hypervisor is the protection boundary |
| KDP (static and dynamic) | Structural read-only-after-init for explicitly-tagged kernel data | Protects only what is explicitly opted in [15] | VTL1 enforces SLAT page tables outside VTL0 reach |
| kCFG (with HVCI) | Structural forward-edge CFI; bitmap in VTL1-protected memory | Backward edge unprotected; same-call-target overwrite via type confusion possible without XFG [29] | Bitmap stored outside VTL0 |
| kCET | Structural backward-edge CFI in CPU hardware | Off-by-default on Server 2025; gated on driver /CETCOMPAT [30] [31] | Shadow stack hardware enforced in silicon |
| Win32kSystemCallFilter | Structural surface deletion for sandboxed renderers | Full lockdown not viable for UI-bearing processes [7] | Per-process bitmap consulted by syscall dispatcher |
The gap between the same-privilege upper bound (PatchGuard, KASLR-alone -- structurally zero) and the cross-privilege upper bound (HVCI, KDP, kCET -- structurally meaningful) is exactly the gap Microsoft has spent twenty-one years migrating across. With the paradox stated formally, the rest of the article is a single question: where in the privilege hierarchy does the next problem live, and how is Microsoft positioned to answer it?
9. Open problems on the June 2026 frontier
The same-privilege paradox is in 2026 closer to architecturally resolved than at any prior point in Windows history -- the VTL1-anchored stack of HVCI / KDP / kCFG / kCET makes the cross-privilege answer real. But every structural mitigation has a practical residual, and five of them are large enough to be the article's frontier.
BYOVD: the dominant 2026 attacker path
Bring-Your-Own-Vulnerable-Driver is the dominant practical defeat of every structural mitigation in the 2026 stack. Uroburos's 2011 pattern is essentially what current attackers do: locate a signed third-party driver with a kernel-write primitive (an IOCTL that allows arbitrary physical memory read or write, or arbitrary MSR manipulation), install it through a legitimate driver-load path, exploit the primitive to obtain arbitrary kernel write, then flip the policy flags or hook the structures Microsoft thought were protected. Elastic Security Labs' 2024 survey of in-the-wild Windows kernel LPE 0-days confirms that BYOVD remains a recurring subsystem of incidents [39], and the Project Zero "0day In the Wild" tracker continues to record Windows kernel-mode CVEs across DWM, win32k, and ALPC subsystems [40]. Every structural mitigation collapses the moment an attacker reaches arbitrary kernel write through a legitimately-loaded driver: KDP-protected pages can be ignored if the attacker can install a new driver that simply does not allocate from the secure pool; kCFG can be bypassed by writing to memory that was not opted in; kCET can be bypassed via McGarr-style iretq corruption [32]; PatchGuard can be hooked from a coexisting driver.
The Microsoft Recommended Driver Block List [34] is the reactive answer. The structural problem -- that signed third-party drivers with kernel-write primitives exist at all, and that the third-party driver supply chain cannot be removed for compatibility reasons -- is unresolved.
The VBS coverage gap
Every VTL1-anchored mitigation collapses on systems that cannot run VBS. Older silicon (pre-2015 Intel without VT-x / VT-d / EPT, AMD parts predating AMD-V / NPT), enterprise-imaged corporate fleets that disabled VBS for compatibility, ARM64 devices below a baseline, and any system without UEFI Secure Boot all fall back to the same-privilege defenses we just classified as structurally bounded. The defender's threat model is the worst case in the fleet, not the average case in the Microsoft launch announcement.
Win32k Lockdown coverage in UI-bearing processes
Office, browsers' GPU and UI processes, and any application that draws windows cannot use the full Win32kSystemCallFilter lockdown. Their allow-lists must cover composition, font rendering, and a substantial fraction of the GDI surface -- which is exactly the surface from which historical LPE bugs emerged. The 2016 win32kbase.sys / win32kfull.sys typeisolation refactor (Windows 10 v1607, build 14393) split win32k.sys to make the surface more attributable, but per-app auto-tuning of the allow-list from observed-call traces remains an open product-engineering problem [41]. Until UI-bearing processes can use a tight allow-list rather than a permissive one, the win32k surface remains the systemic LPE foothold Bochspwn identified in 2013 [19].
Hypervisor escapes as the structural counter
Every VTL1-anchored mitigation assumes VTL1 is uncompromised. Hyper-V CVEs show that the hypervisor TCB hosts its own vulnerability surface. CVE-2024-38080 (Hyper-V SLAT vulnerability) is a 2024 example with Akamai write-up [42]. Joanna Rutkowska's 2006 Blue Pill demonstration at Black Hat USA, Subverting Vista Kernel for Fun and Profit, was the seminal academic primary for the hypervisor-rootkit class and remains the canonical "Hyperjacking" reference [43]. Every step the Windows mitigation stack takes toward putting more enforcement in VTL1 raises the criticality of VTL1's own correctness. The Hyper-V code base is small relative to ntoskrnl but is not zero, and the post-2018 trend of finding side-channel and architectural bugs in CPU hardware applies to VTL1 as much as it does to VTL0.
kCET deployment completion
kCET is shipping but off-by-default on Windows Server 2025, gated on driver /CETCOMPAT compatibility [30]. Until kCET is on-by-default across the inbox kernel and all loaded drivers, the backward-edge ROP class against the Windows kernel remains exploitable in practice. McGarr's 2025 Black Hat USA deck documents both the structural-bypass frontier and the operational gating problem [31] [33] [32].
Historical anchoring: the win32k LPE share
The "win32k killed half of LPE" framing in the article's subtitle deserves time-scoping. Pre-lockdown, win32k was the dominant Windows kernel LPE subsystem -- Stuxnet 2010 (CVE-2010-2743) is the historical anchor [21], Bochspwn 2013 documented the systemic shape [19] [20], Forshaw 2016 reports that the Chrome M54 lockdown "blocked the sandbox escape of an exploit chain being used in the wild" [10], and Elastic Security Labs' 2024 in-the-wild survey continues to name win32k among the recurring subsystems [39]. The Project Zero 0day tracker also confirms that win32k remains in the post-lockdown attacker mix [40]. The lockdown removed roughly half the historically-vulnerable syscall surface from sandboxed renderers specifically; both the fraction and the scope are time- and context-bounded, and a precise percentage cannot be cited to the Project Zero tracker because the tracker does not publish per-subsystem aggregates.
Diagram source
flowchart TD
subgraph SD["Surface deletion (kernel system-call boundary)"]
SDF["Win32kSystemCallFilter per-process bitmap"]
SDD["DisallowWin32kSystemCalls all-or-nothing"]
end
subgraph V1["VTL1 (Secure Kernel anchored)"]
V1H["HVCI (W^X SLAT for kernel pages)"]
V1K["KDP static and dynamic via SLAT RO"]
V1C["kCFG bitmap in VTL1-protected memory"]
end
subgraph CPU["CPU mediated (hardware enforced)"]
CPUS["kCET shadow stack on Intel CET / AMD"]
CPUK["KVA Shadow CR3 switch"]
end
subgraph V0["VTL0 same-privilege (CPL=0)"]
V0P["PatchGuard integrity checks"]
V0K["KASLR base-address randomisation"]
end
SD --> V1
V1 --> CPU
CPU --> V0 BYOVD is in 2026 what same-privilege bypass was in 2007 -- the dominant practical defeat of a mitigation stack whose individual pieces are each structurally sound. The next twenty-one years of Windows kernel self-defense will be substantially the story of what Microsoft does about it.
10. What a Windows defender or driver developer actually does today
The article's intellectual payoff has been made; the practical payoff is the rest of this section. Five concrete decision questions, in roughly the order a working practitioner would reason through them.
1. Is the system Secured-core or Windows 11 22H2+ with Memory Integrity on?
If yes, HVCI, KDP, kCFG, and the Microsoft Recommended Driver Block Rules are baseline [15] [34]. Layer kCET if all loaded drivers are /CETCOMPAT and the CPU is Intel 11th-gen Tiger Lake or later or AMD Zen 3 or later [30]. The baseline gets you the structural mitigations the same-privilege paradox argues are required; everything else is layered on top.
2. Is the workload a sandboxed renderer or sandboxable child process?
Apply Win32kSystemCallFilter (Windows 10 1709+) via UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, ...) at CreateProcess time, not at runtime [7]. The Forshaw / Fratric race-the-mitigation Edge demonstration is the empirical reason -- if the filter is applied after the child process has started, an attacker who races the policy application can simply not be filtered [10]. The Chromium sandbox is the canonical consumer reference for what this composition looks like in a production browser [24].
3. Is the workload UI-bearing?
Full lockdown is out of reach for processes that draw windows, render fonts, or dispatch input. The practical answer is the adjacent mitigation set: Arbitrary Code Guard (ACG), Code Integrity Guard (CIG), Strict CIG, user-mode shadow stack, and CFG, plus PatchGuard, HVCI, and kCFG at the system level. The composition raises the cost of remote exploitation without requiring the renderer-style syscall-surface deletion.
The four sandbox mitigations to set together
For a sandboxed renderer-class process on Windows 11 22H2+:
Win32kSystemCallFilter--PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICYwith the bitmap permitting only theFilterIdvalues the renderer needs [7].- ACG (Arbitrary Code Guard) -- forbid dynamic code generation in the process.
- CIG / Strict CIG (Code Integrity Guard) -- forbid loading non-Microsoft-signed DLLs (CIG), or non-Microsoft-signed-and-not-store-signed DLLs (Strict CIG).
- User-mode shadow stack and CFG -- backward and forward edge CFI in user mode.
All four are applied via UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, ...) at CreateProcess time, in the same call. The Chromium renderer is the canonical reference deployment [24].
4. Are you a driver author?
Three things to do, in order:
- Mark RO-after-init data via Static KDP. Call
MmProtectDriverSectionfromDriverEntryon any image section that should be read-only for the rest of the driver's lifetime [15]. - Allocate runtime-protected state via Dynamic KDP. Call
ExAllocatePool3with aPOOL_EXTENDED_PARAMETERarray containing aPOOL_EXTENDED_PARAMS_SECURE_POOLextended parameter. SetSECURE_POOL_FLAGS_FREEABLEif the allocation needs to be freeable; setSECURE_POOL_FLAG_MODIFIABLEonly if the allocation must be modifiable under further protected control [15]. - Compile with
/guard:cfand/CETCOMPAT. The first enables CFG instrumentation across the driver image; the second tells the loader the driver is compatible with kernel-mode shadow stack [29] [30].
The driver-side KDP pattern is short enough to show in full:
// DriverEntry-time static KDP: mark a .rdata-like section as read-only
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath) {
NTSTATUS status = MmProtectDriverSection(
&g_PolicyTable, // address of the section to protect
sizeof(g_PolicyTable), // size in bytes
0); // reserved
if (!NT_SUCCESS(status)) return status;
// ... rest of driver init
return STATUS_SUCCESS;
}
// Runtime dynamic KDP allocation: a secure pool buffer
POOL_EXTENDED_PARAMETER params[2] = {0};
params[0].Type = PoolExtendedParameterSecurePool;
params[0].SecurePoolParams = &(POOL_EXTENDED_PARAMS_SECURE_POOL){
.SecurePoolFlags = SECURE_POOL_FLAGS_FREEABLE,
.SecurePoolBuffer = NULL,
.Cookie = 0xC0FFEEDEADBEEFULL,
.NoFill = FALSE,
};
params[1].Type = PoolExtendedParameterInvalidType;
PVOID secureBuffer = ExAllocatePool3(
POOL_FLAG_NON_PAGED, // pool flags
bufferSize, // size
'KDPx', // pool tag
params, // extended parameters
1); // count of extended parameters
5. Are you a defender on an existing fleet?
Verify that the Recommended Driver Block Rules are active via CiTool --list-policies. Look for a policy whose Friendly Name is Microsoft Windows Driver Policy and Is Currently Enforced is true [34]. Watch Event ID 3099 in the CodeIntegrity Operational log for block events. For verifying the broader VBS / HVCI state, the canonical PowerShell query is Get-CimInstance Win32_DeviceGuard followed by selecting VirtualizationBasedSecurityStatus, SecurityServicesRunning, and AvailableSecurityProperties. For KVA Shadow specifically, Get-SpeculationControlSettings reports the state. For per-process mitigation policy, Get-ProcessMitigation -System for the system policy and Get-ProcessMitigation -Name <name> for a specific process; the Chromium internal page chrome://sandbox shows the per-process filter state from inside the browser.
A reader who wants to play with the field-decoding logic can do it in a browser. The Python below mirrors what the PowerShell pipeline does -- enumerate the bits, decode by name. The real Windows API surface is bigger, but the decoding shape is the same.
# Conceptual decoder for Win32_DeviceGuard fields
# Real PowerShell: Get-CimInstance Win32_DeviceGuard | Select VirtualizationBasedSecurityStatus,
# SecurityServicesRunning, AvailableSecurityProperties
VBS_STATUS = {
0: "VBS not enabled",
1: "VBS enabled but not running",
2: "VBS enabled and running",
}
SECURITY_SERVICES = {
0: "None",
1: "Credential Guard",
2: "HVCI",
3: "System Guard Secure Launch",
4: "SMM Firmware Measurement",
7: "Kernel Mode Hardware-enforced Stack Protection (kCET)",
8: "Hypervisor-Protected Code Integrity (HVCI legacy)",
}
AVAILABLE_PROPERTIES = {
1: "Base virtualization support",
2: "Secure boot",
3: "DMA protection",
4: "Secure memory overwrite",
5: "UEFI code readonly",
6: "SMM security mitigations",
7: "Mode-based execute control for HVCI",
8: "APIC virtualization",
}
def decode(field_name, value, table):
if isinstance(value, list):
names = [table.get(v, f"unknown({v})") for v in value]
print(f" {field_name}: {names}")
else:
print(f" {field_name}: {table.get(value, f'unknown({value})')}")
# Simulated CIM response from a Secured-core PC
sample = {
"VirtualizationBasedSecurityStatus": 2,
"SecurityServicesRunning": [1, 2, 7],
"AvailableSecurityProperties": [1, 2, 3, 5, 7],
}
print("Win32_DeviceGuard decoded:")
decode("VirtualizationBasedSecurityStatus",
sample["VirtualizationBasedSecurityStatus"], VBS_STATUS)
decode("SecurityServicesRunning",
sample["SecurityServicesRunning"], SECURITY_SERVICES)
decode("AvailableSecurityProperties",
sample["AvailableSecurityProperties"], AVAILABLE_PROPERTIES) Press Run to execute.
Common pitfalls
A short reference list of mistakes that recur in real-world reviews:
- Apply mitigations at
CreateProcess, not at runtime. The Forshaw / Fratric race is the cited example [10]. - Do not assume
DisallowWin32kSystemCallsis the modern lockdown. It is the Windows 8 ancestor ofWin32kSystemCallFilterand is structurally distinct -- different mitigation enum, different policy struct [6] [7]. - Do not use
MmAllocateNodePagesForMdlExfor Dynamic KDP. The canonical API isExAllocatePool3with the secure-pool extended parameter; the NUMA-MDL API is a different API for a different purpose [15]. - kCET disables system-wide on a non-
/CETCOMPATdriver. A single non-compat driver in the inbox set turns it off [30]. - PatchGuard is not a security boundary. Do not architect a defense whose security argument rests on it; Microsoft's own Servicing Criteria say so [1].
None of these decisions makes the kernel a security boundary; together they make the kernel as hard to defeat as today's stack allows. The remaining questions are FAQs.
11. Frequently asked questions
Frequently asked questions
Doesn't PatchGuard prove the kernel is secure?
No. Microsoft's own Security Servicing Criteria for Windows explicitly does not enumerate admin-to-kernel or kernel-to-kernel as a security boundary; PatchGuard is an engineering deterrent, not a security boundary [1]. The most empirically grounded refutation is Uroburos's 2011 -- 2014 operational coexistence with PatchGuard on production Windows systems [2]. PatchGuard raises the cost of a class of attacks; it does not eliminate any class of attacks.
Was Vista the first Windows with PatchGuard?
No. PatchGuard shipped on April 25, 2005, with Windows XP Professional x64 Edition and Windows Server 2003 x64 Edition [4]. Vista x64 (November 2006) inherited PatchGuard v2 from the 2005 release; the x86 editions of Vista never received PatchGuard. The "Vista first" misreading conflates PatchGuard's first widely-publicised release with its first shipping release.
Was Uroburos a PatchGuard bypass?
No. Uroburos was a Driver Signature Enforcement (DSE) bypass that coexisted with PatchGuard for three years (2011 -- 2014) without modifying any PatchGuard-protected structure. It loaded a signed-but-vulnerable copy of Oracle's VBoxDrv.sys, used the vulnerability to flip the g_CiEnabled DSE-gating flag, loaded its own unsigned rootkit driver, then operated alongside PatchGuard [2] [3]. The canonical PatchGuard bypass is GhostHook (Kasif Dekel, CyberArk, June 2017), which uses an Intel-PT-buffer-fill PMI to redirect execution without touching any structure PatchGuard enumerates [23].
Is DisallowWin32kSystemCalls the same as Win32kSystemCallFilter?
No. They are distinct SetProcessMitigationPolicy enums with distinct semantics. DisallowWin32kSystemCalls shipped in Windows 8 (2012) as a PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY and is all-or-nothing [6]. Win32kSystemCallFilter shipped in Windows 10 1709 (October 2017) as a PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY and is a per-syscall allow-list driven by a bitmap of system-defined FilterId values [7]. Chromium uses both in different process types -- the blanket-disable for processes that need no UI, the per-syscall filter for the renderer [24].
Is PatchGuard x64-only?
Microsoft's documentation still calls it an x64 feature [5], but in deployment it is also enforced on 64-bit ARM Windows in 2026. It has never shipped on x86 -- the precise framing is "64-bit Windows only, both x64 and ARM64." The "x64 only" framing is documentation-accurate but deployment-incomplete.
Is KDP a kernel-mode mitigation?
Mostly no. KDP is a VBS-backed (Secure Kernel / VTL1) mitigation that protects kernel memory but is enforced outside the kernel. The Microsoft launch blog states the architecture directly: "the memory managed by KDP is always verified by the secure kernel (VTL1) and protected using SLAT tables by the hypervisor" [15]. KDP is the canonical example of the same-privilege paradox resolved by structural means: the enforcement lives at a privilege level the VTL0 attacker cannot reach.
Did the Win32k Lockdown kill half the LPE class?
Title hyperbole, time-scoped. Pre-lockdown, win32k was the dominant Windows kernel LPE subsystem -- Stuxnet 2010 used a win32k.sys keyboard-layout LPE [21]; Bochspwn 2013 documented the systemic shape [19]; Forshaw reports that Chrome's M54 win32k lockdown "blocked the sandbox escape of an exploit chain being used in the wild" [10]. Elastic Security Labs' 2024 in-the-wild survey continues to name win32k among the recurring subsystems [39]. The lockdown removed roughly half the historically-vulnerable syscall surface from sandboxed renderers specifically -- both the fraction and the scope are time- and context-bounded.
PatchGuard, KASLR, KDP,
Win32kSystemCallFilter-- four answers, twenty-one years, one paradox. The arc resolves: every meaningful kernel defense in modern Windows ultimately lives at a privilege level the attacker does not have, because the alternative -- defending the kernel from inside the kernel -- is the one thing the architecture cannot do.
Study guide
Key terms
- Same-Privilege Paradox
- A defense at the attacker's privilege level cannot in principle succeed; the de facto design constraint Microsoft has acknowledged in writing through the Security Servicing Criteria.
- PatchGuard (KPP)
- Microsoft kernel feature that periodically verifies a fixed list of kernel structures and bug-checks the system on mismatch with stop code 0x109; not a security boundary.
- SSDT
- System Service Descriptor Table; the kernel function-pointer table that dispatches system calls. Pre-PatchGuard, the canonical AV hooking surface; post-PatchGuard, a protected structure.
- KMCS
- Kernel-Mode Code Signing; the 64-bit Windows policy that the kernel will load only Authenticode-signed drivers in production.
- CRITICAL_STRUCTURE_CORRUPTION (0x109)
- The bug-check stop code PatchGuard raises on detecting an unexpected modification to a protected kernel structure.
- KASLR
- Kernel Address Space Layout Randomisation; probabilistic defense by randomising kernel base address; defeated by side-channel attackers on systems with shared TLB/cache state.
- DSE
- Driver Signature Enforcement; the policy gate that loads only signed drivers in production. The g_CiEnabled flag is the in-memory gate; flipping it is the canonical BYOVD operation.
- Win32kSystemCallFilter
- Windows 10 1709+ process-mitigation policy registering a per-process allow-list of win32k system calls; the canonical 'attack-surface deletion' mitigation.
- KAISER / KPTI
- Kernel Page-Table Isolation; the two-CR3 page-table architecture that makes the kernel address space unreachable from user CR3; Linux shipped KPTI in 2018, Microsoft shipped KVA Shadow.
- LPAC
- Less Privileged AppContainer; a Windows process model that further restricts ambient capabilities. Used by the Chromium renderer in composition with Win32kSystemCallFilter.
- KDP
- Kernel Data Protection; static via MmProtectDriverSection, dynamic via ExAllocatePool3 with POOL_EXTENDED_PARAMS_SECURE_POOL. Enforced by the Secure Kernel (VTL1) via SLAT.
- VBS / VTL1
- Virtualization-Based Security; the hypervisor-partitioned architecture in which a Secure Kernel runs at Virtual Trust Level 1, above the NT kernel in VTL0.
- BYOVD
- Bring-Your-Own-Vulnerable-Driver; the dominant 2026 attacker pattern of installing a signed third-party driver with a kernel-write primitive to obtain arbitrary kernel-mode access.
- KTRR
- Kernel Text Read-only Region; Apple Silicon's hardware-enforced read-only kernel text region, locked at boot at the AMCC memory-controller level.
- Reference Monitor (Anderson 1972)
- The formal anchor for the same-privilege paradox: a security policy must be enforced by a monitor that is always invoked, tamper-resistant from its subjects, and small enough to be analysed.
- HVCI
- Hypervisor-Protected Code Integrity; the VTL1-anchored W^X enforcement for kernel pages that underpins KDP, kCFG, and kCET.
References
- (2025). Microsoft Security Servicing Criteria for Windows. https://www.microsoft.com/en-us/msrc/windows-security-servicing-criteria ↩
- (2014). Uroburos -- highly complex espionage software with Russian roots. https://www.gdatasoftware.com/blog/2014/02/23968-uroburos-highly-complex-espionage-software-with-russian-roots ↩
- (2022). Turla / Snake / Uroburos rootkit analysis. https://stmxcsr.com/persistence/turla.html ↩
- (2007). Microsoft Security Advisory 932596: Update for Windows Kernel Patch Protection. https://learn.microsoft.com/en-us/security-updates/securityadvisories/2007/932596 ↩
- (2024). Patching Policy for x64-Based Systems (Driver x64 Restrictions). https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/driver-x64-restrictions ↩
- (2023). PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY structure (winnt.h). https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-process_mitigation_system_call_disable_policy ↩
- (2023). _PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY structure (ntddk.h). https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_process_mitigation_system_call_filter_policy ↩
- (2013). Practical Timing Side Channel Attacks Against Kernel Space ASLR. https://doi.org/10.1109/SP.2013.23 ↩
- (2017). KASLR is Dead: Long Live KASLR. https://gruss.cc/files/kaiser.pdf ↩
- (2016). Breaking the Chain. https://googleprojectzero.blogspot.com/2016/11/breaking-chain.html ↩
- (2006). McAfee, Symantec: Vista x64 Locks Out Third-Party Security Vendors. https://www.crn.com/news/security/199702850/mcafee-symantec-vista-x64-locks-out-third-party-security-vendors ↩
- (2005). Bypassing PatchGuard on Windows x64 (Uninformed Vol. 3). https://web.archive.org/web/2007/http://uninformed.org/?v=3&a=3 ↩
- (2018). KVA Shadow: Mitigating Meltdown on Windows. https://www.microsoft.com/en-us/msrc/blog/2018/03/kva-shadow-mitigating-meltdown-on-windows/ ↩
- (2014). Windows 8.1 Patch Protections. https://www.nosuchcon.org/talks/2014/D2_01_Andrea_Allievi_Win8.1_Patch_protections.pdf ↩
- (2020). Introducing Kernel Data Protection, a new platform security technology for preventing data corruption. https://www.microsoft.com/en-us/security/blog/2020/07/08/introducing-kernel-data-protection-a-new-platform-security-technology-for-preventing-data-corruption/ ↩
- (2007). Subverting PatchGuard Version 2 (Uninformed Vol. 6). https://web.archive.org/web/2024/https://uninformed.org/?v=6&a=1 ↩
- (2007). PatchGuard Reloaded: A Brief Analysis of PatchGuard Version 3 (Uninformed Vol. 8). https://web.archive.org/web/2024/http://uninformed.org/?v=8&a=5 ↩
- (2007). Inside the Windows Vista Kernel, Part 3. https://learn.microsoft.com/en-us/previous-versions/technet-magazine/cc162458(v=msdn.10) ↩
- (2013). Bochspwn paper presented at SyScan 2013. https://j00ru.vexillium.org/2013/05/bochspwn-paper-presented-at-syscan-2013/ ↩
- (2013). Identifying and Exploiting Windows Kernel Race Conditions via Memory Access Patterns (Black Hat USA 2013 slides). https://j00ru.vexillium.org/slides/2013/blackhat.pdf ↩
- (2010). CVE-2010-2743 -- Windows win32k.sys NtUserLoadKeyboardLayoutEx. https://nvd.nist.gov/vuln/detail/CVE-2010-2743 ↩
- (2024). UPGDSED -- Universal PatchGuard and Driver Signature Enforcement Disable. https://github.com/hfiref0x/UPGDSED ↩
- (2017). GhostHook -- Bypassing PatchGuard with Processor Trace Based Hooking. https://www.cyberark.com/resources/threat-research-blog/ghosthook-bypassing-patchguard-with-processor-trace-based-hooking ↩
- (2025). Chromium Sandbox Design. https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/design/sandbox.md ↩
- (2018). Reading privileged memory with a side-channel. https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html ↩
- (2018). Meltdown: Reading Kernel Memory from User Space. https://www.usenix.org/conference/usenixsecurity18/presentation/lipp ↩
- (2018). In-Depth Look Into the Security Features of Windows' Meltdown Patch. https://www.fortinet.com/blog/threat-research/in-depth-look-into-the-security-features-of-windows-meltdown-patch ↩
- (2024). EfiGuard. https://github.com/Mattiwatti/EfiGuard ↩
- (2024). Control Flow Guard. https://learn.microsoft.com/en-us/windows/win32/secbp/control-flow-guard ↩
- (2025). Kernel Mode Hardware-enforced Stack Protection. https://learn.microsoft.com/en-us/windows-server/security/kernel-mode-hardware-stack-protection ↩
- (2025). Breaking the Shield: Circumventing Kernel-Mode Shadow Stacks on Windows. https://www.blackhat.com/us-25/briefings/schedule/#breaking-the-shield-circumventing-kernel-mode-shadow-stacks-on-windows-44432 ↩
- (2025). Kernel-Mode Shadow Stacks on Windows. https://connormcgarr.github.io/km-shadow-stacks/ ↩
- (2025). km-shadow-stacks. https://github.com/connormcgarr/km-shadow-stacks ↩
- (2025). Microsoft Recommended Driver Block Rules. https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/design/microsoft-recommended-driver-block-rules ↩
- (2017). KTRR Explained. https://siguza.github.io/KTRR/ ↩
- (2025). Linux Kernel Runtime Guard (LKRG). https://www.openwall.com/lkrg/ ↩
- (2025). lkrg-org/lkrg. https://github.com/openwall/lkrg ↩
- (1972). Computer Security Technology Planning Study (Anderson Report). https://csrc.nist.gov/files/pubs/conference/1972/12/01/computer-security-technology-planning-study/final/docs/ande72.pdf ↩
- (2024). Exploring Windows kernel LPE 0-days. https://www.elastic.co/security-labs/exploring-windows-lpe-zero-days ↩
- (2025). 0day In the Wild: Root Cause Analyses. https://googleprojectzero.github.io/0days-in-the-wild/rca.html ↩
- (2025). Windows x64 win32k.sys system call table. https://j00ru.vexillium.org/syscalls/win32k/64/ ↩
- (2024). Critical Vulnerability Discovered in Windows Hyper-V (CVE-2024-38080). https://www.akamai.com/blog/security-research/critical-vulnerability-discovered-in-windows-hyper-v-cve-2024-38080 ↩
- (2006). Subverting Vista Kernel For Fun And Profit. https://www.blackhat.com/presentations/bh-usa-06/BH-US-06-Rutkowska.pdf ↩