ELF x86 - 为什么返回地址被推送两次?

逆向工程 拆卸 x86 小精灵
2021-07-03 06:59:10

我反转了一个 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个回答

本之前的堆栈上and esp, 0xfffffff0的是对准堆栈16个字节的指令。该指令不会擦除先前位于的数据esp(因此ecx-4仍指向返回地址),但堆栈指针现在指向可能与函数开头不同的值。所以需要将返回值([ecx-4]入栈中,使其esp指向返回地址而不是一些垃圾数据。

例如,假设先前的esp值为0x11111118然后函数返回地址位于esp(即等于[esp])。但是在and操作之后,espnow equals 0x11111110,所以函数返回地址在esp+8address ,它不在堆栈上(实际上下面)并且esp现在指向一些其他数据,这绝对不是函数返回地址。但我们知道,ecx-4指向的地址(因为ecx= 0x11111118+4= 0x1111111C),所以我们推[ecx-4]到堆栈,使esp现在指向它。