
このツールは、javascript-obfuscator で保護された、コンパイル済み V8 JavaScript バイトコードを静的に難読化解除することに特化しています。
元の JavaScript ソースではなく、View8 が生成する疑似コードに対して動作します。このプロジェクトは JSCeal ペイロードを対象に開発・テストされました。
フィルタはパターン駆動型であり、主に研究ツールキットおよびリファレンス実装として意図されています。このツールは汎用の JavaScript 難読化解除ツールではなく、元のソースコードを再構築せず、実行可能な JavaScript を生成しません。その出力は、静的解析、検索、比較、関数ツリーのエクスポートを目的とした View8 疑似コードのままです。
📖 Wiki を読む
pickle を使用します。悪意のある、または信頼できない .pkl ファイルを読み込むと、コードが実行される可能性があります。View8 でローカルに生成したシリアライズファイルのみを読み込んでください。requirements.txt からの Python 依存関係brotli コマンドラインユーティリティ分離された Python 環境を作成します:
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install --upgrade pip
python3 -m pip install -r requirements.txt
deobf_ai.py の OpenAI バックエンドには、追加で OpenAI Python パッケージが必要です:
python3 -m pip install openai
Anthropic バックエンドは requests を通じて HTTP API を使用します。Ollama バックエンドは、到達可能な Ollama サーバーを期待します。
元の JSCeal app.jsc ペイロードは Brotli 圧縮されています。Linux では、brotli ユーティリティで解凍できます:
brotli -d app.jsc -o app.decompressed.jsc
scripts/ 配下のバッチワークフローは、この手順を scripts/unpack_all.sh で実行します。
Windows で、または brotli コマンドラインユーティリティが利用できない場合、同梱の Node.js ヘルパーをフォールバックとして使用できます。これは入力の解凍のみを行い、実行はしません:
node Utils/decompress-jsc.js app.jsc
次のファイルを書き出します:
app.jsc.decompressed.jsc
V8 コードキャッシュはバージョン固有です。ペイロードと同じ V8 バージョン用にビルドされた逆アセンブラを使用してください。
開発中に使用された JSCeal サンプルは、V8 10.2.154.26 に基づいていました。無関係な V8 ビルドのデフォルト逆アセンブラは正しく動作しません。
ソースツリーには、逆アセンブラのソースと必要な V8 パッチが以下に含まれています:
Utils/disasm/v8dasm.cpp
Utils/disasm/patches/
プリビルドの Linux バイナリはプロジェクトリリースに同梱されており、ソースツリーには再ビルドに必要なソースとパッチが含まれています。詳細な説明はプロジェクトの Wiki にあります。一致する v8dasm を入手またはビルドした後、以下を実行します:
/path/to/v8dasm app.decompressed.jsc > app.jsc.disasm.txt
逆アセンブルされたファイルを view8.py に渡し、さらなる処理用のシリアライズ出力と人間が読める疑似コードの両方を生成します:
mkdir -p decompiled
python3 View8/view8.py \
--input_format disassembled \
--inp app.jsc.disasm.txt \
--normalize \
--out decompiled/app.dec.txt \
--export_format decompiled serialized
これにより、以下が生成されます:
decompiled/app.dec.txt
decompiled/app.dec.pkl
--normalize オプションにより、生成された関数識別子が、逆アセンブルと逆コンパイルを繰り返し実行しても再現可能になります。
個々の難読化レイヤー用に個別のフィルタがあります。これらは deobf_all.py でシリアライズされた View8 出力にまとめて適用できます:
mkdir -p deobfuscated
python3 deobf_all.py \
--inp decompiled/app.dec.pkl \
--out deobfuscated/app.deobf.txt \
--export_format decompiled serialized
デフォルトの文字列フィルタは、分析された JSCeal ペイロードの大部分で使用されているバリアント 2 です。より単純な文字列スキームを明示的に選択するには、次を追加します:
--str_deobf 1
典型的な出力は次のとおりです:
deobfuscated/app.deobf.txt
deobfuscated/app.deobf.pkl
deobfuscated/app.deobf.txt.strings.txt
decompiled/app.dec.resolved_funcs.csv
解決済み関数 CSV はサンプル固有のキャッシュです。これが存在しない場合、文字列パスは必要なデコーダ設定を回復し、CSV を書き込み、同じ実行で文字列の難読化解除を続行します。以降の実行はキャッシュを再利用するため、通常は高速です。
解決済み関数 CSV を、異なる逆コンパイル済みペイロードで再利用しないでください。
すべての構造的難読化解除フィルタが適用された後、deobf_ai.py は関数の動作を説明する名前を提案できます。Anthropic、OpenAI、Ollama バックエンドをサポートしています。
実行を再現可能にするために、モデルを明示的に渡してください。
export ANTHROPIC_API_KEY='...'
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--llm_backend anthropic \
--model '<model-id>' \
--export_format decompiled serialized
export OPENAI_API_KEY='...'
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--llm_backend openai \
--model '<model-id>' \
--export_format decompiled serialized
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--llm_backend ollama \
--model '<local-model>' \
--ollama_url http://localhost:11434 \
--export_format decompiled serialized
デフォルトモードでは、リネーマーはエントリ関数から始まる直接呼び出しツリーを構築し、呼び出しを通じて到達した関数のみをリネームします。コールバックや割り当てられたハンドラを含む、すべての可視の関数参照を含めるには --greedy を追加します。
生成された 2 列の CSV はキャッシュとして機能し、中断された実行を続行できます。既存のキャッシュを --csv で明示的に選択します:
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--csv deobfuscated/app.deobf.renamed_funcs.greedy.example-model.csv \
--llm_backend anthropic \
--model '<model-id>' \
--greedy \
--export_format decompiled serialized
通常モードでは、CSV は潜在的に部分的なキャッシュとして扱われます。キャッシュされた名前が最初に適用され、キャッシュでカバーされている関数は選択された呼び出しまたは参照ツリーから削除され、LLM は未解決の関数に対してのみ呼び出されます。CSV がそのツリーを完全にカバーしている場合、API キーや LLM 接続は不要です。ツリーの一部のみをカバーしている場合、選択されたバックエンドが初期化され、新しく生成されたマッピングが同じ CSV に追加されます。
CSV が作成されたときと同じツリーモードを使用してください。--greedy 実行から生成された CSV は、直接呼び出しサブセットを再利用するだけでなく、その実行を続行することが目的の場合は、通常、再度 --greedy が必要です。
CSV に、レビュー済み、編集済み、インポート済み、またはリベース済みのマッピングなど、適用したいラベルがすでに含まれている場合は、--apply-csv-only を使用します:
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--csv renamed_functions.normalized.csv \
--apply-csv-only \
--export_format decompiled serialized
このモードでは:
--csv が必要です;--func と組み合わせることはできません。元の関数識別子が入力に存在しない行は無視されます。CSV に、読み込まれたファイルに適用可能なマッピングが含まれていない場合、コマンドは失敗します。
--func を正確な完全な関数識別子とともに使用して、難読化解除された 1 つの関数の焦点を絞ったセマンティック分析を要求します:
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--func func_example_0x100001234 \
--llm_backend anthropic \
--model '<model-id>'
分析には、提案された名前、動作の要約、入力と戻り値、副作用、ステップバイステップのロジック、クリーンアップされた疑似コード、裏付けとなる証拠、未解決の不確実性が含まれます。--csv を指定すると、読み込まれたコーパスを変更せずに、選択した関数内の参照のコンテキストとしてキャッシュされたセマンティック名が追加されます。--analysis-out analysis/function.md を使用して、レポートを Markdown として保存します。あいまい一致は提案としてのみ出力されます。要求された関数識別子は正確に一致する必要があります。
温度、バッチ処理、Anthropic 思考モード、トークン制限、カスタム CSV パスを制御するオプションについては、--help を使用してください。
LLM が生成した名前はナビゲーションの補助であり、証拠ではありません。常に難読化解除された本体と照合して検証してください。
難読化解除された JSCeal 出力は通常、非常に大きくなります。シリアライズされた出力を View8 に再読み込みし、より小さな関数ツリーに分割します。
この段階で、--scope 0 を追加します。スコープ伝播は難読化解除器によってすでに実行されており、繰り返すと値が誤って伝播される可能性があります。
宣言者関係に基づくツリー:
python3 View8/view8.py \
--input_format serialized \
--inp deobfuscated/app.deobf.pkl \
--out trees/declarers \
--export_format decompiled \
--tree start \
--scope 0
コンパクトな直接呼び出しの概要:
python3 View8/view8.py \
--input_format serialized \
--inp deobfuscated/app.deobf.pkl \
--out trees/calls \
--export_format decompiled \
--tree start \
--scope 0 \
--split_mode calls \
--inline_depth 1 \
--split_depth 5
コールバックや割り当てられたハンドラを含む、より広範な参照ツリー:
python3 View8/view8.py \
--input_format serialized \
--inp deobfuscated/app.deobf.pkl \
--out trees/references \
--export_format decompiled \
--tree start \
--scope 0 \
--split_mode references \
--inline_depth 1 \
--split_depth 3
JSC ファイルによっては、異なる文字列難読化モードを使用する場合があります。
最も単純な観測モードはインデックスシフトを使用し、deobf_str1.py で処理されます。最も一般的な JSCeal モードは、Base64、RC4、チャンク化された文字列、および変換されたインデックスを使用します。これは deobf_str2.py で処理されます。
完全なパイプラインはデフォルトでバリアント 2 を選択します。フィルタはテスト用に個別に実行することもできます。
deobf_str2.py--help を使用して、利用可能なすべてのモードとオプションを表示します:
python3 deobf_str2.py --help
直接的な文字列難読化解除の実行は、次のように開始できます:
python3 deobf_str2.py \
--inp decompiled/app.dec.pkl \
--out work/app.strings.txt \
--export_format decompiled serialized
実行中に、スクリプトは文字列デコーダ関数を特定し、有効なキャッシュされた設定を読み込み、欠落しているものを解決し、結果の CSV を保存し、文字列をデコードします。2 回目の実行は不要です。
deobf_str2.py を直接使用する場合、デフォルトの CSV 名は resolved_funcs.csv です。サンプル固有のパスを --csv または -c で選択します:
python3 deobf_str2.py \
--inp decompiled/app.dec.pkl \
--out work/app.strings.txt \
--csv decompiled/app.dec.resolved_funcs.csv \
--export_format decompiled serialized \
--verbosity 1
個々のフィルタを連鎖させる場合、後続のパスが View8 オブジェクトに対して操作を続行できるように、ステージ間でシリアライズされた出力を保持してください。
deobf_all.py は次のステージを順番に適用します:
LLM 支援による関数名の変更はオプションであり、構造的難読化解除の後に個別に実行されます。
リポジトリには、scripts/ 配下に完全なヘルパーワークフローが含まれています。すべてのスクリプトは 1 つのディレクトリに保持され、同じ一元化された設定を参照します。
scripts/config.sh 共有ツールとワークスペースのパス
scripts/copy_payloads.sh JSCeal app.jsc ファイルを収集し MD5 で命名
scripts/unpack_all.sh Brotli 解凍
scripts/disasm_all.sh バッチ V8 逆アセンブル
scripts/decompile_all.sh バッチ View8 逆コンパイル
scripts/deobfuscate_all.sh 結合ログ付きバッチ難読化解除
scripts/run_unattended.sh 分離された難読化解除と検証
scripts/collect_output.sh デコーダキャッシュと文字列リストの収集
同梱の scripts/config.sh には、サンプル環境からのパスが含まれています:
JSC_DEOBF_ROOT="$HOME/jsc_deobfuscator"
V8DASM="$HOME/code/v8/v8dasm"
そのファイルを 1 回編集して、インストールパス、一致する V8 逆アセンブラ、ワークスペースディレクトリ、外部コマンド、ログパス、収集レイアウトを設定します。ワークスペースはデフォルトで、ヘルパースクリプトが起動されたディレクトリになります。
すべての値は環境変数でも上書きできます。JSC_HELPER_CONFIG は別の設定ファイルを選択できます。
典型的なバッチ実行は次のとおりです:
scripts/copy_payloads.sh
scripts/unpack_all.sh
scripts/disasm_all.sh
scripts/decompile_all.sh
scripts/deobfuscate_all.sh
scripts/collect_output.sh
スクリプトは、発見された app.jsc ファイルを Brotli 圧縮ペイロードとして扱い、MD5 で命名するなど、JSCeal コーパスで使用される規則を保持します。ワークフローを無関係なサンプルに適用する前に、scripts/README.md を確認してください。
長時間のバッチの場合、scripts/run_unattended.sh は nohup で難読化解除を起動し、タイムスタンプ付きのログ、PID、ステータスファイルを書き込み、キャッシュされた文字列デコーダ関数への未解決の参照がないか、生成された各出力を検証します:
scripts/run_unattended.sh
選択したサンプルを明示的に指定できます:
scripts/run_unattended.sh \
decompiled/sample1.dec.pkl \
decompiled/sample2.dec.pkl
View8/ View8 逆コンパイラおよび関数ツリーエクスポーター
Utils/decompress-jsc.js Windows 用 Brotli 解凍フォールバック
Utils/disasm/v8dasm.cpp V8 逆アセンブラソース
Utils/disasm/patches/ 逆アセンブラに必要な V8 パッチ
Utils/check_unresolved_decoder_references.py
出力検証ヘルパー
deobf_all.py 完全なデフォルト難読化解除パイプライン
deobf_str1.py 単純な文字列インデックスシフトフィルタ
deobf_str2.py インデックス回復付き RC4/Base64 文字列フィルタ
deobf_scope2.py スコープと辞書の伝播
deobf_unflattener.py 制御フローの平坦化解除
deobf_replace_ops.py プロキシと操作ラッパーの置換
deobf_globals.py グローバル伝播
deobf_inline_temporaries.py 控えめな最終クリーンアップ
deobf_ai.py オプションの LLM 支援関数名変更
scripts/ 設定可能なバッチおよび検証ヘルパー
すべての主要なパスは、テスト用に個別に実行できます。選択したスクリプトを --help 付きで実行して、その完全なインターフェースを確認します:
python3 deobf_str1.py --help
python3 deobf_str2.py --help
python3 deobf_scope2.py --help
python3 deobf_unflattener.py --help
python3 deobf_replace_ops.py --help
python3 deobf_globals.py --help
python3 deobf_inline_temporaries.py --help
javascript-obfuscator 出力で観察されたパターンを認識します。新しいバリアントには、追加の検出器または変換が必要になる場合があります。パイプラインは、付随する研究で使用された JSCeal コーパスに対して回帰テストされています。基本的なリリースチェックには以下が含まれます:
python3 -m compileall -q .
python3 deobf_all.py --help
python3 deobf_str2.py --help
python3 deobf_ai.py --help
python3 View8/view8.py --help
各コーパスサンプルについて、実行が以下を満たすことを確認します:
.pkl と .txt の両方の出力を書き出す;無人ヘルパースクリプトは、最終的なデコーダ参照検証を自動化します。
javascript-obfuscator によって生成されたパターンを対象としています。このプロジェクトのために作成された JSC Deobfuscator ソースコードは、GNU General Public License バージョン 2、または(オプションで)それ以降のバージョン(GPL-2.0-or-later)の下でライセンスされています。完全なライセンス文については、LICENSE を参照してください。
Copyright (C) 2026 Aleksandra "Hasherezade" Doniec @ Check Point Research.
View8 サブモジュールは別のプロジェクトです。Utils/disasm/ 配下のサードパーティ由来の逆アセンブラ素材は、既存の来歴を保持し、上記の著作権表示によって再ライセンスされることはありません。