长期记录和更新安卓 HTTPS 抓包相关的内容与笔记。
由来
网上好多文章比较水,只知道照抄步骤。这里以科普、重点和笔记的形式写下安卓 HTTPS 抓包那些事,方便有各方面基础的人快速上手安卓抓 HTTPS 包。
原理相关
基于逆向、协议逆向以及实现某些 app 自动化等需求,往往需要抓取指定 app 的 HTTPS 包才能完成。本文只讨论 HTTPS 抓包本身,涉及 apk 对设备 root 与反调试检测的就不展开了。
中间人
抓 HTTPS 的方式大致分为两类:hack 与非 hack。
- hack 方式:例如基于 eBPF 的 gojue/ecapture,在 client 端 hook 相关 SSL 即可解密 HTTPS 报文,另外例如 frida hook app。
- 非 hack 方式:例如中间人攻击。
eBPF 需要较高内核版本且有对应内核模块支持。网上很多人用 root、KSU 等,却很少去编译内核增加 ebpf 的支持,所以这种方式很难普及, frida 的话要写注入逻辑,一般要电脑配合且要懂点编程和逆向基础。而中间人攻击的原理是:
1 | 客户端 攻击者 服务器(https://example.com) |
- 客户端向服务器发起 HTTPS 请求,中间人伪装成服务器完成 TLS 握手,拦截并解析数据;中间人再以客户端身份与真实服务器通信,在服务器看来就是普通的一个客户端在访问自己。
- 攻击者自签 example.com 的 TLS 证书并回复给客户端。
- 客户端后续发送的
https://example.com/api等请求,攻击者解密后再向服务器请求,拿到数据后以 HTTPS 形式回给客户端。 - 从开发视角看,中间人相当于以明文查看 HTTPS 请求,可拦截请求与响应,也可针对某些 URL path 做策略。
HTTPS 刚普及时,很多客户端不校验中间人证书是否由权威 CA 签发(用浏览器访问会看到红色警告)。后来普遍校验证书后,做中间人时需要在 Linux 上把自建 CA 加入 /etc/ssl/certs/ca-certificates.crt 等系统信任链。
安卓的凭据
例如在 Windows 电脑上用 Fiddler,在电脑里加入 Fiddler 的 CA 后,Fiddler 可以抓浏览器或进程的 HTTPS 报文。Linux、Windows、安卓本质都是同一套中间人原理,只是细节不同。在安卓上,CA 以「凭据」形式存在,路径是:设置 → 系统安全 → 凭据存储 → 信任的证书,分为「系统」和「用户」两类。
安卓 7.0 起不再信任用户安装的 CA,需要把 CA 放进「系统」凭据。需要手机 root,可用 MT 管理器 或 adb shell(root)把 CA 放到 /system/etc/security/cacerts/。
SSL Pinning
部分 app 不信任系统凭据或对服务器证书做校验,可能还需要配合 LSPosed 和 Magisk 模块(如 JustTrustMe、TrustMeAlready)hook 应用内的 X509TrustManager、okhttp3 等跳过证书校验。会 Frida 的话也可以直接 Frida hook。
高版本安卓的凭据
在安卓 15 + KSU 上试过 Reqable:左上角菜单 → 证书管理 → 安装证书,我选的是手动复制证书文件,证书会保存到 Download/Reqable/xxxxx.0。KSU 授权 com.android.shell 取得 root 后,在 adb root shell 里仍无法把证书推到 /system/etc/security/cacerts/,用 MT 管理器移动也会报「挂载读写失败」。
查资料得知有人分析 framework.jar 发现从安卓 14 起证书目录是 /apex/com.android.conscrypt/cacerts,但试了下依然无法直接写入。继续查发现 /apex 有更严格的系统分区保护,即便 root 后 remount 也改不了。后来看到做法是:先装 OverlayFS MetaModule,再装 MoveCertificate,把证书放到 /data/local/tmp/cert/ 下重启,就能在系统凭据里看到新 CA。
看了下 MoveCertificate 的 post-fs-data.sh,是通过 tmpfs 覆盖挂载 /apex/com.android.conscrypt/cacerts 并配合 SELinux 权限完成凭据列表的注入,前提是已安装 OverlayFS MetaModule。另外我试过只 ksu 里关掉 OverlayFS 模块不关别的,手机重启会起不来。
然后把 Reqable 记录模式选成 V-P-N,应用指定微信,开启增强并启动抓包,打开微信和小程序,发现抓到的全是 CONNECT,点进请求显示 SSL 握手失败,说明 CA 没被正确信任。后来试了 Reqable 生成的 Magisk 模块刷入,并取消使用 MoveCertificate 模块,重启后就能正常抓到了。
安卓原理和工具选项
模拟器和安卓上开虚机抓包不讨论,如果你看懂了原理又嫌弃 root 麻烦,可以自行查看相关文章。
指定 app 抓包原理
安卓上「指定 app 走代理」的实现原理可以看我之前的文章 开发一个让指定应用走代理的安卓 app 过程。安卓的 VPNService 本身支持让指定 app 走类似 Linux /dev/tun 的通道,应用开发者只需实现相应逻辑即可。
工具选型
有人会把 Fiddler 的 CA 导入手机,电脑跑 Fiddler,手机 WiFi 代理指向电脑的 Fiddler 端口。但不少 apk 会检测 WiFi 是否设置了代理,一旦发现就不走代理,导致抓不到该 app 的 HTTPS,所以更稳妥的方式还是:在安卓上装抓包/代理软件,用 VPNService 指定 app,再做中间人拦截。
微信小程序的鉴权里,code 不能重复使用(QQ 的似乎可以),所以常需要抓包拦截住请求不让它发出去,然用请求里的 code 在代码里去使用。我调研了一下,以下是搜到的对比:
| 软件 | 开源 | UI 和功能 | CA 相关 |
|---|---|---|---|
| Reqable | 未开源,前身是 HttpCanary | UI 现代,请求查看体验较好。需 VIP 解锁全部功能(只有价格说明没具体有哪些功能) | 安装后 CA 随机生成这点不错,并且支持生成 magisk 模块;PC 端 USB 装证书到手机疑似通过 adb root 完成,无手动步骤,比较担心被注入不好的东西 |
| proxypin | 开源 | UI 现代,请求查看不如 Reqable 细致,但支持断点、重写请求 | apk 完全可以像 Reqable 那样生成一个 magisk 模块,而不需要让人去下载注入CA 的 Magisk-ProxyPinCA 模块。 apk 生成的 CA 与 Magisk-ProxyPinCA 内的CA 是固定而不是随机的,可能是一个安全隐患点 |
理清原理后,甚至可以自己搭一套分布式抓包方案,例如:
- 在 Linux 上写/部署一个带中间人能力的 SOCKS5 服务端;
- 复用或开发开源安卓代理 app(如 appproxy);
- 手机安装上述 CA,启动 appproxy,让待抓包的 app 走代理,上游指向该 SOCKS5;
- SOCKS5 收到流量后做中间人解密,并在 Web 端展示。既利用了安卓的指定 app 走代理,又可以专心开发服务端,不需要过多关注安卓方面。
这里举例是想表明工具只存在功能细节上的差异,不存在某个工具可以做到某个工具不可以的说法。
一些题外话
这些模块可能会在 /data/local/tmp 下创建目录用来注入 CA。若 apk 检测这些路径或系统凭据里是否出现这类 CA 名称,可能被用来做 root/环境检测。所以不抓包时记得把相关模块关掉。