该工具致力于对使用 javascript-obfuscator 保护的已编译 V8 JavaScript 字节码进行静态反混淆。
它作用于 View8 生成的伪代码,而非原始 JavaScript 源码。该项目针对 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
默认字符串过滤器为变体 2,用于大多数已分析的 JSCeal 载荷。要显式选择更简单的字符串方案,请添加:
--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 可包含所有可见的函数引用,包括回调和分配的处理程序。
生成的两列 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 并指定精确的完整函数标识符,请求对一个反混淆函数进行聚焦的语义分析:
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。模糊匹配仅作为建议打印;请求的函数标识符必须精确匹配。
使用 --help 查看控制温度、批处理、Anthropic 思考模式、令牌限制和自定义 CSV 路径的选项。
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 并解码字符串。无需第二次运行。
当直接使用 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/ 下包含完整的辅助工作流。所有脚本都放在同一目录中,并引用相同的集中配置。
scripts/config.sh 共享工具和工作区路径
scripts/copy_payloads.sh 收集并按 MD5 命名 JSCeal app.jsc 文件
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"
编辑该文件一次,以配置安装路径、匹配的 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
这些脚本保留了 JSCeal 语料库使用的约定,包括将发现的 app.jsc 文件视为 Brotli 压缩载荷并按 MD5 命名。在将工作流应用于无关样本之前,请先查看 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 反混淆器源代码根据 GNU 通用公共许可证第 2 版或(由您选择)任何更高版本(GPL-2.0-or-later)授权。完整许可证文本见 LICENSE。
版权所有 (C) 2026 Aleksandra "Hasherezade" Doniec @ Check Point Research。
View8 子模块是独立项目。Utils/disasm/ 下源自第三方的反汇编器材料保留其原有出处,不受上述版权声明重新授权。