解析dex2oat的实现
Posted 小道安全
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解析dex2oat的实现相关的知识,希望对你有一定的参考价值。
简介
在android系统5.0及以上系统开始逐渐丢弃Dalvik虚拟机,由于ART虚拟机对内存分配和回收都做了算法优化,降低了内存碎片化程度,回收时间也得以缩短,所有android系统5.0及以上都在主推ART虚拟机。在ART虚拟机中ART则会将Dex通过dex2oat工具编译得到一个ELF文件,它是一个可执行的文件。所以下面我们就针对ART的dex2oat实现进行做分析。
dex2oat介绍
Dex2oat的全称是:dalvik excutable file to optimized art file,它是一个对 android系统下的dex文件,进行编译优化的程序。通过dex2oat的编译优化,可以大大的提高android系统的启动的速度和使用手机过程的的流畅度。
dex2oat在安卓手机环境下的存放位置为/system/bin/dex2oat
dex2oat在开源系统中的路径为\\art\\dex2oat\\dex2oat.cc。
为什么要使用dex2oat进行转换
在android系统中,Android 虚拟机可以识别到的是dex文件,App应用在使用过程中如果每次将dex文件加载进行内存,解释性执行字节码,效率就会变得非常低, 从而影响到用户在使用安卓手机的体验。通过利用dex2oat进行优化处理, 那么可以在android系统运行之前,利用合适的时机将dex文件字节码,提前转化为虚拟机上可以执行运行的机器码,后续直接从效率更高的机器码中运行,则运行阶段更加流畅,优化用户体验。
dex2oat代码
1.dex2oat类定义
class Dex2Oat {
public:
//创建函数,返回值为bool,
static bool Create(Dex2Oat** p_dex2oat,
const RuntimeOptions& runtime_options,
const CompilerOptions& compiler_options,
Compiler::Kind compiler_kind,
InstructionSet instruction_set,
InstructionSetFeatures instruction_set_features,
VerificationResults* verification_results,
DexFileToMethodInlinerMap* method_inliner_map,
size_t thread_count)
SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) {
//判断参数传递进来的释放为空
CHECK(verification_results != nullptr);
CHECK(method_inliner_map != nullptr);
//用智能指针方式进行去实例化dex2oat
std::unique_ptr<Dex2Oat> dex2oat(new Dex2Oat(&compiler_options,
compiler_kind,
instruction_set,
instruction_set_features,
verification_results,
method_inliner_map,
thread_count));
if (!dex2oat->CreateRuntime(runtime_options, instruction_set)) {
*p_dex2oat = nullptr;
return false;
}
*p_dex2oat = dex2oat.release();
return true;
}
//dex2oat的虚构函数,用于释放操作。
~Dex2Oat() {
delete runtime_;
LogCompletionTime();
}
void LogCompletionTime() {
LOG(INFO) << "dex2oat took " << PrettyDuration(NanoTime() - start_ns_)
<< " (threads: " << thread_count_ << ")";
}
//从文件上获取到类名称
std::set<std::string>* ReadImageClassesFromFile(const char* image_classes_filename) {
std::unique_ptr<std::ifstream> image_classes_file(new std::ifstream(image_classes_filename,
std::ifstream::in));
if (image_classes_file.get() == nullptr) {
LOG(ERROR) << "Failed to open image classes file " << image_classes_filename;
return nullptr;
}
std::unique_ptr<std::set<std::string>> result(ReadImageClasses(*image_classes_file));
image_classes_file->close();
return result.release();
}
//读取imageclasses
std::set<std::string>* ReadImageClasses(std::istream& image_classes_stream) {
std::unique_ptr<std::set<std::string>> image_classes(new std::set<std::string>);
while (image_classes_stream.good()) {
std::string dot;
std::getline(image_classes_stream, dot);
if (StartsWith(dot, "#") || dot.empty()) {
continue;
}
std::string descriptor(DotToDescriptor(dot.c_str()));
image_classes->insert(descriptor);
}
return image_classes.release();
}
// Reads the class names (java.lang.Object) and returns a set of descriptors (Ljava/lang/Object;)
//从zip文件(apk其实就是个zip文件)读取类名称,读取到返回一个描述
std::set<std::string>* ReadImageClassesFromZip(const char* zip_filename,
const char* image_classes_filename,
std::string* error_msg) {
//通过智能指针进行打开zip压缩包,也就是apk包
std::unique_ptr<ZipArchive> zip_archive(ZipArchive::Open(zip_filename, error_msg));
//判断打开是否失败
if (zip_archive.get() == nullptr) {
return nullptr;
}
//进行遍历zip包获取zip包里面的文件信息
std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(image_classes_filename, error_msg));
if (zip_entry.get() == nullptr) {
*error_msg = StringPrintf("Failed to find '%s' within '%s': %s", image_classes_filename,
zip_filename, error_msg->c_str());
return nullptr;
}
std::unique_ptr<MemMap> image_classes_file(zip_entry->ExtractToMemMap(zip_filename,
image_classes_filename,
error_msg));
if (image_classes_file.get() == nullptr) {
*error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", image_classes_filename,
zip_filename, error_msg->c_str());
return nullptr;
}
const std::string image_classes_string(reinterpret_cast<char*>(image_classes_file->Begin()),
image_classes_file->Size());
std::istringstream image_classes_stream(image_classes_string);
return ReadImageClasses(image_classes_stream);
}
bool PatchOatCode(const CompilerDriver* compiler_driver, File* oat_file,
const std::string& oat_location, std::string* error_msg) {
// We asked to include patch information but we are not making an image. We need to fix
// everything up manually.
std::unique_ptr<ElfFile> elf_file(ElfFile::Open(oat_file, PROT_READ|PROT_WRITE,
MAP_SHARED, error_msg));
if (elf_file.get() == NULL) {
LOG(ERROR) << error_msg;
return false;
}
{
ReaderMutexLock mu(Thread::Current(), *Locks::mutator_lock_);
return ElfPatcher::Patch(compiler_driver, elf_file.get(), oat_location, error_msg);
}
}
//创建一个oat文件,返回一个常量指针
const CompilerDriver* CreateOatFile(const std::string& boot_image_option,
const std::string& android_root,
bool is_host,
const std::vector<const DexFile*>& dex_files,
File* oat_file,
const std::string& oat_location,
const std::string& bitcode_filename,
bool image,
std::unique_ptr<std::set<std::string>>& image_classes,
bool dump_stats,
bool dump_passes,
TimingLogger& timings,
CumulativeLogger& compiler_phases_timings,
std::string profile_file,
SafeMap<std::string, std::string>* key_value_store) {
CHECK(key_value_store != nullptr);
// Handle and ClassLoader creation needs to come after Runtime::Create
jobject class_loader = nullptr;
//获取自身进程
Thread* self = Thread::Current();
//如果boot_image_option不为空的话,执行下面的代码
if (!boot_image_option.empty()) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
std::vector<const DexFile*> class_path_files(dex_files);
OpenClassPathFiles(runtime_->GetClassPathString(), class_path_files);
ScopedObjectAccess soa(self);
//循环遍历并类文件大小,并进行dex文件进行注册
for (size_t i = 0; i < class_path_files.size(); i++) {
class_linker->RegisterDexFile(*class_path_files[i]);
}
soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader);
ScopedLocalRef<jobject> class_loader_local(soa.Env(),
soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader));
class_loader = soa.Env()->NewGlobalRef(class_loader_local.get());
Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path_files);
}
std::unique_ptr<CompilerDriver> driver(new CompilerDriver(compiler_options_,
verification_results_,
method_inliner_map_,
compiler_kind_,
instruction_set_,
instruction_set_features_,
image,
image_classes.release(),
thread_count_,
dump_stats,
dump_passes,
&compiler_phases_timings,
profile_file));
driver->GetCompiler()->SetBitcodeFileName(*driver.get(), bitcode_filename);
driver->CompileAll(class_loader, dex_files, &timings);
TimingLogger::ScopedTiming t2("dex2oat OatWriter", &timings);
std::string image_file_location;
uint32_t image_file_location_oat_checksum = 0;
uintptr_t image_file_location_oat_data_begin = 0;
int32_t image_patch_delta = 0;
if (!driver->IsImage()) {
TimingLogger::ScopedTiming t3("Loading image checksum", &timings);
gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();
image_file_location_oat_checksum = image_space->GetImageHeader().GetOatChecksum();
image_file_location_oat_data_begin =
reinterpret_cast<uintptr_t>(image_space->GetImageHeader().GetOatDataBegin());
image_file_location = image_space->GetImageFilename();
image_patch_delta = image_space->GetImageHeader().GetPatchDelta();
}
if (!image_file_location.empty()) {
key_value_store->Put(OatHeader::kImageLocationKey, image_file_location);
}
//oat写入操作
OatWriter oat_writer(dex_files, image_file_location_oat_checksum,
image_file_location_oat_data_begin,
image_patch_delta,
driver.get(),
&timings,
key_value_store);
t2.NewTiming("Writing ELF");
if (!driver->WriteElf(android_root, is_host, dex_files, &oat_writer, oat_file)) {
LOG(ERROR) << "Failed to write ELF file " << oat_file->GetPath();
return nullptr;
}
// Flush result to disk. Patching code will re-open the file (mmap), so ensure that our view
// of the file already made it there and won't be re-ordered with writes from PatchOat or
// image patching.
oat_file->Flush();
if (!driver->IsImage() && driver->GetCompilerOptions().GetIncludePatchInformation()) {
t2.NewTiming("Patching ELF");
std::string error_msg;
if (!PatchOatCode(driver.get(), oat_file, oat_location, &error_msg)) {
LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath() << ": " << error_msg;
return nullptr;
}
}
return driver.release();
}
//创建一个映射文件,成功返回true,失败返回false
bool CreateImageFile(const std::string& image_filename,
uintptr_t image_base,
const std::string& oat_filename,
const std::string& oat_location,
const CompilerDriver& compiler)
LOCKS_EXCLUDED(Locks::mutator_lock_) {
uintptr_t oat_data_begin;
{
// ImageWriter is scoped so it can free memory before doing FixupElf
ImageWriter image_writer(compiler);
if (!image_writer.Write(image_filename, image_base, oat_filename, oat_location)) {
LOG(ERROR) << "Failed to create image file " << image_filename;
return false;
}
oat_data_begin = image_writer.GetOatDataBegin();
}
std::unique_ptr<File> oat_file(OS::OpenFileReadWrite(oat_filename.c_str()));
if (oat_file.get() == nullptr) {
PLOG(ERROR) << "Failed to open ELF file: " << oat_filename;
return false;
}
if (!ElfFixup::Fixup(oat_file.get(), oat_data_begin)) {
LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath();
return false;
}
return true;
}
private:
//定义一个显示的dex2oat构造函数
explicit Dex2Oat(const CompilerOptions* compiler_options,
Compiler::Kind compiler_kind,
InstructionSet instruction_set,
InstructionSetFeatures instruction_set_features,
VerificationResults* verification_results,
DexFileToMethodInlinerMap* method_inliner_map,
size_t thread_count)
: compiler_options_(compiler_options),
compiler_kind_(compiler_kind),
instruction_set_(instruction_set),
instruction_set_features_(instruction_set_features),
verification_results_(verification_results),
method_inliner_map_(method_inliner_map),
runtime_(nullptr),
thread_count_(thread_count),
start_ns_(NanoTime()) {
CHECK(compiler_options != nullptr);
CHECK(verification_results != nullptr);
CHECK(method_inliner_map != nullptr);
}
bool CreateRuntime(const RuntimeOptions& runtime_options, InstructionSet instruction_set)
SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) {
if (!Runtime::Create(runtime_options, false)) {
LOG(ERROR) << "Failed to create runtime";
return false;
}
Runtime* runtime = Runtime::Current();
runtime->SetInstructionSet(instruction_set)以上是关于解析dex2oat的实现的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向ART 脱壳 ( dex2oat 脱壳 | /art/dex2oat/dex2oat.cc#Dex2oat 函数源码 )
Android 逆向ART 脱壳 ( dex2oat 脱壳 | aosp 中搜索 dex2oat 源码 | dex2oat.cc#main 主函数源码 )
Android性能优化之Android 10+ dex2oat实践
Android 逆向ART 函数抽取加壳 ② ( 禁用 dex2oat 简介 | TurboDex 中禁用 dex2oat 参考示例 )