首页 > 其他分享 >app抓包专题

app抓包专题

时间:2024-03-07 23:00:41浏览次数:28  
标签:function use 专题 console log app var Java 抓包

一、系统代理-NO_PROXY

  • 安卓开发时设置NO_PROXY,手机会不走系统代理,比如得物
  • 绕过方式:
    • 1、软件

      • Drony、SocksDroid(推荐)、ProxyDroid、Postern
      • 注意:需要关闭手机上的系统代理
    • 2、frida Hook

      Java.perform(function () {
          var Builder = Java.use("okhttp3.OkHttpClient$Builder");
      
          Builder.proxy.implementation = function (proxy) {
              var res = this.proxy(null);
              return res;
          }
      });
      
      // frida -U -f com.shizhuang.duapp -l  hook-proxy.js 

      注意:frida检测,对于得物,需要删除 libmsaoaidsec.so 文件
      适用于okhttp3发送请求,对于第三方包进行混淆,Hook方式无法绕过,需要借助于不会被混淆的系统包。

二、客户端证书校验

  • - 在客户端中预设证书信息
    - 客户端向服务端发送请求,将服务端返回的证书信息(公钥)和客户端预设证书信息进行校验
  • SSL PINNING是Google官方推荐的校验方式,原理是在客户端(安卓APP)中预先设置好证书信息,握手时与服务端返回的证书进行比较。如果有这种客户端校验,那么charles等抓包工具,就无法抓包了。因为charles作为中间人返回给客户端的证书信息与原客户端预先设置的不一致,所以,客户端检测到,就拒绝发送请求了。
  • 绕过方式:
    • 1、frida Hook

      • frida_multiple_unpinning.js
        /*  Android ssl certificate pinning bypass script for various methods
            by Maurizio Siddu
        
            Run with:
            frida -U -f [APP_ID] -l frida_multiple_unpinning.js --no-pause
            frida -UF -l frida_multiple_unpinning.js
        */
        
        setTimeout(function() {
            Java.perform(function() {
                console.log('');
                console.log('======');
                console.log('[#] Android Bypass for various Certificate Pinning methods [#]');
                console.log('======');
        
        
                var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
                var SSLContext = Java.use('javax.net.ssl.SSLContext');
        
                // TrustManager (Android < 7) //
                ////////////////////////////////
                var TrustManager = Java.registerClass({
                    // Implement a custom TrustManager
                    name: 'dev.asd.test.TrustManager',
                    implements: [X509TrustManager],
                    methods: {
                        checkClientTrusted: function(chain, authType) {},
                        checkServerTrusted: function(chain, authType) {},
                        getAcceptedIssuers: function() {return []; }
                    }
                });
                // Prepare the TrustManager array to pass to SSLContext.init()
                var TrustManagers = [TrustManager.$new()];
                // Get a handle on the init() on the SSLContext class
                var SSLContext_init = SSLContext.init.overload(
                    '[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom');
                try {
                    // Override the init method, specifying the custom TrustManager
                    SSLContext_init.implementation = function(keyManager, trustManager, secureRandom) {
                        console.log('[+] Bypassing Trustmanager (Android < 7) pinner');
                        SSLContext_init.call(this, keyManager, TrustManagers, secureRandom);
                    };
                } catch (err) {
                    console.log('[-] TrustManager (Android < 7) pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // OkHTTPv3 (quadruple bypass) //
                /////////////////////////////////
                try {
                    // Bypass OkHTTPv3 {1}
                    var okhttp3_Activity_1 = Java.use('okhttp3.CertificatePinner');
                    okhttp3_Activity_1.check.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
                        console.log('[+] Bypassing OkHTTPv3 {1}: ' + a);
                        return;
                    };
                } catch (err) {
                    console.log('[-] OkHTTPv3 {1} pinner not found');
                    //console.log(err);
                }
                try {
                    // Bypass OkHTTPv3 {2}
                    // This method of CertificatePinner.check is deprecated but could be found in some old Android apps
                    var okhttp3_Activity_2 = Java.use('okhttp3.CertificatePinner');
                    okhttp3_Activity_2.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function(a, b) {
                        console.log('[+] Bypassing OkHTTPv3 {2}: ' + a);
                        return;
                    };
                } catch (err) {
                    console.log('[-] OkHTTPv3 {2} pinner not found');
                    //console.log(err);
                }
                try {
                    // Bypass OkHTTPv3 {3}
                    var okhttp3_Activity_3 = Java.use('okhttp3.CertificatePinner');
                    okhttp3_Activity_3.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function(a, b) {
                        console.log('[+] Bypassing OkHTTPv3 {3}: ' + a);
                        return;
                    };
                } catch(err) {
                    console.log('[-] OkHTTPv3 {3} pinner not found');
                    //console.log(err);
                }
                try {
                    // Bypass OkHTTPv3 {4}
                    var okhttp3_Activity_4 = Java.use('okhttp3.CertificatePinner');
                    //okhttp3_Activity_4['check$okhttp'].implementation = function(a, b) {
                    okhttp3_Activity_4.check$okhttp.overload('java.lang.String', 'kotlin.jvm.functions.Function0').implementation = function(a, b) {
                        console.log('[+] Bypassing OkHTTPv3 {4}: ' + a);
                        return;
                    };
                } catch(err) {
                    console.log('[-] OkHTTPv3 {4} pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // Trustkit (triple bypass) //
                //////////////////////////////
                try {
                    // Bypass Trustkit {1}
                    var trustkit_Activity_1 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');
                    trustkit_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(a, b) {
                        console.log('[+] Bypassing Trustkit {1}: ' + a);
                        return true;
                    };
                } catch (err) {
                    console.log('[-] Trustkit {1} pinner not found');
                    //console.log(err);
                }
                try {
                    // Bypass Trustkit {2}
                    var trustkit_Activity_2 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');
                    trustkit_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function(a, b) {
                        console.log('[+] Bypassing Trustkit {2}: ' + a);
                        return true;
                    };
                } catch (err) {
                    console.log('[-] Trustkit {2} pinner not found');
                    //console.log(err);
                }
                try {
                    // Bypass Trustkit {3}
                    var trustkit_PinningTrustManager = Java.use('com.datatheorem.android.trustkit.pinning.PinningTrustManager');
                    trustkit_PinningTrustManager.checkServerTrusted.overload('[Ljava.security.cert.X509Certificate;', 'java.lang.String').implementation = function(chain, authType) {
                        console.log('[+] Bypassing Trustkit {3}');
                        //return;
                    };
                } catch (err) {
                    console.log('[-] Trustkit {3} pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // TrustManagerImpl (Android > 7) //
                ////////////////////////////////////
                try {
                    // Bypass TrustManagerImpl (Android > 7) {1}
                    var array_list = Java.use("java.util.ArrayList");
                    var TrustManagerImpl_Activity_1 = Java.use('com.android.org.conscrypt.TrustManagerImpl');
                    TrustManagerImpl_Activity_1.checkTrustedRecursive.implementation = function(certs, ocspData, tlsSctData, host, clientAuth, untrustedChain, trustAnchorChain, used) {
                        console.log('[+] Bypassing TrustManagerImpl (Android > 7) checkTrustedRecursive check: '+ host);
                        return array_list.$new();
                    };
                } catch (err) {
                    console.log('[-] TrustManagerImpl (Android > 7) checkTrustedRecursive check not found');
                    //console.log(err);
                }
                try {
                    // Bypass TrustManagerImpl (Android > 7) {2} (probably no more necessary)
                    var TrustManagerImpl_Activity_2 = Java.use('com.android.org.conscrypt.TrustManagerImpl');
                    TrustManagerImpl_Activity_2.verifyChain.implementation = function(untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
                        console.log('[+] Bypassing TrustManagerImpl (Android > 7) verifyChain check: ' + host);
                        return untrustedChain;
                    };
                } catch (err) {
                    console.log('[-] TrustManagerImpl (Android > 7) verifyChain check not found');
                    //console.log(err);
                }
        
        
        
        
        
                // Appcelerator Titanium PinningTrustManager //
                ///////////////////////////////////////////////
                try {
                    var appcelerator_PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager');
                    appcelerator_PinningTrustManager.checkServerTrusted.implementation = function(chain, authType) {
                        console.log('[+] Bypassing Appcelerator PinningTrustManager');
                        return;
                    };
                } catch (err) {
                    console.log('[-] Appcelerator PinningTrustManager pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // Fabric PinningTrustManager //
                ////////////////////////////////
                try {
                    var fabric_PinningTrustManager = Java.use('io.fabric.sdk.android.services.network.PinningTrustManager');
                    fabric_PinningTrustManager.checkServerTrusted.implementation = function(chain, authType) {
                        console.log('[+] Bypassing Fabric PinningTrustManager');
                        return;
                    };
                } catch (err) {
                    console.log('[-] Fabric PinningTrustManager pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // OpenSSLSocketImpl Conscrypt (double bypass) //
                /////////////////////////////////////////////////
                try {
                    var OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');
                    OpenSSLSocketImpl.verifyCertificateChain.implementation = function(certRefs, JavaObject, authMethod) {
                        console.log('[+] Bypassing OpenSSLSocketImpl Conscrypt {1}');
                    };
                } catch (err) {
                    console.log('[-] OpenSSLSocketImpl Conscrypt {1} pinner not found');
                    //console.log(err);
                }
                try {
                    var OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');
                    OpenSSLSocketImpl.verifyCertificateChain.implementation = function(certChain, authMethod) {
                        console.log('[+] Bypassing OpenSSLSocketImpl Conscrypt {2}');
                    };
                } catch (err) {
                    console.log('[-] OpenSSLSocketImpl Conscrypt {2} pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // OpenSSLEngineSocketImpl Conscrypt //
                ///////////////////////////////////////
                try {
                    var OpenSSLEngineSocketImpl_Activity = Java.use('com.android.org.conscrypt.OpenSSLEngineSocketImpl');
                    OpenSSLEngineSocketImpl_Activity.verifyCertificateChain.overload('[Ljava.lang.Long;', 'java.lang.String').implementation = function(a, b) {
                        console.log('[+] Bypassing OpenSSLEngineSocketImpl Conscrypt: ' + b);
                    };
                } catch (err) {
                    console.log('[-] OpenSSLEngineSocketImpl Conscrypt pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // OpenSSLSocketImpl Apache Harmony //
                //////////////////////////////////////
                try {
                    var OpenSSLSocketImpl_Harmony = Java.use('org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl');
                    OpenSSLSocketImpl_Harmony.verifyCertificateChain.implementation = function(asn1DerEncodedCertificateChain, authMethod) {
                        console.log('[+] Bypassing OpenSSLSocketImpl Apache Harmony');
                    };
                } catch (err) {
                    console.log('[-] OpenSSLSocketImpl Apache Harmony pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // PhoneGap sslCertificateChecker //
                ////////////////////////////////////
                try {
                    var phonegap_Activity = Java.use('nl.xservices.plugins.sslCertificateChecker');
                    phonegap_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function(a, b, c) {
                        console.log('[+] Bypassing PhoneGap sslCertificateChecker: ' + a);
                        return true;
                    };
                } catch (err) {
                    console.log('[-] PhoneGap sslCertificateChecker pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // IBM MobileFirst pinTrustedCertificatePublicKey (double bypass) //
                ////////////////////////////////////////////////////////////////////
                try {
                    // Bypass IBM MobileFirst {1}
                    var WLClient_Activity_1 = Java.use('com.worklight.wlclient.api.WLClient');
                    WLClient_Activity_1.getInstance().pinTrustedCertificatePublicKey.overload('java.lang.String').implementation = function(cert) {
                        console.log('[+] Bypassing IBM MobileFirst pinTrustedCertificatePublicKey {1}: ' + cert);
                        return;
                    };
                    } catch (err) {
                    console.log('[-] IBM MobileFirst pinTrustedCertificatePublicKey {1} pinner not found');
                    //console.log(err);
                }
                try {
                    // Bypass IBM MobileFirst {2}
                    var WLClient_Activity_2 = Java.use('com.worklight.wlclient.api.WLClient');
                    WLClient_Activity_2.getInstance().pinTrustedCertificatePublicKey.overload('[Ljava.lang.String;').implementation = function(cert) {
                        console.log('[+] Bypassing IBM MobileFirst pinTrustedCertificatePublicKey {2}: ' + cert);
                        return;
                    };
                } catch (err) {
                    console.log('[-] IBM MobileFirst pinTrustedCertificatePublicKey {2} pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // IBM WorkLight (ancestor of MobileFirst) HostNameVerifierWithCertificatePinning (quadruple bypass) //
                ///////////////////////////////////////////////////////////////////////////////////////////////////////
                try {
                    // Bypass IBM WorkLight {1}
                    var worklight_Activity_1 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
                    worklight_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSocket').implementation = function(a, b) {
                        console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {1}: ' + a);
                        return;
                    };
                } catch (err) {
                    console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {1} pinner not found');
                    //console.log(err);
                }
                try {
                    // Bypass IBM WorkLight {2}
                    var worklight_Activity_2 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
                    worklight_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function(a, b) {
                        console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {2}: ' + a);
                        return;
                    };
                } catch (err) {
                    console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {2} pinner not found');
                    //console.log(err);
                }
                try {
                    // Bypass IBM WorkLight {3}
                    var worklight_Activity_3 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
                    worklight_Activity_3.verify.overload('java.lang.String', '[Ljava.lang.String;', '[Ljava.lang.String;').implementation = function(a, b) {
                        console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {3}: ' + a);
                        return;
                    };
                } catch (err) {
                    console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {3} pinner not found');
                    //console.log(err);
                }
                try {
                    // Bypass IBM WorkLight {4}
                    var worklight_Activity_4 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
                    worklight_Activity_4.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(a, b) {
                        console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {4}: ' + a);
                        return true;
                    };
                } catch (err) {
                    console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {4} pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // Conscrypt CertPinManager //
                //////////////////////////////
                try {
                    var conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager');
                    conscrypt_CertPinManager_Activity.checkChainPinning.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
                        console.log('[+] Bypassing Conscrypt CertPinManager: ' + a);
                        //return;
                        return true;
                    };
                } catch (err) {
                    console.log('[-] Conscrypt CertPinManager pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // Conscrypt CertPinManager (Legacy) //
                ///////////////////////////////////////
                try {
                    var legacy_conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager');
                    legacy_conscrypt_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
                        console.log('[+] Bypassing Conscrypt CertPinManager (Legacy): ' + a);
                        return true;
                    };
                } catch (err) {
                    console.log('[-] Conscrypt CertPinManager (Legacy) pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // CWAC-Netsecurity (unofficial back-port pinner for Android<4.2) CertPinManager //
                ///////////////////////////////////////////////////////////////////////////////////
                try {
                    var cwac_CertPinManager_Activity = Java.use('com.commonsware.cwac.netsecurity.conscrypt.CertPinManager');
                    cwac_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
                        console.log('[+] Bypassing CWAC-Netsecurity CertPinManager: ' + a);
                        return true;
                    };
                } catch (err) {
                    console.log('[-] CWAC-Netsecurity CertPinManager pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // Worklight Androidgap WLCertificatePinningPlugin //
                /////////////////////////////////////////////////////
                try {
                    var androidgap_WLCertificatePinningPlugin_Activity = Java.use('com.worklight.androidgap.plugin.WLCertificatePinningPlugin');
                    androidgap_WLCertificatePinningPlugin_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function(a, b, c) {
                        console.log('[+] Bypassing Worklight Androidgap WLCertificatePinningPlugin: ' + a);
                        return true;
                    };
                } catch (err) {
                    console.log('[-] Worklight Androidgap WLCertificatePinningPlugin pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // Netty FingerprintTrustManagerFactory //
                //////////////////////////////////////////
                try {
                    var netty_FingerprintTrustManagerFactory = Java.use('io.netty.handler.ssl.util.FingerprintTrustManagerFactory');
                    //NOTE: sometimes this below implementation could be useful
                    //var netty_FingerprintTrustManagerFactory = Java.use('org.jboss.netty.handler.ssl.util.FingerprintTrustManagerFactory');
                    netty_FingerprintTrustManagerFactory.checkTrusted.implementation = function(type, chain) {
                        console.log('[+] Bypassing Netty FingerprintTrustManagerFactory');
                    };
                } catch (err) {
                    console.log('[-] Netty FingerprintTrustManagerFactory pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // Squareup CertificatePinner [OkHTTP<v3] (double bypass) //
                ////////////////////////////////////////////////////////////
                try {
                    // Bypass Squareup CertificatePinner  {1}
                    var Squareup_CertificatePinner_Activity_1 = Java.use('com.squareup.okhttp.CertificatePinner');
                    Squareup_CertificatePinner_Activity_1.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function(a, b) {
                        console.log('[+] Bypassing Squareup CertificatePinner {1}: ' + a);
                        return;
                    };
                } catch (err) {
                    console.log('[-] Squareup CertificatePinner {1} pinner not found');
                    //console.log(err);
                }
                try {
                    // Bypass Squareup CertificatePinner {2}
                    var Squareup_CertificatePinner_Activity_2 = Java.use('com.squareup.okhttp.CertificatePinner');
                    Squareup_CertificatePinner_Activity_2.check.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
                        console.log('[+] Bypassing Squareup CertificatePinner {2}: ' + a);
                        return;
                    };
                } catch (err) {
                    console.log('[-] Squareup CertificatePinner {2} pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // Squareup OkHostnameVerifier [OkHTTP v3] (double bypass) //
                /////////////////////////////////////////////////////////////
                try {
                    // Bypass Squareup OkHostnameVerifier {1}
                    var Squareup_OkHostnameVerifier_Activity_1 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
                    Squareup_OkHostnameVerifier_Activity_1.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function(a, b) {
                        console.log('[+] Bypassing Squareup OkHostnameVerifier {1}: ' + a);
                        return true;
                    };
                } catch (err) {
                    console.log('[-] Squareup OkHostnameVerifier check not found');
                    //console.log(err);
                }
                try {
                    // Bypass Squareup OkHostnameVerifier {2}
                    var Squareup_OkHostnameVerifier_Activity_2 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
                    Squareup_OkHostnameVerifier_Activity_2.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(a, b) {
                        console.log('[+] Bypassing Squareup OkHostnameVerifier {2}: ' + a);
                        return true;
                    };
                } catch (err) {
                    console.log('[-] Squareup OkHostnameVerifier check not found');
                    //console.log(err);
                }
        
        
        
        
                // Android WebViewClient (quadruple bypass) //
                //////////////////////////////////////////////
                try {
                    // Bypass WebViewClient {1} (deprecated from Android 6)
                    var AndroidWebViewClient_Activity_1 = Java.use('android.webkit.WebViewClient');
                    AndroidWebViewClient_Activity_1.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function(obj1, obj2, obj3) {
                        console.log('[+] Bypassing Android WebViewClient check {1}');
                    };
                } catch (err) {
                    console.log('[-] Android WebViewClient {1} check not found');
                    //console.log(err)
                }
                try {
                    // Bypass WebViewClient {2}
                    var AndroidWebViewClient_Activity_2 = Java.use('android.webkit.WebViewClient');
                    AndroidWebViewClient_Activity_2.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function(obj1, obj2, obj3) {
                        console.log('[+] Bypassing Android WebViewClient check {2}');
                    };
                } catch (err) {
                    console.log('[-] Android WebViewClient {2} check not found');
                    //console.log(err)
                }
                try {
                    // Bypass WebViewClient {3}
                    var AndroidWebViewClient_Activity_3 = Java.use('android.webkit.WebViewClient');
                    AndroidWebViewClient_Activity_3.onReceivedError.overload('android.webkit.WebView', 'int', 'java.lang.String', 'java.lang.String').implementation = function(obj1, obj2, obj3, obj4) {
                        console.log('[+] Bypassing Android WebViewClient check {3}');
                    };
                } catch (err) {
                    console.log('[-] Android WebViewClient {3} check not found');
                    //console.log(err)
                }
                try {
                    // Bypass WebViewClient {4}
                    var AndroidWebViewClient_Activity_4 = Java.use('android.webkit.WebViewClient');
                    AndroidWebViewClient_Activity_4.onReceivedError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function(obj1, obj2, obj3) {
                        console.log('[+] Bypassing Android WebViewClient check {4}');
                    };
                } catch (err) {
                    console.log('[-] Android WebViewClient {4} check not found');
                    //console.log(err)
                }
        
        
        
        
                // Apache Cordova WebViewClient //
                //////////////////////////////////
                try {
                    var CordovaWebViewClient_Activity = Java.use('org.apache.cordova.CordovaWebViewClient');
                    CordovaWebViewClient_Activity.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function(obj1, obj2, obj3) {
                        console.log('[+] Bypassing Apache Cordova WebViewClient check');
                        obj3.proceed();
                    };
                } catch (err) {
                    console.log('[-] Apache Cordova WebViewClient check not found');
                    //console.log(err);
                }
        
        
        
        
                // Boye AbstractVerifier //
                ///////////////////////////
                try {
                    var boye_AbstractVerifier = Java.use('ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier');
                    boye_AbstractVerifier.verify.implementation = function(host, ssl) {
                        console.log('[+] Bypassing Boye AbstractVerifier check: ' + host);
                    };
                } catch (err) {
                    console.log('[-] Boye AbstractVerifier check not found');
                    //console.log(err);
                }
        
        
        
        
                // Apache AbstractVerifier //
                /////////////////////////////
                try {
                    var apache_AbstractVerifier = Java.use('org.apache.http.conn.ssl.AbstractVerifier');
                    apache_AbstractVerifier.verify.implementation = function(a, b, c, d) {
                        console.log('[+] Bypassing Apache AbstractVerifier check: ' + a);
                        return;
                    };
                } catch (err) {
                    console.log('[-] Apache AbstractVerifier check not found');
                    //console.log(err);
                }
        
        
        
        
                // Chromium Cronet //
                /////////////////////
                try {
                    var CronetEngineBuilderImpl_Activity = Java.use("org.chromium.net.impl.CronetEngineBuilderImpl");
                    // Setting argument to TRUE (default is TRUE) to disable Public Key pinning for local trust anchors
                    CronetEngine_Activity.enablePublicKeyPinningBypassForLocalTrustAnchors.overload('boolean').implementation = function(a) {
                        console.log("[+] Disabling Public Key pinning for local trust anchors in Chromium Cronet");
                        var cronet_obj_1 = CronetEngine_Activity.enablePublicKeyPinningBypassForLocalTrustAnchors.call(this, true);
                        return cronet_obj_1;
                    };
                    // Bypassing Chromium Cronet pinner
                    CronetEngine_Activity.addPublicKeyPins.overload('java.lang.String', 'java.util.Set', 'boolean', 'java.util.Date').implementation = function(hostName, pinsSha256, includeSubdomains, expirationDate) {
                        console.log("[+] Bypassing Chromium Cronet pinner: " + hostName);
                        var cronet_obj_2 = CronetEngine_Activity.addPublicKeyPins.call(this, hostName, pinsSha256, includeSubdomains, expirationDate);
                        return cronet_obj_2;
                    };
                } catch (err) {
                    console.log('[-] Chromium Cronet pinner not found')
                    //console.log(err);
                }
        
        
        
                // Flutter Pinning packages http_certificate_pinning and ssl_pinning_plugin (double bypass) //
                //////////////////////////////////////////////////////////////////////////////////////////////
                try {
                    // Bypass HttpCertificatePinning.check {1}
                    var HttpCertificatePinning_Activity = Java.use('diefferson.http_certificate_pinning.HttpCertificatePinning');
                    HttpCertificatePinning_Activity.checkConnexion.overload("java.lang.String", "java.util.List", "java.util.Map", "int", "java.lang.String").implementation = function (a, b, c ,d, e) {
                        console.log('[+] Bypassing Flutter HttpCertificatePinning : ' + a);
                        return true;
                    };
                } catch (err) {
                    console.log('[-] Flutter HttpCertificatePinning pinner not found');
                    //console.log(err);
                }
                try {
                    // Bypass SslPinningPlugin.check {2}
                    var SslPinningPlugin_Activity = Java.use('com.macif.plugin.sslpinningplugin.SslPinningPlugin');
                    SslPinningPlugin_Activity.checkConnexion.overload("java.lang.String", "java.util.List", "java.util.Map", "int", "java.lang.String").implementation = function (a, b, c ,d, e) {
                        console.log('[+] Bypassing Flutter SslPinningPlugin: ' + a);
                        return true;
                    };
                } catch (err) {
                    console.log('[-] Flutter SslPinningPlugin pinner not found');
                    //console.log(err);
                }
        
        
        
        
                // Dynamic SSLPeerUnverifiedException Patcher                                //
                // An useful technique to bypass SSLPeerUnverifiedException failures raising //
                // when the Android app uses some uncommon SSL Pinning methods or an heavily //
                // code obfuscation. Inspired by an idea of: https://github.com/httptoolkit  //
                ///////////////////////////////////////////////////////////////////////////////
                function rudimentaryFix(typeName) {
                    // This is a improvable rudimentary fix, if not works you can patch it manually
                    if (typeName === undefined){
                        return;
                    } else if (typeName === 'boolean') {
                        return true;
                    } else {
                        return null;
                    }
                }
                try {
                    var UnverifiedCertError = Java.use('javax.net.ssl.SSLPeerUnverifiedException');
                    UnverifiedCertError.$init.implementation = function (str) {
                        console.log('\x1b[36m[!] Unexpected SSLPeerUnverifiedException occurred, trying to patch it dynamically...\x1b[0m');
                        try {
                            var stackTrace = Java.use('java.lang.Thread').currentThread().getStackTrace();
                            var exceptionStackIndex = stackTrace.findIndex(stack =>
                                stack.getClassName() === "javax.net.ssl.SSLPeerUnverifiedException"
                            );
                            // Retrieve the method raising the SSLPeerUnverifiedException
                            var callingFunctionStack = stackTrace[exceptionStackIndex + 1];
                            var className = callingFunctionStack.getClassName();
                            var methodName = callingFunctionStack.getMethodName();
                            var callingClass = Java.use(className);
                            var callingMethod = callingClass[methodName];
                            console.log('\x1b[36m[!] Attempting to bypass uncommon SSL Pinning method on: '+className+'.'+methodName+'\x1b[0m');
                            // Skip it when already patched by Frida
                            if (callingMethod.implementation) {
                                return;
                            }
                            // Trying to patch the uncommon SSL Pinning method via implementation
                            var returnTypeName = callingMethod.returnType.type;
                            callingMethod.implementation = function() {
                                rudimentaryFix(returnTypeName);
                            };
                        } catch (e) {
                            // Dynamic patching via implementation does not works, then trying via function overloading
                            //console.log('[!] The uncommon SSL Pinning method has more than one overload);
                            if (String(e).includes(".overload")) {
                                var splittedList = String(e).split(".overload");
                                for (let i=2; i<splittedList.length; i++) {
                                    var extractedOverload = splittedList[i].trim().split("(")[1].slice(0,-1).replaceAll("'","");
                                    // Check if extractedOverload has multiple arguments
                                    if (extractedOverload.includes(",")) {
                                        // Go here if overloaded method has multiple arguments (NOTE: max 6 args are covered here)
                                        var argList = extractedOverload.split(", ");
                                        console.log('\x1b[36m[!] Attempting overload of '+className+'.'+methodName+' with arguments: '+extractedOverload+'\x1b[0m');
                                        if (argList.length == 2) {
                                            callingMethod.overload(argList[0], argList[1]).implementation = function(a,b) {
                                                rudimentaryFix(returnTypeName);
                                            }
                                        } else if (argNum == 3) {
                                            callingMethod.overload(argList[0], argList[1], argList[2]).implementation = function(a,b,c) {
                                                rudimentaryFix(returnTypeName);
                                            }
                                        }  else if (argNum == 4) {
                                            callingMethod.overload(argList[0], argList[1], argList[2], argList[3]).implementation = function(a,b,c,d) {
                                                rudimentaryFix(returnTypeName);
                                            }
                                        }  else if (argNum == 5) {
                                            callingMethod.overload(argList[0], argList[1], argList[2], argList[3], argList[4]).implementation = function(a,b,c,d,e) {
                                                rudimentaryFix(returnTypeName);
                                            }
                                        }  else if (argNum == 6) {
                                            callingMethod.overload(argList[0], argList[1], argList[2], argList[3], argList[4], argList[5]).implementation = function(a,b,c,d,e,f) {
                                                rudimentaryFix(returnTypeName);
                                            }
                                        }
                                    // Go here if overloaded method has a single argument
                                    } else {
                                        callingMethod.overload(extractedOverload).implementation = function(a) {
                                            rudimentaryFix(returnTypeName);
                                        }
                                    }
                                }
                            } else {
                                console.log('\x1b[36m[-] Failed to dynamically patch SSLPeerUnverifiedException '+e+'\x1b[0m');
                            }
                        }
                        //console.log('\x1b[36m[+] SSLPeerUnverifiedException hooked\x1b[0m');
                        return this.$init(str);
                    };
                } catch (err) {
                    //console.log('\x1b[36m[-] SSLPeerUnverifiedException not found\x1b[0m');
                    //console.log('\x1b[36m'+err+'\x1b[0m');
                }
            });
        
        }, 0);
        View Code
      • 脚本启动方式:
        frida -U -f [APP_ID] -l frida_multiple_unpinning.js
        frida -UF -l frida_multiple_unpinning.js

        注意:frida的hook检测,比如安居客需要删除文件:libmsaoaidsec.so

    • 2、Xposed Hook

      • 安装 Magisk 面具(手机root)

      • 在面具中刷入LSPosed框架
        • 下载Zygisk-LSPosed:https://github.com/LSPosed/LSPosed/releases
        • Magisk开启Zygisk
        • 上传Zygisk-LSPosed zip文件,并在Magisk中进行安装
        • 刷入成功后,就可以看到 LSPosed 的图标,如果没有出现的话,可以通过MT、NP等管理器去手机的 /data/adb/lspd/目录下找manager.apk包,然后再点击安装即可。
      • 安装JustTrustMePlus.apk
        • 在LSPosed中启用模块,并勾选上需要启用该模块的app

三、服务端证书校验

  • - 在客户端预设证书(p12/bks)
    - 客户端向服务端发送请求时,携带证书信息,在服务端会校验客户端携带过来证书的合法性
  • 校验时逻辑
    • apk打包时,通常将 bks 或 p12 格式的证书保存在assets 或 raw 等目录
    • 安卓代码发送请求时,会读取【证书内容】+【证书密码】
    • 注意:一般大点的公司不会采用服务端证书校验,因为会增加服务器压力
  • 逆向
    • 1、Hook密码

      Java.perform(function () {
          var KeyStore = Java.use("java.security.KeyStore");
      
          KeyStore.load.overload('java.io.InputStream', '[C').implementation = function (v1, v2) {
              var pwd = Java.use("java.lang.String").$new(v2);
              console.log('\n------------')
              console.log("类型:" + this.getType());
              console.log("密码:" + pwd);
              // console.log(JSON.stringify(v1));
              //console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
              var res = this.load(v1, v2);
              return res;
          };
      });
      // frida -U -f com.paopaotalk.im -l 1.hook_password.js

      KeyStore.load是系统函数,所以这是一个通用hook脚本

    • 2、获取证书文件

      • 方式1:定位代码,找到加载证书的文件路径,然后去apk中寻找
      • 方式2:Hook证书文件【注意:手机需要对当前app开启存储权限】
        Java.perform(function () {
            var KeyStore = Java.use("java.security.KeyStore");
            var String = Java.use("java.lang.String");
        
        
            KeyStore.load.overload('java.io.InputStream', '[C').implementation = function (inputStream, v2) {
                var pwd = String.$new(v2);
                console.log('\n------------')
                console.log("密码:" + pwd, "类型:" + this.getType());
        
                if (this.getType() === "BKS") {
                    var myArray = new Array(1024);
                    for (var i = 0; i < myArray.length; i++) {
                        myArray[i] = 0x0;
                    }
                    var buffer = Java.array('byte', myArray);
                    var file = Java.use("java.io.File").$new("/sdcard/Download/cert-" + new Date().getTime() + ".bks");
                    var out = Java.use("java.io.FileOutputStream").$new(file);
                    var r;
                    while ((r = inputStream.read(buffer)) > 0) {
                        out.write(buffer, 0, r);
                    }
                    console.log("save success!")
                    out.close()
                } else if (this.getType() === "pkcs12") {
                    var myArray = new Array(1024);
                    for (var i = 0; i < myArray.length; i++) {
                        myArray[i] = 0x0;
                    }
                    var buffer = Java.array('byte', myArray);
                    var file = Java.use("java.io.File").$new("/sdcard/Download/cert-" + new Date().getTime() + ".p12");
                    var out = Java.use("java.io.FileOutputStream").$new(file);
                    var r;
                    while ((r = inputStream.read(buffer)) > 0) {
                        out.write(buffer, 0, r);
                    }
                    console.log("save success!")
                    out.close()
                }
        
                var res = this.load(inputStream, v2);
                return res;
            };
        
        });
        
        // frida -U -f com.paopaotalk.im -l hook_cert.js
        View Code
    • 3、转换证书格式

      • charles不支持导入bks格式的证书,如果逆向过程中得到了bks格式证书,需要使用 portecle 将bks证书转化弄成p12格式,然后再处理。
        • 启动portecle :
          java -jar portecle.jar

          或者直接双击portecle.jar也可以打开

        • 打开bks文件:【File】-【Open Keystore File...】-【找到文件,输入上述hook到的密码】
        • 导出p12文件:【右击文件】-【Export】-【导出类型选择:Private Key and Certificates】-【导出格式选择:PKCS12】
    • 4、charles导入证书

      • 【Proxy】-【SSL Proxying Settings】-【选择Client Certificates】-【add】-【Host和Port可以选填:*】-【选择Import P12】-【输入密码】
    • 5、Python如何发送请求

      • 方式1:
        • 使用requests-pkcs12模块
          pip install requests-pkcs12
        • 代码示例:
          from requests_pkcs12 import get, post
          
          res = post(
              url='https://39.108.102.14:46077/userservices/v2/user/login',
              json={
                  "device_type": "app"
              },
              headers={
                  "bundle_id": "com.paopaotalk.im"
              },
              pkcs12_filename='Client.p12',
              pkcs12_password='111111',
              verify=False
          )
          print(res.text)
      • 方式2:
        • 使用requests模块(亲测不推荐)
          • 默认requests不支持直接使用p12格式的证书,所以需要将p12转换成pem才可以
            openssl pkcs12 -in Client.p12 -out demo.pem -nodes -passin 'pass:111111'
          • 代码示例:
            from requests import post
            
            res = post(
                url='https://39.108.102.14:46077/userservices/v2/user/login',
                json={
                    "device_type": "app"
                },
                headers={
                    "bundle_id": "com.paopaotalk.im"
                },
                cert='demo.pem',
                verify=False
            )
            print(res.text)

             openssl转换证书格式貌似不太好使,不推荐这种方案

四、代码混淆

  • 关于混淆
    • 第三方的包是可以进行混淆的,例如:OKHttp3.Http.Cert.check 被混淆后可以是a.f.c.b 形式
    • 系统包不会被混淆,比如:java.lang.String
    • 因此:代码混淆针对的是【客户端证书的校验】
  • 解决思路:
    • Hook系统底层必走的核心方法,获取调用栈
    • 根据调用栈向上寻找到客户端证书校验的代码位置,通过GDA/Jadx等工具分析源码,对代码混淆前后的类名和方法名进行比对
    • 编写frida Hook脚本
  • 客户端证书校验顺序
    • 注意:内部按照顺序对这个3个过程进行校验,只要有一个无法通过,后续的校验就不会再触发执行。上述三个校验的触发位置是在:okhttp3.internal.connection.RealConnection类中的connectTls方法

  • Hook流程
    • 1、Hook系统方法connectTls位置【同时也能过证书校验】
      Java.perform(function () {
          var Platform = Java.use('com.android.org.conscrypt.Platform');
          Platform.checkServerTrusted.overload('javax.net.ssl.X509TrustManager', '[Ljava.security.cert.X509Certificate;', 'java.lang.String', 'com.android.org.conscrypt.AbstractConscryptSocket').implementation = function (x509tm, chain, authType, socket) {
              console.log('\n[+] checkServer  ',x509tm,JSON.stringify(x509tm) );
              console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
              // 这里会去调用客户端证书校验的方法,不执行,就是不去校验(直接通过)。
              // return this.checkServerTrusted(x509tm, chain, authType, socket);
          };
      });
      
      // frida -U -f cn.ticktick.task -l hook_system.js

      根据调用栈向上找到证书校验的位置,即com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake的上一级调用栈(日志直接看它的下一行),然后通过GDA等查看源码进行比对

    • 2、Hook【主机校验:verify方法】----需要分两步
      • 第一步
        • Hook connectTls方法,读取内部的hostNameVerifier值,从而获取混淆后的类名【需要使用反射】
          Java.perform(function () {
              // 反射获取对象属性
              function getFieldValue(obj, fieldName) {
                  var cls = obj.getClass();
                  var field = cls.getDeclaredField(fieldName);
                  field.setAccessible(true);
                  var value = field.get(obj);
                  return value;
              }var RealConnection = Java.use('uk.c');
              RealConnection.f.implementation = function (a, b, c, d) {
                  try {
                      // 源码:【!a1.j.verify()】  =>  【this.c.a.j.verify()】
                      var route = getFieldValue(this, "c");
                      console.log('route=', route);
                      var address = getFieldValue(route, 'a');
                      console.log('address=', address);
                      var hostnameVerifier = getFieldValue(address, 'j');
                      console.log('\n[+++] hostnameVerifier', JSON.stringify(hostnameVerifier));
          
                  } catch (e) {
                      console.log(e);
                  }
                  return this.f(a, b, c, d);
              };
          });
      • 第二步
        • 根据上述Hook结果,进行Hook
          Java.perform(function () {
              var d = Java.use('al.d');
              d.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(a, b){
                  console.log('2、主机名校验:verify。。。')
                  return true;
              }
          });
    • 3、Hook 【Pinner公钥校验:check方法】
      • 可以参照frida_multiple_unpinning脚本中的写法,但是具体的类和方法名需要替换成混淆后的【即原check方法】
        Java.perform(function () {
            var pinner = Java.use('rk.f');
            pinner.a.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
                console.log('[+] pinner check ' + a);
                return;
            };
        });
        
        // frida -UF -l hook_check.js
  • 示例:滴答清单v6.3.3.0【需要同时hook过校验】
    Java.perform(function () {
    
        // 1、证书校验
        var Platform = Java.use('com.android.org.conscrypt.Platform');
        Platform.checkServerTrusted.overload('javax.net.ssl.X509TrustManager', '[Ljava.security.cert.X509Certificate;', 'java.lang.String', 'com.android.org.conscrypt.AbstractConscryptSocket').implementation = function (x509tm, chain, authType, socket) {
            // console.log('\n[+] checkServer  ',x509tm,JSON.stringify(x509tm) );
            // console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
            // 这里会去调用客户端证书校验的方法,不执行,就是不去校验(直接通过)。
            // return this.checkServerTrusted(x509tm, chain, authType, socket);
            console.log('1、证书校验。。。')
        };
    
        // 2、主机名校验
        var d = Java.use('al.d');
        d.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(a, b){
            console.log('2、主机名校验:verify。。。')
            return true;
        }
    
        // 3、pinner公钥校验
        var pinner = Java.use('rk.f');
        pinner.a.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
            console.log('3、pinner公钥check。。。');
            return;
        };
    });

     

标签:function,use,专题,console,log,app,var,Java,抓包
From: https://www.cnblogs.com/eliwang/p/18023833

相关文章

  • csapp Lab1
    frompixiv环境配置问题当我按照官网Lab1中的WriteUp对项目进行make时,出现如下错误:很快我找到了问题的原因:fromthere但是在aptinstall时又出现了问题:查找网络,说是Ubuntu版本太高,但是apt的源太低,要aptupdate但是在aptupdate时又出现问题:解决方法如法炮制:......
  • Apple Watch
    全新未开封。AppleWatch(铝),运动型表带以及USB-C充电线,要求iPhone8或后续机型,配iOS16或更高版本。MidnightAluminumCase,MidnightSportBandSeries841mmMidAluMidSpGPS型号:A2770Apple产品京东自营旗舰店:https://item.jd.com/100038004483.html价格:2449......
  • APP开发好后如何快速进行内测分发
    在APP开发过程中,内测是非常关键的一环。内测不仅能够帮助开发团队发现潜在的问题,还能确保应用在正式上线前具备良好的用户体验。那么,APP开发好后如何快速进行内测呢?今天,我将为大家分享一些实用的经验和建议,并带大家了解虾分发平台xiafenfa.com,它将成为您APP内测的强大后盾。首先,......
  • 实体类与数据库的直接交互问题,DTO,AutoMapper的使用
    实体类、DTO与数据库交互的最佳实践实体类与数据库的直接交互问题在软件开发中,实体类通常被设计为反映业务域的数据模型。这些实体类可能包含以下元素:特性(Attributes):用于定义实体属性的额外信息,比如数据验证规则或ORM(对象关系映射)框架的映射信息。继承关系:实体之间可能存......
  • uniapp清除指定key缓存
    清除缓存onLaunch:function(){console.log('AppLaunch')constpreservedKeys=['ishowFixPre','readTime']try{const{keys}=uni.getStorageInfoSync()keys.forEach((key)=>......
  • AppleScript成功实现FaceTime语音,FaceTime视频,FaceTime蓝号检测,检测数据是否开通Fa
    FaceTime是苹果公司iOS和macOS(以前称MacOSX或OSX)内置的一款视频通话软件,通过Wi-Fi或者蜂窝数据接入互联网,在两个装有FaceTime的设备之间实现视频通话。其要求通话双方均具有装有FaceTime的苹果设备,苹果ID以及可接入互联网的3G/4G/5G或者Wi-Fi网络。 一、Windows电脑上部署......
  • burpsuit app 抓包 安卓7.0以上证书制作
    burpsuitapp抓包以及安卓7.0以上证书制作前言:今天在使用某校园跑脚本时需要上传token,只能抓包获取,但发现安卓7.0以上的证书不能直接导入,故记录一下制作以及导入方式。首先我们要从burpsuite的客户端或者官方网页获得证书,将证书放在kali中或其他带有openssl的linux系统中,对其......
  • pyest+appium实现APP自动化测试,思路全总结在这里
    01、appium环境搭建安装nodejshttp://nodejs.cn/为什么要安装nodejs?因为appium这个工具的服务端是由nodejs语言开发的 安装jdk,并且配置环境变量为什么要装jdk?因为我们要测试安卓,那么安卓的调试环境需要依赖jdk 安装sdk,并配置环境变量为什么要装sdk?因为我们要......
  • 关于uniapp调用支付宝登录问题
    uniapp的uni.login的provider不支持支付宝但是呢,我看插件市场都要钱这个还需要钱吗你直接硬写呗,支付宝比如登录官方时这么写的ok 我们在uniapp上也这么写就行了button调用一键登录uniapp不会报错,然后我们发行打包到支付宝的开发工具里经测试可以正常使用 返回 ......
  • 长连接网关技术专题(十):百度基于Go的千万级统一长连接服务架构实践
    本文由百度技术团队分享,引用自百度Geek说,原题“千万级高性能长连接Go服务架构实践”,为了阅读便利,本文进行了排版优化等。1、引言移动互联网时代,长连接服务成为了提升应用实时性和互动性的基础服务。本文将介绍百度基于golang实现的统一长连接服务,从统一长连接功能实现和性能......