Shadow Space Example

EDIT:

I accepted the answer below and also added my own with my final version of the code. Hopefully he shows people actual examples of highlighting shadow space, not more words.

EDIT 2: I also managed to find a link to the PDF calling conventions in the YouTube video annotation (total), which has interesting interesting snippets on Shadow Space and Red Zone on Linux. It can be found here: http://www.agner.org/optimize/calling_conventions.pdf

ORIGINAL:

I looked at several other issues here and around the Internet, but I cannot find a suitable example of highlighting "Shadow Space" when calling a routine / Windows API in a 64-bit Windows assembly.

My understanding is this:

  • Caller must sub rsp,<bytes here>beforecall callee
  • Callee should use it to store registers if necessary (or local variables if register preservation is not required).
  • Caller clears it, for example: add rsp,<bytes here>
  • The allocated amount should be aligned to 32 bytes.

With that in mind, this is what I tried:

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

My two lines: "Hello" and "Peace! \ N". It manages to print "Hello" before the crash. I have a suspicion that I am doing it right ... except that I have to clean up somehow (and I'm not sure how).

What am I doing wrong? I tried a combination of sizes, and also tried to “highlight Shadow Space” before WinAPI calls (should I do this?).

, , . , ABI, write WinAPI ( ).

+4
2

. , stdcall/cdecl: WriteFile . ( ). , ( , ) ( ). (start) , WriteFile → .

WinAPI (GetStdHandle WriteConsoleA) write:

write:
    push rbp
    mov rbp, rsp
    sub rsp, (8 + 32)       ; 5th argument of WriteConsoleA + Shadow space

    mov [rbp+16],rcx        ; <-- use the Shadow space of `start`
    mov [rbp+24],rdx        ; <-- and again

    mov rcx, -11            ; Get handle to StdOut
    call GetStdHandle

    mov rcx,rax             ; hConsoleOutput
    mov rdx, [rbp+16]       ; lpBuffer
    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
+4

, , , . , , , UNWIND_INFO/ x64 ASM Windows, . , , .

EDIT:

Raymonds . rbp, , , .

; Windows APIs

; GetStdHandle
; ------------
; HANDLE WINAPI GetStdHandle(
;     _In_ DWORD nStdHandle
; ); 
extern GetStdHandle

; WriteFile
; ------------
; BOOL WINAPI WriteFile(
;   _In_        HANDLE       hFile,
;   _In_        LPCVOID      lpBuffer,
;   _In_        DWORD        nNumberOfBytesToWrite,
;   _Out_opt_   LPDWORD      lpNumberOfBytesWritten,
;   _Inout_opt_ LPOVERLAPPED lpOverlapped
; );
extern WriteFile

; ExitProcess
; -----------
; VOID WINAPI ExitProcess(
;     _In_ UINT uExitCode
; );
extern ExitProcess

global start

section .data

    STD_OUTPUT_HANDLE   equ -11
    NULL                equ 0

    msg1                 db "Hello ", 0
    msg1.len             equ $-msg1

    msg2                 db "World!", 10, 0
    msg2.len             equ $-msg2

section .bss

empty               resd 1

section .text

start:

    sub rsp,0x28    ; Allocate 32 bytes of Shadow Space + align it to 16 bytes (8 byte return address already on stack, so 8 + 40 = 16*3)

    mov rcx,msg1
    mov rdx,msg1.len
    call write

    mov rcx,msg2
    mov rdx,msg2.len
    call write

    mov rcx,NULL
    call ExitProcess

    add rsp,0x28    ; Restore the stack pointer before exiting

    ret

write:

    ; Allocate another 40 bytes of stack space (the return address makes 48 total). Its 32
    ; bytes of Shadow Space for the WinAPI calls + 8 more bytes for the fifth argument
    ; to the WriteFile API call.
    sub rsp,0x28

    mov [rsp+0x30],rcx      ; Argument 1 is 48 bytes back in the stack (40 for Shadow Space above, 8 for return address)
    mov [rsp+0x38],rdx      ; Argument 2 is just after Argument 1

    mov rcx,STD_OUTPUT_HANDLE   ; Get handle to StdOut
    call GetStdHandle

    mov rcx,rax             ; hFile
    mov rdx,[rsp+0x30]      ; lpBuffer
    mov r8,[rsp+0x38]       ; nNumberOfBytesToWrite
    mov r9,empty            ; lpNumberOfBytesWritten

    ; Move the 5th argument directly behind the Shadow Space
   mov qword [rsp+0x20],0   ; lpOverlapped, Argument 5 (just after the Shadow Space 32 bytes back)
    call WriteFile

    add rsp,0x28        ; Restore the stack pointer (remove the Shadow Space)

    ret

...:

Finally, work!

+2

Source: https://habr.com/ru/post/1612684/


All Articles