码迷,mamicode.com
首页 > 其他好文 > 详细

Xposed源码剖析——概述

时间:2015-08-18 21:33:11      阅读:315      评论:0      收藏:0      [点我收藏+]

标签:android   github   cydia   hook   xposed   

技术分享

XPosed是与Cydia其名的工具,它能够让Android设备在没有修改源码的情况下修改系统中的API运行结果。我们通常称之为:God Mode(上帝模式)。

之前享大家分享了Xposed的基础,Xposed的作用和最简单的用法。那么,它的原理和它的内部构造是如何构成的?下面,我们从Github上看看,rovo89大神是如何制作的。

rovo89的github地址:https://github.com/rovo89

在主页上我们看到了,xposed其实主要是由三个项目来组成的,如下图所示;
技术分享

三个分别是:

项目 说明
Xposed Xposed框架的native部分(主要是改性app_process二进制文件)
XposedInstaller Xposed框架的Android端本地管理,环境架构搭建,以及第三方module资源下载的工具。
XposedBridge Xposed向开发者提供的API与相应的工具类库

XposedInstaller的构成

Xposed项目使我们最常用的项目,当然,他也是构造Xposed的核心部分。(也许你会说,其实是xposed项目更重要,它主要是替换app_process,ok我们后面再说它)。

如下图所示,是我们在XPosedInstaller apk中见到的,安装xposed框架的界面。
技术分享

InstallerFragment我们能够在其中找到install方法,其中主要就是针对使用不同方式的将自定义的app_process文件替换掉系统的app_process文件。

    /**
     * xposed install
     * @return 安装成功返回true,否则false
     */
    private boolean install() {
        // 获取安装的方式,直接写入 or 使用 recovery进行安装
        final int installMode = getInstallMode();

        // 检查获取Root权限
        if (!startShell())
            return false;

        List<String> messages = new LinkedList<String>();
        boolean showAlert = true;
        try {
            messages.add(getString(R.string.sdcard_location, XposedApp.getInstance().getExternalFilesDir(null)));
            messages.add("");

            messages.add(getString(R.string.file_copying, "Xposed-Disabler-Recovery.zip"));

            // 把Xposed-Disabler-Recovery.zip文件 从asset copy到sdcard中
            if (AssetUtil.writeAssetToSdcardFile("Xposed-Disabler-Recovery.zip", 00644) == null) {
                messages.add("");
                messages.add(getString(R.string.file_extract_failed, "Xposed-Disabler-Recovery.zip"));
                return false;
            }

            // 将编译后的app_process二进制文件,从asset文件夹中,copy到/data/data/de.robv.android.xposed.installer/bin/app_process下
            File appProcessFile = AssetUtil.writeAssetToFile(APP_PROCESS_NAME, new File(XposedApp.BASE_DIR + "bin/app_process"), 00700);
            if (appProcessFile == null) {
                showAlert(getString(R.string.file_extract_failed, "app_process"));
                return false;
            }

            if (installMode == INSTALL_MODE_NORMAL) {
                // 普通安装模式
                // 重新挂载/system为rw模式
                messages.add(getString(R.string.file_mounting_writable, "/system"));
                if (mRootUtil.executeWithBusybox("mount -o remount,rw /system", messages) != 0) {
                    messages.add(getString(R.string.file_mount_writable_failed, "/system"));
                    messages.add(getString(R.string.file_trying_to_continue));
                }

                // 查看原有的app_process文件是否已经备份,如果没有备份,现将原有的app_process文件备份一下
                if (new File("/system/bin/app_process.orig").exists()) {
                    messages.add(getString(R.string.file_backup_already_exists, "/system/bin/app_process.orig"));
                } else {
                    if (mRootUtil.executeWithBusybox("cp -a /system/bin/app_process /system/bin/app_process.orig", messages) != 0) {
                        messages.add("");
                        messages.add(getString(R.string.file_backup_failed, "/system/bin/app_process"));
                        return false;
                    } else {
                        messages.add(getString(R.string.file_backup_successful, "/system/bin/app_process.orig"));
                    }

                    mRootUtil.executeWithBusybox("sync", messages);
                }

                // 将项目中的自定义app_process文件copy覆盖系统的app_process,修改权限
                messages.add(getString(R.string.file_copying, "app_process"));
                if (mRootUtil.executeWithBusybox("cp -a " + appProcessFile.getAbsolutePath() + " /system/bin/app_process", messages) != 0) {
                    messages.add("");
                    messages.add(getString(R.string.file_copy_failed, "app_process", "/system/bin"));
                    return false;
                }
                if (mRootUtil.executeWithBusybox("chmod 755 /system/bin/app_process", messages) != 0) {
                    messages.add("");
                    messages.add(getString(R.string.file_set_perms_failed, "/system/bin/app_process"));
                    return false;
                }
                if (mRootUtil.executeWithBusybox("chown root:shell /system/bin/app_process", messages) != 0) {
                    messages.add("");
                    messages.add(getString(R.string.file_set_owner_failed, "/system/bin/app_process"));
                    return false;
                }

            } else if (installMode == INSTALL_MODE_RECOVERY_AUTO) {
                // 自动进入Recovery
                if (!prepareAutoFlash(messages, "Xposed-Installer-Recovery.zip"))
                    return false;

            } else if (installMode == INSTALL_MODE_RECOVERY_MANUAL) {
                // 手动进入Recovery
                if (!prepareManualFlash(messages, "Xposed-Installer-Recovery.zip"))
                    return false;
            }

            File blocker = new File(XposedApp.BASE_DIR + "conf/disabled");
            if (blocker.exists()) {
                messages.add(getString(R.string.file_removing, blocker.getAbsolutePath()));
                if (mRootUtil.executeWithBusybox("rm " + blocker.getAbsolutePath(), messages) != 0) {
                    messages.add("");
                    messages.add(getString(R.string.file_remove_failed, blocker.getAbsolutePath()));
                    return false;
                }
            }

            // copy XposedBridge.jar
            messages.add(getString(R.string.file_copying, "XposedBridge.jar"));
            File jarFile = AssetUtil.writeAssetToFile("XposedBridge.jar", new File(JAR_PATH_NEWVERSION), 00644);
            if (jarFile == null) {
                messages.add("");
                messages.add(getString(R.string.file_extract_failed, "XposedBridge.jar"));
                return false;
            }

            mRootUtil.executeWithBusybox("sync", messages);

            showAlert = false;
            messages.add("");

            if (installMode == INSTALL_MODE_NORMAL) {
                offerReboot(messages);
            } else {
                offerRebootToRecovery(messages, "Xposed-Installer-Recovery.zip", installMode);
            }
            return true;

        } finally {
            // 删除busybox 工具库
            AssetUtil.removeBusybox();

            if (showAlert)
                showAlert(TextUtils.join("\n", messages).trim());
        }
    }

ok,我们看完了代码,发现所有的工作都是为了app_process文件的替换。那么,系统中这个app_process是做什么的?为什么我们需要替换?替换成什么样?替换后对于我们么来说有什么帮助呢?


Xposed原理

我们在android的源码中的init.rc文件可以看到

service zygote /system/bin/app_process -Xzygote /system/bin –zygote –start-system-server
socket zygote stream 666 
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd

app_process是andriod app的启动程序(具体形式是zygote fork()调用一个 app_process作为Android app的载体)

Xposed的实现方案

针对Hook的不同进程来说又可以分为全局Hook与单个应用程序进程Hook,我们知道在Android系统中,应用程序进程都是由Zygote进程孵化出来的,而Zygote进程是由Init进程启动的。

Zygote进程在启动时会创建一个Dalvik虚拟机实例,每当它孵化一个新的应用程序进程时,都会将这个Dalvik虚拟机实例复制到新的应用程序进程里面去,从而使得每一个应用程序进程都有一个独立的Dalvik虚拟机实例。所以如果选择对Zygote进程Hook,则能够达到针对系统上所有的应用程序进程Hook,即一个全局Hook。如下图所示:

技术分享

/*
* @author zhoushengtao(周圣韬)
* @since 2015年8月18 日 19:41:32
* @weixin stchou_zst
* @blog http://blog.csdn.net/yzzst
* @交流学习QQ群:341989536
* @私人QQ:445914891
/
技术分享

版权声明:转载请标注:http://blog.csdn.net/yzzst 。 本文为博主原创文章,未经博主允许不得转载。

Xposed源码剖析——概述

标签:android   github   cydia   hook   xposed   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!