<pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
    <pre id="vvttv"></pre>

      <p id="vvttv"></p>

          <p id="vvttv"></p>

                <p id="vvttv"></p>

                <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                  <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                    <p id="vvttv"></p>

                    原文地址:http://drops.wooyun.org/tips/2986

                    0x00起因


                    首先說明下,本文不是正統的《一次app抓包引發的Android分析記錄》的續篇,只是分析的某APP和起因是一樣的,故借題。然而本文所做的分析解決了《一次app抓包引發的Android分析記錄》所留下的問題,故稱為續。

                    移動應用已不像起初,burpuite代理改遍天下。交叉編譯、傳輸加密、DEX加殼等防護方式開始再慢慢應用,我們已經很難再肆意的抓包改數據了。

                    文中所分析的APP也是,將加密算法交叉編譯至so庫中,對傳輸參數進行整體加密。分析arm匯編代碼是一條路子,但已然令大部分人望而生畏。然而安全總是充滿著各種奇思淫意,就算不走匯編,依舊能找到其它路子。

                    接下來通過這篇文章向各位分享下分析過程。

                    0x01整體思路


                    我們此次分析的目的是為了還原傳輸過程中的request和response,當然更重要的是要能控制request中的參數。為此我們需要了解參數是如何加密的。通過《一次app抓包引發的Android分析記錄》我們知道加密函數是libGoblin.so中的e函數,但似乎通過它要還原出解密函數不是那么容易。

                    不過既然知道了參數是何函數進行加密,那我們只要再知道參數是什么樣的格式,直接調用這個函數來加密偽造后的數據,而后抓包替換掉對應的參數不就可以了嗎?

                    為此我采取的策略是在json數據進入加密函數之前將其截獲,這樣就能知道參數是以什么樣的格式傳遞。知道了具體的參數格式,便可偽造數據抓包改包。

                    0x02解析request


                    首先來看下一個request,如下圖參數都是加密的,本小節目的就是為了搞清楚下面這一串是什么東西。

                    2014091023582979037.png

                    萬年不變的第一步,apktool反編譯、dex2jar反編譯。當然代碼混淆了,不過這不影響我們分析。android發送網絡請求主要采用JDK的HttpURLConnection和Apache的HttpClient,搜索跟這兩個相關的函數和字段以及請求的URL。而這些特征函數和字段,通常是不會進行混淆的。Andbug動態跟蹤亦可,本次通文采用靜態代碼分析,故如此!

                    通過AndroidManifest.xml了解app的結構,找到主包名等等。jd-gui查看java代碼,request是POST請求,所以搜索post、HttpPost字眼看看:

                    2014091023593412283.png

                    利用如上方式,反復通過搜索http請求方法及請求URL等特征縮小范圍,最終定位到AbstractHttpRequest類,該類是抽象類并擁有很多有趣的方法。而CommonTask類擴展了AbstractHttpRequest類。通過閱讀代碼知道該類為關鍵類。《一次app抓包引發的Android分析記錄》文中亦說明了,此處不再贅述!

                    而c參數被AbstractHttpRequest的chrome()處理,跟進該函數:

                    2014091100005867568.png

                    str為字符串常量“6000lex”和json數據一起進入NetworkParam的convertValue(),跟進:

                    2014091100024792775.png

                    在convertValue()中最終調用了加密函數,因此我們在Goblin.e加密paramString1和paramString2之前將這兩個參數通過log打印出來就知道請求的數據到底是什么東西了。

                    2014091100031885901.png

                    用文本編輯器打開com.xxx.net下的NetworkParam.smali定位到convertValue()函數,在Goblin.e處添加如下代碼:

                    2014091100041466275.png

                    通過修改smali代碼將加密前后的字符串打印出來,重打包簽名后安裝,查看logcat日志:

                    2014091100045620668.png

                    如上圖所示,現在我們已經知道了參數傳遞的格式了。然而日志中還出現了預料之外的數據。照上分析p1應該為常量“6000lex”,而圖中卻出現了時間戳。對比傳輸的數據(下圖),發現上圖第二個request-e是b參數的密文。而b的明文正是登陸信息。搜索convertValue發現b也是調用該函數加密,故導致此現象。

                    2014091100054441062.png

                    通過如上分析,最終確定了登陸時c和b格式分別為:

                    c={“adid":"f854a2765b5dcc3e","cid":"C2487","gid":"5EFD7B7D-A648-2F40-9D53-D42F1BCCC468","ke":"1410276980456","ma":"","mno":"310260","model":"sdk","msg":"","nt":"burp","osVersion":"4.4_19","pid":"10010","sid":"352C4C51-F09F-C929-E03A-B5E311BA2808","t":"p_ucLogin","uid":"000000000000000","un":"","vid":"60001060"} 
                    
                    b={"loginT":1,"paramJson":"","prenum":"","pwd":"xxxx","uname":"xxxx","userSecurity":{"communityCode":"0","imeiCode":"000000000000000","imsiCode":"310260000000000","osType":"14","stationId":"0","terminalType":"02"}}
                    

                    由于c中的ke和b的加密因子一樣。猜測服務端解密時,先通過“6000lex”解密出c,獲取ke的值,再通過ke解密出b參數。

                    實際上上面那個猜想是正確的,而《一次app抓包引發的Android分析記錄》中所做的猜想也是正確的。Goblin.d()就是解密函數。

                    《一次app抓包引發的Android分析記錄》中所記錄的:

                    2014091100063691127.png

                    利用Goblin.d()解密后為:

                    2014091100070015786.png

                    至于《一次app抓包引發的Android分析記錄》中為何解密會失敗,下面章節會說明到!

                    0x03解析response


                    如下,response響應報文亦是亂七八糟的一堆。這樣就算我們能改包了,也無法判斷結果到底是否正確。因此在開始改包之前,必須先解密response。

                    2014091100090539984.png

                    通過0x02的分析知道app是用Apache的HttpClient進行post請求。而HttpClient獲取response報文是通過getEntity()函數。故直接搜索getEntity,有了0x02的分析,輕松定位到AbstractHttpRequest類的getResult方法,由于此處dex2jar反編譯錯誤。所以直接分析smali代碼。

                    打開AbstractHttpRequest.smali:

                    2014091100094127866.png

                    2014091100101178907.png

                    getEntity()結果為v0,v0最終進入到dealWithResponse(),而dealWithResponse返回一個Object而不是String,所以繼續跟進dealWithResponse():

                    2014091100104472979.png

                    dealWithResponse只有一個參數,故跟蹤p1:

                    2014091100111966691.png

                    p1最終進行到parseProtoResponse()和buildHttpResultString()中,跟進parseProtoResponse():

                    2014091100120155024.png

                    parseProtoResponse()中調用了Goblin中的函數,可能這個函數就是我們想要的。先放著。我們再看看buildHttpResultString()這個函數,此處直接jd-gui查看:

                    2014091100123887602.png

                    buildHttpResultString()是個抽象類,具體代碼在CommonTask、MultiTask、PollTask中實現。而這幾個類中最終都是調用Response類的pareResponse()方法,而pareResponse()也調用了Goblin中的解密函數。parseProtoResponse()也是Response類一個方法。所以我們將解密響應報文的函數定位在這兩個函數中。接下來就是驗證下是否正確。

                    修改Response.smali中的parseProtoResponse()和pareResponse(),將解密后的結果通過日志打印出來:

                    2014091100131736750.png

                    在parseProtoResponse()和pareResponse()中標記了幾處,但最終只出現如上結果,故確認解密函數為pareResponse()。

                    0x04控制request


                    至此我們已經完全看到了request和response傳輸的明文內容,如下所示,一個完成的請求響應過程:

                    2014091100141294546.png

                    當然我們目的是為了測試,所以必須要能改request請求才可以。

                    嘗試一:

                    既然我們知道了request的加密函數,那么在自己的APP中調用,加密完替換掉burp攔截到得數據即可。

                    新建一個app引用同樣的Goblin類,進行加解密測試,測試代碼如下:

                    2014091100145140718.png

                    加密可以加密,但實際上加密結果和原始的密文不一樣。而解密卻失敗,失敗的原因正和《一次app抓包引發的Android分析記錄》中所做的測試一樣。

                    2014091100151565721.png

                    發生了JNI WARNING:NewStringUTF input is not valid Modified UTF-8錯誤,而這個錯誤是由于在JNI中,google修改了UTF8的標準,當正常UTF8中包含了不符合這個標準的字節時,checkJNI函數就會報這個錯,導致應用崩潰。

                    在google中亦有關于此錯誤的報告:

                    https://code.google.com/p/android/issues/detail?id=64892????????

                    https://code.google.com/p/android/issues/detail?id=25386

                    然而直接將原始密文拿來解密卻可以正常解碼,所以問題出可能出在加密環節。折騰半天,沒有發現適合我們這邊的處理辦法。但在測試過程中發現,在原始APP應用中通過修改smali代碼可以正常加解密。難道so中還有檢測環境?當然這個得查看arm匯編才知道。

                    既然如此,那直接改造原始app吧。

                    嘗試二:

                    改造思路:在原始APP內部中攔截參數—>通過外部修改攔截到的參數—>放行參數,后續按正常流程進行

                    在原始app內部中攔截參數,只要在讓參數再進入加密之前進入到我們控制的函數中即可。為了方便說明。我們先來看看如何通過外部修改內部攔截的參數。

                    借助android的廣播機制,我們能實現實時的跟app進行交互。因此,也能實時的讓外部跟app內部進行數據交互。新建一個myBroadcast類,代碼如下:

                    #!java
                    public class myBroadcast extends BroadcastReceiver{ public static boolean sw = false; public static boolean swc = false; public static boolean swb = false; public static String datac = null; public static String datab = null; public static String kec = "6000lex";
                    
                        // 接收廣播
                        public void onReceive(Context context, Intent intent) {     
                            Log.i("broadcast-intent",intent.toString());
                    
                            String action = intent.getAction();
                            if(action.equals("com.test.broadcast1")){
                                sw = intent.getBooleanExtra("sw", true);   // 控制是否攔截
                                swc = intent.getBooleanExtra("swc", false);// 控制攔截c      
                                swb = intent.getBooleanExtra("swb",false); // 控制攔截b
                    
                            }
                            else if(action.equals("com.test.broadcast2")){
                                datac = intent.getStringExtra("datac");    // 接收c
                                datab = intent.getStringExtra("datab");    // 接收b
                            }       
                            Log.v("receiver-data:sw:swc:swb|datac:datab",sw+":"+swc+":"+swb+"|"+datac+":"+datab);
                        }
                    
                        // 延遲函數
                        public static void delay(){     
                            try {
                                Thread.currentThread();
                                Thread.sleep(3000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    
                        // 修改函數
                        public static String alter(String ke,String json){
                            Log.v("json-data-1",ke+":"+json);
                    
                            while(sw){
                                delay();
                                if(ke.equals(kec)){
                                    if(swc){
                                        if(datac!=null){
                                            json = datac;
                                            Log.v("json-data1-2",json);
                                            break;
                                        }                                           
                                    }
                                    else{
                                        break;
                                    }
                                }
                                else{
                                    if(swb){
                                        if(datab!=null){
                                            json =datab;
                                            Log.v("json-data2-2",json);
                                            break;                  
                                        }
                                    }
                                    else{
                                        break;
                                    }
                                }                       
                            }   
                            return json;
                        }
                    
                    }
                    

                    利用onReceive實時接收外部數據,利用alter函數檢測外部是否發送了攔截指令。當收到攔截的指令時,調用delay()函數進行循環延時,直到接收到偽造的數據或者關閉攔截。

                    將myBroadcast類轉化為smali代碼。把myBroadcast.smali放在NetworkParam.smali同級目錄下。并在AndroidManifest.xml中注冊myBroadcast這個receiver,且將exproted設置為true。

                    即允許該receiver被外部訪問。

                    2014091100175256805.png

                    這樣我們就能在NetworkParam.smali中使用這個receiver

                    接下來,我們來修改NetworkParam.smali,使其接收我們的指令。在Goblin.e前后修改如下:

                    2014091100181216605.png

                    讓p0進入alter()函數,修改后結果保存至v3,讓v3替換p0進入到Goblin.e()中。“request-data-1”打印出原來的參數,“json-data-1”打印出進入alter函數中的參數。“request-data-2”打印出修改后的參數,“request-data-e”,打印出加密后的參數。

                    修改完后,重新打包、簽名、安裝,運行查看logcat日志:

                    1、?默認設置是不攔截,所以logcat日志中應該能完整得看到

                    “request-data-1”—>“json-data-1”—>“request-data-2(不變)”—>“request-data-e”—>“response-data”
                    

                    測試如下:

                    2014091100184047629.png

                    和預期一樣

                    2、?設置攔截指令,即sw為true,攔截數據進入循環延遲并等待接收偽造的參數。所以logcat日志中應該只能看到“request-data-1”—>”json-data-1”,測試如下:

                    am命令發送廣播:

                    2014091100191488877.png

                    Logcat日志,如預期,數據被攔截,應用一直處于加載當中:

                    2014091100193347858.png

                    3、發送偽造數據,按照設計。此時logcat日志中應該能看到

                    “request-data-1”—>“json-data-1”—>“request-data-2(修改后)”—>“request-data-e”—>“response-data”
                    

                    測試如下:

                    發送廣播指令,攔截b參數,放行c參數:

                    2014091100195565253.png

                    Logcat日志顯示如下,c(帶600lex的)被放行,b(帶時間戳的)被攔截:

                    2014091100202519355.png

                    am命令發送datab數據,將uname改為test222:

                    2014091100220530381.png

                    結果如下,receiver接收到偽造的數據后,將原b參數進行修改后放行:

                    2014091100223140482.png

                    和預期一樣。

                    0x05結語


                    最終,我們實現了查看傳輸明文信息,并控制了request請求報文。即便它采用so加密。我們依舊可以盡情的測試了~

                    ?

                      <pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
                      <pre id="vvttv"></pre>

                        <p id="vvttv"></p>

                            <p id="vvttv"></p>

                                  <p id="vvttv"></p>

                                  <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                                    <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                                      <p id="vvttv"></p>

                                      这里只有精品视频