To understand software, sometimes you have to stop using the abstraction and build it yourself.
Understanding Windows systems programming by removing the abstractions and building them again from the machine level.
Win32 MASM SDK is a custom low-level SDK/runtime project written entirely in 32-bit x86 MASM Assembly.
Instead of relying on an existing assembly framework or SDK such as MASM32, this project manually defines the required Windows types, constants, API prototypes, data structures, runtime interfaces, and utility procedures.
The goal is not simply to "write Assembly."
The goal is to understand what actually happens underneath abstractions such as:
- Standard input/output
- Strings
- Integer conversion
- Memory allocation
- Function calls
- Calling conventions
- Runtime libraries
- Error handling
- Static libraries
- Linker symbol resolution
- Object files
- Windows API interaction
Everything is built incrementally from the ground up.
| Component | Technology |
|---|---|
| Architecture | x86 / IA-32 |
| Assembly | Microsoft Macro Assembler (MASM) |
| Syntax | Intel syntax |
| Calling Convention | __stdcall |
| Platform | Windows |
| IDE | Visual Studio |
| Build System | MSBuild |
| Linker | Microsoft LINK |
| Output | Static .lib |
| Windows APIs | Win32 API |
Don't just use the abstraction. Build the abstraction.
High-level languages make concepts look simple such as:
- Console Input
- Console Output
- Strings
- Integers
- Memory
- Functions
- Exceptions
- Objects
This project explores what those concepts actually require when working directly with:
- Registers
- Stack
- Memory
- Pointers
- Flags
- Calling Conventions
- Windows API
- Linker
- Object Files
One of the fundamental goals of this project is to understand the Windows API without hiding it behind a pre-built assembly SDK.
The project therefore defines its own:
- Windows data types
- Constants
- Handles
- Pointer types
- API prototypes
- Library imports
For example:
GetStdHandle PROTO STDCALL, nStdHandle: DWORD
WriteConsoleA PROTO STDCALL,
hConsoleOutput: HANDLE,
lpBuffer: LPCVOID,
nNumberOfCharsToWrite: DWORD,
lpNumberOfCharsWritten: LPDWORD,
lpReserved: LPVOIDThe APIs are then linked directly against the Windows system libraries.
The project contains a custom console runtime built on top of the Win32 Console API.
It maintains its own console state __console:
-
stdIn (Standard Input Stream)
- hStdIn โ Handle to the input stream.
- nLength โ Stream buffer length.
- position โ Current read pointer index.
- buffer โ Raw input data storage.
-
stdOut (Standard Output Stream)
- hStdOut โ Handle to the output stream.
- nLength โ Stream buffer length.
- buffer โ Raw output data storage.
-
stdErr (Standard Error Stream)
- hStdErr โ Handle to the error stream.
This allows higher-level procedures such as:
call ConsoleInit
call PrintStringA
call PrintInt
call PrintUInt
call ReadInt
call ReadUIntto operate on top of the lower-level Windows API.
The runtime implements buffered input instead of directly reading every character individually from the Windows API.
Implemented input procedures include:
| Procedure | Purpose |
|---|---|
ReadCharA |
Reads a single character |
ReadStringA |
Reads a string/token |
ReadLineA |
Reads a complete line |
ReadUInt |
Parses an unsigned 32-bit integer |
ReadInt |
Parses a signed 32-bit integer |
ReadUInt supports:
- Leading spaces
- Tabs
- Optional
+ - Detection of
- - Decimal digit parsing
- Overflow detection
UINT_MAXsaturation on overflow
ReadInt additionally handles:
- Positive integers
- Negative integers
INT_MAXINT_MIN- Signed overflow
- Positive/negative overflow limits
For example:
INT_MIN.
The output subsystem provides buffered console output with support for:
- Character output
- String output
- Newlines
- Unsigned integers
- Signed integers
- Hexadecimal values
- Memory addresses
- Error reporting
Available procedures include:
PrintCharA
PrintStringA
PrintNewLine
PrintUInt
PrintInt
PrintUIntHex
PrintMemAddress
PrintErrorThe output buffer can be flushed explicitly or automatically when required.
The SDK contains low-level conversion routines for transforming data between strings and integer representations.
UIntToString
IntToStringUIntToHex
UIntToFixedHexStringToUIntThese routines operate directly on bytes, registers, arithmetic instructions, and memory.
No high-level language runtime is involved.
The project also contains basic low-level string primitives.
Current functionality includes:
GetStringLengthA
ReverseStringAThese operate directly on null-terminated character buffers and memory.
The SDK also contains reusable low-level algorithms such as:
MinOfTwo
SwapByteThese procedures form the beginning of a reusable algorithm layer.
The project directly interacts with the Windows process heap.
Example APIs:
GetProcessHeap
HeapAlloc
HeapFreeThis allows programs using the SDK to perform raw heap allocation from Assembly.
Example:
call GetProcessHeap followed by call HeapAlloc and eventually: call HeapFree
The project also provides utilities for inspecting memory addresses such as PrintMemAddress.
The SDK primarily uses the Windows __stdcall calling convention.
Example:
PrintStringA PROC STDCALL,
lpBuffer: LPCSTR
; procedure body
ret
PrintStringA ENDPThis project is also being used to understand:
- Stack-based argument passing
- Caller/callee responsibilities
- Register preservation
- Stack frames
- Procedure interfaces
- Symbol visibility
- MASM procedure declarations
- External symbols
- Linker resolution
Understanding calling conventions is essential when Assembly code interacts with compiled Windows libraries.
The project intentionally separates interfaces from implementations.
Contain definitions such as:
- Types
- Constants
- Structures
- Prototypes
- External declarations
Contain the actual implementations.
For example:
include/console.inc console/PrintStringA.asm PrintStringA
The Assembly modules are compiled into object files and eventually combined
into: win32sdk.lib
Other Assembly programs can then link against this library.
This makes the project behave as a reusable low-level SDK/runtime rather than just a collection of standalone Assembly programs.
The project also explores how symbols move across compilation units.
For example:
EXTERN __console:Consoleallows other modules to reference the global console object defined inside console.asm:
__console Console <>This provides practical experience with:
- External symbols
- Global data
- Object files
- Static libraries
- Linker resolution
- Unresolved externals
- Symbol ownership
The project is also being extended toward Object-Oriented Programming in pure x86 Assembly.
The objective is to understand how concepts normally associated with:
- C++
- Java
- C#
- Python
can be implemented directly at the Assembly level.
Topics being explored include:
- Objects
- Structures
- Encapsulation
- Methods
thispointerECXas the object pointer__thiscall- Method dispatch
- Object memory layout
- C++-style name mangling
The long-term goal is to understand OOP not merely as a language feature, but as a set of conventions implemented through memory, pointers, registers, and calling conventions.
A program using the SDK can look like:
.386
.model flat, stdcall
option casemap:none
include win32sdk.inc
includelib win32sdk.lib
.const
message BYTE "Hello from x86 MASM!", 0
.code
start PROC
call ConsoleInit
push OFFSET message
call PrintStringA
call PrintNewLine
INVOKE ExitProcess, 0
start ENDP
END mainThe important part is that PrintStringA, ConsoleInit, and the underlying
console infrastructure are not provided by an external Assembly framework.
They are being built as part of this project.
The SDK is continuously evolving as new low-level abstractions are implemented and existing components are refined.
The architecture is intentionally designed to grow from a small collection of Assembly procedures into a more complete reusable systems-programming foundation.