Two processes need to share a megabyte of data. A program wants to read a 4 GB file without allocating 4 GB of memory. The loader needs a single copy of kernel32.dll‘s code to serve every process on the system. All three problems are solved by the same primitive: the section object. Known in the Win32 API as a file mapping, a section represents a region of memory that can be backed by a file on disk or by the paging file, and mapped into one or more address spaces. It underpins DLL loading, shared memory, and memory-mapped file I/O. This article dissects what a section really is, how views of it are mapped and shared, and why it is both a workhorse of the OS and a favorite of stealthy code injection.
Section Objects
A section is a first-class kernel object, managed by the Object Manager with its own type (Section) exactly like Process, Thread, and File objects covered earlier in this series. User mode creates one with CreateFileMapping (or the native NtCreateSection) and receives a handle. Sections come in two fundamental flavors distinguished by what backs their pages:
- File-backed sections — created over an open file handle. The file’s contents are the backing store; touched pages are read from the file on demand and dirty pages are written back to it. This is what a memory-mapped file is.
- Pagefile-backed sections — created with
INVALID_HANDLE_VALUEas the file. These are anonymous shared memory: the backing store is the system paging file, and the section exists only to share data between processes (or within one) by name or inherited handle.
A special and hugely important case is the image section (SEC_IMAGE). When the loader maps an executable or DLL, it creates an image section, which tells the memory manager to lay the PE file out according to its section headers — applying the correct page protections to .text, .data, and the rest — rather than mapping the raw file bytes linearly. Image sections are the bridge between the PE format discussed earlier and the running process.
Mapping Views
Creating a section does not, by itself, place anything in an address space. To access the memory, a process maps a view of the section with MapViewOfFile (native NtMapViewOfSection). A view is a window — possibly of the whole section, possibly a sub-range at some offset — that appears at a base address in the caller’s virtual address space. The process reads and writes the view like ordinary memory; the memory manager handles paging behind the scenes.
Each mapped view is described by a Virtual Address Descriptor in the process’s VAD tree — the same structure introduced in the virtual memory article — but marked as a mapped region rather than private memory, with a pointer back to the section. This is exactly why walking the VAD tree distinguishes Mapped from Private regions: a mapped view is shared, file- or pagefile-backed memory, while private memory belongs to one process alone. When two processes map the same section, their VADs point at the same underlying section object, and — crucially — they end up sharing the same physical pages.
Prototype PTEs and Sharing
Sharing raises a subtle problem the memory manager must solve. If process A and process B both map the same file page, and that page gets trimmed from memory, how does the manager know they were referring to the same physical page — and how does it bring the page back when either process faults on it? Per-process hardware PTEs are not enough, because each process has its own page tables.
The answer is the prototype PTE. For every shareable page, the memory manager maintains a single authoritative software PTE — the prototype — owned by the section, not by any process. Each process’s own PTE for a shared page can point at the prototype rather than directly at a frame. When a process faults on the page, the fault handler follows its PTE to the prototype PTE, which is the single source of truth for where that page currently lives: valid in RAM, on the standby list, or out in the backing file. This indirection (a specific case of the software-PTE formats described in the virtual memory article) is what lets one physical copy serve every mapping and lets the manager find the page no matter which process touches it first.
Copy-on-Write
Pure sharing works when everyone only reads. But some shared pages need to diverge the moment a process writes to them — a DLL’s writable global variables, for instance, must be private to each process even though the DLL’s image is shared. This is handled by copy-on-write (CoW), requested with PAGE_WRITECOPY / SEC_ semantics.
A copy-on-write page is mapped read-only in every sharer’s page tables even though it is logically writable. As long as everyone reads, all processes share one physical copy. The instant a process writes, the CPU raises a protection fault; the memory manager recognizes the CoW marking, allocates a fresh private page, copies the original contents into it, remaps that single process’s PTE to the private copy with write access, and lets the write proceed. Every other process still shares the original. This is the mechanism behind efficient DLL data sections and the general “share until modified” behavior that keeps system memory use low.
Image Sections and DLL Sharing
Image sections tie the previous two ideas together into one of Windows’ most important optimizations. When a DLL is loaded into many processes, its code pages (.text) are read-only and identical everywhere, so a single physical copy is shared across every process through the section’s prototype PTEs — loading ntdll.dll into a hundred processes costs one copy of its code, not a hundred. Its writable data pages, by contrast, are mapped copy-on-write, so each process transparently gets its own private copy as soon as it modifies a global. The result is that shared code is genuinely shared while per-process state stays isolated, all driven by the section and its page protections.
One consequence worth noting: because image pages are backed by the image file itself, the physical memory for a rarely-used DLL page can simply be dropped and re-read from the file rather than written to the pagefile — clean, file-backed pages are cheap to reclaim.
Inspecting Sections and Views
Sections and their views are directly observable. In a kernel debugger you can see how a region is backed and read the section object itself; on a live system, Sysinternals tools show mapped files per process:
# WinDbg: walk a process's VAD tree — note "Mapped" vs "Private" regions,
# and the "ControlArea" / section a mapped view points at.
!process 0 0 notepad.exe
.process /P <eprocess>
!vad <VadRoot>
# Inspect a single mapped region and its backing control area / file
!vad <vad-address> 1
# Dump the section object type and a section instance
dt nt!_SECTION <section-address>
# Find section handles a process holds (Object Manager type "Section")
!handle 0 7 <eprocess> Section
Without a debugger, VMMap visualizes a process’s address space and labels each region as Image, Mapped File, Shareable, or Private, and Process Explorer (View > Lower Pane > DLLs/Handles) lists mapped files and Section handles. Sysinternals handle.exe can enumerate Section handles by name — handy for spotting named shared memory in \BaseNamedObjects.
Security Relevance
Because sections move executable and shared memory around without the “obvious” APIs, they recur throughout offensive tradecraft — and understanding them defensively is what lets a hunter recognize the technique:
- Section-based injection. Instead of
VirtualAllocEx+WriteProcessMemory(a heavily monitored pair), an attacker can create a pagefile-backed section, map a writable view into their own process to stage a payload, then map a second, executable view of the same section into a target process. The code appears in the target as shared, file-mapped memory rather than freshly written private memory — a quieter footprint that classic write-based detections miss. - Mapped vs private as a signal. The flip side is a strong defensive tell: legitimate executable code is almost always image-backed. Executable pages that are
Mapped(pagefile-backed shareable) orPrivateRWX — surfaced by the same!vad/VMMap views above — are exactly what memory scanners flag as possible injected code. - Named-section squatting. Named sections live in the object namespace (typically
\BaseNamedObjects), so a low-privileged process can pre-create a section name that a privileged process expects to create itself — the named-object squatting pattern from the Object Manager article — potentially feeding attacker-controlled shared memory to a service.
All of this is described for defensive understanding and authorized testing only. The takeaway for defenders is concrete: watch for cross-process section mapping (NtMapViewOfSection into a remote process) and treat non-image executable regions as suspect.
Conclusion
Section objects are the quiet machinery behind shared memory, memory-mapped files, and DLL sharing. By pairing views (tracked as mapped VADs) with prototype PTEs and copy-on-write, the memory manager delivers a single physical copy of shared data while keeping per-process modifications private — the same design that makes DLL loading cheap makes stealthy injection possible. With sections understood, the next article turns to how drivers stack filters on top of file and volume I/O: the filter manager and minifilter drivers.
You Might Also Like
This article is part of the Windows Internals series. These related deep-dives cover adjacent parts of the system:



Comments