C printf原型解析

printf 函数原型解析

c 复制代码
int __cdecl printf(const char *format, ...);
  1. 返回值:int,代表成功输出的字符个数
  2. 调用约定 (x86):__cdecl,调用者负责堆栈平衡;x64 下 Windows 统一 ABI,__cdecl关键字失效
  3. 参数结构
    ○ 固定参数:const char *format 格式化字符串
    ○ 可变参数:...,必须放在末尾
  4. 工作原理 遍历 format 字符串,读到%时,读取后面的格式符(%d/%f/%s),依靠格式符来告诉 va_arg 该取什么类型的数据
    ⚠️重点:C 语言本身不会自动检测可变参数的数量与类型,完全靠格式化字符串,类型不匹配直接触发未定义行为

va_list 系列宏使用流程

c 复制代码
va_list args;           // 定义可变参数迭代指针
va_start(args, format); // 绑定到最后一个固定参数,args指向第一个可变参数
va_arg(args, type);     // 取出当前参数,指针自动向后偏移
va_end(args);           // 清理

内存布局区分

● x86(cdecl):参数从右向左全部压栈,所有可变参数都在栈上连续存放,va_arg本质就是指针 + 类型宽度偏移

● x64 Windows ABI:前 4 个参数优先放在rcx,rdx,r8,r9寄存器,剩余参数入栈;va_start 会处理寄存器里存放的参数,不再单纯只操作栈

坑:x64 下可变参数不是全部在栈上,逆向调试的时候容易踩坑

格式符对应 va_arg 取值

格式符 va_arg 取类型 说明
%d int 整型
%f double 注意:float 传可变参数会自动提升为 double,不能写 float
%s char* 字符串指针

两种可变参数设计方案对比

  1. 显式计数法
c 复制代码
int Sum(int count, ...);

第一个参数 count,直接写明后面一共有多少个参数;适合参数类型全部相同场景

示例:Sum(3,10,20,30),count=3 代表 3 个可变参数

  1. 特征匹配法(printf 采用) 靠格式化字符串format里面的%占位符,统计参数数量、识别参数类型;适合参数类型混杂场景

核心注意事项

  1. 类型严格匹配 格式符和真实参数类型不一致,会读取错误内存,程序崩溃或者乱输出
    比如%d读取 double,直接取 4 字节,解析结果完全错误
  2. 读取顺序 可变参数读取顺序和传入顺序一致;x86 虽然参数从右往左压栈,但是栈增长向下,遍历的时候依然从左到右取参数
  3. 缺参问题 格式化字符串写了 3 个%,但是只传 2 个实参 → va_arg 继续向后读取栈上随机内存,属于未定义行为(格式化字符串漏洞原理基础)
  4. 整型提升规则 可变参数中char、short会自动提升为int;float自动提升为double,va_arg不能用char/short/float

底层逆向视角

● x86:va_start就是获取栈上固定参数的地址,计算偏移找到第一个可变参数

va_arg = 指针 + sizeof (类型)

● x64:va_list不再是单纯指针,是一个结构体,内部保存寄存器中存放参数的备份地址 + 栈参数地址,所以 x64 的 va 系列宏实现比 x86 复杂很多

格式化字符串漏洞关联拓展(拓展)

printf 第一个参数可控,用户可以自己写入%p %x %n,就能读取栈上内存甚至写入内存,就是经典的格式化字符串漏洞,根源就是 printf 靠字符串解析参数,没有边界校验

相关推荐
\光辉岁月/39 分钟前
5.math类
java·开发语言
不像程序员的程序媛1 小时前
mybatisplus insert dto未指定id时会如何
java·开发语言
BeiGuTing_code1 小时前
C字符输出:一个换行符引发的“失踪案”
c语言·开发语言
我命由我123451 小时前
5-2.Python 编码进阶 - 字符串进阶(拼接、普通格式化、普通格式化数字精度控制、快速格式化、遍历、常用方法)
java·开发语言·后端·python·学习·java-ee·学习方法
http阿拉丁神猫5 小时前
Go语言入门笔记:从基础到开发环境搭建(二)
开发语言·笔记·golang
不会就选b6 小时前
C++补充部分(一)--lambda 表达式
开发语言·c++
Pniubi9 小时前
HashMap的扩容和树化边界
java·开发语言
gCode Teacher 格码致知11 小时前
Pandas教学-17:Series与Dataframe的关系
开发语言·python·pandas
发量惊人的中年网工11 小时前
分公司访问总部ERP慢怎么办?SD-WAN组网的排查与验收要点
服务器·开发语言·php