文章目录
一、ART 下的函数抽取恢复时机
二、禁用 dex2oat 机制源码分析
1、oat_file_assistant.cc#GenerateOatFileNoChecks 源码分析
2、oat_file_assistant.cc#Dex2Oat 源码分析
3、exec_utils.cc#Exec 源码分析
4、exec_utils.cc#ExecAndReturnCode 源码分析
一、ART 下的函数抽取恢复时机
ART 下的函数抽取恢复时机 :
恢复抽取函数早于 oat 文件编译 : 在 ART 虚拟机下 , 需要将 dex 文件编译生成为 oat 文件 , 将 dex 文件中的 函数指令 抽取出来 , 必须 在 生成 oat 文件之前 , 将从 抽取的函数指令恢复 ;
禁用 dex2oat 机制 : 如果 禁用 dex2oat 的编译过程 , 则 恢复 被抽取的 函数指令 , 不在受 该条件限制 , 不是必须在 dex2oat 之前恢复 , 可以稍晚一些再恢复函数指令 ;
如果选择第一种方案 , 在 dex2oat 之前进行恢复 , 这没有任何意义 , dex2oat 编译后 , 生成的 oat 文件是完整的 , 此时 可以 完整的将 oat 文件 dump 到 SD 卡中 , 基本等于没有加固 , 还是一个一代壳 ;
因此 , 大部分加固厂商 , 选择 禁用 dex2oat 机制 ; 这样处于安全考虑 , 牺牲了应用的运行效率 ;
二、禁用 dex2oat 机制源码分析
在之前的博客章节 【Android 逆向】ART 脱壳 ( DexClassLoader 脱壳 | oat_file_assistant.cc 中涉及的 oat 文件生成流程 ) 四、oat_file_assistant.cc#GenerateOatFileNoChecks 函数分析 中 , 分析到 , dex2oat 编译过程中 , 需要调用 /art/runtime/oat_file_assistant.cc#GenerateOatFileNoChecks 函数 ;
1、oat_file_assistant.cc#GenerateOatFileNoChecks 源码分析
在该函数中 , 调用 dex2oat 进行编译 ;
在 /art/runtime/oat_file_assistant.cc#GenerateOatFileNoChecks 函数 中的 核心跳转语句是 调用了 /art/runtime/oat_file_assistant.cc#Dex2Oat 函数 ;
oat_file_assistant.cc#GenerateOatFileNoChecks 函数源码 :
OatFileAssistant::ResultOfAttemptToUpdate OatFileAssistant::GenerateOatFileNoChecks( OatFileAssistant::OatFileInfo& info, CompilerFilter::Filter filter, std::string* error_msg) { CHECK(error_msg != nullptr); Runtime* runtime = Runtime::Current(); // 判断 Dex2Oat 当前是否可用 , 如果不可用 , 直接返回 if (!runtime->IsDex2OatEnabled()) { *error_msg = "Generation of oat file for dex location " + dex_location_ + " not attempted because dex2oat is disabled."; return kUpdateNotAttempted; } if (info.Filename() == nullptr) { *error_msg = "Generation of oat file for dex location " + dex_location_ + " not attempted because the oat file name could not be determined."; return kUpdateNotAttempted; } const std::string& oat_file_name = *info.Filename(); const std::string& vdex_file_name = GetVdexFilename(oat_file_name); // dex2oat忽略丢失的dex文件,不报告错误。 // 请在此处明确检查,以便正确检测错误。 // TODO:为什么dex2oat会这样做? struct stat dex_path_stat; if (TEMP_FAILURE_RETRY(stat(dex_location_.c_str(), &dex_path_stat)) != 0) { *error_msg = "Could not access dex location " + dex_location_ + ":" + strerror(errno); return kUpdateNotAttempted; } // 如果这是odex位置,我们需要创建odex文件布局 (../oat/isa/..) if (!info.IsOatLocation()) { if (!PrepareOdexDirectories(dex_location_, oat_file_name, isa_, error_msg)) { return kUpdateNotAttempted; } } // 设置oat和vdex文件的权限。 // 当组和其他人传播时,用户总是被读取和写入 // 原始dex文件的读取权限。 mode_t file_mode = S_IRUSR | S_IWUSR | (dex_path_stat.st_mode & S_IRGRP) | (dex_path_stat.st_mode & S_IROTH); std::unique_ptr<File> vdex_file(OS::CreateEmptyFile(vdex_file_name.c_str())); if (vdex_file.get() == nullptr) { *error_msg = "Generation of oat file " + oat_file_name + " not attempted because the vdex file " + vdex_file_name + " could not be opened."; return kUpdateNotAttempted; } if (fchmod(vdex_file->Fd(), file_mode) != 0) { *error_msg = "Generation of oat file " + oat_file_name + " not attempted because the vdex file " + vdex_file_name + " could not be made world readable."; return kUpdateNotAttempted; } std::unique_ptr<File> oat_file(OS::CreateEmptyFile(oat_file_name.c_str())); if (oat_file.get() == nullptr) { *error_msg = "Generation of oat file " + oat_file_name + " not attempted because the oat file could not be created."; return kUpdateNotAttempted; } if (fchmod(oat_file->Fd(), file_mode) != 0) { *error_msg = "Generation of oat file " + oat_file_name + " not attempted because the oat file could not be made world readable."; oat_file->Erase(); return kUpdateNotAttempted; } std::vector<std::string> args; args.push_back("--dex-file=" + dex_location_); args.push_back("--output-vdex-fd=" + std::to_string(vdex_file->Fd())); args.push_back("--oat-fd=" + std::to_string(oat_file->Fd())); args.push_back("--oat-location=" + oat_file_name); args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter)); // ★ 核心跳转 if (!Dex2Oat(args, error_msg)) { // 手动删除oat和vdex文件。这样可以确保没有垃圾 // 如果进程意外死亡,则剩余。 vdex_file->Erase(); unlink(vdex_file_name.c_str()); oat_file->Erase(); unlink(oat_file_name.c_str()); return kUpdateFailed; } if (vdex_file->FlushCloseOrErase() != 0) { *error_msg = "Unable to close vdex file " + vdex_file_name; unlink(vdex_file_name.c_str()); return kUpdateFailed; } if (oat_file->FlushCloseOrErase() != 0) { *error_msg = "Unable to close oat file " + oat_file_name; unlink(oat_file_name.c_str()); return kUpdateFailed; } // 标记 odex 件已更改,我们应该尝试重新加载。 info.Reset(); return kUpdateSucceeded; }
源码路径 : /art/runtime/oat_file_assistant.cc#GenerateOatFileNoChecks