Select your country

Not finding what you are looking for, select your country from our regional selector:

Search

Author:

Ogulcan Ugur
Cyber Security Analyst

https://github.com/zero2504/Fairy-Law

Introduction

Modern Endpoint Detection and Response (EDR) solutions comprise kernel-mode and user-mode components. These components work together to monitor processes, detect suspicious behavior and block attacks. However, a few years ago, attackers discovered a technique to bypass certain EDR functions. The trick is to offload their malware to a child process launched with a special mitigation policy: MicrosoftSignedOnly.

What is the purpose of this policy?

It ensures that a process can only load libraries (DLLs) that are signed by Microsoft.

Consequence:

Many EDRs inject their own DLLs into processes in order to intercept API calls, a process known as 'hooking'. However, when MicrosoftSignedOnly is enabled, these EDR DLLs cannot be loaded into the process unless they are signed by Microsoft. This means that the EDR cannot redirect or analyze API calls. 

  • What does “hooking” mean?

Hooking is a technique used by security software to redirect certain operating system functions for monitoring purposes.

Example: 

A process wants to open a file: this is a normal function call in the system. An EDR then places a 'hook' on this function, meaning the request is intercepted and checked before execution. Many of these hooks are located in user mode, which is precisely where the mitigation policy takes effect and blocks the EDR DLL. However, EDRs that place their hooks in kernel mode remain largely unaffected by this workaround.

How are these protective measures applied?

BOOL SetProcessMitigationPolicy(
  [in] PROCESS_MITIGATION_POLICY MitigationPolicy,
  [in] PVOID                     lpBuffer,
  [in] SIZE_T                    dwLength
);

 

This function enables processes with necessary permissions to activate or configure various security policies.

These include, but are not limited to:

  • Data Execution Prevention (DEP)
  • Address Space Layout Randomization (ASLR)
  • Dynamic Code Policy
  • Control Flow Guard (CFG)
  • Image Load Policies
  • Signature Policies (e.g., MicrosoftSignedOnly)

Developers provide a structure type corresponding to the relevant policy flags (e.g. PROCESS_MITIGATION_IMAGE_LOAD_POLICY).

Depending on the mitigation policy selected, certain process actions may be permitted, restricted or prohibited entirely.

These protective measures were originally developed to prevent processes from being exploited or manipulated, thereby enhancing the system's overall security.

Use in adversarial activity

Adversaries have found ways to abuse these mechanisms to weaken or bypass security controls. As described within MITRE ATT&CK under Impair Defenses: Disable or Modify Tools, attackers may leverage process mitigation policies to prevent certain EDR products from injecting their user-mode monitoring components.

For example:

By spawning a process with the PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON flag - typically via UpdateProcThreadAttribute - attackers can block loading of any DLL that is not signed by Microsoft. Since many EDR solutions rely on injecting vendor-signed DLLs to perform API hooking and behavioral monitoring, this approach can significantly reduce their visibility of the process.

Figure 1: Process mitigation policies for a process launched with the “MicrosoftSignedOnly” restriction

Technical Background: Windows Internals

To understand the behavior of the system-wide mitigation policies stored under HKLM/SYSTEM/CurrentControlSet/Control/Session Manager/Kernel/MitigationOptions, it is necessary to examine the Windows boot arhitecture and the structure of early kernel initialization. The enforcement semantics of MitigationOptions are specifically linked to the kernel's Phase 0 initialization sequence, rather than to any subsequent user-mode components, such as the Session Manager (smss.exe.).

Early Registry Loading

Windows initializes the SYSTEM hive during kernel startup, long before any user-mode process exists. Registry modifications use a memory-mapped model with 2-MB views and PAGE_WRITECOPY semantics. Updates are appended to per-hive transaction logs but written back to disk only by the registry lazy writer, which periodically reconciles dirty pages. Because hive pages may remain resident or be paged out, and because updates are not immediately committed to the persistent hive file, the kernel cannot rely on runtime hive state for loading security-critical configuration values such as MitigationOptions.

This separation between runtime hive state and boot-time configuration is fundamental to the immutability of mitigation policies after boot.

Kernel Boot Phases and the Role of Phase 0

Windows boot proceeds through two kernel phases:

  • Phase 0: minimal kernel bring-up, per-CPU initialization, interrupt setup, creation of core object types, and initialization of the Process Manager.
  • Phase 1: initialization of executive subsystems (Object Manager, Memory Manager, I/O Manager, Security Subsystem, Configuration Manager, etc.).

During both phases:

  • File systems are not yet fully available
  • Win32 APIs are not present
  • ETW cannot write to disk
  • User-mode does not exist

Only after Phase 1 does the kernel create smss.exe, the first user-mode process.

The Session Manager and its unique role

Smss.exe is the first user-mode process created by the kernel after Phase 1 completes. It is implemented as a Protected Process Light (PPL) and runs as a native application without relying on Win32 APIs. Smss.exe is responsible for initializing Session 0 (services), Session 1 (interactive logon) and additional sessions in Terminal Services environments.

During its one-time initialization, smss.exe performs several critical tasks, including:

  • loading the SOFTWARE, SAM and SECURITY registry hives
  • creating the \KnownDlls directory and mapping permanent section objects
  • establishing system-wide environment variables
  • creating object-manager directories
  • processing BootExecute actions
  • launching Wininit.exe (Session 0) and Winlogon.exe (interactive sessions)

Smss.exe is therefore the first user-mode component capable of accessing fully initialized registry hives. Importantly, this occurs only after the kernel has already constructed and frozen the global mitigation-policy table during Phase 0, meaning smss.exe has no influence on the initialization of MitigationOptions.

Initialization of system-wide MitigationOptions

A crucial detail that is often overlooked in public documentation is that Windows initializes and freezes the global process mitigation table during Phase 0 of the Process Manager's start-up process.

Windows Internals (Part 2, Chapter 12) states:

“Systemwide process mitigation options are initialized and merged with the options specified in HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Kernel\MitigationOptions.”

This initialization takes place before the object manager is fully operational, before the filesystem stack is ready, and before any Win32 subsystem is available. Its position in Phase 0 ensures deterministic enforcement semantics for all subsequently created processes.

Precise initialization sequence:

1. Process manager initializes during Phase 0

2. It defines the core process, thread, job, and partition object types

3. It allocates global mitigation option structures

4. It reads the registry value HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Kernel\MitigationOptions

5. It merges:

  • Kernel defaults
  • Platform-enforced constraints,
  • Policy-based restrictions (e.g, MicrosoftSignedOnly)
  • Registry-specific overrides

6. The resulting mitigation configuration is then frozen and becomes the global policy table

7. The table is inherited by any process created afterwards

8. Smss.exe is only launched afterwards

Verification of Phase-0 initialization (Kernel debugging)

In order to verify that MitigationOptions are initialized during Phase 0, a virtual Windows 11 machine was examined using KDNET remote kernel debugging. A breakpoint was established within a kernel routine that directly accesses the global mitigation table: PsIsSystemWideMitigationOptionSet.

Figure 2: Early Phase-0 stack trace

Mitigation routine was hooked successfully:

Figure 3: Breakpoint installed on PsIsSystemWideMitigationOptionSet

When the system hit the breakpoint in PsIsSystemWideMitigationOptionSet, the disassembly clearly showed that the routine reads directly from the global mitigation table:

Figure 4: Disassembly of PsIsSystemWideMitigationOptionSet

Immediately afterwards, the content of nt!PspSystemMitigationOptions was dumped. The structure was already allocated and populated, even though no user-mode process existed yet and smss.exe had not been created.

The initial dump (before modifying the registry) showed the kernel defaults:

Figure 5: Default global mitigation table during Phase 0

After writing a new mitigation configuration into HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Kernel\MitigationOptions and rebooting the system, the kernel showed updated bits in the same structure:

Figure 6: Modified mitigation table after reboot

The kernel debugger evidence demonstrates that the global process mitigation table PspSystemMitigationOptions is allocated, populated from boot-time registry configuration, and finalized during Phase 0 of kernel initialization, before smss.exe is created and long before the Windows subsystem becomes operational. Any registry changes to MitigationOptions made at runtime are therefore ignored until the next reboot.

The fact that smss.exe later loads additional registry hives (including SOFTWARE, SAM and SECURITY) does not influence the mitigation state, because the global table has already been finalized.

Therefore, any change to MitigationOptions requires:

  • a complete system reboot
  • re-execution of Phase 0
  • reconstruction of the global mitigation policy table

Late boot dependencies and subsystem stabilization

Once the Session Manager (smss.exe) has completed its core initialization tasks, including loading the Software hive, creating the KnownDlls directory and coordinating subsystem setup, the remaining executive components finalize their initialization. During this late-boot phase, the I/O manager fully mounts the file system, Event Tracing for Windows (ETW) flushes buffered boot-time events once stable hive access is available, and the Service Control Manager finishes initializing the user-mode driver (UMDF) after the Win32 subsystem becomes operational. These components implicitly rely on the fact that global process mitigation settings have already been computed during Phase 0, after which the system assumes mitigation policy immutability and all late-boot subsystems operate under the fixed mitigation environment established early in kernel initialization.

Not yet another method to compromise or disable EDR security solutions: “Fairy Law”

This analysis examined how attackers can exploit certain mitigation policies to create processes that are no longer monitored by many EDR solutions. This approach is not new and is described in the MITRE ATT&CK Framework under the 'Impair Defenses' technique (T1562) Disable or Modify Tools'. Windows provides several mechanisms for setting process mitigation policies. As well as API-based configuration options such as SetProcessMitigationPolicy and UpdateProcThreadAttribute, there is another, lesser-known approach that is controlled via the Windows registry.

Manipulation of the registry value “MitigationOptions”

Microsoft allows security-related parameters to be set in the kernel configuration area via PowerShell or native registry APIs, such as RegOpenKeyExA, RegSetValueExA and RegCreateKeyExA.

One particularly relevant key is located at:

 

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\kernel

 

The binary value MitigationOptions exists there:

Figure 7: The name and value of the current mitigation options in the registry hive.

Function of value

  • It serves as a global configuration source for various process mitigation policies
  • If the value does not exist, it can be created, or modified manually or via script, provided the attacker has administrator permissions, since changes under HKLM are privileged

“Fairy Law” – Technique

The technique described here, called 'Fairy Law', sets the MitigationOptions value to enable the MicrosoftSignedOnly policy globally.

This means:

Only binaries signed by Microsoft may be loaded into processes. All other DLLs are blocked by the loader.

This disables all EDR components that require DLLs that are not signed by Microsoft to operate.

Many EDR solutions feature anti-tamper protection designed to prevent their components from being disabled or manipulated. If MicrosoftSignedOnly is enabled globally, the operating system itself will block these components before the EDR has the opportunity to protect itself.

The following is to be understood:

  • Telemetry can be massively reduced or even prevented
  • Hooking and user-mode monitoring are prevented
  • Anti-tamper protection is partially or completely disabled

Exception: EDRs with Microsoft-signed components.

Some EDR vendors, such as CrowdStrike in this example, have modules that are officially signed by Microsoft, such as “Microsoft Windows Hardware Compatibility Publisher” or “Microsoft Third Party Component CA”. These modules can still be loaded even when MicrosoftSignedOnly is enabled globally. Such EDRs can continue to provide some of their functionality. Conversely, products without Microsoft signatures lose a large proportion of their monitoring capabilities.

Figure 8: Microsoft signed Crowdstrike Support Module

Configuring MitigationOptions via PowerShell

PowerShell offers a simple way to create or overwrite the corresponding registry value with administrator permission:

 

Set-ProcessMitigation -System -Enable MicrosoftSignedOnly

 

In addition to the MicrosoftSignedOnly policy, there are several other policies that can be configured. A full list is available on the Microsoft’s documentation.

Figure 9: List of available mitigation parameters that can be configured using Set-ProcessMitigation.

Not all mitigations can be used with the -System option, as applying some of them would result in essential Windows functionality being broken. For instance, DisallowChildProcessCreation would stop Windows from creating the necessary system processes.

The main advantage of using PowerShell is that you do not need to know the underlying bitmask value for each mitigation, the cmdlet resolves this automatically. By contrast, when configuring mitigations from a C program, you have to specify the correct bit value for each mitigation you want to enable manually.

Configuring MitigationOptions via Windows-API

The same modification can be performed programmatically using the Windows registry API.
Following C++ program demonstrates how an attacker or administrator could:

  1. Check the current mitigation state of the running process
  2. Elevate privileges if required
  3. Write the binary MitigationOptions value
  4. Trigger a system reboot -> Policy is loaded only during boot
  1. Checking the current mitigation policy
    PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY sig{}; GetProcessMitigationPolicy(GetCurrentProcess(), ProcessSignaturePolicy, &sig, sizeof(sig)); 

    This retrieves the current process signature policy flags.
    If sig.MicrosoftSignedOnly == 1, the mitigation is already active.

  2. Verifying administrative privileges

    if (!IsProcessElevated()) {     RestartElevated();     return 0; } 

    Writing to HKLM requires administrator privileges.
    If the program is not elevated, it attempts to restart itself with elevated permissions.

  3. Opening or creating the registry key

    // Open or create the registry key         LONG result = RegCreateKeyExA(             HKEY_LOCAL_MACHINE,              // root hive             subkey,                          // subkey path             0,             NULL,                            // class type (unused)             REG_OPTION_NON_VOLATILE,         // key persists after reboot             KEY_WRITE | KEY_READ,            // access rights             NULL,                            // security attributes             &hKey,                           // returned key handle             &disposition                     // tells if key was created or opened         );         if (result != ERROR_SUCCESS) {             printf("Error opening/creating registry key: %ld\n", result);             return 1;         }         if (disposition == REG_CREATED_NEW_KEY) {             printf("Registry key was created.\n");         }         else {             printf("Registry key already exists.\n");         } 

    This ensures that the kernel registry key either exists or is created if it doesn’t.

  4. Writing the MitigationOptions value

    // The REG_BINARY value for MicrosoftSignedOnly         BYTE mitigationValue[] = {             0x00, 0x00, 0x00, 0x00,             0x00, 0x10, 0x00, 0x00,             0x00, 0x00, 0x00, 0x00,             0x00, 0x00, 0x00, 0x00,             0x00, 0x00, 0x00, 0x00         }; // Set or overwrite the REG_BINARY value         result = RegSetValueExA(             hKey,             valueName,                       // value name             0,             REG_BINARY,                      // binary value             mitigationValue,                 // data buffer             sizeof(mitigationValue)          // size of the binary data         );         if (result != ERROR_SUCCESS) {             printf("Error writing value: %ld\n", result);             RegCloseKey(hKey);             return 1;         }         printf("MitigationOptions successfully written.\n");         RegCloseKey(hKey); 

    This 20-byte binary value activates the MicrosoftSignedOnly bit in the global mitigation configuration.

    As a result: All third-party or custom DLLs are blocked at load time

  5. Persistence and reboot

    AddToStartup(); RunPowerShell("Restart-Computer -Force"); 

    The code optionally adds itself to the system startup and triggers an immediate reboot.

    Again, the reboot is essential because Windows enforces mitigation settings only during system initialization.

Figure 10: Exploit Mitigation preventing a non-Microsoft-signed DLL from loading

The illustration shows how the MicrosoftSignedOnly countermeasure prevented SRServer.exe from loading the signed DLL, qrcodelib.dll.

Impact of the MicrosoftSignedOnly mitigation policy on endpoint security solutions

To evaluate practical consequences of enforcing the MicrosoftSignedOnly global mitigation policy, several leading Endpoint Detection and Response (EDR) solutions were examined in a controlled laboratory environment. The objective was to assess whether each vendor’s endpoint agent would remain operational if Windows blocked the loading of all non-Microsoft-signed user-mode libraries, and whether any self-protection, telemetry or fallback mechanisms could compensate for this. This analysis does not include two market-leading solutions: CrowdStrike Falcon and Microsoft Defender for Endpoint. Both vendors deploy Microsoft-signed components.

All tests were conducted with the tamper-protection feature enabled for each product to determine whether the vendors' self-protection mechanisms can maintain functionality under these restrictive conditions.

SentinelOne

After modifying the mitigation configuration, SentinelOne did not generate any alerts indicating degradation or loss of protective functionality. However, when the system was rebooted, which was necessary for the new mitigation settings to take effect, the agent's user-mode components failed immediately during startup. Windows rejected loading of several SentinelOne DLLs, including SentinelAgentCore.dll and SentinelOneAgentUI.dll, with the standard 'Bad Image' error and status code 0xc0000428. This indicates a failure of signature validation under the enforced policy.

Figure 11: SentinelOne components failing to start due to blocked non-Microsoft-signed DLLs - SentinelOneAgentUI.dll
Figure 12: SentinelOne components failing to start due to blocked non-Microsoft-signed DLLs - SentinelOneAgentCore.dll

Failure of these components prevents SentinelOne from loading its behavioral monitoring pipeline, user-mode hooks, event interception logic and telemetry dispatch modules. Therefore, after rebooting, the endpoint is no longer monitored and is left fully unprotected.

Palo Alto Cortex XDR

Palo Alto Cortex XDR showed identical degradation characteristics. After activating MicrosoftSignedOnly and rebooting the machine, Cortex’s user-mode loader (cytray.exe) failed to initialize because it attempted to load the unsigned module.

Figure 13: Cortex XDR (cytray.exe) failing to load as a result of MicrosoftSignedOnly enforcement, preventing initialization of required user-mode components

As a result, the agent was unable to start, leaving the system without endpoint protection capabilities. As with the other products evaluated, Cortex did not generate a local alert to indicate that the agent was not functioning.

Proof of Concept Video:

Trend Micro Apex One

Trend Micro exhibited a similar outcome. Once the mitigation policy was enabled and the system rebooted, the Apex One agent silently failed during initialization. The agent simply failed to start.

Impact on SIEM agents and telemetry infrastructure

The enforcement of MicrosoftSignedOnly has consequences that extend beyond EDR products.

Several SIEM and log-collection agents rely on:

  • proprietary DLLs for ETW consumption
  • parsers and correlation modules
  • custom event filter providers

These modules may also be unsigned. When MicrosoftSignedOnly is active, such components are denied access during process initialization, which may result in:

  • complete startup failure of the SIEM agent
  • loss of event forwarding
  • absence of security logs in central SIEM

The result of this is a compound visibility gap: the endpoint is left unprotected and unmonitored after reboot, with no telemetry leaving the host.

Constraints on attackers under MicrosoftSignedOnly

Although MicrosoftSignedOnly can unintentionally disable several endpoint security solutions, it also significantly constrains attackers.

Notably, the policy prevents:

  • DLL injection using custom images
  • loading of reflective DLLs

Therefore, attackers must rely alternative techniques that do not involve loading external binaries, such as:

  • pure in-memory shellcode
  • living-off-the-land approaches
  • legitimate signed component abuse

These constraints reduce the attacker’s flexibility, even though they do not mitigate all threat vectors.

Conclusion

The analysis shows that enabling MicrosoftSignedOnly via the MitigationOptions registry value significantly impacts endpoint security products that rely on libraries that are not signed by Microsoft. Without these signed components, the functionality of several EDR solutions is lost after a reboot, leaving the system without monitoring and telemetry. While DLL-based injection techniques are restricted by the policy, memory-resident execution paths remain vulnerable to attack.

Windows provides a mechanism that allows system-wide protection measures to be either overridden or applied for individual executable files. This approach enables targeted exceptions and can be legitimately used by EDR vendors whose DLLs are not signed by Microsoft to address this vulnerability. At the same time, however, it can also be abused by attackers to bypass the globally enforced MicrosoftSignedOnly restriction, for example by ensuring that ordinary applications like Chrome or Firefox can still run despite the system-wide policy.

This mechanism is implemented through the Image File Execution Options (IFEO), which allow specific protection measures to be defined for individual executables. If a deviating protection measure is configured for a particular process (e.g., disabling MicrosoftSignedOnly for a third-party vendor’s binary), the corresponding executable remains functional even if it would otherwise be blocked by the system-wide policy.

IFEO configurations are stored under the following registry path:

 

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options

 

Image File Execution Options offer precise control over the execution behavior of specific processes and were initially designed for debugging, instrumentation and compatibility purposes.

Figure 14: Comparison between a blocked process (binaryninja.exe) and an allowed process (firefox.exe) under the MicrosoftSignedOnly system-wide mitigation

The left window shows binaryninja.exe, which is blocked due to the system-wide MicrosoftSignedOnly mitigation that prevents unsigned third-party DLLs from loading. This results in a 'Bad Image' error caused by an unsigned QtWidgets6.dll file. By contrast, Firefox.exe (on the right) runs successfully because an IFEO entry explicitly disables MicrosoftSignedOnly for Firefox. This demonstrates how IFEO overrides can selectively bypass global mitigations.

Figure 15: IFEO registry entry for firefox.exe that overrides system-wide mitigations by disabling MicrosoftSignedOnly

The MitigationOptions value explicitly overrides the global MicrosoftSignedOnly mitigation, allowing Firefox to load unsigned DLLs despite the system-wide restriction. We have designed our own detection approaches to reveal unusual or atypical changes in this technology's environment at an early stage. This often enables anomalies to be identified before they result in the protective mechanisms failing.

References

[1] Russinovich, M. E., Solomon, D. A. & Ionescu, A. (2016). Windows Internals, Part 1 & 2 (7. Edition.). Microsoft Press.

[2] iRED Team. Preventing 3rd Party DLLs from Injecting into your Malware.
https://www.ired.team/offensive-security/defense-evasion/preventing-3rd-party-dlls-from-injecting-into-your-processes

[3] Microsoft Docs. Set-ProcessMitigation.
https://learn.microsoft.com/en-us/powershell/module/processmitigations/set-processmitigation?view=windowsserver2025-ps

[4] MITRE ATT&CK®. Impair Defenses: Disable or Modify Tools.
https://attack.mitre.org/techniques/T1562/001/

[5] Microsoft Docs. Image File Execution Options
https://learn.microsoft.com/en-us/previous-versions/windows/desktop/xperf/image-file-execution-options

Incident Response Hotline

Facing cyber incidents right now?

Contact our 24/7/365 world wide service incident response hotline.

CSIRT