而由应用程序开发者自己所编写的代码由dalvik.system.PathClassLoader加载器加载,打印出来的信息如下:
dalvik.system.PathClassLoader[DexPathList[[directory “.”],nativeLibraryDirectories=[/system/lib64, /vendor/lib64, /system/lib64, /vendor/lib64]]]
查看源码可以看到PathClassLoader是继承自BaseDexClassLoader的,而PathClassLoader还有另外两个兄弟: InMemoryDexClassLoader以及DexClassLoader,而壳程序很多都使用了这两个类加载器来加载解密后的dex文件。其中InMemoryDexClassLoader是Android8.0以后新增的类,可以实现所谓的"不落地加载"。
总结一下,主要有如下几个ClassLoader:
- BootClassLoader: 加载系统核心类的加载器,由系统创建
- BaseDexClassLoader: 加载dex文件的基类加载器
- PathClassLoader: 加载应用程序开发者自己编写的代码的加载器,比如四大组件类,它继承自BaseDexClassLoader
- DexClassLoader: 从源码中可以看到几乎和BaseDexClassLoader没有区别,它继承自BaseDexClassLoader,一般用于实现插件化和加壳
- InMemoryDexClassLoader: 通过ByteBuffer数组来加载dex的加载器,它继承自BaseDexClassLoader
- 自定义ClassLoader: 可以实现想实现的任何功能
前面说过壳加载完原始的dex以后还需要对ClassLoader进行修正,否则加载组件类运行的时候会报ClassNotFoundException,为什么会报这种错误呢? 这就涉及到了组件类的创建过程,比如对于Activity来说,应用程序的Activity对象是在ActivityThread类的performLaunchActivity()方法中通过调用mInstrumentation.newActivity()创建出来的,这个函数的实现逻辑为:
可以看到是通过ClassLoader先加载Activity类,再通过newInstance()来实现化类对象。
这个方法传递进来的ClassLoader是加载应用程序的ClassLoader,它所加载的dex为应用程序的主体的dex,对应的DexPathList是没有原始的dex路径的,因此会报ClassNotFoundException。这里也可以看出,一个BaseClassLoader对应着其实是一个Dex文件的列表,如果尝试让BaseClassLoader加载不在这个列表中的类,就会报ClassNotFoundException。
为了解决上面的问题,可以有两种解决方案:
- 替换系统组件类加载器为我们的
DexClassLoader,同时设置DexClassLoader的parent为系统组件类加载器 - 打包原有的双亲关系,在系统组件类加载器和
BootClassLoader的中间插入我们的DexClassLoader,即加载原始dex的DexClassLoader作为PathClassLoader的parent
第一种解决方案是将系统组件类替换,这样通过mInstrumentation.newActivity()试图加载类的时候,就能找到相应的类。
第二种解决方案将ClassLoader的继承关系修改为: BootClassLoader --> DexClassLoader --> PathClassLoader,由于双亲委派机制的存在,当PathClassLoader<

最低0.47元/天 解锁文章
2160

被折叠的 条评论
为什么被折叠?



