
CLI Go qui désobfusque la sortie de javascript-obfuscator (obfuscator.io) et déminifie le JavaScript à l'aide de transformations AST, de décodage statique et d'un repli sur un bac à sable goja.
jd est un outil Go qui désobfusque la sortie de javascript-obfuscator (obfuscator.io) et déminifie le JavaScript. C'est un portage en Go de webcrack et synchrony.
Détecte et inverse la sortie de javascript-obfuscator :
var/const/let)Plus de 20 transformations de lisibilité :
| Transformation | Exemple |
|---|---|
| computed-properties | console["log"] → console.log |
| merge-strings | "a" + "b" → "ab" |
| unminify-booleans | !0 → true, !1 → false |
| number-expressions | 1 + 2 → 3 |
| void-to-undefined | void 0 → undefined |
| raw-literals | 0x1 → 1 |
| sequence | a(), b(), c() → instructions séparées |
| split-variable-declarations | var a=1, b=2 → var a=1; var b=2 |
| block-statements | envelopper les corps à instruction unique dans { } |
| logical-to-if | a && b() → if (a) b() |
| ternary-to-if | a ? b() : c() → if (a) b() else c() |
| merge-else-if | else { if (...) } → else if (...) |
| for-to-while | for(;;) → while(true) |
| yoda | 5 === x → x === 5 |
| infinity | 1/0 → Infinity |
| invert-boolean-logic | !(a == b) → a != b |
| unary-expressions | supprimer les void/!/typeof sans effet au niveau instruction |
| remove-double-not | !!true → true |
Le parseur de goja ne prend pas en charge la syntaxe des modules ES (import/export). jd pré-extrait les instructions import/export, analyse le script restant, exécute les transformations, puis ajoute les instructions au début de la sortie. Les expressions import() dynamiques sont correctement distinguées des déclarations d'import.
Pour les fichiers que goja ne peut pas analyser entièrement (par exemple les définitions de langage de l'éditeur Monaco utilisant intensivement les expressions régulières), jd se rabat sur un formatage au niveau source : un tokenizer découpe sur les points-virgules tout en préservant verbatim les littéraux d'expressions régulières, les chaînes et les commentaires.
brew install ejfkdev/tap/jd
Téléchargez depuis GitHub Releases (Linux/macOS/Windows, x86_64/ARM64).
go build -o jd .
# Deobfuscate a file (output to stdout)
jd obfuscated.js
# Write to a file
jd obfuscated.js -o cleaned.js
# Read from stdin
cat obfuscated.js | jd -
# Process a directory — recursively processes all .js/.mjs/.cjs files,
# mirrors the directory tree to the output directory.
jd src/ -o dist/
# Directory mode with default output: creates <input>-deobfuscated
jd src/
# Specify file extensions
jd src/ -o dist/ --ext .js,.mjs
# Parallel processing (N workers, default: number of CPUs)
jd src/ -o dist/ -j 8
# Skip non-code files (only output processed JS)
jd src/ -o dist/ --copy-noncode=false
# Only deobfuscate, skip unminify
jd --unminify=false obfuscated.js
# JSON output with warnings
jd --json obfuscated.js
| Option | Défaut | Description |
|---|---|---|
-o, --output | stdout | fichier ou répertoire de sortie (défaut pour un répertoire : <input>-deobfuscated) |
--deobfuscate | true | exécuter la désobfuscation obfuscator.io |
--unminify | true | exécuter les transformations de lisibilité |
--sandbox | auto | exécution du décodeur : auto (statique puis bac à sable), only (toujours le bac à sable), off (statique uniquement) |
--timeout | 10s | délai d'expiration du bac à sable par fichier |
--ext | .js,.mjs,.cjs | extensions de fichiers à traiter en mode répertoire |
-j, --workers | 0 (=CPU) | workers parallèles pour le mode répertoire |
--copy-noncode | true | copier les fichiers non-code dans le répertoire de sortie |
-v, --verbose | false | afficher les diagnostics sur stderr |
--json | false | émettre un JSON {code, warnings} |
jd/
├── main.go # CLI entry
├── internal/
│ ├── cli/ # cobra CLI (i18n: English/Chinese)
│ ├── deobfuscator/ # top-level pipeline + ES module preprocessing
│ ├── jsast/ # AST walker (Cursor, Replace, Remove, Clone)
│ ├── codegen/ # AST → JavaScript printer (pretty/compact)
│ ├── scope/ # lexical scope & binding analysis
│ ├── sandbox/ # goja VM wrapper for decoder execution
│ ├── decoder/ # static decoding: Base64/RC4/rotation
│ ├── deobfuscate/ # string-array/rotator/decoder detection + transforms
│ ├── unminify/ # 20 readability transforms + fixpoint runner
│ └── transform/ # Transform abstraction + ApplyFixpoint
└── testdata/samples/ # test fixtures
parse → splitModuleStatements → deobfuscate → unminify → generate