如何定位程序中从stdin读取数据的函数 辅助Fuzzing持久化模式开发
大代码库下定位stdin读取目标函数的高效方案
完全不需要逐行梳理GDB输出的数百行全量函数枚举结果,直接通过断点锚定调用栈反向定位,所有操作都可以直接执行:
1. 反向定位目标函数,跳过全量枚举环节
不用等rbreak跑完所有函数再筛选,一次性在所有可能触发输入读取的入口下断点,程序命中后顺着调用栈找目标:
- 一次性对所有涉及输入读取的常用入口下断点:
break read, break fread, break getc, break fgetc, break fgets, break scanf, break readv, break recvfrom - 启动程序后,每次断点命中时先校验当前操作是否为stdin读取:
- 若是系统调用层的
read,直接打印第一个传入的文件描述符参数:print fd,fd值为0时就是对应stdin的读取操作 - 若是libc封装的流操作函数(如
fread/fgets),校验传入的FILE*流对象地址是否与GDB内置的stdin符号地址相等,匹配上就是读stdin的场景
- 若是系统调用层的
- 确认是stdin读取场景后,执行
bt full打印完整调用栈,从栈顶往下逐帧排查,剔除libc、动态链接器等外部库的函数帧,剩下的第一个属于目标程序自身的函数,就是需要外围套Fuzz循环的目标位置。
2. 优化原有GDB枚举流程,压缩无效输出
你原来用rbreak ^[^@]*$全量匹配的方式,会混入大量动态库导出符号、无意义的内部函数符号,导致输出量激增。可以给断点匹配加地址过滤规则,只输出目标主程序自身的自定义函数:
- 先通过
info proc mappings查出主程序ELF加载的内存段起止地址 - 替换原有rbreak规则,加上地址范围过滤:
rbreak /m <主程序段起始地址>,<主程序段结束地址> ^[a-zA-Z_][a-zA-Z0-9_]*$,这样输出的枚举结果会剔除所有外部库符号,纯自定义函数的输出量通常不会超过几十行,梳理成本直接大幅降低。
持久化Fuzz适配的注意事项
- 定位到目标读stdin的函数后,确认所有前置初始化逻辑(全局变量初始化、外部资源加载、配置解析等)已经执行完成,再在这个函数外围套循环逻辑,避免因初始状态不完整导致Fuzz覆盖范围出现大量无效用例
- 针对静态编译、无动态库符号的目标,可以直接在
sys_read系统调用入口下断,命中后校验fd=0的场景,顺着调用栈照样能定位到目标,不需要做全量符号枚举。
内容的提问来源于stack exchange,提问作者lemonadeice
相关产品推荐
相关产品推荐

