android逆向奇技淫巧二十六:基礎庫的hook&x音檢測frida方式(十一)
1、萬丈高樓平地起,正常人都知道高樓大廈地基的重要性!現代產業鏈的成熟,讓產業分工越來越明細,很少有公司或團隊能完整地提供產業鏈上每個環節的產品,很多都是基於某個廠家上游的產品繼續做下游的開發,典型的如應用app開發,肯定要基於作業系統提供的api介面;同理,作業系統的開發需要基於cpu提供的彙編指令,不太可能有一家公司從cpu的製造、作業系統的開發到應用的開發大包大攬全都做(主要是管理人員沒那麼高超的管理能力運作幾十、甚至上百萬人的超大規模的團隊)!站在逆向的角度,只要抓住了底層作業系統或基礎庫提供的介面,是不是就抓住了上層應用的執行軌跡了?
做業務應用開發,速度很重要,因為網際網路是個快魚吃慢魚的時代:app早上線1天運營,可能會比競爭對手多圈幾十萬使用者,牢牢樹立起各種壁壘,讓後來者很難追上!所以開發人員為了提高速度,大概率會用很多現成的基礎庫或API(避免無意義的重複造輪子);同時,由於基礎庫長時間被大量app使用,如果有嚴重的bug或效能缺陷,早就被爆出來修復了,所以直接用基礎庫也比自己另起爐灶單獨搞一套划算得多!
- 字串類的操作:strstr、strcmp、strcat、strlen.....
- 檔案類的操作:open、read、write、close、fgetc.....
- 網路IO類操作:send、recv......
- 執行緒類操作:pthrea_create.....
我們能在Java層面使用的各種功能,底層也都是靠這些基礎庫的api實現的!比如java的FileInputStream執行時,JVM肯定呼叫了libc庫的open、read、fgetc等api來實現;又比如java的socket、outputstream等函式在jvm層面肯定呼叫了sockt、connect、send/sendto等api。再說直白點:libart.so肯定呼叫了libc.so的api,所以hook這些基礎庫(包括java層和native層)的api時,肯定能在一定程度上追蹤、還原app的各種操作
2、(1)先看看socket函式,linux/android用這個函式建立socket描述符,x音hook的結果如下(hook指令碼在文章末尾):
Entering => socket args[0] => 0xa args[1] => 0x2 args[2] => 0x0
called from: 0xc7bf8f43 libopenjdkjvm.so!JVM_Socket+0x33 0xc79ede46 libopenjdk.so!PlainDatagramSocketImpl_datagramSocketCreate+0x86 0x7093ff0d boot.oat!oatexec+0xe5f0d
第三個引數是protocol為0,作業系統核心會自動選擇type型別對應的預設協議;第二個引數是0x2,說明socket的type是SOCK_DGRAM,也就是UDP協議啦,個人猜測:這有可能是傳輸音視訊資料,也有可能是quic協議,需要進一步分析!還有,從呼叫棧的資料看,果然是上層的jvm在呼叫native層的socket函式!
(2)繼續看重要的api:send和sendto,這個是hook的結果。能找到啥關鍵資訊麼?x音的X-Khronos、X-Gorgon都能看到!
Entering => send args[0] => 0xf1 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 9aeea748 47 45 54 20 2f 74 6f 73 2d 63 6e 2d 70 2d 30 30 GET /tos-cn-p-00 9aeea758 31 35 2f 30 34 62 32 65 61 66 62 30 30 39 31 34 15/04b2eafb00914 9aeea768 65 61 63 61 63 39 35 32 32 65 64 63 63 34 63 37 eacac9522edcc4c7 9aeea778 64 65 63 5f 31 36 34 39 35 36 34 38 33 34 7e 74 dec_1649564834~t 9aeea788 70 6c 76 2d 6e 6f 6f 70 2e 69 6d 61 67 65 3f 78 plv-noop.image?x 9aeea798 2d 65 78 70 69 72 65 73 3d 31 36 34 39 35 37 39 -expires=1649579 9aeea7a8 37 30 37 26 78 2d 73 69 67 6e 61 74 75 72 65 3d 707&x-signature= 9aeea7b8 68 49 4e 64 79 31 5a 56 48 76 71 68 55 35 4c 4c hINdy1ZVHvqhU5LL 9aeea7c8 48 72 4b 67 43 6a 53 6d 72 42 59 25 33 44 20 48 HrKgCjSmrBY%3D H 9aeea7d8 54 54 50 2f 31 2e 31 0d 0a 41 63 63 65 70 74 2d TTP/1.1..Accept- 9aeea7e8 45 6e 63 6f 64 69 6e 67 3a 20 69 64 65 6e 74 69 Encoding: identi 9aeea7f8 74 79 0d 0a 52 61 6e 67 65 3a 20 62 79 74 65 73 ty..Range: bytes 9aeea808 3d 30 2d 0d 0a 58 2d 4b 68 72 6f 6e 6f 73 3a 20 =0-..X-Khronos: 9aeea818 31 36 34 39 35 37 36 30 31 30 0d 0a 58 2d 47 6f 1649576010..X-Go 9aeea828 72 67 6f 6e 3a 20 30 34 30 34 38 30 37 39 30 30 rgon: 0404807900 9aeea838 30 30 33 61 39 32 34 66 64 31 36 63 61 35 62 33 003a924fd16ca5b3 9aeea848 34 38 38 66 34 33 65 30 64 62 36 38 38 39 61 38 488f43e0db6889a8 9aeea858 31 66 61 39 30 63 37 35 38 34 0d 0a 48 6f 73 74 1fa90c7584..Host 9aeea868 3a 20 70 33 2d 73 69 67 6e 2e 64 6f 75 79 69 6e : p3-sign.douyin 9aeea878 70 69 63 2e 63 6f 6d 0d 0a 43 6f 6e 6e 65 63 74 pic.com..Connect 9aeea888 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c 69 76 65 0d ion: Keep-Alive. 9aeea898 0a 55 73 65 72 2d 41 67 65 6e 74 3a 20 6f 6b 68 .User-Agent: okh 9aeea8a8 74 74 70 2f 33 2e 31 30 2e 30 2e 31 0d 0a 0d 0a ttp/3.10.0.1.... args[2] => 0x170 called from: 0xc79d8c42 libopenjdk.so!NET_Send+0x62 0xc79f2a83 libopenjdk.so!SocketOutputStream_socketWrite0+0x133 0x7094a7ed boot.oat!oatexec+0xf07ed Entering => sendto args[0] => 0xf1 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 9aeea748 47 45 54 20 2f 74 6f 73 2d 63 6e 2d 70 2d 30 30 GET /tos-cn-p-00 9aeea758 31 35 2f 30 34 62 32 65 61 66 62 30 30 39 31 34 15/04b2eafb00914 9aeea768 65 61 63 61 63 39 35 32 32 65 64 63 63 34 63 37 eacac9522edcc4c7 9aeea778 64 65 63 5f 31 36 34 39 35 36 34 38 33 34 7e 74 dec_1649564834~t 9aeea788 70 6c 76 2d 6e 6f 6f 70 2e 69 6d 61 67 65 3f 78 plv-noop.image?x 9aeea798 2d 65 78 70 69 72 65 73 3d 31 36 34 39 35 37 39 -expires=1649579 9aeea7a8 37 30 37 26 78 2d 73 69 67 6e 61 74 75 72 65 3d 707&x-signature= 9aeea7b8 68 49 4e 64 79 31 5a 56 48 76 71 68 55 35 4c 4c hINdy1ZVHvqhU5LL 9aeea7c8 48 72 4b 67 43 6a 53 6d 72 42 59 25 33 44 20 48 HrKgCjSmrBY%3D H 9aeea7d8 54 54 50 2f 31 2e 31 0d 0a 41 63 63 65 70 74 2d TTP/1.1..Accept- 9aeea7e8 45 6e 63 6f 64 69 6e 67 3a 20 69 64 65 6e 74 69 Encoding: identi 9aeea7f8 74 79 0d 0a 52 61 6e 67 65 3a 20 62 79 74 65 73 ty..Range: bytes 9aeea808 3d 30 2d 0d 0a 58 2d 4b 68 72 6f 6e 6f 73 3a 20 =0-..X-Khronos: 9aeea818 31 36 34 39 35 37 36 30 31 30 0d 0a 58 2d 47 6f 1649576010..X-Go 9aeea828 72 67 6f 6e 3a 20 30 34 30 34 38 30 37 39 30 30 rgon: 0404807900 9aeea838 30 30 33 61 39 32 34 66 64 31 36 63 61 35 62 33 003a924fd16ca5b3 9aeea848 34 38 38 66 34 33 65 30 64 62 36 38 38 39 61 38 488f43e0db6889a8 9aeea858 31 66 61 39 30 63 37 35 38 34 0d 0a 48 6f 73 74 1fa90c7584..Host 9aeea868 3a 20 70 33 2d 73 69 67 6e 2e 64 6f 75 79 69 6e : p3-sign.douyin 9aeea878 70 69 63 2e 63 6f 6d 0d 0a 43 6f 6e 6e 65 63 74 pic.com..Connect 9aeea888 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c 69 76 65 0d ion: Keep-Alive. 9aeea898 0a 55 73 65 72 2d 41 67 65 6e 74 3a 20 6f 6b 68 .User-Agent: okh 9aeea8a8 74 74 70 2f 33 2e 31 30 2e 30 2e 31 0d 0a 0d 0a ttp/3.10.0.1.... args[2] => 0x170 called from: 0xc4d4c6d7 libc.so!send+0x47 0xc79d8c42 libopenjdk.so!NET_Send+0x62 0xc79f2a83 libopenjdk.so!SocketOutputStream_socketWrite0+0x133 0x7094a7ed boot.oat!oatexec+0xf07ed exit => sendto
從呼叫棧看,send方法呼叫了sendto方法發資料!再往上就是java層的socketOutPutStream的socketWrite方法呼叫了native的send函式!所以理論上講,去hook java層的socket類、outputStream等也能得到傳送的資料!
(3)fgets函式:從檔案讀資料的。hook前面兩個引數部分日誌如下:這樣是不是很明顯在檢測frida了?
Entering => fgets args[0] => abda5000-abfe8000 rw-p 00000000 00:00 0 [anon:.bss] args[1] => 0x200 retval is => abfe8000-ad635000 r-xp 00000000 08:12 917529 /data/local/tmp/re.frida.server/frida-agent-32.so exit => fgets Entering => fgets args[0] => abfe8000-ad635000 r-xp 00000000 08:12 917529 /data/local/tmp/re.frida.server/frida-agent-32.so args[1] => 0x200 retval is => ad635000-ad681000 r--p 0164c000 08:12 917529 /data/local/tmp/re.frida.server/frida-agent-32.so exit => fgets Entering => fgets args[0] => ad635000-ad681000 r--p 0164c000 08:12 917529 /data/local/tmp/re.frida.server/frida-agent-32.so args[1] => 0x200 retval is => ad681000-ad68f000 rw-p 01698000 08:12 917529 /data/local/tmp/re.frida.server/frida-agent-32.so exit => fgets Entering => fgets args[0] => ad681000-ad68f000 rw-p 01698000 08:12 917529 /data/local/tmp/re.frida.server/frida-agent-32.so args[1] => 0x200 retval is => ad68f000-ad6c2000 rw-p 00000000 00:00 0 [anon:.bss]
個人猜測檢測的程式碼可能是這樣寫的:
char line[0x200]; FILE* fp; fp = fopen("/proc/self/maps", "r"); if (fp) { while (fgets(line, 0x200, fp)) { if (strstr(line, "frida")) { /* Evil library is loaded. Do something… 檢測frida的程式碼邏輯*/ } } fclose(fp); } else { /* Error opening /proc/self/maps. If this happens, something is off. */ } }
順著這個思路,也可以hook strstr、strcmp等常見的函式看看有沒有檢測的邏輯!
(4)hook的核心js程式碼:整體的思路很簡單,就是遍歷modules,找到libc.so;然後進一步找到遍歷庫的匯出表,找到關鍵的庫函式去hook!
function traceNativeExport(){ var modules = Process.enumerateModules(); for(var i = 0;i<modules.length;i++){ var module = modules[i]; //只hook libc.so if(module.name.indexOf("libc.so")<0){ continue; } var exports = module.enumerateExports(); for(var j = 0;j<exports.length;j++){ //console.log("module name is =>",module.name," symbol name is =>",exports[j].name) //var path = "/sdcard/Download/so/"+module.name+".txt" // var path = "/data/data/com.ss.aweme/cache/"+module.name+".txt" // writeSomething(path,"type: "+exports[j].type+" function name :"+exports[j].name+" address : "+exports[j].address+" offset => 0x"+ ( exports[j].address.sub(modules[i].base) )+"\n") // if(exports[j].name.indexOf("strto")>=0)continue; // if(exports[j].name.indexOf("strco")>=0)continue; // if(exports[j].name.indexOf("_l")>=0)continue; // if(exports[j].name.indexOf("pthread")>=0)continue; //int socket(int domain, int type, int protocol); /*if(exports[j].name.indexOf("socket")>=0){ attach(exports[j].name,exports[j].address); }*/ /*if(exports[j].name.indexOf("pthread_create")>=0){ attach(exports[j].name,exports[j].address); }*/ //int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) /*if(exports[j].name.indexOf("connect")>=0){ attach(exports[j].name,exports[j].address); }*/ // if(exports[j].name.indexOf("read")>=0){ // attach(exports[j].name,exports[j].address); // } // if(exports[j].name.indexOf("write")>=0){ // attach(exports[j].name,exports[j].address); // } //ssize_t send(int sockfd, const void *buf, size_t len, int flags); /*if(exports[j].name.indexOf("send")>=0){ attach(exports[j].name,exports[j].address); } /*if(exports[j].name.indexOf("strstr")>=0){ attach(exports[j].name,exports[j].address); }*/ /*if(exports[j].name.indexOf("strcmp")>=0){ attach(exports[j].name,exports[j].address); }*/ if(exports[j].name.indexOf("fgets")>=0){ attach(exports[j].name,exports[j].address); } // if(exports[j].name.indexOf("recv")>=0){ // attach(exports[j].name,exports[j].address); // } } } } function attach(name,address){ console.log("attaching ",name); Interceptor.attach(address,{ onEnter:function(args){ console.log("Entering => " ,name) console.log("args[0] => ",args[0].readCString()) console.log("args[1] => ",args[1]) /*if(args[0].readCString().indexOf("frida")>=0 ||args[0].readCString().indexOf("xpose")>=0 ||args[1].readCString().indexOf("xpose")>=0 ||args[1].readCString().indexOf("frida")>=0){ console.log("Entering => " ,name) console.log("args[0] => ",args[0].readCString()) console.log("args[1] => ",args[1].readCString()) console.log('\n called from:\n' +Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n'); }*/ /*console.log("args[0] => ",args[0].readCString()) console.log("args[1] => ",args[1].readCString())*/ /*console.log( hexdump(args[0],{ offset: 0, length: parseInt(args[1]), header: true, ansi: true }))*/ //console.log("args[2] => ",args[2]) //console.log('\n called from:\n' +Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n'); },onLeave:function(retval){ console.log("retval is => ",retval.readCString()) console.log("\n exit => ",name) // console.log("retval is => ",retval.readCString()) } }) }
參考:
1、https://blog.csdn.net/zhangmiaoping23/article/details/109697329 多種特徵檢測frida