学习 frida 源码,先从 test 案例入口开始分析,以 https://bbs.kanxue.com/thread-278423.htm 作为指导进行学习,有理解不对的地方欢迎指正,谢谢。测试文件 frida\subprojects\frida-gum\tests\core\arch-arm64\interceptor-arm64.c 你看到的这段代码是一个 单元测试(Unit Test)。目标模块: Interceptor (拦截器),这是 Frida 用来实现 Inline Hook 的核心组件。目标架构: interceptor_arm64,这特指是为 ARM64 架构(目前绝大多数 64 位智能手机的 CPU 架构)编写的测试。核心概念:lr 寄存器测试的真正目的:一个棘手的边界情况 这部分很简单,只是一个目录,告诉测试框架:“嘿,我们要跑这两个测试。”这个测试用例测试的是:Hook 一个“会读取 lr 寄存器”的*普通函数*。这个测试用例测试的是:Hook 一个“会读取 lr 寄存器”的*Thunk 函数*。这两个测试非常精彩,它们共同验证了 Interceptor 的一个核心能力:这就是 Frida 强大的 稳定性(Robustness) 的体现。它不仅能 Hook 函数,还能在 Hook 的同时,保证原函数的(尤其是依赖 lr 这种易变状态的)逻辑不被破坏。下面从“它做了什么” (What it does) 转向了“它是怎么做的” (How it does it)。看上面两个 TESTCASE 中的公共函数 interceptor_fixture_attach 是 Frida 测试框架中用于“挂钩” (Hook) 的辅助函数 (Helper Functions)。让我们来解剖它们。interceptor_fixture_attach 是一个 “必须成功”的包装器。它存在的意义就是为了让 TESTCASE 里的代码更简洁。在测试中,我们 期望 Hook 总是成功的。所以我们用这个函数:它去尝试 Hook,如果失败了,就直接让测试失败。如果成功了,它就安静地返回。这是真正的主菜。这个函数负责 创建并注册一个监听器 (Listener),然后把它附加 (attach) 到目标函数上。我们把测试需要的数据存放到“工具箱” ctx 中。ctx->fixture = h;:把测试“固定装置”h 存进去。ctx->enter_char = enter_char;:把 '>' 存进去。ctx->leave_char = leave_char;:把 '<' 存进去。回顾一下 Hooked 函数调用 的工作流:目标函数被调用,Hook 触发。Frida 调用 on_enter(即 arm64_listener_context_on_enter)。Frida 把 user_data(即 ctx)传给 on_enter。on_enter 函数内部:(1). 通过 ctx 拿到 ctx->fixture(即 h)。
(2). 通过 ctx 拿到 ctx->enter_char(即 '>')。
(3). 把 '>' 追加到 h->result->str 字符串的末尾。Frida 调用原始的目标函数(ctx.run() 内部的原始逻辑)。原始函数执行完毕,准备返回。Frida 在它真正返回 之前,调用 on_leave (即 arm64_listener_context_on_leave)。on_leave 函数内部:(1). 通过 ctx 拿到 ctx->fixture(即 h)。
(2). 通过 ctx 拿到 ctx->leave_char(即 '<')。
(3) 把 '<' 追加到 h->result->str 字符串的末尾。(此时,h->result->str 的内容变成了 "><")on_leave 返回,Frida 将原始函数的返回值(如果有的话)交还给调用者。 这就是 fixture->result->str == "><" 这个断言的由来!通过分析这两个函数,你实际上已经学通了 Frida Interceptor (C API 层面) 的标准工作流程:分配上下文 (Context):创建一个结构体(如 Arm64ListenerContext)来存放你需要的所有信息(回调函数、用户数据等)。创建监听器 (Listener):创建一个 GumInvocationListener 对象。配置回调 (Callbacks):设置 listener->on_enter 和 listener->on_leave 指向你自己的 C 函数。设置 user_data:把你的 上下文 (Context) 地址赋值给 listener->user_data。这是连接回调函数和你的数据的桥梁。调用 gum_interceptor_attach:传入目标函数和配置好的监听器,执行 Hook。处理结果:可以注意到,其中 on_enter 和 on_leave 是可以由用户自行重载的。然后再从 gum_interceptor_attach 进入,该函数包括了布置 hook 并启动 hook 的任务:interceptor_fixture_try_attach 只是一个测试辅助函数,而你现在看到的 gum_interceptor_attach 则是 Frida Interceptor 模块的公开 C API 核心。所有语言(JavaScript, Python, Swift...)的 Interceptor.attach() 最终都会调用到这个 C 函数。让我们来一步步解剖这个“引擎”。这个函数的 真正工作 可以分为两个阶段:这是在执行“高危操作”(修改正在运行的程序的代码)之前的标准 安全措施。精妙的技巧! 这行代码告诉 Interceptor:“嘿,接下来我(指当前这个线程)要执行一些内部操作了。如果我不小心调用了 其他 已经被 Hook 的函数,请不要 触发它们的 onEnter/onLeave 回调。”为什么这么做? 在 Frida Hook 框架中,当我们对一个函数(如 open, recv, malloc)安装拦截(intercept)后,所有线程执行该函数时都会跳转到我们注入的 trampoline / replacement 函数。但有时,我们自己当前线程的代码 也会调用被 Hook 的函数(比如 Hook malloc 时,我们自己的日志模块也会用到 malloc),这就可能导致:当前线程陷入递归 hook → 死循环 → 崩溃。为了避免这种情况,Frida 提供了:最后,我们来看看那些 goto 语句。在 C 语言中,goto 经常被(正确地)用于 集中的错误处理和资源释放。这是一种非常标准的模式。 gum_interceptor_attach 是一个 非常健壮 的函数:Inline Hook(也称内联钩子)是一种低级的函数钩子技术,它通过直接修改目标函数的机器码(通常是函数开头的几条指令)来实现钩子。具体来说,它会用跳转指令(如 jmp)替换函数的起始代码,将执行流重定向到自定义的钩子
...(已截断)
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-289011.htm
[原创]frida-gum 源码解读
260 浏览
14 回复
tql 我反手就是一个三连
用了ai吗?
值得怀疑
用了ai吗?
用了,gemini,提升效率
用了ai吗?
用了,gemini,提升效率
教教我吧~
用了,gemini,提升效率
强啊 ai写这么多 给我网页都搞卡了
用了,gemini,提升效率
强啊 ai写这么多 给我网页都搞卡了
牛啊,感谢分享
回复来看看,先谢过楼主!
tql
申请加精!
mark
看看
看看
学习
感谢分享,学习一下。
学习