生活随笔
收集整理的這篇文章主要介紹了
进击的Android Hook 注入术《二》
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
目錄(?)[-]
繼續注入 分類本質目的過程示例一 Host代碼libmysoso代碼調用 示例代碼
繼續
在《一》里,我把基本思路描述了一遍,接下為我們先從注入開始入手。
注入
分類
我們平時所說的代碼注入,主要靜態和動態兩種方式
- 靜態注入,針對是可執行文件,比如平時我們修改ELF,DEX文件等等,相關的輔助工具也很多,比如IDA、JEB、ApkTool等等;
- 動態注入,針對是進程,比如修改進程的寄存器、內存值等等;
動態跟靜態最大的區別是,動態不需要改動源文件,但需要高權限(通常是root權限),而且所需的技術含量更高。
本質
動態注入技術,本質上就是一種調度技術。想想平時我們調試一個進程時,可以做哪些功能? 一般有下列幾項:
- 查看變量值
- 修改變量值
- 跟蹤進程跳轉
- 查看進程調用堆棧
- 等等
動態注入相比于普通的調試,最大的區別就是動態注入是一個
”自動化調試并達到加載自定義動態鏈接庫“的過程。所謂自動化,其實就是通過代碼實現,在Linux上通過Ptrace就可以完成上面所有功能,當然Ptrace功能是比較原始的,平時調試中的功能還需要很多高層邏輯封裝才可以實現。 在閱讀下面章節之前,強烈建議閱讀一下man文檔,見這里。
目的
一般而言,我們要對一個進程進行注入,主要有以下幾方面目的:
- 增強目標進程的功能;
- 修復目標進程缺陷;
- 劫持目標進程函數;
- 竊取目標進程數據;
- 篡改目標進程數據;
過程
如上圖所示,進程A注入到進程B后,通過修改寄存器和內存,讓進程B加載自定義的動態庫a,當a被加載后,a會嘗試加載其他模塊,比如加載dex文件等等,具體的注入過程如下:
- ATTATCH,指定目標進程,開始調試;
- GETREGS,獲取目標進程的寄存器,保存現場;
- SETREGS,修改PC等相關寄存器,使其指向mmap;
- POPETEXT,把so path寫入mmap申請的地址空間;
- SETRESG,修改PC等相關寄存器,使其指向dlopen;
- SETREGS,恢復現場;
- DETACH,解除調試,使其恢復;
上述是一個簡化的過程,整個注入的代碼,我已經上傳到github,地址https://github.com/boyliang/Poison 當so被dlopen加載到目標進程后,我們需要讓so中的邏輯被執行,比較復雜的做法是同樣使用ptrace修改寄存器的辦法,讓目標進程調用dlsym找到我們函數的地址。而比較簡單的做法有兩種,如下
- 使用gcc的預編譯指令__attribute__ ((__constructor__)),作用是讓so被加載后,函數被自動執行;
[cpp] view plain
copy __attribute__?((__constructor__))??void?Main()?{???LOGI(">>>>>>>>>>>>>I?am?in,?I?am?a?bad?boy?1!!!!<<<<<<<<<<<<<<");?????void*?handle?=?dlopen("libinso.so",?RTLD_NOW);???void?(*setA_func)(int)?=?(void?(*)(int))dlsym(handle,?"setA");?????if?(setA_func)?{?????setA_func(999);???}??}?? - 使用c++全局對象初始化,其構造函數會被自動執行;
[cpp] view plain
copy void?Main();????static?void*?_main(void*){??????Main();??????return?NULL;??}????class?EntryClass?{??public:????????EntryClass()?{??????????pthread_t?tid;??????????pthread_create(&tid,?NULL,?_main,?NULL);??????????pthread_detach(tid);??????}????}?boy;?? 示例一
下面示例一個通過ptrace注入的示例,涉及到兩部分代碼,一部分是目標進程代碼記作host,另一部分是被我們注入的so代碼記作libmyso.so
Host代碼
包含三個源文件,分別是demo1.c,inso.h, inso.c
[cpp] view plain
copy ???????????__attribute__?((visibility?("default")))?void?setA(int?i);????__attribute__?((visibility?("default")))?int?getA();?? [cpp] view plain
copy ?????????#include?<stdio.h>??#include?"inso.h"????static?int?gA?=?1;????void?setA(int?i){??????gA?=?i;??}????int?getA(){??????return?gA;??}?? [cpp] view plain
copy ?????????#include?<stdio.h>??#include?<unistd.h>????#include?"inso.h"??#include?"log.h"????int?main(){????????LOGI("DEMO1?start.");????????while(1){??????????LOGI("%d",?getA());??????????setA(getA()?+?1);??????????sleep(2);??????}????????return?0;??}?? libmyso.so代碼
[cpp] view plain
copy ?????????#include?<stdio.h>??#include?<stddef.h>??#include?<dlfcn.h>??#include?<pthread.h>??#include?<stddef.h>????#include??"log.h"????__attribute__?((__constructor__))??void?Main()?{??????LOGI(">>>>>>>>>>>>>I?am?in,?I?am?a?bad?boy?1!!!!<<<<<<<<<<<<<<");????????void*?handle?=?dlopen("libinso.so",?RTLD_NOW);??????void?(*setA_func)(int)?=?(void?(*)(int))dlsym(handle,?"setA");????????if?(setA_func)?{??????????setA_func(999);??????}??}?? 調用
注入程序,我將其命名為poison,使用方法是poison <so_path> <target_pit>。下面是示例的輸出顯示:
[plain] view plain
copy I/TTT?????(??594):?DEMO1?start.??I/TTT?????(??594):?1??I/TTT?????(??594):?2??I/TTT?????(??594):?3??I/TTT?????(??594):?4??I/TTT?????(??594):?5??I/TTT?????(??594):?6??I/TTT?????(??594):?7??I/TTT?????(??594):?>>>>>>>>>>>>>I?am?in,?I?am?a?bad?boy?1!!!!<<<<<<<<<<<<<<??I/TTT?????(??594):?999??I/TTT?????(??594):?1000??I/TTT?????(??594):?1001?? 當執行./poison /data/local/tmp/libmyso.so 594后,輸出中馬上出現了特定字符串,并且打印的數據一下子變成了999,證明我們注入成功了。
示例代碼
上述示例所涉及到代碼,我都放發布到github上了,大家如果想研究代碼,可以到https://github.com/boyliang/injection_by_ptrace
在《三》,我會再介紹一種Android上特有的注入技術,敬請期待。
原文地址:?http://blog.csdn.net/l173864930/article/details/38456313
總結
以上是生活随笔為你收集整理的进击的Android Hook 注入术《二》的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。