1

平台是 x86_64 Windows 7。

这是C源代码:

#include<windows.h>
int main(void){
    asm("int3");
    CreateWindowEx(0,NULL,NULL,0,5,6,7,8,NULL,NULL,NULL,NULL);
    return(0);
}

编译为以下程序集:

push rbp
mov rbp,rsp
sub rsp,60h
int3
mov qword[rsp+58h],0
mov qword[rsp+50h],0
mov qword[rsp+48h],0
mov qword[rsp+40h],0
mov qword[rsp+38h],8
mov qword[rsp+30h],7
mov qword[rsp+28h],6
mov qword[rsp+20h],5
mov r9d,0
mov r8d,0
mov edx,0
mov ecx,0
call CreateWindowEx
mov eax,0
add rsp,60h
pop rbp
ret

从概念上讲,这就是我在不同执行点的堆栈(地址是任意的):

90 -rsp-

90 old rbp
88 -rsp-

90 old rbp
88 -rsp- -rbp-

90 old rbp
88 -rbp- (never used?)
80 (rsp+58h)
78 (rsp+50h)
70 (rsp+48h)
68 (rsp+40h)
60 (rsp+38h)
58 (rsp+30h)
50 (rsp+28h)
48 (rsp+20h)
40 (shadow)
38 (shadow)
30 (shadow)
28 -rsp- (shadow) (will contain call instruction's return pointer...)

如您所见,根据 C 程序的编译输出,堆栈存在问题。首先,有 8 个字节永远不会被使用,并且 8 个字节的影子空间将被返回指针的调用指令覆盖。似乎所有内容都比应有的向下移动了 8 个字节,因为如果向上移动 8 个字节就可以了。但是 API 调用按预期工作,这是否只是对 Microsoft 调用约定实现的忽视?

4

1 回答 1

3

当某些东西被压入堆栈时,新项目不会rsp在指令开始时指向指向的位置 -rsp在存储新项目之前递减(即,rsp指向的堆栈位置正在使用中)。

因此,如果rsp ==0x90在启动该功能时,旧的rbp将位于地址0x88(并将rbp指向该地址)。

然后当rsp == 0x28call指令执行时,返回地址将放在 address 中0x20,而不是0x28

于 2012-09-02T09:43:06.647 回答