模板

default rel ; default using relative address, can prevent some reloc
global _start
section .text

%define u(x) __?utf16?__(x) ; can use u('123') to define utf-16 string

_start:

lea rdi, [msg_ascii] ; or you should use `lea rax, [rel message]` without `default rel`
mov rax, msg_ascii_len ; mov length (value, not ref) to rax

mov     ax,11001000b ; binary

jmp stop

stop:
    times 64 db 0x90 ; fill 64 nop
    ret
; function calling convention mark:
;   for example (linux)[linux, windows]:
;       self and sub function including linux and windows call
;       current function use linux call
;       caller must make sure preserve callee saved regs
;       and if current function is windows call,
;       make sure preserve 0x20 space on stack
;   or for example (linux)[rdi, rsi, rcx, rdx, rax]:
;       means only `rdi, rsi, rcx, rdx, rax` will change by function

; windows safe reg: rbx, rbp, rdi, rsi, rsp, r12, r13, r14, r15
; linux safe reg: rbx, rbp, rsp, r12, r13, r14, r15 (windows -rdi, -rsi)

; memcmp(addr1: rdi, addr2: rsi, length: edx)
;   rax: 0 -> same
;        1 -> not the same
;   (linux)[rdi, rsi, rcx, rdx, rax]
memcmp:
    mov ecx, edx
    repe cmpsb
    setne al
    movzx eax, al
    ret

; memset(dst: rdi, value: sil, length: edx)
;   (linux)[rdi, rsi, rcx, rdx, rax]
memset:
    mov eax, esi
    mov ecx, edx
    rep stosb
    ret

; memcpy(dst: rdi, src: rsi, length: edx)
;   (linux)[rdi, rsi, rcx, rdx, rax]
memcpy:
    mov ecx, edx
    rep movsb
    ret

; strlen(str: rdi)
;   eax: length
;   (linux)[rdi, rcx, rax]
strlen:
    xor ecx, ecx    ; ecx = 0
    dec ecx         ; ecx = -1 (0xFFFFFFFF)
    ; rcx = maximum length to scan
    xor eax, eax    ; eax = 0 (al = 0 value to scan for)
    cld             ; clear DF, rep will mov forward, rcx will dec
    repne scasb     ; scan the memory for AL
    sub eax, ecx    ; eax = 0 - ecx_leftover = scanned bytes + 1
    sub eax, 2      ; fix that into "string length" (-1 for '\\0')
    ret

; strcmp(str1: rdi, str2: rsi)
;   rax: 0 -> same
;        1 -> not the same
;   (linux)[rdi, rsi, rcx, rdx, rax, r8]
strcmp:
    mov r8, rdi     ; save str1 to r8
    call strlen     ; get str1 len
    mov rdi, r8
    mov edx, eax
    inc edx         ; compare including ending NULL byte
    call memcmp     ; memcmp(str1, str2, strlen(str1) + 1)
    ret

section .data

msg_ascii:      db      '123', 0
msg_ascii_len:  equ     $-msg_ascii ; represent msg_ascii, a const, will not present in final shellcode

msg_16:         dw      u('hello, world'), 0
msg_16_len:     equ     $-msg_16

buffer:         resb    64              ; reserve 64 bytes

db `\\u263a`            ; unicode, will be store in UTF-8, a smiley face 
db `\\xe2\\x98\\xba`      ; hex bytes

字符串、常量等内容:

NASM Manual

NASM Tutorial (lmu.edu)

Compile to Win64

需要Mingw-w64的ld

注意链接出的.text段不可写,只有RX,需要RWX可以加上 -N 参数

nasm ./sc.asm -fwin64 -o sc.o
C:\\msys64\\mingw64\\bin\\ld.exe .\\sc.o -o sc.exe