【Android 逆向】ART 脱壳 ( 修改 /art/runtime/dex_file.cc#OpenCommon 系统源码进行脱壳 )





一、要修改的源码 /art/runtime/dex_file.cc#OpenCommon



/art/runtime/dex_file.cc#OpenCommon 方法可以作为脱壳点 , 在该函数中可以获取 DEX 文件在内存中的 起始地址 和 文件大小 , 直接将该文件保存到本地 SD 卡即可 ;

脱壳的代码与 【Android 逆向】整体加固脱壳 ( 脱壳点简介 | 修改系统源码进行脱壳 ) 博客中的代码类似 ;


/art/runtime/dex_file.cc#OpenCommon 函数源码 :

std::unique_ptr<DexFile> DexFile::OpenCommon(const uint8_t* base,
                                             size_t size,
                                             const std::string& location,
                                             uint32_t location_checksum,
                                             const OatDexFile* oat_dex_file,
                                             bool verify,
                                             bool verify_checksum,
                                             std::string* error_msg,
                                             VerifyResult* verify_result) {
  if (verify_result != nullptr) {
    *verify_result = VerifyResult::kVerifyNotAttempted;
  }
  std::unique_ptr<DexFile> dex_file(new DexFile(base,
                                                size,
                                                location,
                                                location_checksum,
                                                oat_dex_file));
  if (dex_file == nullptr) {
    *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(),
                              error_msg->c_str());
    return nullptr;
  }
  if (!dex_file->Init(error_msg)) {
    dex_file.reset();
    return nullptr;
  }
  if (verify && !DexFileVerifier::Verify(dex_file.get(),
                                         dex_file->Begin(),
                                         dex_file->Size(),
                                         location.c_str(),
                                         verify_checksum,
                                         error_msg)) {
    if (verify_result != nullptr) {
      *verify_result = VerifyResult::kVerifyFailed;
    }
    return nullptr;
  }
  if (verify_result != nullptr) {
    *verify_result = VerifyResult::kVerifySucceeded;
  }
  return dex_file;
}

源码路径 : /art/runtime/dex_file.cc#OpenCommon





二、修改 /art/runtime/dex_file.cc#OpenCommon 函数源码进行脱壳



/art/runtime/dex_file.cc#OpenCommon 函数中 ,

const uint8_t* base 参数是 dex 文件在内存的首地址 ,

size_t size 参数是 dex 文件在内存中的大小 ;


修改源码后 , 重新编译系统 , 在新编译的系统中 , 运行要脱壳的应用 , 即可将应用脱壳后的 dex 文件 , 输出到 /sdcard/pid_dexCount_output.dex 路径中 ;


编译结束后 , 运行虚拟机 , 或者刷到 Pixel 手机中 , 即可运行该系统 ;


修改后的 /art/runtime/dex_file.cc#OpenCommon 函数源码 :

/* 记录当前 dex 文件索引 */
int dexCount = 0;

std::unique_ptr<DexFile> DexFile::OpenCommon(const uint8_t* base,
                                             size_t size,
                                             const std::string& location,
                                             uint32_t location_checksum,
                                             const OatDexFile* oat_dex_file,
                                             bool verify,
                                             bool verify_checksum,
                                             std::string* error_msg,
                                             VerifyResult* verify_result) {

  // ---------- ★ 下面是脱壳内容 ----------

  // 系统启动后 , 可能会生成很多 dex 文件 , 
  // DEX 文件保存路径
  char output[50]={0};
  
  // 获取当前进程 ID , 这是为了区分准备的 
  int pid = getpid();
  
  // 生成文件名称 , 由于单个 APK 可能有多个 DEX 文件 
  // 这里将每个 DEX 文件的 进程 ID 和 DEX 文件字节大小 
  // 放入 DEX 文件名中 , 加以识别
  sprintf(output, "/sdcard/%d_%d_output.dex", pid, dexCount);
  
  // dex 文件索引自增
  dexCount++;
  	
  // 以写的方式 , 打开文件 , 如果没有就创建该文件
  int fd = open(output, "wb+");
  
  // 文件打开成功 , 则 dump 内存数据到 /sdcard/output.dex 文件中
  if (fd > 0)
  {
  	// 将 base 地址的内存数据拷贝到 fd 文件中 , 拷贝 size 字节
  	write(fd, base, size);
  	// 关闭文件 
  	close(fd);
  }
  
  // ---------- ★ 上面是脱壳内容 ----------

  if (verify_result != nullptr) {
    *verify_result = VerifyResult::kVerifyNotAttempted;
  }
  std::unique_ptr<DexFile> dex_file(new DexFile(base,
                                                size,
                                                location,
                                                location_checksum,
                                                oat_dex_file));
  if (dex_file == nullptr) {
    *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(),
                              error_msg->c_str());
    return nullptr;
  }
  if (!dex_file->Init(error_msg)) {
    dex_file.reset();
    return nullptr;
  }
  if (verify && !DexFileVerifier::Verify(dex_file.get(),
                                         dex_file->Begin(),
                                         dex_file->Size(),
                                         location.c_str(),
                                         verify_checksum,
                                         error_msg)) {
    if (verify_result != nullptr) {
      *verify_result = VerifyResult::kVerifyFailed;
    }
    return nullptr;
  }
  if (verify_result != nullptr) {
    *verify_result = VerifyResult::kVerifySucceeded;
  }
  return dex_file;
}

源码路径 : /art/runtime/dex_file.cc#OpenCommon

<think>好的,我现在需要帮助用户解决Android编译过程中遇到的boot.art生成错误的问题。用户提到定位到boot.art文件生成错误,并且提到了dex_bootjars,可能和Franklin相关。首先,我得回忆一下Android构建系统中关于ART和boot.art的部分。 首先,boot.artAndroid运行时(ART)的启动映像文件,包含预加载的核心类,用于加快系统启动速度。生成这个文件的过程中,可能会涉及到dex2oat工具将Dex文件转换为OAT文件。如果这个步骤出错,通常可能的原因包括:依赖的Dex文件缺失或损坏、dex2oat工具本身有问题、内存不足、或者环境配置错误。 接下来,用户提到了dex_bootjars,这应该是构建系统中定义boot classpath的变量,指定了哪些JAR文件需要被包含在启动类路径中。如果这个变量配置不正确,可能导致dex_bootjars中的某些JAR文件无法找到或处理,进而导致生成boot.art失败。 可能还需要考虑Franklin,但我不确定这是指某个特定的工具、脚本,还是用户的环境名称。可能需要用户进一步澄清,但暂时假设是构建配置中的某个部分。 现在,我需要一步步分析可能的原因和解决方法: 1. **检查构建日志**:用户需要查看详细的错误信息,确定具体的失败原因。比如是否某个特定的JAR文件无法生成,或者dex2oat报错。 2. **验证dex_bootjars配置**:检查Android构建配置文件(如Makefile或bp文件)中的dex_bootjars变量,确保所有指定的JAR文件存在且路径正确。 3. **检查依赖关系**:确保所有依赖的模块已经正确编译,特别是boot类路径中的JAR文件是否成功生成。 4. **内存问题**:dex2oat在转换大型Dex文件时可能需要较多内存,尤其是在并行编译时。增加系统内存或减少并行编译任务数(如使用make -j4降低线程数)可能有效。 5. **清理和重新构建**:执行make clean或删除out目录,然后重新构建,避免旧的中间文件干扰。 6. **更新代码和工具链**:确保代码库是最新的,尤其是ART相关的部分,以及dex2oat工具是否更新。 7. **检查文件权限**:确保构建过程中有足够的权限访问相关文件和目录,特别是生成的中间文件。 另外,参考用户提供的引用内容,其中提到Android系统分析和优化工具,可能相关的工具如systrace、perfetto等,但这些更多用于运行时分析,可能不直接帮助编译问题。不过,构建日志分析工具可能有用。 可能还需要考虑dexpreopt相关的配置,因为boot.art的生成与dexpreopt优化有关。如果dexpreopt配置错误,可能导致生成失败。需要检查是否在构建配置中正确启用了dexpreopt,或者是否有冲突的选项。 用户的环境问题也不能忽视,比如磁盘空间不足、系统版本兼容性(如JDK版本是否符合要求)、Python版本等。这些都是常见导致构建失败的原因。 总结步骤: - 查看具体错误日志,定位到具体的失败命令或文件。 - 验证dex_bootjars的配置是否正确。 - 确保所有依赖的JAR文件存在且有效。 - 尝试清理后重新构建。 - 调整系统资源(内存、线程数)。 - 检查工具链和代码更新状态。</think>针对Android编译过程中出现的`boot.art`生成错误,以下是逐步排查和解决方案: --- ### **1. 查看详细构建日志** 首先定位具体错误信息,例如: ```bash make -j8 2>&1 | tee build.log # 保存完整日志 grep "boot.art" build.log # 筛选相关错误 ``` 常见错误可能包括: - **Dex文件缺失**:如`Failed to open dex file: out/target/common/obj/JAVA_LIBRARIES/core-oj_intermediates/classes.dex` - **dex2oat内存不足**:`dex2oat crashed due to out of memory` - **权限问题**:`Permission denied while writing to oat file` --- ### **2. 验证`dex_bootjars`配置** 检查`dex_bootjars`定义的JAR文件是否存在: - 文件位置:`Android.mk`或`Android.bp`中定义`dex_bootjars`的模块。 - 示例配置片段: ```makefile # 在设备特定的mk文件中 PRODUCT_BOOT_JARS := core-oj:core-libart:conscrypt:okhttp ``` 确保所有列出的JAR模块已正确编译,并在`out/target/common/obj/JAVA_LIBRARIES`下生成对应的`classes.dex`。 --- ### **3. 检查依赖的Dex文件** 确认`dex_bootjars`中每个模块的Dex文件已生成: ```bash ls out/target/common/obj/JAVA_LIBRARIES/*_intermediates/classes.dex ``` 若某个`classes.dex`缺失,需单独编译该模块: ```bash make <module_name> # 如make core-oj ``` --- ### **4. 清理并重新构建** 清理旧的构建产物: ```bash make clean # 或 rm -rf out/ make -j4 # 降低并行任务数以减少内存压力 ``` --- ### **5. 调整系统资源** - **增加内存**:关闭其他占用内存的进程,或增加交换空间: ```bash sudo fallocate -l 8G /swapfile sudo mkswap /swapfile && sudo swapon /swapfile ``` - **限制并行任务数**:使用`make -j2`或`-j1`减少并发。 --- ### **6. 检查dexpreopt配置** 若项目启用了**Dex预处理优化**(如GMS应用),需确保配置正确: - 文件位置:`device/<vendor>/<device>/device.mk` - 关键参数: ```makefile WITH_DEXPREOPT := true DEXPREOPT_GENERATE_DEBUG_IMAGES := false ``` --- ### **7. 更新代码和工具链** - 同步最新代码: ```bash repo sync -j4 ``` - 检查JDK版本: ```bash java -version # 要求OpenJDK 8或11 ``` --- ### **8. 文件权限和路径** 确保构建用户对目录有写权限: ```bash sudo chown -R user:user out/ # 替换为实际用户 ``` --- ### **典型错误解决示例** 若日志显示`dex2oat failed to compile classes.dex`: 1. 手动运行dex2oat: ```bash dex2oat --dex-file=classes.dex --oat-file=boot.oat ``` 2. 若报错`Java heap space`,调整dex2oat内存: ```bash export ANDROID_JAVA_HOME=/path/to/java8 export DEX2OAT_XMX=4G # 增加内存限制 ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值