Assembly language examples using NASM on Windows

Extra information




The %define preprocessor directive
My code examples use %define to replace local variables and registers with a more descriptive word.
NASM will automatically replace these words with their proper meaning.

Note
This could possibly lead to more code readability issues than it solves, as the instruction may look invalid, or have a double meaning.

Example
Local variables are usually given as an offset to EBP, but this is not descriptive of what it represents.

                                                ; %define preprocessor directive example
%define OrderNumber EBP - 4                     ; Use "OrderNumber" in place of EBP - 4

mov   EAX, dword [OrderNumber]                  ; mov  EAX, dword [EBP - 4]


Example
x64 has 16 general purpose registers, where possible, use registers before resorting to memory variables.
Renaming a register to something more descriptive will make the code objectives easier to follow.

                                                ; %define preprocessor directive example
%define Form        R8                          ; Use "Form" in place of R8 
%define Quantity    R9                          ; Use "Quantity" in place of R9
%define BaseAddress R10                         ; Use "BaseAddress" in place of R10
%define Offset      R11                         ; Use "Offset" in place of R11
%define Position    R12                         ; Use "Position" in place of R12

mov   Form, 27B6h                               ; mov  R8, 27B6h
mov   Quantity, 400h                            ; mov  R9, 400h

lea   Position, [BaseAddress + Offset]          ; lea  R12, [R10 + R11]



Why use EAX instead of RAX?
For shorter instruction encodings, use the 8 Extended registers instead of an R register, but only for data up to 32 bits.
The upper 32 bits of the R register will be set to zero.

                                                ; Equivalent instructions
mov  EAX, 1                                     ; B801000000, 5 bytes
mov  RAX, 1                                     ; 48B80100000000000000, 10 bytes


Where appropriate, NASM performs this optimisation automatically.


32 bit Windows API functions
Function names are decorated with a _ prefix and an @ + number suffix.

For example, if the Windows API documentation calls it WriteFile, we would use _WriteFile@20.
@20 is the total number of bytes used by its parameters. WriteFile takes 5 double words = 20 bytes.

The parameters are pushed onto the stack in reverse order.
WriteFile (hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped) would be

                                                ; 32 bit Windows API functions
push  lpOverlapped                              ; 5th parameter
push  lpNumberOfBytesWritten                    ; 4th parameter
push  nNumberOfBytesToWrite                     ; 3rd parameter
push  lpBuffer                                  ; 2nd parameter
push  hFile                                     ; 1st parameter
call  _WriteFile@20                             ; 32 bit decorated Windows API function



Stack alignment for 64 bit Windows API functions
The stack should be 16 byte aligned before calling a Windows API function, but the stack will be 8 byte aligned on entry.
To align to 16 bytes, use the following as your program's first instruction. From then on, you should keep the stack balanced.

                                                ; Windows 64 bit stack alignment
Start:
sub   RSP, 8                                    ; Align the stack to a multiple of 16 bytes




64 bit Windows API functions
Function names are not decorated as they are in 32 bit.

The first 4 parameters are passed in RCX, RDX, R8 and R9. The other parameters are put on to the stack.
There should be enough space on the stack for the function to spill the 4 parameters, this is called Shadow Space.
If the function parameters misalign the stack, extra bytes should be added to realign it.

Example
If the function takes 5 parameters, we would allocate 48 bytes (32 + 8 + 8)
Remember to remove the same number of bytes after the function returns.

WriteFile (hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped) would be

                                                ; 64 bit Windows API functions
and   RSP, 0FFFFFFFFFFFFFFF0h                   ; Align the stack to a multiple of 16 bytes

sub   RSP, 32 + 8 + 8                           ; Shadow space + 5th parameter + align stack
                                                ; to a multiple of 16 bytes

mov   RCX, hFile                                ; 1st parameter
mov   RDX, lpBuffer                             ; 2nd parameter
mov   R8, nNumberOfBytesToWrite                 ; 3rd parameter
mov   R9, lpNumberOfBytesWritten                ; 4th parameter
mov   qword [RSP + 4 * 8], lpOverlapped         ; 5th parameter
call  WriteFile                                 ; 64 bit Windows API function (not decorated)

add   RSP, 48                                   ; Remove the 48 bytes



64 bit Windows structures

Example - MSG structure

                                                ; MSG structure. 48 bytes
section .bss
alignb 8
 msg.hwnd            resq 1                     ; 8 bytes
 msg.message         resd 1                     ; 4 bytes
 msg.Padding1        resd 1                     ; 4 bytes. Natural alignment padding
 msg.wParam          resq 1                     ; 8 bytes
 msg.lParam          resq 1                     ; 8 bytes
 msg.time            resd 1                     ; 4 bytes
 msg.py.x            resd 1                     ; 4 bytes
 msg.pt.y            resd 1                     ; 4 bytes
 msg.Padding2        resd 1                     ; 4 bytes. Structure length padding


Example - PAINTSTRUCT struture

                                                ; PAINTSTRUCT structure. 72 bytes
section .bss
alignb 8
 ps.hdc              resq 1                     ; 8 bytes
 ps.fErase           resd 1                     ; 4 bytes
 ps.rcPaint.left     resd 1                     ; 4 bytes
 ps.rcPaint.top      resd 1                     ; 4 bytes
 ps.rcPaint.right    resd 1                     ; 4 bytes
 ps.rcPaint.bottom   resd 1                     ; 4 bytes
 ps.Restore          resd 1                     ; 4 bytes
 ps.fIncUpdate       resd 1                     ; 4 bytes
 ps.rgbReserved      resb 32                    ; 32 bytes
 ps.Padding          resd 1                     ; 4 bytes. Structure length padding


Example - WNDCLASSEX struture

                                                ; WNDCLASSEX structure. 80 bytes
section .bss
alignb 8
 wc.cbSize           resd 1                     ; 4 bytes
 wc.style            resd 1                     ; 4 bytes
 wc.lpfnWndProc      resq 1                     ; 8 bytes
 wc.cbClsExtra       resd 1                     ; 4 bytes
 wc.cbWndExtra       resd 1                     ; 4 bytes
 wc.hInstance        resq 1                     ; 8 bytes
 wc.hIcon            resq 1                     ; 8 bytes
 wc.hCursor          resq 1                     ; 8 bytes
 wc.hbrBackground    resq 1                     ; 8 bytes
 wc.lpszMenuName     resq 1                     ; 8 bytes
 wc.lpszClassName    resq 1                     ; 8 bytes
 wc.hIconSm          resq 1                     ; 8 bytes