原文出处——>[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项目,我们在目录中看到其目录结构,如下所示:
![](http://img.blog.csdn.net/20150821093045272)
从目录中,我们能够清楚的了解到,其中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 进行了替换修改**
![](http://img.blog.csdn.net/20150821093251404)
**2. onVmCreated 增加了Xposed的回调**
![](http://img.blog.csdn.net/20150821093405424)
**3. main函数中,增加了 xposed 的 options 操作**
![](http://img.blog.csdn.net/20150821093500309)
我们在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逻辑,到这里我们已经清楚了。逻辑如下图所示。
![](http://img.blog.csdn.net/20150821093617938)
那么,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屏幕刷新机制