OatFile* OatFile::Open(const std::string& oat_filename,
const std::string& oat_location,
uint8_t* requested_base,
uint8_t* oat_file_begin,
bool executable,
bool low_4gb,
const char* abs_dex_location,
std::string* error_msg) {
ScopedTrace trace("Open oat file " + oat_location);
CHECK(!oat_filename.empty()) << oat_location;
CheckLocation(oat_location);
std::string vdex_filename = GetVdexFilename(oat_filename);//首先获得vdex的信息
// Check that the files even exist, fast-fail.
if (kIsVdexEnabled && !OS::FileExists(vdex_filename.c_str())) {
*error_msg = StringPrintf("File %s does not exist.", vdex_filename.c_str());
return nullptr;
} else if (!OS::FileExists(oat_filename.c_str())) {
*error_msg = StringPrintf("File %s does not exist.", oat_filename.c_str());
return nullptr;
}
// Try dlopen first, as it is required for native debuggability. This will fail fast if dlopen is
// disabled.
OatFile* with_dlopen = OatFileBase::OpenOatFile<DlOpenOatFile>(vdex_filename,
oat_filename,
oat_location,
requested_base,
oat_file_begin,
false /* writable */,
executable,
low_4gb,
abs_dex_location,
error_msg);//先试图通过OatFileBase::OpenOatFile<DlOpenOatFile>打开OatFile,我们知道art分为quick和portable两中优化模式,这里先假设他是portable尝试打开oat
if (with_dlopen != nullptr) {
return with_dlopen;
}
if (kPrintDlOpenErrorMessage) {
LOG(ERROR) << "Failed to dlopen: " << oat_filename << " with error " << *error_msg;
}
// If we aren't trying to execute, we just use our own ElfFile loader for a couple reasons:
//
// On target, dlopen may fail when compiling due to selinux restrictions on installd.
//
// We use our own ELF loader for Quick to deal with legacy apps that
// open a generated dex file by name, remove the file, then open
// another generated dex file with the same name. http://b/10614658
//
// On host, dlopen is expected to fail when cross compiling, so fall back to OpenElfFile.
//
//
// Another independent reason is the absolute placement of boot.oat. dlopen on the host usually
// does honor the virtual address encoded in the ELF file only for ET_EXEC files, not ET_DYN.
OatFile* with_internal = OatFileBase::OpenOatFile<ElfOatFile>(vdex_filename,
oat_filename,
oat_location,
requested_base,
oat_file_begin,
false /* writable */,
executable,
low_4gb,
abs_dex_location,
error_msg);//上面尝试不成功,就通过OatFileBase::OpenOatFile<ElfOatFile>打开oat,这就是quick模式了,和以前版本加载方式不大一样,以前是先判断quick还是portable模式在选择函数。
return with_internal;
}
OatFile* OatFile::OpenWritable(File* file,
const std::string& location,
const char* abs_dex_location,
std::string* error_msg) {
CheckLocation(location);
return ElfOatFile::OpenElfFile(file,
location,
nullptr,
nullptr,
true,
false,
/*low_4gb*/false,
abs_dex_location,
error_msg);
}
4.2后面
GetOatDexFile 通过key也就是dex_location在oat_dex_files_map里查询,从oat_file里找到oat_dex_file,这里的oat_dex_files_这个map是oat_file初始化时在setup函数中生成的,具体要看oat文件加载过程
const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location,
const uint32_t* dex_location_checksum,
std::string* error_msg) const {
// NOTE: We assume here that the canonical location for a given dex_location never
// changes. If it does (i.e. some symlink used by the filename changes) we may return
// an incorrect OatDexFile. As long as we have a checksum to check, we shall return
// an identical file or fail; otherwise we may see some unpredictable failures.
// TODO: Additional analysis of usage patterns to see if this can be simplified
// without any performance loss, for example by not doing the first lock-free lookup.
const OatFile::OatDexFile* oat_dex_file = nullptr;
StringPiece key(dex_location);
// Try to find the key cheaply in the oat_dex_files_ map which holds dex locations
// directly mentioned in the oat file and doesn't require locking.
auto primary_it = oat_dex_files_.find(key);//通过key也就是dex_location在oat_dex_files_ map里查询,从oat_file里找到oat_dex_file,这里的oat_dex_files_这个map是oat_file初始化时在setup函数中生成的,具体要看oat文件加载过程
// Add the location and canonical location (if different) to the oat_dex_files_ table.
// StringPiece key(oat_dex_file->GetDexFileLocation());
// oat_dex_files_.Put(key, oat_dex_file);
if (primary_it != oat_dex_files_.end()) {//下面几个if是判断其他特殊情况,处理异常的,比如dex_location不是唯一,dex_location没有找到如何加载和报错
oat_dex_file = primary_it->second;
DCHECK(oat_dex_file != nullptr);
} else {
// This dex_location is not one of the dex locations directly mentioned in the
// oat file. The correct lookup is via the canonical location but first see in
// the secondary_oat_dex_files_ whether we've looked up this location before.
MutexLock mu(Thread::Current(), secondary_lookup_lock_);
auto secondary_lb = secondary_oat_dex_files_.lower_bound(key);
if (secondary_lb != secondary_oat_dex_files_.end() && key == secondary_lb->first) {
oat_dex_file = secondary_lb->second; // May be null.
} else {
// We haven't seen this dex_location before, we must check the canonical location.
std::string dex_canonical_location = DexFile::GetDexCanonicalLocation(dex_location);//如果没有找到dex_location,这里会根据绝对路径重新加载dex
if (dex_canonical_location != dex_location) {
StringPiece canonical_key(dex_canonical_location);
auto canonical_it = oat_dex_files_.find(canonical_key);
if (canonical_it != oat_dex_files_.end()) {
oat_dex_file = canonical_it->second;
} // else keep null.
} // else keep null.
// Copy the key to the string_cache_ and store the result in secondary map.
string_cache_.emplace_back(key.data(), key.length());
StringPiece key_copy(string_cache_.back());
secondary_oat_dex_files_.PutBefore(secondary_lb, key_copy, oat_dex_file);//这里把根据绝对路径重新加载的dex信息放入secondary map,以便下次使用
}
}
if (oat_dex_file == nullptr) {
if (error_msg != nullptr) {
std::string dex_canonical_location = DexFile::GetDexCanonicalLocation(dex_location);
*error_msg = "Failed to find OatDexFile for DexFile " + std::string(dex_location)
+ " (canonical path " + dex_canonical_location + ") in OatFile " + GetLocation();
}
return nullptr;
}
if (dex_location_checksum != nullptr &&
oat_dex_file->GetDexFileLocationChecksum() != *dex_location_checksum) {
if (error_msg != nullptr) {
std::string dex_canonical_location = DexFile::GetDexCanonicalLocation(dex_location);
std::string checksum = StringPrintf("0x%08x", oat_dex_file->GetDexFileLocationChecksum());
std::string required_checksum = StringPrintf("0x%08x", *dex_location_checksum);
*error_msg = "OatDexFile for DexFile " + std::string(dex_location)
+ " (canonical path " + dex_canonical_location + ") in OatFile " + GetLocation()
+ " has checksum " + checksum + " but " + required_checksum + " was required";
}
return nullptr;
}
return oat_dex_file;
}
4.3通过GetOatDexFile
获得
oat_file
里的oat_dex_file后,就可以调用OpenDexFile获得
oat_dex_file 存储的 dex_file的信息了,这里就走到了dex_file.cc文件里的DexFile::Open这个关键函数,而这个
DexFile::Open
最终调用了OpenCommon这个关键函数,这里就是我们常用的一个脱壳函数,下一篇分析
DexFile::Open 下层的函数,就可以搞明白大佬们为什么hook
OpenCommon
和OpenAndReadMagic来脱整体的dex加固
std::unique_ptr<const DexFile> OatFile::OatDexFile::OpenDexFile(std::string* error_msg) const {
ScopedTrace trace(__PRETTY_FUNCTION__);
static constexpr bool kVerify = false;
static constexpr bool kVerifyChecksum = false;
return DexFile::Open(dex_file_pointer_,
FileSize(),
dex_file_location_,
dex_file_location_checksum_,
this,
kVerify,
kVerifyChecksum,
error_msg);
}
总结一下,时间仓促,有些注释可能有点错误,有些细节实现我也没仔细看,希望大家指出我的错误我好努力改进,在libre里画个及其丑陋的图辅助自己理解,箭头指向被调用的函数,双向箭头两个函数再同一个上层函数里先后调用,从opeDexFileNative最终调用到了OatFile::Open与DexFile::Open ,前者获得oat_file,,后者通过获得的oat_file得数据结构获得的
oat_dex_file的数据结构获得dex_file,下一篇菜鸟整理一下这2个函数是如何获得
oat_file与
oat_dex_file并加载到内存中的。