VX小程序逆向分析
Frida雖然確實調試起來相當方便,但是Xposed由于能夠安裝在用戶手機上實現持久化的hook,至今受到很多人的青睞,對于微信小程序的wx.request API。
本文將以該API作為用例,介紹如何使用Xposed來對微信小程序的js API進行hook,首先我們要知道微信小程序跟服務器交互最終都會調用wx.request這個api跟服務器交互,我們的最終目的是要通過分析這個api得到request數據和response數據,測試的微信版本是8.0.30。
背景知識
眾所周知,Xposed主要用于安卓Java層的Hook,而微信小程序則是由JS編寫的,顯然無法直接進行hook。安卓有一個WebView的組件能夠用于網頁的解析和js的執行,并且提供了JSBridge可以支持js代碼調用安卓的java代碼,微信小程序正是以此為基礎開發了它的微信小程序框架,微信小程序特有的API則是由這個框架中的WxJsApiBridge提供的,因此以wx.開頭的API都能在這個框架中找到對應的Java代碼,所以我們雖然不能直接hook js代碼,但是我們可以通過hook這些js api對應的Java代碼來實現微信小程序api的hook。
Frida調試
在編寫Xposed插件前,首先先使用Frida進行逆向分析以及hook調試,確保功能能夠實現后在用Xposed編寫插件,畢竟Xposed插件調試起來還是不如Frida方便。
首先我們要知道,js代碼中的wx.xxx字符串一定會在java層中出現嗎?答案是否定的,wx.getLocation和其他一些api的名字確實會在java層出現,java層的字段表現形式就是 String NAME = “getLocation”,但是我們今天要分析的api wx.request在java層中不叫這個名字,因此在jadx反編譯完微信以后,直接搜索該字符串是搜索不到的。既然搜索不到那就換一個思路,微信小程序wx.xxx最終都會通過WxJsApiBridge調用到java層對應的api實現,所以我們可以通過frida hook這個類相應的方法來確定wx.request在java層對應的api叫什么名字,通過jadx搜索發現有一個類叫做com.tencent.mm.appbrand.commonjni.AppBrandJsBridgeBinding。
定位到具體的類以后,我們可以用Objection來hook整個類來觀察這個類中函數的調用情況,以此發現主要的函數。不過在hook之前,需要注意的是,微信小程序一般會以新進程的方式啟動,其進程名為com.tencent.mm:appbrand0、com.tencent.mm:appbrand1、com.tencent.mm:appbrand2、com.tencent.mm:appbrand3、com.tencent.mm:appbrand4。微信最多同時運行5個小程序進程,所以最多只能同時運行5個小程序,如果打開第6個小程序,微信會把最近不怎么用的小程序關掉給新打開的小程序運行,因此,如果直接用frida -U com.tencent.mm -l xxx或者objection -g com.tencent.mm explore來hook的話,是無法看到函數調用的,因為你hook的進程不是微信小程序的進程而是微信的進程。所以我們要指定pid來進行hook,可以使用dumpsys activity top | grep ACTIVITY來得到;也可以使用frida -UF -l xxx來hook當前最頂層的Activity。對于Xposed則沒有這個問題,只需指定微信的包名就會自動hook上所有的子進程。
結合動態測試的函數調用結果,隨便瀏覽一下被調用的函數的代碼,看到了一個主要函數代碼如下:

這個函數是關鍵,通過動態hook調試發現,每個wx.xxx的api通過經過invokeCallbackHandler,由這個函數通過調用native函數最終調用到具體的java實現,其他的參數我們先不管,我們看最后一個參數String類型,通過動態hook調試發現這個參數保存的就是具體的java層實現的名字,wx.request對應的java層的api名字如下圖所示:

我們直接在jadx中搜索整個名字看看,如下圖所示:

搜索發現還有一處,異步調用是走上面這個類,同步調用是走下面這個類 如下圖所示:

這個a方法就是關鍵,廢話不多說直接說結果,a方法的第二個參數就是request參數,最終這兩個類的a方法都會調用this.yOx.a,點進去如下所示:

第二個參數就是wx.request請求參數,所以直接hook這個方法就可以得到向服務器發送的數據,那服務器返回的數據在哪里呢!右鍵點擊查找這個參數的所有引用,發現有兩處很可疑,如下所示:

點進去看看這兩處的調用,如下所示:

發現他們在一起,通過第一處調用的上一行的log可以看出,不驗證白名單的domains都會走這里,正常的微信小程序都會開啟這個驗證,所以第二處才是跟服務器發起交互的函數調用,這樣就找到了wx.request發送的函數調用,因為我們不止要獲取發送的數據,還要獲取服務器響應的數據,所以還得分析wx.request callback在java層對應的實現,具體的callback的實現是在so層,由于時間關系就懶得跟了,這里告訴大家一個簡單的獲取響應的數據的方法,前面說過wx.xx的api都要通過WxJsApiBridge做橋接實現跟java層方法的調用,這樣的話可不可以直接hook com.tencent.mm.appbrand.commonjni.AppBrandJsBridgeBinding這個類的接受訂閱消息的方法來得到響應的數據呢?答案是可以的,如下所示:


Xposed hook wx.request java層代碼得到發送的數據實現如下所示:

得到響應數據的Xposed代碼就不貼了,方法同上。