文章目录
前言
一、/art/dex2oat/dex2oat.cc#Dex2oat 函数源码
二、/art/dex2oat/dex2oat.cc#Setup 函数源码 ( 脱壳点 )
前言
在上一篇博客 【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); // 在堆上而不是堆栈上分配'dex2oat',如Clang // 可能产生的堆栈帧对于此函数或 // 将其内联的函数(如main),这些函数不适合 // “-Wframe大于”选项的要求。 std::unique_ptr<Dex2Oat> dex2oat = MakeUnique<Dex2Oat>(&timings); // 解析参数。参数错误将导致UsageError中的exit(exit_失败)。 dex2oat->ParseArgs(argc, argv); // 如果需要,处理概要文件信息以进行概要文件引导编译。 // 此操作涉及I/O。 if (dex2oat->UseProfile()) { if (!dex2oat->LoadProfile()) { LOG(ERROR) << "Failed to process profile file"; return dex2oat::ReturnCode::kOther; } } art::MemMap::Init(); // For ZipEntry::ExtractToMemMap, and vdex. // 尽早检查编译结果是否可以写入 if (!dex2oat->OpenFile()) { return dex2oat::ReturnCode::kOther; } // 当以下任一项为真时,打印整行: // 1)调试生成 // 2)编译图像 // 3)使用--host编译 // 4)在主机上编译(不是目标版本) // 否则,打印剥离的命令行。 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; } // 帮助在设备上调试。可用于确定哪个dalvikvm实例调用了dex2oat // 例如。由工具/对分搜索/对分搜索使用。皮耶。 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 函数源码 :
// 确保dex缓存保持活动状态,因为我们不希望在编译期间发生类卸载。 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; } // 预注册dex文件,以便在编译和验证期间无需锁定即可访问验证结果。 verification_results_->AddDexFile(dex_file); }