__printf_chk

使用的条件是编译参数开了 -D_FORTIFY_SOURCE=2 且优化等级不低于 O1

该函数会对 fmt_string 进行检查,禁止下列情况:

  1. %N$标签存在跳过某些项的情况(如只出现了 %2$s 却没有出现 %1$s
  2. fmt_string包含%n,但在可写段

所以即便开启了FORTIFY检查,仍然可以通过格串来leak一些信息

float

printf和__printf_chk对浮点数的处理是特殊的,通过xmm寄存器来传参,其中浮点数参数的个数会通过 eax 寄存器(实际上是al)来传递

Untitled

在内部处理时,printf会判断al是否为零,来决定是否将xmm寄存器入栈保存(一旦非零,则会将所有xmm寄存器都入栈)

Untitled

传入的eax的值是在编译时就根据格式化字符串确定的,但如果我们提供的格串是一个变量,由于无法预知浮点数个数,编译器就会将eax置为0,如果此时我们在格串中填入浮点数相关的内容,由于 eax 为0,xmm不会被入栈,在后续的处理中就会打印栈上的垃圾信息,从而leak出有效地址

ref: https://www.dazhuanlan.com/rihour/topics/1385078