FART 自动化脱壳框架一些 bug 修复记录

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

open() 判断不严谨

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); 一直没有执行。

open() 的返回值语义是:

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

  • 失败时:返回 -1

正确的判断方式应该是:

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

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 定义参考: 解决方案:把 dump 路径改为:/sdcard/Android/data/\/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 文件存放路径 // 创建目录:/sdcard/Android/data//fart std::string base_dir = "/sdcard/Android/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"; 修改完成后重新编译刷机。参考:[移植 FART 到 Android 10 实现自动化脱壳](https://cyrus-studio.github.io/blog/posts/%E7%A7%BB%E6%A4%8D-fart-%E5%88%B0-android-10-%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%8A%A8%E5%8C%96%E8%84%B1%E5%A3%B3/) 即使 app 没有存储卡读写权限也能正常 dump 了。 ![word/media/image1.png](https://i-blog.csdnimg.cn/img_convert/113f557eed207a94db4fd843b06a7503.png) ## 跳过 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/dex2oatd strstr(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; } ... } ## 完整源码 开源地址: 相关文章: * [FART 自动化脱壳框架简介与脱壳点的选择](https://cyrus-studio.github.io/blog/posts/fart-%E8%87%AA%E5%8A%A8%E5%8C%96%E8%84%B1%E5%A3%B3%E6%A1%86%E6%9E%B6%E7%AE%80%E4%BB%8B%E4%B8%8E%E8%84%B1%E5%A3%B3%E7%82%B9%E7%9A%84%E9%80%89%E6%8B%A9/) * [FART 主动调用组件设计和源码分析](https://cyrus-studio.github.io/blog/posts/fart-%E4%B8%BB%E5%8A%A8%E8%B0%83%E7%94%A8%E7%BB%84%E4%BB%B6%E8%AE%BE%E8%AE%A1%E5%92%8C%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/) * [移植 FART 到 Android 10 实现自动化脱壳](https://cyrus-studio.github.io/blog/posts/%E7%A7%BB%E6%A4%8D-fart-%E5%88%B0-android-10-%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%8A%A8%E5%8C%96%E8%84%B1%E5%A3%B3/)

相关推荐
inmK13 小时前
蓝奏云官方版不好用?蓝云最后一版实测:轻量化 + 不限速(避更新坑) 蓝云、蓝奏云第三方安卓版、蓝云最后一版、蓝奏云无广告管理工具、安卓网盘轻量化 APP
android·工具·网盘工具
giaoho3 小时前
Android 热点开发的相关api总结
android
咖啡の猫4 小时前
Android开发-常用布局
android·gitee
程序员老刘5 小时前
Google突然“变脸“,2026年要给全球开发者上“紧箍咒“?
android·flutter·客户端
Tans55 小时前
Androidx Lifecycle 源码阅读笔记
android·android jetpack·源码阅读
雨白5 小时前
实现双向滑动的 ScalableImageView(下)
android
峥嵘life5 小时前
Android Studio新版本编译release版本apk实现
android·ide·android studio
彭刷子6 小时前
【Bug】Nexus无法正常启动的五种解决方法
bug·nexus
studyForMokey8 小时前
【Android 消息机制】Handler
android
敲代码的鱼哇8 小时前
跳转原生系统设置插件 支持安卓/iOS/鸿蒙UTS组件
android·ios·harmonyos