Assembly-00: Step 0 for Everyone
Saying hi in x64 assembly using MASM, covering C runtime integration and Windows API calls.
If you’re reverse engineering binaries or messing with low-level exploits, you can’t skip learning assembly. High-level languages sugarcoat everything. Assembly is where you see exactly what’s happening—every register, every call, every push and pop. It’s the bedrock of malware analysis, debugging, and exploitation.
This post is about writing simple x64 assembly on Windows, outputting text to the console using both the C runtime and the Windows API, so you can see how it all actually works under the hood.
NASM vs MASM: Which One Should You Use?
You’ll see both out there. Here’s the quick breakdown:
NASM (Netwide Assembler)
- Open-source and cross-platform.
- Great for bare-metal work, OS devs, and anyone outside the Microsoft ecosystem.
- Syntax is clean and explicit—no surprises.
- You’ll need to do a lot yourself: linking, calling conventions, you name it.
MASM (Microsoft Macro Assembler)
- Windows-native and Visual Studio-friendly.
- Tightly integrated with Microsoft’s toolchain.
- Comes with macros, language extensions, and better support for structured programming.
- If you’re reversing on Windows or integrating with C code or Windows API—MASM is your go-to.
Here’s a fast reference if you’re picking a side:
Feature | NASM | MASM |
---|---|---|
License | BSD | Microsoft Proprietary |
Platform | Cross-platform | Windows only |
Syntax | Bare-bones | Macro-rich |
Integration | Manual | Visual Studio native |
Best For | Bootloaders, x-plat | Windows reversing, system-level coding |
Now let’s code.
Console Output with MASM: Two Ways to Say Hello
You’re going to print "Hello, Reader!"
to the screen—once using the C runtime (printf
) and once using the Windows API (WriteConsoleA
).
Method 1: C Runtime (printf
)
.data
msg db "Hello, Reader!", 0
format db "%s", 10, 0
.code
extrn printf:proc
hello proc public
lea rax, offset msg
ret
hello endp
main proc
sub rsp, 40
call hello
lea rcx, format
mov rdx, rax
call printf
add rsp, 40
xor eax, eax
ret
main endp
end
What’s Happening?
- .data: Message string and printf format.
- hello: Returns the address of the string.
- main: Sets up stack (Windows x64 ABI requires shadow space), sets up arguments, calls
printf
, exits cleanly.
Make sure you link:
ml64 /c hello.asm
link hello.obj /subsystem:console /defaultlib:msvcrt.lib /defaultlib:legacy_stdio_definitions.lib
This method is fine if you don’t mind the C runtime. Want to go lower? Read on.
Method 2: Straight Windows API.
.data
msg db "Hello, Reader!", 13, 10, 0
.code
extrn ExitProcess:proc
extrn GetStdHandle:proc
extrn WriteConsoleA:proc
main proc
sub rsp, 48
mov rcx, -11
call GetStdHandle
mov r12, rax
mov rcx, r12
lea rdx, msg
mov r8, 15
lea r9, [rsp+32]
mov qword ptr [rsp+32], 0
mov qword ptr [rsp+40], 0
call WriteConsoleA
add rsp, 48
xor rcx, rcx
call ExitProcess
main endp
end
Why Bother With This?
- No runtime dependencies.
- You’re fully in control.
- You get direct access to Windows internals.
Call Flow:
- Grab the console handle with
GetStdHandle
. - Use
WriteConsoleA
to print your message. - Clean up and exit via
ExitProcess
.
Build it:
ml64 /c hello_winapi.asm
link /SUBSYSTEM:CONSOLE /ENTRY:main hello_winapi.obj kernel32.lib
This is as raw as Windows programming gets.
Final Thoughts
Assembly isn’t going away—and honestly, it’s not as scary as people make it sound. It’s just precise. More like this coming soon. Until then, keep it low-level and as always, may your analysis be quick and your code easy to crack!