The MOVAPS issue
在做一道ret2libc的时候被这个问题困住了好久
为什么使用下面这个payload程序会崩溃,但是逻辑没有问题呀!
1 | p.sendafter( |
使用这个在system
前加了一个ret
的payload就可以了?!
1 | p.sendafter( |
经过大佬指点了解到在Ubuntu18版本及以上(还有一部分的Ubuntu16版本)64位程序调用system时是需要栈对齐的。
根本原因是64位的system
命令有个movaps
指令,这条指令是:
1 | movaps xmmword ptr [rsp + 0x50], xmm0 |
从 https://www.felixcloutier.com/x86/movaps 处我们可以知道,这条指令的功能是: 将xmm0中保存的单精度浮点数从xmm0移动至地址[rsp + 0x50]处 。
当然,更重要的是这条指令的执行条件,这直接关系到程序报错的原因。原文中对执行条件的描述如下:
When the source or destination operand is a memory operand, the operand must be aligned on a 16-byte (128-bit version), 32-byte (VEX.256 encoded version) or 64-byte (EVEX.512 encoded version) boundary or a general-protection exception (#GP) will be generated.
此时报错的原因就显而易见了:当内存地址作为操作数时,内存地址必须对齐 16Byte 、 32Byte 或 64Byte 。这里所说的对齐 xByte,就是指地址必须是 x 的倍数。
这时又出现了一个问题:到底是对齐多少字节呢?我们可以找到这样一段描述:
This instruction can be used to load an XMM, YMM or ZMM register from an 128-bit, 256-bit or 512-bit memory location, to store the contents of an XMM, YMM or ZMM register into a 128-bit, 256-bit or 512-bit memory location, or to move data between two XMM, two YMM or two ZMM registers.
基于此,我们可以推测:使用 XMM 时,需要 16Byte 对齐;使用 YMM 时,需要 32Byte 对齐;使用 ZMM 时,需要 64Byte 对齐。
而此处出错的指令使用了 XMM 寄存器,因此我们需要确保在执行这一指令时,rsp + 0x50 是 16 的倍数。直观地说,就是该地址必须以数字 0 结尾。
(调用printf时也需要对齐)
目前了解到有两种办法可以解决这个问题(但也不是每次都行,实在不行就换成execve吧…
第一种办法:
在system前加个ret
第二种办法:
在system的地址上加1-16,尝试,这是为了跳过一个栈操作
参考: