当前位置:   article > 正文

Xposed源码剖析——app_process作用详解

app_process

Xposed源码剖析——app_process作用详解

首先吐槽一下CSDN的改版吧,发表这篇文章之前其实我已经将此篇文章写过了两三次了。就是发表不成功。而且CSDN将我的文章草稿也一带>删除掉了。弄得我现在只有使用sublime写一次,保证它们删不掉。


承接上文 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

发现了,rovo89针对了一下几个地方进行了修改。

atrace_set_tracing_enabled 进行了替换修改 

onVmCreated 增加了Xposed的回调

main函数中,增加了 xposed 的 options 操作 
 
我们在xposed.cpp中,能够看到其handleOptions的具体逻辑,其实就是处理一些xposed的特殊命令而已。 
如下所示:

<code class="hljs cpp has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color:#8800;box-sizing: border-box;">/** Handle special command line options. */</span>
<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">bool</span> handleOptions(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">int</span> argc, <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">char</span>* <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">const</span> argv[]) {
    parseXposedProp();

    <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (argc == <span class="hljs-number" style="color:#06666;box-sizing: border-box;">2</span> && <span class="hljs-built_in" style="color:#66066;box-sizing: border-box;">strcmp</span>(argv[<span class="hljs-number" style="color:#06666;box-sizing: border-box;">1</span>], <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"--xposedversion"</span>) == <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>) {
        <span class="hljs-built_in" style="color:#66066;box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"Xposed version: %s\n"</span>, xposedVersion);
        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">true</span>;
    }

    <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (argc == <span class="hljs-number" style="color:#06666;box-sizing: border-box;">2</span> && <span class="hljs-built_in" style="color:#66066;box-sizing: border-box;">strcmp</span>(argv[<span class="hljs-number" style="color:#06666;box-sizing: border-box;">1</span>], <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"--xposedtestsafemode"</span>) == <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>) {
        <span class="hljs-built_in" style="color:#66066;box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"Testing Xposed safemode trigger\n"</span>);

        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (detectSafemodeTrigger(shouldSkipSafemodeDelay())) {
            <span class="hljs-built_in" style="color:#66066;box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"Safemode triggered\n"</span>);
        } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">else</span> {
            <span class="hljs-built_in" style="color:#66066;box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"Safemode not triggered\n"</span>);
        }
        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">true</span>;
    }

    <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// From Lollipop coding, used to override the process name</span>
    argBlockStart = argv[<span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>];
    uintptr_t start = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">reinterpret_cast</span><uintptr_t>(argv[<span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>]);
    uintptr_t end = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">reinterpret_cast</span><uintptr_t>(argv[argc - <span class="hljs-number" style="color:#06666;box-sizing: border-box;">1</span>]);
    end += <span class="hljs-built_in" style="color:#66066;box-sizing: border-box;">strlen</span>(argv[argc - <span class="hljs-number" style="color:#06666;box-sizing: border-box;">1</span>]) + <span class="hljs-number" style="color:#06666;box-sizing: border-box;">1</span>;
    argBlockLength = end - start;

    <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">false</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li></ul>

* main函数中,启动的时候增加了启动一些逻辑 * 

具体的, 我们可以看到。runtime.start那一段。做出了一个启动。

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">    isXposedLoaded = xposed::initialize(zygote, startSystemServer, className, argc, argv);
    <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (zygote) {
        <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 当xposed成功启动的时候,start XPOSED_CLASS_DOTS_ZYGOTE这个类</span>
        runtime.start(isXposedLoaded ? XPOSED_CLASS_DOTS_ZYGOTE : <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"com.android.internal.os.ZygoteInit"</span>,
                startSystemServer ? <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"start-system-server"</span> : <span class="hljs-string" style="color:#0880;box-sizing: border-box;">""</span>);
    } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (className) {
        <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// Remainder of args get passed to startup class main()</span>
        runtime.mClassName = className;
        runtime.mArgC = argc - i;
        runtime.mArgV = argv + i;
        <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 当xposed成功启动的时候,start XPOSED_CLASS_DOTS_ZYGOTE这个类</span>
        runtime.start(isXposedLoaded ? XPOSED_CLASS_DOTS_TOOLS : <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"com.android.internal.os.RuntimeInit"</span>,
                application ? <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"application"</span> : <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"tool"</span>);
    } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">else</span> {
        fprintf(stderr, <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"Error: no class name or --zygote supplied.\n"</span>);
        app_usage();
        LOG_ALWAYS_FATAL(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"app_process: no class name or --zygote supplied."</span>);
        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">10</span>;
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul>

这里的我们看到,在main函数中启动了逻辑,

<code class="hljs sql has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">runtime.<span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">start</span>(isXposedLoaded ? XPOSED_CLASS_DOTS_ZYGOTE : <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"com.android.internal.os.ZygoteInit"</span>,
                startSystemServer ? <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"start-system-server"</span> : <span class="hljs-string" style="color:#0880;box-sizing: border-box;">""</span>);</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>

其中,XPOSED_CLASS_DOTS_ZYGOTE 变量在,xposed.h头文件中有定义,如下所示:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-preprocessor" style="color:#444444;box-sizing: border-box;">#<span class="hljs-keyword" style="color:#444444;box-sizing: border-box;">define</span> XPOSED_CLASS_DOTS_ZYGOTE "de.robv.android.xposed.XposedBridge"</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

发现,其实这个类就是我们之前向私有目录防止的XposedBridge项目的包名。

而runtime.start这个包名有什么作用呢?我们在AndroidRuntime中找到start方法的具体逻辑 
在源代码中/frameworks/base/core/jni/AndroidRuntime.cpp中看到

<code class="hljs applescript has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">/*
 * Start <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">the</span> Android runtime.  This involves starting <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">the</span> virtual machine
 * <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">and</span> calling <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">the</span> <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"static void main(String[] args)"</span> method <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">in</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">the</span> <span class="hljs-type" style="box-sizing: border-box;">class</span>
 * named <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">by</span> <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"className"</span>.
 *
 * Passes <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">the</span> main function two arguments, <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">the</span> <span class="hljs-type" style="box-sizing: border-box;">class</span> <span class="hljs-property" style="box-sizing: border-box;">name</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">and</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">the</span> specified
 * options <span class="hljs-type" style="box-sizing: border-box;">string</span>.
 */
void AndroidRuntime::start(const char* className, const char* options)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>

系统源码对start方法的定义,就是启动对应类的 start void main入口函数。这里,就将三个项目的逻辑连接起来了。


XposedBridge.java

我们在XposedBridge.java代码中,看到其main方法,如下所示:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">    <span class="hljs-javadoc" style="color:#8800;box-sizing: border-box;">/**
     * Called when native methods and other things are initialized, but before preloading classes etc.
     */</span>
    <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">main</span>(String[] args) {
        <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// Initialize the Xposed framework and modules</span>
        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">try</span> {
            SELinuxHelper.initOnce();
            SELinuxHelper.initForProcess(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>);

            runtime = getRuntime();
            <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (initNative()) {
                XPOSED_BRIDGE_VERSION = getXposedVersion();
                <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (isZygote) {
                    startsSystemServer = startsSystemServer();
                    <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 为启动一个新的 zygote做好 hook准备</span>
                    initForZygote();
                }
                <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 载入Xposed的一些modules</span>
                loadModules();
            } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">else</span> {
                log(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"Errors during native Xposed initialization"</span>);
            }
        } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">catch</span> (Throwable t) {
            log(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"Errors during Xposed initialization"</span>);
            log(t);
            disableHooks = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">true</span>;
        }

        <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 调用系统原来的启动方法</span>
        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (isZygote)
            ZygoteInit.main(args);
        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">else</span>
            RuntimeInit.main(args);
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li></ul>

ok,那么,整个app_process的复制hook逻辑,到这里我们已经清楚了。逻辑如下图所示。

那么,xposed具体怎么实现系统api逻辑的replace和inject我们下次在做分析。


原文地址: http://blog.csdn.net/yzzst/article/details/47829657

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号