Search code examples
winapix86-64fasm

fasm: Hello world on 64-bit Win32 with and without macros


I'm trying to do my first steps in x86 assembly using fasm on Windows 10 64-bit. For that I used this hello world code

format pe64 console
entry start

STD_OUTPUT_HANDLE = -11

section '.text' code readable executable

start:
        sub     rsp, 8*7
        mov     rcx, STD_OUTPUT_HANDLE
        call    [GetStdHandle]
        mov     rcx, rax
        lea     rdx, [message]
        mov     r8d, message_length
        lea     r9, [rsp+4*8]
        mov     qword[rsp+4*8], 0
        call    [WriteFile]
        mov     ecx, eax
        call    [ExitProcess]

section '.data' data readable writeable

message         db 'Hello World!',0
message_length  = $ - message

section '.idata' import data readable writeable

        dd      0,0,0,RVA kernel_name,RVA kernel_table
        dd      0,0,0,0,0

kernel_table:
        ExitProcess     dq RVA _ExitProcess
        GetStdHandle    dq RVA _GetStdHandle
        WriteFile       dq RVA _WriteFile
                        dq 0

kernel_name     db 'KERNEL32.DLL',0
user_name       db 'USER32.DLL',0

_ExitProcess    db 0,0,'ExitProcess',0
_GetStdHandle   db 0,0,'GetStdHandle',0
_WriteFile      db 0,0,'WriteFile',0

which prints "Hello World!".

I then try to use some macros and change the code to

include 'win64ax.inc'

STD_OUTPUT_HANDLE = -11

.code
start:
        sub     rsp, 8*6
        mov     rcx, STD_OUTPUT_HANDLE
        call    [GetStdHandle]
        mov     rcx, rax
        lea     rdx, [message]
        mov     r8d, message_length
        lea     r9, [rsp+4*8]
        mov     qword[rsp+4*8], 0
        call    [WriteFile]
        mov     ecx, eax
        call    [ExitProcess]
.end start

section '.data' data readable writeable

message         db 'Hello World!',0
message_length  = $ - message

However, now nothing is printed when executing it. When I compare the disassembly in x64dbg, it does not look that different. Working:

sub rsp,38
mov rcx,FFFFFFFFFFFFFFF5
call qword ptr ds:[<GetStdHandle>]
mov rcx,rax
lea rdx,qword ptr ds:[402000]
mov r8d,D
lea r9,qword ptr ss:[rsp+20]
mov qword ptr ss:[rsp+20],0
call qword ptr ds:[<WriteFile>]
mov ecx,eax
call qword ptr ds:[<ExitProcess>]

and not working:

sub rsp,8
sub rsp,30
mov rcx,FFFFFFFFFFFFFFF5
call qword ptr ds:[<GetStdHandle>]
mov rcx,rax
lea rdx,qword ptr ds:[403000]
mov r8d,D
lea r9,qword ptr ss:[rsp+20]
mov qword ptr ss:[rsp+20],0
call qword ptr ds:[<WriteFile>]
mov ecx,eax
call qword ptr ds:[<ExitProcess>]

The only difference is here

lea rdx,qword ptr ds:[403000]

What's wrong with my macro-using code?


Solution

  • The format pe64 console at the start seems to be necessary. Without it, GetStdHandle returns 0 in rax.