diff --git a/docs/README.md b/docs/README.md index 3f64b66..f48f3c2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -78,3 +78,4 @@ Shellsmith 是 Android 与 iOS 双平台应用加固工具。Android 流程加 - [BYOS HTTPS 密钥服务](design/byos-key-server.md):用户自建服务所需信息、接口与联调要求。 - [BYOS 密钥服务端参考实现](design/byos-key-server-reference.md):Go/PostgreSQL 参考实现、KMS/HSM 后端、部署和运维手册。 +- [2026-10-23 XopProtector 分支差异审计](process/2026-10-23-xop-diff-audit.md):本地分支与 origin/main 的基线、冲突面和逐项裁决。 diff --git a/docs/process/2026-10-23-xop-diff-audit.md b/docs/process/2026-10-23-xop-diff-audit.md new file mode 100644 index 0000000..d2de416 --- /dev/null +++ b/docs/process/2026-10-23-xop-diff-audit.md @@ -0,0 +1,72 @@ +# XopProtector 分支差异审计(2026-10-23) + +**状态:** 仅审计,不合并、不改代码、不删除上游目录。本文记录本地分支与 `origin/main` 的真实基线、冲突面和逐项裁决,供后续决定「合入、上游 PR 或归档」。 + +## 基线 + +| 项目 | 值 | +|---|---| +| 本地 `HEAD` | `e408b87`(2026-09-19,`增强PVM2 / 支付 True-VMP,适配Android16,增强SO 保护`) | +| `origin/main` | `4a41d0b`(2026-10-20,合并 shadowhook 2.0.1) | +| 本地与远端关系 | 本地 `main` 落后 `origin/main` 5 个提交 | +| `e408b87..origin/main` | 36 个文件,`+5657 / -692` | +| 本地未提交工作区 | 22 个文件,`+1614 / -237` | + +## 远端 5 个提交的主题 + +```text +4a41d0b Merge pull request #21 from ouchangxin/feature/upgrade_shadowhook_2.0.1 +08f940f 升级shadowhook框架版本到2.0.1 +3cefb55 SO 加载策略调整(L2e 为主),Dobby ARM64 重定位增强,16KB 页对齐 +5990c31 更新版本为0.7.2 +7b18e91 修改SO冷启动策略,避免 attach 全表 RC4 和体积误判 L2e +``` + +主要改动集中在 SO 保护与加载链路:`business_so.cpp`、`BusinessSoProtector.java`、Dobby ARM64、`elf_util`、`NativeLibDirRedirect`、`p4-so-ab-matrix.ps1`。这不是一条 PVM2 格式升级线。 + +## 本地未提交 diff 的冲突面 + +本地未提交的 22 个文件里,与 `origin/main` 已改动文件重叠、不能直接 rebase 的至少有: + +- `build.gradle.kts` +- `native/src/main/cpp/dex/dex_file.cpp` +- `native/src/main/cpp/vm/pvm2_format.cpp` +- `native/src/main/cpp/vm/pvm2_format.h` +- `packer/.../BusinessSoProtector.java` +- `packer/.../PackerMain.java` +- `packer/.../TrueVmpTrampoline.java` +- `packer/.../elf/ReadElf.java` + +其余本地改动(`AssetsEncryptor`、`AutoVmpPolicy`、`Pvm2Compiler`、`Pvm2Morph`、`Pvm2Opcodes`、`ResPathObfuscator`、测试和 `settings.gradle.kts`)需要逐项对照,不能按「22 个文件整体 rebase」处理。 + +## 逐项裁决 + +| 项目 | 事实 | 裁决 | +|---|---|---| +| 本地 PVM2 v6 | 本地 `pvm2_format.h` 在 V5 后新增 V6;`origin/main` 只到 V5;`third_party/xopprotector` 已支持 V6–V9 | **先做语义对照**:把本地 v6 的寄存器置换、10 字节 handler、三变体 dispatch 与 third_party 的 v6–v9 逐项比较。若只是重复实现,丢弃并在 third_party 补齐仍缺的 dispatch 密钥流;不要先假定是独有能力 | +| `find_class_desc` contextClassLoader | `third_party` 已有 `forName` + `contextClassLoader`,并用 `string_from_utf8` 处理 MUTF-8;本地仍用 `NewStringUTF` | **丢弃本地这条**。third_party 已领先,不存在「third_party 未必有」的问题 | +| `dex_file.cpp` SHA-1 溢出 | `origin/main` 仍是 `size_t bit_len`;本地改为 `uint64_t`,修复 32 位 ABI 下 `len * 8` 溢出;`third_party/xopprotector` 未 vendoring `dex/`,该文件不参与 Shellsmith 主线编译 | **保留为独立上游 PR**,只回 Xop 独立壳线;不要合入 third_party(没有目标文件),也不要把它算作 Shellsmith 主线修复 | +| `build.gradle.kts` 的 `exportShellFiles` | `origin/main` 已对 `build.gradle.kts` 做了 143 行改动 | rebase 后对照远端实现;仅在本地版本确实更稳健且不冲突时保留,否则丢弃 | +| `TrueVmpTrampoline` / `ReadElf` / `PackerMain` / `BusinessSoProtector` | 本地与远端同时改动,语义需要逐段比对 | 按「SO 加载」「True-VMP」「DEX/ELF 读取」拆成独立改动,不整体合并 | +| PVM2 v6 与 third_party v9 的关系 | third_party 是 Shellsmith 的独立演进线,V9 已包含 V6–V8 能力 | 不能把 Xop 本地 v6 当作 third_party 的升级来源;只把 third_party 缺失的语义作为候选 | + +## 不做什么 + +- 不直接 `git rebase` 22 个未提交文件;先 `git fetch`,以 `origin/main` 为基线重新评估。 +- 不把 `origin/main` 的 SO 保护改动与本地 PVM2 v6 改动混成一个提交。 +- 不把 `dex_file.cpp` 的 SHA-1 修复合入 `third_party/xopprotector`;该目录没有 `dex/`,Shellsmith 主线也不编译它。 +- 不在 diff 审计完成前删除或归档 `XopProtector`;本地 HEAD 落后 5 个提交,当前比较基线不是最新上游。 + +## 下一步 + +1. `git fetch origin`,确认 `origin/main` 仍为 `4a41d0b` 或更新;以最新远端为基线重跑 diff。 +2. 先处理 `dex_file.cpp` 的 SHA-1 修复:独立分支、独立 PR、仅回 Xop 上游。 +3. 对本地 PVM2 v6 与 third_party v6–v9 做语义对照,输出「重复 / 缺失 / 冲突」三列清单。 +4. 对 `build.gradle.kts`、`TrueVmpTrampoline`、`ReadElf`、`PackerMain`、`BusinessSoProtector` 逐文件裁决。 +5. 全部裁决完成后,再决定 Xop 目录是归档、保留为支付 True-VMP 实验线,还是只保留上游 PR。 + +## 关联 + +- [第三方 PVM2 运行时](https://github.com/kairowan/Shellsmith/tree/main/third_party/xopprotector) +- [路线图](roadmap.md) +- [Android 代码保护升级方案](../design/android-code-protection-upgrade.md) diff --git a/docs/process/roadmap.md b/docs/process/roadmap.md index 2cd35c0..0412ee4 100644 --- a/docs/process/roadmap.md +++ b/docs/process/roadmap.md @@ -6,9 +6,10 @@ | 项目 | 当前结论 | |------|----------| -| 版本基线 | 当前源码 `1.8.0`,本轮从已公开的 `1.7.0` 升级;正式发布状态以 GitHub Releases 为准,历史版本内容不在本文件重复 | +| 版本基线 | 当前源码 `1.9.0`(2026-10-21 发布);正式发布状态以 GitHub Releases 为准,历史版本内容不在本文件重复 | | 正式交付形态 | Linux、macOS、Windows 桌面 GUI;CLI 仅供本地开发、调试与回归,不由 CI 单独出包 | -| Android 支持 | 标准模式支持 Android 5.0 及以上;Android 4.4 工控兼容模式限定 `armeabi-v7a` | +| Android 支持 | 标准模式支持 Android 5.0 及以上;Android 4.4 工控兼容模式限定 `armeabi-v7a`;BYOS `device_approval` 要求 `minSdk 26+`,`play_integrity` 要求 `minSdk 29+` | +| BYOS / DEXB v7 | `1.9.0` 已发布设备批准与 Play Integrity 的 BYOS;APK 只携带服务地址与 token,不携带 IKM;单设备 IKM 泄漏边界见下方「明确的边界」 | | iOS 支持 | 工作副本接入、签名链核验与 Archive/Export 验证;运行期保护依赖上游 freeRASP 能力 | | 维护策略 | 补丁线只处理可稳定复现、且影响安装、启动、数据安全、大范围兼容或**安全边界**的缺陷;安全类缺陷可单独发补丁版 | | 当前公开问题 | 需真机或样本才能推进:#3 / #10 / #13 启动崩溃类未复现,#109 uni-app 缺样本,#11 杀软误报、#121 Fedora 空白窗、#129 Windows keytool、#2 16 KB 设备、#110 反调试探针均为「已修复待真机验证」。细节见[融合项目 Issue 台账](issue-ledger.md) | @@ -24,25 +25,26 @@ | 打开链接的命令注入 | Windows 上此前把链接交给 `cmd /c start` 解析且白名单只比较字符串前缀,更新说明(不在更新包验签范围内)里的注入链接可执行任意程序;`1.6.3` 改为系统 shell API + 按 URL 组件与字符白名单校验 | | PVM2 打包器与运行时不同源 | 打包器 JAR 与壳运行时曾分别来自仓库产物与外部固定提交,镜像格式版本不一致会让产物在设备上启动即崩;`1.6.2` 起运行时源码随仓库分发,发布期闸门恢复为硬性拦截 | | 只读位置无法一键更新 | 从磁盘映像或 Gatekeeper 转位路径运行的 macOS 应用此前只能跳转下载页;`1.6.1` 起改装到「应用程序」并从该位置启动 | +| apktool 资源解码路径穿越 | CVE-2026-39973 影响 3.0.0/3.0.1,3.0.2 修复;仓库自 `f1979f9`(2026-10-12)起使用 3.0.3,发布门禁固定 SHA-256 并拒绝 3.0.1 残留。剩余缺口仅为 CI 依赖漏洞扫描 | ### 明确的边界(需要架构决策,不是实现缺陷) | 边界 | 说明 | |------|------| | DEXB v6 不提供对静态分析的机密性 | 包裹密钥的两个输入(证书指纹、build_id)都在包内明文头部,仅凭 APK 即可离线还原 IKM,并派生 PVM2、assets、业务 SO 的密钥。该层实际提供的是「改包重签后无法运行」与提高自动化分析成本。详见[技术内参](../design/internals.md)的「DEXB v6 的机密性边界」 | -| 原生库可被替换 | 壳运行时以无自校验的 `System.loadLibrary` 加载,替换 `.so` 即可绕过签名校验与运行期检查 | -| 运行期存在明文落盘 | 解密后的 DEX 缓存、assets 与业务 `.so` 均写入应用私有目录且不清理 | +| 原生库可被替换 | 壳运行时先 `System.loadLibrary`,之后 `RuntimeSecurity` 才执行 `NativeIntegrity`。后者已覆盖 `nativeLibraryDir` 与 APK/ABI split 两条路径并对完整 ELF 做 SHA-256,但被替换的 `.so` 可在校验前执行;`.so` 内 constructor 也不构成新信任根。该检查属于检测增强,不是修复。 | +| 运行期存在明文落盘(待核) | 待核:解密后的 DEX 缓存、assets 与业务 `.so` 是否写入应用私有目录、是否存在清理路径,尚未逐项复核;复核前不作为已确认边界。 | +| BYOS 单设备 IKM 泄漏 | 同一产物所有设备最终得到同一把 IKM;per-device wrapping 只改变信封,不改变明文,不能阻止一台设备提取 IKM 后解开同一产物的其他副本。要阻断必须 per-device payload/不同产物,和当前单 APK 分发模式冲突。现有协议覆盖网络侧、重放和服务端越权,不覆盖已授权设备内存提取;记录为明确边界,不列为待办。 | ### 待修(按严重度,尚未排期) | 项目 | 说明 | |------|------| -| apktool 3.0.1 资源解码路径穿越 | 资源解码路径未做规范化,打开恶意 APK 可写出输出目录之外;同时存在版本硬编码、发布分发物无哈希固定、CI 无依赖漏洞扫描 | | 签名口令与子密钥暴露面 | apksigner 口令经命令行参数传递;PVM2/PAS2/PSO2 子密钥经环境变量传给打包器 | | 本地密码保护强度 | `enc:v1` 的密钥由固定串与路径拼哈希得出,拿到 `shield.db` 即可离线还原 | | 发布链路信任与并发 | 自动发布链路持有更新签名私钥且工作流级 `contents: write`,检出未关闭凭据持久化,无并发控制与人工审批 | +| CI 依赖漏洞扫描缺口 | 仓库内没有 Dependabot / cargo-audit / cargo-deny 配置;新 CVE 仍只能靠人工发现。apktool 3.0.3 的固定哈希不能替代持续扫描。 | | iOS 保护强度与验证 | freeRASP 只通知不阻断,注入调用不注册回调;Swift Confidential 校验在解析不到配置时静默跳过 | -| 运行期反分析 | 反调试/反 Root 全在进程内可 patch;壳库启动期完整性校验已加入并在 Release 默认开启,解压副本的更广设备矩阵和更强的运行时防护仍需继续验证 | | 反馈接口滥用面 | 无全局日上限、CORS 为通配、正文零清洗、首次部署用的 schema 缺限流表 | | 文档与实现一致性 | 部分流程文档与实际工作流不符;本文件此前长期停留在 `1.4.0` 阶段,即为其中一例 | @@ -56,14 +58,13 @@ |--------|------|----------| | 收敛保护实现的公开面 | 壳体与虚拟机的格式定义、解释器与编译器源码不再随公开仓库分发,减少分析者可直接使用的完整规格;`LICENSE` 与 `NOTICE` 继续随发布包提供 | 构建可复现性不下降:源码改为私有子模块或预构建产物,CI 与本地构建步骤同步更新 | | 降级产物内的诊断线索 | 原生库中保留的 PVM2 诊断串与依赖路径/版本串可直接用于指纹与格式推断 | 诊断信息不再进入发布产物;排障改为独立符号文件或本地构建选项 | -| 修复 apktool 相关风险 | 打开不受信任 APK 即可被写出目录,属于主用法上的现实风险 | 升级到已修复版本,同步全部硬编码版本引用并加哈希校验;CI 增加依赖漏洞扫描作为兜底 | -| 补齐运行期反分析 | 反调试/反 Root 可被进程内 patch;壳库完整性需要覆盖系统实际加载的解压副本,策略位仍依赖签名包元数据 | 缓存路径补齐检查;壳库校验覆盖 `nativeLibraryDir` 与 APK 直接映射两种路径;Release 默认开启、Debug 可显式覆盖;全部按失败关闭,并在文档与报告中如实区分「检测」与「阻断」 | +| 补齐 CI 依赖漏洞扫描 | 目前没有 Dependabot / cargo-audit / cargo-deny;新 CVE 仍然只能靠人工发现 | 至少接入一种持续扫描;首次扫描结果单独记录;不阻断现有发布 | ### 随后处理 | 工作项 | 目的 | 进入条件 | |--------|------|----------| -| 设备密钥与首次配置边界 | 设备包装可保护本地状态或限制缓存复制;若原始 IKM 仍可从 APK 恢复,事后包装不能阻止离线解密或仿真 | 先明确秘密来源。需要 APK 单独不足以解密时,必须有使用方后台授权配置或受控设备预配置;同时设计换机、清数据、重装和密钥失效行为 | +| 设备密钥与首次配置边界 | 本地设备包装只能保护本地状态;BYOS 已把 IKM 移出 APK,但单设备泄漏边界见「明确的边界」。per-device payload 属于新架构,不进入当前排期 | 仅在重新论证分发模式与成本后进入;换机、清数据、重装和密钥失效行为已在 [BYOS 服务端参考](../design/byos-key-server-reference.md) 中说明 | | 关键方法覆盖与明文生命周期 | 升级分支已实现必保方法最后调用退出清理、镜像及解析副本清理,并通过并发与异常路径检查;继续按真实业务扩大经过验证的范围 | 新增语义必须有原始/转换版本的结果与异常对照;完整内存 DEX 与方法回填继续保持下方暂停/停止结论 | ### 中期评估 @@ -71,7 +72,8 @@ | 工作项 | 目的 | 进入条件 | |--------|------|----------| | 分析环境识别与误导路径 | 自动化分析依赖「重建结果与样本一致」来自我确认。对高置信分析环境改走语义等价但误导的路径,比直接崩溃更有效(崩溃等于把检查点告诉分析者) | 严格限定高置信信号与可配置开关,误报不得影响正常用户;必须有回归样本证明正常环境不受影响 | -| 资源与标识符加密 | 明文路由类名清单、字符串池与资源命名会直接降低分析成本 | 不影响启动耗时与第三方框架兼容;回归覆盖既有 ARouter/TheRouter 路径 | +| 路由资源与标识符加密 | `protect/dex.rs` 直接写出 `assets/arouter_routes.txt` 与 `assets/therouter_registry.txt`;资源命名也会降低分析成本。这是资源层问题,DEX 字符串池混淆不会覆盖。 | 不影响启动耗时与 ARouter/TheRouter 兼容;运行时解密或移除明文 assets;回归覆盖既有路径 | +| DEX 字符串池混淆 | DEX 字符串池仍会暴露类名、路由与端点等信息,与 assets 路由清单是不同泄漏面 | 不影响反射与第三方框架;单独验收,不与路由 assets 合并 | | 隐藏 Root 与分析环境规则扩充 | 现有检测在 Magisk Hide、Zygisk 等隐藏方案下覆盖不足。可补的通用信号包括异常挂载点(`/proc/self/mountinfo`)、属性交叉比对(`getprop` 与 `/system/build.prop` 原始文件结果不一致)、隐藏的 `su` 残留元数据、注入库路径(`/proc/self/maps`) | 以**可插拔规则模块**承载,规则更新不改核心架构与协议;只基于通用行为特征,不针对特定工具品牌或版本;误报不得影响正常用户与工控设备 | | iOS 常量覆盖与联动响应 | 把 API endpoint、密钥材料等字面量纳入 Swift Confidential 覆盖范围;并让运行期检测结果与业务联动(高置信威胁下使敏感常量失效或返回诱饵数据),不再只是「检测到但不阻断」 | 前置条件:先修「freeRASP 不阻断」「注入时不注册回调」「Swift Confidential 校验在解析不到配置时静默跳过」三处管道;联动策略必须在隐私与兼容说明中写明 | @@ -79,9 +81,9 @@ | 方向 | 现状与判断 | 如果要做,必须先满足 | |------|-----------|--------------------| -| 使用方自有服务的可选接入 | 维护者不提供或运维服务器、密钥服务及中转。默认加固链路离线;联网仅在使用方提供服务地址、接口与凭据并显式配置后接入,不作为离线升级前置条件 | 区分桌面加固时取材料与应用运行时授权:前者若把完整恢复材料放回 APK,仍无包外秘密收益;后者须由使用方提供可信首次配置及授权服务,独立设计运行时身份、服务不可用与恢复行为,不能把桌面管理凭据打入 APK | +| 使用方自有服务的进一步扩展 | BYOS 已在 `1.9.0` 实现设备批准/Play Integrity;默认仍离线。单设备 IKM 泄漏是明确边界,per-device payload 属于新架构,不排期。 | 仅在重新论证分发模式、成本与撤回策略后进入 | -将来若推进,协议必须按下列口径设计,否则没有安全收益:**设备证明(Play Integrity / App Attest)是必需项而不是可选项**,并以证明绑定的设备公钥包裹密钥后再下发。仅校验签名证书指纹、包名与版本号的方案不成立——这三项都在 APK 内公开,任何人都能原样重放请求领取密钥;同时若所有设备收到同一把明文密钥,一次响应泄漏即等于全部用户可解。 +BYOS 已实现,不再属于「待考虑」。协议的安全收益来自设备证明/设备批准、HTTPS、服务端授权、防重放、时间窗和 IKM 不进入 APK。**设备公钥包裹同一把 IKM 不改变「单设备泄漏 → 全体可解」的边界**;若未来要求阻断该威胁,必须改为 per-device payload(每设备不同密文/不同产物),这会与当前单 APK 分发模式冲突,属于新架构,不纳入当前路线图。 ### 评估口径 @@ -108,6 +110,8 @@ `codex/android-code-protection-upgrade` 已实现通用方法保护验收链、运行时清理与阻断联动、Native 构建证据接入及最终签名摘要绑定。仓库 APK 与 7 模块 AAB 通过宿主打包检查,Native/组合样本通过单台 Android 15 设备回归;授权真实 APK 已完成候选清点、限定方法功能回归与离线恢复检查。高频启动强停已定位到该设备的厂商进程创建计数策略,校准后补齐三组分段启动/PSS 测量,温控中断及历史压力失败均保留。完整业务、跨设备及抗语义还原能力仍须按范围验证,不能标记整包“3.5 代达标”。最新采样结论和证据统一见 [实施方案与验证记录](../design/android-code-protection-upgrade.md)。 +XopProtector 本地分支与 `origin/main` 的差异审计见 [2026-10-23 Xop 分支差异审计](2026-10-23-xop-diff-audit.md);该记录只描述审计与待裁决项,不代表已合并。 + ## 后续候选 候选方向不等于已排期版本;只有需求、依赖条件和验收资源同时具备后才进入下一版本。 @@ -129,7 +133,7 @@ | API 29 以上完整内存 DEX | 暂停产品接入 | 公开加载链路与回退状态已完成大量实验,但真实大 APK 的长期内存性价比门禁未通过,详见 [内存 DEX 设计](../design/memory-dex-production.md) | | DEX 结构与方法代码分离 | 停止产品接入 | 离线协议、真实多 DEX 与攻击测试已完成;公开运行时仍要求形成完整 DEX,继续只能依赖高风险私有运行时或独立虚拟机,详见 [代码分离研究](../design/dex-code-separation.md) | | ART/系统函数 Hook、自修改代码、可写可执行内存 | 禁止 | 与多版本兼容、安全软件风险和项目安全边界冲突,不进入正式方案 | -| 独立在线加固服务 | 不计划 | 除「服务端密钥下发」这一受成本约束的待考虑方向外,项目保持本地离线处理,不托管用户 APK、证书或密码 | +| 独立在线加固服务 | 不计划 | 除已实现的 BYOS 包外密钥(由使用方自建服务端)外,项目保持本地离线处理,不托管用户 APK、证书或密码 | ## 并行维护规则