编辑:
我接受了下面的答案,并在我对代码的最终修订中添加了我自己的答案。希望它能向人们展示影子空间分配的实际例子,而不是更多的文字。
编辑 2:我还设法在 YouTube 视频(所有内容)的注释中找到了调用约定 PDF 的链接,其中有一些关于 Shadow Space 和 Linux 上的红区的有趣花絮。可以在这里找到:http://www.agner.org/optimize/calling_conventions.pdf
原创:
我在这里和整个互联网上查看了其他几个问题,但我似乎找不到在 64 位 Windows 程序集中调用子例程/Windows API 时分配“影子空间”的合适示例。
我的理解是这样的:
- 来电者应该
sub rsp,<bytes here>
在call callee
之前 - 如果需要,被调用者应该使用它来存储寄存器(或局部变量,如果不需要寄存器保存)
- 来电者清理它,例如:
add rsp,<bytes here>
- 分配的数量应对齐到 32 字节
考虑到这一点,这就是我尝试过的:
section .text
start:
sub rsp,0x20 ; <---- Allocate 32 bytes of "Shadow space"
mov rcx,msg1
mov rdx,msg1.len
call write
add rsp,0x20
mov rcx,NULL
call ExitProcess
ret
write:
mov [rsp+0x08],rcx ; <-- use the Shadow space
mov [rsp+0x10],rdx ; <-- and again
mov rcx,STD_OUTPUT_HANDLE ; Get handle to StdOut
call GetStdHandle
mov rcx,rax ; hConsoleOutput
mov rdx,[rsp+0x08] ; lpBuffer
mov r8,[rsp+0x10] ; nNumberOfCharsToWrite
mov r9,empty ; lpNumberOfCharsWritten
push NULL ; lpReserved
call WriteConsoleA
ret
我的两个字符串是“Hello”和“World!\n”。这设法在崩溃前打印“Hello”。我怀疑我做的是正确的......除了我应该以某种方式清理(我不确定如何清理)。
我做错了什么?我已经尝试了大小的组合,也尝试了在 WinAPI 调用之前“分配影子空间”(我应该这样做吗?)。
应该注意的是,当我根本不关心阴影空间时,它工作得很好。但是,自从我的 write
以来,我一直在努力遵守 ABI。函数调用 WinAPI(因此不是叶函数)。
最佳答案
必须在调用之前直接提供阴影空间。将阴影空间想象成旧的 stdcall/cdecl 约定的遗物:对于 WriteFile
,您需要五次推送。阴影空间代表最后四次推送(前四个参数)。现在您需要四个寄存器,影子空间(只是空间,内容无关紧要)和影子空间之后堆栈上的一个值(这实际上是第一次压入)。目前,调用者的返回地址 (start
) 位于 WriteFile
将用作影子空间 -> 崩溃的空间中。
您可以在 write
函数内为 WinAPI 函数(GetStdHandle
和 WriteConsoleA
)创建一个新的阴影空间:
write:
push rbp
mov rbp, rsp
sub rsp, (16 + 32) ; 5th argument of WriteConsoleA (8) + Shadow space (32)
; plus another 8 to make it a multiple of 16 (to keep stack aligned after one push aligned it after function entry)
mov [rbp+16],rcx ; <-- use our Shadow space, provided by `start`
mov [rbp+24],rdx ; <-- and again, to save our incoming args
mov rcx, -11 ; Get handle to StdOut
call GetStdHandle
mov rcx,rax ; hConsoleOutput
mov rdx, [rbp+16] ; lpBuffer ; reloaded saved copy of register arg
mov r8, [rbp+24] ; nNumberOfCharsToWrite
mov r9,empty ; lpNumberOfCharsWritten
mov qword [rsp+32],0 ; lpReserved - 5th argument directly behind the shadow space
call WriteConsoleA
leave
ret
关于windows - 阴影空间示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33273797/