
Ofuscador de PowerShell
Su objetivo es transformar el código para dificultar el análisis y las firmas estáticas, útil en laboratorios y compromisos autorizados de Red Team/Pentesting.
Soporta 6 niveles de ofuscación más una arquitectura de transformaciones/pipeline que permite apilar técnicas como tokenización de cadenas, cifrado ligero de literales, enmascaramiento de números, morfología de identificadores, "jitter" de formato, cosmética de flujo de control, inyección de código muerto, perfiles de fragmentación y perfiles deterministas.
⚠️ Uso responsable: esta herramienta está destinada solo para investigación y pruebas autorizadas. No la utilice con fines maliciosos.```powershell
./psobf -h
██████╗ ███████╗ ██████╗ ██████╗ ███████╗
██╔══██╗██╔════╝██╔═══██╗██╔══██╗██╔════╝
██████╔╝███████╗██║ ██║██████╔╝█████╗
██╔═══╝ ╚════██║██║ ██║██╔══██╗██╔══╝
██║ ███████║╚██████╔╝██████╔╝██║
╚═╝ ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝
Omar Salazar
v.2.0.0
Usage: psobf -i -o -level <1|2|3|4|5|6> [options]
Obfuscation Levels: 1 - Char join encoding 2 - Base64 encoding 3 - Base64 encoding (alternate) 4 - GZip + Base64 compression 5 - Script fragmentation 6 - AES-256 CTR encryption (NEW in 2.0.0)
Transform Pipeline Options (use with -pipeline): iden - Identifier morphing (use with -iden obf) strenc - String encryption (use with -strenc xor|rc4) stringdict - String tokenization (use with -stringdict N) numenc - Number encoding fmt - Format jitter (use with -fmt jitter) cf - Control flow obfuscation (use with -cf-opaque, -cf-shuffle) dead - Dead code injection (use with -deadcode N) hexenc - Hex string encoding (NEW) alias - Cmdlet alias substitution (NEW) unicode - Unicode character encoding (NEW) antidebug - Anti-debugging/VM detection (NEW) iexobf - Invoke-Expression obfuscation (NEW)
Examples:
psobf -i script.ps1 -o out.ps1 -level 2
psobf -i script.ps1 -o out.ps1 -level 6 -profile heavy
psobf -i script.ps1 -o out.ps1 -level 4 -pipeline "iden,alias,hexenc,antidebug,iexobf" -iden obf
psobf -i script.ps1 -o out.ps1 -level 4 -pipeline "strenc" -strenc rc4 -strkey 0011223344556677
## Características
<h1 align="center">
<img src="https://assets.kitploit.com/production/public/readmes/6598/11956ab9f65e8dc1b0460652042c601f70d28bb67e9fd6f0a89813ed5369997f.gif" alt="psobf" width="700px"></a>
<br>
</h1>
<h1 align="center">
<img src="https://raw.githubusercontent.com/taurusomar/psobf/HEAD/static/poc2.gif" alt="psobf" width="700px"></a>
<br>
</h1>
---
## Instalación```bash
go install github.com/TaurusOmar/psobf/v2/cmd/[email protected]
psobf -i input.ps1 -o out.ps1 -level 1..6 [options] psobf -h # full help
## Características
<h1 align="center">
<img src="https://assets.kitploit.com/production/public/readmes/6598/11956ab9f65e8dc1b0460652042c601f70d28bb67e9fd6f0a89813ed5369997f.gif" alt="psobf" width="700px"></a>
<br>
</h1>
<h1 align="center">
<img src="https://raw.githubusercontent.com/taurusomar/psobf/HEAD/static/poc2.gif" alt="psobf" width="700px"></a>
<br>
</h1>
---
## Instalación```bash
go install github.com/TaurusOmar/psobf/cmd/[email protected]
psobf -i input.ps1 -o out.ps1 -level 1..6 [options] psobf -h # full help
---
## Referencia completa de flags
| Flag | Tipo / Valores | Predeterminado | Descripción | Ejemplo | | |
| ------------- | ----------------- | -------------------: | ------------------------------------------- | ------------------------------------------------------------ | ------------------------------- | ---------------------- |
| `-i` | string | — | Entrada PS1 (usa `-stdin` para leer desde pipe) | `-i script.ps1` | | |
| `-o` | string | `obfuscated.ps1` | Salida (usa `-stdout` para escribir a STDOUT) | `-o out.ps1` | | |
| `-level` | 1..6 | 1 | Empaquetador final (ver Niveles) | `-level 4` | | |
| `-noexec` | bool | false | Emitir solo payload (sin `Invoke-Expression`) | `-noexec` | | |
| `-stdin` | bool | false | Leer PS desde STDIN | `-stdin` | | |
| `-stdout` | bool | false | Escribir resultado a STDOUT | `-stdout` | | |
| `-seed` | int64 | aleatorio | Aleatoriedad reproducible | `-seed 42` | | |
| `-q` | bool | false | Silencioso (sin banner) | `-q` | | |
| `-pipeline` | csv | — | Transformaciones a aplicar en orden | `-pipeline "iden,strenc,stringdict,numenc,fmt,cf,dead,frag"` | | |
| `-iden` | `keep`/`obf` | `keep` | Modificación de identificadores (vars y funciones) | `-iden obf` | | |
| `-strenc` | `off`/`xor`/`rc4` | `off` | Cifrado de literales de cadena | `-strenc rc4` | | |
| `-strkey` | hex | — | Clave para `-strenc` | `-strkey 0011223344556677` | | |
| `-stringdict` | 0..100 | 0 | Tokenizar cadenas largas; % de probabilidad por literal | `-stringdict 40` | | |
| `-numenc` | bool | false | Codificar números como expresiones aritméticas en PS | `-numenc` | | |
| `-fmt` | `off`/`jitter` | `off` | Aleatorizar espacios en blanco / saltos de línea | `-fmt jitter` | | |
| `-cf-opaque` | bool | false | Envolver en `if(1 -eq 1){...}` | `-cf-opaque` | | |
| `-cf-shuffle` | bool | false | Reordenar **bloques de funciones** | `-cf-shuffle` | | |
| `-deadcode` | 0..100 | 0 | Probabilidad de inyectar código muerto | `-deadcode 20` | | |
| `-frag` | `perfil=ajustado | medio | suelto\` | — | Perfil de fragmentación (nivel 5) | `-frag perfil=medio` |
| `-minfrag` | int | 10 | Tamaño mínimo de fragmento (nivel 5) | `-minfrag 8` | | |
| `-maxfrag` | int | 20 | Tamaño máximo de fragmento (nivel 5) | `-maxfrag 16` | | |
| `-profile` | \`ligero | equilibrado| pesado\` | — | Ajustes predefinidos para pipeline/seed/etc. | `-profile pesado` |
| `-fuzz` | int | 0 | Producir N variantes (semillas diferentes) | `-fuzz 5` | | |
| `-poly` | int | 0 | Variantes polimórficas por transformación | `-poly 3` | | |
> El **pipeline** se ejecuta **antes** del empaquetado final con **`-level`**.
---
## Script de entrada de ejemplo (seguro)
Para mantener los ejemplos inofensivos, usaremos:```powershell
Write-Host "Hello, World!"
$answer = 42
function Greet($name) { Write-Host ("Hi, " + $name) }
Greet "Ada"
Lo siguiente muestra la forma de las salidas (fragmentos). Los payloads reales diferirán.
psobf -i sample.ps1 -o out.ps1 -level 1
**Salida (fragmento):**```powershell
$obfuscated = $([char[]](87,114,105,116,101,45,72,111,115,116,32,34,72,101,108,108,111,44,32,87,111,114,108,100,33,34,10,36,97,110,115,119,101,114,32,61,32,52,50,10,102,117,110,99,116,105,111,110,32,71,114,101,101,116,40,36,110,97,109,101,41,32,123,32,87,114,105,116,101,45,72,111,115,116,32,40,34,72,105,44,32,34,32,43,32,36,110,97,109,101,41,32,125,10,71,114,101,101,116,32,34,65,100,97,34,10) -join ''); Invoke-Expression $obfuscated
psobf -i sample.ps1 -o out.ps1 -level 2
**Salida (fragmento):**```powershell
$obfuscated = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('V3JpdGUtSG9zdCAiSGVsbG8sIFdvcmxkISIKJGFuc3dlciA9IDQyCmZ1bmN0aW9uIEdyZWV0KCRuYW1lKSB7IFdyaXRlLUhvc3QgKCJIaSwgIiArICRuYW1lKSB9CkdyZWV0ICJBZGEiCg==')); Invoke-Expression $obfuscated
psobf -i sample.ps1 -o out.ps1 -level 3
**Salida (fragmento):**```powershell
$e = [Convert]::FromBase64String('V3JpdGUtSG9zdCAiSGVsbG8sIFdvcmxkISIKJGFuc3dlciA9IDQyCmZ1bmN0aW9uIEdyZWV0KCRuYW1lKSB7IFdyaXRlLUhvc3QgKCJIaSwgIiArICRuYW1lKSB9CkdyZWV0ICJBZGEiCg=='); $obfuscated = [Text.Encoding]::UTF8.GetString($e); Invoke-Expression $obfuscated
psobf -i sample.ps1 -o out.ps1 -level 4
**Salida (fragmento):**```powershell
$compressed = 'H4sIAAAAAAAA/wovyixJ1fXILy5RUPJIzcnJ11EIzy/KSVFU4lJJzCsuTy1SsFUwMeJKK81LLsnMz1NwL0pNLdFQyUvMTdVUqFZA0q+h5JGpo6CkoK0Ala3lAitWUHJMSVTiAgQAAP//m+Ey2GoAAAA='; $bytes = [Convert]::FromBase64String($compressed); $ms = New-Object IO.MemoryStream(,$bytes); $gz = New-Object IO.Compression.GzipStream($ms,[IO.Compression.CompressionMode]::Decompress); $sr = New-Object IO.StreamReader($gz); $obfuscated = $sr.ReadToEnd(); Invoke-Expression $obfuscated
psobf -i sample.ps1 -o out.ps1 -level 5
**Salida (fragmento):**```powershell
$fragments = @('Write-Host "Hello',', World!"
$','answer = 42','
function G','reet($name)',' { Write-Ho','st ("Hi, " ','+ $name) }
','Greet "Ada"','
'); $script = $fragments -join ''; Invoke-Expression $script
psobf -i sample.ps1 -o out.ps1 -level 6
**Salida (fragmento):**```powershell
$k=[Convert]::FromBase64String('...base64key...');$iv=[Convert]::FromBase64String('...base64iv...');$e=[Convert]::FromBase64String('...base64ciphertext...');$a=New-Object Security.Cryptography.AesManaged;$a.Key=$k;$a.IV=$iv;$d=$a.CreateDecryptor();$bytes=$d.TransformFinalBlock($e,0,$e.Length);$dec=[Text.Encoding]::UTF8.GetString($bytes);Invoke-Expression $dec
Usa
-noexecpara inspeccionar payloads sin ejecutarlos.
-iden)__$.Comando```bash psobf -i sample.ps1 -o out.ps1 -level 4 -pipeline "iden" -iden obf -seed 11
**Salida (fragmento)**```powershell
$WguE = 42
function QhZy($Chx){ Write-Host ("Hi, " + $Chx) }
QhZy "Ada"
-strenc xor|rc4)Encripta solo literales de cadena (sin manipulación de API). Los descifra justo a tiempo en tiempo de ejecución. Banderas: -strenc xor|rc4, -strkey .
Comando```bash psobf -i sample.ps1 -o out.ps1 -level 4 -pipeline "strenc" -strenc xor -strkey a1b2c3d4 -seed 42
**Salida (fragmento)**```powershell
$b=[Convert]::FromBase64String('EwAB...'); for($i=0;$i -lt $b.Length;$i++){$b[$i]=$b[$i] -bxor 0xA1}; [Text.Encoding]::UTF8.GetString($b)
Comando```bash psobf -i sample.ps1 -o out.ps1 -level 2 -pipeline "strenc" -strenc rc4 -strkey 0011223344556677 -seed 7
**Salida (fragmento)**```powershell
function __decGWREVT($k,[byte[]]$d){ $s=0..255; $j=0; for($i=0;$i -lt 256;$i++){ $j=($j+$s[$i]+$k[$i%$k.Length])%256; $t=$s[$i];$s[$i]=$s[$j];$s[$j]=$t } $i=0;$j=0; for($x=0;$x -lt $d.Length;$x++){ $i=($i+1)%256;$j=($j+$s[$i])%256; $t=$s[$i];$s[$i]=$s[$j];$s[$j]=$t; $d[$x]=$d[$x] -bxor $s[($s[$i]+$s[$j])%256] } [Text.Encoding]::UTF8.GetString($d) }
...
( __decGWREVT ([byte[]](0..(8-1)|%{[Convert]::ToByte('0011223344556677'.Substring($_*2,2),16)})) ([Convert]::FromBase64String('m7m7...')) )
-stringdict)Tokeniza cadenas largas en un array $D y las reconstruye en tiempo de ejecución. Reduce firmas repetitivas.
Bandera: -stringdict <0..100>
Comando```bash psobf -i sample.ps1 -o out.ps1 -level 3 -pipeline "stringdict" -stringdict 40 -seed 1
**Salida (fragmento)**```powershell
$D=@('Hello',', World','!','Hi, ', 'Ada');
Write-Host ($D[0]+$D[1]+$D[2])
function Greet($name){ Write-Host ($D[3] + $name) }
Greet $D[4]
-numenc)Reemplaza números simples por expresiones aritméticas/bitwise equivalentes (fuera de cadenas).```bash psobf -i sample.ps1 -o out.ps1 -level 2 -pipeline "numenc" -numenc -seed 1337
**Salida (fragmento)**```powershell
$answer = ((0x2A -bxor 0x00)+0)
Cuidado: Las redirecciones como 2>&1 deben permanecer idénticas. Si tu fuente tiene redirecciones sin comillas y estás experimentando problemas, deshabilita -numenc o encapsula esas redirecciones en cadenas en la fuente.
-fmt)Aleatoriza espacios y saltos de línea.
Comando```bash psobf -i sample.ps1 -o out.ps1 -level 2 -pipeline "fmt" -fmt jitter -seed 20
**Salida (fragmento)**```powershell
Write-Host "Hello, World!"
$answer=42
function Greet($name) { Write-Host ("Hi, "+$name) }
Greet "Ada"
-cf-opaque, -cf-shuffle)-cf-opaque: envuelve todo el script en una rama que nunca es falsa.-cf-shuffle: reordena los bloques de funciones (no instrucciones individuales). Notarás cambios solo si tu script define funciones.Comando```bash psobf -i sample.ps1 -o out.ps1 -level 4 -pipeline "cf" -cf-opaque -cf-shuffle -seed 77
**Salida (fragmento)**```powershell
if(1 -eq 1){
function Greet($name){ Write-Host ("Hi, " + $name) }
Write-Host "Hello, World!"
$answer = 42
Greet "Ada"
}
-deadcode)Inyecta funciones no-op, bucles de 0 iteraciones, cadenas inofensivas, etc. Controlado por probabilidad. Bandera: -deadcode <0..100> (probabilidad de inyección de fragmentos).
Comando```bash psobf -i sample.ps1 -o out.ps1 -level 4 -pipeline "dead" -deadcode 25 -seed 5
**Salida (fragmento)**```powershell
function __dummyzQJxJk { return }
for($i=0;$i -lt 0;$i++){Start-Sleep -Milliseconds 0}
$x='canary';$y=$x+$x|Out-Null
Write-Host "Hello, World!"
...
-frag, -minfrag, -maxfrag)Solo afecta al nivel 5 (fragmentos de cadena + unión en tiempo de ejecución).
Perfiles:
profile=tight → fragmentos pequeños (≈6–10)profile=medium → fragmentos medianos (≈10–18)profile=loose → fragmentos más grandes (≈14–28)O ajusta con -minfrag / -maxfrag.
Comandos```bash
psobf -i sample.ps1 -o out.ps1 -level 5 -frag profile=loose -seed 9
psobf -i sample.ps1 -o out.ps1 -level 5 -minfrag 8 -maxfrag 16 -seed 9
**Salida (fragmento)**```powershell
$fragments=@('Write-Host "Hello,',' World!"',"`n", '$answer = 42',"`n",'function Greet($','name){ Write-Host ("Hi, "+$name)}',"`n",'Greet "Ada"');
$script=$fragments -join ''; Invoke-Expression $script
hexenc)Codifica cadenas literales como hexadecimal.```bash psobf -i sample.ps1 -o out.ps1 -level 2 -pipeline "hexenc" -seed 42
**Salida (fragmento):**```powershell
[Text.Encoding]:https://raw.githubusercontent.com/taurusomar/psobf/HEAD/:UTF8.GetString(%5BConvert%5D::FromHexString(%2748656C6C6F%27))
alias)Reemplaza los cmdlets de PowerShell con sus alias cortos.```bash psobf -i sample.ps1 -o out.ps1 -level 2 -pipeline "alias" -seed 42
**Salida (fragmento):**```powershell
# Write-Host → echo/write/outright
# Get-ChildItem → dir/ls/gci
# ForEach-Object → foreach/%
unicode)Convierte caracteres de cadena al formato [char]0xNNNN.```bash
psobf -i sample.ps1 -o out.ps1 -level 2 -pipeline "unicode" -seed 42
**Salida (fragmento):**```powershell
"H[char]0x0065[char]0x006C[char]0x006Co"
antidebug)Inyecta fragmentos de detección de sandbox/VM/debugger.```bash psobf -i sample.ps1 -o out.ps1 -level 4 -pipeline "antidebug" -seed 42
**Salida (fragmento):**```powershell
if($env:COMPUTERNAME -match '^(SANDBOX|MALWARE|VIRUS)'){ exit }
if((Get-WmiObject Win32_ComputerSystem).Model -match '^(VirtualBox|VMware)'){ exit }
# ... original script ...
iexobf)Reemplaza Invoke-Expression con formas alternativas.```bash
psobf -i sample.ps1 -o out.ps1 -level 2 -pipeline "iexobf" -seed 42
**Salida (fragmento):**```powershell
# Invoke-Expression → IEX or .
. $code # instead of Invoke-Expression $code
Los preajustes son puntos de partida convenientes. Cualquier indicador explícito que pases anula el preajuste. Cualquier indicador que pases explícitamente tiene prioridad sobre el perfil.
-seed N → salida determinista para una configuración dada.-seed → aleatoriedad con semilla criptográfica.-fuzz N → produce N variantes (out.ps1.v1.ps1, out.ps1.v2.ps1, …), excelente para pruebas de diversidad.Ejemplo```bash psobf -i sample.ps1 -o out.ps1 -level 4 -profile heavy -fuzz 3
---
## STDIN/STDOUT y `-noexec`
* **Tubería de entrada/salida** ```bash
cat sample.ps1 | psobf -stdin -stdout -level 2 > out.ps1
El objetivo es diversificar los artefactos y reducir las firmas estables para la investigación en entornos autorizados.
2. **Máxima diversidad (formato + fragmentación + código muerto)**```bash
psobf -i sample.ps1 -o out.ps1 -level 5 \
-pipeline "fmt,frag,dead" -fmt jitter -frag profile=loose -deadcode 15 \
-fuzz 5
4. **Reducir IOCs estáticos (números + diccionario)**```bash
psobf -i sample.ps1 -o out.ps1 -level 2 -pipeline "numenc,stringdict" -numenc -stringdict 35 -seed 9
---
## Mejores prácticas y notas defensivas
* Rote **`-strkey`** y **`-seed`** por compilación.
* Prefiera combinar capas: `-strenc` + `-stringdict` + `-fmt jitter` + fragmentación.
* Use `-fuzz` para generar familias de variantes para pruebas de detección.
* Mantenga una línea base limpia e inofensiva y verifique la equivalencia funcional en un entorno aislado antes y después de las transformaciones.
* Si su script depende de una sintaxis PS delicada (por ejemplo, redirecciones), manténgalas entre comillas o deshabilite `-numenc`.
---
## Diagrama de arquitectura```
┌──────────────┐
│ input.ps1 │
└──────┬───────┘
│ read (-i / -stdin)
▼
┌──────────────┐
│ Pipeline │ order you choose
│ iden │ rename vars/funcs
│ strenc │ XOR/RC4 literals
│ stringdict │ tokenize + rejoin
│ numenc │ numeric masking
│ fmt │ whitespace jitter
│ cf │ opaque/shuffle
│ dead │ harmless noise
└──────┬───────┘
│ mutated script
▼
┌──────────────┐
│ Level 1..5 │ final packing
└──────┬───────┘
│ + Invoke-Expression (unless -noexec)
▼
┌──────────────┐
│ out.ps1 │
└──────────────┘
psobf -i sample.ps1 -o out.ps1 -level 2 -seed 123
psobf -i sample.ps1 -o out.ps1 -level 4 -pipeline "strenc" -strenc rc4 -strkey 0011223344556677
psobf -i sample.ps1 -o out.ps1 -level 3 -pipeline "stringdict,numenc" -stringdict 40 -numenc
psobf -i sample.ps1 -o out.ps1 -level 5
-pipeline "iden,strenc,stringdict,numenc,fmt,cf,dead,frag"
-iden obf -strenc xor -strkey a1b2c3d4 -stringdict 35 -numenc
-fmt jitter -cf-opaque -deadcode 15 -frag profile=medium -seed 777
psobf -i sample.ps1 -o out.ps1 -level 6 -profile heavy -seed 999
psobf -i sample.ps1 -o out.ps1 -level 4 -pipeline "antidebug,alias,hexenc" -seed 42
psobf -i sample.ps1 -o out.ps1 -level 6
-pipeline "iden,alias,hexenc,unicode,antidebug,iexobf,strenc"
-iden obf -strenc rc4 -strkey 0011223344556677 -seed 42
psobf -i sample.ps1 -o payload.txt -level 4 -noexec
## Legal
Este proyecto es solo para pruebas **educativas** y **autorizadas**. Usted es el único responsable de su uso. Los autores y colaboradores no asumen ninguna responsabilidad por daños directos o indirectos.