Android注入之Ptrace注入

###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

  1. 附加到遠程進程。it

  2. 保存CONTEXT環境。class

  3. 調用mmap分配內存,向內存中寫入注入SO的路徑及調用的函數名稱。原理

  4. 遠程調用dlopen加載注入的SO。遍歷

  5. 遠程調用dlsys獲取調用函數地址。request

  6. 遠程調用須要的函數。

  7. 恢復寄存器環境。

  8. 從進程中分離。 ###具體細節

  9. 遍歷系統全部/proc/PID/cmdline,對比是不是咱們注入的APK,得到APK的PID值。

  10. Ptrace附加,waitpid等待子進程暫停。(Ptrace附加後子進程會暫停)

  11. Ptrace獲取當前子進程CONTEXT環境。

  12. 獲取子進程mmap函數地址。

  13. 父進程遠程調用子進程mmap分配內容,獲取函數返回值。

  14. Ptrace寫入須要的字符串。

  15. 獲取子進程dlopen,dlsys,dlclose函數地址。

  16. 父進程遠程調用子進程dlopen,dlsys加載並獲取SO中函數地址。

  17. 調用注入SO的函數。

  18. 恢復子進程CONTEXT環境。

  19. Ptrace分離

如何獲取子進程函數地址?

因爲庫函數是由加載Android某些連接庫實現調用的,那麼子進程中函數的偏移與父進程偏移相同,只是模塊基址不一樣,那麼:

  1. 讀取proc/PID/maps,獲取子進程和父進程調用函數所在模塊的基地址。
  2. 獲取父進程中函數的絕對地址。
  3. 計算出子進程中函數地址。

如何調用函數?

ARM函數調用約定: 函數調用的前4個參數經過R0-R3寄存器傳遞,剩餘的參數按從右到左的順序壓入棧進行傳遞 返回值保存在R0中

  1. 判斷參數個數,小於4個直接賦值R0-R3,大於4個則須要擡高棧(目的是爲了避免破壞棧中後面的數據,以便最後恢復),向棧中按順序寫入參數。
  2. 設置PC寄存器值爲調用函數地址。
  3. 判斷調用函數指令爲ARM或是Thumb,並置CPST寄存器的標誌位(判斷跳轉的地址位[0]是否爲1,見BLX原理)
  4. 設置LR寄存器爲0。(目的是爲了調用完函數後子進程暫停)
  5. 運行子程序。(ptrace(PTRACE_CONT),當下一次系統調用,子進程退出或子進程的執行發生錯誤。)
  6. 獲取子程序暫停。(waitpid(WUNTRACED) 當子進程暫停後,當即返回)。
相關文章
相關標籤/搜索