版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/
ART 下类加载流程
1. 类加载的时机
1、隐式加载:
-
创建类的实例
-
访问类的静态变量,或者为静态变量赋值
-
调用类的静态方法
-
使用反射方式来强制创建某个类或接口对应的 java.lang.Class 对象
-
初始化某个类的子类
2、显示加载:
-
使用 loadClass() 加载
-
使用 forName() 加载
两者又有所不同。
2. 类加载的流程
loadClass 和 forName 也是有区别的;
loadClass 只完成了第一步,就是加载;
Class.forName 是完成了3步,加载、链接和初始化。
| 阶段 | 发生了什么 |
|---|---|
| 加载 | 字节码文件 -> Class 对象 |
| 验证 | 检查字节码合法性 |
| 准备 | 静态变量分配内存,默认值 |
| 解析 | 符号引用 → 真实引用 |
| 初始化 | 调用 <clinit> 函数,static 代码块执行,静态变量赋值 |
一个类从“加载” 到 “可以使用” 的完整生命周期:加载(Loading)→ 连接(Linking)→ 初始化(Initialization)。
加载(Loading)
↓
连接(Linking)
→ 验证(Verification)
→ 准备(Preparation)
→ 解析(Resolution)
↓
初始化(Initialization)
↓
使用(Use)
↓
卸载(Unload)
相关文章:Android 下的 ClassLoader 与 双亲委派机制
ClassLinker::LoadMethod
ClassLinker::LoadMethod 是 ART 中负责将 dex 文件中的方法信息解析并填充到 ArtMethod(Java 函数的 native 表示) 结构体中的关键函数,是抽取壳的实现基础。
从 ClassLoader.loadClass() 开始,逐步分析 ART 下类加载的完整流程。
ClassLoader 的 loadClass(String name, boolean resolve) 方法的核心实现,它正是 双亲委派机制(Parent Delegation Model) 的体现。
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// 1️⃣ 首先检查类是否已经加载过
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false); // 2️⃣ 向父类加载器请求加载
} else {
c = findBootstrapClassOrNull(name); // 3️⃣ 否则用 BootstrapClassLoader
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// 4️⃣ 父加载器找不到,当前类加载器自己尝试加载
c = findClass(name);
}
}
return c;
}
ClassLoader.loadClass → ClassLinker::LoadMethod 调用路径
ClassLoader.loadClass(name)
↓
BaseDexClassLoader.findClass(name)
↓
DexPathList.findClass(name)
↓
Element.findClass(name)
↓
DexFile.loadClassBinaryName(name)
↓
DexFile.defineClass(name)
↓
DexFile.defineClassNative(name)
↓
→ ClassLinker::DefineClass(Thread* self, const char* descriptor, size_t hash, Handle<mirror::ClassLoader> class_loader, const DexFile& dex_file, const dex::ClassDef& dex_class_def)
→ ClassLinker::LoadClass(Thread* self, const DexFile& dex_file, const dex::ClassDef& dex_class_def, Handle<mirror::Class> klass)
→ LoadField(field, klass, ...)
→ LoadMethod(dex_file, method, klass, art_method) ←🎯目标函数
ClassLinker::LoadMethod 真正进入到对类中 Java 函数对应的 ArtMethod 对象的初始化,ArtMethod 包含了当前指向内存中 CodeItem 的偏移
调用 SetCodeItemOffset 方法设置 ArtMethod 中 CodeItem 的偏移
如果拿到了 CodeItemOffset 我们是不是就可以通过打补丁的方式恢复被抽取的 CodeItem 了。
hook execve 函数,禁用 dex2oat
ART 下实现抽取壳的另一个难点:dex2oat 编译流程。
如果 dex2oat 对抽取的 dex 进行编译生成了



最低0.47元/天 解锁文章
448

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



