☰
Android 7.0+ HTTPS抓包乱码?三步把Burp证书装进系统根证书
2026/10/1 2:09:19 网站建设 项目流程

刚接触手机抓包的时候,最容易卡住的往往不是Burp怎么装,而是当你把一切配置妥当、信心满满地打开APP操作一轮,回到Burp的HTTP history一看,满屏的CONNECT记录,点开全是乱码。这就是典型的证书信任问题:Android 7.0之后系统默认不信任用户安装的CA证书,你在手机里手动装的Burp证书,对大部分APP来说等于没装。这篇文章就把这件事彻底讲透:为什么必须要系统根证书,怎么把Burp的CA证书转换成安卓认识的格式,以及三种不同设备条件下的安装路线和常见坑。

1. 为什么 HTTPS 抓包会变成一片乱码——用户证书与系统证书的差别

1.1 先看现象:设好了监听,却只抓到一堆 CONNECT

我先描述一下最常见的翻车现场。你打开Burp Suite,在Proxy选项卡的Proxy Listener里添加了一个监听地址,一般是0.0.0.0:8080,然后在同一局域网内的安卓手机上,进入WiFi设置,把网络的手动代理指向电脑的IP和8080端口。到这里为止,操作完全正确。

接着你在手机上打开任意一个APP,随便点两下,切回Burp的HTTP history,你会发现里面确实有记录,但几乎全是CONNECT开头的请求,点开Response栏,没有任何可读的数据,有时候是一堆看不懂的二进制。如果用的是Burp的默认配置,你还会看到提示说客户端没有发送完整的请求。

这个现象的本质并不是代理没配上,也不是Burp坏了,而是HTTPS流量经过代理时,客户端和Burp之间建立TLS隧道需要先通过CONNECT方法建立连接。连接建立之后,Burp需要向客户端出示自己的CA证书来解密流量。但如果客户端不信任这个CA,就会直接掐断握手。结果就是你在Burp里看到的只有一堆空洞的CONNECT记录。

1.2 Android 7.0 起信任机制的改变

问题出在Android系统的证书信任策略上。系统里有两个完全不同的证书仓库:

  • /system/etc/security/cacerts/:系统级CA证书仓库,存放出厂预置的、被系统认定为可信的根证书。
  • /data/misc/user/0/cacerts-added/:用户级CA证书仓库,存放用户手动安装的证书。

在Android 6.0及更早的版本里,APP对这两个仓库里的证书是一视同仁的,都会信任。所以那时候你只要在手机浏览器里访问http://burp,下载并安装Burp的CA证书,就能直接抓HTTPS明文。

Android 7.0(API 24)开始,Google收紧了策略:APP默认只信任系统级CA证书,不再信任用户手动安装的证书。也就是说,你在手机上装的那个Burp证书,对绝大多数APP来说根本不起作用。这就是为什么需要把Burp的CA证书塞进系统证书目录,也就是标题里说的“系统根证书”。

安卓版本默认信任用户CA证书手动安装证书后能否直接抓HTTPS
Android 6.0及以下是可以
Android 7.0否基本不行
Android 8.0 - 9.0否不行
Android 10 - 14否不行
Android 15否不行,且证书目录管理更严格

所以,整篇文章的核心只有一件事:把Burp的CA证书以正确的文件名、正确的权限放进/system/etc/security/cacerts/目录。文件放进去了,系统就把Burp的CA当作和DigiCert、Let's Encrypt同级的可信根证书,HTTPS流量才能在Burp里还原成明文。

2. 动手前的环境准备:版本确认与工具清单

2.1 先搞清楚三件事

在动手之前,我建议你先花两分钟确认三件事:系统版本、root状态、有没有Magisk。这三件事直接决定你该走哪条安装路线。

查看系统版本很简单,手机连着电脑,执行:

adb shell getprop ro.build.version.release

看root状态,执行:

adb shell "su -c id"

如果返回uid=0(root),说明有root权限。如果提示su: not found或permission denied,说明没root。另外在设置里看看有没有Magisk应用,Magisk是现在最主流的root方案,它不仅能提供root权限,还能通过模块机制在不改动系统分区的情况下注入系统文件,这对添加系统证书来说非常有用。

为什么要先确认这些?因为不同状态对应不同方案:

  • 有root,有Magisk:走Magisk模块路线,最干净、最好回滚。
  • 有root,没Magisk:直接挂载系统分区,把证书文件复制进去。
  • 没root:只能用模拟器方案,或者考虑先给手机装Magisk。

2.2 工具清单

我整理了一份工具清单,按重要性排序:

工具用途版本建议
Burp Suite抓包工具本体Community版或Professional版均可
adb platform-tools手机与电脑通信建议最新版
OpenSSL证书格式转换、计算hash文件名1.x或3.x均可
Magisk向系统注入证书文件已root设备强烈建议
一台安卓设备测试目标真机或模拟器均可

Burp Suite可以直接从官方渠道下载,Community版足够完成基本的抓包和证书导出。adb platform-tools在Android开发者官网就能拿到。OpenSSL在Windows上可以用Git自带的bash里的openssl,或者用WSL,macOS和Linux直接终端里就有。

2.3 让手机进入可调试状态

接下来说说准备工作里最容易被忽略的细节。手机进入开发者模式的操作是:设置里找到“关于手机”,连续点击版本号7次,然后返回设置菜单,就能看到“开发者选项”。

进入开发者选项后,打开“USB调试”。部分手机上还有一个“仅充电模式下允许ADB调试”的选项,一并打开。用数据线连接电脑,执行:

adb devices

如果看到device状态而不是unauthorized,说明一切正常。第一次连接时手机上会弹出USB调试授权窗口,需要手动确认并勾选“始终允许”。

这里有个小建议:如果测试用的是一台闲置手机,建议在开发者选项里把“屏幕保持唤醒”和“自动系统更新”都关掉,防止测试过程中系统自动更新导致环境变化。

3. 证书格式转换的全过程:从DER到PEM再到重命名

3.1 从Burp导出一张DER格式的CA证书

Burp的CA证书导出入口在Proxy设置里。打开Burp Suite,进入Proxy -> Proxy Settings,往下找到Certificate相关区域,点击“Import / Export CA certificate”,在弹出的窗口里选择“Export”,然后选择“Certificate in DER format”,指定导出路径,比如cacert.der。

导出的DER文件是二进制格式,安卓系统证书目录里需要的是PEM格式,也就是Base64编码的文本格式。之所以要这个步骤,是因为我们后面要用OpenSSL计算证书的hash值作为文件名,而OpenSSL处理PEM格式更顺手。

3.2 用OpenSSL完成格式转换和hash命名

打开终端,进入证书文件所在目录,先做格式转换:

openssl x509 -inform DER -in cacert.der -out cacert.pem

转换完成后,计算这个证书的主题hash值。安卓系统证书目录里的文件名规则是<hash>.0,其中hash是证书Subject的哈希值,算法是subject_hash_old:

openssl x509 -inform PEM -subject_hash_old -in cacert.pem

执行后会输出一串十六进制字符,比如9a5b5752。注意,这里必须用subject_hash_old,而不是subject_hash。安卓系统在命名证书文件时使用的哈希算法是MD5-based的旧版算法,用subject_hash算出来的结果完全不一样,会导致系统无法识别。

得到hash值后,把PEM文件重命名:

mv cacert.pem 9a5b5752.0

到这里,证书格式转换就完成了。这个9a5b5752.0就是我们要往系统目录里塞的文件。

3.3 一条命令直接生成最终文件

为了避免每次手动敲命令记错参数,我通常把整个过程写成一串命令:

openssl x509 -inform DER -in cacert.der -out cacert.pem hash=$(openssl x509 -inform PEM -subject_hash_old -in cacert.pem | head -1) cp cacert.pem "$hash.0" echo "生成的文件名: $hash.0"

这个脚本的逻辑很简单:先转格式,再算hash,最后复制成hash.0。执行完之后,当前目录下就是可以直接推到手机里的最终证书文件。

有一点要提醒:Burp每次重新导出的CA证书,只要没有重置过CA,生成的文件hash都是一样的。所以在多次测试中,你生成的通常都是同一个名字,不会变。只有当你把Burp的CA彻底重置,hash才会变化。

4. 三种把证书塞进系统证书库的实战路线

4.1 路线A:root真机直接挂载系统分区

这个方法适用于已经root但没装Magisk的手机。核心思路是把/system分区重新挂载为可读写,然后把证书文件复制进/system/etc/security/cacerts/。

先用adb把证书文件推到手机里:

adb push 9a5b5752.0 /data/local/tmp/

然后进入adb shell,获取root权限:

adb shell su

接下来挂载系统分区。不同安卓版本的命令略有差异,常见的是:

mount -o rw,remount /system

在Android 9及以上的某些设备上,直接remount可能会失败,提示Device or resource busy或者read-only file system。这时候需要先关闭verity校验:

adb disable-verity adb reboot

重启后再执行mount命令,一般就能成功了。关闭verity会触发系统启动时对分区的完整性校验,首次重启后手机会有个初始化过程,耐心等它完成。

成功挂载后,复制证书并设置权限:

cp /data/local/tmp/9a5b5752.0 /system/etc/security/cacerts/ chmod 644 /system/etc/security/cacerts/9a5b5752.0 chown root:root /system/etc/security/cacerts/9a5b5752.0

然后重启手机。注意,chmod和chown不能省略,这是很多人忽略的关键点。证书文件的权限不对,系统会直接忽略。

这个方法的优点是通用,任何root设备都能用。缺点是会改动/system分区,如果系统是只读分区设计,操作麻烦且容易在OTA升级后失效。

4.2 路线B:Magisk模块方式(最省心,推荐)

Magisk是目前最主流的root方案,它的模块机制可以在不直接修改系统分区的情况下,把文件注入到系统目录里,效果等同于修改系统分区,但更干净,卸载也方便。

先在手机上装好Magisk并授予root权限,然后通过adb创建模块目录结构:

adb shell su mkdir -p /data/adb/modules/burpcert/system/etc/security/cacerts

把证书文件复制进去:

cp /data/local/tmp/9a5b5752.0 /data/adb/modules/burpcert/system/etc/security/cacerts/

设置权限:

chmod -R 755 /data/adb/modules/burpcert chmod 644 /data/adb/modules/burpcert/system/etc/security/cacerts/9a5b5752.0 chown -R root:root /data/adb/modules/burpcert

为了让Magisk正确识别这个模块,还需要创建module.prop文件:

echo "id=burpcert" > /data/adb/modules/burpcert/module.prop echo "name=Burp CA Certificate" >> /data/adb/modules/burpcert/module.prop echo "version=1.0" >> /data/adb/modules/burpcert/module.prop echo "versionCode=1" >> /data/adb/modules/burpcert/module.prop echo "author=you" >> /data/adb/modules/burpcert/module.prop echo "description=Add Burp CA to system trust store" >> /data/adb/modules/burpcert/module.prop

重启手机。Magisk会在启动阶段自动把/data/adb/modules/burpcert/system/etc/security/cacerts/下的证书文件合并到系统证书目录,效果和直接复制到/system一模一样,但系统分区本身没有改动。

这个方案有几个明显优势:第一,不需要处理/system分区挂载和verity的问题;第二,卸载模块即可完全恢复原状;第三,如果手机升级系统,Magisk模块一般还能保留,系统证书依然生效。所以我个人强烈推荐这个方案。

4.3 路线C:模拟器方案(无root也能跑通)

如果你手里没有root设备,或者不想折腾真机,用模拟器可以快速验证抓包流程。Android Studio自带的AVD模拟器有一个很实用的特性:可以临时以“可写系统”模式启动。

启动AVD时加上-writable-system参数:

emulator -avd <你的AVD名称> -writable-system -no-snapshot

注意,-no-snapshot很关键,否则模拟器会从快照恢复,-writable-system不生效。启动后执行:

adb root adb remount adb push 9a5b5752.0 /system/etc/security/cacerts/ adb shell chmod 644 /system/etc/security/cacerts/9a5b5752.0

AVD默认带root,adb root可以直接获取root权限,adb remount会把/system挂载为可写。推入证书后重启模拟器即可。

第三方模拟器如MuMu、雷电,通常自带root权限,操作方法和路线A类似:

adb shell su mount -o rw,remount /system cp /data/local/tmp/9a5b5752.0 /system/etc/security/cacerts/ chmod 644 /system/etc/security/cacerts/9a5b5752.0

模拟器方案的优点是门槛低,不需要真机root;缺点是AVD在非-writable-system模式重启后,之前写入的系统文件会丢失,需要重新push。第三方模拟器则相对稳定一些,但某些定制模拟器的/system分区可能被厂商做了特殊处理,需要灵活变通。

4.4 三条路线怎么选

路线适用条件优点缺点
root真机直接挂载有root、无Magisk通用性强改动系统分区,verity问题麻烦
Magisk模块有Magisk最干净、可回滚、推荐需要先安装Magisk
模拟器方案无root或临时测试门槛低、速度快AVD重启失效,定制模拟器偶有问题

如果是长期做APP测试,我的建议是直接给测试机装Magisk,走模块路线。只为了临时抓个包,模拟器就够了。

5. 验证抓包是否成功,以及我踩过的几个坑

5.1 怎么确认证书真的生效了

证书安装完后,先别急着开Burp抓包,先确认证书是否被系统识别。在手机上进入设置 -> 安全 -> 加密与凭据 -> 信任的凭据 -> 系统,往下翻,如果能找到“PortSwigger CA”这样的条目,说明证书已经成功进入系统证书仓库。

然后回到Burp,把手机WiFi的手动代理重新配置好,打开一个HTTPS网站,比如https://www.baidu.com,看看HTTP history里是否出现了明文请求。如果能看到完整的URL、请求头和响应数据,恭喜,抓包链路已经通了。

如果只是浏览器能抓,但某个APP还是看不到明文,先别怀疑证书,大概率是遇到了下面第四节里说的SSL Pinning问题。

5.2 坑1:hash用错命令导致系统不识别

这个坑我踩过不止一次。OpenSSL里有-subject_hash和-subject_hash_old两个参数,前者算出来的是SHA1哈希,后者是MD5哈希。安卓系统的证书仓库要求的是MD5版本,也就是-subject_hash_old。

如果用了-subject_hash,文件名虽然也符合格式,但系统加载时会去查找对应hash的证书,找不到就跳过,效果就是证书白装了,抓包还是乱码。排查方法很简单:把证书文件复制到系统目录后,执行adb shell ls /system/etc/security/cacerts/,确认文件名和你算出来的一致。如果安装后系统证书列表里没有,先重新算一遍hash。

5.3 坑2:权限和属主不对,开机直接被忽略

证书文件复制到系统目录后,权限必须是644,属主必须是root:root。如果是从/data/local/tmp复制过来的文件,权限可能还是原来的600或755,系统加载证书时发现权限不对,会拒绝加载。

我习惯在复制后强制执行一遍:

adb shell su chmod 644 /system/etc/security/cacerts/9a5b5752.0 chown root:root /system/etc/security/cacerts/9a5b5752.0

在部分开启了SELinux强制模式的设备上,可能还需要恢复文件的安全上下文,否则证书目录的SELinux策略不允许加载。遇到这种情况,执行:

restorecon /system/etc/security/cacerts/9a5b5752.0

或者干脆用Magisk模块方式,它会自动处理SELinux上下文,这也是我推荐Magisk的另一个原因。

5.4 坑3:手机系统时间不准,TLS直接报证书过期

这是一个很隐蔽的问题。证书有效性和设备时间强相关。如果手机时间比真实时间偏早或偏晚超过一定范围,TLS握手时会判定Burp出示的证书不在有效期内,直接中止连接。

表现是:Burp里能看到CONNECT请求,但没有任何明文数据,有时候还会看到certificate_expired或certificate_unknown的错误提示。排查方法很简单,看看手机状态栏的时间是否正确,打开“自动确定日期和时间”,重新校准后再试。

这个坑在模拟器上尤其常见,模拟器默认时间可能和宿主机不一致,或者快照恢复后时间没同步。

5.5 坑4:遇到SSL Pinning的APP,证书装了也没用

即使证书成功进入系统仓库,仍然有一类APP抓不到明文,就是启用了SSL Pinning的APP。这类APP在代码里直接内置了服务器的证书或公钥,或者只信任自己指定的CA,完全无视系统证书仓库。

判断方法:在Burp能抓到该APP的CONNECT请求,但TLS握手反复失败,或者APP直接提示网络异常、无法连接。这种情况不是你证书装错了,而是APP做了证书绑定。

常规的解决思路是通过Frida、Objection这类动态插桩工具,在运行时hook掉APP的证书校验逻辑,或者在APP的networkSecurityConfig里额外信任系统证书。但这涉及具体APP的逆向分析,已经超出了“添加系统根证书”这个主题的范围。我只提醒一句:做这类测试时,确保你是在测试自己有权限的APP,不要在未授权的情况下对别人的服务做验证。

5.6 坑5:厂商定制系统的额外写保护

MIUI、EMUI、ColorOS这些厂商定制系统,经常会在原生Android之上加一些骚操作。比如某些MIUI版本里,即使你有root权限,直接remount/system也会失败,因为系统还有一层单独的写保护。某些EMUI版本里,证书文件改了之后重启会被还原。

遇到这种设备,别在挂载分区上死磕,直接上Magisk模块方案。Magisk的模块机制是挂在magisk镜像里的,不走系统分区的写保护逻辑,兼容性最好。如果一定要用直接挂载方案,可以试试先关闭系统的“增强保护”或“系统分区保护”开关,但说实话,不如Magisk省心。

最后再分享一个实际操作中的习惯:证书文件推到系统目录后,我一般不会立即重启设备,而是先执行adb shell ls -lZ /system/etc/security/cacerts/9a5b5752.0看一眼文件的权限、属主和SELinux标签。确认三项都正常后,再重启验证。这样即使出问题,也能快速定位是文件名、权限还是SELinux的问题。抓包这件事,原理并不复杂,真正考验耐心的是这些细枝末节。把这些细节都处理好,手机抓包这关就算彻底过了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询