如何借助C语言调试器,找出使函数返回0的输入参数?
用源码级调试器(GDB)确定函数返回0时的参数取值
答案是肯定的,但核心思路不是设置返回值反推参数(这相当于修改输出,没法逆向得到合法输入),而是拦截函数返回0的时刻,直接读取当时的输入参数。下面是针对GDB(包括你用的gdbgui)的具体操作方法:
一、有源码的情况(最简便)
如果能拿到函数的源码,直接给返回逻辑加条件断点是最高效的方式:
- 先编译代码时带上调试信息:
gcc -g your_code.c -o your_program - 启动GDB(或gdbgui)加载程序:
gdb ./your_program - 找到函数中所有
return语句的行号,给每个返回行设置条件断点,仅当返回值为0时暂停:- 假设函数
int foo(int a, int b, int c)的返回语句在第20行,且返回的是变量res,则执行:break your_code.c:20 if res == 0 - 如果是直接返回表达式(比如
return a + b - c;),可以把条件写为表达式本身:break your_code.c:20 if (a + b - c) == 0
- 假设函数
- 运行程序:
run,当函数返回0时,调试器会自动暂停 - 查看当前参数:用
info args直接列出所有参数值,或者单独打印print a、print b、print c
如果函数有多个return语句,逐个加断点太麻烦,可以用GDB的catch return功能捕捉所有返回事件,再给事件加条件:
- 执行
catch return foo(指定捕捉foo函数的返回) - 用
info breakpoints查看这个捕捉点的编号(比如编号是1) - 给捕捉点加条件:
condition 1 $rax == 0(x86_64架构下返回值存在rax寄存器;x86架构用$eax) - 运行程序,触发条件时暂停,再用
info args查看参数
二、无源码但有调试符号的情况
如果只有带调试符号的二进制文件(比如.o或编译后的程序),可以通过寄存器检查返回值:
- 启动GDB加载程序后,先找到函数的返回指令位置:
disassemble foo,找到最后几条指令里的retq(x86_64)或ret(x86) - 在返回指令前设置断点,比如
break *0xXXXXXX(0xXXXXXX是返回指令的内存地址) - 给断点加条件:
condition 1 $rax == 0(同样,x86用$eax) - 运行程序,触发断点时,查看参数寄存器:x86_64前3个整数参数存在
rdi、rsi、rdx,执行print $rdi、print $rsi、print $rdx即可得到参数值;x86架构参数存在栈上,可用print *(int*)($ebp+8)等方式读取
注意事项
- 如果函数是递归调用,调试器会在每次返回0时都暂停,需要手动记录参数或调整条件
- 确保编译时没有开启优化(比如
-O2),否则编译器可能会重排代码、优化参数存储,导致调试时无法正确读取参数值
内容的提问来源于stack exchange,提问作者Sarah
相关产品推荐
相关产品推荐

