The Big Picture: Following a Parcel

Think of a parcel being sent from your door to a faraway warehouse. It goes through a local post office, a sorting centre, a lorry, a depot and finally the warehouse. Then a receipt travels back. You see only two things: you hand it over, and the receipt arrives.

A single Windows call works the same way. This section follows one real call all the way down and back, step by step. Sections 1 to 4 gave you each stage. Now you see them join up.

Our example: a program wants to create a file called notes.txt.

5.1 Step 1: The Application Calls a Win32 Function

What it is: The program (or its language runtime) calls CreateFileW.

HANDLE h = CreateFileW(L"notes.txt", GENERIC_WRITE, 0, NULL,
                       CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

In plain English: "Open notes.txt for writing. If it exists, replace it. If it does not, make it."

How the program finds CreateFileW: when it started, the Windows loader (Chapter 22) read the program's import list, loaded kernel32.dll, and wrote the address of CreateFileW into the program's import table. The call is therefore a normal function call, still inside the program's own process, in user mode.

Note. If the program is written in Python, C#, Java or another language, its runtime calls CreateFileW on its behalf (see Section 1.3).

5.2 Step 2: Win32 Calls the Matching Native API Function

What it is: kernel32.dll forwards the call to kernelbase.dll, which does the Win32 tidy-up. If the program named an API set (Section 2.5), Windows has already swapped it for the real DLL. Then kernelbase.dll:

TaskExample
Checks and fixes inputsIs the file name too long? Is it empty?
Expands the pathnotes.txt becomes C:\Users\You\notes.txt, based on the program's current folder
Changes it to the kernel's style\??\C:\Users\You\notes.txt
Builds Native structuresA UNICODE_STRING and an OBJECT_ATTRIBUTES (Section 3.2)
Chooses the Native functionNtCreateFile

Then it calls ntdll!NtCreateFile. (The ! is how people write "function X inside DLL Y": dll!function.)

5.3 Step 3: The Native API Runs the System Call

What it is: NtCreateFile is a tiny stub in ntdll.dll. It loads its service number into a register and runs the syscall instruction (Section 4.3). The CPU switches from ring 3 to ring 0. We have now crossed the border.

5.4 Step 4: The Kernel Handles the Request

What it is: The kernel entry point looks up the service number in the dispatch table (SSDT, Section 4.2) and runs the kernel's NtCreateFile. This code, inside ntoskrnl.exe, belongs to the I/O Manager and the Object Manager. It:

  1. Checks that the pointers the program gave are really in the program's memory.
  2. Looks up the path in the Object Manager's namespace (the kernel's own tree of names). \??\C: points to the disk volume for drive C.
  3. Asks the Security Reference Monitor: "Is this user allowed to create a file here?" (This is where ERROR_ACCESS_DENIED can start.)
  4. Creates a file object and a handle for it (Chapter 9).
  5. Builds an I/O request, a package that says "create this file", and sends it down to the right driver.

5.5 Step 5: The Kernel Calls Into a Driver if Hardware Is Involved

What it is: The I/O Manager passes its request package to a stack of drivers, each doing one job. The first is the file system driver (for most PCs, NTFS, the file system you will meet in the later chapters on file systems and storage). It:

  • Works out where on the disk the file's information goes.
  • Updates its records (the file name, size, time stamps, the journal that protects it against crashes).
  • Hands a smaller request to the volume and disk drivers below it.
File system driver (NTFS)   "create 'notes.txt' in this folder"
        │
        ▼
Volume / partition driver    "translate to a place on the disk"
        │
        ▼
Disk / storage driver        "send this command to the SSD"

A recently written file is often kept in RAM first, in the cache, and written to the disk a little later. So a call to create a file may be answered quickly even before the SSD has finished. Windows lets programs ask for stronger guarantees when they need them.

5.6 Step 6: The Driver Communicates With the Hardware

What it is: The lowest driver in the stack, for an SSD usually the NVMe driver (Chapter 4 explained NVMe and PCIe), writes a command into a queue in RAM and rings a "doorbell" on the device. The SSD then reads the command using DMA (Chapter 4, Section 4), does the work and sends back an interrupt (Chapter 4, Section 3) to say "done". The driver's interrupt handler marks the request as finished.

5.7 Step 7: The Result Returns Back Up the Chain

What it is: The answer takes the same road in reverse:

StepWhoWhat they do
1DriverMarks the request complete
2I/O ManagerFills in a status block (success, plus how many bytes)
3KernelReturns an NTSTATUS and the new handle to the syscall return path
4CPUExecutes sysret: back to ring 3
5ntdll!NtCreateFileReturns to its caller
6kernelbase.dllTranslates NTSTATUS into a Win32 result. On success, returns the handle. On failure, returns INVALID_HANDLE_VALUE and stores an error code
7The programReceives the handle and keeps going

The handle is just a ticket number. The real object stays in the kernel. The program only holds the ticket, and uses it for later calls such as WriteFile(h, ...) and CloseHandle(h).

5.8 The Whole Chain in One Picture

 ┌───────────────────────────────────────────────────────────┐
 │ USER MODE (ring 3)                                        │
 │                                                           │
 │  Your program:  CreateFileW(L"notes.txt", ...)            │
 │        │                                         ▲        │
 │        ▼                                         │        │
 │  kernel32.dll ──► kernelbase.dll   (Win32 work)  │        │
 │        │                                         │        │
 │        ▼                                         │        │
 │  ntdll.dll:  NtCreateFile  (stub)                │        │
 │        │  syscall                         handle │        │
 └────────┼──────────────────────────────────────────┼───────┘
 ═════════╪═══════ border: ring 3 / ring 0 ═══════════╪════════
 ┌────────▼──────────────────────────────────────────┴───────┐
 │ KERNEL MODE (ring 0)                                      │
 │                                                           │
 │  System service dispatch (SSDT) ──► NtCreateFile          │
 │        │                            (ntoskrnl.exe)        │
 │        ▼                                                  │
 │  Object Manager + Security check + I/O Manager            │
 │        │                                                  │
 │        ▼                                                  │
 │  File system driver (NTFS) ──► disk driver (NVMe)         │
 └────────┼──────────────────────────────────────────────────┘
          ▼
   SSD hardware  (command via DMA, then an interrupt back)

The whole trip normally takes a tiny fraction of a millisecond when the data is in the cache. It takes longer if the SSD has to be reached.

5.9 A Second Example: MessageBox and VirtualAlloc

The same layers apply to every call. Here are two other trips, shown briefly.

Example A: VirtualAlloc. "Give me memory."

Program   VirtualAlloc(NULL, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)
   │
   ▼
kernel32 / kernelbase    (Win32: checks the inputs)
   │
   ▼
ntdll!NtAllocateVirtualMemory  ──► syscall
   │
   ▼  ring 0
Memory Manager   finds a free range of virtual addresses and
                 sets it up (no physical RAM is used until touched)
   │
   ▼
Back up: the program gets the starting address of the new memory

No driver and no hardware is involved. The Memory Manager is part of the kernel. This is the virtual memory idea from Chapter 3 (and Chapter 8). The result is an address, not a handle.

Example B: MessageBoxW. "Show a pop-up."

Program   MessageBoxW(NULL, L"Hello", L"Title", MB_OK)
   │
   ▼
user32.dll    (the window and message part of Win32)
   │
   ▼
win32u.dll    (a small bridge that makes the window system calls)
   │
   ▼  syscall (to the window-system part of the kernel, "win32k")
   │
   ▼  ring 0
Window manager creates the pop-up; the graphics driver draws it

Unlike a file call, a window call goes through user32.dll and win32u.dll, not through the file Native API. It uses the second table of services (the "shadow" table from Section 4.2). The idea is the same, and you can still see ntdll.dll and kernel32.dll used along the way.

CallStarts inNative or bridge layerKernel partDriver and hardware?
CreateFileWkernel32 / kernelbasentdll!NtCreateFileI/O and Object ManagersYes (file system, disk)
VirtualAllockernel32 / kernelbasentdll!NtAllocateVirtualMemoryMemory ManagerNo
MessageBoxWuser32win32u.dllWindow systemYes (graphics)

5.10 Why This Knowledge Is Useful

SituationHow the chain helps
A program says "Access denied"The error began in the kernel's security check and was translated up
A program is slow reading tiny piecesEach call is a full trip through the chain. Read in bigger blocks
Security software shows NtCreateFileNow you know it is the Native version of "create/open file"
Process Monitor shows CreateFileIt shows the file operation at the kernel side. Section 6 lets you try
An old program works on Windows 11It uses Win32, which is stable. The layers below changed freely

Summary

StepLayerMode
1Application calls CreateFileWUser
2kernelbase.dll checks inputs, builds structures, calls NtCreateFileUser
3ntdll.dll stub runs syscallUser, then crosses the border
4Kernel dispatches and validates (I/O, Object, Security)Kernel
5File system driver, then disk driverKernel
6SSD does the work (DMA, interrupt)Hardware
7Result and handle return up the same roadKernel, then user