安卓 熱修複的原理

來源:互聯網
上載者:User

標籤:void   when   orm   開發   需要   dcl   zed   oid   引用   

 韓夢飛沙  韓亞飛  [email protected]  yue31313  han_meng_fei_sha

#熱修複技術

APP提早發出去的包,如果出現用戶端的問題,實在是干著急,覆水難收。因此線上修複方案迫在眉睫。

###概述

基於Xposed中的思想,通過修改c層的Method執行個體描述,來實現更改與之對應的java方法的行為,從而達到修複的目的。

###Xposed

誕生於XDA論壇,類似一個應用平台,不同的是其提供諸多系統級的應用。可實現許多神奇的功能。Xposed需要以越獄為前提,像是iOS中的cydia。

Xposed可以修改任何程式的任何java方法(需root),github上提供了XposedInstaller,是一個android app。提供很多framework層,應用程式層級的程式。開發人員可以為其開發一些系統或應用方面的外掛程式,自訂android系統,它甚至可以做動態許可權管理(XposedMods)。

###Android系統啟動與應用啟動

Zygote進程是Android手機系統啟動後,常駐的一個名為‘受精卵’的進程。

  • zygote的啟動實現指令碼在/init.rc檔案中
  • 啟動過程中執行的二進位檔案在/system/bin/app_process

任何應用程式啟動時,會從zygote進程fork出一個新的進程。並裝載一些必要的class,invoke一些初始化方法。這其中包括像:

  • ActivityThread
  • ServiceThread
  • ApplicationPackageManager

等應用啟動中必要的類,觸發必要的方法,比如:handleBindApplication,將此進程與對應的應用綁定的初始化方法;同時,會將zygote進程中的dalvik虛擬機器執行個體複製一份,因此每個應用程式進程都有自己的dalvik虛擬機器執行個體;會將已有Java運行時載入到進程中;會註冊一些android核心類的jni方法到虛擬機器中,支撐從c到java的啟動過程。

###Xposed做了手腳

Xposed在這個過程改寫了app_process(源碼在Xposed : a modified app_process binary),替換/system/bin/app_process這個二進位檔案。然後做了兩個事:

  1. 通過Xposed的hook技術,在上述過程中,對上面提到的那些載入的類的方法hook。
  2. 載入XposedBridge.jar

這時hook必要的方法是為了方便開發人員為它開發外掛程式,載入XposedBridge.jar是為動態hook提供了基礎。在這個時候載入它意味著,所有的程式在啟動時,都可以載入這個jar(因為上面提到的fork過程)。結合hook技術,從而達到了控制所有程式的所有方法。

為獲得/system/bin/目錄的讀寫權限,因而需要以root為前提。

###Xposed的hook思想

那麼Xposed是怎麼hook java方法的呢?要從XposedBridge看起,重點在 XposedBridge.hookmethod(原方法的Member對象,含有新方法的XC_MethodHook對象);,這裡會調到

private native synchronized static void hookMethodNative(Member method, Class<?> declaringClass, int slot, Object additionalInfo);

這個native的方法,通過這個方法,可以讓所hook的方法,轉向native層的一個c方法。如何做到?

When a transmit from java to native occurs, dvm sets up a native stack.In dvmCallJNIMethod(), dvmPlatformInvoke is used to call the native method(signature in Method.insns).

在jni這個中間世界裡,類型資料由jni表來溝通java和c的世界;方法由c++指標結合DVM*系(如dvmSlotToMethod,dvmDecodeIndirectRef等方法)的api方法,操作虛擬機器,從而實現java方法與c方法的世界。

那麼hook的過程是這樣:首先通過dexclassload來load所要hook的方法,分析類後,進c層,見代碼XposedBridge_hookMethodNative方法,拿到要hook的Method類,然後通過dvmslotTomethod方法擷取Method*指標,

Method* method = dvmSlotToMethod(declaredClass, slot);

declaredClass就是所hook方法所在的類,對應的jobject。slot是Method類中,描述此java對象在vm中的索引;那麼通過這個方法,我們就擷取了c層的Method指標,通過

SET_METHOD_FLAG(method, ACC_NATIVE);

將該方法標記為一個native方法,然後通過

method->nativeFunc = &hookedMethodCallback;

定向c層方法到hookedMethodCallback,這樣當被hook的java方法執行時,就會調到c層的hookedMethodCallback方法。

通過meth->nativeFunc重新導向MethodCallBridge到hookedMethodCallback這個方法上,控制這個c++指標是無視java的private的。

另外,在method結構體中有

method->insns = (const u2*) hookInfo;

用insns指向替換成為的方法,以便hookedMethodCallback可以擷取真正期望執行的java方法。

現在所有被hook的方法,都指向了hookedMethodCallbackc方法中,然後在此方法中實現調用替換成為的java方法。

###從Xposed提煉精髓

回顧Xposed,以root為必要條件,在app_process載入XposedBidge.jar,從而實現有hook所有應用的所有方法的能力;而後續動態hook應用內的方法,其實只是load了從zypote進程複製出來的運行時的這個XposedBidge.jar,然後hook而已。因此,若在一個應用範圍內的hook,root不是必須的,只是單純的載入hook的實現方法,即可修改本應用的方法。

業界內也不乏通過「修改BaseDexClassLoader中的pathList,來動態載入dex」方式實現熱修複。後者純java實現,但需要hack類的最佳化流程,將打CLASS_ISPREVERIFIED標籤的類,去除此標籤,以解決類與類引用不在一個dex中的異常問題。這會放棄dex optimize對啟動運行速度的最佳化。原則上,這對於方法數沒有大到需要multidex的應用,損失更明顯。而前者不觸犯原有的最佳化流程,只點殺需要hook的方法,更為純粹、有效。

安卓 熱修複的原理

聯繫我們

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