Frida内存分配使用是否正确?文件替换场景遇权限异常
问题
我需要在运行时给类文本编辑器打补丁:当用户打开任意文件时,自动替换为打开预定义文件/tmp/predefined。我用Frida的JavaScript API拦截所有open()系统调用,判断后替换第一个参数(文件路径)。
脚本patcher.js如下:
function main() { Interceptor.attach(Module.getExportByName(null, 'open'), { onEnter(args) { const originalPath = args[0].readCString(); if (shouldReplace(originalPath)){ args[0].writeUtf8String('/tmp/predefined'); // (1) //args[0] = Memory.allocUtf8String("/tmp/predefined"); (2) } }, }); } function shouldReplace(path) { if (!path) return false; // Do not replace essential system or config files: if (path.startsWith("/usr/") || path.startsWith("/etc/") || path.startsWith("/lib") || path.startsWith("/var/") || path.startsWith("/proc/") || path.startsWith("/sys/") || path.startsWith("/dev/") || path.startsWith("/run/") || path.startsWith("/home/user/.config/") || path.startsWith("/home/user/.cache") || path.startsWith("/home/user/.local") ) { return false; } // Avoid replacing if it's already the predefined file (prevent infinite loop) if (path === "/tmp/predefined") { return false; } // Otherwise, assume it's a user-requested file and should be replaced return true; } main()
测试时使用gnome-text-editor,运行命令:
./frida -l patcher.js -f /usr/bin/gnome-text-editor /tmp/originalFile
启用(1)直接改写args[0]指向的内存时功能正常,能成功打开/tmp/predefined。但启用(2),用Memory.allocUtf8String分配新内存并让args[0]指向它时,出现两个异常:
- 编辑器提示
Could Not Open File You do not have permissions to open the file,无法打开/tmp/predefined - 终端输出警告:
(gnome-text-editor:9036): editor-document-WARNING **: 11:11:33.542: Failed to load file: Error opening file /tmp/originalFile: No such file or directory,但/tmp/originalFile实际存在。
我想知道是不是Memory.allocUtf8String的用法有误?
原因分析与解决方法
问题根源
Memory.allocUtf8String()默认在Frida自身的内存区域分配内存,这块内存对目标进程来说是不可访问的。当你把args[0]指向该区域后,目标进程调用open()时会尝试读取不可访问的地址,导致实际传递给系统调用的路径无效,进而触发权限错误和文件不存在的警告。
而直接用args[0].writeUtf8String()是修改目标进程自己分配的、可正常访问的内存区域,系统调用能正确读取到新路径,因此功能正常。
正确的内存分配方式
要在目标进程的可访问内存中分配空间,需要确保内存属于目标进程的地址空间。可以用Memory.alloc()配合writeUtf8String()来实现:
修改后的onEnter代码片段:
onEnter(args) { const originalPath = args[0].readCString(); if (shouldReplace(originalPath)){ // 在目标进程的可访问内存中分配足够空间存储路径 const newPathLen = '/tmp/predefined'.length + 1; // +1 用于字符串结束符 const newPathPtr = Memory.alloc(newPathLen); newPathPtr.writeUtf8String('/tmp/predefined'); args[0] = newPathPtr; } }
额外说明
- 也可以用
Process.pageSize直接分配一整页内存,避免计算路径长度的麻烦,比如Memory.alloc(Process.pageSize) - 所有传递给目标进程函数或系统调用的内存,必须属于目标进程的地址空间,不能用Frida自身的内存区域
内容的提问来源于stack exchange,提问作者ibse
相关产品推荐
相关产品推荐

