• Xposed原理简介及其精简化


    Xposed原理简介及其精简化

    Xposed是⼀个很强⼤的Android平台上的HOOK⼯具,⽽且作者为了⽅便开发者使⽤开发了⼀个APP(Xposed Installer,下⽂称为Installer)
    来使⽤开发者⾃⼰开发的模块。开发者安装⾃⼰的模块后需要在Installer中勾选⾃⼰的模块然后重启⼿机⾃⼰的模块才会起作⽤。但是这样有点不
    利于开发者测试,每次都要点开Installer操作⼏下尤其是还要重启就显得有点⿇烦了。
    读过Xposed的源码后会发现仅通过更改XposedBridge.jar的源码就可以更简便⼀些:

    1. 不需重启⼿机
    2. 不需操作Installer这个App,且不⽤安装hook模块,只需push到⼿机即可⾸先需要下载源码,rovo89链接⾥⾯有Xposed所有源码,我们只需要下载XposedBridge就好。
      原版的Xposed并不适⽤于三星⼿机,wanam改过的Xposed可以⽤,所以如果是三星⼿机的话就下载wanam的。

    1. Xposed原理简介

    现在安装Xposed⽐较⽅便,因为Xposed作者开发了⼀个Xposed Installer App,下载后按照提⽰傻⽠式安装(前提是root⼿机)。其实它的
    安装过程是这个样⼦的:⾸先探测⼿机型号,然后按照⼿机版本下载不同的刷机包,最后把Xposed刷机包刷⼊⼿机重启就好。刷机包下载 ⾥⾯
    有所有版本的刷机包。
    刷机包解压打开⾥⾯的问件构成是这个样⼦的:

    META-INF/    ⾥⾯有⽂件配置脚本 flash-script.sh 配置各个⽂件安装位置。
    system/bin/   替换zygote进程等⽂件
    system/framework/XposedBridge.jar jar包位置
    system/lib system/lib64 ⼀些so⽂件所在位置
    xposed.prop xposed版本说明⽂件
    

    所以安装Xposed的过程就上把上⾯这些⽂件放到⼿机⾥相同⽂件路径下。
    通过查看⽂件安装脚本发现:
    system/bin/下⾯的⽂件替换了app_process等⽂件,app_process就是zygote进程⽂件。所以Xposed通过替换zygote进程实现了控制⼿机
    上所有app进程。因为所有app进程都是由Zygote fork出来的。
    Xposed的基本原理是修改了ART/Davilk虚拟机,将需要hook的函数注册为Native层函数。当执⾏到这⼀函数是虚拟机会优先执⾏Native层函
    数,然后再去执⾏Java层函数,这样完成函数的hook。如下图:

    通过读Xposed源码发现其启动过程:

    1. ⼿机启动时init进程会启动zygote这个进程。由于zygote进程⽂件app_process已被替换,所以启动的时Xposed版的zygote进程。
    2. Xposed_zygote进程启动后会初始化⼀些so⽂件(system/lib system/lib64),然后进⼊XposedBridge.jar中的XposedBridge.main中
      初始化jar包完成对⼀些关键Android系统函数的hook。
    3. Hook则是利⽤修改过的虚拟机将函数注册为native函数。
    4. 然后再返回zygote中完成原本zygote需要做的⼯作。
      这只是在宏观层⾯稍微介绍了下Xposed,要想详细了解需要读它的源码了。下⾯两篇写的挺好,要想深⼊理解的可以看看。
      Android Hook框架Xposed原理与源代码分析
      深⼊理解Android之Xposed详解

    2. Xposed精简化

    上⾯稍微介绍了下它的原理,下⾯就介绍如何精简化Xposed。下⾯只修改了XposedBridge.jar包中的XposedBridge.java这个⽂件,修改完重
    新Build apk然后把apk重命名为XposedBridge.jar然后替换刷机包中的jar包,刷⼊⼿机即可。

    2.1 取消重启⼿机

    看下XposedBridge.jar的源码
    代码⽂件de.robv.android.xposed.XposedBridge.java

    protected static void main(String[] args) {
            // Initialize the Xposed framework and modules
            try {
                if (!hadInitErrors()) {
                    initXResources();
                    SELinuxHelper.initOnce();
                    SELinuxHelper.initForProcess(null);
                    runtime = getRuntime();
                    XPOSED_BRIDGE_VERSION = getXposedVersion();
                    if (isZygote) {
                        XposedInit.hookResources();
                        XposedInit.initForZygote();
                    }
                   //修改时需注释下⾯这⾏代码
                    XposedInit.loadModules();//*********load hook 模块*******************
                } else {
                    Log.e(TAG, "Not initializing Xposed because of previous errors");
                }
            } catch (Throwable t) {
                Log.e(TAG, "Errors during Xposed initialization", t);
                disableHooks = true;
            }
            // Call the original startup code
            if (isZygote) {  //****代码修改位置****           
                ZygoteInit.main(args);
            } else {
                RuntimeInit.main(args);
            }
        }
    
    

    注意上⾯的XposedInit.loadModules()这个函数,这个函数的作⽤就是load hook模块到进程中。
    因为zygote启动时先跑到java层XposeBridge.main中,在main⾥⾯有⼀步操作是将hook模块load进来,模块加载到zygote进程中,zygote
    fork所有的app进程⾥⾯也有这个hook模块,所以这个模块可以hook任意app。(编写hook模块的第⼀步就是判断当前的进程名字,如果是要
    hook的进程就hook,不是则返回)。所以修改模块后,要将模块重新load zygote所以修改的逻辑是不把模块load到zygote⾥⾯,
    ⽽是load到⾃⼰想要hook的进程⾥⾯,这样修改模块后只需重启该进程即可。
    在上⾯代码的代码修改位置添加如下代码,并将上⾯XposedInit.loadModules()注释掉即可。

    if (isZygote) {
                XposedHelpers.findAndHookMethod("com.android.internal.os.ZygoteConnection", BOOTCLASSLOADER, "handleChildProc",
                        "com.android.internal.os.ZygoteConnection.Arguments",FileDescriptor[].class,FileDescriptor.class,
                        PrintStream.class,new XC_MethodHook() {
                            @Override
                            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                                // TODO Auto-generated method stub
                                super.afterHookedMethod(param);
                                String processName = (String) XposedHelpers.getObjectField(param.args[0], "niceName");
                                String coperationAppName = "指定进程名称如:com.android.settings";
                                if(processName != null){
                                    if(processName.startsWith(coperationAppName)){
                                        log("--------Begin Load Module-------");
                                        XposedInit.loadModules()
                                    }
                                }
                            }
                        });
                ZygoteInit.main(args);
            } else {
                RuntimeInit.main(args);
            }
    

    2.2 取消操作Installer A

    通过读Install App的源码发现其实勾选hook模块其实app就是把模块的apk位置写到⼀个⽂件⾥,等load模块时会读取这个⽂件,从这个⽂件中
    的apk路径下把apk load到进程中,看下loadmodules的源码。

    XposedInit.java
    /**
         * Try to load all modules defined in <code>BASE_DIR/conf/modules.list</code>
         */
        /*package*/ static void loadModules() throws IOException {
            final String filename = BASE_DIR + "conf/modules.list";
            BaseService service = SELinuxHelper.getAppDataFileService();
            if (!service.checkFileExists(filename)) {
                Log.e(TAG, "Cannot load any modules because " + filename + " was not found");
                return;
            }
            ClassLoader topClassLoader = XposedBridge.BOOTCLASSLOADER;
            ClassLoader parent;
            while ((parent = topClassLoader.getParent()) != null) {
                topClassLoader = parent;
            }
            InputStream stream = service.getFileInputStream(filename);
            BufferedReader apks = new BufferedReader(new InputStreamReader(stream));
            String apk;
            while ((apk = apks.readLine()) != null) {
                loadModule(apk, topClassLoader);
            }
            apks.close();
        }
    
    

    apk配置⽂件就是installer app⽂件路径下的conf/modules.list这个⽂件data/data/de.robv.android.xposed.installer/conf/modules.list
    或者data/user_de/0/de.robv.android.xposed.installer/conf/modules.list(不同⼿机版本位置不同)
    所以我们改下,直接给他个确定的apk路径及名称。就定为/data/local/tmp/module.apk。
    所以再把之前的代码改成如下的样⼦就好了。

    if (isZygote) {
                XposedHelpers.findAndHookMethod("com.android.internal.os.ZygoteConnection", BOOTCLASSLOADER, "handleChildProc",
                        "com.android.internal.os.ZygoteConnection.Arguments",FileDescriptor[].class,FileDescriptor.class,
                        PrintStream.class,new XC_MethodHook() {
                            @Override
                            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                                // TODO Auto-generated method stub
                                super.afterHookedMethod(param);
                                String processName = (String) XposedHelpers.getObjectField(param.args[0], "niceName");
                                String coperationAppName = "指定进程名称如:com.android.settings";
                                if(processName != null){
                                    if(processName.startsWith(coperationAppName)){
                                        log("--------Begin Load Module-------");
                                        String path = "/data/local/tmp/module.apk";
                                        //注意由loadModules换成了loadModule,记得改
                                        XposedInit.loadModule(path, BOOTCLASSLOADER);
                                    }
                                }
                            }
                        });
                ZygoteInit.main(args);
            } else {
                RuntimeInit.main(args);
            }
    

    每次修改模块后直接修改名字为module.apk然后push到/data/local/tmp/下,然后重启app就好

  • 相关阅读:
    Python进阶2.3 with的使用
    thinkswoole 跨域
    调用windows服务来监视文件夹状态
    IIS 文件名、目录名或卷标语法不正确解决方法一例
    jqgrid 动态列生成
    Oracle 术语解释 只有一部分
    招聘.NET高级软件工程师
    Zabbix监控集群操作用户“登录失败次数“和“失败日志记录“
    Gin框架组合(Zap、lumberjack、ini)使用手册
    逛书城有感
  • 原文地址:https://www.cnblogs.com/gqv2009/p/16270786.html
Copyright © 2020-2023  润新知