Android 12模拟器应用文件读写路径重定向(Frida反调试问题)
解决方案:Android模拟器应用路径重定向至共享文件夹
针对你的需求,以下是几种可行的实现方式,既能避开应用反调试机制,又能完成路径重定向:
一、系统级Bind Mount挂载(最稳定,无需Hook)
这个方法直接在Linux内核层面替换目录映射,完全绕开应用的反调试逻辑,是多模拟器共用文件场景的最优解。
操作步骤:
- 确保模拟器已获取Root权限:
- 原生Android模拟器可通过命令
emulator -avd <avd_name> -writable-system -selinux permissive启动,获取临时Root; - 第三方模拟器(如雷电、夜神)通常自带Root开关,直接开启即可。
- 原生Android模拟器可通过命令
- 准备共享目录:
- 在Windows共享文件夹中创建两个子目录,比如
app_data和app_files,分别对应应用的/data/data/<包名>和/storage/emulated/0/Android/data/<包名>路径; - 在模拟器中通过
df命令查看共享文件夹的挂载路径,通常为/mnt/shared或/mnt/sdcard/Windows/Shared。
- 在Windows共享文件夹中创建两个子目录,比如
- 迁移原有文件(可选):
如果应用已下载过文件,先将原目录内容复制到共享目录:cp -r /data/data/com.your.app/* /mnt/shared/app_data/com.your.app/ cp -r /storage/emulated/0/Android/data/com.your.app/* /mnt/shared/app_files/com.your.app/ - 执行Bind Mount:
- 先删除原应用目录(或重命名备份):
rm -rf /data/data/com.your.app rm -rf /storage/emulated/0/Android/data/com.your.app - 创建空目录并完成挂载:
mkdir -p /data/data/com.your.app mkdir -p /storage/emulated/0/Android/data/com.your.app mount --bind /mnt/shared/app_data/com.your.app /data/data/com.your.app mount --bind /mnt/shared/app_files/com.your.app /storage/emulated/0/Android/data/com.your.app
- 先删除原应用目录(或重命名备份):
- 处理SELinux限制(Android 12需注意):
Android 12的SELinux可能阻止挂载后的文件访问,可临时设置为宽容模式:
若要永久生效,可修改setenforce 0/etc/selinux/config文件,将SELINUX=enforcing改为SELINUX=permissive,重启模拟器即可。
二、绕过反调试后Hook目标应用进程
如果Bind Mount无法满足动态路径替换需求,可先绕过应用的反检测,再Hook应用自身进程的文件操作函数。
1. 绕过Frida反检测
- 使用
--no-pause参数启动Frida,避免进程启动时被暂停检测:frida -U --no-pause -f com.your.app -l redirect.js - 禁用应用的ptrace反调试检测,在脚本开头添加:
Interceptor.attach(Module.findExportByName(null, "ptrace"), { onEnter: function(args) { args[0] = ptr(0); // 阻止PT_TRACE_ME以外的ptrace调用 }, onLeave: function(retval) { retval.replace(ptr(0)); // 返回成功状态 } });
2. Hook文件操作函数(含自定义库)
直接Hook应用进程内的open、stat以及libabc.so中的目标函数,替换路径为共享文件夹:
const SHARED_DATA_PATH = "/mnt/shared/app_data/com.your.app"; const SHARED_FILES_PATH = "/mnt/shared/app_files/com.your.app"; // Hook libc中的核心文件操作函数 function hookLibcFunctions() { ["open", "openat", "stat", "lstat", "fopen"].forEach(funcName => { const func = Module.findExportByName("libc.so", funcName); if (!func) return; Interceptor.attach(func, { onEnter: function(args) { let path; if (funcName === "openat") { path = Memory.readCString(args[1]); } else { path = Memory.readCString(args[0]); } // 替换/data/data路径 if (path.includes("/data/data/com.your.app/")) { const newPath = path.replace("/data/data/com.your.app", SHARED_DATA_PATH); funcName === "openat" ? args[1] = ptr(Memory.allocUtf8String(newPath)) : args[0] = ptr(Memory.allocUtf8String(newPath)); } // 替换外部存储路径 else if (path.includes("/storage/emulated/0/Android/data/com.your.app/")) { const newPath = path.replace("/storage/emulated/0/Android/data/com.your.app", SHARED_FILES_PATH); funcName === "openat" ? args[1] = ptr(Memory.allocUtf8String(newPath)) : args[0] = ptr(Memory.allocUtf8String(newPath)); } } }); }); } // Hook libabc.so中的目标函数 function hookLibabc() { const libabc = Module.load("libabc.so"); // 根据崩溃日志中的地址0x5125d计算函数偏移(基址+偏移) const targetFunc = libabc.base.add(0x5125d); Interceptor.attach(targetFunc, { onEnter: function(args) { // 假设该函数第一个参数为路径 const path = Memory.readCString(args[0]); if (path.includes("/storage/emulated/0/Android/data/com.your.app/")) { const newPath = path.replace("/storage/emulated/0/Android/data/com.your.app", SHARED_FILES_PATH); args[0] = ptr(Memory.allocUtf8String(newPath)); } } }); } // 初始化钩子 setImmediate(() => { hookLibcFunctions(); hookLibabc(); });
三、第三方模拟器自定义存储路径
部分第三方模拟器(如雷电、逍遥)支持直接将应用存储目录绑定到Windows共享文件夹,可在模拟器设置的「存储」选项中找到相关配置,无需手动执行命令或编写Hook脚本,适合快速实现需求。
内容的提问来源于stack exchange,提问作者Ruan
相关产品推荐
相关产品推荐

