关于Windows:调用ExitProcess时应该如何准备堆栈?

How should one prepare the stack when calling ExitProcess?

我正在尝试学习如何在汇编中调用操作系统功能,并弄清楚了一个示例,该示例将创建然后关闭文件(在关闭时删除文件)。在研究ExitProcess的用法时,我遇到了一些清理堆栈的示例,有些则没有。更令人困惑的是,无论是否进行清理,事情似乎都可以正常工作...

在这种情况下处理堆栈的正确方法是什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
extern CloseHandle : proc
extern CreateFileA : proc
extern ExitProcess : proc

include FileAccess.inc
include FileDisposition.inc
include FileFlag.inc
include FileShare.inc

.data

filePath byte"C:\\Temp\\test123.txt",0

.code

Main PROC
    sub rsp, 48h                                                      ; align with 16 while simultaneously making room on the stack for the"home space" and any parameters
    lea rcx, filePath                                                 ; put address of file name into parameter slot 0
    mov rdx, FILE_ACCESS_READ                                         ; put access mode into parameter slot 1
    mov r8, FILE_SHARE_READ                                           ; put share mode into parameter slot 2
    xor r9, r9                                                        ; put security attributes into parameter slot 3
    mov qword ptr [((rsp + 48h) - 28h)], FILE_DISPOSITION_CREATE      ; put disposition into parameter slot 4
    mov qword ptr [((rsp + 48h) - 20h)], FILE_FLAG_DELETE_ON_CLOSE    ; put flags into parameter slot 5
    mov qword ptr [((rsp + 48h) - 18h)], 0                            ; put template handle into parameter slot 6
    call CreateFileA                                                  ; create file handle
    mov rcx, rax                                                      ; move file handle into parameter slot 0
    call CloseHandle                                                  ; close file handle
    add rsp, 48h                                                      ; free all space that was reserved on the stack
    xor ecx, ecx                                                      ; set return value to zero
    call ExitProcess
Main ENDP

END


ExitProcess常用函数(windows api),并且必须使用x64的通用调用约定来调用。特别是堆栈必须保持16字节对齐
因此像其他任何api一样调用ExitProcesscall ExitProcess之前的add rsp, 48h指令错误

还有一些一般注意事项:
导入的api始终称为间接-如果要调用SomeApi-声明变量(x64的代码)

1
extern __imp_SomeApi : QWORD

并致电

1
call __imp_SomeApi

如果我们声明

1
extern SomeApi : proc

然后做

1
call SomeApi

链接器创建存根

1
2
SomeApi:
jmp  qword ptr __imp_SomeApi

因此最好直接使用__imp_SomeApi形式。

也总是更好地使用W而不是A api形式。所以所有代码看起来都像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
FILE_FLAG_DELETE_ON_CLOSE = 04000000h
CREATE_ALWAYS = 2
FILE_SHARE_READ = 1
GENERIC_READ = 080000000h
INVALID_HANDLE_VALUE = -1

extern __imp_ExitProcess : QWORD
extern __imp_CreateFileW : QWORD
extern __imp_CloseHandle : QWORD

WSTRING macro text
    FORC arg, text
    DW '&arg'
    ENDM
    DW 0
endm

.const
    ALIGN 2
filePath: WSTRING <C:\\Temp\\test123.txt>

.code
Main proc
    sub rsp, 48h                                                        
    mov qword ptr [rsp + 30h], 0                                        
    mov qword ptr [rsp + 28h], FILE_FLAG_DELETE_ON_CLOSE                
    mov qword ptr [rsp + 20h], CREATE_ALWAYS                            
    xor r9, r9                                                          
    mov r8, FILE_SHARE_READ                                            
    mov rdx, GENERIC_READ                                              
    lea rcx, filePath                                                  
    call __imp_CreateFileW
    cmp rax, INVALID_HANDLE_VALUE
    je @@0                                          
    mov rcx, rax                                                        
    call __imp_CloseHandle  
@@0:                                          
    xor ecx, ecx                                                        
    call __imp_ExitProcess
    add rsp, 48h                                                        
    ret                                                    
Main endp

end