美文网首页
插件化方式(hook)

插件化方式(hook)

作者: 爬行的蚂蚁2725 | 来源:发表于2019-02-20 14:39 被阅读0次

    主要原理:将插件的dex和宿主的dex融为一体
    这里涉及到连个classloader,DexClassLoader和PathClassLoader他们都继承了BaseDexClassLoader,
    DexClassLoader可以加载任何目录的dex,PathClassLoader只能加载系统安装的dex.
    dex在内存中的表现形式为Element,在BasedexClassLoader下有个成员变量pathList,
    PathList类中有个成员变量dexElements,是Element的集合。也就是所有的dex在内存中会被加载成Element集合,于是我们可以将插件中的dexElements 融合到系统的dexElents数组。

    public class HookUtil {
      public void injectPluginClass() {
            String cachePath = context.getCacheDir().getAbsolutePath();
            String apkPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/plugin.apk";
            DexClassLoader dexClassLoader = new DexClassLoader(apkPath, cachePath, cachePath, context.getClassLoader());
    
          //     第一步   找到    插件的Elements数组  dexPathlist  ----?dexElement
    
            try {
                Class myDexClazzLoader=Class.forName("dalvik.system.BaseDexClassLoader");
                Field  myPathListFiled=myDexClazzLoader.getDeclaredField("pathList");
                myPathListFiled.setAccessible(true);
                Object myPathListObject =myPathListFiled.get(dexClassLoader);
    
    
                Class  myPathClazz=myPathListObject.getClass();
                Field  myElementsField = myPathClazz.getDeclaredField("dexElements");
                myElementsField.setAccessible(true);
    //          自己插件的  dexElements[]
                Object myElements=myElementsField.get(myPathListObject);
    
                //     第二步   找到    系统的Elements数组    dexElements
                PathClassLoader pathClassLoader= (PathClassLoader) context.getClassLoader();
                Class baseDexClazzLoader = Class.forName("dalvik.system.BaseDexClassLoader");
                Field pathListFiled = baseDexClazzLoader.getDeclaredField("pathList");
                pathListFiled.setAccessible(true);
                Object pathListObject = pathListFiled.get(pathClassLoader);
    
                Class systemPathClazz = pathListObject.getClass();
                Field systemElementsField = systemPathClazz.getDeclaredField("dexElements");
                systemElementsField.setAccessible(true);
                //系统的  dexElements[]
                Object systemElements = systemElementsField.get(pathListObject);
                //     第三步  上面的dexElements  数组  合并成新的  dexElements     然后通过反射重新注入系统的Field (dexElements )变量中
    
    //       新的     Element[] 对象
    //            dalvik.system.Element
    
                int systemLength = Array.getLength(systemElements);
                int myLength = Array.getLength(myElements);
    //            找到 Element  的Class类型   数组    每一个成员的类型
                Class<?> sigleElementClazz = systemElements.getClass().getComponentType();
                int newSysteLength = myLength + systemLength;
                Object newElementsArray=Array.newInstance(sigleElementClazz, newSysteLength);
    //融合
                for (int i = 0; i < newSysteLength; i++) {
    //                先融合 插件的Elements
                    if (i < myLength) {
                        Array.set(newElementsArray, i, Array.get(myElements, i));
                    }else {
                        Array.set(newElementsArray,i,Array.get(systemElements,i-myLength));
                    }
                }
                Field  elementsField=pathListObject.getClass().getDeclaredField("dexElements");;
                elementsField.setAccessible(true);
    //            将新生成的EleMents数组对象重新放到系统中去
                elementsField.set( pathListObject,newElementsArray);
    
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }
    

    application中注册hook,并重写Resources 和AssetManager

    public class MyApplication extends Application {
        private static Context sContext;
        private static final String TAG = "xxx";
        private AssetManager assetManager;
        private Resources newResource;
        private Resources.Theme mTheme;
        @Override
        public void onCreate() {
            super.onCreate();
            HookUtil hookUtil = new HookUtil();
            hookUtil.hookStartActivity(this);
            hookUtil.hookHookMh(this);
            hookUtil.injectPluginClass();
    //        重构
            String apkPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/plugin.apk";
    
    
            try {
                assetManager = AssetManager.class.newInstance();
                Method addAssetPathMethod = assetManager.getClass().getDeclaredMethod("addAssetPath", String.class);
                addAssetPathMethod.setAccessible(true);
                addAssetPathMethod.invoke(assetManager, apkPath);
    //        手动实例化
                Method ensureStringBlocks = AssetManager.class.getDeclaredMethod("ensureStringBlocks");
                ensureStringBlocks.setAccessible(true);
                ensureStringBlocks.invoke(assetManager);
    //            插件的StringBloac被实例化了
                Resources supResource = getResources();
                newResource = new Resources(assetManager, supResource.getDisplayMetrics(), supResource.getConfiguration());
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    
        }
    
        public AssetManager getAssetManager() {
            return assetManager==null?super.getAssets():assetManager;
        }
    
        @Override
        public Resources getResources() {
            return newResource==null?super.getResources():newResource;
        }
        //    resource
    }
    

    在插件中创建baseActivity 获取新的AssetManager和Resources

    public class BaseActivity extends Activity{
    
        @Override
        public Resources getResources() {
            if (getApplication() != null && getApplication().getResources() != null) {
                return getApplication().getResources();
            }
            return super.getResources();
        }
    
        @Override
        public AssetManager getAssets() {
            if (getApplication() != null && getApplication().getAssets() != null) {
                return getApplication().getAssets();
            }
            return super.getAssets();
        }
    //    @Override
    //    public Resources.Theme getTheme() {
    //        if(getApplication() != null && getApplication().getTheme() != null){
    //            return getApplication().getTheme();
    //        }
    //        return super.getTheme();
    //    }
    }
    

    相关文章

      网友评论

          本文标题:插件化方式(hook)

          本文链接:https://www.haomeiwen.com/subject/ydkhyqtx.html