美文网首页
动态加载apk

动态加载apk

作者: carlwu_186 | 来源:发表于2022-06-09 17:05 被阅读0次

    插桩方式实现

    • 通过dexClassLoader将第三方的apk加载到ClassLoader中。
    • 打开第三方apk时,实际上打开的是父应用的可以空壳activity。先用packageManager加载apk,拿到LauncherActivity的全类名,通过前面的ClassLoader反射实例化apk中的LauncherActivity
    • 父app的空壳activity里面所有的生命周期方法都调用反射拿到的LauncherActivity对应的方法。把父app的空壳activity保存到第三方activity中备用(that)。
    • 由于反射实例化的LauncherActivity是没有上下文的,所以任何使用到了this的方法都要重写,用父app传进来的that代替this
    • 第三方app中会使用到自己的资源文件,所以父空壳activity还需要重写getResources方法,利用AssetManager加载apk得到Resources
    • 这种方法要求了父app的空壳activity在注册时,launchMode必须是standard
    • 第三方appk的activity不需要在自己的Manifest中注册。
    • Service的方式类似Activity。
    • 第三方apk中的动态广播类似Activity。

    插件的静态广播接收器必须转换为宿主的动态广播接收器

    • 插件apk里面的静态广播接收器可以在宿主app中以动态广播接收器的方式注册,核心是如何获取插件apk的Manifest中定义的BoradCastReceiver全类名以及对应的Intent-Filter。
    • 借鉴系统如何安装apk,实现静态广播的注册方式。
    • Android系统安装apk:1.把apk文件复制到data/app 目录下。2.开辟存放应用文件的数据 data/data/包名。3.将apk中的dex文件安装到data/dalvik-cache目录下。
    • 真正加载广播接收器,是发生在系统启动时。1.PackageManagerService的main方法被SystemService调用。2.main方法会去扫描data/app目录,拿到apk文件后new一个PackageParser,调用PackageParser.parsePackage(apkFile)方法得到实体PackageParser.Package,里面就包含了解析apk得到的所有四大组件信息。3.PackageParser.parsePackage(apkFile)实现原理:通过AssetManager.addAssetPath(apkPath)拿到AssetManager,然后作为参数拿到apk对应的Resources,可以从Resources获取到AndroidManifest.xml的xml信息。然后就是解析xml信息得到任何四大组件的内容。
    • 拿到了插件apk里面所谓的静态广播接收器的全类名和intent-filter后,就按照动态广播的方式在宿主app中注册一样intent-filter的动态广播接收器,通过反射的方式实例化插件的静态广播接收器,宿主把所有的广播转发给插件。

    Hook绕过AMS方式实现

    • 将插件apk的dexElements导入到系统ClassLoader中。
    • 使用DexClassLoader加载一个插件apk,拿到DexClassLoader。这时它的父类BaseDexClassLoader里面有一个 DexPathList pathList 里面有一个成员Element[] dexElements 就是用来存放dex资源的。
    • 同样,系统Context的ClassLoader是PathClassLoader,它也继承自BaseDexClassLoader,所以它也有pathList对象。把插件包的ClassLoader中的dexElements取出,放入到系统Context的ClassLoader中,之后系统就可以直接找到插件包中的class资源了。

    双亲委派机制

    • ClassLoader的双亲委派机制:ClassLoader的loadClass方法会优先查找parent:ClassLoader的loadClass方法,parent为空时就到BootstrapClassLoader中查找,如果还是没找到自己的pathList中找。
    • pathList查找的方式是:遍历里面的dexElements,从Element元素中取出dexFile,然后调用到native层找到Class。
    • 所以,dexElements这个数组里面加入插件的dexElements是有讲究的,如果把插件的dexElements插到前面,系统就会优先使用插件里面定义的类,后面的dexFile即使定义了也不会用到它。
    • 有两个Hook点:1. ActivityManager.startActivity,修改Intent的目标地址为宿主APP的一个空壳Activity,骗过AMS的检查。2. 给ActivityThread的sMainThreadHandler指定mCallback,当msg是startActivity类型时还原msg中Intent参数的目标地址为插件中的Activity地址。

    插件包中资源文件的加载问题

    • 参考动态换肤,需要重写插件activity的getResources、getAssets两个方法,还需要重写Application的getAssetManager、getResources两个方法。

    相关文章

      网友评论

          本文标题:动态加载apk

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