前言
在上一篇博客 【Android 逆向】ART 脱壳 ( dex2oat 脱壳 | aosp 中搜索 dex2oat 源码 | dex2oat.cc#main 主函数源码 ) 中 , 分析到 dex2oat 工具源码中的主函数为 /art/dex2oat/dex2oat.cc#main , 在该函数中调用了 /art/dex2oat/dex2oat.cc#Dex2oat 函数 ;
在将 dex 文件编译为 oat 文件的过程中 , 只要出现了 DexFile 对象 , 就可以将该对象对应的 dex 文件导出 , 即 dex 脱壳 , 该过程的脱壳点很多 ;
脱壳方法参考 【Android 逆向】ART 脱壳 ( 修改 /art/runtime/dex_file.cc#OpenCommon 系统源码进行脱壳 ) 博客 , 在脱壳点添加将内存中的 dex 文件 dump 到本地 SD 卡中的源码 , 然后在编译好的系统中运行要脱壳的应用 , 即可完成脱壳操作 ;
一、/art/dex2oat/dex2oat.cc#Dex2oat 函数源码
在 /art/dex2oat/dex2oat.cc#Dex2oat 函数中 , 调用了 /art/dex2oat/dex2oat.cc#Setup 函数 , 其中就遍历了 DexFile 对象 , 在遍历时可以将内存中的 dex 数据 dump 到 SD 卡中 ;
在调用的 /art/dex2oat/dex2oat.cc#CompileApp 函数中 , 也有脱壳点 ;
/art/dex2oat/dex2oat.cc#Dex2oat 函数源码 :
static dex2oat::ReturnCode Dex2oat(int argc, char** argv) {
b13564922();
TimingLogger timings("compiler", false, false);
std::unique_ptr<Dex2Oat> dex2oat = MakeUnique<Dex2Oat>(&timings);
dex2oat->ParseArgs(argc, argv);
if (dex2oat->UseProfile()) {
if (!dex2oat->LoadProfile()) {
LOG(ERROR) << "Failed to process profile file";
return dex2oat::ReturnCode::kOther;
}
}
art::MemMap::Init();
if (!dex2oat->OpenFile()) {
return dex2oat::ReturnCode::kOther;
}
if (kIsDebugBuild || dex2oat->IsBootImage() || dex2oat->IsHost() || !kIsTargetBuild) {
LOG(INFO) << CommandLine();
} else {
LOG(INFO) << StrippedCommandLine();
}
dex2oat::ReturnCode setup_code = dex2oat->Setup();
if (setup_code != dex2oat::ReturnCode::kNoFailure) {
dex2oat->EraseOutputFiles();
return setup_code;
}
VLOG(compiler) << "Running dex2oat (parent PID = " << getppid() << ")";
dex2oat::ReturnCode result;
if (dex2oat->IsImage()) {
result = CompileImage(*dex2oat);
} else {
result = CompileApp(*dex2oat);
}
dex2oat->Shutdown();
return result;
}
源码路径 : /art/dex2oat/dex2oat.cc#Dex2oat
二、/art/dex2oat/dex2oat.cc#Setup 函数源码 ( 脱壳点 )
在 /art/dex2oat/dex2oat.cc#Setup 函数的最后位置 , 逐个遍历 dex 文件 , 此时是可以拿到 dex_file 直接导出 dex 文件数据到 SD 卡中 , 此处可以进行脱壳 ;
只要出现了 DexFile 实例对象 , 就可以进行脱壳操作 ;
/art/dex2oat/dex2oat.cc#Setup 函数源码 :
for (const auto& dex_file : dex_files_) {
ScopedObjectAccess soa(self);
dex_caches_.push_back(soa.AddLocalReference<jobject>(
class_linker->RegisterDexFile(*dex_file,
soa.Decode<mirror::ClassLoader>(class_loader_).Ptr())));
if (dex_caches_.back() == nullptr) {
soa.Self()->AssertPendingException();
soa.Self()->ClearException();
PLOG(ERROR) << "Failed to register dex file.";
return dex2oat::ReturnCode::kOther;
}
verification_results_->AddDexFile(dex_file);
}
/art/dex2oat/dex2oat.cc#Setup 函数源码 :
dex2oat::ReturnCode Setup() {
TimingLogger::ScopedTiming t("dex2oat Setup", timings_);
if (!PrepareImageClasses() || !PrepareCompiledClasses() || !PrepareCompiledMethods()) {
return dex2oat::ReturnCode::kOther;
}
verification_results_.reset(new VerificationResults(compiler_options_.get()));
callbacks_.reset(new QuickCompilerCallbacks(
verification_results_.get(),
IsBootImage() ?
CompilerCallbacks::CallbackMode::kCompileBootImage :
CompilerCallbacks::CallbackMode::kCompileApp));
RuntimeArgumentMap runtime_options;
if (!PrepareRuntimeOptions(&runtime_options)) {
return dex2oat::ReturnCode::kOther;
}
CreateOatWriters();
if (!AddDexFileSources()) {
return dex2oat::ReturnCode::kOther;
}
if (IsBootImage() && image_filenames_.size() > 1) {
key_value_store_->Put(OatHeader::kBootClassPathKey,
gc::space::ImageSpace::GetMultiImageBootClassPath(dex_locations_,
oat_filenames_,
image_filenames_));
}
if (!IsBootImage()) {
if (!CreateRuntime(std::move(runtime_options))) {
return dex2oat::ReturnCode::kCreateRuntime;
}
if (CompilerFilter::DependsOnImageChecksum(compiler_options_->GetCompilerFilter())) {
TimingLogger::ScopedTiming t3("Loading image checksum", timings_);
std::vector<gc::space::ImageSpace*> image_spaces =
Runtime::Current()->GetHeap()->GetBootImageSpaces();
image_file_location_oat_checksum_ = image_spaces[0]->GetImageHeader().GetOatChecksum();
image_file_location_oat_data_begin_ =
reinterpret_cast<uintptr_t>(image_spaces[0]->GetImageHeader().GetOatDataBegin());
image_patch_delta_ = image_spaces[0]->GetImageHeader().GetPatchDelta();
std::vector<std::string> image_filenames;
for (const gc::space::ImageSpace* image_space : image_spaces) {
image_filenames.push_back(image_space->GetImageFilename());
}
std::string image_file_location = android::base::Join(image_filenames, ':');
if (!image_file_location.empty()) {
key_value_store_->Put(OatHeader::kImageLocationKey, image_file_location);
}
} else {
image_file_location_oat_checksum_ = 0u;
image_file_location_oat_data_begin_ = 0u;
image_patch_delta_ = 0;
}
std::vector<std::string> class_path_locations =
GetClassPathLocations(runtime_->GetClassPathString());
OpenClassPathFiles(class_path_locations,
&class_path_files_,
&opened_oat_files_,
runtime_->GetInstructionSet(),
classpath_dir_);
std::vector<const DexFile*> class_path_files = MakeNonOwningPointerVector(class_path_files_);
std::string encoded_class_path;
if (class_path_locations.size() == 1 &&
class_path_locations[0] == OatFile::kSpecialSharedLibrary) {
encoded_class_path = OatFile::kSpecialSharedLibrary;
} else {
encoded_class_path = OatFile::EncodeDexFileDependencies(class_path_files, classpath_dir_);
}
key_value_store_->Put(OatHeader::kClassPathKey, encoded_class_path);
}
{
TimingLogger::ScopedTiming t_dex("Writing and opening dex files", timings_);
rodata_.reserve(oat_writers_.size());
for (size_t i = 0, size = oat_writers_.size(); i != size; ++i) {
rodata_.push_back(elf_writers_[i]->StartRoData());
std::unique_ptr<MemMap> opened_dex_files_map;
std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
const bool verify = !DoDexLayoutOptimizations() && (input_vdex_file_ == nullptr);
if (!oat_writers_[i]->WriteAndOpenDexFiles(
kIsVdexEnabled ? vdex_files_[i].get() : oat_files_[i].get(),
rodata_.back(),
instruction_set_,
instruction_set_features_.get(),
key_value_store_.get(),
verify,
update_input_vdex_,
&opened_dex_files_map,
&opened_dex_files)) {
return dex2oat::ReturnCode::kOther;
}
dex_files_per_oat_file_.push_back(MakeNonOwningPointerVector(opened_dex_files));
if (opened_dex_files_map != nullptr) {
opened_dex_files_maps_.push_back(std::move(opened_dex_files_map));
for (std::unique_ptr<const DexFile>& dex_file : opened_dex_files) {
dex_file_oat_index_map_.emplace(dex_file.get(), i);
opened_dex_files_.push_back(std::move(dex_file));
}
} else {
DCHECK(opened_dex_files.empty());
}
}
}
dex_files_ = MakeNonOwningPointerVector(opened_dex_files_);
CHECK(driver_ == nullptr);
if (swap_fd_ != -1) {
if (!UseSwap(IsBootImage(), dex_files_)) {
close(swap_fd_);
swap_fd_ = -1;
VLOG(compiler) << "Decided to run without swap.";
} else {
LOG(INFO) << "Large app, accepted running with swap.";
}
}
if (!IsBootImage() && IsVeryLarge(dex_files_)) {
if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kExtract,
compiler_options_->GetCompilerFilter())) {
LOG(INFO) << "Very large app, downgrading to extract.";
compiler_options_->SetCompilerFilter(CompilerFilter::kExtract);
}
}
if (IsBootImage()) {
runtime_options.Set(RuntimeArgumentMap::BootClassPathDexList, &opened_dex_files_);
if (!CreateRuntime(std::move(runtime_options))) {
return dex2oat::ReturnCode::kOther;
}
}
Thread* self = Thread::Current();
WellKnownClasses::Init(self->GetJniEnv());
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
if (!IsBootImage()) {
constexpr bool kSaveDexInput = false;
if (kSaveDexInput) {
SaveDexInput();
}
ScopedObjectAccess soa(self);
std::vector<const DexFile*> class_path_files = MakeNonOwningPointerVector(class_path_files_);
class_path_files.insert(class_path_files.end(), dex_files_.begin(), dex_files_.end());
class_loader_ = class_linker->CreatePathClassLoader(self, class_path_files);
}
for (const std::unique_ptr<MemMap>& map : opened_dex_files_maps_) {
if (!map->Protect(PROT_READ | PROT_WRITE)) {
PLOG(ERROR) << "Failed to make .dex files writeable.";
return dex2oat::ReturnCode::kOther;
}
}
for (const auto& dex_file : dex_files_) {
ScopedObjectAccess soa(self);
dex_caches_.push_back(soa.AddLocalReference<jobject>(
class_linker->RegisterDexFile(*dex_file,
soa.Decode<mirror::ClassLoader>(class_loader_).Ptr())));
if (dex_caches_.back() == nullptr) {
soa.Self()->AssertPendingException();
soa.Self()->ClearException();
PLOG(ERROR) << "Failed to register dex file.";
return dex2oat::ReturnCode::kOther;
}
verification_results_->AddDexFile(dex_file);
}
return dex2oat::ReturnCode::kNoFailure;
}
源码路径 : /art/dex2oat/dex2oat.cc#Setup
|