首页 > 解决方案 > 调用 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

标签: windowsassembly64-bitmasm

解决方案


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

还有一些一般注意事项:导入的 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

推荐阅读