frida內存檢索svc指令查找sendto和recvfrom進行hook抓包
利用wirkeshake抓包初步分析
配置本地PC的ip為192.168.5.150并在上面運行server,然后在pixel手機上安裝client_連接192.168.5.150服務器.apk,手機ip為192.168.5.221,在PC上通過wireshake進行抓包。如下所示,看到No.14是手機發給server的HTTP GET包,No.17為server發給手機的HTTP報文。

追蹤http流,可以看到server返回給手機一個字符串“hello world"。

常規抓包方案
根據上面分析,apk使用的http通信,采用tcp協議。
2.1 嘗試Java層使用tcp通信的常規hook點,如下所示。
java.net.SocketInputStream. socketRead0
java.net.SocketOutputStream. socketWrite0
2.2嘗試JNI層使用tcp通信的常規hook點。
apk直接調用libc.so中接口實現收發包,一般tcp是使用send和recv函數,而udp使用sendto和recvfrom函數。查看libc源碼,send最終還是調用的sendto,而sendto通過系統調用實現。recv原理與send一致,所以我們直接hook住libc.so的recvfrom和sendto正常是可以拿到tcp和udp的包。
經過實驗分析,上面兩種方法都沒有能抓到包,那么剩下的可能就是so中通過系統調用實現了sendto和recvfrom函數,下面對此猜想進行分析驗證。
進一步分析
3.1 先利用frida_fart對apk進行脫殼,脫殼后看到onCreate函數native化了,加載了一個libnative-lib.so,還有一個jni函數stringFromJNI。

3.2 解壓apk取出libnative-lib.so,利用IDA分析,但是打不開報如下錯誤。

利用readelf查看,section段查看結果如下,也是不正常的。我利用010Editor打開這個so進行ELF解析,也會報錯。

3.3 使用frida去dump出運行時的so,核心代碼如下。

將這個so拉入IDA進行分析,這次不會報錯了,使用ctrl+F5反編譯,查看到so中使用系統調用實現了sendto和recvfrom,如下所示。

查看sub_2BD8的匯編代碼,看到svc 0指令對應的機器碼是“00 00 00 EF"。

因為上面分析的so是加殼的so,所以我們無法確定svc指令的真實地址,所以需要從內存中根據機器碼找到svc指令,然后通過hook住svc指令,去dump收發包數據。
frida腳本實現
4.1 尋找hook時機,一般加殼so的解碼在init或者init_array中實現,它們在so加載過程中會進行調用,所以選擇java層加載so完畢后進行hook,代碼如下。

4.2 根據libnative-lib.so模塊的基地址和偏移,從內存中匹配svc 0的機器碼,并反匯編出附近的指令進行匹配,如果找到了svc 0,則對其地址進行hook。

4.3 hook住svc 0后打印收發包的data部分。
首先查看sendto和recvfrom的機器碼分別是290和292, 如下所示。

查看sendto原型如下,在它執行前打印出r0即fd,r1即buffer,r2即buffersize。在它執行后打印r0即sendto的返回值也就是真正發送出去的包的長度。recvfrom原理與之一致。

下面在sendto和recvfrom執行完畢后,打印出收發包的data部分以及調用棧。

4.4 運行frida腳本,同時支持dump出so和抓包,并打印出了調用棧。
如下是發包數據,可以看到apk做了一次HTTP GET的操作。

如下是收包數據,可以看到收到的真實數據為“helloworld"。

綜上,frida抓包結果與wireshake抓包結果是一致的,同時也是可以利用frida dump出的運行中的so以及調用棧,分析so中收發包函數的流程。