# AfterPack 与其他 JavaScript 混淆器的对比

AfterPack 与 javascript-obfuscator、js-confuser、JScrambler、JSDefender 和 ByteHide 在构建耗时、输出体积以及输出是否仍能运行方面的对比，在同一套测试框架上测得。

Source: https://www.afterpack.dev/zh/docs/comparison

每个混淆器都声称能抵御逆向工程。真正重要的是，在去混淆器或前沿模型处理过输出之后，[还剩下什么是可读的](https://www.afterpack.dev/zh/docs/reversal-classes)，以及这份保护在构建耗时和体积上的代价。

我们在自己的测试框架上把 javascript-obfuscator、js-confuser 和 ByteHide 与 AfterPack 放在一起运行，并在此处和首页公布结果；参见[测量方法](#how-we-measured)。JSDefender 和 JScrambler 不在本次测试中，仅依据厂商文档描述。AfterPack 自身的独立数据见[性能](https://www.afterpack.dev/zh/docs/performance)。

## 去混淆处理后还剩下什么

在一次公开测试中，一个编码智能体在大约十分钟内把 `javascript-obfuscator` 和一款商业工具（JScrambler）的输出都还原成了可读的逻辑（[完整过程见我们的博客](https://www.afterpack.dev/zh/blog/ai-deobfuscates-javascript)）。固定的输出形态让这件事变得廉价：字符串数组（即便是加密的）、自定义 VM 解释器，或自我重定义的解码器引导代码。`webcrack` 和 `restringer` 为这些形态硬编码了识别器，几微秒就能剥除；前沿模型用一段提示词代替解析器，做的是同样的事。

每次 AfterPack 构建的形态都不同，所以针对某次构建的模式编写的工具，到下一次就会失效。运行你代码的人仍然可以读到它使用的值：在引擎 0.2.2 上，一个 15 行的运行时钩子在每个预设下都还原出了 97 个埋入字符串中的 96 个。[威胁模型](https://www.afterpack.dev/zh/docs/threat-model#measured-results)列出了每类攻击者能还原什么。

*(animated fixed-pipeline vs per-build-shape comparison — see the web page)*

## 功能对比

与首页对比相同的六家厂商和七行，顺序也相同。

> **这些行的数据来源**
>
> 前三行是在我们自己的测试框架上测得的——参见下文的[测量方法](#how-we-measured)。
> 其余各行中 AfterPack 那一列来自我们自己的文档和已发布的产品。其他各列
> 都是该厂商公布的内容；厂商没有公布任何信息的地方，单元格会如实注明。

| 功能 | AfterPack (0.2.6) | javascript-obfuscator (5.6.0) | js-confuser (2.1.3) | JSDefender | ByteHide (1.0.5) | JScrambler |
|---|---|---|---|---|---|---|
| [构建耗时](#how-we-measured) | `extreme` 下 2.1 s | `medium` 下 4.7 s（长 2.3 倍） | `high` 下 8.8 s（长 4.2 倍） | 未测试 | 未在 bundle 上测试 | 未测试 |
| 输出体积，gzip 后 | `extreme` 下为压缩后 bundle 的 10.5 倍（8.25 至 11.19 倍） | 11.0 倍 | 12.1 倍（单次未设种子的抽样） | 未测试 | 未在 bundle 上测试 | 未测试 |
| [仍能运行的最强预设](#how-we-measured) | `extreme`（最高预设，5/5） | `medium`（`high` 在无头 CI 中挂起，0/5） | `high`（最高预设，5/5） | 未测试 | 默认（全部开关打开：0/5） | 未测试 |
| [价格与免费层级](https://www.afterpack.dev/zh/docs/tiers) | 免费，本地不限量——付费版 $49/月起 | 免费，开源——VM 附加组件 $19/月 | 免费，开源 | 仅限询价 | 预约演示 | 仅限询价 |
| 框架插件 | 13 个官方插件 | 社区加载器 | 仅 Node API | 未找到 | 插件，厂商自述 | CLI + API |
| 可在边缘运行 | 是——WASM + Workers | 未见文档 | 未见文档 | 未见文档 | 未见文档 | 未见文档 |
| 符合 CSP 的输出（无 `eval`、无 `new Function`） | 是，默认如此 | 未见文档 | 未见文档 | 未见文档 | 未见文档 | 未见文档 |

## 测量方法

机器：一台 Apple M2 Max，Node 24.21.0。下面每个实测数字都来自 2026 年 10 月 16 日在 AfterPack 引擎 0.2.6 上的同一次测试运行，可用相同输入复现。构建耗时会随机器负载浮动，体积不会。

**构建耗时与输出体积。**五个真实的、已压缩的生产 bundle，端到端运行，按墙钟计时，取每个 bundle 的中位数；体积是 gzip 后的输出与 gzip 后的压缩输入之比。AfterPack 和 js-confuser 使用各自的最高预设（`extreme` 和 `high`）。javascript-obfuscator 的最高预设 `high-obfuscation` 会启用反调试器，在无头或 CI 环境中挂起，因此改用 `medium-obfuscation`，即其输出仍能运行完成的最强预设。

**仍能运行的最强预设。**五个可执行程序，先保护再在无头 CI 中运行。AfterPack 和 js-confuser 在最高预设下 5/5 通过；javascript-obfuscator 在 `high` 下为 0/5（即上文的反调试器），在 `medium` 下为 5/5，表中报告的是后者。

**AfterPack 更轻的预设**在相同 bundle 上：默认的 `light` 为 1.36 倍、0.19 s；`medium` 为 7.26 倍、0.82 s；`hard` 为 8.20 倍、1.12 s。

**ByteHide。**ByteHide 没有预设等级，只有开关，因此它在五个程序上运行了两次：一次用默认设置，一次打开所有保护开关。默认设置下五个程序全部正常；打开所有开关后，五个都无法运行。它没有在生产 bundle 上运行，因此没有构建耗时和体积数据。

**JSDefender 与 JScrambler。**两者都不在本次测试中，因此都没有实测数据。JScrambler 的免费套餐只做标识符重命名和压缩，其混淆变换需要付费套餐。它们的价格、插件、边缘和 CSP 各行来自公开文档，JScrambler 的去混淆说明来自一个公开的 JScrambler 去混淆器（见[与 JScrambler 对比](#vs-jscrambler)）。

## 与 javascript-obfuscator 对比

大多数团队首先会选用的免费开源默认方案，也是 `webcrack` 所针对编写的工具。它的输出是一条固定的流程：字符串数组、旋转解码器引导代码，以及带有可识别 switch 形态的控制流扁平化——这些曾经是障碍，如今成了特征。

- 核心用 Rust 编写，以原生二进制或 WebAssembly 形式发布，而不是 JavaScript 库。在我们的测试框架上（[测量方法](#how-we-measured)），AfterPack 在 `extreme` 下保护一个真实生产 bundle 的中位耗时为 2.1 s，javascript-obfuscator 在 `medium` 下为 4.7 s，gzip 后体积相近：10.5 倍对 11.0 倍。
- 它的输出在每次构建中形态相同，这正是 `webcrack` 依赖的特征。AfterPack 的形态每次构建都会改变。

两者都免费；[AfterPack](https://www.afterpack.dev/zh/docs/tiers) 还提供不限次数的构建，且无需信用卡。

## 与 js-confuser 对比

一个较新的开源替代品，同样免费（MIT）。在我们的测试框架上（[测量方法](#how-we-measured)），同样的 bundle 在其最高预设（`high`）下输出为压缩后体积的 12.1 倍，中位构建耗时 8.8 s，约为 AfterPack 在 `extreme` 下的四倍。在该预设下，五个可执行程序都仍能正确运行。

- js-confuser 的文档中没有种子选项，因此输出在不同构建之间并不确定：同一个输入每次运行都可能产生不同的字节。
- 有公开的分析文章记录了如何恢复 js-confuser 的原始逻辑；我们自己没有复现过。

## 与 JScrambler 对比

老牌商业产品，需要经过销售沟通并签订企业合同才能用上。它的基础层级输出的结构可以通过模式识别出来。

JScrambler 的文档声称其保护默认是多态的，对同一输入保护两次不会产生相同的输出。文档中还提供了一个随机化种子，用于精确复现某一次保护。

一个公开的开源 JScrambler 去混淆器会根据结构来识别 JScrambler 注入的各个部分：全局对象解析器、字符串解码器、控制流状态机以及名称别名设置。它会从每个文件中读出密钥和常量。它的样本来自互不相关的网站，却共享同样的注入前导代码，因此即使名称、密钥和常量都会变化，同一个识别器仍然能跨构建、跨客户沿用。

- 公开的自助价格（Indie $49/月），而不是需要经过销售才能签的合同。
- [Free 层级](https://www.afterpack.dev/zh/docs/tiers)在原始能力上胜过大多数商业产品的入门层级，而且无需账户。
- [Enterprise](https://www.afterpack.dev/zh/docs/enterprise) 面向不能把源代码发送给第三方 API 的团队。零外发的选项是[免费的本地构建](https://www.afterpack.dev/zh/docs/deployment-modes)。

## 与 JSDefender 对比

PreEmptive 的商业 JavaScript 保护产品。引擎和 CLI 不在公共 npm 上：它们需要从一个需要认证的账户门户下载，而且每次运行都要通过网络检查许可证，因此构建无法离线运行，许可证过期后也无法运行。许可证是浮动许可证，对并发构建数有限制。

它的流程是一组固定的十三种代码变换，每种都可以单独开关。其中两种默认开启：把字符串字面量提取到一张编码表中，以及对声明的变量和函数重命名。其余的涵盖控制流扁平化、布尔和整数字面量编码、属性间接访问、表达式序列化、函数重排和变量分组。另有单独的选项用于添加环境锁：自我防御的完整性检查、开发者工具屏蔽、控制台隐藏、域名锁和日期锁。JSDefender 的运行时会被注入到受保护的产物中，而公开的去混淆器正是利用了这一点：有三个开源工具通过运行与受保护代码一同发布的解码器来恢复原始逻辑。

输出不是多态的。每次构建的流程都相同，而且 `randomSeed` 选项会让给定种子下的输出逐字节稳定，因此针对某个版本编写的识别器仍然能匹配下一个版本。

它不在我们当前的测试运行中，因此本页没有它的实测数据。

AfterPack 无法保护的文件会[让构建失败](https://www.afterpack.dev/zh/docs/diagnostics)，而不是被发布出去。

## 与 ByteHide 对比

一项云端保护服务。它的 CLI 和打包工具插件会把每个文件发送到 ByteHide 的服务器，再把返回的内容写回，因此它的构建耗时包含网络往返。

它背后的引擎看起来就是 javascript-obfuscator：它的选项名称和校验消息都是 javascript-obfuscator 自己的，而且在相同选项和种子下，去掉 ByteHide 额外的数字包装步骤之后，其输出与 javascript-obfuscator 4.x 一致。它具有同样的固定形态：在打开所有保护开关的情况下，我们做出的每一次构建中预埋的密钥都被 `webcrack` 恢复了出来，而默认的字符串编码只是用一个密钥字节对每个字符串做 XOR。

在我们的测试框架上（[测量方法](#how-we-measured)），它的默认设置让五个程序全部正常运行；打开所有保护开关后，五个都无法运行。

- [AfterPack 的免费层级](https://www.afterpack.dev/zh/docs/tiers)完全在你的机器上运行，不计量，无需账户、无需绑卡，也无需预约演示。
- 把源代码发送到任何云端构建步骤——包括 ByteHide——正是 [Enterprise](https://www.afterpack.dev/zh/docs/enterprise) 和[免费的本地构建](https://www.afterpack.dev/zh/docs/deployment-modes)存在所要避免的取舍。

## 与 Terser 对比

Terser 属于另一类工具：它做的是压缩，能很好地缩短名称、折叠常量表达式。压缩后的代码保留了全部原始逻辑，因此对阅读结果的 LLM 毫无抵抗力。先运行 Terser，再对它的输出运行 AfterPack。AfterPack 不能替代压缩器：即使是它不做任何混淆的 [`minify` 预设](https://www.afterpack.dev/zh/docs/presets#the-ladder)，也会让一个已经压缩过的 bundle 变大。

## 静态攻击者能恢复什么

| 工具 | 静态阅读者能恢复什么 |
|---|---|
| 仅压缩 | 一切。前沿 LLM 解释压缩代码与解释格式化代码几乎一样容易，因为只有名称变了。 |
| javascript-obfuscator | 实际上是一切。固定流程的输出意味着 `webcrack` 几秒钟就能将其逆向。 |
| js-confuser | 有公开的分析文章记录了如何恢复其原始逻辑；我们自己没有复现过。 |
| JScrambler（基础层级） | 真实存在、但可通过模式识别的结构。 |
| JSDefender | 实际上是一切。解码器随产物一起发布，因此公开工具可以运行它并把原始逻辑打印出来。 |
| ByteHide | 实际上是一切。输出具有 javascript-obfuscator 的固定形态，因此 `webcrack` 能恢复它，而默认的字符串编码只是单字节 XOR。 |
| **AfterPack Free** | 一个[行为相同](https://www.afterpack.dev/zh/docs/semantic-contract)的等价程序。名称在每个预设下都会被重命名，字符串从 `light` 起会被[编码](https://www.afterpack.dev/zh/docs/reversal-classes)；在 `light` 下数字仍然可读。模式工具得到的不比 grep 多，而静态求值仍能还原大部分字符串（[实测](https://www.afterpack.dev/zh/docs/threat-model#measured-results)）。下一次构建的形态不同。 |
| **[AfterPack Pro](https://www.afterpack.dev/zh/docs/pro)**（[标记的区域](https://www.afterpack.dev/zh/docs/directives#what-you-can-set)） | 一个[行为相同](https://www.afterpack.dev/zh/docs/semantic-contract)的等价程序：与 Free 相同的变换，在你标记的区域上使用更重的预设。 |

完整的类别定义见[还原类](https://www.afterpack.dev/zh/docs/reversal-classes)和 [AfterPack 的工作原理](https://www.afterpack.dev/zh/docs/concepts#what-an-attacker-can-actually-recover)。用 [Protection Map](https://www.afterpack.dev/zh/docs/protection-map) 验证你自己的构建。

## 本对比的范围

[只要时间足够，任何混淆器的输出都可以被逆向](https://www.afterpack.dev/zh/docs/threat-model#what-obfuscation-protects)，包括 AfterPack 的。面对固定流程的工具，一次写好的识别器对每次构建都有效。面对 AfterPack，基于某次构建形态做的工具到下一次要重做，而运行时钩子对每次构建都有效。

## 下一步

- [AfterPack 的工作原理](https://www.afterpack.dev/zh/docs/concepts)：完整解释还原类以及密钥如何留存。
- [层级](https://www.afterpack.dev/zh/docs/tiers)：Free/Pro 的边界，以及精准的 Pro 变换在哪里生效。
- [威胁模型](https://www.afterpack.dev/zh/docs/threat-model)：上述每一项说法所针对的对手阶梯。
- [审计](https://www.afterpack.dev/zh/docs/audit)：扫描任何线上网站（你自己的或竞争对手的），看看它目前泄露了什么。
