AMSI bypass
TL;DR: AMSI is a userland scanning interface — patch
AmsiScanBufferin-process so it returns clean, and PowerShell/JScript stop forwarding to Defender for the rest of the session.
What it is
The Antimalware Scan Interface (amsi.dll) is a Windows API that script hosts (PowerShell, WSH, Office VBA, .NET in-memory assemblies) call before executing untrusted content. The host passes a buffer to AmsiScanBuffer, which round-trips to the registered AV provider. Bypasses target the in-process surface — since AMSI runs in the host’s address space, anything executing in that host can rewrite it.
Preconditions / where it applies
- Code execution inside a script host that uses AMSI:
powershell.exe,pwsh.exe,wscript.exe,cscript.exe, Office processes,dotnet.exefor loaded assemblies - Read/write access to your own process memory (always true unless PPL or a third party set memory protections)
- AMSI signatures are constantly updated, so the literal one-liner changes — the pattern survives
Technique
Canonical approach: find AmsiScanBuffer in amsi.dll, flip page protections to RW, write a stub that forces AMSI_RESULT_CLEAN (0) and S_OK, restore protections. In PowerShell:
1
2
3
$a=[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')
$f=$a.GetField('amsiInitFailed','NonPublic,Static')
$f.SetValue($null,$true)
That sets a managed flag that short-circuits scanning — fragile, signatured for years, but illustrates the pattern. Sturdier variants patch the unmanaged function directly:
1
2
3
4
void* p = GetProcAddress(LoadLibrary("amsi.dll"), "AmsiScanBuffer");
DWORD old; VirtualProtect(p, 6, PAGE_EXECUTE_READWRITE, &old);
memcpy(p, "\x48\x31\xC0\xC3", 4); // xor rax,rax ; ret -> S_OK, score 0
VirtualProtect(p, 6, old, &old);
Variations: hardware breakpoint on AmsiScanBuffer and skip via Vectored Exception Handler (no memory write — defeats integrity checks), patch AmsiOpenSession to return failure so a session never registers, hook NtTraceEvent / EtwEventWrite simultaneously since AMSI itself emits an event when scanning happens.
Constrained Language Mode (CLM) blocks the managed reflection technique — Add-Type, reflection, and arbitrary type lookups are gone. You either need an unmanaged-side patch shipped via .NET P/Invoke from a non-CLM context, or you bypass CLM first.
Each substring of the patch gets signatured. Obfuscate, fetch strings from environment, build the byte array dynamically.
A subtler variant returns 0x80070057 (E_INVALIDARG) in eax instead of S_OK — the call technically fails, but on multiple Defender code paths the buffer’s effective scan result is still treated as clean, and a non-zero HRESULT looks less suspicious to a sanity check that asserts “AMSI returned exactly success” as a tamper canary. Patching AmsiOpenSession to fail also short-circuits later AmsiScanBuffer calls because the host bails before reaching the scanner.
Detection and defence
- AMSI providers report events with
Microsoft-Antimalware-Scan-InterfaceETW; tampering changes the rate to zero abruptly - EDRs can monitor write access to
amsi.dllin-memory regions via ETW Threat Intelligence - Page protection changes on loaded modules to RWX are a strong signal
- WDAC + Constrained Language Mode + signed-only script policy + PPL Defender all materially raise the bar
- Defender enrolls in
MpClient!ScanContentcallbacks regardless — bypassing AMSI doesn’t bypass on-access file scanning
References
- Microsoft Docs — AMSI — the official interface and behaviour
- S3cur3Th1sSh1t — Amsi-Bypass-Powershell — collection of historic bypasses with notes on lifespan
- Pentest Partners blog — hardware-breakpoint variant write-ups
- ired.team — AV bypass with Metasploit templates — adjacent userland evasion patterns useful when chaining around AMSI
- etw-bypass edr-hooks-and-unhooking