Xposed原理簡介及其精簡化
Xposed是一個很強大的Android平臺上的HOOK工具,而且作者為了方便開發者使用開發了一個APP(Xposed Installer,下文稱為Installer) 來使用開發者自己開發的模組。開發者安裝自己的模組後需要在Installer中勾選自己的模組然後重啟手機自己的模組才會起作用。但是這樣有點不利於開發者測試,每次都要點開Installer操作幾下尤其是還要重啟就顯得有點麻煩了。
讀過Xposed的原始碼後會發現僅通過更改XposedBridge.jar的原始碼就可以更簡便一些:
1. 不需重啟手機
2. 不需操作Installer這個App,且不用安裝hook模組,只需push到手機即可
首先需要下載原始碼,rovo89連結裡面有Xposed所有原始碼,我們只需要下載XposedBridge就好。原版的Xposed並不適用於三星手機,wanam改過的Xposed可以用,所以如果是三星手機的話就下載wanam的。
1. Xposed原理簡介
現在安裝Xposed比較方便,因為Xposed作者開發了一個Xposed Installer App,下載後按照提示傻瓜式安裝(前提是root手機)。其實它的安裝過程是這個樣子的:首先探測手機型號,然後按照手機版本下載不同的刷機包,最後把Xposed刷機包刷入手機重啟就好。刷機包下載 裡面有所有版本的刷機包。
刷機包解壓開啟裡面的問件構成是這個樣子的:
META-INF/ 裡面有檔案配置指令碼 flash-script.sh 配置各個檔案安裝位置。
system/bin/ 替換zygote程式等檔案
system/framework/XposedBridge.jar jar包位置
system/lib system/lib64 一些so檔案所在位置
xposed.prop xposed版本說明檔案
所以安裝Xposed的過程就上把上面這些檔案放到手機裡相同檔案路徑下。
通過檢視檔案安裝指令碼發現:
system/bin/下面的檔案替換了app_process等檔案,app_process就是zygote程式檔案。所以Xposed通過替換zygote程式實現了控制手機上所有app程式。因為所有app程式都是由Zygote fork出來的。
Xposed的基本原理是修改了ART/Davilk虛擬機器,將需要hook的函式註冊為Native層函式。當執行到這一函式是虛擬機器會優先執行Native層函式,然後再去執行Java層函式,這樣完成函式的hook。如下圖:
通過讀Xposed原始碼發現其啟動過程:
- 手機啟動時init程式會啟動zygote這個程式。由於zygote程式檔案app_process已被替換,所以啟動的時Xposed版的zygote程式。
- Xposed_zygote程式啟動後會初始化一些so檔案(system/lib system/lib64),然後進入XposedBridge.jar中的XposedBridge.main中初始化jar包完成對一些關鍵Android系統函式的hook。
- Hook則是利用修改過的虛擬機器將函式註冊為native函式。
- 然後再返回zygote中完成原本zygote需要做的工作。
這只是在巨集觀層面稍微介紹了下Xposed,要想詳細瞭解需要讀它的原始碼了。下面兩篇寫的挺好,要想深入理解的可以看看。
Android Hook框架Xposed原理與原始碼分析
深入理解Android之Xposed詳解
2. Xposed精簡化
上面稍微介紹了下它的原理,下面就介紹如何精簡化Xposed。下面只修改了XposedBridge.jar包中的XposedBridge.java這個檔案,修改完重新Build apk然後把apk重新命名為XposedBridge.jar然後替換刷機包中的jar包,刷入手機即可。
2.1 取消重啟手機
看下XposedBridge.jar的原始碼
程式碼檔案de.robv.android.xposed.XposedBridge.java
protected static void main(String[] args) {
// Initialize the Xposed framework and modules
try {
if (!hadInitErrors()) {
initXResources();
SELinuxHelper.initOnce();
SELinuxHelper.initForProcess(null);
runtime = getRuntime();
XPOSED_BRIDGE_VERSION = getXposedVersion();
if (isZygote) {
XposedInit.hookResources();
XposedInit.initForZygote();
}
//修改時需註釋下面這行程式碼
XposedInit.loadModules();//*********load hook 模組*******************
} else {
Log.e(TAG, "Not initializing Xposed because of previous errors");
}
} catch (Throwable t) {
Log.e(TAG, "Errors during Xposed initialization", t);
disableHooks = true;
}
// Call the original startup code
if (isZygote) { //****程式碼修改位置****
ZygoteInit.main(args);
} else {
RuntimeInit.main(args);
}
}
注意上面的XposedInit.loadModules()這個函式,這個函式的作用就是load hook模組到程式中。
因為zygote啟動時先跑到java層XposeBridge.main中,在main裡面有一步操作是將hook模組load進來,模組載入到zygote程式中,zygote fork所有的app程式裡面也有這個hook模組,所以這個模組可以hook任意app。(編寫hook模組的第一步就是判斷當前的程式名字,如果是要hook的程式就hook,不是則返回)。
所以修改模組後,要將模組重新load zygote裡面必須重啟zygote,要想zygote重啟就要重啟手機了。
所以修改的邏輯是不把模組load到zygote裡面,而是load到自己想要hook的程式裡面,這樣修改模組後只需重啟該程式即可。
在上面程式碼的程式碼修改位置新增如下程式碼,並將上面XposedInit.loadModules()註釋掉即可。
if (isZygote) {
XposedHelpers.findAndHookMethod("com.android.internal.os.ZygoteConnection", BOOTCLASSLOADER, "handleChildProc",
"com.android.internal.os.ZygoteConnection.Arguments",FileDescriptor[].class,FileDescriptor.class,
PrintStream.class,new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// TODO Auto-generated method stub
super.afterHookedMethod(param);
String processName = (String) XposedHelpers.getObjectField(param.args[0], "niceName");
String coperationAppName = "指定程式名稱如:com.android.settings";
if(processName != null){
if(processName.startsWith(coperationAppName)){
log("--------Begin Load Module-------");
XposedInit.loadModules()
}
}
}
});
ZygoteInit.main(args);
} else {
RuntimeInit.main(args);
}
2.2 取消操作Installer APP
通過讀Install App的原始碼發現其實勾選hook模組其實app就是把模組的apk位置寫到一個檔案裡,等load模組時會讀取這個檔案,從這個檔案中的apk路徑下把apk load到程式中。
看下loadmodules的原始碼
XposedInit.java
/**
* Try to load all modules defined in <code>BASE_DIR/conf/modules.list</code>
*/
/*package*/ static void loadModules() throws IOException {
final String filename = BASE_DIR + "conf/modules.list";
BaseService service = SELinuxHelper.getAppDataFileService();
if (!service.checkFileExists(filename)) {
Log.e(TAG, "Cannot load any modules because " + filename + " was not found");
return;
}
ClassLoader topClassLoader = XposedBridge.BOOTCLASSLOADER;
ClassLoader parent;
while ((parent = topClassLoader.getParent()) != null) {
topClassLoader = parent;
}
InputStream stream = service.getFileInputStream(filename);
BufferedReader apks = new BufferedReader(new InputStreamReader(stream));
String apk;
while ((apk = apks.readLine()) != null) {
loadModule(apk, topClassLoader);
}
apks.close();
}
apk配置檔案就是installer app檔案路徑下的conf/modules.list這個檔案data/data/de.robv.android.xposed.installer/conf/modules.list
或者data/user_de/0/de.robv.android.xposed.installer/conf/modules.list(不同手機版本位置不同)
所以我們改下,直接給他個確定的apk路徑及名稱。就定為/data/local/tmp/module.apk。
所以再把之前的程式碼改成如下的樣子就好了
if (isZygote) {
XposedHelpers.findAndHookMethod("com.android.internal.os.ZygoteConnection", BOOTCLASSLOADER, "handleChildProc",
"com.android.internal.os.ZygoteConnection.Arguments",FileDescriptor[].class,FileDescriptor.class,
PrintStream.class,new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// TODO Auto-generated method stub
super.afterHookedMethod(param);
String processName = (String) XposedHelpers.getObjectField(param.args[0], "niceName");
String coperationAppName = "指定程式名稱如:com.android.settings";
if(processName != null){
if(processName.startsWith(coperationAppName)){
log("--------Begin Load Module-------");
String path = "/data/local/tmp/module.apk";
//注意由loadModules換成了loadModule,記得改
XposedInit.loadModule(path, BOOTCLASSLOADER);
}
}
}
});
ZygoteInit.main(args);
} else {
RuntimeInit.main(args);
}
所以每次修改模組後直接修改名字為module.apk然後push到/data/local/tmp/下,然後重啟app就好。
相關文章
- 精準化測試原理簡介
- 從docker介紹及其簡介Docker
- metaq原理簡介
- HSF原理簡介
- Flutter原理簡介Flutter
- MySQL原理簡介—11.最佳化案例介紹MySql
- ECMAScript5.1及其新增API簡介API
- Varnish(一)簡介與原理
- ppium簡介及工作原理
- 以太坊簡介(2019 精校精注版)
- OceanBase簡介及其與MySQL的比較MySql
- Xposed原理分析
- MySQL原理簡介—9.MySQL索引原理MySql索引
- WebSocket原理及技術簡介Web
- Thanos工作原理及元件簡介元件
- 大資料框架原理簡介大資料框架
- Servlet簡介及其生命週期詳解Servlet
- 條形碼生成原理介紹及簡介
- iptables基礎原理和使用簡介
- Go之NSQ簡介,原理和使用Go
- 從提升樹到 XGBoost, 原理簡介
- 迅雷精簡版 for Mac!附精簡教程!Mac
- javascript模組化簡介JavaScript
- 01模組化簡介
- 強化學習-簡介強化學習
- JAVA集合框架中的常用集合及其特點、適用場景、實現原理簡介Java框架
- 塔式伺服器的簡單介紹及其優點伺服器
- 01 . Vue簡介,原理,環境安裝Vue
- el-form中rules的原理簡介ORM
- 將彩色圖轉化為灰度圖及其原理介紹
- Lucene底層原理和最佳化經驗分享(1)-Lucene簡介和索引原理索引
- JavaScript 2024新變化簡介JavaScript
- HTML 文字格式化簡介HTML
- Python 精靈模組簡介_python sprites module introducePython
- 刀鋒伺服器的簡單介紹及其優點伺服器
- 機架式伺服器的簡單介紹及其優點伺服器
- 01 . ELK Stack簡介原理及部署應用
- 簡介