<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    一次金融APP的解密歷程

    VSole2022-11-14 11:04:57

    聲明:本文僅限于技術討論與分享,嚴禁用于非法途徑。若讀者因此作出任何危害網絡安全行為后果自負,與本號及原作者無關。

    前言:

    客戶僅提供官網下載地址給我們測試。但是由于官網的版本不是最新的,APP會強制你升級。而升級后的APP,是進行加固后的,無法使用frida進行hook,注入進程。那同樣也無法使用SSL Unpinning進行限制客戶端校驗證書。新版app使用查殼軟件顯示未加殼,但是查看源代碼明顯少了很多代碼,且很多都是變量聲明而已。

    繞過更新:

    我們要想能對APP滲透測試,一般都是需要抓包和解密的。首先使用burp進行抓包代理,官網版本的APP(以下統稱舊版APP),是可以輕松抓到APP的包的(該條請求為檢驗APP最新版本的請求)。但是內容使用了加密,具體什么加密是不得而知。

    img

    獲取到請求密文:

    vVAK0jos5eT9gmQJaHOaYbqZ1mgXoBH3bee3MTF3G5wNRHRoPPOYokZLT4MQqaPDN%2BLeEYpIzzDJeErDHcDfhY8muosLfOaw35W3BuCxDNtuNFB86RumMBtOcQXT08qw
    

    響應包未json,urldecode后為:

    {"duration":"0ms","note":"","code":1,"resultDES":"UX/jHk6yqix2yxZIrf0rSIuOjCy6oGxjCPUfBL2avG+DWy/++NW16+YQHVFQ+Nj2w9VOWGcH4OxFtGxbR6K7I6pY0Q9hkP9gc0K0JLZ5O+PwOW72nzissCiLG+cHqadKHzkPOQDdBUuBoa4W1Jz7fQ=="}
    

    通過desStr和resultDES,一開始我猜測他為des加密,具體是不是,后續再說。

    先進入APP,但是一進入APP就提示更新:

    img

    通過前言,我們知道是不能更新的。(當然不乏某些技術大佬也可以把新版APP搞定,我技術有限,感覺舊版的比較容易搞)。那我們就明確了目標,要先繞過更新校驗。

    對于不了解hook和frida的同學,我這邊推薦先去網上了解下,還有安裝之類的,再來看此篇文章。

    首先我們明確一下思路,要怎么繞過這個更新校驗呢?

    (1)直接反編譯,修改APP的版本信息為99.99之類的;

    (2)通過修改版本驗證請求,使用http層面去繞過;

    (3)使用hook,去重寫更新函數,或者繞過更新函數;

    第一點要app能支持反編譯且不存在校驗簽名。第二點要能知道加密密文的密鑰。所以我選擇第三種:

    通過jadx搜索更新,發現了兩處,成功獲取到源代碼。

    img

    類名分別為:com.xxxx.AppUpdate和com.xxxx.WelcomeActivity,通過代碼審計可以看到,是先調用的WelcomeActivity,WelcomeActivity再去調用的AppUpdate:

    img

    跟蹤進入AppUpdate,調用的checkNativeAppVersion():

    img

    通過上述代碼,我們可以看到,這邊就是用于判斷是否升級的函數。

    public void onResponse(Call call, Response response) throws IOException {
        try {
            JSONObject jSONObject = new JSONObject(C.s2(new JSONObject(URLDecoder.decode(response.body().string(), DataUtil.UTF8)).getString("resultDES"), Config.WHITE_KEY, Config.IV.getBytes()));
            if (jSONObject.optInt("code", -1) > 0) {
                JSONObject optJSONObject = jSONObject.optJSONObject("object");
                if (optJSONObject == null) {
                    return;
                }
                if (WakedResultReceiver.CONTEXT_KEY.equals(optJSONObject.optString("isUpdate", ChatConfig.CARD_TYPE))) {
                    nativeAppVersionInterface.updateApp(optJSONObject.optString("desc", "當前有新版本,是否需要更新"), optJSONObject.optString(ClientCookie.VERSION_ATTR, ""));
                } else {
                    nativeAppVersionInterface.noUpdateApp();
                }
            } else {
                nativeAppVersionInterface.showError(jSONObject.optString("note"));
            }
        } catch (JSONException e) {
            e.printStackTrace();
            nativeAppVersionInterface.showError(e.getMessage());
        }
    }
    

    當JSONObject.optInt("code", -1) > 0時,是會去進行升級的,否則則執行nativeAppVersionInterface.noUpdateApp()。

    這邊分析完后,其實我們就可以寫js進行hook操作了。

    我們的hook思路可以這樣設置了:

    重寫checkNativeAppVersion函數,執行執行nativeAppVersionInterface.noUpdateApp()。

    Ps:因為我一開始直接重寫了checkNativeAppVersion,只執行了console.log(“enter checkNativeAppVersion”),沒有對APP進行啟動,這樣就會直接卡死在啟動頁。

    附上js代碼:

    if(Java.available){
        console.log('success');
            Java.perform(function(){
            var appUpdate = Java.use("com.xxxx.AppUpdate");
            appUpdate.checkNativeAppVersion.implementation = function(a,b,c,d,e,f){
                console.log("enter AppUpdate");//判斷是否進入該hook函數,進入會執行該命令
                f.noUpdateApp();//直接執行不需要更新函數,APP會自動進入
            }
            });
    }
    

    使用命令:frida -U -l .\xxx.js -f 包名 --no-pause

    img

    成功進入:

    img

    解密:

    已經成功進入該APP,但是如果想成功進行滲透測試的話,還需要能解開APP的加密。通過des字段,初步判斷為des加密,再回頭看看剛剛更新的那個請求,是有用c.s2()函數進行操作的,大概率s2就是解密函數。

    JSONObject jSONObject = new JSONObject(C.s2(new JSONObject(URLDecoder.decode(response.body().string(), DataUtil.UTF8)).getString("resultDES"), Config.WHITE_KEY, Config.IV.getBytes()));
    

    可以看到s2的三個參數,即前面響應包中的json字段里面的resultDES參數,然后其次是Config.WHITE_KEY, Config.IV兩個參數,其中Config.IV是以字節數組的形式進行傳參的。通過跳轉可以看到配置文件的參數。

    img

    然后呢,因為獲取到密鑰和偏移量iv,這樣的話des就可以解了。但是問題是解不開。后續的思路就是如果可以直接hook這兩個加解密函數的話,是不是就可以不用管他的加解密了。

    img

    s1和s2函數不在java層,那我們就需要hook native層的代碼。Hook so文件。首先我們先把安裝包后綴apk改成zip,然后解壓。就可以找到wkb-1.2.2.so的文件了。(路徑為lib/arm64-v8a/wkb-1.2.2.so,前面的arm64根據自己測試機的CPU架構進行選擇。)直接用ida打開,在導出函數里面搜索des:

    img

    里面有很多des的相關函數。可使用以下js進行hook導出函數:

    if(Java.available){
        console.log('success');
            Java.perform(function(){
            var point = Module.findExportByName("libwkb-1.2.2.so","desDecryptByteArray");
            Interceptor.attach(point,{
                onEnter: function(args){
                    console.log("Hook start");
                    console.log("args[0]=" + args[0]); //打印我們java層第一個傳入的參數
                    console.log("args[1]=" + args[1]); //打印我們java層傳入的第二個參數
                },
                onLeave: function(retval){ //onLeave: function(retval)是該函數執行結束要執行的代碼,其中retval參數即是返回值
                    console.log("return:" + retval); //打印返回值
                }
            });
            });
    }
    

    但是這邊很奇怪的是,通過函數findExportByName找到的地址都是為null,一開始以為是還沒加載到so文件,但是后續進入APP后還是一樣為null。(有知道的大佬可以說下)

    img

    這就比較蛋疼了,得手動計算地址。首先先獲取so文件的地址,看能不能獲取到,若不行,則表示未加載so文件。

    var soAddr = Module.findBaseAddress("libwkb-1.2.2.so");
    console.log("soAddr:" + soAddr);
    

    img

    有地址出來,說明so文件是存在的,可以正常調用。那么這邊就要去計算函數偏移量。之前在網上看到別人的一個公式:

    *函數地址=so***初始地址+**函數偏移量+1

    但是我后面嘗試了好幾個,好像不同手機不同的計算方法,也可能我操作的有問題。我這邊的函數地址就是:

    *函數地址=so***初始地址+**函數偏移量

    不用加一。我自己是用這個方法測試計算的:找到一個導出函數可以被查詢到的,比如我這邊使用的就是JNI_OnLoad函數:

    img

    img

    獲取JNI_OnLoad的地址為0x79d5d7883c,然后使用這個地址減去so的地址:

    0x79d5d7883c ? 0x79d5d67000 = 1183c

    差值剛好為JNI_OnLoad的偏移量,所以我這邊就不用再進行加一操作了。

    這樣我們就可以成功hook任意函數了。通過我一個個嘗試發現,以下函數一個都沒調用過:

    img

    然后呢,我查找了s2函數的用例,發現被decodeSm4的函數調用過。

    img

    我就嘗試了一下,hook了sm4EncryptByteArr:

    img

    img

    附上js:

    var soAddr = Module.findBaseAddress("libwkb-1.2.2.so");
    var point = soAddr.add(0x136f0);
    Interceptor.attach(point,{
                onEnter: function(args){
                    console.log("Hook start");
                    console.log("args[0]=" + args[0]); //打印我們java層第一個傳入的參數
                    console.log("args[2]=" + Java.vm.getEnv().getStringUtfChars(args[2], null).readCString()); //打印我們java層傳入的第三個參數
                    console.log("args[3]=" + Java.vm.getEnv().getStringUtfChars(args[3], null).readCString()); //打印我們java層傳入的第四個參數
                },
                onLeave: function(retval){ //onLeave: function(retval)是該函數執行結束要執行的代碼,其中retval參數即是返回值
                    console.log("return:" + Java.vm.getEnv().getStringUtfChars(retval, null).readCString()); //打印返回值
                    // retval.replace(0); //替換返回值為0
                    // return retval;
                }
            });
    

    Ps:通過ida里面的參數,我們可以看到第二個參數為類,我們就沒給他打印出來。

    我人傻了,一開始的des字眼和偏移量這些都符合des的加密方式,誤導了我好久,一直往des方向去找。

    尾聲:

    其實很早我就已經解密成功了,直接通過java層,剛剛發現調用s2的decodeSm4函數,直接hook那邊即可成功獲取請求和響應的明文:

    img

    但是若通過js去操作修改數值,實在太麻煩了,要獲取密鑰和加密方式,通過腳本自動去加解密,所以我才會去hook native層,獲取到密鑰。因為上述密鑰Config.WHITE_KEY,其實是還有一層加密的,通過hook decodeWhiteKey函數的返回值,成功獲取了密鑰。

    img

    img

    其實后續我也嘗試去修改版本號繞過,但是事實證明,代碼存在驗簽:

    09fb86b8fbc058e8ecab0e5a8a04be6

    可以看到,把版本號修改為99.9.99,成功繞過了更新檢測,但是他還存在一個盜版驗簽檢測:

    5db5880584da7a62dea2030e6c00a57

    驗簽代碼一樣需要用hook去繞過。所以前面說的方法一也是行不通的。然后我又突發奇想,有沒有可能他密文里面就包含版本信息,那如果我使用99.9.99的版本,抓取密文,然后再安裝舊版APP,在他去請求版本更新時,替換密文,是不是可以繞過呢?經過嘗試,結果是:可以。他的版本校驗就是在服務端,這種方法也可以繞過。

    總結:

    不用輕易相信別人留下的信息,還是得根據自己的分析得出結論。其實后續我一直在想為什么那個字段是des呢,感覺之前是des加密,后續金融行業都進行了國密改造,然后字段并未更改,導致這種現象,當然只是猜測。至此,已完成對這APP的抓包和加解密。

    app
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    修復的零日漏洞被記錄為CVE-2024-23222 [iOS, macOS, tvOS],它是一個WebKit混淆問題,攻擊者可以利用它在目標設備上執行代碼。
    蘋果正在測試一項新的安全功能,該功能將限制 iPhone 竊賊對被盜手機的操作,即使他們擁有密碼。
    Apple 最新的 iOS 和 macOS 平臺更新帶來的不僅僅是緊急安全補丁。該公司激活了一項名為iMessage 聯系人密鑰驗證的新功能,以阻止冒充者和復雜的威脅行為者濫用其 iMessage 服務器基礎設施。
    最新的iOS 17.2 和 iPadOS 17.2包含至少 11 個已記錄的安全缺陷的修復程序,其中一些缺陷嚴重到足以導致任意代碼執行或應用程序沙箱逃逸。
    蘋果公司周四為其旗艦 macOS 和 iOS 平臺推出了安全更新,以修復舊系統移動設備上已經被利用的兩個嚴重漏洞。這些在 WebKit 瀏覽引擎中標記的漏洞可被用來劫持敏感內容或發起任意代碼執行攻擊。該公司推出了iOS 17.1.2 和 iPadOS 17.1.2,修復了 WebKit 缺陷,并警告稱,可以通過惡意網頁內容發起漏洞利用。該公司表示:“蘋果公司已獲悉一份報告,稱該問題可能已被針對 i
    Google Play和APP Store作為我們日常生活中最耳熟能詳的兩大應用商店,在提供便利的同時,也藏匿著諸多安全風險。Google Play因其寬松的網絡環境,成為了惡意軟件繁育的溫床。而蘋果生態雖然是出了名的“干凈”,但也難逃惡意軟件的偽裝。
    APP協議分析心得
    2023-07-18 09:23:41
    對脫殼流程有不明白的可參考我之前寫的文章:[原創]ART環境下dex加載流程分析及frida dump dex方案。var magic_Hex = [0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00];var dex_path = "/data/data/" + apk_Name + "/" + dex_size + ".dex";
    Apple 發布了安全更新,以解決兩個在野外被積極利用并針對 iPad、Mac 和 iPhone 的零日漏洞。這些漏洞被跟蹤為CVE-2023-28205和CVE-2023-28206。Cearbhaill 發現的相同安全問題。雖然蘋果公司表示它“知道有關此問題可能已被積極利用的報告”,但它并未將此類漏洞利用歸因于任何特定的網絡犯罪或民族國家組織。
    APP 聊天協議逆向
    2023-04-07 09:46:21
    環境主機:win10手機:Pixel 4 ,Android 10APP版本:V4.70.0工具IDA、JADX、Frida、Charles、WireShark逆向思路總結:猜流量抓包分析聊天數據一般都為TCP傳輸,所以直接使用WireShark抓包。經過不斷觀察以下特征數據很像聊天數據:接下來的思路就是Hook libc.so 的send函數,打印調用堆棧。查殼、脫殼未查到,那就先將APK拖進JADX里進行分析。Frida Hook擼起袖子就準備直接開干,Frida Server已啟動,直接運行。不出意外的意外,Process terminated。再次跟進去,發現了重點胖揍對象。再次發起Frida魔法攻擊。result結果即為TCP data。
    據此,用戶協議具有格式條款的特征,即單方擬定和不協商。一般線下簽訂格式條款時,盡管合同是由提供方事先擬定,但另一方有權對合同中的條款提出質疑,與提供方就條款內容進行協商,達成一致才能生效。一方面,警惕通過“指定管轄”條款影響用戶維權。根據民法典的規定,提供格式條款一方不合理地免除或者減輕其責任、加重對方責任、限制對方主要權利,或者提供格式條款一方排除對方主要權利等情形,該格式條款可以認定無效。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类