原文出處——>[Xposed源碼剖析——app_process作用詳解](http://blog.csdn.net/yzzst/article/details/47829657)
承接上文[Xposed源碼剖析——概述](http://blog.csdn.net/yzzst/article/details/47659987)
上面我們分析Xposed項目的源碼,從XposedInstaller開始說明了Xposed安裝的原理與過程。我們知道,XposedInstaller主要的工作就是:
* 替換系統的app_process(當然,這個操作需要Root權限)
* 將xposed的api文件,XposedBridge.jar文件放置到私有目錄中
至于 為什么要替換app_process文件?
系統中的app_process文件有什么作用?
替換后的app_process為什么能夠幫助我們hook?
下面我們就開始看看,rovo89大神的xposed開源項目。從GitHub上面clone下來xposed項目,我們在目錄中看到其目錄結構,如下所示:

從目錄中,我們能夠清楚的了解到,其中xposed項目現在已經支持Dalvik虛擬機與art虛擬機的架構了。
#### **app_main.cpp 源碼閱讀與對比**
ok這里,我們先從app_process的源碼開始閱讀,打開app_main.cpp文件,估計大家和我一下,一時間也看不出來xposed針對源碼修改了一些什么。
那么,我們就直接拿源碼與xposed中的app_main.cpp進行對比。
源碼地址:/frameworks/base/cmds/app_process/app_main.cpp
[app_main](https://www.androidos.net.cn/android/5.0.1_r1/xref/frameworks/base/cmds/app_process/app_main.cpp)(Android 5.0版本)
發現了,rovo89針對了一下幾個地方進行了修改。
**1. atrace_set_tracing_enabled 進行了替換修改**

**2. onVmCreated 增加了Xposed的回調**

**3. main函數中,增加了 xposed 的 options 操作**

我們在xposed.cpp中,能夠看到其handleOptions的具體邏輯,其實就是處理一些xposed的特殊命令而已。
如下所示:
~~~
/** Handle special command line options. */
bool handleOptions(int argc, char* const argv[]) {
parseXposedProp();
if (argc == 2 && strcmp(argv[1], "--xposedversion") == 0) {
printf("Xposed version: %s\n", xposedVersion);
return true;
}
if (argc == 2 && strcmp(argv[1], "--xposedtestsafemode") == 0) {
printf("Testing Xposed safemode trigger\n");
if (detectSafemodeTrigger(shouldSkipSafemodeDelay())) {
printf("Safemode triggered\n");
} else {
printf("Safemode not triggered\n");
}
return true;
}
// From Lollipop coding, used to override the process name
argBlockStart = argv[0];
uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]);
uintptr_t end = reinterpret_cast<uintptr_t>(argv[argc - 1]);
end += strlen(argv[argc - 1]) + 1;
argBlockLength = end - start;
return false;
}
~~~
**4. main函數中,啟動的時候增加了啟動一些邏輯**
具體的, 我們可以看到。runtime.start那一段。做出了一個啟動。
~~~
isXposedLoaded = xposed::initialize(zygote, startSystemServer, className, argc, argv);
if (zygote) {
// 當xposed成功啟動的時候,start XPOSED_CLASS_DOTS_ZYGOTE這個類
runtime.start(isXposedLoaded ? XPOSED_CLASS_DOTS_ZYGOTE : "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;
// 當xposed成功啟動的時候,start XPOSED_CLASS_DOTS_ZYGOTE這個類
runtime.start(isXposedLoaded ? XPOSED_CLASS_DOTS_TOOLS : "com.android.internal.os.RuntimeInit",
application ? "application" : "tool");
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
return 10;
}
~~~
這里的我們看到,在main函數中啟動了邏輯,
~~~
runtime.start(isXposedLoaded ? XPOSED_CLASS_DOTS_ZYGOTE : "com.android.internal.os.ZygoteInit",
startSystemServer ? "start-system-server" : "");
~~~
其中,XPOSED_CLASS_DOTS_ZYGOTE 變量在,xposed.h頭文件中有定義,如下所示:
~~~
#define XPOSED_CLASS_DOTS_ZYGOTE "de.robv.android.xposed.XposedBridge"
~~~
發現,其實這個類就是我們之前向私有目錄防止的XposedBridge項目的包名。
而runtime.start這個包名有什么作用呢?我們在AndroidRuntime中找到start方法的具體邏輯
在源代碼中/frameworks/base/core/jni/AndroidRuntime.cpp中看到
~~~
/*
* Start the Android runtime. This involves starting the virtual machine
* and calling the "static void main(String[] args)" method in the class
* named by "className".
*
* Passes the main function two arguments, the class name and the specified
* options string.
*/
void AndroidRuntime::start(const char* className, const char* options)
~~~
系統源碼對start方法的定義,就是啟動對應類的 start void main入口函數。這里,就將三個項目的邏輯連接起來了。
**XposedBridge.java**
我們在XposedBridge.java代碼中,看到其main方法,如下所示:
~~~
/**
* Called when native methods and other things are initialized, but before preloading classes etc.
*/
protected static void main(String[] args) {
// Initialize the Xposed framework and modules
try {
SELinuxHelper.initOnce();
SELinuxHelper.initForProcess(null);
runtime = getRuntime();
if (initNative()) {
XPOSED_BRIDGE_VERSION = getXposedVersion();
if (isZygote) {
startsSystemServer = startsSystemServer();
// 為啟動一個新的 zygote做好 hook準備
initForZygote();
}
// 載入Xposed的一些modules
loadModules();
} else {
log("Errors during native Xposed initialization");
}
} catch (Throwable t) {
log("Errors during Xposed initialization");
log(t);
disableHooks = true;
}
// 調用系統原來的啟動方法
if (isZygote)
ZygoteInit.main(args);
else
RuntimeInit.main(args);
}
~~~
ok,那么,整個app_process的復制hook邏輯,到這里我們已經清楚了。邏輯如下圖所示。

那么,xposed具體怎么實現系統api邏輯的replace和inject我們下次在做分析。
- 前言
- Android系統的體系結構
- Dalvik VM 和 JVM 的比較
- Android 打包應用程序并安裝的過程
- Android ADB工具
- Android應用開發
- Android UI相關知識總結
- Android 中window 、view、 Activity的關系
- Android應用界面
- Android中的drawable和bitmap
- AndroidUI組件adapterView及其子類和Adapter的關系
- Android四大組件
- Android 數據存儲
- SharedPreference
- Android應用的資源
- 數組資源
- 使用Drawable資源
- Material Design
- Android 進程和線程
- 進程
- 線程
- Android Application類的介紹
- 意圖(Intent)
- Intent 和 Intent 過濾器(Google官網介紹)
- Android中關于任務棧的總結
- 任務和返回棧(官網譯文)
- 總結
- Android應用安全現狀與解決方案
- Android 安全開發
- HTTPS
- 安卓 代碼混淆與打包
- 動態注入技術(hook技術)
- 一、什么是hook技術
- 二、常用的Hook 工具
- Xposed源碼剖析——概述
- Xposed源碼剖析——app_process作用詳解
- Xposed源碼剖析——Xposed初始化
- Xposed源碼剖析——hook具體實現
- 無需Root也能Hook?——Depoxsed框架演示
- 三、HookAndroid應用
- 四、Hook原生應用程序
- 五、Hook 檢測/修復
- Android 應用的逆向與加固保護技術
- OpenCV在Android中的開發
- Android高級開發進階
- 高級UI
- UI繪制流程及原理
- Android新布局ConstraintLayout約束布局
- 關鍵幀動畫
- 幀動畫共享元素變換
- Android異步消息處理機制完全解析,帶你從源碼的角度徹底理解
- Android中為什么主線程不會因為Looper.loop()里的死循環卡死?
- 為什么 Android 要采用 Binder 作為 IPC 機制?
- JVM 中一個線程的 Java 棧和寄存器中分別放的是什么?
- Android源碼的Binder權限是如何控制?
- 如何詳解 Activity 的生命周期?
- 為什么Android的Handler采用管道而不使用Binder?
- ThreadLocal,你真的懂了嗎?
- Android屏幕刷新機制