修改Android源码,解放HTTPS抓包
Posted 袁国正_yy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了修改Android源码,解放HTTPS抓包相关的知识,希望对你有一定的参考价值。
欢迎访问我的个人网站:https://coderyuan.com
文章目录
为什么HTTPS不能抓包了?
Google在android 7.0以后的版本中,添加了“网络安全配置(Network security configuration)”的相关配置项。其旨在增强App的安全性,可以避免TargetSDK版本>=N的App内部网络请求在非测试环境下被恶意抓包。
Network Sercurity Configuration对安全性的保证,主要是通过以下几个途径:是否允许明文HTTP请求(非HTTPS)、HTTPS证书(区分系统、用户)信任设置、域名以及App的Debug或Release配置,只有符合Manifest中配置的NetworkConfig字段内容下的条件,才可以进行正常的HTTP请求,如果需要使用Charles、Fiddler等工具进行抓包,也需要利用NetworkConfig来配置可以信任的证书,否则HTTPS请求在CONNECT阶段,就会返回错误,同时LogCat会打印出类似以下的错误信息:
Caused by: java.security.cert.CertificateException: xxx.
at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:661)
at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:539)
at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:605)
at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:495)
at com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:321)
at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:113)
at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:87)
at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:116)
at com.huawei.secure.android.common.ssl.SecureX509TrustManager.checkServerTrusted(:105)
at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:212)
at com.android.org.conscrypt.ConscryptFileDescriptorSocket.verifyCertificateChain(ConscryptFileDescriptorSocket.java:404)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
at com.android.org.conscrypt.NativeSsl.doHandshake(NativeSsl.java:375)
通常,Android开发者会将NetworkConfig按照以下XML文件进行配置:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!-- 允许明文HTTP(非HTTPS)请求 -->
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<!-- 其他情况只允许信任系统内置证书 -->
<certificates src="system"/>
</trust-anchors>
</base-config>
<!-- 仅Debug包允许用户证书 -->
<debug-overrides>
<trust-anchors>
<certificates src="user"/>
</trust-anchors>
</debug-overrides>
</network-security-config>
然而对于开发者来说,通常App发版上线会选择使用Release版本的安装包,如果希望对Release包抓包,只能使用Android 6.0及以下的手机,这样一来,有时候出现线上问题,便无法进行HTTPS抓包,并不利于测试和修正
如何解决这一问题?
基本的几个思路
-
反编译APK,修改NetworkConfig相关的XML文件,让App可以信任用户配置的证书
这个方案局限性比较大,现在很多App都对反编译技术(主要是apktool)进行了防御,有的App使用apktool解包以后,就无法成功打包了,还有的用上了加固技术,通用的反编译工具无法直接获取真正Apk内部的文件。不过,如果能够使用apktool成功获得解码后的XML文件,且进行修改后能够重新打包成可以运行的Apk,这样做也是可行的
-
使用Hook
使用Xposed框架在App请求过程中进行Hook,依赖的基础仍然是反编译,且Xposed框架需要建立在Root后的基础上,成功率比较低,且成本还比较高
-
修改Android源码
这个应该是最成功且一劳永逸的办法了,但成本不小,需要有一台性能不错的电脑(至少硬盘空间够大)和一台Google的手机,具体如何实现,下面详细来说
寻求一个适合自己的办法
这里并不是说修改源码就是最好的,举例来讲,能使用6.0手机,是最简单的办法,但随着现在最低SDK版本的提升,在不久的将来,一些App或许就不会再支持6.0了,所以我只是在寻找一个更为靠谱的方案
如何改Android源码
准备工作
首先需要将AOSP的源码准备好,这里就不在赘述了,跟着Google官方的文档下载即可:https://source.android.com/setup/build/downloading
如果没法访问Google,可以使用清华大学的镜像:https://mirrors.tuna.tsinghua.edu.cn/help/AOSP/
分析源码
AOSP的源码非常的庞大,如果是初次接触,可能会完全摸不着头脑,当然,我们也不可能完全把它的结构和内容摸索清楚再进行修改,学会用文本查找很重要
这里安利VSCode,我们不需要使用Android Studio这样的工具,因为太慢!
首先去搜索一下NetworkSecurityConfig,就会发现有以下相关的文件
其中NetworkSucurityConfig.java
和XmlConfigSource.java
就和证书判断逻辑相关
仔细分析一波NetworkSucurityConfig
类,可以发现这个类使用了Android中常见的Builder模式来进行创建,其中包括一个返回默认配置Builder的静态方法
public static final Builder getDefaultBuilder(ApplicationInfo info)
在Android 9以前,这个方法的参数为两个int型字段:int targetSdkVersion, int targetSandboxVesrsion
这里列出这个方法的详细代码
/**
* Return a @link Builder for the default @code NetworkSecurityConfig.
*
* <p>
* The default configuration has the following properties:
* <ol>
* <li>If the application targets API level 27 (Android O MR1) or lower then cleartext traffic
* is allowed by default.</li>
* <li>Cleartext traffic is not permitted for ephemeral apps.</li>
* <li>HSTS is not enforced.</li>
* <li>No certificate pinning is used.</li>
* <li>The system certificate store is trusted for connections.</li>
* <li>If the application targets API level 23 (Android M) or lower then the user certificate
* store is trusted by default as well for non-privileged applications.</li>
* <li>Privileged applications do not trust the user certificate store on Android P and higher.
* </li>
* </ol>
*
* @hide
*/
public static Builder getDefaultBuilder(ApplicationInfo info)
Builder builder = new Builder()
.setHstsEnforced(DEFAULT_HSTS_ENFORCED)
// System certificate store, does not bypass static pins.
.addCertificatesEntryRef(
new CertificatesEntryRef(SystemCertificateSource.getInstance(), false));
final boolean cleartextTrafficPermitted = info.targetSdkVersion < Build.VERSION_CODES.P
&& info.targetSandboxVersion < 2;
builder.setCleartextTrafficPermitted(cleartextTrafficPermitted);
// Applications targeting N and above must opt in into trusting the user added certificate
// store.
if (info.targetSdkVersion <= Build.VERSION_CODES.M && !info.isPrivilegedApp())
// User certificate store, does not bypass static pins.
builder.addCertificatesEntryRef(
new CertificatesEntryRef(UserCertificateSource.getInstance(), false));
return builder;
可以看出以下几个特点:
-
Android 9(假设Target和系统版本一样)以下默认允许明文传输(非HTTPS)
-
默认只信任系统内置的根证书,Android 7以下添加对用户配置的证书信任
-
HSTS不强制开启
于是再次搜索这个方法的调用
其中,第一个调用的地方是重写了XmlConfigSource
实现的ConfigSource
类中的方法getDefaultConfig
而第二个地方则是在private void parseNetworkSecurityConfig(XmlResourceParser parser)
这个方法当中,根据方法名,就知道这是在解析XML配置中的网络安全配置
那么再分别查看它们的调用
那么,系统读取App网络安全配置的基本流程就可以猜想出来了:
-
首先是解析
AndroidMainfest.xml
文件 -
中间会初始化一个
XmlConfigSource
实例用来解析NetworkConfig -
当需要用到网络配置的具体内容时,会调用
XmlConfigSource
实例的getDefaultConfig
方法,其中ensureInitialized
会具体负责解析XML文件中的证书、域名、是否允许明文等配置 -
parseNetworkSecurityConfig
方法会首先利用NetworkSecurityConfig
类的getDefaultBuilder
方法获取一个通用的Builder,构建一个默认配置,再根据XML中的实际情况进行补充
修改相关源码
了解了网络安全配置加载的流程,那么从理论上来说,我们可以在任一环境进行修改,即可去掉HTTPS的抓包限制,其中,修改的几个点如下:
-
首先修改
NetworkSecurityConfig
的默认Builder,让它能够和Android 6.0以下的配置一样,默认添加对用户配置的证书信任,具体修改如下:// NetworkSecurityConfig.java // 修改前 public static Builder getDefaultBuilder(ApplicationInfo info) Builder builder = new Builder() .setHstsEnforced(DEFAULT_HSTS_ENFORCED) // System certificate store, does not bypass static pins. .addCertificatesEntryRef( new CertificatesEntryRef(SystemCertificateSource.getInstance(), false)); final boolean cleartextTrafficPermitted = info.targetSdkVersion < Build.VERSION_CODES.P && info.targetSandboxVersion < 2; builder.setCleartextTrafficPermitted(cleartextTrafficPermitted); // Applications targeting N and above must opt in into trusting the user added certificate // store. if (info.targetSdkVersion <= Build.VERSION_CODES.M && !info.isPrivilegedApp()) // User certificate store, does not bypass static pins. builder.addCertificatesEntryRef( new CertificatesEntryRef(UserCertificateSource.getInstance(), false)); return builder;
// NetworkSecurityConfig.java // 修改后 public static final Builder getDefaultBuilder(ApplicationInfo info) Builder builder = new Builder() .setHstsEnforced(DEFAULT_HSTS_ENFORCED) // System certificate store, does not bypass static pins. .addCertificatesEntryRef( new CertificatesEntryRef(SystemCertificateSource.getInstance(), false)); final boolean cleartextTrafficPermitted = info.targetSdkVersion < Build.VERSION_CODES.P && info.targetSandboxVersion < 2; builder.setCleartextTrafficPermitted(true); // 修改点1:忽略targetSdkVersion的判断,直接添加UserCertificateSource builder.addCertificatesEntryRef(new CertificatesEntryRef(UserCertificateSource.getInstance(), false)); return builder;
-
其次我们需要忽略App内置的配置,直接忽略
XmlConfigSource
中的解析结果,getDefaultConfig
方法直接返回我们改过的DefaultConfig:// XmlConfigSource.java // 修改前 public NetworkSecurityConfig getDefaultConfig() ensureInitialized(); return mDefaultConfig;
// XmlConfigSource.java // 修改后 public NetworkSecurityConfig getDefaultConfig() // 防止出现其他异常,其他初始化操作不进行修改(保留ensureInitialized方法的调用) ensureInitialized(); // 修改点2:不使用解析后的mDefaultConfig,重新获取一个DefaultConfig NetworkSecurityConfig.Builder builder = NetworkSecurityConfig.getDefaultBuilder(null); return builder.build();
刷机验证
确认没有基本的Java语法问题以后,lunch、make一波走起!!
如果还不会编译AOSP,戳这里:https://source.android.com/setup/build/building
稍等片刻,刷机试验……
注意:刷完机后,先不要着急连上WiFi挂上代理抓包,很多手机刷完以后时间会还原,所以先去设置中把时间调成正确的,否则无论如何证书都是过期的……
调整好时间后,连上Charles或者Fiddler的代理,装上它们的证书,即可对任意的App进行HTTPS抓包了!
终于不是满屏红叉了!!
以上是关于修改Android源码,解放HTTPS抓包的主要内容,如果未能解决你的问题,请参考以下文章