LEARN WIN32 API DEEP DIVE
Learn Win32 API: From Zero to Windows System Programmer
Goal: Deeply understand Windows system programming through the Win32 API—from basic handle operations to building real system tools that interact directly with the Windows kernel.
Why Win32 API Matters
Every Windows application—from Notepad to Visual Studio—ultimately calls Win32 APIs. Frameworks like .NET, Qt, and Electron are just abstractions over these same APIs. When you understand Win32, you understand Windows itself.
After completing these projects, you will:
- Understand the difference between handles and pointers (and why Windows chose handles)
- Know how Windows manages memory, processes, threads, and files
- Be able to build real system utilities that work at the OS level
- Debug any Windows application by understanding what’s happening underneath
- Write high-performance I/O code using overlapped operations
- Understand DLL loading, process injection, and security boundaries
Core Concept Analysis
The Windows Object Model
User Mode Kernel Mode
----------- -----------
HANDLE ──────────────────────────► Kernel Object
│ │
│ (Handle Table) │
│ Process-specific │
│ index into kernel │
│ object table │
│ ▼
│ ┌─────────────┐
└──────────────────────────────│ Object Body │
│ - Type │
│ - Security │
│ - RefCount │
└─────────────┘
Fundamental Concepts
- Handles vs. Pointers
- Pointers: Direct memory addresses—if you have it, you can access it
- Handles: Opaque indices into a per-process table maintained by the kernel
- Why handles?: Security (kernel validates access), abstraction (kernel can move objects), process isolation (handles are per-process)
- The Win32 API Pattern
// 1. Create/Open an object → get a HANDLE HANDLE hFile = CreateFile(...); // 2. Check for errors if (hFile == INVALID_HANDLE_VALUE) { DWORD error = GetLastError(); // Error code // Handle error } // 3. Use the handle with other APIs ReadFile(hFile, buffer, size, &bytesRead, NULL); // 4. Clean up CloseHandle(hFile); - Error Handling
- GetLastError(): Returns last error for current thread (per-thread error code)
- HRESULT: COM-style error codes (32-bit: severity, facility, code)
- NTSTATUS: Native API error codes (used by kernel)
- FormatMessage(): Convert error codes to human-readable text
- Unicode in Windows
- Windows uses UTF-16 internally (2 bytes per character, 4 for supplementary)
- W suffix: Unicode version (CreateFileW)—use these
- A suffix: ANSI version (CreateFileA)—legacy, avoid
- TCHAR: Macro that resolves to wchar_t with UNICODE defined
- Recommendation: Always use W APIs directly, forget TCHAR exists
-
Core Object Types | Object Type | Creation API | Description | |————-|————–|————-| | File | CreateFile | Files, directories, devices, pipes | | Process | CreateProcess | Running program instance | | Thread | CreateThread | Execution context within process | | Event | CreateEvent | Synchronization primitive | | Mutex | CreateMutex | Mutual exclusion | | Semaphore | CreateSemaphore | Resource counting | | File Mapping | CreateFileMapping | Shared memory | | Registry Key | RegOpenKeyEx | Registry access | | Heap | HeapCreate | Memory allocation arena |
- Memory Architecture
┌───────────────────────────────┐ 0xFFFFFFFF (4GB on 32-bit) │ Kernel Space │ (Not directly accessible) ├───────────────────────────────┤ 0x80000000 (typically) │ Stack (grows down) │ ├───────────────────────────────┤ │ ↓ │ │ (Free space) │ │ ↑ │ ├───────────────────────────────┤ │ Heap(s) (grows up) │ ├───────────────────────────────┤ │ DLLs │ ├───────────────────────────────┤ │ Executable Image │ ├───────────────────────────────┤ │ Reserved/NULL │ └───────────────────────────────┘ 0x00000000
Project List
Projects are ordered from fundamental understanding to advanced implementations.
Project 1: Win32 Error Message Lookup Tool
- File: LEARN_WIN32_API_DEEP_DIVE.md
- Main Programming Language: C
- Alternative Programming Languages: C++, Rust (windows-rs)
- Coolness Level: Level 2: Practical but Forgettable
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 1: Beginner
- Knowledge Area: Error Handling / Win32 Fundamentals
- Software or Tool: Windows Error Lookup
- Main Book: “Windows via C/C++” by Jeffrey Richter
What you’ll build: A command-line tool that takes Win32 error codes (like 5, 2, 1314) or HRESULT values and displays the human-readable message, category, and common causes.
Why it teaches Win32: This is the first thing every Windows developer needs—understanding error codes. You’ll learn FormatMessage, the difference between Win32 errors and HRESULT, and how Windows reports problems.
Core challenges you’ll face:
- Understanding error code formats → maps to Win32 vs HRESULT vs NTSTATUS
- Using FormatMessage with different flags → maps to message table lookups
- Handling system vs custom message sources → maps to DLL message resources
- Unicode output to console → maps to wide character handling
Key Concepts:
- GetLastError/SetLastError: “Windows via C/C++” Chapter 1 - Jeffrey Richter
- HRESULT structure: MSDN “Structure of COM Error Codes”
- FormatMessage API: “Windows System Programming” Chapter 2 - Johnson Hart
- Console Unicode: “Windows Internals Part 1” Appendix - Russinovich
Difficulty: Beginner Time estimate: Weekend Prerequisites: Basic C, ability to compile on Windows (Visual Studio or MinGW)
Real world outcome:
C:\> errcode 5
Win32 Error Code: 5 (0x00000005)
Message: Access is denied.
Category: Security/Permissions
Common causes:
- Trying to access a file without proper permissions
- Running as non-admin when admin rights needed
- File is locked by another process
C:\> errcode 0x80070005
HRESULT: 0x80070005
Severity: Error
Facility: WIN32 (7)
Code: 5
Message: Access is denied.
C:\> errcode 0xC0000005
NTSTATUS: 0xC0000005
Message: Access violation
This is a memory access violation (read/write to invalid address)
Implementation Hints:
FormatMessage is the key API:
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | // Look up in system message table
FORMAT_MESSAGE_ALLOCATE_BUFFER, // Let Windows allocate the buffer
NULL, // Source (NULL for system)
errorCode, // The error code to look up
0, // Language (0 = default)
(LPWSTR)&messageBuffer, // Output buffer
0, // Min size
NULL // Arguments for format strings
);
For HRESULT decoding, remember the structure:
- Bits 31: Severity (0=success, 1=error)
- Bits 30-29: Reserved
- Bits 28-16: Facility code (identifies subsystem)
- Bits 15-0: Error code
Questions to answer yourself:
- What happens when you call GetLastError() twice in a row?
- Why does SetLastError(0) exist?
- How do you get error messages from a specific DLL?
Learning milestones:
- You decode Win32 errors correctly → You understand thread-local error storage
- You parse HRESULT components → You understand COM error architecture
- You format messages with arguments → You understand Windows message tables
- Console shows Unicode correctly → You understand Windows text encoding
Project 2: File Copy Utility with Progress
- File: LEARN_WIN32_API_DEEP_DIVE.md
- Main Programming Language: C
- Alternative Programming Languages: C++, Rust
- Coolness Level: Level 2: Practical but Forgettable
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 1: Beginner
- Knowledge Area: File I/O / Handle Management
- Software or Tool: Custom File Copy Tool
- Main Book: “Windows System Programming” by Johnson M. Hart
What you’ll build: A command-line file copy utility that shows real-time progress, handles large files (>4GB), and properly reports errors—essentially a simple version of robocopy.
Why it teaches Win32: File I/O is the most fundamental Win32 operation. You’ll learn CreateFile (which is misnamed—it opens everything), handle management, and the ReadFile/WriteFile pattern that applies to all I/O.
Core challenges you’ll face:
- Opening files with correct flags → maps to access modes, share modes, disposition
- Reading/writing in chunks → maps to buffer management, large file handling
- Getting file size for progress → maps to GetFileSizeEx, 64-bit file sizes
- Handling errors mid-copy → maps to cleanup, resource management
Key Concepts:
- CreateFile parameters: “Windows System Programming” Chapter 2 - Johnson Hart
- Buffered I/O strategies: “Windows via C/C++” Chapter 10 - Jeffrey Richter
- Handle cleanup patterns: “Effective C++” Item 13 (RAII concept) - Scott Meyers
- Large file support: MSDN “File Pointers” documentation
Difficulty: Beginner Time estimate: Weekend Prerequisites: Project 1 completed, basic file concepts
Real world outcome:
C:\> mycopy source.iso D:\backup\source.iso
Copying: source.iso
Size: 4.7 GB
[████████████████████░░░░░░░░░░] 68% | 3.2 GB / 4.7 GB | 125 MB/s | ETA: 12s
Copy completed successfully!
Source: C:\source.iso (4,700,000,000 bytes)
Dest: D:\backup\source.iso (4,700,000,000 bytes)
Time: 38 seconds
Speed: 123.7 MB/s
C:\> mycopy readonly.txt D:\test.txt
Error copying file:
Source: C:\readonly.txt
Error: 32 (ERROR_SHARING_VIOLATION)
Message: The process cannot access the file because it is being used
by another process.
Implementation Hints:
CreateFile is the gateway to all I/O in Windows. Despite its name, it doesn’t just create files—it opens files, directories, devices, pipes, and more.
HANDLE hFile = CreateFileW(
L"path\\to\\file", // File path (Unicode)
GENERIC_READ, // Desired access (GENERIC_READ, GENERIC_WRITE, etc.)
FILE_SHARE_READ, // Share mode (who else can access while we have it open)
NULL, // Security attributes
OPEN_EXISTING, // Creation disposition (CREATE_NEW, OPEN_EXISTING, etc.)
FILE_ATTRIBUTE_NORMAL, // Flags and attributes
NULL // Template file
);
Key questions to answer:
- What’s the difference between GENERIC_READ and FILE_GENERIC_READ?
- Why would you use FILE_SHARE_READ vs 0 for share mode?
- What does FILE_FLAG_SEQUENTIAL_SCAN do and when should you use it?
- How do you handle files larger than 4GB (hint: LARGE_INTEGER)?
Buffer size matters for performance:
- Too small (4KB): Many system calls, slow
- Too large (1GB): Memory waste, potential allocation failure
- Sweet spot: 64KB-1MB typically
Learning milestones:
- Basic copy works → You understand CreateFile/ReadFile/WriteFile/CloseHandle
- Progress shows correctly → You understand file size queries and position tracking
- Large files (>4GB) work → You understand 64-bit file operations
- Errors handled gracefully → You understand proper cleanup and error reporting
Project 3: Directory Tree Walker
- File: LEARN_WIN32_API_DEEP_DIVE.md
- Main Programming Language: C
- Alternative Programming Languages: C++, Rust
- Coolness Level: Level 2: Practical but Forgettable
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 1: Beginner
- Knowledge Area: File System / Directory Enumeration
- Software or Tool: Directory Analyzer Tool
- Main Book: “Windows System Programming” by Johnson M. Hart
What you’ll build: A tool that recursively walks a directory tree, displaying the structure and calculating sizes—like tree /F combined with disk usage analysis.
Why it teaches Win32: Directory enumeration uses a different pattern than file I/O—the FindFirstFile/FindNextFile/FindClose trilogy. You’ll also encounter WIN32_FIND_DATA, file attributes, and the peculiarities of Windows paths.
Core challenges you’ll face:
- Understanding FindFirstFile pattern → maps to iterator-style enumeration
- Handling “.” and “..” entries → maps to directory traversal edge cases
- Building paths correctly → maps to path manipulation, MAX_PATH
- Dealing with symbolic links and junctions → maps to reparse points
Key Concepts:
- FindFirstFile/FindNextFile: “Windows System Programming” Chapter 3 - Johnson Hart
- WIN32_FIND_DATA structure: MSDN documentation
- Path handling: “Windows via C/C++” Chapter 15 - Jeffrey Richter
- File attributes and reparse points: “Windows Internals Part 2” Chapter 12 - Russinovich
Difficulty: Beginner Time estimate: Weekend Prerequisites: Project 2 completed
Real world outcome:
C:\> dirtree C:\Windows\System32\drivers
C:\Windows\System32\drivers
├── etc
│ ├── hosts 1.2 KB
│ ├── networks 0.4 KB
│ └── services 17.5 KB
│ └── [3 files, 19.1 KB]
├── UMDF
│ ├── en-US
│ │ └── WpdMtpDr.dll.mui 3.0 KB
│ └── WpdMtpDr.dll 97.0 KB
│ └── [2 files, 100.0 KB]
├── acpi.sys 234.5 KB
├── ntfs.sys 2.1 MB
└── ...
Summary:
Directories: 156
Files: 1,847
Total Size: 234.7 MB
Largest: ntfs.sys (2.1 MB)
Implementation Hints:
The enumeration pattern:
WIN32_FIND_DATAW findData;
HANDLE hFind = FindFirstFileW(L"C:\\path\\*", &findData);
if (hFind == INVALID_HANDLE_VALUE) {
// Handle error or empty directory
}
do {
// Skip "." and ".."
if (wcscmp(findData.cFileName, L".") == 0 ||
wcscmp(findData.cFileName, L"..") == 0) {
continue;
}
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// It's a directory - recurse
} else {
// It's a file - process it
}
} while (FindNextFileW(hFind, &findData));
FindClose(hFind);
Questions to think about:
- Why does the search pattern end with “” not “.*”?
- What’s the difference between FILE_ATTRIBUTE_DIRECTORY and FILE_ATTRIBUTE_REPARSE_POINT?
- How do you avoid infinite loops with symbolic links?
- What’s MAX_PATH and how do you handle longer paths (hint: “\\?\” prefix)?
Learning milestones:
- Basic tree display works → You understand FindFirst/FindNext pattern
- Sizes accumulate correctly → You understand recursive algorithms with Windows APIs
- Handles junction points → You understand reparse points
- Works with long paths → You understand path limitations and workarounds
Project 4: Registry Explorer CLI
- File: LEARN_WIN32_API_DEEP_DIVE.md
- Main Programming Language: C
- Alternative Programming Languages: C++, Rust
- Coolness Level: Level 2: Practical but Forgettable
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 1: Beginner
- Knowledge Area: Registry / Configuration Storage
- Software or Tool: Registry CLI Tool
- Main Book: “Windows Internals Part 1” by Russinovich, Solomon, and Ionescu
What you’ll build: A command-line registry editor that can query, add, modify, and delete registry values—a scriptable alternative to regedit.
Why it teaches Win32: The registry is Windows’ hierarchical configuration database. Registry APIs (RegOpenKeyEx, RegQueryValueEx, etc.) follow patterns similar to file I/O but with their own quirks around data types and access rights.
Core challenges you’ll face:
- Understanding registry structure → maps to hives, keys, values, types
- Handling different value types → maps to REG_SZ, REG_DWORD, REG_BINARY, etc.
- Registry access rights → maps to security and elevation
- 32-bit vs 64-bit registry views → maps to WoW64 redirection
Key Concepts:
- Registry architecture: “Windows Internals Part 1” Chapter 4 - Russinovich
- Registry APIs: “Windows System Programming” Chapter 4 - Johnson Hart
- WoW64 Registry Reflection: MSDN “Registry Keys Affected by WOW64”
- Registry security: “Windows Security Internals” Chapter 7 - Forshaw
Difficulty: Beginner Time estimate: Weekend Prerequisites: Basic understanding of handles from earlier projects
Real world outcome:
C:\> regcli query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion
ProductName REG_SZ Windows 10 Pro
EditionID REG_SZ Professional
CurrentBuild REG_SZ 19045
UBR REG_DWORD 3693
C:\> regcli query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion /v ProductName
Windows 10 Pro
C:\> regcli add HKCU\SOFTWARE\MyApp /v Setting1 /t REG_DWORD /d 42
Successfully created value 'Setting1'
C:\> regcli export HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion > output.reg
C:\> regcli query HKLM\SOFTWARE\Microsoft /s | head -20
Microsoft
├── .NETFramework
│ ├── v2.0.50727
│ ├── v4.0.30319
│ └── ...
├── Windows
│ ├── CurrentVersion
│ │ ├── Run
│ │ ├── Uninstall
│ │ └── ...
Implementation Hints:
Registry APIs follow the handle pattern:
HKEY hKey;
LONG result = RegOpenKeyExW(
HKEY_LOCAL_MACHINE, // Predefined root key
L"SOFTWARE\\Microsoft", // Subkey path
0, // Options
KEY_READ, // Desired access
&hKey // Output handle
);
if (result != ERROR_SUCCESS) {
// Handle error - note: registry uses LONG, not GetLastError
}
// Enumerate values
DWORD index = 0;
WCHAR valueName[256];
DWORD valueNameLen = 256;
DWORD type;
BYTE data[1024];
DWORD dataSize = 1024;
while (RegEnumValueW(hKey, index, valueName, &valueNameLen,
NULL, &type, data, &dataSize) == ERROR_SUCCESS) {
// Process value based on type
index++;
valueNameLen = 256; // Reset for next iteration
dataSize = 1024;
}
RegCloseKey(hKey);
Important questions:
- Why do predefined keys (HKEY_LOCAL_MACHINE) not need to be closed?
- What happens if you open a 32-bit registry view from a 64-bit app?
- How do you read a REG_MULTI_SZ (multi-string) value?
- Why would RegQueryValueEx return ERROR_MORE_DATA?
Learning milestones:
- Can read registry values → You understand RegOpenKeyEx/RegQueryValueEx
- Handles all data types → You understand REG_* type system
- Recursive enumeration works → You understand RegEnumKeyEx/RegEnumValue
- Modify operations succeed → You understand registry write permissions
Project 5: Process Lister (Task Manager Clone)
- File: LEARN_WIN32_API_DEEP_DIVE.md
- Main Programming Language: C
- Alternative Programming Languages: C++, Rust
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 2: Intermediate
- Knowledge Area: Process Management / System Information
- Software or Tool: Process List Tool
- Main Book: “Windows via C/C++” by Jeffrey Richter
What you’ll build: A command-line tool that lists all running processes with their PID, memory usage, thread count, and executable path—like a scriptable Task Manager.
Why it teaches Win32: Process enumeration is your first step into the “system” side of Windows programming. You’ll use ToolHelp32 or PSAPI to enumerate processes, then OpenProcess to get handles to query information.
Core challenges you’ll face:
- Enumerating all processes → maps to CreateToolhelp32Snapshot or EnumProcesses
- Opening processes for query → maps to access rights, privilege requirements
- Getting process details → maps to QueryFullProcessImageName, memory counters
- Handling access denied → maps to elevation, protected processes
Key Concepts:
- Process enumeration: “Windows via C/C++” Chapter 4 - Jeffrey Richter
- Process object and handles: “Windows Internals Part 1” Chapter 3 - Russinovich
- Memory counters: MSDN “PROCESS_MEMORY_COUNTERS” structure
- Protected processes: “Windows Internals Part 1” Chapter 3 - Russinovich
Difficulty: Intermediate Time estimate: 1-2 weeks Prerequisites: Completed file and registry projects, understanding of handles
Real world outcome:
C:\> proclist
PID PPID Threads Memory Name Path
---- ---- ------- ------ ---- ----
0 0 4 0 KB [System Process]
4 0 156 144 KB System
88 4 3 1.2 MB Registry
464 4 8 3.4 MB smss.exe
572 556 12 5.1 MB csrss.exe \Windows\System32\csrss.exe
632 556 12 4.8 MB wininit.exe \Windows\System32\wininit.exe
...
14532 12340 15 78.5 MB chrome.exe \Program Files\Google\Chrome\...
Processes: 247 | Threads: 3,128 | Total Memory: 8.2 GB
C:\> proclist /pid 14532
Process: chrome.exe (PID: 14532)
Path: C:\Program Files\Google\Chrome\Application\chrome.exe
Parent: chrome.exe (PID: 12340)
User: DESKTOP-ABC\John
Started: 2024-01-15 09:23:45
Threads: 15
Handles: 542
Working Set: 78.5 MB
Private: 52.3 MB
CPU Time: 00:05:32.156
Modules:
chrome.exe 1.8 MB 0x00007FF6A0000000
ntdll.dll 2.0 MB 0x00007FFC80000000
kernel32.dll 768 KB 0x00007FFC7E000000
...
Implementation Hints:
Two main approaches for process enumeration:
Approach 1: ToolHelp32 (easier, more info)
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32W pe32 = { sizeof(pe32) };
if (Process32FirstW(hSnapshot, &pe32)) {
do {
// pe32.th32ProcessID - PID
// pe32.th32ParentProcessID - Parent PID
// pe32.cntThreads - Thread count
// pe32.szExeFile - Executable name
} while (Process32NextW(hSnapshot, &pe32));
}
CloseHandle(hSnapshot);
Approach 2: PSAPI (just PIDs, then open each)
DWORD pids[1024], bytesReturned;
EnumProcesses(pids, sizeof(pids), &bytesReturned);
int processCount = bytesReturned / sizeof(DWORD);
for (int i = 0; i < processCount; i++) {
HANDLE hProc = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE,
pids[i]
);
// Query process info...
CloseHandle(hProc);
}
Questions to explore:
- Why can’t you open System (PID 4) with OpenProcess?
- What’s the difference between QueryFullProcessImageName and GetModuleFileNameEx?
- Why do you need SeDebugPrivilege for some processes?
- What are protected processes light (PPL)?
Learning milestones:
- Basic process list works → You understand enumeration APIs
- Memory and thread counts show → You understand process info queries
- Full paths work → You understand QueryFullProcessImageName
- Handle “access denied” gracefully → You understand process security
Project 6: Memory Map Viewer
- File: LEARN_WIN32_API_DEEP_DIVE.md
- Main Programming Language: C
- Alternative Programming Languages: C++, Rust
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 2: Intermediate
- Knowledge Area: Memory Management / Virtual Memory
- Software or Tool: Memory Map Analyzer
- Main Book: “Windows Internals Part 1” by Russinovich, Solomon, and Ionescu
What you’ll build: A tool that displays the virtual memory layout of any process—showing code, heap, stack, DLLs, and mapped files with their protection and state.
Why it teaches Win32: This is where you truly understand Windows memory management. You’ll see how VirtualAlloc creates regions, how DLLs get mapped, and how the stack grows. This knowledge is essential for debugging, security research, and optimization.
Core challenges you’ll face:
- Querying memory regions → maps to VirtualQueryEx, MEMORY_BASIC_INFORMATION
- Understanding memory states → maps to committed, reserved, free
- Interpreting protection flags → maps to PAGE_EXECUTE_READ, PAGE_READWRITE, etc.
- Identifying region types → maps to image, mapped, private
Key Concepts:
- Virtual memory architecture: “Windows Internals Part 1” Chapter 5 - Russinovich
- VirtualAlloc/VirtualQuery: “Windows via C/C++” Chapter 13 - Jeffrey Richter
- Memory protection: “Windows System Programming” Chapter 5 - Johnson Hart
- Address space layout: “Windows Internals Part 1” Chapter 5 - Russinovich
Difficulty: Intermediate Time estimate: 1-2 weeks Prerequisites: Process project completed, basic understanding of virtual memory
Real world outcome:
C:\> memmap 14532
Process: chrome.exe (PID: 14532)
Virtual Address Space Map:
Address Range Size State Protect Type Info
------------------------------- -------- -------- --------- ---------- ----
0x00000000`00000000 64 KB Free --- ---
0x00000000`00010000 64 KB Reserved --- Private
0x00000000`00020000 4 KB Commit RW- Private [Stack Guard]
0x00000000`00021000 1020 KB Commit RW- Private [Stack]
...
0x00007FF6`A0000000 4 KB Commit R-- Image chrome.exe [Headers]
0x00007FF6`A0001000 1.2 MB Commit R-X Image chrome.exe [.text]
0x00007FF6`A0130000 400 KB Commit R-- Image chrome.exe [.rdata]
0x00007FF6`A0195000 48 KB Commit RW- Image chrome.exe [.data]
...
0x00007FFC`80000000 2 MB Commit R-X Image ntdll.dll [.text]
...
0x00007FFC`F0000000 - End --- Free --- ---
Summary:
Committed: 856 MB (private: 520 MB, image: 336 MB)
Reserved: 2.1 GB
Free: 127 TB (64-bit address space)
Heaps: 12 (total: 45 MB)
Stacks: 15 (total: 15 MB)
Loaded DLLs: 87
Implementation Hints:
The core loop for memory enumeration:
HANDLE hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, targetPid);
MEMORY_BASIC_INFORMATION mbi;
LPVOID address = NULL;
while (VirtualQueryEx(hProcess, address, &mbi, sizeof(mbi))) {
// mbi.BaseAddress - Region start
// mbi.RegionSize - Size of this region
// mbi.State - MEM_COMMIT, MEM_RESERVE, MEM_FREE
// mbi.Protect - PAGE_READONLY, PAGE_READWRITE, etc.
// mbi.Type - MEM_IMAGE, MEM_MAPPED, MEM_PRIVATE
// mbi.AllocationBase - Start of the allocation
// Move to next region
address = (LPBYTE)mbi.BaseAddress + mbi.RegionSize;
}
Protection flags to understand:
- PAGE_EXECUTE_READ (R-X) - Code
- PAGE_READWRITE (RW-) - Data, heap, stack
- PAGE_READONLY (R–) - Read-only data, imports
- PAGE_NOACCESS (—) - Guard pages, reserved
- PAGE_GUARD - Stack guard (triggers exception on access)
Questions to explore:
- Why is there a large “hole” in the address space on 64-bit Windows?
- What’s the difference between MEM_RESERVE and MEM_COMMIT?
- How can you identify heap vs stack vs regular allocation?
- What does MEM_IMAGE tell you vs MEM_MAPPED?
Learning milestones:
- Basic region list works → You understand VirtualQueryEx
- Protection flags decoded → You understand page protection
- DLLs identified by path → You understand MEM_IMAGE and module mapping
- Can map heap regions → You understand HeapWalk (advanced)
Project 7: Simple Command Shell
- File: LEARN_WIN32_API_DEEP_DIVE.md
- Main Programming Language: C
- Alternative Programming Languages: C++, Rust
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 2: Intermediate
- Knowledge Area: Process Creation / Pipes / I/O
- Software or Tool: Custom Shell
- Main Book: “Windows System Programming” by Johnson M. Hart
What you’ll build: A command shell that can launch programs, capture their output, handle pipes between commands, and support basic I/O redirection—a minimal cmd.exe.
Why it teaches Win32: CreateProcess is the heart of Windows program execution. Combined with pipes and I/O redirection, you’ll understand how shells work, how stdout/stderr flow, and how processes communicate.
Core challenges you’ll face:
- Parsing command lines → maps to tokenization, quoting rules
- Creating child processes → maps to CreateProcess, STARTUPINFO
- Piping between processes → maps to CreatePipe, handle inheritance
- Redirecting I/O → maps to STARTUPINFO handles, HANDLE_FLAG_INHERIT
Key Concepts:
- CreateProcess: “Windows via C/C++” Chapter 4 - Jeffrey Richter
- Pipe I/O: “Windows System Programming” Chapter 6 - Johnson Hart
- Handle inheritance: “Windows via C/C++” Chapter 3 - Jeffrey Richter
- Console I/O: “Windows System Programming” Chapter 2 - Johnson Hart
Difficulty: Intermediate Time estimate: 1-2 weeks Prerequisites: File I/O project, process project completed
Real world outcome:
mysh> dir C:\Windows | findstr System
Directory of C:\Windows
01/15/2024 09:00 AM <DIR> System32
01/15/2024 09:00 AM <DIR> SystemResources
01/15/2024 09:00 AM <DIR> SysWOW64
mysh> echo Hello > output.txt
mysh> type output.txt
Hello
mysh> notepad.exe &
[Started: notepad.exe, PID: 15632]
mysh> tasklist | findstr chrome | sort
chrome.exe 12340 Console 1 156,532 K
chrome.exe 14532 Console 1 78,456 K
chrome.exe 14680 Console 1 45,232 K
mysh> set PATH
PATH=C:\Windows\system32;C:\Windows;...
mysh> cd C:\Users
C:\Users> pwd
C:\Users
Implementation Hints:
CreateProcess core usage:
STARTUPINFOW si = { sizeof(si) };
PROCESS_INFORMATION pi;
// For I/O redirection:
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = hInputPipe; // or GetStdHandle(STD_INPUT_HANDLE)
si.hStdOutput = hOutputPipe;
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
BOOL success = CreateProcessW(
NULL, // Application name (NULL = parse from command line)
commandLine, // Command line (mutable!)
NULL, // Process security attributes
NULL, // Thread security attributes
TRUE, // Inherit handles
0, // Creation flags
NULL, // Environment (NULL = inherit)
NULL, // Current directory (NULL = inherit)
&si, // Startup info
&pi // Process information (output)
);
// IMPORTANT: Close handles you don't need
CloseHandle(pi.hThread);
// Keep pi.hProcess if you need to wait for it
For pipes between commands (cmd1 | cmd2):
HANDLE hReadPipe, hWritePipe;
SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, TRUE }; // Inherit handles
CreatePipe(&hReadPipe, &hWritePipe, &sa, 0);
// cmd1's stdout → hWritePipe
// cmd2's stdin → hReadPipe
// IMPORTANT: Close the ends you don't use in each process!
Questions to think about:
- Why must the command line buffer be writable?
- What happens if you don’t close pipe handles correctly?
- How do you handle commands that don’t exist?
- What’s the difference between CREATE_NEW_CONSOLE and 0?
Learning milestones:
- Simple commands run → You understand CreateProcess basics
- Output capture works → You understand pipe creation and STARTF_USESTDHANDLES
-
**Pipelines work (cmd cmd)** → You understand multi-process pipe chains - Background execution works (&) → You understand handle management and detachment
Project 8: File System Monitor
- File: LEARN_WIN32_API_DEEP_DIVE.md
- Main Programming Language: C
- Alternative Programming Languages: C++, Rust
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 3. The “Service & Support” Model (B2B Utility)
- Difficulty: Level 3: Advanced
- Knowledge Area: Overlapped I/O / File System Events
- Software or Tool: File Watcher Tool
- Main Book: “Windows via C/C++” by Jeffrey Richter
What you’ll build: A real-time file system monitor that watches directories for changes (creates, deletes, renames, modifications) and logs them—like a simplified version of Process Monitor’s file operations.
Why it teaches Win32: This introduces asynchronous/overlapped I/O, which is essential for high-performance Windows programming. ReadDirectoryChangesW is a great introduction to the Windows async model.
Core challenges you’ll face:
- Setting up overlapped I/O → maps to OVERLAPPED structure, event objects
- Understanding change notifications → maps to FILE_NOTIFY_INFORMATION parsing
- Handling buffer overflows → maps to when changes happen faster than you process
- Recursive directory watching → maps to subdirectory monitoring flags
Key Concepts:
- Overlapped I/O: “Windows via C/C++” Chapter 10 - Jeffrey Richter
- ReadDirectoryChangesW: MSDN documentation
- Event objects: “Windows via C/C++” Chapter 8 - Jeffrey Richter
- IOCP for scaling: “Windows via C/C++” Chapter 10 - Jeffrey Richter
Difficulty: Advanced Time estimate: 1-2 weeks Prerequisites: All prior projects, understanding of async concepts
Real world outcome:
C:\> fswatch C:\Users\John\Documents --recursive
Watching: C:\Users\John\Documents (recursive)
Press Ctrl+C to stop...
[2024-01-15 10:23:45.123] CREATED C:\Users\John\Documents\report.docx
[2024-01-15 10:23:45.456] MODIFIED C:\Users\John\Documents\report.docx
[2024-01-15 10:23:46.789] MODIFIED C:\Users\John\Documents\report.docx
[2024-01-15 10:24:12.345] RENAMED C:\Users\John\Documents\report.docx
-> C:\Users\John\Documents\report_final.docx
[2024-01-15 10:25:33.678] DELETED C:\Users\John\Documents\~$report.docx
[2024-01-15 10:26:01.234] CREATED C:\Users\John\Documents\New Folder
(directory)
Statistics (last 60 seconds):
Created: 12
Modified: 45
Deleted: 8
Renamed: 3
Implementation Hints:
Basic overlapped I/O setup:
HANDLE hDir = CreateFileW(
directoryPath,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, // Key flags!
NULL
);
OVERLAPPED overlapped = {0};
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
BYTE buffer[4096];
DWORD bytesReturned;
ReadDirectoryChangesW(
hDir,
buffer,
sizeof(buffer),
TRUE, // Watch subtree
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_SIZE,
&bytesReturned,
&overlapped,
NULL // Or completion routine
);
// Wait for changes
WaitForSingleObject(overlapped.hEvent, INFINITE);
// Parse FILE_NOTIFY_INFORMATION structures in buffer
FILE_NOTIFY_INFORMATION* fni = (FILE_NOTIFY_INFORMATION*)buffer;
while (TRUE) {
// fni->Action - what happened
// fni->FileName - the file (NOT null-terminated!)
// fni->FileNameLength - length in bytes
if (fni->NextEntryOffset == 0) break;
fni = (FILE_NOTIFY_INFORMATION*)((BYTE*)fni + fni->NextEntryOffset);
}
Key questions:
- Why do you need FILE_FLAG_BACKUP_SEMANTICS for directories?
- What happens if changes occur faster than you can process them?
- How do you handle FILE_ACTION_RENAMED_OLD_NAME and FILE_ACTION_RENAMED_NEW_NAME?
- What’s the difference between using an event vs a completion routine?
Learning milestones:
- Basic notifications work → You understand ReadDirectoryChangesW
- Overlapped I/O pattern mastered → You understand async I/O model
- Rename tracking works → You understand pairing old/new name events
- No missed events under load → You understand buffer management and re-issuing
Project 9: DLL Dependency Walker
- File: LEARN_WIN32_API_DEEP_DIVE.md
- Main Programming Language: C
- Alternative Programming Languages: C++, Rust
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 2. The “Micro-SaaS / Pro Tool” (Solo-Preneur Potential)
- Difficulty: Level 3: Advanced
- Knowledge Area: PE Format / DLL Loading
- Software or Tool: Dependency Analysis Tool
- Main Book: “Windows Internals Part 1” by Russinovich, Solomon, and Ionescu
What you’ll build: A tool that analyzes an executable and shows all its DLL dependencies (including recursive), exports, and imports—like the classic Dependency Walker tool.
Why it teaches Win32: This forces you to understand the PE (Portable Executable) format and how Windows loads DLLs. You’ll parse headers, import tables, and understand the loader’s perspective.
Core challenges you’ll face:
- Parsing PE headers → maps to DOS header, NT headers, section table
- Reading import directory → maps to Import Address Table, Import Name Table
- Resolving DLL paths → maps to search order, SxS, API sets
- Handling 32-bit vs 64-bit → maps to PE32 vs PE32+ formats
Key Concepts:
- PE format: “Windows Internals Part 1” Chapter 3 - Russinovich
- Import table structure: “Practical Malware Analysis” Chapter 1 - Sikorski & Honig
- DLL search order: MSDN “Dynamic-Link Library Search Order”
- API Sets: “Windows Internals Part 1” Chapter 3 - Russinovich
Difficulty: Advanced Time estimate: 2-3 weeks Prerequisites: Memory map project, understanding of binary formats
Real world outcome:
C:\> depends notepad.exe
Analyzing: C:\Windows\System32\notepad.exe
Type: PE32+ (64-bit)
Subsystem: Windows GUI
Import Dependencies:
├── KERNEL32.dll (C:\Windows\System32\KERNEL32.DLL)
│ ├── GetLastError
│ ├── CreateFileW
│ ├── ReadFile
│ └── ... (45 more functions)
├── USER32.dll (C:\Windows\System32\USER32.DLL)
│ ├── CreateWindowExW
│ ├── SendMessageW
│ └── ... (78 more functions)
├── GDI32.dll (C:\Windows\System32\GDI32.DLL)
│ └── ... (12 functions)
├── COMCTL32.dll (C:\Windows\WinSxS\...\COMCTL32.DLL)
│ └── ... (5 functions)
└── api-ms-win-core-*.dll → KERNELBASE.dll (API Set)
Dependency Tree (recursive):
notepad.exe
├── KERNEL32.dll
│ └── KERNELBASE.dll
│ └── ntdll.dll
├── USER32.dll
│ ├── win32u.dll
│ ├── GDI32.dll
│ └── ...
└── ...
Missing Dependencies: None
Potential Issues: None
Exports (none - not a DLL)
Implementation Hints:
PE parsing requires understanding the header chain:
DOS Header (at offset 0)
e_lfanew → PE Signature ("PE\0\0")
↓
File Header (COFF)
↓
Optional Header (PE32/PE32+)
↓
Data Directories[16]
↓
Section Headers[]
For imports, look at Data Directory index 1 (IMAGE_DIRECTORY_ENTRY_IMPORT):
1. Map the file into memory (CreateFileMapping + MapViewOfFile)
2. Find DOS header, verify "MZ"
3. Follow e_lfanew to PE signature, verify "PE\0\0"
4. Parse IMAGE_FILE_HEADER and IMAGE_OPTIONAL_HEADER
5. Get Data Directories from optional header
6. Import Directory points to IMAGE_IMPORT_DESCRIPTOR array
7. Each descriptor has:
- Name (RVA to DLL name)
- OriginalFirstThunk (Import Name Table)
- FirstThunk (Import Address Table)
8. Walk the INT to get function names
Key concepts:
- RVA (Relative Virtual Address) vs File Offset - you need to convert!
- API Sets (api-ms-win-*) are virtual DLLs that redirect to real DLLs
- The loader’s search order is complex: app directory, SxS, System32, PATH…
Learning milestones:
- Can parse PE headers → You understand the PE format
- Can list imports → You understand import tables
- Can resolve DLL paths → You understand the loader search order
- Can handle API sets → You understand modern Windows redirection
Project 10: Thread Pool and Work Queue
- File: LEARN_WIN32_API_DEEP_DIVE.md
- Main Programming Language: C
- Alternative Programming Languages: C++, Rust
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 3: Advanced
- Knowledge Area: Threading / Synchronization
- Software or Tool: Custom Thread Pool Library
- Main Book: “Windows via C/C++” by Jeffrey Richter
What you’ll build: A reusable thread pool library that efficiently processes work items, with configurable pool size, work stealing, and graceful shutdown.
Why it teaches Win32: Threading is where Win32 gets interesting. You’ll learn CreateThread, synchronization primitives (events, mutexes, critical sections, condition variables), and how to coordinate concurrent work safely.
Core challenges you’ll face:
- Thread lifecycle management → maps to CreateThread, ExitThread, WaitForMultipleObjects
- Work queue synchronization → maps to CRITICAL_SECTION, condition variables
- Efficient waiting → maps to WaitForSingleObject vs spinning
- Graceful shutdown → maps to signaling threads, cleanup order
Key Concepts:
- Thread APIs: “Windows via C/C++” Chapter 6 - Jeffrey Richter
- Synchronization: “Windows via C/C++” Chapter 8 - Jeffrey Richter
- Condition variables: “Windows via C/C++” Chapter 8 - Jeffrey Richter
- Thread pool design: “C++ Concurrency in Action” Chapter 9 - Anthony Williams
Difficulty: Advanced Time estimate: 2-3 weeks Prerequisites: Process/thread basics, understanding of concurrency
Real world outcome:
// Usage example:
ThreadPool* pool = ThreadPoolCreate(4); // 4 worker threads
// Submit work
for (int i = 0; i < 1000; i++) {
ThreadPoolSubmit(pool, ProcessItem, &items[i]);
}
// Wait for all work to complete
ThreadPoolWait(pool);
// Shutdown
ThreadPoolDestroy(pool);
C:\> threadpool_test
Created thread pool with 4 workers
Submitting 10000 work items...
All items submitted in 12ms
Progress: [████████████████████] 100% (10000/10000)
Completed in 1.23 seconds
Throughput: 8,130 items/second
Average latency: 0.49ms per item
Thread utilization: 97.2%
Per-thread stats:
Thread 0: 2,512 items processed
Thread 1: 2,498 items processed
Thread 2: 2,503 items processed
Thread 3: 2,487 items processed
Implementation Hints:
Basic structure:
typedef struct {
CRITICAL_SECTION lock;
CONDITION_VARIABLE workAvailable;
CONDITION_VARIABLE workComplete;
WorkItem* queue; // Work queue (ring buffer or linked list)
int queueSize;
int queueHead, queueTail;
HANDLE* threads; // Worker thread handles
int threadCount;
volatile BOOL shutdown; // Shutdown signal
volatile int pendingWork;
} ThreadPool;
Worker thread loop:
DWORD WINAPI WorkerThread(LPVOID param) {
ThreadPool* pool = (ThreadPool*)param;
while (TRUE) {
EnterCriticalSection(&pool->lock);
// Wait for work or shutdown
while (pool->queueSize == 0 && !pool->shutdown) {
SleepConditionVariableCS(&pool->workAvailable,
&pool->lock,
INFINITE);
}
if (pool->shutdown && pool->queueSize == 0) {
LeaveCriticalSection(&pool->lock);
break;
}
// Dequeue work item
WorkItem item = DequeueWork(pool);
LeaveCriticalSection(&pool->lock);
// Execute work (outside lock!)
item.func(item.param);
// Signal completion
InterlockedDecrement(&pool->pendingWork);
WakeConditionVariable(&pool->workComplete);
}
return 0;
}
Key questions:
- Why use CRITICAL_SECTION instead of Mutex?
- What’s the difference between WakeConditionVariable and WakeAllConditionVariable?
- How do you handle the case where work items can spawn more work?
- Why check for shutdown twice in the worker loop?
Learning milestones:
- Basic submission/execution works → You understand thread creation and work queues
- No deadlocks or races → You understand synchronization
- Wait for completion works → You understand condition variables
- Graceful shutdown works → You understand coordinated cleanup
Project 11: Service Application
- File: LEARN_WIN32_API_DEEP_DIVE.md
- Main Programming Language: C
- Alternative Programming Languages: C++, Rust
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 3. The “Service & Support” Model (B2B Utility)
- Difficulty: Level 3: Advanced
- Knowledge Area: Windows Services / SCM
- Software or Tool: Windows Service
- Main Book: “Windows System Programming” by Johnson M. Hart
What you’ll build: A proper Windows service that installs, starts, stops, and responds to the Service Control Manager—the foundation for any background daemon on Windows.
Why it teaches Win32: Services are how Windows runs background processes. The Service Control Manager (SCM) protocol is unique to Windows and teaches you about system architecture, security contexts, and proper daemon design.
Core challenges you’ll face:
- Service entry point pattern → maps to ServiceMain, service dispatch table
- SCM communication → maps to RegisterServiceCtrlHandler, SetServiceStatus
- Handling control requests → maps to SERVICE_CONTROL_STOP, pause, etc.
- Running as SYSTEM → maps to security contexts, session 0 isolation
Key Concepts:
- Service architecture: “Windows System Programming” Chapter 13 - Johnson Hart
- SCM protocol: “Windows via C/C++” Chapter 4 - Jeffrey Richter
- Service security: “Windows Internals Part 1” Chapter 7 - Russinovich
- Session 0 isolation: MSDN “Application Compatibility: Session 0 Isolation”
Difficulty: Advanced Time estimate: 1-2 weeks Prerequisites: Process and thread understanding, basic Windows administration
Real world outcome:
C:\> myservice install
Service 'MyService' installed successfully.
C:\> sc query MyService
SERVICE_NAME: MyService
TYPE : 10 WIN32_OWN_PROCESS
STATE : 1 STOPPED
C:\> net start MyService
The MyService service is starting.
The MyService service was started successfully.
C:\> sc query MyService
SERVICE_NAME: MyService
TYPE : 10 WIN32_OWN_PROCESS
STATE : 4 RUNNING
(STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)
C:\> myservice status
Service is running (PID: 5678)
Uptime: 00:05:23
Requests processed: 1,234
C:\> net stop MyService
The MyService service is stopping.
The MyService service was stopped successfully.
C:\> myservice uninstall
Service 'MyService' uninstalled successfully.
Implementation Hints:
Service structure:
// Main entry point
int main(int argc, char* argv[]) {
if (argc > 1) {
if (strcmp(argv[1], "install") == 0) return InstallService();
if (strcmp(argv[1], "uninstall") == 0) return UninstallService();
}
// When run by SCM, start service dispatcher
SERVICE_TABLE_ENTRY serviceTable[] = {
{ L"MyService", ServiceMain },
{ NULL, NULL }
};
StartServiceCtrlDispatcher(serviceTable);
return 0;
}
// Called by SCM to start the service
void WINAPI ServiceMain(DWORD argc, LPWSTR* argv) {
// Register control handler
g_statusHandle = RegisterServiceCtrlHandlerEx(
L"MyService",
ServiceCtrlHandler,
NULL
);
// Report starting
ReportServiceStatus(SERVICE_START_PENDING, 0, 3000);
// Do initialization...
// Report running
ReportServiceStatus(SERVICE_RUNNING, 0, 0);
// Main service loop
while (!g_shutdown) {
// Do work...
Sleep(1000);
}
// Report stopped
ReportServiceStatus(SERVICE_STOPPED, 0, 0);
}
// Handle control requests
DWORD WINAPI ServiceCtrlHandler(
DWORD control,
DWORD eventType,
LPVOID eventData,
LPVOID context
) {
switch (control) {
case SERVICE_CONTROL_STOP:
ReportServiceStatus(SERVICE_STOP_PENDING, 0, 3000);
g_shutdown = TRUE;
return NO_ERROR;
case SERVICE_CONTROL_INTERROGATE:
return NO_ERROR;
}
return ERROR_CALL_NOT_IMPLEMENTED;
}
Key questions:
- Why does ServiceMain run on a different thread than main()?
- What happens if you don’t respond to SERVICE_CONTROL_STOP in time?
- How do you debug a service? (hint: DebugBreak or attach debugger)
- What’s the difference between LocalSystem, LocalService, and NetworkService?
Learning milestones:
- Service installs and starts → You understand SCM registration
- Responds to stop correctly → You understand the control handler
- Runs continuously → You understand the service main loop
- Survives logoff → You understand session 0 and service isolation
Project 12: Named Pipe Server
- File: LEARN_WIN32_API_DEEP_DIVE.md
- Main Programming Language: C
- Alternative Programming Languages: C++, Rust
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 3: Advanced
- Knowledge Area: IPC / Named Pipes
- Software or Tool: IPC Server/Client
- Main Book: “Windows System Programming” by Johnson M. Hart
What you’ll build: A client-server application using named pipes for inter-process communication, supporting multiple simultaneous clients—the foundation for local IPC on Windows.
Why it teaches Win32: Named pipes are Windows’ primary IPC mechanism. This teaches you CreateNamedPipe, overlapped I/O for multiple clients, and the security model for inter-process communication.
Core challenges you’ll face:
- Creating named pipe server → maps to CreateNamedPipe, PIPE_ACCESS_
- Handling multiple clients → maps to ConnectNamedPipe, overlapped I/O
- Message framing → maps to PIPE_TYPE_MESSAGE vs PIPE_TYPE_BYTE
- Security descriptors → maps to pipe access control
Key Concepts:
- Named pipe APIs: “Windows System Programming” Chapter 11 - Johnson Hart
- Overlapped pipe I/O: “Windows via C/C++” Chapter 10 - Jeffrey Richter
- Pipe security: “Windows Security Internals” Chapter 8 - Forshaw
- Message mode pipes: MSDN “Named Pipe Type, Read, and Wait Modes”
Difficulty: Advanced Time estimate: 1-2 weeks Prerequisites: Overlapped I/O understanding from file watcher project
Real world outcome:
# Server terminal
C:\> pipeserver --name "\\.\pipe\MyService"
Server listening on \\.\pipe\MyService
[10:23:45] Client connected from PID 1234
[10:23:45] Client 1: Request: "HELLO"
[10:23:45] Client 1: Response: "HELLO BACK"
[10:23:46] Client connected from PID 5678
[10:23:46] Client 2: Request: "STATUS"
[10:23:46] Client 2: Response: "OK: Uptime 00:05:23, Clients: 2"
[10:23:47] Client 1 disconnected
^C Shutting down...
# Client terminal
C:\> pipeclient --name "\\.\pipe\MyService"
Connected to \\.\pipe\MyService
> HELLO
< HELLO BACK
> STATUS
< OK: Uptime 00:05:23, Clients: 2
> quit
Disconnected.
Implementation Hints:
Server pattern with multiple clients:
// Create pipe instance
HANDLE hPipe = CreateNamedPipeW(
L"\\\\.\\pipe\\MyPipe",
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, // Max instances
4096, // Output buffer
4096, // Input buffer
0, // Default timeout
NULL // Security (NULL = default)
);
// Wait for client connection (overlapped)
OVERLAPPED overlapped = {0};
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
ConnectNamedPipe(hPipe, &overlapped);
WaitForSingleObject(overlapped.hEvent, INFINITE);
// Now client is connected - read/write with ReadFile/WriteFile
For multiple clients, you need either:
- A thread per client (simple)
- Overlapped I/O with WaitForMultipleObjects (intermediate)
- I/O Completion Ports (advanced, scalable)
Questions to explore:
- What’s the difference between PIPE_TYPE_MESSAGE and PIPE_TYPE_BYTE?
- How do you get the client’s PID (hint: GetNamedPipeClientProcessId)?
- What happens if the client dies while you’re reading?
- How do you secure a pipe so only certain users can connect?
Learning milestones:
- Single client works → You understand CreateNamedPipe basics
- Message mode works → You understand pipe types
- Multiple clients work → You understand overlapped I/O or threading
- Security works → You understand pipe security descriptors
Project 13: DLL Injection Tool
- File: LEARN_WIN32_API_DEEP_DIVE.md
- Main Programming Language: C
- Alternative Programming Languages: C++, Rust
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 4: Expert
- Knowledge Area: Process Manipulation / Code Injection
- Software or Tool: DLL Injector
- Main Book: “Windows Internals Part 1” by Russinovich, Solomon, and Ionescu
What you’ll build: A tool that injects a DLL into a running process using the classic CreateRemoteThread technique—the foundation for modding, debugging, and security research.
Why it teaches Win32: This combines everything: process handles, memory management (VirtualAllocEx), cross-process writes (WriteProcessMemory), and remote thread creation. It’s the “boss level” of Win32 process manipulation.
Core challenges you’ll face:
- Opening target process → maps to OpenProcess, PROCESS_ALL_ACCESS
- Allocating memory in remote process → maps to VirtualAllocEx
- Writing to remote process → maps to WriteProcessMemory
- Creating remote thread → maps to CreateRemoteThread, LoadLibraryW address
Key Concepts:
- Process memory manipulation: “Windows via C/C++” Chapter 22 - Jeffrey Richter
- DLL injection techniques: “Practical Malware Analysis” Chapter 12 - Sikorski & Honig
- Thread creation in remote process: “Windows Internals Part 1” Chapter 3 - Russinovich
- Anti-injection defenses: “Windows Internals Part 1” Chapter 7 - Russinovich
Difficulty: Expert Time estimate: 2-3 weeks Prerequisites: Memory map and process projects, understanding of DLL loading
Real world outcome:
C:\> injector --pid 1234 --dll mydll.dll
Target: notepad.exe (PID: 1234)
DLL: C:\path\to\mydll.dll
[+] Opening target process...
[+] Allocated 520 bytes in target @ 0x1A0000
[+] Wrote DLL path to target memory
[+] Found LoadLibraryW @ 0x7FFE12345678
[+] Created remote thread (TID: 5678)
[+] Remote thread completed, return value: 0x00007FFE90000000 (DLL base)
Injection successful! DLL loaded at 0x00007FFE90000000
C:\> injector --pid 1234 --list
Modules in notepad.exe (PID: 1234):
0x00007FF789000000 notepad.exe
0x00007FFE80000000 ntdll.dll
0x00007FFE78000000 kernel32.dll
...
0x00007FFE90000000 mydll.dll <-- Injected!
Implementation Hints:
The classic injection flow:
// 1. Open target process with required access
HANDLE hProcess = OpenProcess(
PROCESS_CREATE_THREAD |
PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION |
PROCESS_VM_WRITE |
PROCESS_VM_READ,
FALSE,
targetPid
);
// 2. Allocate memory in target for DLL path
size_t pathSize = (wcslen(dllPath) + 1) * sizeof(WCHAR);
LPVOID remoteBuffer = VirtualAllocEx(
hProcess,
NULL,
pathSize,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
);
// 3. Write DLL path to remote memory
WriteProcessMemory(hProcess, remoteBuffer, dllPath, pathSize, NULL);
// 4. Get address of LoadLibraryW (same in all processes due to ASLR per-boot)
HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll");
LPVOID loadLibraryAddr = GetProcAddress(hKernel32, "LoadLibraryW");
// 5. Create remote thread that calls LoadLibraryW with our path
HANDLE hThread = CreateRemoteThread(
hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)loadLibraryAddr,
remoteBuffer,
0,
NULL
);
// 6. Wait for it to complete
WaitForSingleObject(hThread, INFINITE);
// 7. Get exit code (DLL base address or 0 if failed)
DWORD exitCode;
GetExitCodeThread(hThread, &exitCode);
// 8. Cleanup
CloseHandle(hThread);
VirtualFreeEx(hProcess, remoteBuffer, 0, MEM_RELEASE);
CloseHandle(hProcess);
Important questions:
- Why does LoadLibraryW address work across processes?
- What’s the difference between 32-bit and 64-bit injection?
- What protections exist to prevent injection (PPL, CFG, etc.)?
- How would you inject into a process that hasn’t loaded kernel32 yet?
Learning milestones:
- Can inject into normal processes → You understand the basic technique
- Handles 32/64 bit correctly → You understand architecture differences
- Can detect injection failures → You understand what can go wrong
- Understands protections → You know about modern Windows defenses
Project 14: Mini Debugger
- File: LEARN_WIN32_API_DEEP_DIVE.md
- Main Programming Language: C
- Alternative Programming Languages: C++, Rust
- Coolness Level: Level 5: Pure Magic (Super Cool)
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 5: Master
- Knowledge Area: Debugging / Process Control
- Software or Tool: Custom Debugger
- Main Book: “Windows Internals Part 1” by Russinovich, Solomon, and Ionescu
What you’ll build: A command-line debugger that can attach to processes, set breakpoints, step through code, and inspect memory—a stripped-down WinDbg.
Why it teaches Win32: The Windows debug APIs are the ultimate process control mechanism. You’ll learn WaitForDebugEvent, context manipulation, and how breakpoints actually work (int 3, DR registers).
Core challenges you’ll face:
- Debug event loop → maps to WaitForDebugEvent, ContinueDebugEvent
- Handling exceptions → maps to EXCEPTION_DEBUG_EVENT, breakpoints
- Reading/writing context → maps to GetThreadContext, SetThreadContext
- Setting breakpoints → maps to int3 (0xCC) patching, hardware breakpoints
Key Concepts:
- Debug API: “Windows via C/C++” Chapter 24 - Jeffrey Richter
- Exception handling: “Windows Internals Part 1” Chapter 8 - Russinovich
- Context and registers: “Windows via C/C++” Chapter 24 - Jeffrey Richter
- Breakpoint implementation: “Practical Malware Analysis” Chapter 8 - Sikorski & Honig
Difficulty: Master Time estimate: 1 month+ Prerequisites: All previous projects, assembly basics, understanding of x64 ABI
Real world outcome:
C:\> minidbg notepad.exe
minidbg - Mini Windows Debugger
Debugging: notepad.exe (PID: 1234)
Process created. Entry point: 0x00007FF789001000
[BREAKPOINT] ntdll!LdrInitializeThunk
dbg> bp kernel32!CreateFileW
Breakpoint 1 set at 0x00007FFE78012340
dbg> g
[BREAKPOINT] Hit breakpoint 1 at kernel32!CreateFileW
RIP: 0x00007FFE78012340
RCX: 0x00000012ABCD0000 -> L"C:\Users\John\test.txt"
RDX: 0x80000000 (GENERIC_READ)
R8: 0x00000001 (FILE_SHARE_READ)
dbg> k
Call Stack:
kernel32!CreateFileW+0x0
notepad!OpenFile+0x45
notepad!WndProc+0x234
USER32!DispatchMessageW+0x123
notepad!WinMain+0x78
dbg> r
RAX: 0x0000000000000000 RBX: 0x0000000000000000
RCX: 0x00000012ABCD0000 RDX: 0x0000000080000000
R8: 0x0000000000000001 R9: 0x0000000000000000
RIP: 0x00007FFE78012340 RSP: 0x00000012ABCD8000
RFLAGS: 0x0000000000000246
dbg> db rcx
00000012`ABCD0000 43 00 3A 00 5C 00 55 00-73 00 65 00 72 00 73 00 C.:.\.U.s.e.r.s.
00000012`ABCD0010 5C 00 4A 00 6F 00 68 00-6E 00 5C 00 74 00 65 00 \.J.o.h.n.\.t.e.
dbg> g
Process exited with code 0
Implementation Hints:
Basic debug loop:
// Start debugging
DEBUG_EVENT debugEvent;
DWORD continueStatus = DBG_CONTINUE;
// Either create process with DEBUG_PROCESS flag
CreateProcess(..., DEBUG_PROCESS, ...);
// Or attach to existing
DebugActiveProcess(targetPid);
while (TRUE) {
WaitForDebugEvent(&debugEvent, INFINITE);
switch (debugEvent.dwDebugEventCode) {
case CREATE_PROCESS_DEBUG_EVENT:
// Process started - save handle
break;
case EXCEPTION_DEBUG_EVENT:
// Exception occurred
DWORD exceptionCode = debugEvent.u.Exception.ExceptionRecord.ExceptionCode;
if (exceptionCode == EXCEPTION_BREAKPOINT) {
// int3 hit - check if it's ours or system
} else if (exceptionCode == EXCEPTION_SINGLE_STEP) {
// Single step completed
} else {
// Real exception - pass to debuggee
continueStatus = DBG_EXCEPTION_NOT_HANDLED;
}
break;
case EXIT_PROCESS_DEBUG_EVENT:
// Process exited
return;
case LOAD_DLL_DEBUG_EVENT:
// DLL loaded - good time to set breakpoints
break;
}
ContinueDebugEvent(
debugEvent.dwProcessId,
debugEvent.dwThreadId,
continueStatus
);
continueStatus = DBG_CONTINUE;
}
Setting a software breakpoint:
// 1. Read original byte
BYTE originalByte;
ReadProcessMemory(hProcess, address, &originalByte, 1, NULL);
// 2. Write int3 (0xCC)
BYTE int3 = 0xCC;
WriteProcessMemory(hProcess, address, &int3, 1, NULL);
// 3. When breakpoint hits, restore original byte and single-step
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_FULL;
GetThreadContext(hThread, &ctx);
// Restore original byte
WriteProcessMemory(hProcess, address, &originalByte, 1, NULL);
// Back up RIP to re-execute the instruction
ctx.Rip--;
// Enable single-step (TRAP flag)
ctx.EFlags |= 0x100;
SetThreadContext(hThread, &ctx);
// After single-step, re-set the breakpoint
Questions to master:
- Why does RIP point past the int3 when the breakpoint hits?
- How do hardware breakpoints (DR0-DR7) differ from software breakpoints?
- What’s the difference between first-chance and second-chance exceptions?
- How do you handle multi-threaded debugging?
Learning milestones:
- Can attach and see events → You understand the debug loop
- Breakpoints work → You understand int3 and context manipulation
- Single-stepping works → You understand TRAP flag
- Stack traces work → You understand x64 unwinding
Project 15: Custom Heap Allocator
- File: LEARN_WIN32_API_DEEP_DIVE.md
- Main Programming Language: C
- Alternative Programming Languages: C++, Rust
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 4: Expert
- Knowledge Area: Memory Management / Heap Internals
- Software or Tool: Custom Memory Allocator
- Main Book: “Windows Internals Part 1” by Russinovich, Solomon, and Ionescu
What you’ll build: A custom heap allocator using VirtualAlloc that implements malloc/free semantics with your own allocation strategy—understanding how heaps really work.
Why it teaches Win32: This is the deepest understanding of Windows memory management. You’ll learn VirtualAlloc (reserve/commit/decommit), page granularity, and how to build data structures for tracking allocations.
Core challenges you’ll face:
- Using VirtualAlloc correctly → maps to reserve vs commit, page alignment
- Tracking allocations → maps to free lists, headers, coalescing
- Handling fragmentation → maps to allocation strategies, compaction
- Thread safety → maps to locking strategies for heap access
Key Concepts:
- VirtualAlloc: “Windows via C/C++” Chapter 13 - Jeffrey Richter
- Heap algorithms: “Introduction to Algorithms” Chapter 17 - CLRS
- Windows heap implementation: “Windows Internals Part 1” Chapter 5 - Russinovich
- Lock-free data structures: “C++ Concurrency in Action” Chapter 7 - Anthony Williams
Difficulty: Expert Time estimate: 2-4 weeks Prerequisites: Memory map project, data structures knowledge
Real world outcome:
C:\> heaptest
Custom Heap Allocator Test
Allocating 10000 random-sized blocks (16 bytes - 1 MB)...
Allocation time: 45ms
Heap statistics:
Total reserved: 64 MB (16 regions)
Total committed: 12.3 MB
Allocated: 8.7 MB in 10000 blocks
Free: 3.6 MB in 234 free chunks
Overhead: 1.2 MB (9.7%)
Fragmentation: 12.3%
Free half the blocks randomly...
Free time: 23ms
After freeing:
Allocated: 4.2 MB in 5000 blocks
Free: 8.1 MB in 412 free chunks (coalesced from 5234)
Allocate 5000 more blocks...
Reuse rate: 89% (allocated from free list)
Stress test: 1000000 alloc/free cycles...
Completed in 2.3 seconds
Peak memory: 45 MB
Final memory: 12 MB (no leaks)
Implementation Hints:
Basic structure:
typedef struct BlockHeader {
size_t size; // Size of this block (including header)
int free; // Is this block free?
struct BlockHeader* next; // Next block in heap (for coalescing)
struct BlockHeader* prev; // Previous block
} BlockHeader;
typedef struct FreeBlock {
BlockHeader header;
struct FreeBlock* nextFree; // Next in free list
struct FreeBlock* prevFree; // Previous in free list
} FreeBlock;
typedef struct Heap {
CRITICAL_SECTION lock;
FreeBlock* freeList; // Head of free list
void* regionStart; // Start of virtual memory region
size_t regionSize; // Total reserved size
size_t committed; // Currently committed bytes
} Heap;
VirtualAlloc usage:
// Reserve a large region (doesn't use physical memory)
void* region = VirtualAlloc(
NULL,
64 * 1024 * 1024, // 64 MB
MEM_RESERVE,
PAGE_NOACCESS
);
// Commit pages as needed (uses physical memory/pagefile)
VirtualAlloc(
address,
pageSize, // 4 KB typically
MEM_COMMIT,
PAGE_READWRITE
);
// Decommit when no longer needed (returns physical memory)
VirtualFree(
address,
pageSize,
MEM_DECOMMIT
);
Key questions:
- What’s the minimum allocation granularity? (64 KB for reserve, 4 KB for commit)
- How do you handle alignment requirements?
- When should you return memory to the OS (decommit)?
- How do best-fit, first-fit, and segregated free lists compare?
Learning milestones:
- Basic alloc/free works → You understand VirtualAlloc and headers
- Free list works → You understand linked list management
- Coalescing works → You understand reducing fragmentation
- Thread-safe → You understand heap locking
Final Capstone Project: Process Monitor Clone
- File: LEARN_WIN32_API_DEEP_DIVE.md
- Main Programming Language: C
- Alternative Programming Languages: C++, Rust
- Coolness Level: Level 5: Pure Magic (Super Cool)
- Business Potential: 3. The “Service & Support” Model (B2B Utility)
- Difficulty: Level 5: Master
- Knowledge Area: ETW / System Monitoring / Kernel Events
- Software or Tool: System Activity Monitor
- Main Book: “Windows Internals Part 1” by Russinovich, Solomon, and Ionescu
What you’ll build: A comprehensive system activity monitor that shows real-time file, registry, network, and process events across the entire system—a clone of Sysinternals Process Monitor.
Why it teaches Win32: This is the ultimate Win32 project. It combines everything: ETW (Event Tracing for Windows) for kernel events, multiple consumers, high-throughput event processing, and sophisticated filtering. You’ll understand how Windows exposes its internal operations.
Core challenges you’ll face:
- Setting up ETW sessions → maps to StartTrace, EnableTraceEx2
- Consuming events in real-time → maps to OpenTrace, ProcessTrace
- Decoding event data → maps to TDH APIs, manifest parsing
- High-volume event handling → maps to buffering, filtering, UI threading
- Correlating events → maps to process tree, stack traces
Key Concepts:
- ETW architecture: “Windows Internals Part 1” Chapter 8 - Russinovich
- ETW APIs: MSDN “Event Tracing” documentation
- Kernel providers: Microsoft-Windows-Kernel-File, Registry, Process
- TDH (Trace Data Helper): MSDN “Retrieving Event Data Using TDH”
Difficulty: Master Time estimate: 1-2 months Prerequisites: All previous projects completed
Real world outcome:
C:\> procmon --filter notepad.exe
Process Monitor - Real-time System Activity
Filter: Process Name = notepad.exe
═══════════════════════════════════════════════════════════════════════════
Time Process Operation Path Result
────────────────────────────────────────────────────────────────────────────
10:23:45.123 notepad.exe CreateFile C:\test.txt SUCCESS
├─ Desired Access: GENERIC_READ | GENERIC_WRITE
├─ Share Mode: FILE_SHARE_READ
└─ Options: FILE_NON_DIRECTORY_FILE
10:23:45.125 notepad.exe ReadFile C:\test.txt SUCCESS
├─ Offset: 0
└─ Length: 4096
10:23:45.130 notepad.exe RegQueryValue HKCU\Software\Microsoft\ SUCCESS
Notepad\fWrap
└─ Data: 1 (DWORD)
10:23:46.456 notepad.exe WriteFile C:\test.txt SUCCESS
├─ Offset: 0
└─ Length: 1234
10:23:46.789 notepad.exe CloseFile C:\test.txt SUCCESS
───────────────────────────────────────────────────────────────────────────
Events: 5,234 | Filtered: 127 | Rate: 45/sec | Buffer: 2% full
Implementation Hints:
ETW session setup:
EVENT_TRACE_PROPERTIES* props = AllocateSessionProperties();
props->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
props->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
props->Wnode.ClientContext = 1; // QPC timestamps
wcscpy(sessionName, L"MyProcMon");
// Start session
StartTraceW(&sessionHandle, sessionName, props);
// Enable kernel providers
CLASSIC_EVENT_ID eventIds[] = {
// File events
{ { FileIOGuid }, 0 /* all events */ },
// Registry events
{ { RegistryGuid }, 0 },
// Process events
{ { ProcessGuid }, 0 },
};
EnableTraceEx2(
sessionHandle,
&SystemTraceControlGuid,
EVENT_CONTROL_CODE_ENABLE_PROVIDER,
TRACE_LEVEL_INFORMATION,
0, 0,
0,
NULL
);
Event consumption:
EVENT_TRACE_LOGFILEW logFile = {0};
logFile.LoggerName = L"MyProcMon";
logFile.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME |
PROCESS_TRACE_MODE_EVENT_RECORD;
logFile.EventRecordCallback = EventCallback;
TRACEHANDLE traceHandle = OpenTraceW(&logFile);
// This blocks and calls EventCallback for each event
ProcessTrace(&traceHandle, 1, NULL, NULL);
Event callback:
VOID WINAPI EventCallback(PEVENT_RECORD eventRecord) {
// eventRecord->EventHeader contains:
// - TimeStamp (QPC)
// - ProcessId
// - ThreadId
// - EventDescriptor.Id (event type)
// Use TDH to decode the event data
DWORD bufferSize = 0;
TdhGetEventInformation(eventRecord, 0, NULL, NULL, &bufferSize);
TRACE_EVENT_INFO* info = malloc(bufferSize);
TdhGetEventInformation(eventRecord, 0, NULL, info, &bufferSize);
// Parse properties based on event type...
}
Key questions to master:
- What’s the difference between kernel-mode and user-mode ETW providers?
- How do you handle the volume of events without dropping any?
- How do you decode stack traces from events?
- What permissions are needed to enable kernel providers?
Learning milestones:
- Can see file events → You understand ETW basics
- Multiple event types work → You understand provider enabling
- Events decode correctly → You understand TDH
- Filtering works efficiently → You understand event processing
- No dropped events under load → You understand buffering
Project Comparison Table
| Project | Difficulty | Time | Depth of Understanding | Fun Factor |
|---|---|---|---|---|
| Error Message Lookup | Beginner | Weekend | ⭐⭐ | ⭐⭐ |
| File Copy Utility | Beginner | Weekend | ⭐⭐⭐ | ⭐⭐ |
| Directory Tree Walker | Beginner | Weekend | ⭐⭐⭐ | ⭐⭐⭐ |
| Registry Explorer CLI | Beginner | Weekend | ⭐⭐⭐ | ⭐⭐ |
| Process Lister | Intermediate | 1-2 weeks | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| Memory Map Viewer | Intermediate | 1-2 weeks | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Simple Command Shell | Intermediate | 1-2 weeks | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| File System Monitor | Advanced | 1-2 weeks | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| DLL Dependency Walker | Advanced | 2-3 weeks | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Thread Pool | Advanced | 2-3 weeks | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| Service Application | Advanced | 1-2 weeks | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| Named Pipe Server | Advanced | 1-2 weeks | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| DLL Injection Tool | Expert | 2-3 weeks | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Mini Debugger | Master | 1 month+ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Custom Heap Allocator | Expert | 2-4 weeks | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Process Monitor Clone | Master | 1-2 months | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
Recommended Learning Path
If you’re new to Win32:
- Start with Error Message Lookup — Get comfortable with the build environment and basic Win32 patterns
- File Copy Utility — Master the handle pattern with CreateFile/ReadFile/WriteFile
- Directory Tree Walker — Learn enumeration patterns
- Registry Explorer — Another handle-based subsystem
- Process Lister — Your first “system” tool
If you have some systems experience:
- Memory Map Viewer — Jump straight into understanding memory
- Simple Command Shell — Master process creation and piping
- File System Monitor — Learn overlapped I/O
- DLL Dependency Walker — Understand PE format and loading
If you want the hardcore path:
- DLL Injection Tool — Combine everything you know about processes and memory
- Mini Debugger — The ultimate control over program execution
- Process Monitor Clone — ETW and kernel-level visibility
Essential Resources
Primary Books
- “Windows via C/C++” by Jeffrey Richter — The Bible of Win32 programming
- “Windows System Programming” by Johnson M. Hart — Practical, example-driven
- “Windows Internals Part 1 & 2” by Russinovich et al. — Deep understanding of how Windows works
Online Resources
- MSDN Documentation — The authoritative reference
- Windows SDK Samples — Official code examples
- ReactOS Source Code — Open-source Windows implementation (great for understanding undocumented behavior)
- Geoff Chappell’s Site — Deep dives into undocumented Windows
Tools You’ll Need
- Visual Studio — IDE and compiler
- Windows SDK — Headers and libraries
- WinDbg — Debugger (preview version recommended)
- Sysinternals Suite — Reference implementations of what you’re building
- API Monitor — See what APIs programs call
- x64dbg — User-mode debugger for testing
Summary
| Project | Main Language |
|---|---|
| Error Message Lookup Tool | C |
| File Copy Utility with Progress | C |
| Directory Tree Walker | C |
| Registry Explorer CLI | C |
| Process Lister (Task Manager Clone) | C |
| Memory Map Viewer | C |
| Simple Command Shell | C |
| File System Monitor | C |
| DLL Dependency Walker | C |
| Thread Pool and Work Queue | C |
| Service Application | C |
| Named Pipe Server | C |
| DLL Injection Tool | C |
| Mini Debugger | C |
| Custom Heap Allocator | C |
| Process Monitor Clone (Capstone) | C |
These projects will take you from Win32 beginner to expert. By the end, you’ll understand Windows at a level that very few developers achieve—you’ll know what’s really happening when you call an API, and you’ll be able to build sophisticated system tools that work at the OS level.