浅谈 C 语言栈帧与某些 Linux 系统中的 16 字节对齐

做 Pwn 题有时会遇到 payload 在本地打得通而远程打不通的情况,可能的原因之一是远程主机的系统版本要求 16 字节对齐,而所用 payload 没有满足这一点,于是可能报 timeout: the monitored command dumped core

0x00 栈帧结构

每一个函数的栈空间被称为栈帧,一个栈帧上包含了保存的寄存器、分配给局部变量的空间以及传递给要调用函数的参数等等。一个基本的栈结构如下图所示:

P.S. 返回地址属于调用函数的栈帧,而非当前函数的栈帧。

0x01 栈的字节对齐

栈的字节对齐,实际是指栈顶指针必须是 16 字节的整数倍。大多数函数的栈帧边界都必须是 16 的直接倍数。

栈帧边界

栈帧的边界由栈帧基地址指针 EBP 和堆栈指针 ESP 界定(指针存放在相应寄存器中)。EBP 指向当前栈帧底部(高地址),在当前栈帧内位置固定;ESP 指向当前栈帧顶部(低地址),当程序执行时 ESP 会随着数据的入栈和出栈而移动。

P.S. 据调试容易发现栈的 EBP 指针总是 16 字节对齐的。

检查栈对齐

movaps XMMWORD PTR [rsp+0x40], xmm0 这条指令会检查栈是否满足 16 字节对齐,如果不满足,则程序会 crash。

P.S. XMMWORD: Used for 128-bit multimedia operands with MMX and SSE (XMM) instructions.

解决栈对齐问题的方法

  • 利用 ret gadget,在 gadget 前加上一条 ret gadget
  • 跳过函数序言

0x02 参考资料

2019-2020 @lukbash