void ClassLinker::LinkCode(ArtMethod* method, const OatFile::OatClass* oat_class,
uint32_t class_def_method_index) {
Runtime* const runtime = Runtime::Current();
if (runtime->IsAotCompiler()) {
// The following code only applies to a non-compiler runtime.
return;
}
// Method shouldn't have already been linked.
DCHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr);
if (oat_class != nullptr) {
// Every kind of method should at least get an invoke stub from the oat_method.
// non-abstract methods also get their code pointers.
const OatFile::OatMethod oat_method = oat_class->GetOatMethod(class_def_method_index);
oat_method.LinkMethod(method);
}
// Install entry point from interpreter.
bool enter_interpreter = NeedsInterpreter(method, method->GetEntryPointFromQuickCompiledCode());
if (enter_interpreter && !method->IsNative()) {
method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
} else {
method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
}
if (method->IsAbstract()) {
method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
return;
}
if (method->IsStatic() && !method->IsConstructor()) {
// For static methods excluding the class initializer, install the trampoline.
// It will be replaced by the proper entry point by ClassLinker::FixupStaticTrampolines
// after initializing class (see ClassLinker::InitializeClass method).
method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionStub());
} else if (enter_interpreter) {
if (!method->IsNative()) {
// Set entry point from compiled code if there's no code or in interpreter only mode.
method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
} else {
method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub());
}
}
if (method->IsNative()) {
// Unregistering restores the dlsym lookup stub.
method->UnregisterNative();
if (enter_interpreter) {
// We have a native method here without code. Then it should have either the generic JNI
// trampoline as entrypoint (non-static), or the resolution trampoline (static).
// TODO: this doesn't handle all the cases where trampolines may be installed.
const void* entry_point = method->GetEntryPointFromQuickCompiledCode();
DCHECK(IsQuickGenericJniStub(entry_point) || IsQuickResolutionStub(entry_point));
}
}
}
LinkCode函数对不同函数类型进行了不同的处理,进而完成对ArtMethod中相关变量的初始化工作,如针对native函数进行method->UnregisterNative(),针对以quick模式或interpreter模式执行的函数的不同的初始化工作。当然,ArtMethod类提供了一个函数:GetDexFile(),该函数也可以获取到当前ArtMethod对象所在的DexFile对象引用,在获得了当前DexFile对象引用后,也依然可以dump得到当前内存中的dex。
2.实现及实验验证
上面对ART环境下的类加载执行流程简单做了介绍,从而说明这几种通用dump方案的原理。实现部分就不在这里贴了,具体可以看上一篇文章《FART:ART环境下基于主动调用的自动化脱壳方案》,最终FART使用的是通过运行过程中ArtMethod来使用GetDexFile()函数从而获取到DexFile对象引用进而达成dex的dump。这里同时给出四种实现思路(具体的dump时机和方法上一节部分已经给出):
① 通过修改Android系统源代码,在这些dump点插入dump整体dex的代码
② 使用frida来hook这些函数,然后通过指针对这些对象中的变量进行访问,最终定位到内存中的dex的起始点并完成dump
③ 使用ida在过掉前期的反调试之后,对这些函数下断即可(过反调试是个繁琐的任务)
④ 使用xposed或者virtualxposed结合native层函数的hook技术实现
参考链接
https://bbs.pediy.com/thread-252630.htm FART:ART环境下基于主动调用的自动化脱壳方案
https://blog.csdn.net/zhu929033262/article/details/77477402 ART系统类和方法加载分析
https://www.jianshu.com/p/d0b0c1bfbcf6 ART:类的加载、链接和初始化