调用ExitProcess时应该如何准备堆栈?

How should one prepare the stack when calling ExitProcess?

我正在尝试学习如何在汇编中调用操作系统函数,并且已经得到了一个示例,该示例将创建并关闭一个文件(在关闭时删除该文件)。在研究 ExitProcess 的用法时,我遇到了一些清理堆栈的示例和一些不清理堆栈的示例;更令人困惑的是,不管有没有清理步骤,事情似乎都有效......

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

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 usual function (windows api) and must be called with common calling convention for x64. in particular stack must be maintained 16-byte aligned 所以像其他 api 一样调用 ExitProcesscall ExitProcess 之前的 add rsp, 48h 指令是错误的

还有一些一般注意事项: 导入的 api 总是间接调用 - 如果你想调用 SomeApi - 声明变量(x64 代码)

extern __imp_SomeApi : QWORD

并致电

call __imp_SomeApi

如果我们声明

extern SomeApi : proc

并做

call SomeApi

链接器创建存根

SomeApi:
jmp  qword ptr __imp_SomeApi

所以最好直接使用__imp_SomeApi形式。

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

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