ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
原文出处——>[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我们下次在做分析。