注意:阅读本文需要一台已经 root 的安卓手机!
说明
系统:MacOS 10.13.6
手机:小米 6(已 root)
抓包工具:Charles
微信版本:7.0.4
现象
安卓手机无法通过 Charles 代理抓包 https 请求,我前天(2019 年 04 月 16 日)用的 7.0.3 不知道为什么能抓到,昨天手残更新到 7.0.4 就不行了。而 iOS(iPhone5S 12.1.4)没有问题。
查找相关资料,都说微信升级到版本 7 之后就限制了用户证书凭据。根据网上较多的推荐方案,建议把证书放在系统证书存放目录下,那这就需要 Root 手机了,如果没有,以下内容不适合阅读。
接下来,我尝试将 Charles 生成的证书放在手机的系统证书中,并没有那么顺利,很失败!我慢慢来讲解一下。
步骤
生成 Charles 证书
我们要生成一个可以存放在系统证书目录下的可被识别的证书。
手机代理设置好了后,手机访问:<chls.pro/ssl> 下载下来证书,名称是这样的 charles-proxy-ssl-proxying-certificate.pem(你把这个文件搞到电脑上,假设该证书存在电脑的路径:~/charles-proxy-ssl-proxying-certificate.pem)。
在你的电脑终端通过这个命令生成一个 hash 值:
openssl x509 -subject_hash_old -in ~/charles-proxy-ssl-proxying-certificate.pem
可以看到输出了类似如下
P750TM:webs whidy$ openssl x509 -subject_hash_old -in ~/certificate.pem
07e87b3d
—–BEGIN CERTIFICATE—–
MIIFYjCCBEqgAwIBAgIGAWeQpfWHMA…
….
77JclxPc0UdJHi5rOf7w+LU8YZFPdMTLa/c2JjMlspt08UeQVDE=
—–END CERTIFICATE—–
将证书更名 07e87b3d.0 注意后缀!
接下来你可以用任意手段将该文件拷贝至手机的 /system/etc/security/cacerts/ 目录,如果成功则再次尝试抓包,如果失败,请继续看。
超级终端操作
如果不嫌麻烦的话,你完全可以在安卓手机上面的超级终端(自行下载的工具)进行以下操作,但是我没有这样,我在 MacOSX 中启用 adb 连接操作手机,如果你正有此意,请按照我的方式操作。
电脑终端执行以下命令(这里不介绍 brew,不理解的自行学习)
brew cask install android-platform-tools
装好后,数据线连上手机,测试一下
adb devices
没报错,且大概出现以下信息则正常:
List of devices attached
* daemon not running; starting now at tcp:5037
* daemon started successfully
fa8a05fd device
然后获取 root 权限,尝试将文件 07e87b3d.0 拷贝到 /system/etc/security/cacerts/
adb root
获得权限后,直接执行下面命令将证书放入系统目录。
push ~/07e87b3d.0 /system/etc/security/cacerts/
如果成功了,请尝试抓包。如果提示失败,比如权限不足,只读啥的,反正大概错误信息如下:
P750TM:/ whidy$ adb push ~/07e87b3d.0 /system/etc/security/cacerts/
adb: error: failed to copy ‘/Users/whidy/07e87b3d.0’ to ‘/system/etc/security/cacerts/07e87b3d.0′: remote couldn’t create file: Read-only file system
/Users/whidy/07e87b3d.0: 0 files pushed. 0.0 MB/s (1947 bytes in 0.119s)
那就要继续折腾了。网上抄到的 chmod 777 目前是不管用的。要通过 mount 的相关操作来解决这个问题。
装载可写的 system 目录
查看当前 system 目录挂载在哪里 mount,可以得到大致如下:
rootfs on / type rootfs (ro,seclabel,size=2828452k,nr_inodes=707113)
tmpfs on /dev type tmpfs (rw,seclabel,nosuid,relatime,size=2912600k,nr_inodes=728150,mode=755)
devpts on /dev/pts type devpts (rw,seclabel,relatime,mode=600)
proc on /proc type proc (rw,relatime,gid=3009,hidepid=2)
sysfs on /sys type sysfs (rw,seclabel,relatime)
selinuxfs on /sys/fs/selinux type selinuxfs (rw,relatime)
/dev/block/dm-0 on /system type ext4 (ro,seclabel,relatime,discard,data=ordered)
debugfs on /sys/kernel/debug type debugfs (rw,seclabel,relatime)
none on /acct type cgroup (rw,relatime,cpuacct)
none on /dev/stune type cgroup (rw,relatime,schedtune)
tmpfs on /mnt type tmpfs (rw,seclabel,relatime,size=2912600k,nr_inodes=728150,mode=755,gid=1000)
none on /config type configfs (rw,relatime)
none on /dev/memcg type cgroup (rw,relatime,memory)
注意到 /dev/block/dm-0 on /system type ext4 (ro,seclabel,relatime,discard,data=ordered) 这一行,后面括号有个 ro,代表 readonly!
接下来尝试修改为可写(rw)状态:
mount -o rw,remount /dev/block/dm-0 /system
如果成功了,就试试将文件拷贝进去,失败了,例如提示:’/dev/block/dm-0’ is read-only,请继续阅读。
这里参考 Android O, failed to mount /system, /dev/block/dm-0 is read only,一顿操作!我这边是这样的:
adb disable-verity
adb reboot
关闭验证是要重启设备的。执行重启后,继续:
adb root
adb remount
adb shell
再执行 mount 发现结果跟刚才不一样了,找到有 system 的那一行发现这样的
/dev/block/sde43 on /system type ext4 (rw,seclabel,relatime,discard,data=ordered)
已经可写了,我试试拷贝进去。执行 adb push ~/07e87b3d.0 /system/etc/security/cacerts/,出现以下结果:
P750TM:/ whidy$ adb push ~/07e87b3d.0 /system/etc/security/cacerts/
/Users/whidy/07e87b3d.0: 1 file pushed. 0.1 MB/s (1947 bytes in 0.022s)
应该就完成了。再去我的小米 6 手机里面的设置 > 更多设置 > 系统安全 > 加密与凭据 > 信任的凭据 > 系统里面看看,滚到最低部,ok,证书导入成功了。再去抓包看看~
我这文章是边写边记录的,现在可以看到 https 请求的抓包已经 Ok 啦~
最后
我建议最后还原之前操作的 disable-verity,这样操作一下:
adb root
adb enable-verity
adb reboot
行了差不多就这些了。