为什么程序需要栈帧或影子栈?
why procedure need stack frame or shadow stack?
(抱歉我的英语不好,因为我来自韩国)
我试过这段代码
lea rcx, QWORD PTR [message]
call [print_message] ;it covered return address to bad address
xor rcx, rcx
ret
然后崩溃了...
在那之后,我尝试了另一种方式
sub rsp, 8 ;shadow stack
lea rcx, QWORD PTR [message]
call [print_message]
add rsp, 8
ret
; stack frame
push rbp
mov rbp, rsp
lea rcx, QWORD PTR [message]
call [print_message]
mov rsp, rbp
pop rbp
ret
这两个代码是有效的,但问题是...,为什么程序需要这些东西?
这让我很好奇
真正的代码问题来了来自
extern __imp_MessageBoxA : QWORD
.data
message db "1234", 0
.code
entry_point proc
sub rsp, 8
xor ecx, ecx
lea rdx, QWORD PTR [message]
lea r8, QWORD PTR [message]
mov r9, 0
call [__imp_MessageBoxA] ;stdcall
add rsp, 8
ret
entry_point endp
end
不幸的是,我对 64 位代码没有太多经验,所以我不知道确切的细节:
实际上,您不需要影子堆栈或堆栈框架。但是一些 64 位函数需要 rsp
是 16 字节对齐的。
也就是说调用函数时rsp
的值必须是16的倍数
如果您的函数如下所示:
myFunction:
lea rcx, QWORD PTR [message]
call [print_message] ;it covered return address to bad address
...
...那么rsp
是指令call myFunction
之前的16的倍数。而call myFunction
压栈8个字节,所以rsp
不再是16的倍数(但是rsp
的值可以写成16*n+8)。
当您执行 call [print_message]
时,rsp
不是 16 的倍数,如果函数 print_message
要求 rsp
为 16 字节对齐,程序会崩溃.
指令 sub rsp, 8
和 push rbp
将从 rsp
中减去 8,因此 rsp
的值再次是 16 的倍数。
背景是某些 CPU 指令,这些指令需要一个地址是 16 的倍数作为参数。示例:
print_message:
sub rsp, 24
; The next instruction will crash if rsp is not
; a multiple of 16. This is the case if rsp was
; not a multiple of 16 before the
; "call print_message" instruction
paddd xmm0, [rsp]
(抱歉我的英语不好,因为我来自韩国)
我试过这段代码
lea rcx, QWORD PTR [message]
call [print_message] ;it covered return address to bad address
xor rcx, rcx
ret
然后崩溃了...
在那之后,我尝试了另一种方式
sub rsp, 8 ;shadow stack
lea rcx, QWORD PTR [message]
call [print_message]
add rsp, 8
ret
; stack frame
push rbp
mov rbp, rsp
lea rcx, QWORD PTR [message]
call [print_message]
mov rsp, rbp
pop rbp
ret
这两个代码是有效的,但问题是...,为什么程序需要这些东西?
这让我很好奇
真正的代码问题来了来自
extern __imp_MessageBoxA : QWORD
.data
message db "1234", 0
.code
entry_point proc
sub rsp, 8
xor ecx, ecx
lea rdx, QWORD PTR [message]
lea r8, QWORD PTR [message]
mov r9, 0
call [__imp_MessageBoxA] ;stdcall
add rsp, 8
ret
entry_point endp
end
不幸的是,我对 64 位代码没有太多经验,所以我不知道确切的细节:
实际上,您不需要影子堆栈或堆栈框架。但是一些 64 位函数需要 rsp
是 16 字节对齐的。
也就是说调用函数时rsp
的值必须是16的倍数
如果您的函数如下所示:
myFunction:
lea rcx, QWORD PTR [message]
call [print_message] ;it covered return address to bad address
...
...那么rsp
是指令call myFunction
之前的16的倍数。而call myFunction
压栈8个字节,所以rsp
不再是16的倍数(但是rsp
的值可以写成16*n+8)。
当您执行 call [print_message]
时,rsp
不是 16 的倍数,如果函数 print_message
要求 rsp
为 16 字节对齐,程序会崩溃.
指令 sub rsp, 8
和 push rbp
将从 rsp
中减去 8,因此 rsp
的值再次是 16 的倍数。
背景是某些 CPU 指令,这些指令需要一个地址是 16 的倍数作为参数。示例:
print_message:
sub rsp, 24
; The next instruction will crash if rsp is not
; a multiple of 16. This is the case if rsp was
; not a multiple of 16 before the
; "call print_message" instruction
paddd xmm0, [rsp]