我为Xpatch加把米
2019-12-06 18:46:36 Author: bbs.pediy.com(查看原文) 阅读量:296 收藏

    源码

           Github:  https://github.com/skyun1314/haha

         前几天突然看到一个牛逼的工具Xpatch。由于Android 9.0以上手机不好root,不能装xposed 。虽然有一个太极可以免root加载xposed模块,但是里面的模块是有限制的,必须的上传到太极官网,审核通过才能使用 xposed模块。所以 平时 调试app在高版本手机上 兼容性的时候很麻烦。虽然可以重打包测试。但是遇到几百兆的app的时候就特别无力了。Xpatch确实是一个不错的选择,但是他不是app,为了使用方便我把它改成了app,并针对手机特性 结合Xposed代码做了一些优化。

         效果图:

   优化点:

       1、需要加载Xposed模块的app可以选择开启那些模块,而不需要自身开启读取sd卡权限,因为咱们使用了 ContentProvider!

       2、为了加快速度不反编译smali代码,使用dexlib2库查找manifest中定义的 application 最终父类 所在的dex。 并查看当前application中有没有静态代码块,

          同时使用 baksmali d 参数 只反编译一个smali文件从而插入入口代码。最后使用 DexMerger 库 合并dex。速度大大提升

       3、使用AXmlConverter 库修改manifest 二进制文件

  关键代码

使用ContentProvider 保存模块开启状态

public synchronized void updateModulesList(Context showToast) {
        try {

            String[] strings = {MODULES_LIST_FILE, ENABLED_MODULES_LIST_FILE};

            for (int i = 0; i < strings.length; i++) {
                File file = new File(strings[i]);
                if (!file.getParentFile().exists()) {
                    file.getParentFile().mkdirs();
                }
            }

            Cursor query = showToast.getContentResolver().query(StudentsProvider.CONTENT_URIstudents, null, null, null, null);


            if (query != null && query.getCount() > 0) {
                showToast.getContentResolver().delete(StudentsProvider.CONTENT_URIstudents, "_id>0", null);
            }


            PrintWriter modulesList = new PrintWriter(MODULES_LIST_FILE);
            PrintWriter enabledModulesList = new PrintWriter(ENABLED_MODULES_LIST_FILE);

            List<InstalledModule> enabledModules = getEnabledModules();
            for (InstalledModule module : enabledModules) {


                modulesList.println(module.app.sourceDir);
                try {
                    String installer = mPm.getInstallerPackageName(module.app.packageName);
                    if (!PLAY_STORE_PACKAGE.equals(installer)) {
                        enabledModulesList.println(module.app.packageName);


                        ContentValues values = new ContentValues();

                        values.put(StudentsProvider.NAME,
                                module.app.packageName);

                        values.put(StudentsProvider.GRADE,
                                module.app.sourceDir);


                        Uri uri = showToast.getContentResolver().insert(
                                StudentsProvider.CONTENT_URIstudents, values);


                    }
                } catch (IllegalArgumentException ignored) {
                    // In rare cases, the package might not be installed anymore at this point,
                    // so the PackageManager can't return its installer package name.
                }
            }
            modulesList.close();
            enabledModulesList.close();

            FileUtils.setPermissions(MODULES_LIST_FILE, 00664, -1, -1);
            FileUtils.setPermissions(ENABLED_MODULES_LIST_FILE, 00664, -1, -1);


        } catch (IOException e) {
            hahahaha.Log.e(e.toString());
        }
    }

 使用dexlib2 解析 class和method

 public static List<String> getClass(String input) {
        List<String>strings=new ArrayList<>();
        try {

            File file = new File(input);

            MultiDexContainer<? extends DexBackedDexFile> container = DexFileFactory.loadDexContainer(file, null);


            MultiDexContainer.DexEntry<? extends DexBackedDexFile> dexEntry = container.getEntry(container.getDexEntryNames().get(0));
            assert dexEntry != null;
            DexBackedDexFile dexFile = dexEntry.getDexFile();

            for (ClassDef classDef : dexFile.getClasses()) {
                strings.add(classDef.getType());
              //  System.out.println(classDef.getType());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return strings;

    }



    public static List<String> getMethods(String input) {
        List<String>strings=new ArrayList<>();
        try {

            File file = new File(input);

            MultiDexContainer<? extends DexBackedDexFile> container = DexFileFactory.loadDexContainer(file, null);


            MultiDexContainer.DexEntry<? extends DexBackedDexFile> dexEntry = container.getEntry(container.getDexEntryNames().get(0));
            assert dexEntry != null;
            DexBackedDexFile dexFile = dexEntry.getDexFile();


            for (Reference reference: dexFile.getReferences( ReferenceType.METHOD)) {
            //    System.out.println(ReferenceUtil.getReferenceString(reference));

                strings.add(ReferenceUtil.getReferenceString(reference));
            }


        } catch (Exception e) {
            e.printStackTrace();
        }
        return strings;

    }

  使用axml  修改 manifest

  // 修改app名称
                    @Override
                    public NodeVisitor visitChild(String ns, String name) {// manifest 下面的说有大标签

                        if ("application".equals(name)) {


                            return new NodeVisitor(super.visitChild(ns, name)) {


                                @Override
                                public void visitEnd() {
                                    NodeVisitor meta = super.visitChild("http://schemas.android.com/apk/res/android", "meta-data");
                                    meta.visitContentAttr("http://schemas.android.com/apk/res/android", "name", 16842755, 3, meta_data_key);
                                    meta.visitContentAttr("http://schemas.android.com/apk/res/android", "value", 16842788, 3, meta_data_value);
                                    if (!has_Application) {
                                        super.visitContentAttr("http://schemas.android.com/apk/res/android", "name", 16842755, 3, Application_name);
                                    }
                                    super.visitEnd();
                                }


                                @Override
                                public void visitContentAttr(String ns, String name, int resourceId, int type,//application 这一行
                                                             Object obj) {


                                    if ("name".equals(name)) {
                                        yuan_Application=obj.toString();
                                        if(obj.toString().startsWith(".")){
                                            yuan_Application=yuan_packageName+yuan_Application;
                                        }

                                        has_Application = true;
                                        hahahaha.Log.e("visitContentAttr:" + name + "  " + obj + "   " + ns + "   " + resourceId + "  " + type);
                                    }
                                    super.visitContentAttr(ns, name, resourceId, type, obj);
                                }

                                @Override
                                public NodeVisitor visitChild(String ns, String name) {//application 下面所有大标签


                                    return new NodeVisitor(super.visitChild(ns, name)) {


                                        @Override
                                        public void visitContentAttr(String ns, String name, int resourceId, int type, Object obj) {
                                            //     System.out.println("aaaa_visitChild:"+ns+"  "+name+"  "+resourceId+"  "+type+"  "+obj);
                                            super.visitContentAttr(ns, name, resourceId, type, obj);
                                        }

                                        @Override
                                        public NodeVisitor visitChild(String ns, String name) {
                                            // System.out.println("xxxx_visitChild:"+ns+"  "+name);
                                            return super.visitChild(ns, name);
                                        }
                                    };
                                }
                            };


                        }
                        return super.visitChild(ns, name);
                    }
                };
            }
        });

[公告]安全测试和项目外包请将项目需求发到看雪企服平台:https://qifu.kanxue.com

最后于 5小时前 被skyun编辑 ,原因:


文章来源: https://bbs.pediy.com/thread-256256.htm
如有侵权请联系:admin#unsafe.sh