android hook 架構 xposed 如何?注入

來源:互聯網
上載者:User

標籤:

前面分析的adbi架構和libinject都是使用so注入的方式,實現將指定代碼裝入目標進程,這種方式有幾個特點:

1. 是動態,需要目標進程已經啟動

2. 無法影響全域,比如注入A進程掛鈎裡邊libc.so的open函數,此時,B進程使用的libc.so的open函數還是老函數,linux系統通過COW機制,在你注入A進程並執行對open的掛鈎的時候,拷貝了新的頁面,放入新的函數。如果要影響全域,應該注入到類似 Zygote 這樣的進程,且應該在zygote進程啟動之後馬上注入,這樣後續zygote進程產生子進程時就能使用掛鈎後的函數

3. 需要依賴ptrace機制,某些情況下,目標進程無法被執行ptrace,則這種方式會失效

這一篇我們分析另外一種方式,是著名的xposed架構使用的方式,不需要動態注入,而是直接替換android系統的一個可執行程式。

 

一,android應用程式層進程啟動最初始的幾步

linux系統裝載並初始化各個子系統完畢後,執行第一個應用程式層程式init, android 的 init 程式是自己定製的,與其它linux發行版不一樣,它同樣會解析並執行 init.rc 設定檔。其中,有一步如下,調用 app_process 程式啟動 zygote 進程,xposed 替換的就是這個  /system/bin/app_process 程式

 

system/core/rootdir/init.rc

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server    class main    socket zygote stream 660 root system    onrestart write /sys/android_power/request_state wake    onrestart write /sys/power/state on    onrestart restart media    onrestart restart netd

 

android\frameworks\base\cmds\app_process\app_main.cpp  : main 函數

  if (zygote) {        runtime.start("com.android.internal.os.ZygoteInit",                startSystemServer ? "start-system-server" : "");    } else if (className) {        // Remainder of args get passed to startup class main()        runtime.mClassName = className;        runtime.mArgC = argc - i;        runtime.mArgV = argv + i;        runtime.start("com.android.internal.os.RuntimeInit",                application ? "application" : "tool");    } else {

app_process 是native世界進入java世界的入口,它初始化了虛擬機器的執行時環境,並根據不同的參數,調用 com.android.internal.os.ZygoteInit 或者 com.android.internal.os.RuntimeInit 這兩個java類的main函數,如果是前者,則進入的 zygote 的世界。

 

Xposed\app_main.cpp : main 函數

if (zygote) {        runtime.start(keepLoadingXposed ? XPOSED_CLASS_DOTS : "com.android.internal.os.ZygoteInit",                startSystemServer ? "start-system-server" : "");    } else if (className) {        // Remainder of args get passed to startup class main()        runtime.mClassName = className;        runtime.mArgC = argc - i;        runtime.mArgV = argv + i;        runtime.start(keepLoadingXposed ? XPOSED_CLASS_DOTS : "com.android.internal.os.RuntimeInit",                application ? "application" : "tool");    } else {

#define XPOSED_CLASS_DOTS "de.robv.android.xposed.XposedBridge"

與標準流程不一樣的地方,如果檢測到android版本支援xposed且已經安裝了Xposed,則 runtime.start 啟動的是  de.robv.android.xposed.XposedBridge 的main函數,進入了 xposed 的世界

 

xposedbridge.java

private static void main(String[] args) {        // the class the VM has been created for or null for the Zygote process        String startClassName = getStartClassName();        // initialize the Xposed framework and modules        try {            // initialize log file            try {                logFile = new File(BASE_DIR + "log/error.log");                if (startClassName == null && logFile.length() > MAX_LOGFILE_SIZE_SOFT)                    logFile.renameTo(new File(BASE_DIR + "log/error.log.old"));                logWriter = new PrintWriter(new FileWriter(logFile, true));                logFile.setReadable(true, false);                logFile.setWritable(true, false);            } catch (IOException ignored) {}            String date = DateFormat.getDateTimeInstance().format(new Date());            determineXposedVersion();            log("-----------------\n" + date + " UTC\n"                    + "Loading Xposed v" + XPOSED_BRIDGE_VERSION                    + " (for " + (startClassName == null ? "Zygote" : startClassName) + ")...");            if (startClassName == null) {                // Zygote                log("Running ROM ‘" + Build.DISPLAY + "‘ with fingerprint ‘" + Build.FINGERPRINT + "‘");            }            if (initNative()) {                if (startClassName == null) {                    // Initializations for Zygote                    initXbridgeZygote();                }                loadModules(startClassName);            } else {                log("Errors during native Xposed initialization");            }        } catch (Throwable t) {            log("Errors during Xposed initialization");            log(t);            disableHooks = true;        }        // call the original startup code        if (startClassName == null)            ZygoteInit.main(args);        else            RuntimeInit.main(args);    }

xposedbridge 類先初始化xposed需要的環境,然後載入註冊到xposed架構裡的 xposed 模組,這一步執行完後,所以 xposed 對虛擬機器的掛鈎已經完成,mian 函數最後,執行  ZygoteInit.main 或者 RuntimeInit.main ,  進入正常的流程

 

從這裡可以看出,xposed 對虛擬機器的注入採用的是比動態注入更優雅的方式,有幾個特點:

 

1. 由於替換了 app_process ,替換後的app_process 肯定是先啟動 xposed 然後再進入 zygote ,而其他app都是 zygote 建立的,這樣xposed 的掛鈎一定的全域性的,所有app都會被影響

2. 只需要安裝xposed時擁有root許可權以替換系統的 app_process , 之後不再需要root許可權,而前面採用 so動態注入的方式,每次要掛鈎都需要注入,每次注入zygote 都需要root許可權

3. 不需要依賴 ptrace 等機制

android hook 架構 xposed 如何?注入

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.