文章目錄
上一節已經分析應用程式啟動後,會通過RootTools庫的Shell類,擷取root許可權並執行/data/data/com.aatt.fpsm/files/0,也就是apk包中的res/raw/bin0這個二進位檔案,此二進位檔案再通過ptrace系統調用,去綁定到其他進程中,做一些動作。接下來看一下fps meter這個apk到底是做了什麼動作。
Ptrace調用過程分析
ptrace是提供一個進程式控制制另外一個進程啟動並執行機制,通過它可以查看和更改進程的資料,它也是linux上的偵錯工具gdb的基礎。
ptrace調用
為查看ptrace的系統調用情況,最好的方法是在核心對應的系統調處理函數中將相關資訊列印出來,修改核心的ptrace調用,加入trace,這樣就可以在無源碼的情況下,查看到bin0都使用了哪些ptrace操作請求,這裡主要有:
ptrace: pid=76 req=16 addr=0 data=0ptrace: pid=76 req=12 addr=0 data=be86f938 ptrace: pid=76 req=5 addr=be84fa28 data=7461642f ptrace: pid=76 req=5 addr=be84fa2c data=61642f61 ptrace: pid=76 req=5 addr=be84fa30 data=632f6174 ptrace: pid=76 req=5 addr=be84fa34 data=612e6d6f ptrace: pid=76 req=5 addr=be84fa38 data=2e747461 ptrace: pid=76 req=5 addr=be84fa3c data=6d737066 ptrace: pid=76 req=5 addr=be84fa40 data=6c69662f ptrace: pid=76 req=5 addr=be84fa44 data=302f7365 ptrace: pid=76 req=5 addr=be84fa48 data=6f732e ptrace: pid=76 req=13 addr=0 data=be86f938 ptrace: pid=76 req=7 addr=0 data=0 ptrace: pid=76 req=12 addr=0 data=be86f938 ptrace: pid=76 req=5 addr=be84f9a8 data=64616f6c ptrace: pid=76 req=2 addr=be84f9ac data=be86f8bc ptrace: pid=76 req=5 addr=be84f9ac data=40f30000 ptrace: pid=76 req=13 addr=0 data=be86f938 ptrace: pid=76 req=7 addr=0 data=0 ptrace: pid=76 req=12 addr=0 data=be86f938 ptrace: pid=76 req=13 addr=0 data=be86f938 ptrace: pid=76 req=7 addr=0 data=0 ptrace: pid=76 req=12 addr=0 data=be86f938 ptrace: pid=76 req=13 addr=0 data=be86f980 ptrace: pid=76 req=7 addr=0 data=0 ptrace: pid=76 req=17 addr=0 data=0
從trace出來的pid我們可以知道,ptrace是掛到surfaceflinger進程中,對其進行操作修改的,這從該apk的功能來看,確實合理。先看下surfaceflinger的maps資訊(省略了一些非關鍵資訊),這是分析的主要依據:
# cat /proc/76/mapsmaps: root@android:/proc/76 # cat maps 400a8000-400a9000 r-xp 00000000 5d:10 241 /system/bin/surfaceflinger 400a9000-400aa000 r--p 00000000 5d:10 241 /system/bin/surfaceflinger 400aa000-400ab000 rw-p 00000000 00:00 0 400ab000-400b9000 r-xp 00000000 5d:10 167 /system/bin/linker 400b9000-400ba000 r--p 00000000 00:00 0 400ba000-400bb000 r--p 0000e000 5d:10 167 /system/bin/linker 400bb000-400bc000 rw-p 0000f000 5d:10 167 /system/bin/linker 400bc000-400c6000 rw-p 00000000 00:00 0 400c6000-400f5000 r-xp 00000000 5d:10 771 /system/lib/libsurfaceflinger.so 400f5000-400fa000 r--p 0002e000 5d:10 771 /system/lib/libsurfaceflinger.so 400fa000-400fb000 rwxp 00033000 5d:10 771 /system/lib/libsurfaceflinger.so 400fb000-400fc000 rw-p 00034000 5d:10 771 /system/lib/libsurfaceflinger.so ................40146000-40147000 ---p 00000000 00:00 0 40147000-40149000 r--p 00045000 5d:10 644 /system/lib/libc.so 40149000-4014b000 rw-p 00047000 5d:10 644 /system/lib/libc.so 4014b000-40156000 rw-p 00000000 00:00 0 ................401d3000-40210000 r-xp 00000000 5d:10 606 /system/lib/libEGL.so 40210000-40212000 r--p 0003c000 5d:10 606 /system/lib/libEGL.so 40212000-40216000 rw-p 0003e000 5d:10 606 /system/lib/libEGL.so ................40306000-4030e000 r--s 00000000 00:0a 2126 /dev/__properties__ (deleted) 4030e000-4040c000 r--p 00000000 00:0a 2687 /dev/binder 4040c000-4040d000 ---p 00000000 00:00 0 4040d000-4050c000 rw-p 00000000 00:00 0 [stack:125] ................40b7a000-40b80000 rw-p 00000000 00:00 0 [heap] ................40c39000-40c3c000 r-xp 00000000 5d:10 1031 /system/vendor/lib/hw/hwcomposer.default.so 40c3c000-40c43000 ---p 00000000 00:00 0 40c43000-40c44000 r--p 00002000 5d:10 1031 /system/vendor/lib/hw/hwcomposer.default.so 40c44000-40c45000 rw-p 00003000 5d:10 1031 /system/vendor/lib/hw/hwcomposer.default.so 40c45000-40c46000 ---p 00000000 00:00 0 40c46000-40d45000 rw-p 00000000 00:00 0 [stack:184] 40d45000-40d46000 ---p 00000000 00:00 0 40d46000-40e45000 rw-p 00000000 00:00 0 [stack:187] 40e45000-40e47000 rw-p 00000000 00:00 0 ................4163c000-41641000 r-xp 00000000 5d:20 311 /data/data/com.aatt.fpsm/files/0.so 41641000-41642000 r--p 00004000 5d:20 311 /data/data/com.aatt.fpsm/files/0.so 41642000-41643000 rw-p 00005000 5d:20 311 /data/data/com.aatt.fpsm/files/0.so ................bea46000-bea67000 rw-p 00000000 00:00 0 [stack] ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]
從maps資訊中,其實已經能看出一些門道了:
4163c000-41641000 r-xp 00000000 5d:20 311 /data/data/com.aatt.fpsm/files/0.so 41641000-41642000 r--p 00004000 5d:20 311 /data/data/com.aatt.fpsm/files/0.so 41642000-41643000 rw-p 00005000 5d:20 311 /data/data/com.aatt.fpsm/files/0.so
這個資訊可以看出,fps meter中的0.so,被注入到surfaceflinger中,這在android的安全規則中是不可能的。也就是說surfaceFlinger已經被入侵感染了,不是原來的surfaceFlinger了!
繼續分析之前,首先還是看一下ptrace的操作,上述的trace中,request id就是各個ptrace請求命令。這裡用到的有如下幾個:
Request |
Macro |
Description |
16 |
PTRACE_ATTACH |
Attach到被調試進程,attach之後,被調試進程將暫停執行 |
12 |
PTRACE_GETREGS |
擷取被調試線程的各個寄存器值 |
5 |
PTRACE_POKEDATA |
修改記憶體位址的值 |
13 |
PTRACE_SETREGS |
設定寄存器的值 |
7 |
PTRACE_CONT |
繼續執行暫停程式 |
2 |
PTRACE_PEEKDATA |
從被調試進程的指定記憶體位置讀取資料 |
17 |
PTRACE_DETACH |
停止對進程的調試,恢複其常態運行 |
調用細節
為瞭解更細節的資訊,需要更詳盡的trace,繼續將相關的輸入輸出參數都列印出來,結合上面的maps資訊,對每一步的ptrace調用,詳細分析流程如下:
ptrace_request: pid=76 req=16 addr=0 data=0 ptrace_request: pid=76 req=12 addr=0 data=beb68938 PTRACE_GETREGS: r0 00000003 r1 c0186201 r2 bea66ac8 r3 bea66ac4 r4 40b7e020 r5 40b7dff0 r6 40b7e050 r7 00000036 r8 00000001 r9 40b7dff8 sl 00000000 fp bea66b7c ip 402bbf24 sp bea66aa8 lr 4012b9f5 pc 40117ffc cpsr 80000010
這裡是attach到surfaceflinger線程,暫停surfaceflinger線程的執行,然後擷取暫停時的寄存器資料。對於這裡分析的fps meter的注入入侵,需要儲存surfaceflinger線程暫停點的寄存器資訊,入侵完畢後再恢複現場,繼續surfaceflinger的正常運行。
ptrace: pid=76 req=5 addr= bea66a28 data=7461642f ptrace: pid=76 req=5 addr= bea66a2c data=61642f61 ptrace: pid=76 req=5 addr= bea66a30 data=632f6174 ptrace: pid=76 req=5 addr= bea66a34 data=612e6d6f ptrace: pid=76 req=5 addr= bea66a38 data=2e747461 ptrace: pid=76 req=5 addr= bea66a3c data=6d737066 ptrace: pid=76 req=5 addr= bea66a40 data=6c69662f ptrace: pid=76 req=5 addr= bea66a44 data=302f7365 ptrace: pid=76 req=5 addr= bea66a48 data=006f732e
這裡的req=5就是PTRACE_POKEDATA,修改棧上的資料,修改的指標是addr=0xbea66a28, 則以上幾個POKEDATA的調用,作用將(char )addr[]的內容修改為:“/data/data/com.aatt.fpsm/files/0.so”,這即是要注入的so的路徑。
ptrace_request: pid=76 req=13 addr=0 data=beb68938 PTRACE_SETREGS: r0 bea66a28 r1 00000000 r2 bea66ac8 r3 bea66ac4 r4 40b7e020 r5 40b7dff0 r6 40b7e050 r7 00000036 r8 00000001 r9 40b7dff8 sl 00000000 fp bea66b7c ip 402bbf24 sp bea66a28 lr 00000000 pc 400b00ad cpsr 80000030 ptrace_request: pid=76 req=7 addr=0 data=0
調用PTRACE_SETREGS設定寄存器,然後再調用PTRACE_CONT執行。
這裡面設定的寄存器,主要變動如下:
- R0:應參數,是字串“/data/data/com.aatt.fpsm/files/0.so”的指標
- sp : 堆棧地址,也是字串的指標位置
- lr: 函數返回地址
- pc:需要注入代碼的起始地址
這裡的lr是0,程式出錯後跳到0去,肯定會出現異常,導致程式停止,調試端進程可以通過waitpid得知該次注入的代碼已經被執行。
pc的地址 400b00ad,從上節的maps表中可以看到,這是android的動態連接器linker中的代碼,PC是位於linker的代碼位移位置:400b00ad-400ab000=50ad的位置。50ad說明實際位移是0x50AC,最低位的1表明是thumb指令。
那這個位置具體是什麼呢(肯定是某個函數)?這個函數沒有匯出符號,我也沒看出來,不過從參數和上下文分析,猜測可能是dlopen,不然用so作參數,調用linker的函數幹嘛呢? 寫個小程式驗證了一下:
#define LOG_TAG "TEST"#include <dlfcn.h>#include <unistd.h>#include <cutils/log.h>int main(int argc, char *argv){ALOGD("dlopen:%p dlsym:%p", (void*)dlopen, (void*)dlsym);while(1){sleep(100);}}
運行後,輸出的結果:
D/TEST (27539): dlopen:0x4002d0ad dlsym:0x4002d019
對比此測試進程的maps資訊:
root@android:/ # cat /proc/27539/maps40025000-40026000 r-xp 00000000 5d:10 1304 /system/bin/test_linker40026000-40027000 r--p 00000000 5d:10 1304 /system/bin/test_linker40027000-40028000 rw-p 00000000 00:00 040028000-40036000 r-xp 00000000 5d:10 144 /system/bin/linker40036000-40037000 r--p 00000000 00:00 040037000-40038000 r--p 0000e000 5d:10 144 /system/bin/linker40038000-40039000 rw-p 0000f000 5d:10 144 /system/bin/linker...400d5000-400dd000 r--s 00000000 00:0a 2180 /dev/__properties__ (deleted)beb4d000-beb6e000 rw-p 00000000 00:00 0 [stack]ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]
4002d0ad-40028000=50ad, 正好驗證,確定這個ptrace是讓surfaceflinger調用linker中的dlopen,載入/data/data/com.aatt.fpsm/files/0.so
so庫載入完成後,系統waitpid返回,再看一下寄存器:
ptrace_request: pid=76 req=12 addr=0 data=beb68938 PTRACE_GETREGS: r0 400be054 r1 00000000 r2 00000001 r3 004b4001 r4 40b7e020 r5 40b7dff0 r6 40b7e050 r7 00000036 r8 00000001 r9 40b7dff8 sl 00000000 fp bea66b7c ip 00000000 sp bea66a28 lr 00001ffc pc 00000000 cpsr 80000010
surfaceflinger進程暫停,這裡讀取寄存器的值,可以看到PC是0,注入的程式執行完畢
ptrace: pid=76 req=5 addr=bea669a8 data=64616f6c ptrace: pid=76 req=2 addr=bea669ac data=40b7e020 ptrace: pid=76 req=5 addr=bea669ac data=40b7e000
設定地址0xbea669a8的值為"load",讀取的bea669ac值為0x40b7e020,然後再通過PTRACE_POKEDATA將其設定成0x40b7e00,這個地址,位於堆中,應該是malloc出來的一個指標,具體作用不明。
ptrace_request: pid=76 req=13 addr=0 data=beb68938PTRACE_SETREGS: r0 400be054 r1 bea669a8 r2 00000001 r3 004b4001 r4 40b7e020 r5 40b7dff0 r6 40b7e050 r7 00000036 r8 00000001 r9 40b7dff8 sl 00000000 fp bea66b7c ip 00000000 sp bea669a8 lr 00000000 pc 400b0019 cpsr 80000030 ptrace_request: pid=75 req=7 addr=0 data=0
PTRACE_CONT執行, 這裡設定的pc:400b0019,可以看到是linker中的位移位置:0x5019,結合剛才寫的測例,就是dlsym函數。這裡就是查詢到load函數的地址。
ptrace_request: pid=76 req=12 addr=0 data=beb68938PTRACE_GETREGS: r0 4163da81 r1 00000000 r2 400be054 r3 400be054 r4 40b7e020 r5 40b7dff0 r6 40b7e050 r7 00000036 r8 00000001 r9 40b7dff8 sl 00000000 fp bea66b7c ip 00000000 sp bea669a8 lr 00001ffc pc 00000000 cpsr 80000010 ptrace_request: pid=75 req=13 addr=0 data=beb68938 PTRACE_SETREGS: r0 4163da81 r1 00000000 r2 400be054 r3 400be054 r4 40b7e020 r5 40b7dff0 r6 40b7e050 r7 00000036 r8 00000001 r9 40b7dff8 sl 00000000 fp bea66b7c ip 00000000 sp bea669a8 lr 00000000 pc 4163da81 cpsr 80000030 ptrace_request: pid=76 req=7 addr=0 data=0
PC為0.so中的函數,在0.so中的位移為:4163da81-4163c000=1a81,這剛好是剛才dlsym查出來的load函數的位置,見IDA pro的反組譯碼資訊:
這樣,就在surfaceflinger中注入了使用者提供的so庫的代碼了!
注入完成後,接下來我們需要恢複之前被暫停surfaceflinger進程的正常執行:
ptrace_request: pid=76 req=12 addr=0 data=beb68938 PTRACE_GETREGS: r0 00000000 r1 4272d3f3 r2 00000001 r3 40b7dff8 r4 40b7e020 r5 40b7dff0 r6 40b7e050 r7 00000036 r8 00000001 r9 40b7dff8 sl 00000000 fp bea66b7c ip 40000002 sp bea669a8 lr 0000001e pc 00000000 cpsr 60000010 ptrace_request: pid=76 req=13 addr=0 data=beb68938 PTRACE_SETREGS: r0 00000003 r1 c0186201 r2 bea66ac8 r3 bea66ac4 r4 40b7e020 r5 40b7dff0 r6 40b7e050 r7 00000036 r8 00000001 r9 40b7dff8 sl 00000000 fp bea66b7c ip 402bbf24 sp bea66aa8 lr 4012b9f5 pc 40117ffc cpsr 80000010 ptrace_request: pid=76 req=7 addr=0 data=0 ptrace_request: pid=76 req=17 addr=0 data=0
寄存器恢複到暫前的樣子,寄生進程從surfaceflinge分離,恢複宿主進程執行。
小結
以上我們可以簡單的比喻一下:寄生進程為bin0,宿主進程為surfaceflinger,寄生進程通過ptrace綁到宿主進程上,咬一口(linker調用),下了一個卵(/data/data/com.aatt.fpsm/files/0.so及load調用)到宿主進程,然後飛走了。
通過詳細分析了注入過程,應該瞭解了用ptrace將需要的庫或代碼植入宿主進程的方法。在不經意間,你啟動並執行正常進程,已經被人為的添加進去可能有害的代碼,這可能對你的資訊安全或者系統穩定性有很大的影響。
不過linux系統相對來說還是很安全的,這裡也並沒有利用什麼漏洞,如果使用者不root系統的話,是很難被注入代碼的。