windowsassemblyx86-64nasmyasm

Create a Windows 64-Bit executable with YASM assembler


I would like to create a Windows 10/11 Pro 64-Bit assembly source code, that can than proceed by YASM Assembler to form a Windows Executable (.exe Application) so small as possible. For Resources under the GitHub: corkami.

But I don't know which one is best for 64-bit. The solution should contain Assembly text/code with comments that explain how to do so.

E.g.: "You have to set the IAT for more as one Symbols" ... The solution should be "not" link with other Tool-chains. This means: C:\yasm -f bin -o output.exe input.asm.

As a bonus, the source should be compile with C:\nasm -f bin -o output.exe input.asm.

In an answer, it is enough to show the way/steps, to display a MessageBox, and *ExitProcess *call.

Optional, __imp__ShowMessageBoxA is an Export-Symbol from the FPC (Free-Pascal-Compiler) Windows .DLL library file. The assembly should contain this snippet:

EntryPoint:
    sub rsp, 4 * 8
    mov ecx, 0                     // HWND
    mov rdx, [lpText]              // LPCTSTR
    mov r8, [lpCapt]               // LPCTSTR
    mov r9d, 2                     // UINT
    call [__imp__ShowMessageBoxA]

    xor ecx, ecx
    call [__imp__ExitProcess]

lpText db "this and that", 0
lpCapt db "Caption", 0

hnExitProcess:
    dw 0
    db 'ExitProcess', 0
hnShowMessageBoxA:
    dw 0
    db 'ShowMessageBoxA', 0

I tried to use a Example from corkami, but I am lost.

I tried to create flat binary File with yasm.exe -f bin or nasm.exe -f bin which does bring me no Compiler-Errors. The result of yasm -f bin output.exe was the Windows Loader Message: "Symbol ShowMessageBoxA was not found in output.exe". I created a .DLL that was formed by FPC (Free Pascal Compiler) with C:\fpc kalle32.pas :

library kalle32;
uses Windows;
procedure ShowMessageA(h: HWND; t,c: LPCTSTR; u: UINT); stdcall;       export;
begin
  // this will not show
  MessageBoxA(h,t,c,u);
end;
begin
  // this message box will not display on start up on DLL load
  MessageBoxA(0,'Test Message','Caption',0);
end.

I would like to write assembly Code that can compiled with yasm.exe or nasm.exe under the Command Line/Console/Terminal to an executable.


@Margaret Bloom: the smallest/full reproduce example is this one:

BITS 64

%define align(n,r) (((n+(r-1))/r)*r)

; DOS Header
    dw 'MZ'                 ; e_magic
    dw 0                    ; [UNUSED] e_cblp
    dw 0                    ; [UNUSED] c_cp
    dw 0                    ; [UNUSED] e_crlc
    dw 0                    ; [UNUSED] e_cparhdr
    dw 0                    ; [UNUSED] e_minalloc
    dw 0                    ; [UNUSED] e_maxalloc
    dw 0                    ; [UNUSED] e_ss
    dw 0                    ; [UNUSED] e_sp
    dw 0                    ; [UNUSED] e_csum
    dw 0                    ; [UNUSED] e_ip
    dw 0                    ; [UNUSED] e_cs
    dw 0                    ; [UNUSED] e_lfarlc
    dw 0                    ; [UNUSED] e_ovno
    times 4 dw 0            ; [UNUSED] e_res
    dw 0                    ; [UNUSED] e_oemid
    dw 0                    ; [UNUSED] e_oeminfo
    times 10 dw 0           ; [UNUSED] e_res2
    dd pe_hdr               ; e_lfanew

; PE Header
pe_hdr:
    dw 'PE', 0              ; Signature

; Image File Header
    dw 0x8664               ; Machine
    dw 0x01                 ; NumberOfSections
    dd 0                    ; [UNUSED] TimeDateStamp
    dd 0                    ; PointerToSymbolTable
    dd 0                    ; NumberOfSymbols
    dw opt_hdr_size         ; SizeOfOptionalHeader
    dw 0x22                 ; Characteristics

; Optional Header, COFF Standard Fields
opt_hdr:
    dw 0x020b               ; Magic (PE32+)
    db 0x0e                 ; MajorLinkerVersion
    db 0x16                 ; MinorLinkerVersion
    dd code_size            ; SizeOfCode
    dd 0                    ; SizeOfInitializedData
    dd 0                    ; SizeOfUninitializedData
    dd entry                ; AddressOfEntryPoint
    dd iatbl                ; BaseOfCode

; Optional Header, NT Additional Fields
    dq 0x000140000000       ; ImageBase
    dd 0x10                 ; SectionAlignment
    dd 0x10                 ; FileAlignment
    dw 0x06                 ; MajorOperatingSystemVersion
    dw 0                    ; MinorOperatingSystemVersion
    dw 0                    ; MajorImageVersion
    dw 0                    ; MinorImageVersion
    dw 0x06                 ; MajorSubsystemVersion
    dw 0                    ; MinorSubsystemVersion
    dd 0                    ; Reserved1
    dd file_size            ; SizeOfImage
    dd hdr_size             ; SizeOfHeaders
    dd 0                    ; CheckSum
    dw 0x02                 ; Subsystem (Windows GUI)
    dw 0x8160               ; DllCharacteristics
    dq 0x100000             ; SizeOfStackReserve
    dq 0x1000               ; SizeOfStackCommit
    dq 0x100000             ; SizeOfHeapReserve
    dq 0x1000               ; SizeOfHeapCommit
    dd 0                    ; LoaderFlags
    dd 0x02                 ; NumberOfRvaAndSizes

; Optional Header, Data Directories
    dd 0                    ; Export, RVA
    dd 0                    ; Export, Size
    dd itbl                 ; Import, RVA
    dd itbl_size            ; Import, Size

opt_hdr_size equ $-opt_hdr

; Section Table
    section_name db '.'     ; Name
    times 8-($-section_name) db 0
    dd sect_size            ; VirtualSize
    dd iatbl                ; VirtualAddress
    dd code_size            ; SizeOfRawData
    dd iatbl                ; PointerToRawData
    dd 0                    ; PointerToRelocations
    dd 0                    ; PointerToLinenumbers
    dw 0                    ; NumberOfRelocations
    dw 0                    ; NumberOfLinenumbers
    dd 0x60000020           ; Characteristics

hdr_size equ $-$$

code:
; Import Address Directory
iatbl:
    dq symbol
    dq 0

iatbl_size equ $-iatbl

; Strings
title:
    db "Hallo Welt !!!", 0
content:
    db "ABCDEFGHIJKL", 0

; Entry
entry:
; the comment block there are my interest in - why does it not work
    mov r9d, 0x00240040     ; uType
    lea r8, [rel title]     ; lpCaption
    lea rdx, [rel content]  ; lpText
    xor ecx, ecx            ; hWnd
    jmp [rel iatbl]         ; MessageBoxN

    times align($-$$,16)-($-$$) db 0xcc

; Import Directory
itbl:
    dq intbl                ; OriginalFirstThunk
    dd 0                    ; TimeDateStamp
    dd dll_name             ; ForwarderChain
    dd iatbl                ; Name
    dq 0                    ; FirstThunk

itbl_size equ $-itbl

; Import Name Table
intbl:
    dq symbol
    dq 0

; Symbol
symbol:
    dw 0x0294               ; [UNUSED] Function Order
    db 'MessageBoxA', 0     ; Function Name
dll_name:
    db 'USER32.dll', 0
    db 0

sect_size equ $-code

    times align($-$$,16)-($-$$) db 0

code_size equ $-code
file_size equ $-$$

I would extend the Assembly Script above so, that I can use more than one win32api Functions. So, I would use a second, third, ... Function from my own .DLL Files on ground of the existing Code above.


Solution

  • The following code will do what I want. It can be compiled with NASM, and it (the resulting flat image executable .EXE) shows a Ansi-, and a Unicode Version of MessageBoxA/W described in the Microsoft documentation. This can be used to create a Flat Image on the fly with NASM assembly.

    SECTIONS   equ 2
    TIME_DATE   equ 0
    IMAGE_BASE        equ    0x000140000000 ;0x400000 ; org
    SECTION_ALIGNMENT   equ     0x200
    FILE_ALIGNMENT    equ      0x200
    
    BSS_SIZE equ 0
    
    %define nagoa_round(size) ((size + SECTION_ALIGNMENT - 1) & ~(SECTION_ALIGNMENT - 1))
    
    bits 64
    org IMAGE_BASE
    
    section .text
    
    ;;******************************************************************************************************
    ;; if the header is part of the image, define it as section .text because .text is put
    ;; first in the image, and rename the code section as section .code
    
    header:
    
       dw "MZ"                   ; e_magic
       dw 0                       ; e_cblp
       dw 0                       ; e_cp
       dw 0                       ; e_crlc
       dw 0                       ; e_cparhdr
       dw 0                       ; e_minalloc
       dw 0                       ; e_maxalloc
       dw 0                       ; e_ss
       dw 0                       ; e_sp
       dw 0                       ; e_csum
       dw 0                       ; e_ip
       dw 0                       ; e_cs
       dw 0                       ; e_lsarlc
       dw 0                       ; e_ovno
       dq 0                       ; e_res
       dw 0                       ; e_oemid
       dw 0                       ; e_oeminfo
       dd 0,0,0,0,0                    ; e_res2
       dd imageHeader - IMAGE_BASE   ; e_lfanew
    
    imageHeader:
    
       dd "PE"               ; Signature
       dw 0x8664              ; Machine
       dw SECTIONS           ; NumberOfSections
       dd TIME_DATE          ; TimeDateStamp
       dd 0                   ; PointerToSymbolTable
       dd 0                   ; NumberOfSymbols
       dw optionalHeader.SIZE   ; SizeOfOptionalHeader
       dw 0x022               ; Characteristics
    
    optionalHeader:
    
        dw 0x20B                      ; Magic
        db 0                           ; MajorLinkerVersion
        db 0                           ; MinorLinkerVersion
        dd nagoa_round(RAW_CODE.SIZE)   ; SizeOfCode
        dd nagoa_round(RAW_DATA.SIZE)   ; SizeOfInitializedData
        dd nagoa_round(BSS_SIZE)      ; SizeOfUninitializedData
        dd entryPoint                 ; AddressOfEntryPoint
        dd code                        ; BaseOfCode
        ;dd data - IMAGE_BASE          ; BaseOfData
        dq IMAGE_BASE                 ; ImageBase
        dd SECTION_ALIGNMENT          ; SectionAlignment
        dd FILE_ALIGNMENT             ; FileAlignment
        dw 4                           ; MajorOperatingSystemVersion
        dw 0                           ; MinorOperatingSystemVersion
        dw 0                           ; MajorImageVersion
        dw 0                           ; MinorImageVersion
        dw 4                           ; MajorSubsystemVersion
        dw 0                           ; MinorSubsystemVersion
        dd 0                           ; Win32VersionValue
        dd (RAW_HEADER.SIZE + RAW_CODE.SIZE + RAW_DATA.SIZE); SizeOfImage
    
        dd RAW_HEADER.SIZE            ; SizeOfHeaders
        dd 0                           ; CheckSum
        dw 2                           ; Subsystem
        dw 0                           ; DllCharacteristics
        dq 0x40000                     ; SizeOfStackReserve
        dq 0x6000                      ; SizeOfStackCommit
        dq 0x100000                    ; SizeOfHeapReserve
        dq 0x1000                      ; SizeOfHeapCommit
        dd 0                           ; LoaderFlags
        dd 16                          ; NumberOfRvaAndSizes
       dd 0, 0                        ; IMAGE_DIRECTORY_ENTRY_EXPORT
       dd Import_Directory_Table, Import_Directory_Table_Size                       ; IMAGE_DIRECTORY_ENTRY_IMPORT
       dd 0, 0                        ; IMAGE_DIRECTORY_ENTRY_RESOURCE
       dd 0, 0                        ; IMAGE_DIRECTORY_ENTRY_EXCEPTION
       dd 0, 0                        ; IMAGE_DIRECTORY_ENTRY_SECURITY
       dd 0, 0                        ; IMAGE_DIRECTORY_ENTRY_BASERELOC
       dd 0, 0                        ; IMAGE_DIRECTORY_ENTRY_DEBUG
       dd 0, 0                        ; IMAGE_DIRECTORY_ENTRY_COPYRIGHT
       dd 0, 0                        ; IMAGE_DIRECTORY_ENTRY_GLOBALPTR
       dd 0, 0                        ; IMAGE_DIRECTORY_ENTRY_TLS
       dd 0, 0                        ; IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
       dd 0, 0                        ; IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
       ;dd Import_Address_Table, Import_Address_Table_Size                       ; IMAGE_DIRECTORY_ENTRY_IAT
       dd 0,0
       dd 0, 0                        ; IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT
       dd 0, 0                        ; IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
       dd 0, 0                        ; reserved
    
    optionalHeader.SIZE equ $ - optionalHeader
    
    sectionHeaders:
    
        db ".text", 0, 0, 0            ; Name
        dd nagoa_round(RAW_CODE.SIZE)   ; VirtualSize
        dd code                       ; VirtualAddress
        dd RAW_CODE.SIZE              ; SizeOfRawData
        dd RAW_CODE.OFFSET            ; PointerToRawData
        dd 0                           ; PointerToRelocations
        dd 0                           ; PointerToLinenumbers
        dw 0                           ; NumberOfRelocations
        dw 0                           ; NumberOfLinenumbers
        dd 0x60000020                  ; Characteristics
    
        db ".data", 0, 0, 0            ; Name
        dd nagoa_round(RAW_DATA.SIZE)   ; VirtualSize
        dd data                       ; VirtualAddress
        dd RAW_DATA.SIZE              ; SizeOfRawData
        dd RAW_DATA.OFFSET            ; PointerToRawData
        dd 0                           ; PointerToRelocations
        dd 0                           ; PointerToLinenumbers
        dw 0                           ; NumberOfRelocations
        dw 0                           ; NumberOfLinenumbers
        dd 0xC0000040                  ; Characteristics
    
    align FILE_ALIGNMENT, db 0
    RAW_HEADER.SIZE equ $ - header
    
    ;;******************************************************************************************************
    ;;   F I R S T  . c o d e  S E C T I O N
    ;;******************************************************************************************************
    
    VS_CODE   EQU ( ( ( 1 + ( (RAW_HEADER.SIZE-1) >> 12 ) ) * SECTION_ALIGNMENT ) )
    
    section .code vstart=VS_CODE
    
       code:
       entryPoint:
          mov rcx,500
          call [rel Sleep]
          mov r9d, 0x00240040 ; uType
          lea r8, [rel title] ; lpCaption
          lea rdx, [rel content] ; lpText
          xor ecx, ecx ; hWnd
          call [rel MessageBoxA]
          mov rcx,500
          call [rel Sleep]
          mov r9d, 0x00240040 ; uType
          lea r8, [rel TITLE_W] ; lpCaption
          lea rdx, [rel CONTENT_W] ; lpText
          xor ecx, ecx ; hWnd
          call [rel MessageBoxW]
          jmp [rel ExitProcess]
    
       align SECTION_ALIGNMENT, db 0
    
    ;;******************************************************************************************************
    ;;   F I R S T  . d a t a  S E C T I O N
    ;;******************************************************************************************************
    
    VS_DATA   EQU ( VS_CODE + ( ( 1 + ( (RAW_CODE.SIZE-1) >> 12 ) ) * SECTION_ALIGNMENT ) )
    
    section .data vstart=VS_DATA
    data :
        Import_Address_Table:
          DLL_1:
            Sleep:         dq I_Sleep
            ExitProcess:   dq I_ExitProcess
            GetStdHandle:  dq I_GetStdHandle
            dq              0
          DLL_2:
          MessageBoxA    dq I_MessageBoxA
          MessageBoxW    dq I_MessageBoxW
          dq              0
       Import_Address_Table_Size equ $ - Import_Address_Table
       
          align 0x20, db 0
            Import_Directory_Table:
                KERNEL32.originalfthk    dd DLL_1_thunk_table
                KERNEL32.timedate        dd 0 
                KERNEL32.forwarder       dd 0 
                KERNEL32.name            dd dll_name_1
                KERNEL32.firstthunk      dd DLL_1
    
                USER32.originalfthk    dd DLL_2_thunk_table
                USER32.timedate        dd 0 
                USER32.forwarder       dd 0 
                USER32.name            dd dll_name_2
                USER32.firstthunk      dd DLL_2
             
          align 0x20, db 0            ; should be always at the end of Import_Directory_Table
          
          Import_Directory_Table_Size equ $ - Import_Directory_Table
    
          DLL_1_thunk_table :
             dq I_Sleep
             dq   I_ExitProcess
             dq   I_GetStdHandle
             dq 0
          DLL_2_thunk_table :
             dq I_MessageBoxA
             dq   I_MessageBoxW
             dq 0
            I_Sleep:          
                dw               0
                db               'Sleep', 0 
                align            2 , db 0 
            I_ExitProcess:  
                dw               0 
                db               'ExitProcess', 0
                align            2 , db 0 
            I_GetStdHandle:
                dw               0 
                db               'GetStdHandle', 0
             align            2 , db 0 
            I_MessageBoxA:
                dw               0 
                db               'MessageBoxA', 0
             align            2 , db 0 
            I_MessageBoxW:
                dw               0 
                db               'MessageBoxW', 0
             align            2 , db 0 
            dll_name_1:            db 'kernel32.dll', 0
            dll_name_2:           db 'user32.dll', 0
       
        STRING_TABLE:
       %define u(x) __?utf16le?__(x)
       %define w(x) __?utf32le?__(x)
       title:
             db "Hello world !!!", 0
             align            2 , db 0 
       content:
             db "ABCDEFGHIJKL", 0
             align            2 , db 0    
       TITLE_W:         
             dw u("Hello World !!! in Unicode"),0
             align            2 , db 0 
       CONTENT_W:
             db u("ABCDEFGHIJKL"), 0
             align            2 , db 0 
       align SECTION_ALIGNMENT, db 0
    ;;******************************************************************************************************
    ;;   L A S T  . c o d e  S E C T I O N
    ;;******************************************************************************************************
    section .code
    
    align FILE_ALIGNMENT, db 0
    
    RAW_CODE.OFFSET   equ RAW_HEADER.SIZE
    RAW_CODE.SIZE   equ $ - $$
    
    ;;******************************************************************************************************
    ;;   L A S T  . d a t a  S E C T I O N
    ;;******************************************************************************************************
    section .data
    
    align FILE_ALIGNMENT, db 0
    
    RAW_DATA.OFFSET   equ RAW_CODE.OFFSET + RAW_CODE.SIZE
    RAW_DATA.SIZE   equ $ - $$
    
    ;;******************************************************************************************************
    
    IMAGE_END equ $
    
    ;; -- eof --