某車聯網App 通訊協議加密分析

語言: CN / TW / HK

一、目標

李老闆:最近剛買了輛新車,他帶的App挺有意思,要不要盤一盤?

奮飛: 我去,加殼了,還挺有意思,搞一搞。

v6.1.0

二、步驟

抓包

我的抓包環境是 Mac 10.14.6 + httpToolKit, 這一步很順利的抓到包了。

main

1:main

可以看到,http請求和返回值都是加密的,我們的目標就是這個 request 和 response的來歷的。

脫殼

脫殼我們首選的就是 BlackDex ,使用方便,效果好。不過針對這個樣本卻不好使,只脫出來一個dex,大概率是失敗了。

然後就上葫蘆娃大佬的 FRIDA-DEXDump, 這個樣本很狡猾,frida Spawn模式一跑就崩,看來殼比較硬。

這下棘手了,回想起之前我們曾經用 Xcube http://91fans.com.cn/post/antifridaoper/ 來對付加殼應用, 這次繼續試試。

Xcube沒有讓我們失望,注入成功。 但是在Xcube模式下如何跑 FRIDA-DEXDump 呢?

本來想改改程式碼合併進去。無意中發現yang神也寫了個DumpDex http://github.com/lasting-yang/frida_dump

輕鬆合併到js裡面,這下成功的Dump出來了。

字串搜尋

直接搜尋 "request" 結果不多。

find

1:find

很明顯,這個 jsonObject.addProperty 嫌疑最大。

點進去看看,順利的找到了這個 CheckCodeUtil 類。 他的checkcode和decheckcode大概率就是我們這次的目標。

utilcls

1:utilcls

hook 之

``` var CheckCodeUtilCls = Java.use("com.bangcle.comapiprotect.CheckCodeUtil"); CheckCodeUtilCls.checkcode.implementation = function(a,b,c){ var rc = this.checkcode(a,b,c); console.log(TAG + "checkcode >>> a = " + a); console.log(TAG + "checkcode >>> b = " + b); console.log(TAG + "checkcode >>> c = " + c); console.log(TAG + "checkcode >>> rc = " + rc); return rc; }

CheckCodeUtilCls.decheckcode.implementation = function(a){ var rc = this.decheckcode(a); console.log(TAG + "decheckcode >>> a = " + a); console.log(TAG + "decheckcode >>> rc = " + rc); return rc;

} ```

跑一下,奇怪,一點輸出都沒有,這個沒有道理呀?

仔細看看,犯傻了,這類裡面有兩個checkcode函式,所以我們需要指定hook哪一個。 由於我們列印輸出的時候忽略了錯誤輸出,導致沒有看到報錯。

注意: Xcube環境下如果沒有任何輸出,大概率是指令碼報錯了,這時候就不要過濾,直接檢視全部輸出日誌,就可以看到報錯了。

改改程式碼

CheckCodeUtilCls.checkcode.overload('java.lang.String','int','java.lang.String').implementation = function(a,b,c){

這次果然很順利的打印出來了結果。但是奇怪的事情又發生了,App崩了。

挽救崩潰的App

為什麼會崩,難道是我們列印資料有bug?

先把列印入參和結果的程式碼註釋掉。 還是崩。

把所有hook程式碼註釋掉,不崩了,但是我不hook沒法玩呀?

使出終極大法,換手機。 很多時候換個手機 就好了,也許這個手機水土不服吧。

結果打臉了,換了手機依然崩潰。

木有任何僥倖心理了,說明App或者殼,對關鍵函式的Hook做了檢測,發覺被hook就擺爛。

App或者殼肯定是在Native層做的檢測,我們要對付它,就得和它站在同一高度。

不去hook Jave層的函數了,直接取hook Native層的 checkcode 和 decheckcode。

Hook Native

從CheckCodeUtil的java程式碼中找到了 System.loadLibrary("encrypt");, 說明我們要對付的目標是 libencrypt.so。

IDA開啟它,匯出表,暴露了兩個資訊。

1、checkcode函式的地址在 0x24424 , decheckcode函式的地址在 0x2B1BC 。

2、這兩個函式大概率使用了AES演算法。

繼續Hook吧

``` var targetSo = Module.findBaseAddress('libencrypt.so'); console.log(TAG +" ############# libencrypt.so: " +targetSo); // 24424 2B1BC

Interceptor.attach(targetSo.add(0x24424 ),{ onEnter: function(args){ var strCls = Java.use('java.lang.String');

    this.rBuf = ptr(this.context.x0);
    console.log(TAG + " ======================================== ");
    // console.log(TAG + "-------- checkcode x0 = " + ptr(this.context.x0) ) ;

    var strA = Java.cast(this.context.x2, strCls);
    console.log(TAG + "-------- checkcode a = " + strA);

    console.log(TAG + "-------- checkcode b = " + ptr(this.context.x3));

    var strC = Java.cast(this.context.x4, strCls);
    console.log(TAG + "-------- checkcode b = " + strC);


},
onLeave: function(retval){
    var strCls = Java.use('java.lang.String');
    var strRc = Java.cast(retval, strCls);
    console.log(TAG + "-------- checkcode rc = " + strRc);

}

});

Interceptor.attach(targetSo.add(0x2B1BC ),{ onEnter: function(args){ var strCls = Java.use('java.lang.String');

    this.rBuf = ptr(this.context.x0);
    console.log(TAG + " ======================================== ");
    // console.log(TAG + "-------- checkcode x0 = " + ptr(this.context.x0) ) ;

    var strA = Java.cast(this.context.x2, strCls);
    console.log(TAG + "-------- decheckcode a = " + strA);


},
onLeave: function(retval){
    var strCls = Java.use('java.lang.String');
    var strRc = Java.cast(retval, strCls);
    console.log(TAG + "-------- decheckcode rc = " + strRc);

}

}); ```

李老闆: 奮飛呀,函式的第一個引數不是 X0嗎? 你為什麼列印第一個引數是 X2 ?

奮飛: 老闆,早就讓你多批點經費買書,你不同意,這下露怯了吧。去翻翻 jni程式設計就知道了,java呼叫C/C++ 函式的前兩個引數是固定的。真實傳遞進來的引數是從第三個開始。

這次再跑一下。

rc

1:rc

真相大白了。

帝都已經有秋意了,不好上鮮啤了,差不多可以上二鍋頭了。

三、總結

脫殼方法千千萬,重點還是Dump Dex。

加殼應用不要怕,大概率脫完殼之後就都是線索了。不加殼的App才是真的可怕。

指令碼沒有任何輸出,不一定是位置找錯了,還有可能是指令碼的報錯你沒有看到。

App崩了,換手機是有效的,雖然這次打臉了。

針對這個樣本,IDA還告訴我們,so裡面的函式入口的程式碼也被抽取了,要分析這個so,估計還得Dump so。

ffshow

1:ffshow

只有去穿越和反思痛苦,才能得到更高的思想深度,沒有捷徑

Tip:

: 本文的目的只有一個就是學習更多的逆向技巧和思路,如果有人利用本文技術去進行非法商業獲取利益帶來的法律責任都是操作者自己承擔,和本文以及作者沒關係,本文涉及到的程式碼專案可以去 奮飛的朋友們 知識星球自取,歡迎加入知識星球一起學習探討技術。有問題可以加我wx: fenfei331 討論下。

關注微信公眾號: 奮飛安全,最新技術乾貨實時推送