The previous chapter treated the game as a running process. A process dump or module snapshot can list its DLLs, but a familiar D L L name alone does not prove which file supplied the code. Module identity is the next layer of evidence. We will follow that identity through loading and A P I, application programming interface, resolution, then ask which privileges protect the kernel boundary and how a physical-memory capture relates to a process address. At each stage, the practical question is the same: what did the tool actually observe and trust?
Section: A module name is not a full identity.
A game may report that it loaded opengl32.dll, zlib1.dll, or another familiar name. The name alone does not say which file supplied the bytes. The full path, file hash, signer, architecture, and loaded range provide stronger identity.
In brief: A D L L name is a clue; path, build, hash, architecture, and loaded range make the observation specific.
That matters for debugging as well as defense. Loading the wrong version of a legitimate D L L can cause missing exports, crashes, changed structure layouts, or code patterns that no longer match the ones this course uses.
Section: Imports begin a dependency graph.
The P E, portable executable, import table names DLLs and functions the image expects. The Windows loader must locate suitable D L L files, map them, resolve imported function addresses, and repeat the process for those DLLs’ dependencies.
Alternative: Module loading grows a dependency tree: each imported library can bring its own imports, so the final loaded set is larger than one executable’s list.
Code example. The surrounding prose explains this example; the full lesson contains the exact code.
The final loaded set can also include modules requested later with LoadLibrary, graphics layers, accessibility tools, capture software, overlays, or optional game components.
The loader owns the transition from a requested dependency name to a mapped, registered module in the process:
A module snapshot observes the published records after these steps. It does not own the mappings and must not treat a snapshot entry as permission to unload one.
Section: Search order is a compatibility and security boundary.
When code supplies only a D L L name instead of a full path, Windows follows documented resolution rules. Those rules depend on factors such as packaged-app identity, A P I sets (virtual D L L names that Windows redirects to whichever real D L L implements them on that build), side-by-side manifests, already loaded modules, the KnownDLLs list (a fixed set of core system DLLs, recorded in the registry, that Windows always loads from the trusted system directory instead of searching for them), safe D L L search mode (a per-process setting that moves the current working directory later in the search order, so a file planted there is less likely to be picked over the real system D L L), the executable directory, system directories, and configured search paths.
Do not reduce that to “Windows always checks this one folder first.” The precise order depends on how the load was requested and the Windows environment.
For the most common case, an unpackaged desktop program that calls LoadLibrary with a bare name while safe D L L search mode is on (the default), Microsoft documents this order:
The first searched folder that contains a file with that name supplies the D L L. Every check above the numbered searches happens before any folder is searched, which is why a planted file cannot stand in for a KnownDLL. Packaged apps and a few redirection features add steps that the diagram leaves out.
Predict first
C:\Games\Demo\demo.exe calls LoadLibrary with the bare name example.dll, which is not loaded yet and not a KnownDLL. One copy is in C:\Windows\System32 and another in the current folder, C:\Users\Player\Downloads. Safe D L L search mode is on.
Which file loads?
Answer: The copy in System32. With safe search mode on, System32 is search 2 and the current folder is search 5. The game folder (search 1) has no copy, so search 2 finds the file first and the search stops there.

With safe D L L search mode off, the current folder moves up to search 2, right after the application’s folder; holding it back behind the system folders is what the setting does. Either way, both copies report the same short name, example.dll. Only the full path, and the file’s hash and signer, tell a tool which one actually loaded.
Safer application design uses:
supported installation directories with controlled permissions;
manifests and supported side-by-side versioning where appropriate;
LoadLibraryEx flags that express the intended search scope;
absolute paths for application-controlled plug-ins when practical;
no writable current-working directory inserted into dependency search.
This lesson observes what actually loaded. It does not place replacement DLLs into candidate folders or redirect the loader.
Section: Take a ToolHelp module snapshot.
TH32CS_SNAPMODULE lists modules matching the tool’s native architecture. TH32CS_SNAPMODULE32 also asks a 64-bit inspector to include 32-bit modules. The course uses both because the historical game builds are 32-bit.
Each MODULEENTRY32W includes:
modBaseAddr: live module base;
modBaseSize: mapped image size;
szModule: short module name;
szExePath: full file path;
the owner P I D, process identifier, and module handles used by Windows.
The structure has a fixed layout, and the caller must set dwSize first because that layout’s size differs between 32-bit and 64-bit builds. In the 32-bit build this course uses, it looks like this:
Additional detail: Complete lab source: module_inventory.rs.
Code example. The code’s comments explain: SAFETY: the P I D is a value and OwnedHandle owns the snapshot. SAFETY: entry has the required size and is writable. SAFETY: entry remains a valid output structure.
Section: Run a clean baseline.
Start a fresh local game without optional overlays or mod loaders:
Terminal window
Code example. The surrounding prose explains this example; the full lesson contains the exact code.
Capture the result again after entering a match. Some games delay-load graphics, audio, or networking components, so a later list may legitimately be longer.
Repeat the experiment for AssaultCube and Urban Terror:
Terminal window
Code example. The surrounding prose explains this example; the full lesson contains the exact code.
Section: Turn the list into a baseline.
An approved baseline describes each non-system module with:
full canonical path;
SHA-256 hash from the integrity-manifest lesson;
file size and version;
expected publisher or project source;
why and when the game loads it;
which exact game build the entry belongs to.
A different module is not automatically malicious. It may be a graphics capture layer, accessibility tool, language pack, supported mod, or updated dependency. Investigate before removing anything.
Section: Snapshot limitations.
The module list is a moment-in-time view. A D L L may load or unload immediately afterward. A module manually mapped without normal loader registration may not appear in the ToolHelp loader list. A protected or cross-architecture target may restrict enumeration.
A D L L that loads and unloads between two snapshots appears in neither list, even though its code ran inside the game:
Narration: Two clean snapshots can miss a D L L that ran and unloaded between them. Snapshot absence is therefore weaker than a complete history of loads.
Each of these sources sees module loading from a different place, so each one covers something another misses:
ToolHelp module list: the modules the loader has registered, at one instant;
E T W, Event Tracing for Windows, image-load events: every image mapping and unmapping over time, including DLLs that came and went between snapshots;
file hashes and signatures: which bytes are on disk, and who signed them;
the process memory map: every committed region, including executable memory that no module in the list accounts for;
the P E import table: which DLLs the executable declares it needs before it runs;
debugger module events: load and unload notifications as they happen.
Section: Keep defensive observation separate from loader manipulation.
The course does not hide modules, unlink loader entries, overwrite an existing module, or exploit search-order mistakes. Those actions corrupt the loader records that this chapter’s tools read, and that debuggers and crash reporters rely on too.
The complete inventory is module_inventory.rs. Combine its paths with integrity_manifest.rs for a repeatable baseline.
References: dynamic-link library search order, ToolHelp snapshots, and MODULEENTRY32W.