進擊的Android注入術《二》

來源:互聯網
上載者:User

標籤:

繼續在《一》裡,我把基本思路描寫敘述了一遍,接下為我們先從注入開始入手。
注入
分類我們平時所說的代碼注入,主要靜態和動態兩種方式
  • 靜態注入,針對是可運行檔案,比方平時我們改動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被載入後,函數被自己主動運行;
__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++全域對象初始化,其建構函式會被自己主動運行;
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
/* * inso.h * *  Created on: 2014年6月24日 *      Author: boyliang */__attribute__ ((visibility ("default"))) void setA(int i);__attribute__ ((visibility ("default"))) int getA();
/* * inso.c * *  Created on: 2014年6月24日 *      Author: boyliang */#include <stdio.h>#include "inso.h"static int gA = 1;void setA(int i){gA = i;}int getA(){return gA;}
/* * demo1.c * *  Created on: 2014年6月24日 *      Author: boyliang */#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代碼
/* * myso.c * *  Created on: 2014年6月24日 *      Author: boyliang */#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>。以下是示範範例的輸出顯示:
I/TTT     (  594): DEMO1 start.I/TTT     (  594): 1I/TTT     (  594): 2I/TTT     (  594): 3I/TTT     (  594): 4I/TTT     (  594): 5I/TTT     (  594): 6I/TTT     (  594): 7I/TTT     (  594): >>>>>>>>>>>>>I am in, I am a bad boy 1!!!!<<<<<<<<<<<<<<I/TTT     (  594): 999I/TTT     (  594): 1000I/TTT     (  594): 1001
當運行./poison /data/local/tmp/libmyso.so 594後,輸出中立即出現了特定字串,而且列印的資料一下子變成了999,證明我們注入成功了。示範範例代碼上述示範範例所涉及到代碼,我都放公布到github上了,大家假設想研究代碼,能夠到https://github.com/boyliang/injection_by_ptrace在《三》,我會再介紹一種Android上特有的注入技術,敬請期待。

進擊的Android注入術《二》

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.