The Big Picture: Shared Toolboxes
Imagine every cook in a city owning their own copy of a huge cookbook of basic skills: chopping, boiling, baking. That would waste paper. Instead, the city keeps one shared library of skills, and each cook borrows what they need.
Windows does the same. Instead of each program carrying its own code to draw a window, open a file or play a sound, that code lives in shared files called DLLs (Dynamic-Link Libraries). Programs borrow from them when they start (or later, when needed).
notepad.exe chrome.exe game.exe
\ | /
+--------+-------+--------+-------+
v v
kernel32.dll user32.dll <- one copy in RAM
(files, memory...) (windows, input) shared by all
8.1 Dynamic Libraries
What it is: A dynamic library is a file of ready-made code (functions) that programs can use without including it. On Windows these files end in .dll. They use the same PE layout as .exe files (Section 2.3), but they have no "start here" for a user; they are toolboxes.
Why DLLs exist:
| Reason | Benefit |
|---|---|
| Save memory and disk | Many programs share one copy of common code (the code pages are shared, Section 4.2) |
| Easy updates | Fix a bug in one DLL and every program using it benefits |
| Smaller programs | The .exe only holds its own logic |
| Plug-ins | A program can load extra features at runtime |
The opposite is static linking: the library's code is copied into the program when it is built. That makes the .exe bigger and self-contained, but each program carries its own copy.
Famous DLLs found in every Windows process:
| DLL | What it offers |
|---|---|
| ntdll.dll | The lowest layer; talks to the kernel (system calls) |
| kernel32.dll (and kernelbase.dll) | Files, memory, processes and threads |
| user32.dll | Windows, messages, keyboard and mouse |
| gdi32.dll | Drawing text and shapes |
| advapi32.dll | Registry and security functions |
You may also hear the word module. A module is any file loaded into a process: the .exe itself plus every DLL. Section title "Process Modules" means this list.
8.2 DLL Loading
What it is: Loading a DLL means mapping it into the process's address space (Section 4.2) so its functions can be called. It happens in two ways:
| Way | When | How |
|---|---|---|
| Load-time (implicit) | While the process starts | The loader reads the program's import table (8.3) and loads every DLL listed. If one is missing, the program won't start ("... was not found" error) |
| Run-time (explicit) | Whenever the program decides | The program calls LoadLibrary with a DLL name, then GetProcAddress to find a function by name, and FreeLibrary when finished. Used for plug-ins and optional features |
Where does Windows look? If the program gives only a name like mylib.dll, Windows searches places in a set order: known system DLLs first, then the program's own folder, then system folders, and so on. A careless search can be tricked: an attacker puts a fake DLL with the same name in a folder searched earlier (DLL hijacking). Modern programs give full paths or restrict the search to avoid it.
Reference counting. Each LoadLibrary adds 1 to a counter in that process; each FreeLibrary subtracts 1. The DLL leaves the process when the counter reaches 0.
Shared RAM, private data. The first time a DLL is loaded on the PC, its code is read from disk into RAM. When a second process loads the same DLL, Windows maps the same RAM pages into it (shared). Each process gets its own private copy of the DLL's changing data (copy-on-write, Section 4.2).
DllMain. A DLL can have a small start-up routine, called when it is loaded or unloaded and when threads are created. Careless work in it can cause deadlocks, so good DLLs keep it tiny.
See the list of loaded modules of a running process:
Get-Process notepad | Select-Object -ExpandProperty Modules |
Select-Object ModuleName, FileName
tasklist /M /FI "IMAGENAME eq notepad.exe"8.3 Import Table
What it is: Inside every PE file is an import table: a shopping list that says "I need these functions from these DLLs". For example: "from kernel32.dll I need CreateFileW and ReadFile".
notepad.exe's import table (simplified)
+----------------------------------------+
| DLL: kernel32.dll |
| - CreateFileW |
| - ReadFile |
| - ExitProcess |
| DLL: user32.dll |
| - CreateWindowExW |
| - GetMessageW |
+----------------------------------------+
At start-up, the loader:
- Reads the list.
- Loads each DLL (if not already loaded).
- Finds each function's real address in that DLL.
- Writes those addresses into a table in the program, called the Import Address Table (IAT).
Afterwards, whenever the program calls ReadFile, it jumps to the address stored in the IAT. That table is the "phone book" filled in at start-up. Because the loader fills it in, the program does not need to know where the DLL ended up in memory.
Some programs use delay-load: the DLL is loaded only the first time one of its functions is called. That makes start-up faster.
8.4 Exported Functions
What it is: The other side of the import table. A DLL has an export table: the list of functions it offers to others. The exports are the DLL's "front desk". Anything not exported stays private inside.
A function can be exported:
- By name, such as
CreateFileW. - By ordinal, a plain number in the table (less common, less readable).
When a program imports ReadFile from kernel32.dll, the loader looks in kernel32's export table, finds ReadFile, and reads its location. This is the same job GetProcAddress does for run-time loading.
Sometimes an export is a forwarder: "I don't implement this myself; look in that other DLL." Many of kernel32's functions forward to kernelbase.
Exports can also be data and not just functions, but functions are far more common.
Tools to see imports and exports: Developer tools such as dumpbin /imports (from Visual Studio) or free third-party viewers. You do not need them for this course. The Modules listing from 8.2 is enough.
8.5 Base Address and Relocation
What it is: Every PE file states a preferred base address: the spot in the address space where it would like to be loaded. If that spot is free, all the addresses written inside the file are already correct, and nothing needs fixing.
But the spot may be taken (another module is already there), or Windows may choose a different place on purpose for security (ASLR, Section 2.5). Then the module is loaded elsewhere, and any hard-coded addresses inside it are wrong by some distance. Fixing this is called relocation.
Preferred: load at 0x10000000 Actual: loaded at 0x20000000
code says "jump to 0x10001000" must become "jump to 0x20001000"
Relocation adds the difference: +0x10000000
How it works: the file contains a relocation table, a list of all spots inside it that hold absolute addresses. The loader goes through the list and adds the difference to each one.
| Detail | Why it matters |
|---|---|
| Relocation costs time | Pages that must be changed are no longer identical to the file, so they cannot be shared between processes and each process gets its own private copy |
| ASLR makes it common | The same DLL may sit at different addresses in different processes, or after each reboot |
| Position-independent code | Modern 64-bit code mostly uses relative addressing ("jump 200 bytes ahead") so it needs little or no relocation |
For Windows system DLLs, ASLR picks a random base once per boot, and every process shares that address for the DLL, which keeps the shared RAM benefit.
You can see a module's base address in PowerShell: (Get-Process notepad).Modules | Select ModuleName, BaseAddress. Run it in two different programs: the same DLL (like kernel32.dll) is usually at the same address in both during one boot, but a different address after the next restart.
Summary
| Term | Plain meaning |
|---|---|
| DLL | Shared file of code that many programs borrow |
| Module | Any file loaded into a process (the .exe and every DLL) |
| Load-time vs run-time loading | At start-up from the import list vs on demand with LoadLibrary |
| Import table / IAT | Shopping list of needed functions / the phone book the loader fills in |
| Export table | The functions a DLL offers |
| Base address | Where a module is placed in the address space |
| Relocation | Fixing hard-coded addresses when the module is not at its preferred spot |
| ASLR | Random placement for security |
| DLL hijacking | Tricking a program into loading a fake DLL |