做移动端安全测试的朋友应该都遇到过这个场面:Burp监听开好了,安卓手机也把网络代理指到电脑上了,HTTP请求刷屏刷得飞起,一切看起来都很正常。等你想抓某个App的HTTPS请求时,屏幕上要么只剩一堆密文,要么直接弹证书告警。很多人第一反应是把Burp的CA证书导出来装进手机,装完发现还是抓不到。为什么?因为安卓7.0之后的系统默认不信任用户自己安装的证书,App也不认。这篇文章就把“安卓添加Burp系统根证书”这件事彻底讲透,从证书信任原理到实操命令,再到Magisk模块方案和常见坑,一次说清楚。
这篇内容适合刚入门移动安全、App渗透测试,或者纯粹想研究自己手机流量的人。不需要你是逆向大佬,只要会敲几行adb命令、知道root是什么,就能照着做。我会把为什么要这么操作、每一步背后的逻辑都讲明白,而不是简单丢给你一串命令然后说“复制粘贴就行”。
1. 先弄懂为什么装了证书还是不生效
很多人第一次抓HTTPS包失败,第一反应是证书装错了,于是反反复复导出、安装、卸载,折腾一晚上还是老样子。其实问题根源不在操作步骤,而在你对安卓证书信任体系的理解不够。先把原理捋清楚了,后面所有操作都会变得顺理成章。
1.1 HTTPS抓包的本质
HTTPS和HTTP最大的区别就是多了一层TLS加密。客户端和服务器在正式通信前要完成一次TLS握手,协商出会话密钥。这个握手过程里,服务器会把它的证书发给客户端,客户端验证这个证书是不是可信的。验证通过才继续往下走。
Burp这类抓包工具干的事情,在安全圈里叫中间人(Man-in-the-Middle,简称MITM)。它的思路很直接:Burp在中间假装自己是服务器,跟客户端完成一次握手;然后又假装自己是客户端,跟真正的服务器完成另一次握手。这样一来,两端之间的明文流量都要经过Burp中转,自然就能看光光。
要完成这个骗局,Burp得有一张自己的CA根证书。当客户端要求验证服务器身份时,Burp会拿这张CA证书现场签发一张目标域名的证书,发给客户端。客户端一看,这张证书是被Burp的CA签发的,如果客户端信任Burp这个CA,握手就成功;如果不信任,直接报证书错误或者连接失败。
所以问题的关键变成了:怎么让安卓手机上的App信任Burp这张CA。这就是整个抓包配置里最难缠的部分,因为安卓在不同版本上的策略差异实在太大了。
1.2 安卓证书信任体系的两个大坑
安卓系统的证书存储分两个区域:系统证书区和用户证书区。系统证书区里放的是出厂预装的那些根证书,比如DigiCert、GlobalSign这类知名CA。用户证书区是用户自己手动安装的证书,比如你从Burp导出装到手机上的那种。
安卓7.0(API 24)之前,App默认信任所有证书,不管是系统证书还是用户证书,所以那时候抓包很简单,装个用户证书就完事。但从安卓7.0开始,Google改了策略:以targetSdkVersion 24及以上编译的App,默认只信任系统证书区,用户手动装的证书默认不信任。这就是第一个大坑。
第二个大坑是系统证书区不是你想写就能写的。安卓的系统分区默认是只读的,尤其安卓10之后,分区保护更严格,直接remount经常失败。想往系统证书目录里塞东西,一般得root后才能操作,而且还得想办法绕过系统的只读限制。这也是为什么网上很多教程看完还是搞不定,因为不同手机型号、不同安卓版本,操作路径都不一样。
明白这两个坑之后,思路就很清晰了:要么把Burp证书弄进系统证书区,要么想办法让App愿意信任用户证书区的证书。前者是治本,也是这篇文章的重点。
2. 开工前的环境准备
讲完原理,下面进入实操。在动手之前,先把需要的东西准备好。别嫌这一步啰嗦,我见过太多人做到一半发现缺工具,然后临时下载,非常浪费时间。
2.1 手机端和电脑端要备齐的东西
先说手机端。最核心的条件是root权限,因为你要往/system/etc/security/cacerts/目录里写文件,这个目录普通用户连读都有困难。如果你用的是Magisk做的root,那最好,后面有更方便的方案;如果没有root,也不是完全没救,但只能走App调试模式或者模拟器路线,后面我会提一嘴。
电脑端需要准备的东西有这几样:
- Burp Suite,社区版就够用,专业版当然更好,操作路径一样
- adb工具,安卓调试桥,装好Platform Tools就能用
- OpenSSL命令行工具,用来计算证书hash和格式转换。Windows用户可以用Git Bash里自带的openssl,或者装个WSL,Mac和Linux用户系统自带
- 一根能通数据的USB线,别拿那种只能充电的线来糊弄
如果你用的是安卓模拟器,比如Android Studio自带的模拟器或者Genymotion,也是一样的流程,只是root和环境更方便,很多模拟器直接支持adb root命令,连Magisk都不用装。
2.2 确认手机已root且能操作system分区
连接手机之前,先在电脑上确认adb能识别设备。手机打开开发者选项,开启USB调试,然后用数据线连上电脑。终端里执行:
adb devices看到设备ID和device状态就说明连接正常。如果显示unauthorized,去手机上看一下,允许USB调试授权。
接着确认root是否可用。执行:
adb shell su如果终端提示符变成#,说明你拿到root了。如果提示Permission denied,说明root有问题,先解决root再继续。有些手机用Magisk,su授权时会弹窗,记得在手机上点允许。
root确认没问题后,顺手看一下当前用户,以及目标证书目录是否存在:
whoami ls -l /system/etc/security/cacerts/正常情况下你能看到一大堆.0结尾的文件,这些都是系统预置的根证书。后面我们要做的就是把Burp的证书也变成这样一个.0文件,放在这里。
注意:如果你的手机没有root,但目标App恰好是debug版本,或者Manifest里设置了
android:debuggable="true",那可以用另一种思路:通过App调试模式信任用户证书,或者用Frida等工具绕过证书校验。但那是另一套玩法,今天不展开。
3. 一步步把Burp证书塞进系统证书目录
准备工作做完,进入核心环节。整个流程分三步:导出Burp证书、算文件名、推送并设置权限。我还会额外给一个用Magisk模块实现的方案,那个方案更优雅,不折腾系统分区,强烈建议你重点看。
3.1 导出证书并算出正确的文件名
打开Burp,进入Proxy选项卡,再进Proxy Settings,找到Import/Export CA certificate按钮。点开后选择Export,导出格式选DER,保存为cacert.der。这一步生成的其实就是Burp根证书的公钥部分,后面所有操作都围绕这个文件展开。
接下来要解决的XML是文件名。安卓系统证书目录里每个证书的命名规则是:证书主题hash值.0。这个hash不是随便取的,得用OpenSSL针对证书的主题信息算出来。在终端里执行:
# 先把DER格式转成PEM格式,方便后续处理 openssl x509 -inform DER -in cacert.der -out cacert.pem # 计算旧版subject hash openssl x509 -inform PEM -subject_hash_old -in cacert.pem | head -1比如我这里算出来结果是9a5ba575,那么文件名就是9a5ba575.0。把这个文件重命名好备用。
有些教程会告诉你用-subject_hash而不是-subject_hash_old,这俩算出来的值可能不一样。实际测试中安卓系统对两种命名都能识别,但-subject_hash_old兼容性最好,覆盖的安卓版本更广,我推荐优先用它。如果你塞进去之后发现系统不认,再试试用-subject_hash算一遍,把两个名字的文件都放进去,反正不冲突。
# 重命名证书文件,这里以实际算出的hash值为准 mv cacert.pem 9a5ba575.03.2 用adb把证书推送到系统目录
这一步要动系统分区。把改好名的证书先推送到手机的临时目录,然后进入root操作。执行:
# 推送到临时目录 adb push 9a5ba575.0 /data/local/tmp/ # 进入shell并拿到root adb shell su拿到root后,先尝试重新挂载系统分区为可写:
mount -o rw,remount /system如果你的手机这一步没报错,恭喜,后面就简单了。直接拷贝文件到系统证书目录,设置权限,然后重启:
cp /data/local/tmp/9a5ba575.0 /system/etc/security/cacerts/ chmod 644 /system/etc/security/cacerts/9a5ba575.0 reboot重启之后,去手机的设置->安全->加密与凭据->信任的凭据,切到系统标签页,应该能看到一个由Burp签发的证书。看到了就说明系统证书安装成功,回到Burp再试试抓HTTPS包,应该就是明文了。
如果mount -o rw,remount /system报错,不要慌,这是安卓10以后非常常见的情况。系统分区受到dm-verity和动态分区保护,直接remount会被拒。你可以试试另一种方式:
mount -o rw,remount /有些机型根分区和系统分区在同一个逻辑卷上,这样能成功。如果连这个也不行,那就别在系统分区上死磕了,直接用下一节的Magisk模块方案。
3.3 不折腾系统分区的Magisk模块方案
如果你手机用的是Magisk管理root,那强烈推荐走这个方案。Magisk有一个模块系统,可以把自定义文件以overlay的方式挂载到系统路径上,不用真的修改系统分区,重启后还能保留。最妙的是,即使以后Magisk更新,模块通常也还能用,OTA升级后只要重新刷一次Magisk即可。
思路很简单:构建一个Magisk模块目录,里面放我们想挂载到/system/etc/security/cacerts/的文件,然后把模块目录放到/data/adb/modules/下,重启即可生效。
先在电脑上构建好模块目录结构:
mkdir -p burp-system-cert/system/etc/security/cacerts cp 9a5ba575.0 burp-system-cert/system/etc/security/cacerts/ cd burp-system-cert然后创建module.prop文件,这是Magisk模块的元信息文件:
cat > module.prop <<EOF id=burpsystemcert name=Burp System CA Certificate version=v1.0 versionCode=1 author=yourname description=Add Burp CA to Android system trust store EOF把整个模块目录推到手机临时目录,再移动到Magisk模块目录:
adb push burp-system-cert /data/local/tmp/ adb shell su cp -r /data/local/tmp/burp-system-cert /data/adb/modules/ chmod -R 644 /data/adb/modules/burp-system-cert/system/etc/security/cacerts/ chmod 755 /data/adb/modules/burp-system-cert reboot重启后再看系统信任凭据列表,Burp证书应该已经躺在里面了。这个方案的好处显而易见:不需要remount系统分区,不影响系统完整性,以后想移除证书,直接删掉模块目录重启就行。
还有个更懒人的办法:网上有很多现成的Magisk模块,比如MagiskTrustUserCerts,它会自动把用户证书区里的所有证书同步到系统证书区。你只需要先正常安装Burp证书到用户区,再刷这个模块,重启后用户区的证书就会自动变成系统证书。这个方案适合不想手动算hash、不想建模块目录的人,但要注意模块版本和安卓版本的兼容性,有些老模块在安卓14上会失效。
4. 证书装完依然抓不到包?排查思路参考这个表
证书放进去不代表就万事大吉了。实操中总会遇到各种奇奇怪怪的问题,我整理了一份高频问题排查表,全是自己踩过的坑,一次说透。
4.1 高频问题速查表
| 现象 | 最常见原因 | 解决思路 |
|---|---|---|
| 证书文件名不对,系统忽略 | hash计算方式不受支持 | 换-subject_hash_old或-subject_hash重新算,两个都放 |
| 系统证书列表里找不到Burp证书 | 文件权限不对或SELinux上下文不对 | 确认文件权限是644,属主是root:root;Magisk模块检查目录权限 |
| 系统证书列表能看到,但App还是报证书错误 | App做了SSL Pinning,只认自己的服务器证书 | 这个需要绕过证书校验,可以用Frida hook,不是今天讲的范围 |
| remount /system失败 | 安卓10+动态分区/dm-verity保护 | 换Magisk模块方案,别跟系统分区死磕 |
| 重启后证书又不见了 | 修改没有真正写入系统分区,或者被OTA还原 | 用Magisk模块方式挂载,重启也保留 |
| 抓到了HTTPS包但全是加密数据 | Burp解不了TLS握手,证书没被真正信任 | 按流程重做,确认系统证书列表里确实能看到Burp证书 |
| 只抓得到某个App的流量,其它App正常 | 目标App可能用了独立的网络栈或者自带证书固定 | 尝试抓它的WebView流量,或者用Frida绕过校验 |
这里面最让我头疼的是SELinux上下文问题,很多人忽略了这点。即使权限是644,如果文件的SELinux标签不是system_file之类可读类型,系统在读取证书时依然可能拒绝。用Magisk模块方案的话,模块挂载的文件通常会自动继承正确的上下文,所以我说这个方案省心是有道理的。
4.2 两个容易被忽视的细节
第一个细节是证书有效期。Burp生成的CA证书是有有效期的,老版本默认一年,新版本好像是十年。证书过期后,之前费劲装的系统证书就白装了,所有HTTPS抓包都会突然失效。遇到这种玄学问题,先看看Burp里CA证书的过期时间,说不定就是它。解决方法很简单,在Burp里重新导出证书,重新走一遍流程,把旧文件覆盖掉。
第二个细节是安卓14及更高版本的特殊性。安卓14对/system/etc/security/cacerts/目录的读取加入了更严格的限制,有些机型即使把证书放进去,系统也不识别。遇到这种情况,第一优先级依然是Magisk模块方案,而且模块的update.json里最好声明兼容安卓14。如果Magisk也不行,可以看看有没有对应机型的系统证书定制方案,但这类操作风险较高,我个人不太推荐新手尝试。
5. 实操心得和几个提效技巧
最后分享一些个人经验。这套流程我前前后后折腾过不下几十次,从安卓6时代一路做到安卓14,踩过的坑比很多人见过的都多。有几个心得值得单独拿出来说。
第一,能用Magisk模块就别remount系统分区。早期安卓版本remount很好用,但安卓10以后动态分区机制让remount变得很脆弱,搞不好就开不了机。Magisk模块虽然理解成本高一点,但稳定性和安全性都强太多,而且方便切换开关,强烈建议学一下。
第二,模拟器场景可以走捷径。如果你用的是Android Studio自带模拟器,很多镜像支持adb root,得root后直接执行adb remount就能把系统分区挂载成可写,然后推文件就很方便。这是平时调试最快的方式,没有之一,尤其适合在真机上不敢乱动的人先拿模拟器练手。
第三,抓包只是第一步,别忽略流量分析。证书配好之后,很多人就只是在Burp里看着明文请求傻乐,这是浪费。抓包是为了看接口、看参数、看加密逻辑。建议抓完直接导出一份完整的请求历史,拿Proxy -> HTTP History仔细翻一遍,重点关注登录接口、支付接口和数据上报接口,这些地方往往是漏洞的高发区。再配合Burp的被动扫描功能,让工具在后台帮你跑一轮常见漏洞检测,效率会高很多。
第四,证书出问题先看时间。我遇到过很多次大半夜用户说“证书明明装好了就是抓不到包”,远程一看,证书过期了。所以当你怀疑证书问题时,第一件事检查证书有效期,其次再检查系统证书列表里是否真的存在,最后再考虑App自身有没有做额外的证书校验。
这套方法做好之后,安卓App的HTTPS流量对你来说就是透明的。你可以用它来分析App的接口设计、排查自己的网络问题、甚至做恶意外的测试都行。不过提醒一句,抓包工具要用在合法授权的场景里,别拿它去做不该做的事。技术本身没有错,用错了方向才是问题。