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

解决方案:把 dump 路径改为:/sdcard/Android/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 文件存放路径

复制代码
// 创建目录:/sdcard/Android/data/<packageName>/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 实现自动化脱壳

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

跳过 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;
        }

        ...
}

完整源码

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

相关文章:

相关推荐
千里马学框架3 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台3 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone3 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc3 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo3 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077003 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼3 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone3 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen3 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone3 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui