当前位置: 首页 > news >正文

FART 自动化脱壳框架优化实战:Bug 修复与代码改进记录

版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/

open() 判断不严谨导致 dex 重复 dump

源码:https://github.com/CYRUS-STUDIO/FART/blob/master/fart10/art/runtime/art_method.cc

比如:

int dexfilefp = open(dex_path.c_str(), O_RDONLY);
if (dexfilefp > 0) {close(dexfilefp);
}

这个判断条件其实是不严谨的,导致 if 中 的 close(dexfilefp); 一直没有执行,dex 会重复 dump。

open() 的返回值语义是:

  • 成功时:返回一个非负整数(即 >= 0),它是打开的文件描述符。

  • 失败时:返回 -1

正确的判断方式应该是:

if (fp >= 0) {// 成功打开
} else {// 打开失败,打印错误信息LOG(ERROR) << "open dex file failed";
}

减少不必要的 I/O,提高 dump 成功率。

dump 目录创建失败(mkdir failed errno: 13)

FART 中通过 mkdir 函数在 sdcard 上创建 dump 文件存放目录,但是这样必须 app 拥有存储卡读写权限。不然 mkdir 会执行失败。

下面是一个 frida 脚本,调用系统 的 mkdir 函数创建目录

function mkdir(path) {const libc = Module.findExportByName(null, "mkdir");if (!libc) {console.error("[-] Cannot find mkdir symbol.");return;}const mkdirNative = new NativeFunction(libc, 'int', ['pointer', 'int']);const pathStr = Memory.allocUtf8String(path);const mode = 0o777; // 权限const result = mkdirNative(pathStr, mode);if (result === 0) {console.log("[+] mkdir success:", path);} else {const errnoLocation = Module.findExportByName(null, "__errno");if (errnoLocation) {const errnoPtr = new NativeFunction(errnoLocation, 'pointer', []);const errnoValue = Memory.readU32(errnoPtr());console.error("[-] mkdir failed errno:", errnoValue);} else {console.error("[-] mkdir failed");}}
}

调用 mkdir 创建目录 /sdcard/fart/com.cyrus.example

mkdir("/sdcard/fart/com.cyrus.example");

结果如下:

[Remote::com.cyrus.example]-> mkdir("/sdcard/fart/com.cyrus.example");
[-] mkdir failed errno: 13

[-] mkdir failed errno: 13 表示 Permission denied(权限被拒绝)。

常见的 errno 错误码:

errno 值含义
EEXIST目录已经存在
EACCES权限不足
ENOENT上级目录不存在
ENAMETOOLONG路径太长
ENOSPC没有磁盘空间或 inode

errno 定义参考:https://cs.android.com/android/platform/superproject/+/android15-qpr2-release:external/musl/arch/mips64/bits/errno.h;l=13?q=EACCES

解决方案:把 dump 路径改为:/data/data/<packageName>/fart

该目录无需动态申请存储权限,也不受 MANAGE_EXTERNAL_STORAGE 限制。

art_method.cc 中增加以下方法,创建目录并并打印日志

//add 创建目录
bool ensure_dir_exists(const std::string& path) {int res = mkdir(path.c_str(), 0777);if (res == 0 || errno == EEXIST) {return true;} else {LOG(ERROR) << "mkdir failed: " << path << ", errno=" << errno << ", " << errno;return false;}
}

修改 dumpDexFileByExecute 和 dumpArtMethod 方法中 dump 文件存放路径

// 创建目录:/data/data/<packageName>/fart
std::string base_dir = "/data/data/";
std::string app_dir = base_dir + szProcName;
std::string fart_dir = app_dir + "/fart";ensure_dir_exists(app_dir);
ensure_dir_exists(fart_dir);// 保存 dex 文件
std::string dex_path = fart_dir + "/" + std::to_string(size_int) + "_dex_file.dex";
// 保存 class 列表
std::string class_list_path = fart_dir + "/" + std::to_string(size_int) + "_class_list.txt";

dumpArtMethod 方法中 CodeItem 的保存路径也要修改

// 保存 CodeItem
std::string ins_path = fart_dir + "/" + std::to_string(size_int) + "_ins_" + std::to_string(tid) + ".bin";

修改完成后重新编译刷机。

word/media/image1.png

即使 app 没有存储卡读写权限也能正常 dump 了。

wayne:/data/data/com.cyrus.example/fart # ls
1321896_class_list.txt         1437648_dex_file_execute.dex   1488168_class_list_execute.txt 1605504_ins_4714.bin
1321896_class_list_execute.txt 1437648_ins_4714.bin           1488168_dex_file.dex           198768_class_list.txt
1321896_dex_file.dex           1448488_class_list.txt         1488168_dex_file_execute.dex   198768_class_list_execute.txt
1321896_dex_file_execute.dex   1448488_class_list_execute.txt 1488168_ins_4714.bin           198768_dex_file.dex
1321896_ins_4714.bin           1448488_dex_file.dex           1496608_class_list.txt         198768_dex_file_execute.dex
1351008_class_list.txt         1448488_dex_file_execute.dex   1496608_class_list_execute.txt 198768_ins_4714.bin
1351008_class_list_execute.txt 1448488_ins_4714.bin           1496608_dex_file.dex           3782924_class_list_execute.txt
1351008_dex_file.dex           1461504_class_list.txt         1496608_dex_file_execute.dex   3782924_dex_file_execute.dex
1351008_dex_file_execute.dex   1461504_class_list_execute.txt 1496608_ins_4714.bin           400440_class_list_execute.txt
1351008_ins_4714.bin           1461504_dex_file.dex           1537456_class_list.txt         400440_dex_file_execute.dex
1403328_class_list.txt         1461504_dex_file_execute.dex   1537456_class_list_execute.txt 4376620_class_list_execute.txt
1403328_class_list_execute.txt 1461504_ins_4714.bin           1537456_dex_file.dex           4376620_dex_file_execute.dex
1403328_dex_file.dex           1472352_class_list.txt         1537456_dex_file_execute.dex   590624_class_list.txt
1403328_dex_file_execute.dex   1472352_class_list_execute.txt 1537456_ins_4714.bin           590624_class_list_execute.txt
1403328_ins_4714.bin           1472352_dex_file.dex           1571616_class_list.txt         590624_dex_file.dex
1423432_class_list.txt         1472352_dex_file_execute.dex   1571616_class_list_execute.txt 590624_dex_file_execute.dex
1423432_class_list_execute.txt 1472352_ins_4714.bin           1571616_dex_file.dex           590624_ins_4714.bin
1423432_dex_file.dex           1481472_class_list.txt         1571616_dex_file_execute.dex   7387912_class_list_execute.txt
1423432_dex_file_execute.dex   1481472_class_list_execute.txt 1571616_ins_4714.bin           7387912_dex_file_execute.dex
1423432_ins_4714.bin           1481472_dex_file.dex           1605504_class_list.txt         8391596_class_list_execute.txt
1437648_class_list.txt         1481472_dex_file_execute.dex   1605504_class_list_execute.txt 8391596_dex_file_execute.dex
1437648_class_list_execute.txt 1481472_ins_4714.bin           1605504_dex_file.dex           9085048_class_list_execute.txt
1437648_dex_file.dex           1488168_class_list.txt         1605504_dex_file_execute.dex   9085048_dex_file_execute.dex

Android 编译构建阶段的 dump 调用干扰

在 Android 编译构建阶段的 dex2oatd 工具执行时 调用了 art_method.cc 中的方法,导致出现下面的日志

dex2oatd E 05-27 19:26:24  7330  7330 art_method.cc:151] mkdir failed: /sdcard/Android/data/out/soong/host/linux-x86/bin/dex2oatd, errno=2, 2
dex2oatd E 05-27 19:26:24  7330  7330 art_method.cc:151] mkdir failed: /sdcard/Android/data/out/soong/host/linux-x86/bin/dex2oatd/fart, errno=2, 2
dex2oatd E 05-27 19:26:24  7330  7330 art_method.cc:234] [dumpDexFileByExecute] /sdcard/Android/data/out/soong/host/linux-x86/bin/dex2oatd/fart/4376620_dex_file_execute.dex open failed, fp=-1
dex2oatd E 05-27 19:26:24  7330  7330 art_method.cc:151] mkdir failed: /sdcard/Android/data/out/soong/host/linux-x86/bin/dex2oatd, errno=2, 2
dex2oatd E 05-27 19:26:24  7330  7330 art_method.cc:151] mkdir failed: /sdcard/Android/data/out/soong/host/linux-x86/bin/dex2oatd/fart, errno=2, 2

在 dump 前加上判断是否运行在 Android 环境

//add 跳过 Android 编译构建阶段的 dex2oatd 工具执行时的调用
bool isValidAndroidApp(const char* procName) {// 排除 host 工具,例如 dex2oat、dex2oatd、aapt2 等return procName != nullptr &&strstr(procName, "/") == nullptr &&         // 不应该包含路径strstr(procName, "dex2oat") == nullptr &&   // 排除 dex2oat/dex2oatdstrstr(procName, "soong") == nullptr;       // 排除构建系统相关路径
}//add
extern "C" void dumpDexFileByExecute(ArtMethod* artmethod) REQUIRES_SHARED(Locks::mutator_lock_) {...if (szProcName[0] == '\0') {LOG(WARNING) << "[dumpDexFileByExecute] 获取进程名失败:" << artmethod->PrettyMethod();return;}if (!isValidAndroidApp(szProcName)) {LOG(WARNING) << "[dumpDexFileByExecute] 当前进程 " << szProcName << " 非法,跳过 dex dump";return;}...
}//add
extern "C" void dumpArtMethod(ArtMethod* artmethod) REQUIRES_SHARED(Locks::mutator_lock_) {...if (szProcName[0] == '\0') {LOG(WARNING) << "[dumpArtMethod] 获取进程名失败:" << artmethod->PrettyMethod();return;}if (!isValidAndroidApp(szProcName)) {LOG(WARNING) << "[dumpArtMethod] 当前进程 " << szProcName << " 非法,跳过 dex dump";return;}...
}

完整源码

开源地址:https://github.com/CYRUS-STUDIO/FART

相关文章:

  • 干掉抽取壳!FART 自动化脱壳框架与 Execute 脱壳点解析

  • FART 主动调用组件深度解析:破解 ART 下函数抽取壳的终极武器

  • 一步步带你移植 FART 到 Android 10,实现自动化脱壳


文章转载自:

http://AcjQveWv.jbctp.cn
http://ON2wixPV.jbctp.cn
http://IG3d7tlL.jbctp.cn
http://ZvpjbhgM.jbctp.cn
http://UVGoEQGe.jbctp.cn
http://KQZtTWyk.jbctp.cn
http://f59M0jCI.jbctp.cn
http://bmN0JiI8.jbctp.cn
http://mXQe5kek.jbctp.cn
http://38RJ9Ov7.jbctp.cn
http://chH1eTW0.jbctp.cn
http://JOfBGiZY.jbctp.cn
http://Iyp16eVk.jbctp.cn
http://bLLQIHJ4.jbctp.cn
http://hCupUshp.jbctp.cn
http://z3dt8zbA.jbctp.cn
http://fEzjIydt.jbctp.cn
http://5hVs8L8s.jbctp.cn
http://7OKcMNkB.jbctp.cn
http://YlRqzPLU.jbctp.cn
http://DpPeU54s.jbctp.cn
http://b1KYBv3r.jbctp.cn
http://Avaw8y0c.jbctp.cn
http://1n65uUSS.jbctp.cn
http://FwOUFeXn.jbctp.cn
http://lvNkPSvq.jbctp.cn
http://E7ZKs3fW.jbctp.cn
http://xU2xm4gw.jbctp.cn
http://yyYD8jXs.jbctp.cn
http://1lnCdGPJ.jbctp.cn
http://www.dtcms.com/a/364301.html

相关文章:

  • Linux使用-Linux系统管理
  • 物联网时序数据存储方案:Apache IoTDB 集群部署全流程 + TimechoDB 优势解读
  • Debezium系列之:Flink SQL消费Debezium数据,只消费新增数据,过滤掉更新、删除数据
  • 苍穹外卖项目笔记day03
  • 【ShiMetaPi M4-R1】上手:RK3568B2|开源鸿蒙(OpenHarmony) 应用开发快速上手
  • 开源检索增强生成(UltraRAG)框架
  • KafkaRocketMQ重平衡容灾机制
  • 腾讯开源混元多语言翻译模型—— Hunyuan-MT
  • 【算法--链表】142.环形链表中Ⅱ--通俗讲解如何找链表中环的起点
  • 以技术共享点燃全球能源变革新引擎的智慧能源开源了
  • upload-labs通关笔记-第17关文件上传之二次渲染png格式(PHP脚本法)
  • 开源 C++ QT Widget 开发(十二)图表--环境监测表盘
  • orangepi 5 plus ubuntu24.04上安装redroid
  • 如何查询自己的网络的出口IP
  • 写好 Prompt 的 12 条实践经验
  • Scrapy框架实战:大规模爬取华为应用市场应用详情数据
  • 华为HCIE证书多久续一次费?费用多少?
  • nano banana官方最强Prompt模板来了!六大场景模板详解
  • 如何将华为手机数据转移到OPPO手机
  • 《华为基本法》——企业文化的精髓,你学习了几条?
  • 车辆安全供电系统开发原则和实践
  • 利用 Java 爬虫获取淘宝商品详情 API 接口
  • 指针高级(1)
  • Meta-Learning入门:当AI学会“举一反三”——用MAML实现少样本图像分类 (Meta-Learning系列
  • Qt + windows + Linux+QtInstallerFramework打包教程
  • QNX pidin 命令中STATE 含义
  • vue2 + ts 实现透视卡片 + 瀑布上下移动效果
  • 计算机网络---CA证书体系(Certificate Authority)
  • FPGA离群值剔除算法
  • 【C++】在 Windows 系统调用第三方程序(创建进程)