$npx -y skills add meltedinhex/analyst-ai-pack --skill deobfuscating-malicious-powershellDeobfuscates malicious PowerShell by decoding -EncodedCommand, reversing string
| 1 | # Deobfuscating Malicious PowerShell |
| 2 | |
| 3 | ## When to Use |
| 4 | |
| 5 | - You captured an obfuscated PowerShell command from a log, maldoc, or phishing payload. |
| 6 | - You need to recover the real intent: download URLs, dropped paths, shellcode, or next stage. |
| 7 | - You are unrolling layered encoding (base64 → gzip → IEX) to reach the final script. |
| 8 | |
| 9 | **Do not use** `Invoke-Expression` or run the script to "see what it does" on a working host. |
| 10 | Decode statically; only execute in the isolated lab with logging if dynamic confirmation is |
| 11 | required. |
| 12 | |
| 13 | ## Prerequisites |
| 14 | |
| 15 | - Python (bundled script handles base64/gzip/deflate and common transforms), or a sandbox. |
| 16 | - The command/script text captured as a string. |
| 17 | |
| 18 | ## Safety & Handling |
| 19 | |
| 20 | - Never pipe attacker PowerShell into a live shell. Replace `IEX`/`Invoke-Expression` with |
| 21 | output (print) when transforming. |
| 22 | - Treat decoded URLs/IPs as live; defang before sharing. |
| 23 | |
| 24 | ## Workflow |
| 25 | |
| 26 | ### Step 1: Decode -EncodedCommand |
| 27 | |
| 28 | `-EncodedCommand` (`-enc`) is base64 of UTF-16LE. Decode it first: |
| 29 | |
| 30 | ```bash |
| 31 | python scripts/analyst.py decode --encodedcommand "<base64>" |
| 32 | ``` |
| 33 | |
| 34 | ### Step 2: Identify the obfuscation style |
| 35 | |
| 36 | Common patterns: |
| 37 | |
| 38 | ```text |
| 39 | String reversal : [array]::Reverse / -join with [-1..] |
| 40 | Format operator : ("{1}{0}" -f 'b','a') -> 'ab' |
| 41 | Char codes : [char]104 + [char]105 |
| 42 | Concatenation/splits : 'po'+'wer'+'shell', -split / -replace tricks |
| 43 | Backtick/casing noise : I`E`X, iEx, &('i'+'ex') |
| 44 | ``` |
| 45 | |
| 46 | ### Step 3: Unroll encoding layers |
| 47 | |
| 48 | Resolve nested `FromBase64String`, gzip/deflate (`IO.Compression`), and re-IEX layers until |
| 49 | you reach plain script. The script peels base64/gzip layers automatically. |
| 50 | |
| 51 | ```bash |
| 52 | python scripts/analyst.py deobfuscate payload.ps1 |
| 53 | ``` |
| 54 | |
| 55 | ### Step 4: Neutralize execution sinks |
| 56 | |
| 57 | Replace `IEX`, `Invoke-Expression`, `&`, and `.Invoke()` with a print so the recovered script |
| 58 | is rendered, not run. |
| 59 | |
| 60 | ### Step 5: Extract IOCs |
| 61 | |
| 62 | Pull `DownloadString`/`DownloadFile` URLs, C2 hosts, dropped paths, and any embedded |
| 63 | base64 shellcode for separate analysis. |
| 64 | |
| 65 | ## Validation |
| 66 | |
| 67 | - The fully decoded script is human-readable PowerShell with no remaining base64 blobs. |
| 68 | - Execution sinks are neutralized; nothing in your workflow actually ran the payload. |
| 69 | - Extracted URLs/paths are consistent with the script's logic. |
| 70 | |
| 71 | ## Pitfalls |
| 72 | |
| 73 | - Running the script to decode it — the fastest way to get compromised. |
| 74 | - Stopping after one base64 layer when several are nested. |
| 75 | - Missing UTF-16LE vs UTF-8 when decoding `-enc` (it is UTF-16LE). |
| 76 | - Ignoring `-replace`/`-f` transforms that rebuild commands at runtime. |
| 77 | |
| 78 | ## References |
| 79 | |
| 80 | - See [`references/api-reference.md`](references/api-reference.md) for the decoder/deobfuscator. |
| 81 | - PowerShell encoded-command docs and PSDecode (linked in frontmatter). |