修改Android源码,解放HTTPS抓包

欢迎访问我的个人网站:https://coderyuan.com

文章目录

  • 为什么HTTPS不能抓包了?
  • 如何解决这一问题?
    • 基本的几个思路
    • 寻求一个适合自己的办法
  • 如何改Android源码
    • 准备工作
    • 分析源码
  • 修改相关源码
  • 刷机验证

为什么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文件进行配置:


<network-security-config>
    
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            
            <certificates src="system"/>
        trust-anchors>
    base-config>
    
    <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,就会发现有以下相关的文件

修改Android源码,解放HTTPS抓包_第1张图片

其中NetworkSucurityConfig.javaXmlConfigSource.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}.
     *
     * 

* The default configuration has the following properties: *

    *
  1. If the application targets API level 27 (Android O MR1) or lower then cleartext traffic * is allowed by default.
  2. *
  3. Cleartext traffic is not permitted for ephemeral apps.
  4. *
  5. HSTS is not enforced.
  6. *
  7. No certificate pinning is used.
  8. *
  9. The system certificate store is trusted for connections.
  10. *
  11. 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.
  12. *
  13. Privileged applications do not trust the user certificate store on Android P and higher. *
  14. *
* * @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; }

可以看出以下几个特点:

  1. Android 9(假设Target和系统版本一样)以下默认允许明文传输(非HTTPS)

  2. 默认只信任系统内置的根证书,Android 7以下添加对用户配置的证书信任

  3. HSTS不强制开启

于是再次搜索这个方法的调用

修改Android源码,解放HTTPS抓包_第2张图片

其中,第一个调用的地方是重写了XmlConfigSource实现的ConfigSource类中的方法getDefaultConfig

而第二个地方则是在private void parseNetworkSecurityConfig(XmlResourceParser parser)这个方法当中,根据方法名,就知道这是在解析XML配置中的网络安全配置

那么再分别查看它们的调用

修改Android源码,解放HTTPS抓包_第3张图片

修改Android源码,解放HTTPS抓包_第4张图片

那么,系统读取App网络安全配置的基本流程就可以猜想出来了:

  1. 首先是解析AndroidMainfest.xml文件

  2. 中间会初始化一个XmlConfigSource实例用来解析NetworkConfig

  3. 当需要用到网络配置的具体内容时,会调用XmlConfigSource实例的getDefaultConfig方法,其中ensureInitialized会具体负责解析XML文件中的证书、域名、是否允许明文等配置

  4. parseNetworkSecurityConfig方法会首先利用NetworkSecurityConfig类的getDefaultBuilder方法获取一个通用的Builder,构建一个默认配置,再根据XML中的实际情况进行补充

修改相关源码

了解了网络安全配置加载的流程,那么从理论上来说,我们可以在任一环境进行修改,即可去掉HTTPS的抓包限制,其中,修改的几个点如下:

  1. 首先修改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;
        }
    
  2. 其次我们需要忽略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挂上代理抓包,很多手机刷完以后时间会还原,所以先去设置中把时间调成正确的,否则无论如何证书都是过期的……

修改Android源码,解放HTTPS抓包_第5张图片

调整好时间后,连上Charles或者Fiddler的代理,装上它们的证书,即可对任意的App进行HTTPS抓包了!

终于不是满屏红叉了!!

你可能感兴趣的:(Android)