Skip to content
03 · Attack Surface ReductionPart 2 of 4Intermediate

Exploit protection: system and per-app mitigations

Configure Windows exploit protection, the EMET successor: system defaults, per-app mitigations, audit mode, XML export/import and GPO or Intune deployment.

Florian Amette8 min read

Exploit protection is the part of Windows that makes memory-corruption bugs harder to turn into code execution. It is the built-in successor to EMET (the Enhanced Mitigation Experience Toolkit), shipped in Windows 10 1709 and later, Windows 11 and Windows Server 2019 and later. Where ASR rules block suspicious behaviour (Word spawning PowerShell), exploit protection blocks the techniques an exploit uses to get there: executing data, jumping through a return-oriented chain, loading an unsigned DLL into a hardened process.

The ASR pillar only touches it in passing. This guide covers the full job: what the defaults already give you, which per-app mitigations are worth adding, how to test them in audit mode, and how to ship one configuration to the whole fleet. For the wider picture of the area, see Attack Surface Reduction.

How the settings are organised

Exploit protection has two layers:

  • System settings apply to every process unless an app setting overrides them.
  • Program settings apply to a named executable (optionally a full path) and can switch on mitigations that would be too disruptive system-wide.

Every mitigation can be on, off, or use default, and several support an audit state that logs what would have been blocked. The same settings are visible in Windows Security > App & browser control > Exploit protection settings, but on managed devices you should drive them from an XML file distributed by policy, not by clicking.

System mitigationDefaultRecommendation
Control flow guard (CFG)OnKeep on
Data Execution Prevention (DEP)OnKeep on
Force randomization for images (Mandatory ASLR)OffLeave off system-wide; use per app
Randomize memory allocations (Bottom-up ASLR)OnKeep on
High-entropy ASLROnKeep on
Validate exception chains (SEHOP)OnKeep on
Validate heap integrityOnKeep on

The first job is simply to make sure nothing has turned these off. Old imaging scripts, gaming tweaks and "performance" guides sometimes disable DEP or CFG.

Step 1: capture the current state

On a reference machine, look at the effective system and per-app configuration:

PowerShell
# System-wide mitigations
Get-ProcessMitigation -System

# One application
Get-ProcessMitigation -Name winword.exe

# Every app that has per-program settings
Get-ProcessMitigation | Where-Object { $_.ProcessName } |
  Select-Object ProcessName -Unique

Windows ships with some per-app settings already, and a fresh install is the best baseline. Export it so you can diff it later:

PowerShell
Get-ProcessMitigation -RegistryConfigFilePath C:\Temp\ep-baseline.xml

If you still have an EMET policy from years ago, convert it and treat it as a list of ideas, not a configuration to apply:

PowerShell
ConvertTo-ProcessMitigationPolicy -EMETFilePath C:\Temp\emet.xml -OutputFilePath C:\Temp\ep-from-emet.xml

Step 2: choose per-app mitigations

Per-app mitigations are where exploit protection earns its keep, but they are also where it breaks things. Target applications that parse untrusted input and are not already heavily sandboxed: document readers, legacy line-of-business clients that open files from email, media players, archive tools, and old internet-facing server components you cannot replace yet.

MitigationWhat it stopsAudit modeCommon collision
Arbitrary code guard (ACG)Creating or modifying executable memoryYesAnything with a JIT (browsers, .NET, Java, scripting engines)
Code integrity guard (CIG)Loading images not signed by MicrosoftYesThird-party plug-ins, security product DLLs
Block remote imagesLoading DLLs from UNC pathsYesApps run from a network share
Block low integrity imagesLoading files written by low-integrity processesYesRarely
Do not allow child processesSpawning any child processYesApps that open help, updaters, printing helpers
Disable extension pointsAppInit DLLs, legacy IMEs, window hooksNoInput method editors, accessibility tools
Disable Win32k system callsThe kernel GUI attack surfaceYesAnything that draws a window
Export / import address filtering (EAF/IAF)Shellcode resolving APIsYesEDR and anti-cheat hooks
ROP mitigations (stack pivot, caller check, simulate execution)Return-oriented programming chainsYesOlder 32-bit apps, some hooking products
Force randomization for imagesNon-ASLR DLLs loaded at predictable addressesNoOld DLLs without relocation information
Hardware-enforced stack protectionROP via CET shadow stacksYesNeeds Intel 11th gen / AMD Zen 3 or later

Microsoft's own browsers and Office already enable many of these internally, and Chromium-based browsers manage their own sandbox. Don't stack ACG or CIG on top of Edge or Chrome; configure the browser instead (see Edge hardening). Microsoft also warns that EAF, IAF and the ROP mitigations can conflict with EDR and anti-cheat products that hook the same functions, so test on devices that run your real security stack.

Step 3: test in audit mode

Build the per-app settings on a test machine, starting in audit where the mitigation supports it:

PowerShell
# Audit ACG and child process creation for a legacy viewer
Set-ProcessMitigation -Name "C:\Program Files\Contoso\Viewer\viewer.exe" `
  -Enable AuditDynamicCode, AuditChildProcess

# Enforce low-risk mitigations directly
Set-ProcessMitigation -Name viewer.exe -Enable BlockRemoteImages, BlockLowLabel

Parameter names map to mitigation options (for example DisallowChildProcessCreation, AuditChildProcess, DynamicCode, AuditDynamicCode, MicrosoftSignedOnly, ForceRelocateImages). Audit for EAF, IAF and the ROP mitigations is not available through the PowerShell cmdlets; set it in the Windows Security app and export the XML. Run Get-Help Set-ProcessMitigation -Full on your build for the list it supports, because newer releases add options.

Exploit protection writes to two logs under Applications and Services Logs > Microsoft > Windows > Security-Mitigations: KernelMode and UserMode. Each audited mitigation has an audit event and an enforce event; for example, ACG logs 1 (audit) and 2 (blocked), and child process creation logs 3 (audit) and 4 (blocked). Check Microsoft's exploit protection event reference for the complete mapping on your build.

PowerShell
Get-WinEvent -LogName "Microsoft-Windows-Security-Mitigations/UserMode",
                       "Microsoft-Windows-Security-Mitigations/KernelMode" -MaxEvents 200 |
  Select-Object TimeCreated, LogName, Id, Message

Use the application normally for a week or two: open the unusual files, print, run the update check, use the plug-ins. No audit events means the mitigation can be enforced. Events for a real workflow mean you either leave that mitigation off or ask the vendor for a fix.

Step 4: export and deploy the XML

Once the test machine behaves, export the complete configuration. The file contains system and app settings together:

PowerShell
Get-ProcessMitigation -RegistryConfigFilePath \\corp.example\NETLOGON\ExploitProtection\ep-settings.xml

Group Policy. Put the XML on a share that computers can read, then set Computer Configuration > Policies > Administrative Templates > Windows Components > Windows Defender Exploit Guard > Exploit Protection > Use a common set of exploit protection settings to Enabled with the UNC path. Recent ADMX files may show the folder as Microsoft Defender Exploit Guard. The policy stores the path in HKLM\SOFTWARE\Policies\Microsoft\Windows Defender ExploitGuard\Exploit Protection and the device applies the file at the next refresh.

Intune. Use Endpoint security > Attack surface reduction > Create policy > Exploit Protection and paste or upload the XML. The underlying CSP is ExploitGuard/ExploitProtectionSettings.

Lock it. Stop local changes through the Windows Security app with Computer Configuration > Policies > Administrative Templates > Windows Components > Windows Security > App and browser protection > Prevent users from modifying settings (in Intune, the Disallow Exploit Protection Override setting in the same profile).

Treat the XML like code: keep it in version control, change it through a pull request, and roll it out by ring, as you would ASR rules or a security baseline.

What breaks

  • Mandatory ASLR system-wide is the classic self-inflicted outage: old installers and DLLs without relocation data crash at load. Keep it per app.
  • CIG and ACG on apps with plug-ins or a JIT fail silently or crash on first use of the plug-in.
  • Do not allow child processes stops the app opening a browser for help links, launching its updater or calling a PDF printer.
  • Disable extension points breaks East Asian input methods and some accessibility tools.
  • EAF/IAF and ROP mitigations can fight with EDR hooks. The symptom is a crash in the security product's DLL, not in the app.
  • Hardware-enforced stack protection only works on CET-capable CPUs, and in strict mode it will block incompatible DLLs loaded into the process.

When something breaks after rollout, Get-ProcessMitigation -Name app.exe on the affected device tells you what is actually applied, and the Security-Mitigations logs tell you which mitigation fired.

Verify it

On a sample of devices after policy refresh:

PowerShell
# System defaults intact
Get-ProcessMitigation -System | Format-List DEP, ASLR, CFG, SEHOP, Heap

# Your per-app settings applied
Get-ProcessMitigation -Name viewer.exe

# Policy path present
Get-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender ExploitGuard\Exploit Protection" -ErrorAction SilentlyContinue

Forward both Security-Mitigations logs to your SIEM. A sudden burst of enforce events on one host is either a broken update or an exploitation attempt, and both deserve a look.

Where it fits

Exploit protection is one layer of memory safety. Kernel-side, memory integrity (HVCI) and VBS protect the kernel from the same class of attack, and on Windows 11 with HVCI and a CET-capable CPU you can also enable kernel-mode hardware-enforced stack protection from Windows Security > Device security > Core isolation. On top, application control decides what may run at all. For the term itself, see the exploit protection glossary entry.

Checklist

  • System mitigations (DEP, CFG, bottom-up and high-entropy ASLR, SEHOP, heap integrity) verified on across the fleet
  • Exposed legacy apps identified and per-app mitigations chosen
  • Mitigations tested in audit mode, Security-Mitigations events reviewed
  • XML exported, versioned and deployed by GPO or Intune
  • Local override blocked with Prevent users from modifying settings
  • Security-Mitigations logs forwarded and alerted

Frequently asked questions

Does exploit protection need Microsoft Defender Antivirus to be the active antivirus?

No. The mitigations are enforced by the Windows kernel and loader, not by the antivirus engine, so they keep working when a third-party product is primary. What you lose without Defender for Endpoint is central reporting: the audit and block events stay in the local Security-Mitigations logs unless you forward them yourself.

Can I import my old EMET configuration?

Yes. The ConvertTo-ProcessMitigationPolicy cmdlet converts an EMET XML file into the exploit protection format, which you can then apply with Set-ProcessMitigation or distribute by policy. Review the result rather than applying it blindly: many EMET-era entries target software that no longer exists or now ships its own mitigations.

Should I turn on mandatory ASLR for the whole system?

Usually not. Force randomization for images is off at system level by default because it relocates old DLLs that were never built for it, which can crash legacy applications. Enable it per application for exposed programs you have tested, and leave the system default alone unless you run a very modern, well-controlled software estate.

Exploit protection: system and per-app mitigations

Related guides

Attack Surface Reduction

Harden Microsoft Office: macros, OLE and add-ins

Lock down Microsoft 365 Apps: block internet macros, disable XLM, scan VBA with AMSI, keep Protected View on, require signed add-ins, stop OLE and DDE.

Foundation