###Ptrace函數函數
long ptrace(enum __ptrace_request request,pid_t pid,void *addr, void *data);進程
第一個參數決定ptrace的行爲內存
PTRACE_ATTACH:附加到指定遠程進程。 PTRACE_DETACH:從自定遠程進程分離。 PTRACE_PEEKTEXT:從遠程進程指定內存地址來讀取一個WORD大小的數據。 PTRACE_POKETEXT:往遠程進程指定內存地址寫入一個WORD大小的數據。 PTRACE_GETREG:讀取遠程進程當前的寄存器環境。 PTRACE_SETREG:設置遠程進程寄存器環境。字符串
###實現思路cmd
-
附加到遠程進程。it
-
保存CONTEXT環境。class
-
調用mmap分配內存,向內存中寫入注入SO的路徑及調用的函數名稱。原理
-
遠程調用dlopen加載注入的SO。遍歷
-
遠程調用dlsys獲取調用函數地址。request
-
遠程調用須要的函數。
-
恢復寄存器環境。
-
從進程中分離。 ###具體細節
-
遍歷系統全部/proc/PID/cmdline,對比是不是咱們注入的APK,得到APK的PID值。
-
Ptrace附加,waitpid等待子進程暫停。(Ptrace附加後子進程會暫停)
-
Ptrace獲取當前子進程CONTEXT環境。
-
獲取子進程mmap函數地址。
-
父進程遠程調用子進程mmap分配內容,獲取函數返回值。
-
Ptrace寫入須要的字符串。
-
獲取子進程dlopen,dlsys,dlclose函數地址。
-
父進程遠程調用子進程dlopen,dlsys加載並獲取SO中函數地址。
-
調用注入SO的函數。
-
恢復子進程CONTEXT環境。
-
Ptrace分離
如何獲取子進程函數地址?
因爲庫函數是由加載Android某些連接庫實現調用的,那麼子進程中函數的偏移與父進程偏移相同,只是模塊基址不一樣,那麼:
- 讀取proc/PID/maps,獲取子進程和父進程調用函數所在模塊的基地址。
- 獲取父進程中函數的絕對地址。
- 計算出子進程中函數地址。
如何調用函數?
ARM函數調用約定: 函數調用的前4個參數經過R0-R3寄存器傳遞,剩餘的參數按從右到左的順序壓入棧進行傳遞 返回值保存在R0中
- 判斷參數個數,小於4個直接賦值R0-R3,大於4個則須要擡高棧(目的是爲了避免破壞棧中後面的數據,以便最後恢復),向棧中按順序寫入參數。
- 設置PC寄存器值爲調用函數地址。
- 判斷調用函數指令爲ARM或是Thumb,並置CPST寄存器的標誌位(判斷跳轉的地址位[0]是否爲1,見BLX原理)
- 設置LR寄存器爲0。(目的是爲了調用完函數後子進程暫停)
- 運行子程序。(ptrace(PTRACE_CONT),當下一次系統調用,子進程退出或子進程的執行發生錯誤。)
- 獲取子程序暫停。(waitpid(WUNTRACED) 當子進程暫停後,當即返回)。