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()
试图加载类的时候