# Android / iOS 相似度匹配规则与判读手册

规则版本：2026-09-08.v2.1。Android 提取器：android-2.1.0；iOS 提取器：ios-2.1.1。特征格式：mobile-features-v2.1。

第 1–12 节详述基础评分及通用判读；第 13–17 节详述 iOS、深度及跨平台规则；第 18–20 节详述新增 Android 函数实现匹配、分档与迁移。

这份手册对应交付代码中的实际实现。默认阈值是保守的初始工程参数，不是经过你业务样本验证的分类器，也没有“达到 80 分就有 80% 概率抄袭”的含义。建议先用你的应用及几个已知无关应用建立基线。

## 1. 先明确“相同”指什么

| 层次 | 判断依据 | 本服务能给出的结论 |
|---|---|---|
| 同一个上传文件 | 整个 APK/ZIP/APKS/XAPK 的 SHA-256 相同 | 文件字节完全一致 |
| 同一组 APK 内容 | 每个 split 的非签名条目路径及内容哈希完全一致 | 所提供 APK 内容一致；允许 ZIP 封装、条目顺序和签名变化 |
| 大量核心实现相同 | 足量、去公共特征后的规范化方法匹配，双方覆盖高，并有其他支持 | 高度相似，需人工复核 |
| 部分模块被复用 | 基准的一部分独立方法持续命中，整体覆盖不足 | 疑似代码复用 |
| 图文/资源相似 | 文件内容或业务字符串命中，代码不足 | 资源或文本重合 |
| 功能看起来相同 | UI、交互、玩法、文案风格等 | 仅凭本服务当前静态特征无法判断 |

“包名相同”不等于文件相同，“签名不同”不等于没有复制，“签名相同”也不能证明源码相同。共享签名、debug key、换签名、密钥轮换、同公司多应用等情况都可能影响上下文。

相似度不判断合法授权、共同开源来源、开发先后、权属或侵权。结论应作为技术排查入口。

## 2. 输入与留证规则

### I-01 原始样本固定

每次上传保留：原文件、SHA-256、上传 UTC 时间、原始文件名、样本角色、用户填写的来源备注。提取元数据包括包名、versionCode、versionName、组件、权限、证书指纹、拆分 APK 清单与各自哈希。

来源备注是用户记录，不是对 Google Play 页面或采集时间的自动验证。建议保留 GP 页面链接、展示开发者、实际采集时间、安装来源、国家/地区、Android 版本、设备架构/密度/语言，以及自己的发布归档。上架时间与上传本服务时间要区分。

### I-02 拆分包组成一个样本

- 将同一次安装获得的 base 与全部可取得 splits 放入一份 ZIP，上传为一个样本。
- 检查同一包名、versionCode、提取证书集合，split 标识不能重复，集合必须有 base。
- 多个 base、混合版本、不同应用混包直接拒绝，不做“取其中几个能解析的包”的部分成功。
- 单独上传资源 split 会被标记缺 base；多 split 集合缺 base 直接拒绝。
- 单个 base APK 不足以证明获得所有按需功能模块，服务无法自动确认远端动态模块完整性。
- XAPK 中的 OBB、ZIP 中的采集说明和其他外部文件不进入相似度；它们仍在原始上传文件内留存。
- AAB 不直接分析；需生成/采集实际设备对应 APK。含多设备替代变体的完整 bundletool APKS 应先提取对应设备集。

### I-03 版本分别比较

每个基准版本单独提取、单独比对，不合并多个历史版本的特征。否则并集会膨胀分母、交集又会丢失版本特有证据。对一个待测包，可比较自己的多个历史版本，以最相关版本作为复核入口，但保留每份报告。

### I-04 保留解析失败

未知文件、损坏 DEX、异常 XML、条目路径穿越、重复 ZIP 路径、超高压缩比、解压/内存/时间超限均标记失败。失败不等同于低相似，也不会以成功结果替代。任务队列继续处理其他文件。

## 3. 去掉公共部分后再匹配

### F-01 已知 SDK/框架前缀

默认排除 Android/AndroidX、Java、Kotlin、Google、Facebook、常见广告归因 SDK、OkHttp/Okio、Retrofit、RxJava、Flutter、Unity 框架等前缀；完整清单以 `rules.yaml` 为准。排除 R、R$… 与 BuildConfig 生成类。

这是可编辑的初始名单，不是完整 SDK 识别器。SDK 被 relocation 或混淆改名后，前缀排除会失效；同名业务类也可能误排。配置过宽会漏掉自己的代码，请核实基准命名空间。

### F-02 基准业务范围

`core_prefixes: []` 表示分析所有未被排除的类。知道自己的业务命名空间时可填写多个前缀，例如：

```yaml
core_prefixes:
  - com.mycompany.product.
  - com.mycompany.engine.
```

前缀只应用到基准包的代码和字符串。待测包可能改名，仍检查所有未排除的类，以免只因不同包名就失去匹配。排除前缀优先于包含前缀。

生产构建若使用 R8/ProGuard 混淆，优先用实际 APK 中的命名空间和 mapping 文件人工核对。当前版本不自动导入 mapping，也不自动恢复类名。

### F-03 无关对照包去公共特征

在“无关对照包”中出现的相同方法指纹、资源内容哈希、业务字符串哈希和原生库哈希，从基准与待测两侧同时移除。对照包中的代码片段也从片段指标中移除。指纹按内容匹配，即使对照包类名不同也能去掉公共代码。

当前实现是保守的**任一对照命中即排除**，不是 TF-IDF，也不是自动判断哪些包真的无关。对照库混入真实复用样本可能造成漏检。服务会拒绝让同一文件哈希同时作为本次基准/待测与无关对照。

建议逐步添加已核实无关且使用相同技术栈、SDK 或 UI 模板的应用。不要把全网未标注 APK 都当负样本；每份报告记录本次使用的全部对照样本与删除特征数量。修改角色不追溯修改已有报告。

### F-04 去重与最小复杂度

- 每个相同指纹仅投一次票；重复方法、复制资源、多个 split 中重复条目不能提高命中数。
- 默认至少 12 条非 nop 指令，且至少 4 种不同操作码，才进入方法评分。
- 方法权重为 `min(指令数, 200)`，避免一两个超长方法主宰结论。
- 资源权重为 `min(字节数, 65536)`，并按内容哈希去重。一个巨型素材不能无限加分。
- 字符串至少 12 个字符、至少 5 种字符，按完整内容去重；可追加排除常见文案。

## 4. 特征与算法：已实现部分

### C-01 整文件一致

比较上传文件的 SHA-256。相同直接输出“上传文件完全一致”，分数为 100；此时 100 表示一致性规则命中，不依赖加权覆盖分数。APK 集合仅改变 ZIP 元数据就可能产生不同上传哈希，因此还有下一层规则。

### C-02 APK 非签名内容一致

对每个 APK 的所有非目录条目计算内容 SHA-256，并保留内部条目路径。忽略 `META-INF/MANIFEST.MF` 和 META-INF 下的 `.SF/.RSA/.DSA/.EC` 签名文件；保留其他 META-INF 数据。APK Signing Block 不属于 ZIP 文件条目，因而不进入该指纹。

按路径排序后产生该 APK 的内容指纹，再按实际 split 标识排序聚合。条目压缩方式、ZIP 顺序、APK 外部文件名不影响该指标；应用包名/版本等 manifest 内容仍会影响。所有指纹相同才输出“APK 内容一致”，分数为 100。

这不是验证签名，也不验证服务之外的 OBB、远端脚本或动态模块。证书不同仅说明提取结果不同，不能单靠此规则断言“恶意重打包”。

### C-03 规范化 DEX 方法指纹（主指标）

遍历所有 APK 中的所有 `classes*.dex`。为每个有代码的方法生成指令 token 序列：

1. 去掉 nop。
2. 保留操作码，合并 `/range`、`/16` 等编码宽度后缀；不把寄存器编号、分支偏移和常量池索引放进指纹。
3. 保留整数常量；0x7f 开头的应用资源 ID 统一为资源占位符，降低重编译资源重编号的影响。
4. 字符串常量统一为 `str`，其实际内容另入字符串维度。
5. 保留 Android/Java/Javax/JSON 框架引用，增加业务行为区分度。
6. 对应用/SDK 的类名与调用名进行抽象，保留引用/参数形状，降低改包名和常规混淆影响。
7. 对序列求 SHA-256。位置仍保留原类名、方法名、描述符和 split，供报告定位。

方法名称不参与指纹，报告里的名称只用于定位。这个“精确匹配”是**规范化后的指令形态精确匹配**，不是原始字节码相同，也不是严格语义等价证明。删除寄存器/跳转差异可能让不同逻辑发生特征碰撞；源码重写、编译器大改、控制流混淆、方法内联/拆分可能使真实复用不再匹配。

### C-04 指令片段辅助指标

每个方法取连续 5 个 token 的 shingles。去重后排除：

- 无关对照包中出现的片段；
- 本侧样本中出现于至少 `max(3, 该侧独立有效方法数×10%)` 个方法的通用片段。

基准片段在待测包中的覆盖率作为辅助指标；至少有 20 个不同片段共同命中才给出非零辅助分。代码维度为 `0.85×规范化方法精确覆盖 + 0.15×片段覆盖`。

这个片段指标用于给轻微修改保留少量信号，本身不执行方法对齐。第 18 节的独立函数分析另行完成方法配对和调用上下文核对。大量片段重合但没有足量完整方法命中，不能单独达到“高度相似”结论。片段尺寸固定为 5，规则编辑器禁止改变以避免缓存不兼容。

### R-01 资源与资产

匹配 `assets/` 和 `res/` 中至少 256 字节的文件内容哈希。路径作为证据显示，但不要求两边路径相同；重命名素材仍可匹配。排除已知公共资源名前缀、Flutter 包资产和部分框架目录，并排除对照包中的相同内容。

当前是**文件内容精确匹配**。换色、裁剪、重压缩图片不会被感知哈希识别；编译 XML 的资源 ID 或编译方式变化也可能失配。未把 `resources.arsc` 的结构规范化为 UI 树。相同开源图标、系统素材、模板和字体仍需人工核实。

### S-01 业务代码中的字符串

只使用通过业务范围/SDK 过滤的类中实际 const-string 引用。统一空白后做完整字符串哈希匹配，保留原文和方法位置。它比从整个 DEX 全局字符串池直接计数更能减少 SDK 名称干扰，但仍可能含公共异常消息和协议常量。

不把包名、权限列表当业务字符串加分；未实现自动域名归属判断或“唯一标记”认定。服务器地址、独有错误文案、内部路径等命中后可人工复核其是否专有。所有字符串按同等权重计数，没有词义向量或模糊翻译匹配。

### N-01 原生库

对 `lib/…/*.so` 做完整文件内容哈希匹配。默认排除 Flutter/Unity/C++/React Native 等常见运行时文件名，并排除对照指纹。`libapp.so` 也不进入此 DEX 主导评分，因为 Flutter AOT 应由专门方法判断。

未实现 ELF 函数指纹、符号恢复、跨 ABI 比对或 native 反汇编。架构不同/重新编译的同源 native 库会失配；库名相同不会加分。该维度仅占 5%，不能单独判同。

## 5. 公式与判定门槛

设基准独立特征集合为 A、待测为 B；都已经过排除和去重。集合为空时相应覆盖率与 Jaccard 是“不可用”，不会把空对空算成 100%。

- 基准覆盖率 `C(A→B) = Σ[w(a), a∈A∩B] / Σ[w(a), a∈A]`。
- 待测反向覆盖率 `C(B→A) = Σ[w(b), b∈A∩B] / Σ[w(b), b∈B]`。
- Jaccard `J = |A∩B| / |A∪B|`，是独立特征数量口径；不与加权覆盖率混用。
- 方法/资源权重见 F-04；字符串权重为 1；native 也使用 `min(文件字节数, 65536)`。

设 M 为方法精确基准覆盖、G 为片段基准覆盖、R 为资源基准覆盖、S 为字符串基准覆盖、N 为 native 基准覆盖：

`代码维度 D = 0.85M + 0.15G`

`排序分数 = 100 × (0.65D + 0.20R + 0.10S + 0.05N)`

缺失维度按 0 进入总分，**不重分配权重**。因此无 native 的强匹配样本不一定满分；满分的整文件/内容一致规则另行优先处理。报告的代码反向覆盖率与 Jaccard 是完整方法口径，不包含片段加权。

默认规则按照下列先后顺序执行，先满足的结论优先：

| 优先级 | 判定 | 默认条件 |
|---|---|---|
| 1 | 上传文件完全一致 | 上传 SHA-256 相同 |
| 2 | APK 内容一致 | 聚合非签名内容 SHA-256 相同 |
| 3 | 证据不足 | 任一侧独立有效方法数 <30；或识别出跨平台框架、常见加固壳标记、native 占主导、缺 base |
| 4 | 高度相似 | 总分 ≥75，方法精确基准覆盖 ≥65%，反向 ≥50%，独立完整方法命中 ≥30，并且资源命中 ≥3 **或** 字符串命中 ≥5 |
| 5 | 疑似代码复用 | 方法精确基准覆盖 ≥20%，独立完整方法命中 ≥15 |
| 6 | 资源或文本重合 | 资源命中 ≥3 且覆盖 ≥30%，或字符串命中 ≥5 且覆盖 ≥30% |
| 7 | 当前证据较少 | 其余可分析样本 |

资源/字符串支持是附加证据门槛，不是统计意义上的独立概率事件。默认 75/65%/50% 等门槛是工程建议，不是行业统一标准。仅降低 high_score 仍须满足其余门槛；配置变更应增加规则版本号。

**方向示例**：你的 APK 有 100 个等权业务方法，待测包有 1,000 个，前者全部出现在后者。基准覆盖 100%，反向覆盖 10%。它可能复用了你的模块，但不能据此称整个待测应用相同；默认不会触发整体高度相似。

## 6. 不直接计分的上下文

- 包名是否相同。
- 提取到的证书指纹交集；明确标为 `signature_validity: not_verified`。
- 相同的权限、组件名。
- 应用名称、版本、framework 标记、拆分集合。

这类信息常用于人工复核，但过于常见、可伪造或可修改，因此不加权。

Androguard 可提取 v1/v2/v3 等证书信息，但本服务没有验证签名有效性或签名轮换链。证书相同/不同/未提取是三种不同情况；空证书集合不是“签名相同”的证明。外部需要用官方 apksigner 做验证并保存结果，当前服务不自动调用它。

## 7. 可见性、降级与漏检

| 场景 | 当前处理 | 后续需要的分析 |
|---|---|---|
| Flutter | 识别 libflutter / flutter_assets，优先返回证据不足 | Dart AOT 快照、libapp.so 与 Flutter 资源分析 |
| Unity/IL2CPP | 识别 Unity/IL2CPP 运行库，优先降级 | metadata + native 函数与业务资产分析 |
| React Native | 识别 Hermes / bundle 标记，优先降级 | JS/Hermes 语法/字节码层面比对 |
| 常见加固壳 | libjiagu/libDexHelper/libSecShell/libexec、部分 stub 类标记命中时降级 | 合适隔离环境中的可见业务代码收集；当前不解壳 |
| native 体积主导 | 非排除 native 库 >5 MB 且 >DEX 总字节数的 5 倍时降级 | 函数级 native 比对；这是启发式，不是完整 native 比例度量 |
| 只有资源 split、缺 DEX | 不把没有命中解释为无关 | 补齐 base/功能 split |
| 动态加载 DEX/脚本/服务端逻辑 | 无法看到未随包交付的内容 | 补充相应版本实际内容与运行证据 |
| UI 重新绘制、功能重写 | 可能没有文件或方法命中 | 人工流程、截图及交互比较 |
| 强控制流混淆、反射、字符串加密 | 当前规范化未必识别 | 更深入的语义/图结构分析 |

标记检测不完备；没有壳标记不等于没有加固。低分报告始终不保证“确定无关”。即使分数很高，在可见性不足时也保留可见证据并优先输出“证据不足”。

## 8. 推荐的人工复核顺序

1. 核对双方版本、包集合和采集设备是否可比。
2. 看两个方向的代码覆盖率及独立命中方法数，不先盯总分。
3. 在报告中抽查命中最多的业务模块，确认不是 SDK、开源库、模板或代码生成产物。
4. 核对命中资源/文案是否是自己的业务素材，是否能从共同公开来源取得。
5. 在自己的源码/mapping 中定位关键方法，确认规范化丢掉的常量、寄存器和跳转差异是否改变逻辑。
6. 对独有逻辑和独有素材保存逐项说明；如发现排除名单遗漏，更新规则后重新比对。
7. 使用至少一个其他自有历史版本及已知负样本交叉验证，保留正反例和原始报告，不只选择最有利的结果。

报告每个维度展示最多 100 条命中明细，并保留总命中数和截断标记。超过 100 条时不是只有 100 条命中；完整特征留在本机缓存，重新运行相同快照可复算。指纹只是规范化特征摘要，不能反向恢复源代码。

## 9. 用你的包校准，而不是拍一个通用百分比

### 第一轮样本建议

这些数量是实施建议，不是已完成的工作：

- 自有应用选择 3–5 个历史版本，包含正式发布版本和实际混淆构建。
- 若你有源码，可在自己的测试构建上制作换包名、换签名、删改广告、换图标、重压缩资源等正向变体，并保留改动清单。
- 收集约 20–50 个已确认无关、但相似类型或相同技术栈的负样本；尤其要包含相同 SDK/模板的应用。
- 对已怀疑复制的应用，先由你核查关键证据，再赋予“整体复用”“模块复用”“只复用素材”“未知”等标签；未知不充当负样本。

### 分离用于排除、调参和验证的数据

对照指纹库、阈值调整集、最终验证集应按应用家族/开发项目划分，不能把同一应用的不同版本分散到训练和验证两侧制造高准确率。对照库快照也必须固定；验证期间不能看结果再把假阳性临时放入对照库后宣称成功。

### 指标与阈值调整

- 分别统计“整体相似”“部分复用”“素材复用”，不要把几类混为单一正确率。
- 记录 TP/FP/FN/TN，以及“证据不足”占比；弃权结果单列，不伪装成正确的负例。
- 精确率 = TP/(TP+FP)，召回率 = TP/(TP+FN)。分母为零时记不可用。
- 优先检查假阳性来源，先修 SDK/模板排除与业务范围，再调阈值。若宁可多人工复核，也可降低“疑似部分复用”门槛，保留严格的整体相似门槛。
- 覆盖不同版本、ABI、框架、编译模式；不要只测试把同一 APK 复制一份。
- 给每次规则更新记录版本、规则哈希、样本清单、误报/漏报案例和变更理由；最终在未参与调整的验证集报告性能。

本次交付完成的是软件功能、公开 APK/IPA 解析与自建 iOS 正反例工程测试，没有你的样本，尚不能报告真实误报率、召回率或最终业务阈值。

## 10. 配置生效与可重复性

`rules.yaml` 是首次安装默认值；运行中使用 `data/rules.yaml`。所有新任务创建时保存当时规则快照。更改当前配置、样本角色或对照库，均不改变已经生成的报告。

提取器保存的是较低层特征，前缀、排除词、计分权重、门槛可以直接重比，无需重解 APK。`shingle_size` 固定为 5；方法最小长度不能低于 12，字符串最小长度不能低于提取下限 8。新增提取算法时必须更新提取器版本并重建相关缓存，不可复用旧算法缓存假装同一口径。

每份导出包括：双方文件哈希与来源、版本元数据、分项分数和分母、双向覆盖率、命中证据、排除对照数量、可见性限制、规则完整快照与 SHA-256、提取器版本、报告 ID 和生成时间。

## 11. 当前未实现、不能冒充已有能力的扩展

- 从 Google Play 自动发现相似应用、搜索、下载或定时监控。
- 图标/截图感知哈希、OCR、视觉布局和用户流程相似度。
- DEX CFG/调用图匹配、复杂语义同源检测、方法对齐与自动 mapping 还原。
- Android ELF 函数同源、Dart AOT、IL2CPP metadata、Hermes AST 的专门算法（iOS 主程序深度匹配见第 15 节）。
- 壳自动脱除、运行 APK、动态流量采集、运行时代码抓取。
- 自动证明开发先后、授权关系或侵权。
- 有标注数据训练的 TF-IDF、概率校准、百万级向量检索与分布式执行。

当前实现已经能够完成多个包的重复静态检测与可追溯报告；以上扩展应由你实际样本中的漏检/误报驱动选择。

## 12. 官方依据与实现边界

- [Androguard APK API](https://androguard.github.io/androguard/reference/androguard/core/apk/index.html)：APK、Manifest、证书等解析能力。
- [Androguard DEX API](https://androguard.github.io/androguard/reference/androguard/core/dex/index.html)：方法与指令访问。
- [Android App Bundle](https://developer.android.com/guide/app-bundle)：按设备优化与模块交付背景。
- [apksigner](https://developer.android.com/tools/apksigner)：签名验证工具与边界。

这些官方资料支持解析和平台事实。本文的特征权重、归一化设计、降级策略、阈值和校准建议由本服务设计，并不是 Androguard 或 Google 官方提供的“同包判断标准”。

## 13. iOS 输入、可见性与一致性规则

### IOS-I01 只接收明确的应用载荷

IPA 必须恰好包含一个 `Payload/*.app/Info.plist`，存在有效 `CFBundleIdentifier` 与安全的 `CFBundleExecutable` 文件名，并有对应主 Mach-O。校验大小写冲突路径、符号链接、ZIP 穿越、解压预算、FAT 架构表及切片范围；主程序明确声明非 iOS / iOS Simulator 平台时拒绝。

每个 Mach-O 切片单独记录架构、文件 SHA-256、FAT 偏移、加密标记、函数边界来源、函数数和解码覆盖率。ARM64、ARM64e 和 x86_64 可生成函数指纹；其他架构不伪装成可读代码。

### IOS-I02 加密先于解析

在调用 LIEF 或 Capstone 之前，读取 `LC_ENCRYPTION_INFO` / `LC_ENCRYPTION_INFO_64`。`cryptid != 0` 的整个切片不进入代码和二进制字符串提取，包括看起来可读的局部字节。保留加密状态、元数据、资源及独立本地化表。这个规则检查的是声明的加密状态，不是解密功能，也不保证识别所有自定义加固。

没有双方可读且解码覆盖达到 70% 的相同主程序架构时，代码覆盖显示“不可用”，总分为 `null`；不把素材权重放大为整体分数。即使未知代码未命中，也不能排除复制。

### IOS-I03 文件一致与主载荷一致

整 IPA 文件 SHA-256 一致，输出“上传文件完全一致”，可适用于加密文件，但不表示已经读取其代码。

否则对主 `.app` 内每个非目录条目的**相对路径与原始内容哈希**排序聚合；仅忽略路径中的 `_CodeSignature` 目录与主 app 的 `embedded.mobileprovision`。所有 Mach-O 字节，包括嵌入签名与每个架构，仍参与一致性哈希。因此换签后的可执行文件通常不会触发载荷一致，不会为了容忍签名变化而忽略潜在代码差异。

主 `.app` 之外的商店包装文件不参与此载荷结论；应用声明、资源、Framework、PlugIns 均在主载荷内参与。只有范围内所有路径和内容都一致，才输出“应用载荷内容一致”。这不是签名有效性验证，也不代表外部服务内容一致。

## 14. iOS 标准相似度规则

### IOS-C01 可靠函数边界与指令归一化

以 LIEF 读取 `__text` 和 `LC_FUNCTION_STARTS`。没有可靠边界时不将整段任意切块冒充函数。单函数不完整解码则不产生指纹；超过 1 MB 的单函数跳过并体现在解码覆盖率中。仅删除 ARM64 末尾完整四字节零填充和 nop。

规范化保留：操作码、寄存器使用关系与宽度、整数和浮点常量、内存位移、移位/扩展、向量属性、条件码/写回标志、函数内跳转相对目标。函数名、应用名称和绝对函数地址不作为内容指纹；外部跳转目标及 ADR/ADRP 的地址抽象为重定位占位。

这是面向重命名及有限重编译变化的特征匹配，不能证明语义等价：外部调用地址被抽象，编译器内联/优化也会改变边界与指令。报告同时提供原始函数字节 SHA-256、指纹、原符号名、镜像、架构和地址。

优先选择 ARM64，其次 ARM64e，再次 x86_64；每份报告只采用一个双方共同可读的架构，不拼接多个架构抬高命中。

### IOS-F01 主程序、扩展与第三方库

默认只计入主程序及 App Extension 的合格函数。嵌入 Framework / dylib 的函数默认不计分；显式配置 `ios.owned_framework_prefixes` 后，指定路径前缀下的自有代码才加入：

```yaml
ios:
  owned_framework_prefixes:
    - Frameworks/MyBusiness.framework/
  include_extensions: true
```

这是现有完整 `ios` 配置中的局部示例，修改时保留其余字段。前缀相对于主 `.app`。不要把整条 `Frameworks/` 当作自有范围，否则会包含广告、分析和平台运行库。

常见 `_swift_`、`__swift`、`_objc_`、`__objc`、`___`、`_OUTLINED_FUNCTION_`、`_symbolic ` 辅助符号前缀默认排除。Swift mangling 形式很多，名称过滤不能识别所有公共代码；主程序静态链接 SDK 需要通过同平台无关对照包和人工核对补充排除。

方法最少 12 条指令、4 种操作码，指纹去重、权重上限 200，与通用规则一致。无关 iOS 对照包命中的代码、资源和文本指纹从双方移除。Android 对照包不会进入 iOS 标准过滤。

### IOS-R01 资源与文本

主 `.app` 内非 Mach-O 的文件达到 256 字节，且不为 Info.plist、PkgInfo、`.plist`、`.strings` 时作为资源候选。默认排除 `Frameworks/` 与 `SC_Info/` 内容，按文件内容 SHA-256 匹配，不要求资源文件名相同。

二进制文本来自可读切片的 `__cstring`；ObjC 方法名和类名虽然记录为元数据线索，但不作为业务文本加分。可解析的 plist 格式 `.strings` 本地化值加入文本集合；OpenStep 文本格式或损坏的本地化表不会误记为解析成功，会给出未解析提示。统一空白，默认至少 12 字符、5 种字符，完全内容去重；文本不采用语义、翻译或 OCR 匹配。

Assets.car 按整文件内容比较，未解包成图片；图片重压缩、裁剪或换色不会由精确哈希识别。SwiftUI 布局与 storyboard 结构没有规范化为页面树。

### IOS-S01 公式与优先级

设 M 为 iOS 完整规范化函数的加权基准覆盖，R 为资源内容覆盖，S 为可见业务文本覆盖：

`iOS 标准分数 = 100 × (0.70M + 0.20R + 0.10S)`

iOS 不使用 Android 的 15% 指令片段辅助分，也不重复将 Mach-O 整文件计入 native 维度。缺失资源/文本不重分配权重；没有可比代码架构时整体分数不可用。一致性哈希规则优先，结果为 100。

| 优先级 | 判定 | 默认条件 |
|---|---|---|
| 1–2 | 文件/主载荷一致 | 见 IOS-I03，结论明示范围 |
| 3 | 证据不足 | 任一侧有效独立函数 <40，或没有共同可读架构，或被计入的镜像解码覆盖不足 70%，或检测到 Flutter / Unity / Hermes / React 业务盲区 |
| 4 | 高度相似 | 总分 ≥80、精确基准覆盖 ≥70%、反向覆盖 ≥55%、独立函数命中 ≥40，且资源命中 ≥3 或文本命中 ≥5 |
| 5 | 疑似代码复用 | 精确基准覆盖 ≥20%，独立函数命中 ≥15 |
| 6 | 资源或文本重合 | 资源覆盖 ≥30% 且命中 ≥3，或文本覆盖 ≥30% 且命中 ≥5 |
| 7 | 当前证据较少 | 其余具有可读代码且数量足够的样本 |

被明确排除的第三方 Framework 不因为 ARMv7 不支持而阻止主程序 ARM64 比较；但被计入的 App Extension / 自有 Framework 若不可读，则保留盲区并降级。只有主程序可见时，不能声称覆盖全部运行时业务。

## 15. Ghidra / BinDiff 深度规则

### DEEP-01 作用范围

对双方共同可读的同一架构 iOS **主可执行文件**执行 Ghidra 静态分析，使用 BinExport 导出指令、基本块及调用/控制流信息，使用 BinDiff 匹配函数。不会运行应用、从 IPA 加载系统外部库或处理加密切片；不把主程序结果推及所有 Framework 和扩展。

当前工具组合为 Ghidra 12.1.3、BinExport 源提交 `8cec8e2cf0dca87e016a3337d9a3113fb1adb439`、BinDiff 8。BinExport Java 源码针对实际 Ghidra / Protobuf 版本编译并实测，没有把旧扩展改版本号后假装已适配。

### DEEP-02 结构证据与指令证据分开

- BinDiff 原始输出中的 similarity、confidence、函数对、地址、匹配算法和函数数量按原值保存。
- “结构高匹配”定义：函数 similarity ≥0.90 且 confidence ≥0.70。统计对象仅为双方达到 iOS 标准复杂度/符号规则的主程序函数。
- 在每一对匹配函数上，额外检查双方标准规范化指纹是否相同，显示“规范化指令一致”或“结构匹配，指令不同”。这仍不是源码语义等价证明。
- 深度覆盖率按函数数量统计，不是标准分数的指令长度加权覆盖；两个数字不能混为同一口径。
- 深度匹配**不经过无关对照库删除**，不加进标准总分，不自动改变标准结论。静态链接 SDK、函数符号和模板仍需人工复核。

实测反例：自建样本修改运算与移位后，66 个有效函数中仅 1 个规范化指纹一致，但 BinDiff 仍对其余结构类似函数产生大量匹配。报告因此必须展示两类证据；只展示 BinDiff 百分比会使“结构相近”被误读为“内容相同”。

Ghidra BinExport 上游明确标注没有完整操作数树。函数结构相似度和 confidence 都不是复制概率，不能通过平均基础分与深度分制造所谓“最终置信度”。

### DEEP-03 失败、缓存与追溯

每个导出缓存固定二进制哈希、架构、Ghidra 版本及实际 Java 导出脚本、BinExport 扩展和本机反编译器内容哈希。缓存校验导出文件哈希；BinDiff 数据库也校验哈希并检查必要表。

每次深度运行有工作进程组与资源上限。取消和超限停止子进程；Ghidra 未完成导出、分析超时、缺少完成标记或 BinDiff 数据库不完整均不伪装为完成。已有标准/其他组报告保留；本组深度失败显示任务失败，可重试。

下载的深度证据包含 `.BinDiff`、双方 `.BinExport`。JSON / Markdown 保存二进制哈希、导出哈希、版本及统计；界面和文档各展示最多 100 对函数，原始数据库保留完整输出。

## 16. 跨平台配对规则

Android 与 iOS 不能将 DEX 方法指纹与 Mach-O 指纹直接比较。混合选择时仍生成报告，但只有资源和可见文本两个维度，`score=null`，结论固定为“跨平台素材与文本比对”。不依据跨端素材重合自动判定代码同源，也不进行同平台对照库自动排除。

这可以帮助发现两端共享品牌素材或独有文案，但同一字体、开源插画和模板也可能重合。若要证明跨语言移植或重新实现，需要源码、业务流程与独有实现证据；当前服务不会伪造跨端代码百分比。

## 17. 双端校准与发布验收

Android、iOS、跨平台素材任务分别评估；iOS 还应按架构、编译优化、Swift/ObjC、原生/Flutter/Unity 等分层。将加密/缺边界等弃权单独统计，不当作正确负例。默认规则只经过工程场景验证，没有你的应用就不能声称达到某个真实准确率。

推荐先上传自己的可读发布版本与改名/换资源/改业务逻辑的自有构建，再加入共享 SDK 的已知无关应用。调参集和最终验证集按应用家族分离；每次规则更新记录样本、版本、假阳性与假阴性。判断“相同”时先核对哈希范围，再审核双向业务函数证据；素材与商店信息用于支持和溯源。

官方技术来源：

- [LIEF Mach-O API](https://lief.re/doc/latest/formats/macho/python.html)：Mach-O、切片、函数与加密命令访问。
- [Capstone](https://www.capstone-engine.org/)：多架构反汇编能力。
- [Ghidra](https://github.com/NationalSecurityAgency/ghidra)：静态分析与 headless 工具。
- [BinExport for Ghidra](https://github.com/google/binexport/tree/8cec8e2cf0dca87e016a3337d9a3113fb1adb439/java)：导出器源码、用法和已知能力边界。
- [BinDiff](https://github.com/google/bindiff)：二进制函数与图匹配引擎。
- [OWASP iGoat](https://github.com/OWASP/igoat)：公开 iOS 工程验证样本来源。

阈值、评分、排除和降级策略属于本项目实现，不是上述工具的官方同源认定标准。
# 18. Android 函数实现分析（v2.1）

标准模式和深度模式都自动包含本节分析，不需要安装 Ghidra。基础加权分公式保持不变，避免把新增、尚未校准的近似算法直接当作额外加分。

**两种口径同时展示**：单函数本体的一致覆盖；进一步要求已解析的直接调用上下文一致或实现近似的覆盖。后者更严格。两者均以经过过滤、包含调用上下文的独立实现指纹为分母，按 `min(指令数, method_weight_cap)` 加权；不是源码行数比例。

1. 从实际 DEX 指令解码。局部寄存器按首次使用编号；参数寄存器按参数位置编号，保留读写位置关系。抽象应用类名、方法名和字段名，同时保留同一个引用重复出现的关系。公开 Android/Java/Javax/JSON 引用保留原值。
2. 合并编码宽度和调用 `/range`；将 `/2addr` 展开为相同的三操作数形式。保留整数常量、字符串内容哈希及填充数组内容哈希。0x7f 资源 ID 仍统一占位，不能借此确认资源语义一致。
3. 将 DEX 以 code unit 表示的跳转偏移转换到规范化指令位置；保留条件跳转、switch case 值和目标、try 范围、catch 类型及处理目标。不能完整解析控制流的函数不生成实现一致证据。
4. 在同一上传样本内跨 DEX 查找直接被调方法，用其规范化本体指纹核对**一层声明调用目标**。递归和循环不会无限展开。虚调用的实际运行时目标、反射、JNI、短小或不可解析的被调方法不作完整覆盖承诺；报告列出已解析与未解析目标数。
5. 先匹配完整实现指纹，再对剩余方法进行有界候选检索和序列比对。检索使用 5 个连续操作特征，排除出现于超过 64 个候选方法的片段，优先使用 32 个低频片段。候选至少共享 2 个片段、方法长度比 ≥65%；每个函数最多精比 12 个候选，整组最多 50,000 对。触及上限如实显示。
6. 近似方法必须同时达到指令序列 ≥90%、操作特征序列 ≥90%，且常量/数组、字符串、公开调用、分支/异常处理和已解析直接被调方法的约束指纹相同。序列相似度使用 Python `SequenceMatcher(autojunk=False)` 的匹配块比例，不称为运行语义等价或概率。双方均选唯一最佳对应，领先次佳至少 2 个百分点；候选不唯一不计入近似覆盖。
7. 最终配对一对一。指令很像但关键约束不同的配对仅供复核，分组统计差异原因。若函数本体规范化一致而调用上下文不同，会分别标明，不将它计入“连同调用上下文”的覆盖。部分相似证据不能证明整个应用相同。

| 方法证据类型 | 条件 | 含调用上下文覆盖 |
|---|---|---|
| 规范化实现一致 | 本体及已解析直接调用上下文指纹一致 | 计入 |
| 实现近似 | 两个序列阈值、关键约束与双向唯一配对同时达标 | 计入，但与一致分开统计 |
| 仅结构相近 | 两个序列达标，关键约束不同 | 不计入 |
| 本体一致，调用上下文有差异 | 属于上一类的子集 | 只进入本体覆盖 |
| 候选不唯一 / 未解析 / 未检索到 | 证据不足 | 不计为命中，也不证明不同 |

实现最长解析 4,000 条指令；超长或不可解析的有效方法保留在分母，不能删去它们来提高覆盖。短方法及复杂度过滤沿用基础规则。无关对照包的基础指纹与新增实现指纹都会用于过滤；前缀名单仍不是完整的 SDK 分类器。

报告展示最多 100 对详细函数证据，优先列出近似和结构差异，保留双侧类/方法/DEX/split 位置、指纹、序列相似度及关键约束变化。每对预览最多 6 个差异块、每块每侧 5 条指令。全部已配对函数位于 JSON 的 `function_analysis.pairs`，亦可下载 `/api/reports/{id}/functions.csv`。不会宣称预览包含全部指令或源码。

# 19. 每个分项的分档阈值与结论

下表为默认参数；报告固定记录本次使用的参数，不随之后编辑规则而改变。每项“高度重合”都要求表中三个条件**同时满足**。未达到高度档但满足部分档时，结论为“部分重合”；低于部分档且特征足够时为“已见重合较少”；缺少可比特征时显示不可用或数量不足。

| 分项 | 高度档：基准覆盖 | 高度档：待测覆盖 | 高度档：最少独立命中 | 部分档：基准覆盖 / 最少命中 |
|---|---|---|---|---|
| Android 基础代码 | ≥65%（精确口径） | ≥50% | 30 | ≥20% / 15 |
| iOS 可读同架构代码 | ≥70% | ≥55% | 40 | ≥20% / 15 |
| Android 函数实现（独立证据） | ≥70% | ≥50% | 30 | ≥20% / 15 |
| 资源 | ≥80% | ≥50% | 3 | ≥30% / 3 |
| 文本 | ≥80% | ≥50% | 5 | ≥30% / 5 |
| 原生库整文件 | ≥95% | ≥95% | 1 | ≥30% / 1 |

代码分档使用完整规范化方法覆盖，**不使用**85% 精确 +15% 片段的混合值；混合值只用于基础总分。原生库哈希高覆盖可能完全来自同一公共依赖；资源的文件哈希低覆盖也可能来自图片重压缩、编译资源重编号，不等于视觉设计不同。

Android 综合分默认分段（iOS 整体高分起点为 80，其余按本次规则生成）：

| 分数区间 | 分段解释 |
|---|---|
| 0 ≤ 分数 <40 | 可见特征重合较少，不能排除混淆或缺失代码 |
| 40 ≤ 分数 <60 | 部分特征重合，结合代码分项复核 |
| 60 ≤ 分数 <75 | 较多特征重合，尚未达到整体高分门槛 |
| 75 ≤ 分数 <90 | 高分候选，仍须通过代码覆盖、数量、支持证据和可见性门槛 |
| 90 ≤ 分数 ≤100 | 极高分候选，同样不能绕过其他门槛或代替哈希一致性检查 |

“代码高度重合、资源部分重合、整体疑似复用”可以同时成立。报告显示每项 `权重 × 覆盖 ×100` 的贡献、未获分以及整体缺少哪些门槛。某项不可用时不放大其余权重。上传文件/限定载荷完全一致触发 100 分时单独说明；其他方式算出的 100 分不表示文件字节相同。跨平台或加密 iOS 没有可比代码时，不设置整体分数结论。

可在规则编辑器修改 `function_matching`、`dimension_thresholds` 及已有代码阈值。降低门槛不是提升识别质量。阈值校准应同时使用：原包 vs 仅重命名包、同源不同版本、改资源包、相同 SDK 的无关包、只复用小模块的包，并观察假阳性与漏检。当前没有自动训练分类器。

若知道自己的业务命名空间，使用第 3 节的 `core_prefixes`，并补充已确认无关的对照包。常见依赖可按实际情况追加排除，如 `com.bumptech.glide.`、`com.airbnb.lottie.`、`com.iab.omid.`；确认没有排到自己的业务代码后再采用，不能只为提高分数挑选排除项。

# 20. v2.1 升级和可复核范围

新特征保存在 `data/features/v2.1/`。旧样本启动时排队重提取，原始文件、样本 ID、历史报告、历史规则快照及旧特征缓存保留。重新比对生成新报告，不改写历史分数。旧规则文件缺少的新字段按默认值读取；规则编辑器保存的新阈值会进入新报告的规则快照。源码交付包不包含用户 APK/IPA、数据库、特征或报告。

本次功能验证包含真实 DEX 编码的寄存器改名、常量变化、跳转变化、非法目标、返回寄存器变化；还包括直接被调方法变化、歧义候选、一对一去重、背景过滤、缺失方法分母、分档边界、CSV 注入转义、JSON/Markdown 导出及原有双端真实样本/进程恢复测试。它们验证实现，不代表已在你的目标应用分布上完成准确率校准。

算法依据：[Android DEX 指令规范](https://source.android.com/docs/core/runtime/dalvik-bytecode)、[Androguard DEX API](https://androguard.github.io/androguard/reference/androguard/core/dex/index.html)。依赖识别参考：[Glide](https://github.com/bumptech/glide)、[Lottie Android](https://github.com/airbnb/lottie-android)、[IAB Open Measurement SDK](https://interactiveadvertisingbureau.github.io/Open-Measurement-SDKAndroid/)。


## 21. iOS 指令预算与框架范围（v2.1.1）

默认仅反汇编主程序、启用的扩展，以及 `ios.owned_framework_prefixes` 明确纳入的自有 Framework。其他动态框架仍接受 Mach-O 头、加密状态和压缩包安全检查，记录文件哈希和架构；显示“规则排除，未反汇编”，不把未知函数数量伪装成零。

`limits.max_instructions` 仍默认 10,000,000。iOS 对同一架构所有纳入镜像累计计数，不同架构分别计数；`max_methods` 同样按架构累计纳入函数。指令预算计入实际解码的 nop、短函数及未完全解码函数的已处理部分，并在函数内部及时停止。超限会指出架构、当前镜像/函数、已处理数量、上限和对应配置项；不会生成截断成功结果。整个任务的 CPU、超时、内存和存储限制仍生效，Android 的计数规则保持原样。

框架排除前移到反汇编之前；iOS 标准匹配不使用的指令 shingles 不再生成或存储。函数规范化哈希和评分权重不变，不通过降低匹配门槛处理超限。嵌入主程序的静态 SDK 仍需结合符号规则和无关对照包排除，不能认为主程序里的代码全部归应用作者所有。

扩大自有框架范围或启用之前排除的扩展后，下次上传/比对会检查缓存覆盖范围；需要时自动重新提取。重新生成的特征替换当前缓存前，会把旧缓存保存在 `data/features/history/`，文件名包含原缓存 SHA-256，供历史报告追溯。旧版 iOS 提取结果会自动刷新；Android 缓存和历史报告继续保留。

检测到 Flutter 时会明确提示：Runner/原生插件的指纹不是 Dart AOT 业务实现的整体相似度。`App.framework` 可能没有 LC_FUNCTION_STARTS；当前不会凭任意固定切片猜测 Dart 函数边界。可完成样本入库与可见代码/素材检查，但总体同源结论仍受这个覆盖限制约束。


## 22. Android 多 DEX 容量与计数（v2.1.2）

`limits.max_methods` 默认 **500,000**，配置范围 100–500,000；该资源项由双端共用，iOS 仍按同一架构的已纳入镜像累计，Android 跨所有 base / split 的根目录 DEX 累计。Android 仅统计有 `code_item` 的方法定义，抽象/native 声明不计入，不能拿各 DEX 的 `method_ids_size`（含外部引用）之和当作方法实现总量。SDK 排除在 Android 的比对阶段生效；提取仍保留 SDK 指纹，便于修改规则后复用缓存，并保留直接调用上下文。

Android `limits.max_instructions` 默认 10,000,000，统计规范化指令数（nop 不参与规范化）；指令上限与方法上限独立，内存和超时也独立生效。触及任一限制都会让任务失败，并保留具体数量、配置键及 APK/DEX 位置；不会凭截断特征生成成功报告。

超限后，在工作台“匹配规则”中保存合适的容量，再重试原任务。重试仅更新资源限制，原任务冻结的评分权重、函数规则与分项门槛继续使用。只替换工程文件不会自动覆盖已有 `data/rules.yaml` 中的自定义设置。

此次扩容没有改变代码规范化、函数实现配对或相似度判定规则。大包完成提取表示支持范围内的 DEX 扫描完成，不表示已还原所有 native、动态加载或资产目录嵌套 DEX 的实现；嵌套 DEX 当前只进入资源哈希维度。


## 23. 分范围结论与整改建议（v2.2）

`review` 是独立的证据摘要，不替换原 `verdict`、`score`、`score_scope` 或规则哈希。主结论依次采用文件/载荷一致、整体高相似、已达到原分项标准的匹配结果；若没有分项达到标准则说明当前未达标或缺少可比较数据。加密、Flutter、原生主导等盲区不抹去资源/文本的正向结果，也不会被它们补成“代码相同”。整体状态始终独立列出。

高匹配提醒复用报告生成时冻结的分项阈值；不新设更宽松标准。任一方向的覆盖率到线且有匹配项即提醒检查。双向覆盖和独立命中数全部达标为 high_overlap，只有部分方向达到为 one_sided，命中数不足为 small_sample。单看命中数超过最小数量不触发高比例提醒。函数本体按现有 function_matching 阈值单列，不能替代调用上下文或整个应用的行为判断。

每条提醒最多展示 5 个已有命中位置（不是全部命中），文本预览最多 300 字符。完整证据仍由 JSON/函数 CSV 保留原有范围。建议按维度生成：代码核查具体实现和依赖来源，素材/文本核查原创与授权来源，原生库核查供应商及自有代码；自查时处理确认未授权的复用，检测他人包时保存版本、来源和对应位置。只根据来源证据排除公共特征，不能为降低分数任意删除命中。

已有报告在读取时用自身快照补充摘要；不重新计算原分数、不修改数据库内历史记录、不读取当前规则替换历史阈值。已有完整 v2/v2.1 报告可直接看到建议；更早的缺字段记录继续原样提供，不制造不存在的指标。没有新增 Dart AOT 函数恢复，未覆盖范围必须继续保留。
