Android 繞過反代理抓包

在給一個(gè)App抓包的時(shí)候遇到一個(gè)難題攒磨,一旦使用charles代理之后泳桦,app內(nèi)所有的網(wǎng)絡(luò)都失效了,于是我懷疑APP鎖定證書了娩缰。

于是我想到了安全部門安利的一個(gè)軟件frida灸撰,一頓學(xué)習(xí)之后找到了解決方案,通過hook解除了證書鎖定拼坎。(限定于以下網(wǎng)絡(luò)框架)

1.SSLcontext
2.okhttp
3.webview
4.XUtils
5.httpclientandroidlib
6.JSSE
7.network_security_config (android 7.0+)
8.Apache Http client (support partly)

介紹一下frida:

它可以用來修改修改Java層的函數(shù)參數(shù)和返回值
它可以打印Java層的方法堆棧信息
它可以攔截?cái)r截native層的函數(shù)參數(shù)和返回值

  • 第一步 安裝好python 安裝好pip

  • 第二步 安裝frida

    pip install frida
  • 第三步 把frida-server 推送到手機(jī)并且運(yùn)行

    根據(jù)手機(jī)平臺(tái)下載和frida一致版本的 frida-server https://github.com/frida/frida/releases
    比如我的手機(jī)的frida是12.2.27 則我下載frida-server-12.2.27-android-arm.xz
    解壓并且把文件命名為frida-server 推送到手機(jī)
adb push /data/local/tmp frida-server

給文件相應(yīng)的權(quán)限

    chmod 777 /data/local/tmp/frida-server
  • 第四步運(yùn)行

    cd /data/local/tmp
    ./frida-server
  • 第五步 把端口轉(zhuǎn)發(fā)到PC端

    adb forward tcp:27042 tcp:27042
    adb forward tcp:27043 tcp:27043

這樣就建立了手機(jī)和pc端的鏈接

  • 驗(yàn)證一下是否成功

frida-ps -R

如果出現(xiàn)這樣的列表則表示成功

  PID  Name
-----  --------------------------------
 1246  adbd
20790  android.process.TrafficMonitor
21379  android.process.acore
22519  android.process.blacklist
20672  android.process.media
21272  android.process.oppovirusdetect
20767  android.process.safer
       ...
  • 另外一種方式免root使用frida

針對(duì)無殼app,有殼app需要先脫殼.

手動(dòng)完成frida gadget注入和調(diào)用.

1.apktool反編譯apk

$ apktool d test.apk -o test

2.將對(duì)應(yīng)版本的gadget拷貝到/lib沒有了下.例如arm32的設(shè)備路徑如下.

/lib/armeabi/libfrida-gadget.so

下載地址:

https://github.com/frida/frida/releases/

3.smali注入加載library,選擇application類或者Activity入口.

const-string v0, "frida-gadget" invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V

4.如果apk沒有網(wǎng)絡(luò)權(quán)限需要在配置清單中加入如下權(quán)限申明

<uses-permission android:name="android.permission.INTERNET" />

5.回編譯apk

$ apktool b -o newtest.apk test/

6.重新簽名安裝運(yùn)行.成功后啟動(dòng)app會(huì)有如下日志

Frida: Listening on TCP port 27042
  • 第六步接下來就可以編寫hook的程序了 hook.js

    Java.perform(function() {

/*
hook list:
1.SSLcontext
2.okhttp
3.webview
4.XUtils
5.httpclientandroidlib
6.JSSE
7.network\_security\_config (android 7.0+)
8.Apache Http client (support partly)
*/

// Attempts to bypass SSL pinning implementations in a number of
// ways. These include implementing a new TrustManager that will
// accept any SSL certificate, overriding OkHTTP v3 check()
// method etc.
var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
var HostnameVerifier = Java.use('javax.net.ssl.HostnameVerifier');
var SSLContext = Java.use('javax.net.ssl.SSLContext');
var quiet_output = false;

// Helper method to honor the quiet flag.
function quiet_send(data) {

    if (quiet_output) {

        return;
    }

    send(data)
}


// Implement a new TrustManager
// ref: https://gist.github.com/oleavr/3ca67a173ff7d207c6b8c3b0ca65a9d8
// Java.registerClass() is only supported on ART for now(201803). 所以android 4.4以下不兼容,4.4要切換成ART使用.
/*
06-07 16:15:38.541 27021-27073/mi.sslpinningdemo W/System.err: java.lang.IllegalArgumentException: Required method checkServerTrusted(X509Certificate[], String, String, String) missing
06-07 16:15:38.542 27021-27073/mi.sslpinningdemo W/System.err:     at android.net.http.X509TrustManagerExtensions.<init>(X509TrustManagerExtensions.java:73)
        at mi.ssl.MiPinningTrustManger.<init>(MiPinningTrustManger.java:61)
06-07 16:15:38.543 27021-27073/mi.sslpinningdemo W/System.err:     at mi.sslpinningdemo.OkHttpUtil.getSecPinningClient(OkHttpUtil.java:112)
        at mi.sslpinningdemo.OkHttpUtil.get(OkHttpUtil.java:62)
        at mi.sslpinningdemo.MainActivity$1$1.run(MainActivity.java:36)
*/
var X509Certificate = Java.use("java.security.cert.X509Certificate");
var TrustManager;
try {
    TrustManager = Java.registerClass({
        name: 'org.wooyun.TrustManager',
        implements: [X509TrustManager],
        methods: {
            checkClientTrusted: function (chain, authType) {
            },
            checkServerTrusted: function (chain, authType) {
            },
            getAcceptedIssuers: function () {
                // var certs = [X509Certificate.$new()];
                // return certs;
                return [];
            }
        }
    });
} catch (e) {
    console.log("registerClass from X509TrustManager >>>>>>>> " + e.message);
}





// Prepare the TrustManagers array to pass to SSLContext.init()
var TrustManagers = [TrustManager.$new()];

try {
    // Prepare a Empty SSLFactory
    var TLS_SSLContext = SSLContext.getInstance("TLS");
    TLS_SSLContext.init(null,TrustManagers,null);
    var EmptySSLFactory = TLS_SSLContext.getSocketFactory();
} catch (e) {
    console.log(e.message);
}

send('Custom, Empty TrustManager ready');

// 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');

// Override the init method, specifying our new TrustManager
SSLContext_init.implementation = function (keyManager, trustManager, secureRandom) {

    quiet_send('Overriding SSLContext.init() with the custom TrustManager');

    SSLContext_init.call(this, null, TrustManagers, null);
};

/*** okhttp3.x unpinning ***/


// Wrap the logic in a try/catch as not all applications will have
// okhttp as part of the app.
try {

    var CertificatePinner = Java.use('okhttp3.CertificatePinner');

    console.log('OkHTTP 3.x Found');

    CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function () {

        quiet_send('OkHTTP 3.x check() called. Not throwing an exception.');
    }

} catch (err) {

    // If we dont have a ClassNotFoundException exception, raise the
    // problem encountered.
    if (err.message.indexOf('ClassNotFoundException') === 0) {

        throw new Error(err);
    }
}

// Appcelerator Titanium PinningTrustManager

// Wrap the logic in a try/catch as not all applications will have
// appcelerator as part of the app.
try {

    var PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager');

    send('Appcelerator Titanium Found');

    PinningTrustManager.checkServerTrusted.implementation = function () {

        quiet_send('Appcelerator checkServerTrusted() called. Not throwing an exception.');
    }

} catch (err) {

    // If we dont have a ClassNotFoundException exception, raise the
    // problem encountered.
    if (err.message.indexOf('ClassNotFoundException') === 0) {

        throw new Error(err);
    }
}

/*** okhttp unpinning ***/


try {
    var OkHttpClient = Java.use("com.squareup.okhttp.OkHttpClient");
    OkHttpClient.setCertificatePinner.implementation = function(certificatePinner){
        // do nothing
        console.log("OkHttpClient.setCertificatePinner Called!");
        return this;
    };

    // Invalidate the certificate pinnet checks (if "setCertificatePinner" was called before the previous invalidation)
    var CertificatePinner = Java.use("com.squareup.okhttp.CertificatePinner");
    CertificatePinner.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function(p0, p1){
        // do nothing
        console.log("okhttp Called! [Certificate]");
        return;
    };
    CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function(p0, p1){
        // do nothing
        console.log("okhttp Called! [List]");
        return;
    };
} catch (e) {
 console.log("com.squareup.okhttp not found");
}

/*** WebView Hooks ***/

/* frameworks/base/core/java/android/webkit/WebViewClient.java */
/* public void onReceivedSslError(Webview, SslErrorHandler, SslError) */
var WebViewClient = Java.use("android.webkit.WebViewClient");

WebViewClient.onReceivedSslError.implementation = function (webView,sslErrorHandler,sslError){
    quiet_send("WebViewClient onReceivedSslError invoke");
    //執(zhí)行proceed方法
    sslErrorHandler.proceed();
    return ;
};

WebViewClient.onReceivedError.overload('android.webkit.WebView', 'int', 'java.lang.String', 'java.lang.String').implementation = function (a,b,c,d){
    quiet_send("WebViewClient onReceivedError invoked");
    return ;
};

WebViewClient.onReceivedError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function (){
    quiet_send("WebViewClient onReceivedError invoked");
    return ;
};

/*** JSSE Hooks ***/

/* libcore/luni/src/main/java/javax/net/ssl/TrustManagerFactory.java */
/* public final TrustManager[] getTrustManager() */

var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory");
TrustManagerFactory.getTrustManagers.implementation = function(){
    quiet_send("TrustManagerFactory getTrustManagers invoked");
    return TrustManagers;
}

var HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection");
/* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */
/* public void setDefaultHostnameVerifier(HostnameVerifier) */
HttpsURLConnection.setDefaultHostnameVerifier.implementation = function(hostnameVerifier){
    quiet_send("HttpsURLConnection.setDefaultHostnameVerifier invoked");
        return null;
};
/* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */
/* public void setSSLSocketFactory(SSLSocketFactory) */
HttpsURLConnection.setSSLSocketFactory.implementation = function(SSLSocketFactory){
    quiet_send("HttpsURLConnection.setSSLSocketFactory invoked");
        return null;
};
/* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */
/* public void setHostnameVerifier(HostnameVerifier) */
HttpsURLConnection.setHostnameVerifier.implementation = function(hostnameVerifier){
    quiet_send("HttpsURLConnection.setHostnameVerifier invoked");
        return null;
};

/*** Xutils3.x hooks ***/
//Implement a new HostnameVerifier
var TrustHostnameVerifier;
try {
    TrustHostnameVerifier = Java.registerClass({
        name: 'org.wooyun.TrustHostnameVerifier',
        implements: [HostnameVerifier],
        method: {
            verify: function (hostname, session) {
                return true;
            }
        }
    });

} catch (e) {
    //java.lang.ClassNotFoundException: Didn't find class "org.wooyun.TrustHostnameVerifier"
    console.log("registerClass from hostnameVerifier >>>>>>>> " + e.message);
}

try {
    var RequestParams = Java.use('org.xutils.http.RequestParams');
    RequestParams.setSslSocketFactory.implementation = function(sslSocketFactory){
        sslSocketFactory = EmptySSLFactory;
        return null;
    }

    RequestParams.setHostnameVerifier.implementation = function(hostnameVerifier){
        hostnameVerifier = TrustHostnameVerifier.$new();
        return null;
    }

} catch (e) {
    console.log("Xutils hooks not Found");
}

/*** httpclientandroidlib Hooks ***/
try {
    var AbstractVerifier = Java.use("ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier");
    AbstractVerifier.verify.overload('java.lang.String','[Ljava.lang.String','[Ljava.lang.String','boolean').implementation = function(){
        quiet_send("httpclientandroidlib Hooks");
        return null;
    }
} catch (e) {
    console.log("httpclientandroidlib Hooks not found");
}

/***
android 7.0+ network_security_config TrustManagerImpl hook
apache httpclient partly
***/
var TrustManagerImpl = Java.use("com.android.org.conscrypt.TrustManagerImpl");
// try {
//     var Arrays = Java.use("java.util.Arrays");
//     //apache http client pinning maybe baypass
//     //https://github.com/google/conscrypt/blob/c88f9f55a523f128f0e4dace76a34724bfa1e88c/platform/src/main/java/org/conscrypt/TrustManagerImpl.java#471
//     TrustManagerImpl.checkTrusted.implementation = function (chain, authType, session, parameters, authType) {
//         quiet_send("TrustManagerImpl checkTrusted called");
//         //Generics currently result in java.lang.Object
//         return Arrays.asList(chain);
//     }
//
// } catch (e) {
//     console.log("TrustManagerImpl checkTrusted nout found");
// }

try {
    // Android 7+ TrustManagerImpl
    TrustManagerImpl.verifyChain.implementation = function (untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
        quiet_send("TrustManagerImpl verifyChain called");
        // Skip all the logic and just return the chain again :P
        //https://www.nccgroup.trust/uk/about-us/newsroom-and-events/blogs/2017/november/bypassing-androids-network-security-configuration/
        // https://github.com/google/conscrypt/blob/c88f9f55a523f128f0e4dace76a34724bfa1e88c/platform/src/main/java/org/conscrypt/TrustManagerImpl.java#L650
        return untrustedChain;
    }
} catch (e) {
    console.log("TrustManagerImpl verifyChain nout found below 7.0");
}
// -- Sample Java
//
// "Generic" TrustManager Example
//
// TrustManager[] trustAllCerts = new TrustManager[] {
//     new X509TrustManager() {
//         public java.security.cert.X509Certificate[] getAcceptedIssuers() {
//             return null;
//         }
//         public void checkClientTrusted(X509Certificate[] certs, String authType) {  }

//         public void checkServerTrusted(X509Certificate[] certs, String authType) {  }

//     }
// };

// SSLContext sslcontect = SSLContext.getInstance("TLS");
// sslcontect.init(null, trustAllCerts, null);

// OkHTTP 3 Pinning Example
// String hostname = "swapi.co";
// CertificatePinner certificatePinner = new CertificatePinner.Builder()
//         .add(hostname, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
//         .build();

// OkHttpClient client = new OkHttpClient.Builder()
//         .certificatePinner(certificatePinner)
//         .build();

// Request request = new Request.Builder()
//         .url("https://swapi.co/api/people/1")
//         .build();

// Response response = client.newCall(request).execute();
});
  • 第七步 打開APP并且執(zhí)行

frida -U com.chaozh.iReaderFree --no-pause -l hooks.js

這個(gè)時(shí)候用Charles抓包發(fā)現(xiàn)可以繞過去了

參考資料:
https://github.com/WooyunDota/DroidSSLUnpinning
https://github.com/WooyunDota/DroidDrops/blob/master/2018/Frida.Android.Practice.md
https://www.cnblogs.com/qwangxiao/p/9255328.html
https://www.frida.re/docs/android/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末浮毯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子泰鸡,更是在濱河造成了極大的恐慌债蓝,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盛龄,死亡現(xiàn)場(chǎng)離奇詭異惦蚊,居然都是意外死亡器虾,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門蹦锋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來兆沙,“玉大人,你說我怎么就攤上這事莉掂「鹌裕” “怎么了?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵憎妙,是天一觀的道長(zhǎng)库正。 經(jīng)常有香客問我,道長(zhǎng)厘唾,這世上最難降的妖魔是什么褥符? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮抚垃,結(jié)果婚禮上喷楣,老公的妹妹穿的比我還像新娘。我一直安慰自己鹤树,他們只是感情好铣焊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著罕伯,像睡著了一般曲伊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上追他,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天雕擂,我揣著相機(jī)與錄音直秆,去河邊找鬼闹炉。 笑死积锅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的推溃。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼届腐,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼铁坎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起犁苏,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤硬萍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后围详,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體朴乖,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡祖屏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了买羞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袁勺。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖畜普,靈堂內(nèi)的尸體忽然破棺而出期丰,到底是詐尸還是另有隱情,我是刑警寧澤吃挑,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布钝荡,位于F島的核電站,受9級(jí)特大地震影響舶衬,放射性物質(zhì)發(fā)生泄漏埠通。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一逛犹、第九天 我趴在偏房一處隱蔽的房頂上張望端辱。 院中可真熱鬧,春花似錦圾浅、人聲如沸掠手。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)喷鸽。三九已至,卻和暖如春灸拍,著一層夾襖步出監(jiān)牢的瞬間做祝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來泰國(guó)打工鸡岗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留混槐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓轩性,卻偏偏與公主長(zhǎng)得像声登,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子揣苏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容