# 攻击者能恢复什么（还原类）

AfterPack 的各项变换所属的静态攻击者类别，以及恢复每一类能让攻击者得到什么。

Source: https://www.afterpack.dev/zh/docs/reversal-classes

AfterPack 把它的各项保护分为几类。每一类以不同的方式提高还原的成本。知道你代码的[某个区域](https://www.afterpack.dev/zh/docs/directives#what-you-can-set)由哪一类覆盖，你就知道攻击者读它时能恢复出什么。[Protection Map](https://www.afterpack.dev/zh/docs/protection-map) 会按复杂度分数为每个词元着色，并标出你所选代码所属的类别。

## 静态攻击者的定义

这些是**静态攻击者**类别。它们描述的是读取字节的人所面对的情况：grep、AST 工具、一遍去混淆器处理，或者一个不运行代码就解释代码的 LLM。在插桩环境下运行产物的攻击者是另一种更强的情形，参见[威胁模型](https://www.afterpack.dev/zh/docs/threat-model)。

*(interactive reversal-classes diagram — see the web page)*

## 各个类别

| 类别 | 静态攻击者能恢复什么 | 层级 |
|---|---|---|
| **重命名与编码**（多项式单射） | 结构，需要花些功夫。名称、字面量、扁平化的控制流和融合的恒等式，都需要真正的模式识别工作。而这项工作在[每次构建](https://www.afterpack.dev/zh/docs/config#seed)上都必须重做一遍。 | Free |
| **扁平化与融合**（多项式非单射） | 一个[行为相同](https://www.afterpack.dev/zh/docs/semantic-contract)的等价程序。逻辑被重写，使多个不同的原始计算坍缩为同一个输出，能映射回你究竟写的是哪一个的线索已经不存在了。目前没有任何已发布的变换能达到这一类别。 | — |

Free 层级在你的整个 bundle 上产生重命名与编码类别（[完整矩阵见套餐与层级](https://www.afterpack.dev/zh/docs/tiers)）。更高的[预设](https://www.afterpack.dev/zh/docs/presets)会在这一类别内部推得更远。默认预设是 `light`（[复杂度目标](https://www.afterpack.dev/zh/docs/config#complexity) `5`）；更强的预设，例如 [`--preset=hard`](https://www.afterpack.dev/zh/docs/config#preset)，推得更远，同时会使整个 bundle 的页面启动时间成倍增加（[加载代价](https://www.afterpack.dev/zh/docs/presets#load-cost)）。从 `medium` 起，引擎会在整个 bundle 上统一加入控制流扁平化、恒等式融合和[常量破坏](https://www.afterpack.dev/zh/docs/config#strings-encode)，这些都在重命名与编码类别之内。

> **目前不会产生扁平化与融合和破坏与融合类别**
>
> 没有任何构建会达到它们，也从来没有任何区域被归为“扁平化与融合”或“破坏与融合”。[`/* @afterpack preset=extreme */`](https://www.afterpack.dev/zh/docs/config#preset) 会把一个区域提升到[复杂度目标](https://www.afterpack.dev/zh/docs/config#complexity) `25` 并开启[字符串下限](https://www.afterpack.dev/zh/docs/config#strings-encode)，这是重命名与编码类别内部真实、可衡量的保护。

## 恢复一个类别能让攻击者得到什么

一个类别能让攻击者得到什么，取决于他们的目标是什么。

- **一个密钥**（API 密钥、许可证阈值、硬编码的表）：两个类别本身都无法隐藏它。任何与你的程序行为相同的程序都会暴露出密钥，包括从受保护区域恢复出的程序。保护密钥需要另一种机制。参见[保护密钥](https://www.afterpack.dev/zh/docs/threat-model#protecting-a-secret)。
- **理解并克隆你的代码**：静态阅读者可以恢复出一个可运行、可读的等价程序，但前提是完成重命名与编码类别所要求的真正的模式识别工作，而这项工作每次构建都必须重做。这一特性的局限参见 [AfterPack 不能替代什么](https://www.afterpack.dev/zh/docs/threat-model#what-afterpack-does-not-replace)。
- **定位并修补一处校验**（关掉付费墙、把某个 `return true` 翻转）：这两个类别单独都帮不上太多忙。攻击者只需要找到那一个节点。重新找到它要付出一些代价，而这份代价会[在每次发布时重置](https://www.afterpack.dev/zh/docs/config#seed)。自完整性检查（[`transforms.selfIntegrity.enabled`](https://www.afterpack.dev/zh/docs/config#transforms-kind-enabled)）拦不住这种修补：它只检测对它自身校验表的修改。关于轮换，参见[最佳实践](https://www.afterpack.dev/zh/docs/best-practices)。

## 在你自己的构建上验证

[Protection Map](https://www.afterpack.dev/zh/docs/protection-map) 展示逐词元的证据：你的原始源代码，按每个词元的复杂度分数着色，悬停时还能看到它所属的类别以及其背后的变换栈。[打开在线演示](https://www.afterpack.dev/protection-map-demo)，或者用 [`npx afterpack@latest`](https://www.afterpack.dev/zh/docs/cli#usage) 生成你自己的。

## 下一步

- [威胁模型](https://www.afterpack.dev/zh/docs/threat-model)：这些类别所针对的对手阶梯。
- [Protection Map](https://www.afterpack.dev/zh/docs/protection-map)：你自己构建的逐词元视图。
- [最佳实践](https://www.afterpack.dev/zh/docs/best-practices)：该标记什么，以及为什么。
- [指令](https://www.afterpack.dev/zh/docs/directives)：让某个区域在类别之间移动的标记。
- [预设](https://www.afterpack.dev/zh/docs/presets)：阶梯，以及每一级设定的复杂度目标。
