我反转了ELF x86,我想了解为什么将返回地址再次压入堆栈?
main:
lea ecx, [esp+0x4 {argc}]
and esp, 0xfffffff0
push dword [ecx-0x4 {__return_addr}] {var_4}
push ebp, {var_8}
mov ebp, esp
push edi {var_c}
push ecx {argc} {var_10}
sub esp, 0xb0
mov eax, dword [ecx+0x4 {argv}]
mov dword [ebp-0x9c {var_a4}], eax
mov eax, dword [gs:0x14]
mov dword [ebp-0xc {var_14}], eax
xor eax, eax {0x0}
cmp dword [ecx {argc}], 0x2
je 0x80485ae
...
#1 楼
它在将堆栈对齐到16个字节的and esp, 0xfffffff0
指令之前出现在堆栈上。该指令不会删除先前在esp
处的数据(因此ecx-4
仍指向返回地址),但是堆栈指针现在指向的值可能与函数开始时的值不同。因此,需要将返回值([ecx-4]
)压入堆栈,以使esp
指向返回地址,而不是一些垃圾数据。然后,函数返回地址位于esp
(即等于0x11111118
)。但是在esp
操作之后,[esp]
现在等于and
,因此函数返回地址位于esp
地址,该地址不在堆栈上(实际上是在堆栈下面),并且0x11111110
现在指向其他数据,这绝对不是函数返回地址。但是我们知道esp+8
指向该地址(因为esp
= ecx-4
= ecx
),所以我们将0x11111118+4
压入堆栈,因此0x1111111C
现在指向它。
评论
这发生在哪几行?我想这是在推[ecx-0x4] var_4。正如我们在x86-32中一样,不能直接调用eip。
哪些编译器提供此代码?看起来好像是在从函数内部更改函数的返回地址。据我所知,这是所有ABI中的违规行为,因此它必须是非常特定的功能(如__libc_start_main())或混淆技术,以解决递归遍历反汇编技术。