使用Frida与Ghidra分析SO文件:如何获取函数参数地址而非值?
问题分析与解决方案
核心问题定位
你之前的错误在于混淆了参数的值和参数的栈地址:
- Frida的
args数组里,栈传参数直接存储的是参数的数值(比如你看到的静态值),而非参数在栈上的地址。 - 用
Memory.readPointer(args[4])相当于把参数数值当作内存地址去读取,自然会因地址无效触发访问违例,或因参数值为0返回0。
要获取栈上参数的地址,必须结合目标架构的调用约定和Ghidra给出的栈帧偏移来计算,而非直接操作args里的值。
具体解决步骤
1. 确认目标架构的栈帧基指针
Frida可以直接获取当前函数的栈帧基指针(与Ghidra的栈偏移对应):
- ARM 32位:
this.context.fp - ARM 64位:
this.context.x29 - x86:
this.context.ebp - x86_64:
this.context.rbp
2. 从Ghidra提取栈偏移
Ghidra中显示的uint in_stack_00000f98;这类变量,后缀的00000f98是该变量相对于栈帧基指针的偏移值。需要注意:
- 若Ghidra标注的是
+0xf98,则地址为基指针 + 0xf98 - 若标注的是
-0xf98,则地址为基指针 - 0xf98
(可通过Ghidra的函数栈帧视图确认偏移方向)
3. Frida脚本实现
以ARM 32位架构为例,假设Ghidra中param5对应的栈偏移是0xf98,脚本示例:
Interceptor.attach(ptr("0xXXXXXX"), { // 替换为目标函数的实际地址 onEnter: function(args) { // 获取栈帧基指针 const fp = this.context.fp; // 计算param5的栈地址(根据Ghidra偏移调整加减) const param5StackAddr = fp.add(0xf98); console.log("param_5 栈地址: ", param5StackAddr); // 读取栈地址的值,验证是否与args[4]一致 const param5Value = Memory.readUInt32(param5StackAddr); console.log("param_5 栈地址存储的值: ", param5Value); console.log("args[4]直接获取的值: ", args[4].toUInt32()); // 其他栈参数同理,替换Ghidra给出的偏移即可 const param6StackAddr = fp.add(0xf9c); console.log("param_6 栈地址: ", param6StackAddr); } });
关键说明
- 寄存器传递的参数(比如ARM前4个参数用r0-r3)没有栈地址,除非函数开头将寄存器值压栈,这类参数的地址需要从函数的栈保存位置查找。
- 若验证时栈地址的值与
args中的值不一致,说明偏移方向搞反了,把add换成sub即可。
内容的提问来源于stack exchange,提问作者Espeto_Power
相关产品推荐
相关产品推荐

