# 使用手册 命令行速查,配合 `README.md` 一起看。 --- ## 0. 先自检 ```sh swcenc doctor ``` ``` swcenc 环境自检 ================================================================== 引擎根目录 : /opt/swcenc/engine Python : 3.12.3 (/usr/bin/python3) PHP 搜索路径: /www/server/php:/usr/local/php:/opt/php:/opt ── 本机 PHP 工具链 ── ✅ PHP 8.3 /www/server/php/83/bin/php opcache no-debug-non-zts-20230831 ... ── 各 (loader, PHP) 组合可用性 ── PHP 3.1 3.2 ----- -------------------------- -------------------------- 8.3 — 官方无此 loader ✅ strong ``` `✅ strong` 表示这个组合能做字节码加密;`⚠️ 仅 weak` 表示本机缺 opcache。 --- ## 1. 单文件 ```sh swcenc pack <输入.php> -o <输出.php> [选项] ``` ```sh # 最常见:PHP 8.3 + loader 3.2 + 加固 + 验证 swcenc pack app/common.php -o out/common.php \ --php 8.3 --loader-version 3.2 --swc-strict --verify # 老站:PHP 7.2 + loader 3.1 swcenc pack app/common.php -o out/common.php --php 7.2 --loader-version 3.1 --verify # Pro 产物 swcenc pack app/common.php -o out/common.php --php 8.3 --pro --verify ``` > 输出文件建议**不要**覆盖原文件。产物已经不可读,覆盖后想改也改不回来。 --- ## 2. 整目录 ```sh swcenc batch ./app -o ./app_enc --php 8.3 --loader-version 3.2 --verify -j 8 ``` * 保持相对路径:`./app/a/b.php` → `./app_enc/a/b.php` * `-j` 是并发数,按 CPU 核数调。`--verify` 会让每个文件都跑一次 PHP,比较慢。 * 目录里的 `vendor/`、`runtime/` 会被跳过(第三方库没必要加密,且体量大)。 **一个站要上多套环境**时,按 (loader, PHP) 组合各跑一次: ```sh for v in 7.4 8.0 8.1 8.2 8.3; do swcenc batch ./app -o ./dist/php$v --php $v --loader-version 3.2 --swc-strict done ``` 每个组合的产物**只认那一个 PHP 版本**,不能混用。 --- ## 3. 查看与解包 ```sh swcenc info out/common.php ``` ``` 文件 : out/common.php 大小 : 12552 B PHP : 7.3 loader : 3.2 模式 : strong 弱加密标记: 否 载荷 A : 11420 B 载荷 B : 0 B Pro 层 : 是 / 否 ``` ```sh swcenc unpack out/common.php -o payload.bin # 解出载荷(strong 模式下是字节码) ``` `unpack` 只是把容器拆开,不做反编译。strong 载荷是 op_array 字节码,需要 额外的解析工具才能读。 --- ## 4. 矩阵与能力 ```sh swcenc versions # loader 3.1 / 3.2 × PHP 支持矩阵(看本机文件) swcenc caps # 各版本能力分层(JSON,含实测探测结果) swcenc caps --refresh # 重新实测一遍并更新缓存 ``` --- ## 5. 速度:哪种配置快 实测语料:**真实 66 文件 PHP 工程(1.1 MB)**,PHP 8.3 / loader 3.2,40 核机器。 表里是 `batch` 跑完整目录的墙钟时间(取最快一次)。 | 配置 | 总耗时 | 每文件 | 相对默认 | |---|---|---|---| | `--mode weak` | **0.9 s** | 0.014 s | 5.9× 快 | | `strong`(默认,不加固) | **2.4 s** | 0.036 s | 1.0×(基准) | | `strong --swc-strict --verify` | 32.5 s | 0.49 s | 13.8× 慢 | | `strong --swc-strict` | 33.0 s | 0.50 s | 14.0× 慢 | | `strong --swc-strict --swc-calibrate` | 33.9 s | 0.51 s | 14.4× 慢 | | `strong --swc-strict --pro` | 36.8 s | 0.56 s | 15.6× 慢 | | `strong --swc-strict --pro --verify` | 35.8 s | 0.54 s | 15.2× 慢 | | `strong --swc-strict --swc-encode-ops` | **67.2 s** | 1.02 s | 28.6× 慢 | 结论: * **`weak` 最快**,比 `strong` 快约 6 倍 —— 它不做字节码编译,纯 Python 拼容器。 代价是载荷就是源码,只有形式上的保护。 * **加固层(`--swc-strict`)是真正的开销大头**,约 14 倍。 它要做 opdump 转储 + CV 名洗白 + 逐文件探针验证,值不值看你自己的威胁模型。 * `--pro` 在加固之上只多约 10%(置换 + 掩码是纯查表,很便宜)。 * **`--verify` 几乎是免费的** —— 加固通路本来就每文件跑一次探针, 多执行一次产物几乎不增加时间。**强烈建议开**。 * `--swc-encode-ops` 再翻一倍,是因为它要重写整个 opcode 表。 ### 并行度:两种通路的最优值是**相反**的 | | `-j 1` | `-j 2` | `-j 4` | `-j 8` | |---|---|---|---|---| | `strong`(不加固) | 5.15 s | 3.22 s | 2.34 s | **1.81 s** | | `strong --swc-strict` | **26.3 s** | 31.0 s | 31.8 s | 33.7 s | 原因:`strong` 的耗时几乎全在**等 PHP 子进程**(opcache 编译),线程能重叠这段等待; 而加固通路的耗时是**纯 Python 字节操作**,被 GIL 串行化,多开线程只剩上下文切换开销。 所以 `batch` 的 `-j` 默认是**自动**的: * 普通加密 → `min(8, CPU 核数)` * 加固通路(`--swc-strict` / `--pro` / `--swc-encode-ops` / `--swc-calibrate`)→ `1` 显式给 `-j N` 时一律听你的。**如果你在跑加固,别手动加 `-j`**,默认的 1 就是最快的。 ### 单文件固定开销 每个文件都有一次 Python + PHP 启动成本,小文件尤其明显: | | 每次耗时(913 B 小文件) | |---|---| | `--mode weak` | 0.159 s | | `strong` | 0.240 s | 所以**批量走 `batch`,不要循环调用 `pack`**:66 个文件循环调用要 34.9 s, `batch` 只要 2.4 s(strong)。 --- ## 6. 加固选项怎么选 | 场景 | 建议 | |---|---| | 一般交付 | `--swc-strict --verify` | | 要跟官方 swc 产物观感一致 | 再加 `--swc-calibrate`(慢) | | 只想先跑通 | 什么都不加,先确认产物能起来 | | 要更强的逆向门槛 | 加 `--pro`,同时把目标机的 loader 换成 Pro 版 | | `--swc-encode-ops` | ⚠ **目前无效,别指望它**(见下) | | `--swc-repoint` | ⚠ 实验性,默认关闭 | ### ⚠ `--swc-encode-ops` 当前是空操作 这一层(编码态 op + 函数名字面量加密)**目前一个 op 都编不上**,实测 66 文件 真实项目:编码 0 个。原因有两层: 1. 实测表 `pack/newgen_.json` 里的 `encoded` 条目只有 **5–13 条**, 而真实调用序列还需要 `SEND_VAR` / `DO_FCALL` 等形状 —— 序列永远配不平, 于是调用序列门禁(`newgen72.sequence_gate`)放行 0 个; 2. 即便按正版规则「表里有就编」,实测产物会 **SIGSEGV**,差异所在的最后一层 尚未定位。所以门禁是**故意**不编的:宁可不生效,也不产出会崩的产物。 **开着不会出错,但不要把它算作一层保护。** 工具在收尾时会明确告诉你 "本次 `--swc-encode-ops` 没有生效",不会让你误以为多了一层。 要真实强度请用 `--swc-strict` + `--pro`。 ### ⚠ `--swc-repoint` 是实验特性 字面量槽重定位加密函数名:机制单独验证过,但与「去掉名字门禁」组合时大文件 未通过自检,因此**默认关闭**。不确定就不要开。 --- ## 7. 一条完整的发布流程 ```sh set -e SRC=./app OUT=./dist PHP=8.3 LV=3.2 # 1) 自检 swcenc doctor # 2) 加密(加固 + 验证) swcenc batch "$SRC" -o "$OUT/php$PHP" \ --php "$PHP" --loader-version "$LV" \ --swc-strict --verify -j 8 # 3) 抽查一个产物信息 swcenc info "$OUT/php$PHP/index.php" # 4) 在目标机上装对应 loader(不要装错代次 / 版本) # php.ini: extension=swoole_loader${PHP/./}_nts.so # 然后重启 PHP-FPM # 5) Pro 产物额外确认 php.ini 里有: # swoole_loader_pro.enable_vm_hybrid=1 ``` --- ## 8. 常见问答 **Q:加密后能不能改源码?** 不能。改源码必须改明文再重新加密。 **Q:能不能一个产物跑多个 PHP 版本?** 不能,Swoole 是单版本加密。要支持 5 个 PHP 版本就出 5 份。 **Q:目标机需要装什么?** 只要对应版本的 loader 扩展。 **Q:产物会不会回连某个服务器?** 不会。本工具完全离线,不做域名/IP 绑定、不联网校验。 **Q:`--verify` 安全吗?** 它会**真的执行**被加密的文件(用 loader 加载并运行)。只对你自己的、可信的 源码使用;不要拿它验证来路不明的文件。 **Q:产物比源码大还是小?** 通常更大 —— 字节码载荷里有常量表、字面量和元信息,加固层还要再叠数据。 这是正常的。 **Q:报"源码语法检查失败"?** 源码在**目标 PHP 版本**下语法不合法。常见:7.x 用了类型化属性(要 7.4+)、 `match`(要 8.0+)、`new ('...')`(要 8.0+)。换 `--php` 或改源码。 --- ## 2.0 新增:授权、产物绑定、自带运行时 ### 授权 ```sh swcenc machine # 本机机器码 → 发给签发者 swcenc license # 查看授权(客户名 / 版本 / 有效期 / 功能位) swcenc pack a.php -o a.enc.php --license /path/to/license.json ``` 没有有效授权时 `pack` / `batch` 会直接退出(退出码 3),并在 stderr 说明原因 (未找到 / 签名不匹配 / 已过期 / 机器码不匹配)。 ### Windows 版能做什么、不能做什么 | 能力 | Linux | Windows | |---|---|---| | `pack` / `batch` / `info` / `machine` / `license` / `doctor` | ✅ | ✅ | | `--verify`(用真实 loader 跑一遍产物) | ✅ | ❌ loader 是 Linux 扩展,Windows 的 PHP 加载不了 | | 产物绑定(域名 / IP / 到期) | ✅ | ✅ 一样 | | `--pro` / `--swc-strict`(加固层) | ✅ 全部 PHP 版本 | ⚠ **只支持 PHP 7.0 / 7.1**(7.2+ 需要 Linux 专有的转储扩展) | 所以:**在 Windows 上出普通 `strong` 产物完全没问题**(绑定、授权、多版本都正常); 要出加固/Pro 产物、或者要逐文件 `--verify`,请到 Linux 上打包 —— 那边的组合是完整的。 ### 产物绑定 ```sh # 只允许 customer.com 及其子域运行,2027-01-01 到期 swcenc batch ./app -o ./app_enc --php 8.3 \ --domains "customer.com,*.customer.com" --expire 2027-01-01 # 再加来访 IP 白名单 swcenc pack app.php -o app.enc.php --php 8.3 --ips "1.2.3.4,10.0.0.0/8" # 连 CLI 一起绑域名(默认只绑 Web,避免客户 cron 挂掉) swcenc pack app.php -o app.enc.php --php 8.3 --domains "a.com" --bind-cli ``` 命中不允许的环境时: ``` $ php app.enc.php This script is not licensed to run here (host evil.com). # Web 上是 403 ``` ### 自带运行时 ```sh swcenc doctor | head -12 # 看「内置运行时」那一行 ``` 发行包自带 PHP 7.0–8.4 与 Python;`SWCENC_PHP_ROOT` / `SWC_PHP_ROOT` 可以指向 系统里别的 PHP(例如客户机上已经装了他自己那套): ```sh SWC_PHP_ROOT=/www/server/php swcenc doctor ```