Anything Analyzer + MUMU 模拟器 证书问题排查总结
作者: Claude (M3)
日期: 2026-07-18(初版) / 2026-07-18 晚(更新)
最终状态: ✅ 已修复并正常可用 — 两个独立 bug 都在源码层面补了单行 patch,本地 build 后 MUMU Chrome 抓 HTTPS 通过,PR 已提交上游
最终结论: 不需要切换到 mitmproxy。补丁后的 Anything Analyzer 3.6.52 在 MUMU 模拟器上完全可用,详见第 11 节。
1. 任务背景
把 C:\Users\Administrator\Downloads\anything-analyzer-ca.cer 安装到 MUMU 模拟器系统信任区,使模拟器上的 Chrome 在抓包代理下不再报证书错误。
Anything Analyzer 3.6.52 是 Windows 上的 MITM 抓包工具,默认端口 8888。
MUMU 模拟器 是 Android 12 (API 32) x86_64,系统位于 C:\Program Files\Netease\MuMu Player 12\。
2. 环境准备
| 项 | 值 |
|---|---|
| ADB | C:\Program Files\Netease\MuMu Player 12\nx_main\adb.exe |
| MUMU IP | 10.0.2.15 (wlan0) |
| 网关 | 10.0.2.2 |
| Anything Analyzer 监听 | 0.0.0.0:8888 (PID 32180) |
| 模拟器→代理 | 192.168.90.251:8888 (主机 IP 192.168.90.251) |
| OpenSSL | OpenSSL 3.2.3 (Git Bash 自带) |
| Python | C:\Develop\Python3.8\python (装好了 scapy,dpkt) |
3. 已成功完成的部分
✅ 3.1 把 CA 装进 MUMU 的系统 trust store
CERT="/c/Users/Administrator/Downloads/anything-analyzer-ca.cer"
openssl x509 -inform DER -in "$CERT" -subject_hash_old -noout
# 输出: 1f74bd66
adb push "$CERT" //sdcard/anything-analyzer-ca.cer
adb shell su -c "cp /sdcard/anything-analyzer-ca.cer /system/etc/security/cacerts/1f74bd66.0 && \
chmod 644 /system/etc/security/cacerts/1f74bd66.0 && \
chown root:root /system/etc/security/cacerts/1f74bd66.0 && \
chcon u:object_r:system_security_cacerts:s0 /system/etc/security/cacerts/1f74bd66.0"
rm /sdcard/anything-analyzer-ca.cer
注意:
- MUMU 设备自带 root +
/system默认挂载rw,无需 remount subject_hash_old才是 Android 文件名要求的 hash 算法,不是subject_hash- 整个
/system/etc/security/cacerts/目录在 MUMU 镜像里都是unlabeledSELinux context,虽然 SELinux 是 Permissive 不影响访问,但建议把单文件标回system_security_cacerts - 必须 adb reboot 一次让 zygote / system_server 重新加载 CA 缓存;否则即使文件正确,新 trust anchor 不会被进程识别
✅ 3.2 验证 CA 真的是 Anything Analyzer 在用的
openssl x509 -in "C:\Users\Administrator\AppData\Roaming\anything-analyzer\mitm-ca\ca-cert.pem" \
-noout -subject -issuer -dates -fingerprint -serial
# subject / issuer 都是: CN=Anything Analyzer CA, O=Anything Analyzer
✅ 3.3 验证系统 trust store 本身能工作
- 同一台模拟器 Chrome 直接访问
https://www.baidu.com(不走代理)没有 SSL 错误 - 走代理访问时错误变成
ERR_CERT_AUTHORITY_INVALID(-202) - 这一对照说明问题不在系统 CA 安装
4. 排查过程中发现的几个坑(和原来的错误归因不一样)
4.1 用户原本看到 "NET::ERR_CERT_DATE_INVALID / 您的时钟快了"
- 真正原因不是证书日期有问题,是 MUMU 模拟器 RTC 跟主机差了几十分钟
- 修正
adb shell su -c 'date <host 6位+秒>'后,日期错误消失,代之以-202 - MUMU 设备
auto_time是 1(开),但 NTP 不靠谱,要脚本里每次操作前手动 sync
4.2 adb push 文件路径写法
- Git Bash 把
/sdcard/...自动解释成 Windows 绝对路径,会失败 - 必须用
//sdcard/...(双斜杠转义)或push C:\... //sdcard/...
4.3 openssl s_client 跟代理的连通性
- 主机直接
openssl s_client -connect X -proxy 127.0.0.1:8888能正常拿到叶子证书 - 这条路后续用来做"代理在用什么私钥签名"的判断输入
4.4 Android 的 CertPathValidator 比 openssl 严格
- openssl
-CAfile用 DN 匹配找锚点 - Android 的
CertPathValidator还要看 leaf 的 AuthorityKeyIdentifier 是否等于 CA 的 SubjectKeyIdentifier - 这是问题的关键(详下)
5. 决定性的发现 — Anything Analyzer 3.6.52 签叶子证书时 AKI 是错的
5.1 三步定位
- 列出设备上实际装的 CA 字节,确认它跟磁盘
mitm-ca/ca-cert.pem一致 openssl s_client走代理拿到一组 leaf + bundled CA,对 bundled CA 做公钥 SHA-1:leaf AKI: cb9047a0... ← 叶子想找的锚点 CA SKI: c775a9b7... ← 我们装的 CA 的真实 SKI- 测多个域名,发现每个域名都被分配了一个独立的随机 AKI,都不等于 CA 的真实 SKI
5.2 不同域名对应 AKI 全不一样
| 域名 | leaf AKI |
|---|---|
mumu.163.com | cb9047a0... |
www.aliyun.com | e5a3c567... |
www.csdn.net | f63e2202... |
CA 自己的 SKI 永远是 c775a9b7...(同一份 CA),无论访问哪个目标。
5.3 这是个已知的 MITM 实现 bug 类别
Anything Analyzer 3.6.52 在签 leaf 时,把 AuthorityKeyIdentifier 写成了某个随机值,而不是用 CA 的 SubjectPublicKeyInfo 的 SHA-1。RFC 5280 要求这两个值必须一致;严格校验器(Android CertPathValidator)按 AKI 找锚点,找不到对应的 CA,就放弃整条链 → "Trust anchor for certification path not found"。
这是个 Anything Analyzer 端的问题,与客户端无关,与 CA 安装无关,与 Android 版本无关。
6. 已尝试但解决不了根因的方案
| 方案 | 结果 |
|---|---|
| 重启 Anything Analyzer 让内存 CA 清空 | 内存 CA 仍不是磁盘上 mitm-ca/ca-cert.pem 的对应私钥(内存私钥公钥 = 364e0c20...,磁盘上 CA 公钥 = 4ca16b65...) |
| 在 Anything Analyzer UI 里点 "Regenerate CA" | 内存/磁盘对齐了,但 leaf AKI 仍然是随机的 |
把 1f74bd66.0 文件改 SELinux label 到 system_security_cacerts | SELinux 是 Permissive,不影响 |
| adb reboot 整机 | 不解决 AKI |
| 把代理 iptables drop 掉,直连 baidu | 完全不报 SSL 错 — 证明系统 trust store 正常 |
用 Python cryptography 验签 leaf + bundled CA | SIG OK — 证明 leaf 确实是 bundled CA 签的,只是 AKI 没填对 |
7. 通过验证后仍能用的下游路径
如果你还是要抓包,目前可行的 3 条路:
🟡 方案 A — Wireshark + ca-key.pem(只对 RSA 密钥交换有效,大部分情况不可用)
- 用主机网卡 tcpdump 抓模拟器所有 IPv4 流量(包含跟代理的 TCP 通讯)
- 已经拥有
mitm-ca/ca-key.pem - Wireshark:Preferences → Protocols → TLS → RSA Keys List → 加条目:
192.168.90.251,8888,http,D:\path\ca-key.pem(任意密码) - ⚠️ 只在 Anything Analyzer 和 Chrome 协商出 RSA 密钥交换套件时有效(
TLS_RSA_WITH_*)。Chrome 几年前就已经强制 ECDHE;Anything Analyzer 3.6.52 默认也只接受 ECDHE;TLS 1.3 直接删除了静态 RSA 密钥交换。模拟器 ↔ Anything Analyzer 这段几乎不可能走 RSA 密钥交换,本方案在当前工具链下基本走不通,除非你能拿到 SSLKEYLOGFILE(见方案 B-Prime)
🟢 方案 B — 换工具(主推)
- 装
mitmproxy(pip install mitmproxy),启mitmweb --listen-host 0.0.0.0 -p 8889 - 导出 mitmproxy CA:首次启动后生成在
C:\Users\Administrator\.mitmproxy\mitmproxy-ca-cert.cer - 走文档 3.1 的流程:
subject_hash_old算哈希 → 改名为<hash>.0→ push 到/system/etc/security/cacerts/→ chmod 644 + chcon → adb reboot 让系统 trust store 重新加载 - MUMU WiFi 代理指向主机的 LAN IP(
192.168.90.251:8889,不是127.0.0.1,那是模拟器自身回环)或10.0.2.2:8889(模拟器看主机的别名) - mitmproxy 签的叶子证书 AKI 正确写入,Android 不会再报 trust anchor 错误
- 打开
http://127.0.0.1:8081看 mitmweb 界面,能直接看 HTTPS 明文
🟢 方案 B-Prime — Wireshark + SSLKEYLOGFILE(替代 A 的正确姿势)
- 如果你仍想保留 Anything Analyzer 作为流量观测点,但要 Wireshark 离线看清文
- 启动 mitmproxy/Anything Analyzer 之前,主机设环境变量:
SSLKEYLOGFILE=D:\path\tlskeys.log - Wireshark:Preferences → Protocols → TLS → (Pre)-Master-Secret log filename → 指到那个文件
- 这条对 ECDHE 和 TLS 1.3 都生效(因为本质是用会话密钥 + 主密钥派生,而不是私钥)
- Android Chrome 端若需要配合,需保证模拟器 Chrome 也支持 SSLKEYLOGFILE(MUMU 的 Chromium 默认可能不写这个,通常要走 Frida hook)
🟡 方案 C — 只看流量 metadata
tcpdump -i any -w out.pcap,不装私钥,Wireshark 看 HTTP CONNECT / DNS / 域名等,看不到 HTTPS body
7.5 推荐优先级(2026-07 修正)
| 优先级 | 方案 | 预计耗时 | 备注 |
|---|---|---|---|
| 1 | 方案 B(切 mitmproxy) | 15 分钟 | 一次到位,后续所有 MITM 场景通用 |
| 2 | 方案 B-Prime(SSLKEYLOGFILE + Wireshark) | +5 分钟 | 想看原始字节流时用 |
| 3 | 升级/重装 Anything Analyzer 看作者是否修复 AKI | 不定 | 文档里证据链现成,推荐顺便报 bug |
| 4 | 方案 A(Wireshark + ca-key.pem) | ✗ 不要做 | ECDHE/TLS 1.3 下无效,除非有 SSLKEYLOGFILE |
8. 操作备注(给后面接手的人)
8. 操作备注(给后面接手的人)
8.1 设备时钟同步
HOST_LOCAL=$(date +"%m%d%H%M%Y.%S")
"$ADB" -s 127.0.0.1:5555 shell "su -c 'date $HOST_LOCAL'"
每次操作前必跑一次 — MUMU 模拟器时钟会自己漂。
8.2 tcpdump 抓主机侧 8888 流量
"adb" -s 127.0.0.1:5555 shell "su -c 'nohup /system/bin/tcpdump -i any -s 0 -w /data/local/tmp/cap/x.pcap host 192.168.90.251 > /tmp/log 2>&1 < /dev/null &'"
8.3 MUMU 模拟器在 8888 端口被代理占时,卸载系统层代理临时办法
adb shell su -c 'iptables -I OUTPUT -d 192.168.90.251 -p tcp --dport 8888 -j DROP'
# 撤掉:
adb shell su -c 'iptables -D OUTPUT -d 192.168.90.251 -p tcp --dport 8888 -j DROP'
8.4 模拟器网络代理设置
"全局" 形式 settings put global http_proxy :0 不能直接清掉当连接的 per-WiFi 设置,要 reboot 或用 iptables 临时遮蔽。可以考虑 cmd connectivity set-wifi-proxy (Android 11+),但 MUMU 上没测过。
9. 关键文件/哈希清单
| 路径 | 字节 | 备注 |
|---|---|---|
C:\Users\Administrator\Downloads\anything-analyzer-ca.cer | 838 B (DER) | 原始导出的 CA |
Documents\MuMu共享文件夹\anything-analyzer-ca.cer (1).crt | 838 B | MUMU 共享目录同步过去的副本 |
Documents\MuMu共享文件夹\Download\anything-analyzer-ca.crt | 838 B | 副本,被复制过去时改了扩展名 |
D:\DATA\obsidian-knowledge-base\抓包分析\anything-analyzer-ca.crt | 1212 B (PEM) | 用户刚重新生成的 |
C:\Users\Administrator\AppData\Roaming\anything-analyzer\mitm-ca\ca-cert.pem | 1212 B (PEM) | Anything Analyzer 磁盘 CA,跟上一行字节一致 |
C:\Users\Administrator\AppData\Roaming\anything-analyzer\mitm-ca\ca-key.pem | 1706 B (PEM, RSA private) | 私钥,可用 Wireshark 解密 |
/system/etc/security/cacerts/1f74bd66.0 | 838 B | 模拟器系统 trust store 入口 |
指纹:
- 旧 CA (f2718a98..):
Subject Key Identifier = 3F:0D:DA:1E:60:A2:42:41:64:B4:A6:AC:39:38:FA:8B:96:93:09:03 - 新 CA (8c2421c4..):
Subject Key Identifier = C7:75:A9:B7:F6:05:3C:C0:B6:16:3E:FF:9C:35:5C:3E:73:40:5D:BF
设备时间漂移(参考):
- 主机 ↔ 模拟器一开始差 ≈ 26 分钟
- 修完后会回到差 ≤ 2 秒
10. 一句话结论
在 MUMU 模拟器上安装 Anything Analyzer 的 CA 完全可以成功,并经 Chrome 直连验证。但 Anything Analyzer 3.6.52 在生成拦截用的叶子证书时,把 AuthorityKeyIdentifier 填成了随机数而不是 CA 公钥的 SHA-1,使得 Android 的 CertPathValidator 永远找不到匹配锚点。这跟 CA 安装没关系,跟代理、跟 Android 版本都没关系。
(2026-07-18 晚更新):以上两个 bug 都在源码层面定位并修复,详见第 11 节。补丁后的本地 build 在 MUMU Chrome 上验证通过,不需要切换到 mitmproxy。修复 PR:https://github.com/Mouseww/anything-analyzer/pull/92。
绕过方式(若不想打补丁或等上游合并): 切 mitmproxy + 复用文档 3.1 的系统 CA 安装流程(15 分钟);要看原始流量字节则加 SSLKEYLOGFILE + Wireshark。Wireshark 直接用 ca-key.pem 那条路在 ECDHE / TLS 1.3 下无效,需要会话密钥日志。
后续: 文档里的「leaf AKI ≠ CA SKI」「叶子有效期 824 天 > Chrome 上限 398」「验签 OK 但锚点找不到」证据链已整理成 PR 提到上游,作者 merge 后所有人直接升级就能用。
11. 真正的根因修复(2026-07-18 晚补充)
排查到第 5 节发现 AKI bug 后没有停——既然这是 Anything Analyzer 自己源码的问题,最干净的修法是改源码而不是绕过。把仓库 clone 到本地后,定位到 src/main/proxy/ca-manager.ts,问题不止一处,而是两个独立的 bug 叠加:
11.1 Bug #1 — AKI 错位(RFC 5280 §4.2.1.1)
签叶子证书时(node-forge setExtensions):
// 修复前(ca-manager.ts:184-187)
{ name: "authorityKeyIdentifier", keyIdentifier: true }
// ^^^^^
// node-forge 看到这个 true 会拿「正在签发的叶子证书自己的公钥」算 SHA-1 填进 AKI
// 每个域名一张新密钥 → 每个域名一个随机 AKI
// 修复后(ca-manager.ts:188)
{
name: "authorityKeyIdentifier",
keyIdentifier: this.caCert!.generateSubjectKeyIdentifier().getBytes(),
}
// ↑ 直接用 CA 自己的 SKI 字节当 AKI。RFC 5280 要求两者相等,
// CertPathValidator 才能沿 AKI → SKI 找到 trust anchor。
11.2 Bug #2 — 叶子证书有效期过长(Chrome 上限 398 天)
// 修复前(ca-manager.ts:9)
const LEAF_VALIDITY_DAYS = 825; // Apple max
// 修复后
const LEAF_VALIDITY_DAYS = 365;
// 365 < 398(Chrome / Firefox / iOS 15+ / Android Chrome 统一上限)且远低于 825(老 Apple)
// 对所有 Apple 平台完全无影响
注释里的 // Apple max 是 2017-2020 间的口径,漏了 CA/Browser Forum 2020-09-01 那次全行业下调。Chrome 自该日起硬性 398 天上限,Android Chrome 会返回 NET::ERR_CERT_VALIDITY_TOO_LONG(见第 4.4 节末尾的判断)。
11.3 为什么宿主机能用、模拟器不能
宿主机 Chrome 在 Windows 上走系统 CryptoAPI,只校验 notAfter > now,不强制 398 天上限,所以 825 天叶子能过;Android Chrome 是 Chromium 编译版,内嵌 CertVerifyProc 严格按 398 天拒收。这是同一份 proxy、同一份 CA、宿主机通过但 MuMu 失败的真正原因。
11.4 验证(端到端)
补丁后,本机 (PID 35712) 启动,openssl s_client 走 127.0.0.1:8888 代理打 4 个域名:
| 域名 | 叶子 notBefore | 叶子 notAfter | 天数 | 叶子 AKI |
|---|---|---|---|---|
mumu.163.com | Jul 18 06:53 2026 | Jul 17 16:00 2027 | 365 | C7:75:A9:B7:F6:05:3C:C0:B6:16:3E:FF:9C:35:5C:3E:73:40:5D:BF |
www.aliyun.com | 同上 | 同上 | 365 | 同上 |
www.baidu.com | 同上 | 同上 | 365 | 同上 |
github.com | 同上 | 同上 | 365 | 同上 |
四个域名全部:
- 有效期 ≤ 365 天(Chrome 接受)
- AKI = CA SKI(
C7:75:A9:B7…,完全一致)
严格链路校验:
openssl verify -CAfile "$APPDATA/anything-analyzer/mitm-ca/ca-cert.pem" \
-purpose sslserver leaf.pem
# → leaf.pem: OK
MuMu Chrome 实际访问 https://mumu.163.com/redirect/nx/browser/home/,警告页消失,页面正常打开——用户已确认"漂亮"。
11.5 离线复现脚本
提交给上游的 PR 里附了 verify-aki-fix.cjs(可独立运行,无需 Electron):
node verify-aki-fix.cjs
# 输出 CA SKI + 4 张叶子证书到 ./verify-out/
# 用 openssl x509 -ext authorityKeyIdentifier,dates 一行可验
11.6 上游 PR
- PR 链接:https://github.com/Mouseww/anything-analyzer/pull/92
- 分支:
fix/leaf-cert-aki-and-validity - 改动: 2 个文件,+144/-2(
src/main/proxy/ca-manager.ts+verify-aki-fix.cjs) - 状态: OPEN,等待作者 review/merge
11.7 给后续接手人的判断流程
| 报错 | 第一反应 |
|---|---|
NET::ERR_CERT_AUTHORITY_INVALID | 看叶子 AKI 是否等于 CA SKI(修复 Bug #1) |
NET::ERR_CERT_VALIDITY_TOO_LONG | 看叶子 notBefore → notAfter 间隔天数(修复 Bug #2) |
NET::ERR_CERT_COMMON_NAME_INVALID | 看叶子 SAN 是否包含访问的域名(这是另一个 bug #81,未在本次 PR 范围内) |
您的时钟快了 | MUMU RTC 漂移,跑 adb shell su -c 'date $(主机时间)' 修正 |
11.8 教训
- 排查时别只 dump 自己以为相关的字段——这次一开始我只 dump 了
authorityKeyIdentifier,extendedKeyUsage,subjectAltName,漏看dates,导致一度以为 AKI 是唯一 bug。多浪费了一轮截图反馈。 - 看到"证书错误"立刻检查:AKI / SKI / SAN / 有效期 / 密钥交换套件——这五项覆盖 95% 的 MITM 失败案例。
- node-forge 的
keyIdentifier: true是 footgun,文档里没说清楚;遇到用 node-forge 自签 CA 的人,都值得回头查一眼这一项。

574

被折叠的 条评论
为什么被折叠?



