这是一个错误修复版本,其中大多数修复由 @hsorbo 完成,另有一位新贡献者让 C++ 绑定变得更完整。
内存扫描找到自身
Håvard 注意到,Linux 上的指针扫描可能会在一个已不再被任何线程使用的栈中找到它正在寻找的那些值。扫描工作线程会把搜索值溢出到自己的栈上;当线程池被释放、额外工作线程退出后,glibc 会保留这些栈以供复用,而退出栈帧之上的所有内容仍保持映射且可读。延迟清理逻辑取消隐藏这些区域后,下一次扫描就会愉快地找到自己留下的残余。任何曾在线程调度器的线程池上运行的内容也同样如此。
修复方法是在 Gum 线程退出时立即丢弃它溢出到栈上的内容。这项操作由 frida-glib 在线程自身执行的 finalize 回调完成,发生在线程库缓存该栈之前。其他 libc 会直接取消映射已退出线程的栈,因此只有 glibc 需要承担这次额外系统调用的开销。
其他修复
Håvard 还修复了另外两个 Linux 相关问题。当最后一个监听器的分离仍待处理时再次对函数插桩——GumJS 在脚本级事务中正是这样做的——可能会把过时的重定向解析到一个 trampoline,而后者随后会随旧上下文一同释放。现在该函数会被视为仍处于插桩状态;如果新旧插桩均为默认类型,就复用其上下文,否则立即将其停用。此外,对由 dlopen() 作为依赖项引入的模块调用 dlsym() 时不再崩溃;此前 glibc 尚未为我们用作句柄的 link map 计算局部作用域。
最后同样重要的是,@mnalmahmud 通过新的 ProbeListener 接口,让 C++ 绑定可以把探针附加到任意指令,因此不再需要降级使用 C API。
尽情使用吧!
变更日志
- glibc:线程退出时丢弃已终止 Gum 线程的栈,使内存扫描不再找到扫描工作线程或脚本调度器线程池留下的残余。感谢 @hsorbo 追踪到这个问题!
- interceptor:修复等待分离期间重新附加的问题;该问题可能把过时的重定向解析到随后被释放的 trampoline。感谢 @hsorbo!
- linux:通过使用 RTLD_NOLOAD 按需创建句柄,修复在 dlopen() 以依赖项形式发现的模块上调用 dlsym() 时的崩溃。感谢 @hsorbo!
- gumpp:添加探针监听器支持,把 gum_make_probe_listener() 公开为 ProbeListener 接口,并允许 Interceptor::attach() 和 detach() 接受它。感谢 @mnalmahmud!
- frida-compile:按需创建输出文件目录,frida-tools 和 npm 软件包均适用。感谢 @fourcels!
oleavr