1

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?

Thomas S.
  • 5,804
  • 5
  • 37
  • 72
  • 1
    Look at the section headers in PE file and check their Relative Virtual Address. Virtual address of `message` in **.data** section assumes `0x402000` but it is loaded from `0x403000`. – vitsoft Aug 12 '23 at 12:11
  • @vitsoft How do I influence the `0x403000` from the macro code? – Thomas S. Aug 12 '23 at 12:38
  • Break the debugger after the instruction `lea rdx, [message]` and look if the memory addressed by `rdx` contains `Hello World!`. Otherwise I would ask somebody at [FASM Forum](https://board.flatassembler.net/). – vitsoft Aug 12 '23 at 14:42

1 Answers1

2

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

Thomas S.
  • 5,804
  • 5
  • 37
  • 72
  • I'm surprised FASM even makes a `.exe` instead of a `.obj` if the source doesn't specify a format. I wonder how / why it makes an executable at all with a wrong absolute address. Does it help if you use RIP-relative addressing, like `lea rdx, [rel message]` or `default rel` if its syntax matches NASM for this. (RIP-relative is more efficient, so x86-64 code should always use it when there's no register in an addressing mode; [Why does this MOVSS instruction use RIP-relative addressing?](https://stackoverflow.com/q/44967075)) – Peter Cordes Aug 13 '23 at 07:43
  • 2
    @PeterCordes The address of `message` was never the problem (it was a red herring). In his version a PE64 GUI was the default output format. If you build a `console` application the resulting program has sections at different Virtual Memory Addresses. `message` happens to be at a different location depending on how you build (GUI or Console). What is important is the fact that `GetStdHandle` will return an error when there is no console by default (no default console for a WIN GUI), although such a console can be created by attaching a console through the Windows API. – Michael Petch Aug 13 '23 at 10:54
  • FASM's default is to output flat binary files, if you want object files you have to request that using the `format` directive. – Michael Petch Aug 13 '23 at 11:08