環境
主機:win10
手機:Pixel 4 ,Android 10
APP版本:V4.70.0
工具
IDA、JADX、Frida、Charles、WireShark
逆向思路
總結:猜
流量抓包分析
聊天數據一般都為TCP傳輸,所以直接使用WireShark抓包。
經過不斷觀察以下特征數據很像聊天數據:

接下來的思路就是Hook libc.so 的send函數,打印調用堆棧。
查殼、脫殼

未查到,那就先將APK拖進JADX里進行分析。
Frida Hook
擼起袖子就準備直接開干,Frida Server已啟動,直接運行。
frida -Uf cn.xxxx.android -l .\xxx.js --no-pause
世間萬般逆向怎么都如我所愿?不出意外的意外,Process terminated。
狗賊將我的Frida大法拒之門外,作為Frida忠實愛好者(別的不會),這哪能忍?

往上看,/lib/arm64/libmsaoaidsec.so這小子名字一看就不是什么好東西。拖進IDA里將之底褲扒光。
我們知道一般檢測Frida的函數無非是strstr、strcmp、readline,fgets這些。我們當然也知道一般檢測函數大多都在init_proc、JNI_OnLoad中進行調用執行。
打開so 定位到init_proc,然后又聞到了熟悉的味道。

里面調用的函數不是很多,所以直接人肉分析,那這樣不是外套脫了還剩里面的?不行不行。

通過觀察上面的CFG發現,該混淆符合以下邏輯:

整體思路就是先查找主分發器,一般被引用次數最多的那個塊就是主分發器,引用主分發器的塊大概率是真實塊,再使用unicorn模擬執行,遍歷每一個分支,記錄每一個塊,如果某一個塊是上次記錄的塊則也為真實塊,無后繼的塊則為retn塊,剩下的就是無用塊。最終處理后樣子如下:

經過一個一個的點,最終找到了一個十分可疑的家伙sub_1A8A0()。

再次跟進去,發現了重點胖揍對象。
result = pthread_create(qword_45658, 0LL, (void *(*)(void *))sub_18C88, 0LL);
那可不就是這小子阻礙了Frida大軍的步伐。
下面編寫Frida腳本去繞過該檢測手段。
function hook_pthread_create(){ var pt_create_func = Module.findExportByName(null,'pthread_create'); var detect_frida_loop_addr = null; console.log('pt_create_func:',pt_create_func); Interceptor.attach(pt_create_func,{ onEnter:function(){ if(detect_frida_loop_addr == null) { var base_addr = Module.findBaseAddress('libmsaoaidsec.so'); if(base_addr != null){ detect_frida_loop_addr = base_addr.add(0x0000000000018C88) console.log('this.context.x2: ', detect_frida_loop_addr , this.context.x2); if(this.context.x2.compare(detect_frida_loop_addr) == 0) { hook_anti_frida_replace(this.context.x2); } } } }, onLeave : function(retval){ // console.log('retval',retval); } })}function hook_anti_frida_replace(addr){ console.log('replace anti_addr :',addr); Interceptor.replace(addr,new NativeCallback(function(a1){ console.log('replace success'); return; },'pointer',[])); }setImmediate(hook_pthread_create(),3000);
然后就可以愉快的使用Frida了。
加密流程分析
通過Frida Hook libc.so后發現,聊天協議走的是JAVA層的socket,然后Hook JAVA層相關函數得到如下調用堆棧。

那么組包和加密大概率是在wq這個類里面的某些函數實現的。
打開JADX,查看wq.d$d.e函數。

e函數里可以看到body即為tcp數據,經過body = EncryptUtils.encryptMessage(body);加密,跟進encryptMessage函數。


最終發現為DES(DES/ECB/pkcs5padding)加密,加密key由getUserIdKey生成。
再次發起Frida魔法攻擊。

未加密的數據結構為protobuf。
result結果即為TCP data。

解密后就可以拿到聊天內容,發送方昵稱,發送時間等信息。
FreeBuf
信息安全與通信保密雜志社
LemonSec
商密君
虹科網絡可視化與安全
穿過叢林
一顆小胡椒
信息安全與通信保密雜志社
一顆小胡椒
LemonSec
合天網安實驗室
看雪學苑