Created
September 2, 2022 17:07
-
-
Save typeswitch-dev/700d4d3fc5226bd9949c2da8b0306905 to your computer and use it in GitHub Desktop.
Minimal win64 executable in NASM assembly.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
org 0 ; We use "org 0" so Relative Virtual Addresses (RVAs) are easy. | |
; This means that when we want an absolute Virtual Address we have | |
; to add IMAGE_BASE to the RVA (or whatever the base of that section is) | |
IMAGE_BASE equ 0x400000 | |
SECT_ALIGN equ 0x200 | |
FILE_ALIGN equ 0x200 | |
msdos_header: | |
.magic db 'MZ' | |
.cblp dw 0x0090 ; bytes on last page of file | |
.cp dw 0x0003 ; pages in file | |
.crlc dw 0x0000 ; relocations | |
.cparhdr dw 0x0004 ; size of header in paragraphs | |
.minalloc dw 0x0000 ; minimum extra paragraphs needed | |
.maxalloc dw 0xFFFF ; maximum extra paragraphs needed | |
.ss dw 0x0000 ; initial (relative) SS value | |
.sp dw 0x00B8 ; initial SP value | |
.csum dw 0x0000 ; checksum | |
.ip dw 0x0000 ; initial IP value | |
.cs dw 0x0000 ; initial (relative) CS value | |
.lfarlc dw 0x0040 ; file address of relocation table | |
.ovno dw 0x0000 ; overlay number | |
.res dw 0,0,0,0 ; reserved words | |
.oemid dw 0x0000 ; OEM identifier | |
.oeminfo dw 0x0000 ; OEM information | |
.res2 times 10 dw 0 ; reserved words | |
.lfanew dd pe_header ; relative address of PE header | |
bits 16 | |
msdos_program: | |
.entry push cs | |
pop ds | |
mov dx, .message - .entry | |
mov ah, 0x09 | |
int 0x21 | |
mov ax, 0x4C01 | |
int 0x21 | |
.message db "This program cannot be run in DOS mode.", 0xD, 0xD, 0xA, '$' | |
times 0x80 + msdos_header - $ db 0x00 | |
pe_header: | |
.magic db 'PE', 0, 0 | |
.machine dw 0x8664 ; x86-64 | |
.nsections dw 1 ; number of sections | |
.timestamp dd 0 ; 32-bit timestamp for program | |
.symtable dd 0 ; symbol table location (0 for image file) | |
.nsymbols dd 0 ; number of symbols (0 for image file) | |
.opthdrsize dw opt_header.end - opt_header ; size of "optional" header | |
.chrctrstcs dw 0x0022 ; 0x0002 = IMAGE_FILE_EXECUTABLE_IMAGE | |
; 0x0020 = IMAGE_FILE_LARGE_ADDRESS_AWARE | |
opt_header: | |
.magic dw 0x020B ; PE32+ (i.e. a 64-bit PE file) | |
.linkver db 0, 0 | |
.codesize dd code_section_end - code_section ; size of code section | |
.datasize dd 0 ; size initialized data | |
.bsssize dd 0 ; size uninitialized data | |
.entry dd main ; relative address of entry point | |
.codebase dd code_section ; relative address of code section | |
.imagebase dq IMAGE_BASE | |
.sectalign dd SECT_ALIGN ; alignment of sections in VM | |
.filealign dd FILE_ALIGN ; alignment of sections in file | |
.osver dw 6, 0 | |
.imgver dw 0, 0 | |
.subsysver dw 6, 0 | |
.win32ver dd 0 | |
.sizeimage dd image_end ; size of image (multiple of SECT_ALIGN) | |
.sizehdrs dd headers_end ; size of headers (multiple of FILE_ALIGN) | |
.checksum dd 0 | |
.subsystem dw 3 ; windows console subsystem (2 for gui) | |
.dllchars dw 0x8140 ; 0x0040 = DLL can be relocated at load time | |
; 0x0100 = image is NX compatible | |
; 0x8000 = Terminal server aware | |
.stkresv dq 0x100000 | |
.stkcommit dq 0x1000 | |
.heapresv dq 0x100000 | |
.heapcommit dq 0x1000 | |
.loaderflgs dd 0 ; reserved, must be 0 | |
.nrvasize dd (.end-.edata)/8 ; number of entries in "data directory" | |
.edata dd 0, 0 ; (which is still part of optional header) | |
.idata dd import_table | |
dd import_table.end - import_table | |
.res dd 0, 0 | |
.exn dd 0, 0 | |
.sec dd 0, 0 | |
.reloc dd 0, 0 | |
.debug dd 0, 0 | |
.arch dd 0, 0 | |
.gp dd 0, 0 | |
.tls dd 0, 0 | |
.lconfig dd 0, 0 | |
.bimport dd 0, 0 | |
.iat dd iat | |
dd iat.end - iat | |
.dimport dd 0, 0 | |
.com dd 0, 0 | |
.resvd dd 0, 0 | |
.end: | |
code_section_header: | |
.name db ".text",0,0,0 | |
.vsize dd code_section_end - code_section | |
.vaddr dd code_section | |
.psize dd code_section_end - code_section | |
.paddr dd code_section | |
.preloc dd 0 | |
.plines dd 0 | |
.nreloc dw 0 | |
.nlines dw 0 | |
.chars dd 0xE0000020 ; 0x00000020 = IMAGE_SCN_CNT_CODE | |
; 0x20000000 = IMAGE_SCN_MEM_EXECUTE | |
; 0x40000000 = IMAGE_SCN_MEM_READ | |
; 0x80000000 = IMAGE_SCN_MEM_WRITE | |
.end align FILE_ALIGN | |
headers_end: align SECT_ALIGN ; headers must be file aligned | |
code_section: ; section must be section aligned | |
import_table: | |
.ilt dd ilt | |
.ts dd 0 | |
.fc dd 0 | |
.name dd names.kernel32_dll | |
.iat dd iat | |
.null dd 0,0,0,0,0 | |
.end align 8 | |
ilt: | |
.ExitProcess dq names.ExitProcess | |
.CreateFileA dq names.CreateFileA | |
.WriteFile dq names.WriteFile | |
.null dq 0 | |
.end align 8 | |
iat: | |
.ExitProcess dq names.ExitProcess | |
.CreateFileA dq names.CreateFileA | |
.WriteFile dq names.WriteFile | |
.null dq 0 | |
.end align 8 | |
names: ; each entry should be aligned on an even boundary by zero-padding | |
; also a 2 byte "hint" is needed for imported function names | |
; -- using 0,0 is fine, the loader falls back to binary search | |
.kernel32_dll db "kernel32.dll",0,0 | |
.ExitProcess db 0,0,"ExitProcess",0 | |
.CreateFileA db 0,0,"CreateFileA",0 | |
.WriteFile db 0,0,"WriteFile",0 | |
.end align 8 | |
bits 64 | |
; PROGRAM ENTRY | |
main: sub rsp, 32 ; "the shadow space" | |
mov rcx, 42 | |
.bye call [rel iat.ExitProcess] | |
jmp .bye | |
align FILE_ALIGN | |
code_section_end: | |
align SECT_ALIGN | |
image_end: | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment