
javascript-obfuscator(obfuscator.io)の出力を難読化解除し、AST変換、静的デコード、およびgojaサンドボックスへのフォールバックを用いてJavaScriptを非圧縮化するGo CLI。
jd は、javascript-obfuscator(obfuscator.io)の出力を難読化解除し、JavaScript を非圧縮化する Go ツールです。webcrack と synchrony の Go 移植版です。
javascript-obfuscator の出力を検出して逆変換します:
var/const/let)20 以上の可読性変換:
| 変換 | 例 |
|---|---|
| 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() → 個別の文 |
| split-variable-declarations | var a=1, b=2 → var a=1; var b=2 |
| block-statements | 単一の文からなる本体を { } で囲む |
| 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 | 文レベルで無意味な void/!/typeof を削除 |
| remove-double-not | !!true → true |
goja のパーサーは ES モジュール構文(import/export)をサポートしていません。jd は import/export 文を事前に抽出し、残りのスクリプトを解析して変換を実行した後、その文を出力の先頭に付加します。動的な import() 式は import 宣言と正しく区別されます。
goja が完全に解析できないファイル(例:正規表現を多用する Monaco エディタの言語定義)に対して、jd はソースレベルのフォーマットにフォールバックします。トークナイザーが正規表現リテラル、文字列、コメントをそのまま保持しながらセミコロンで分割します。
brew install ejfkdev/tap/jd
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
| フラグ | デフォルト | 説明 |
|---|---|---|
-o, --output | stdout | 出力ファイルまたはディレクトリ(ディレクトリのデフォルト:<input>-deobfuscated) |
--deobfuscate | true | obfuscator.io の難読化解除を実行 |
--unminify | true | 可読性変換を実行 |
--sandbox | auto | デコーダー実行:auto(静的→サンドボックス)、only(常にサンドボックス)、off(静的のみ) |
--timeout | 10s | ファイルごとのサンドボックスタイムアウト |
--ext | .js,.mjs,.cjs | ディレクトリモードで処理するファイル拡張子 |
-j, --workers | 0 (=CPU) | ディレクトリモードの並列ワーカー数 |
--copy-noncode | true | 非コードファイルを出力ディレクトリにコピー |
-v, --verbose | false | 診断情報を stderr に出力 |
--json | false | {code, warnings} JSON を出力 |
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
IgnoreRegExpErrors 付きの goja パーサー。解析できないファイルはソースレベルのフォーマットにフォールバックデコーダーは 2 段階のアプローチを採用しています:
Interrupt タイムアウト、SetMaxCallStackSize、決定的な rand/time、setInterval/setTimeout なしの goja VM で実行 — 静的パスではデコードできないカスタムエンコーダーを処理。MIT