-
-
Notifications
You must be signed in to change notification settings - Fork 40
Pre resolved symbol catalog
OpenGlass normally resolves private DWM symbols by loading the exact public PDB for uDWM.dll and dwmcore.dll, enumerating complete UNDNAME_COMPLETE names, and matching those names against the selected projection bindings. The pre-resolved symbol catalog is an optimization of that resolution step: it stores audited logical-symbol-to-RVA results for an exact PE/PDB identity inside the architecture-specific OpenGlass DLL.
The catalog does not define projection semantics, extend compatibility ranges, replace Layout metadata, or prove support for a Windows build. OpenGlass/ProjectionSchemas/legacy/ and OpenGlass/ProjectionSchemas/milcomp/ remain the only editable projection inventories.
- Start on cataloged binaries without network access or a local Microsoft PDB.
- Remove HTTP and PDB enumeration from the normal injected-DWM startup path for exact catalog hits.
- Preserve the existing PDB cache and Microsoft Symbol Server as fallbacks for uncataloged binaries.
- Reject stale, partial, cross-module, and cross-architecture records before publishing any projected address.
- Keep
uDWM.dllanddwmcore.dllpublication atomic.
- Do not embed complete Microsoft PDB files.
- Do not select RVAs from a Windows marketing name or build/revision alone.
- Do not copy an RVA from one servicing revision to another.
- Do not treat exact symbol resolution as ABI, Layout, hook-contract, semantic, or real-OS evidence.
- Do not update the built-in catalog independently of a signed OpenGlass DLL in the initial implementation.
The architecture deliberately separates three kinds of data:
- Projection schemas declare logical Symbols, complete PDB names, typed ABIs, requirements, binding intervals, fallbacks, and Layout cases. These remain human-reviewed source metadata.
- Resolution audit reports establish the exact PE/PDB pair and the complete-name-to-RVA result produced by the selected DbgHelp implementation.
- Catalog records are normalized derived caches imported from production-candidate resolution reports and validated against the current projection schema.
A catalog record is invalidated when the active resolution contract changes. The contract covers stable ID, kind, type, usage, requirement, configuration condition, selected binding interval, ABI compatibility declaration, and the complete names in that binding. Notes and inactive future bindings do not invalidate an older exact record.
Generated C++ is emitted only below $(IntDir)\Generated\Projection; generated files are never copied into the source tree or edited by hand.
A runtime catalog hit requires all of the following to match the loaded module:
- OpenGlass architecture (
legacyormilcomp); - module (
uDWM.dllordwmcore.dll); - PE machine;
- PE
TimeDateStamp; - PE
SizeOfImage; - RSDS PDB basename;
- CodeView GUID;
- PDB age.
The image file version is still passed to ModuleRegistry::Freeze to select binding and Layout intervals, but it is not sufficient catalog identity. PE and PDB SHA-256 values remain catalog provenance; the built-in runtime does not hash the entire system image on every startup.
The loaded-module and on-disk-file CodeView readers share one checked implementation. It validates PE headers, data-directory bounds, RSDS record bounds, filename termination, and conflicting CodeView records.
Catalog lookup occurs only after both projection registries have successfully frozen their current module versions.
For each module:
- Read the loaded PE identity.
- Find an exact built-in catalog record.
- Validate the complete record before mutating the registry.
- Collect
module base + RVAcandidates by generated symbol index. - If no record matches, use the existing local PDB path.
- If the PDB is absent, use the existing Microsoft Symbol Server download path and parse the result.
- If a matching catalog record is malformed or incomplete, discard it, reset the registry, report the rejection, and use the PDB fallback.
After both modules have collected candidates, OpenGlass retains the existing transaction:
uDWM Reset/Collect/Validate ─┐
├─ CommitModules ─ publish both modules
DwmCore Reset/Collect/Validate ┘
Neither catalog collection nor PDB collection writes m_resolved or projected binding storage. CommitModules remains the only publication boundary.
Each exact module record lists every active Required Symbol and every active Optional Symbol that resolved uniquely for the record's version and configuration.
- An active Required Symbol must resolve uniquely and have exactly one stored name/RVA entry.
- An active Optional Symbol with a unique result has one stored entry.
- A missing or ambiguous Optional Symbol is omitted and uses its existing typed runtime fallback.
- Inactive Symbols are omitted.
- Stable IDs are stored in source records; build generation translates them to the current generated symbol indices.
- Duplicate IDs, duplicate runtime indices, zero or out-of-image RVAs, mismatched names, and an omitted active Required Symbol are errors.
- Code targets must resolve into an executable PE section. Data targets must resolve inside the image.
The complete source record is validated at build time. Runtime validation repeats all cheap safety checks required before address collection: identity, table bounds, unique indices, RVA bounds, section containment, and address-class compatibility.
Catalog outcomes are distinct:
-
NotFound: no exact identity record; use the PDB path without warning. -
Collected: the complete record was accepted and candidates were collected. -
Rejected: an exact record existed but failed validation; clear all partial candidates, record a diagnostic, and use the PDB path.
A rejection before hook preparation is not a DWM FailFast condition. If every fallback also fails, OpenGlass remains pre-hook inert and uses the existing retry/cancel reporting path.
A catalog hit for only one module never permits partial readiness. If the other module cannot validate, CommitModules publishes neither module.
OpenGlass/SymbolCatalogs/inventory/udwm.json and dwmcore.json freeze the exact x64 Winbindex candidates for the build families assigned to each architecture. Refresh inventory separately from evidence collection so moving network data cannot change the target corpus during a collection run:
python Scripts/maintain_symbol_catalog.py inventory . --output-root OpenGlass/SymbolCatalogs/inventory
python Scripts/maintain_symbol_catalog.py collect . --cache PATH_TO_CACHE --dbghelp "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\dbghelp.dll" --missing-output missing-images.json
python Scripts/maintain_symbol_catalog.py verify .
python Scripts/maintain_symbol_catalog.py verify . --cache PATH_TO_CACHE --dbghelp "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\dbghelp.dll"collect requires an explicit Windows Debugging Tools DbgHelp and preserves one resolver version and SHA-256 per architecture catalog. Changing that resolver requires --replace-resolver, which clears every existing shard before recollecting the complete architecture catalog.
The collector downloads each frozen PE through its Microsoft symbol-server image key and rejects a returned file whose SHA-256 differs from the inventory. Those timestamp/SizeOfImage key collisions are committed in inventory/symbol-server-collisions.json. PDB acquisition tries the GUID/age-keyed .pdb object and then the compressed .pd_ form; either is accepted only after CodeView identity validation. Deterministic paired-PDB unavailability and Symbol/RVA rejection are committed in inventory/catalog-exclusions.json. Full transient failure details are written to --missing-output, and failed candidates are never added to runtime shards.
Static verify binds both classification reports to the frozen inventory and requires every candidate to appear exactly once in the runtime catalog, collision report, or exclusion report. With --cache and --dbghelp, it also replays every committed catalog record from the expected cache layout and requires byte-for-byte normalized evidence agreement.
Each architecture index.json explicitly lists every module/build shard. Each shard repeats a complete record for every included PE/PDB identity: complete matched names, full RVAs, address classes, PE/PDB/DbgHelp identities, and the active resolution contract. Records with identical or mostly identical maps remain independent. The source and generated runtime formats deliberately use no delta encoding, shared resolution sets, packed fields, or cross-revision base references; only repeated PDB basename strings share ordinary generated string storage.
Collection accepts only paired PE/PDB production candidates where requested and image versions agree, every active Required Symbol resolves uniquely, and each stored RVA has the expected PE section class. Optional Symbols are stored only when they resolve uniquely; missing or ambiguous Optional Symbols are omitted and use their typed runtime fallback. Output strips machine-local paths, sorts deterministically, writes atomically, and preserves unchanged timestamps.
Resolution audit remains distinct from semantic and real-OS validation. Cataloging an exact identity does not change a projection interval or prove the injection and rendering path on that OS.
The initial catalog is compiled into the signed architecture-specific OpenGlass DLL. There is no independently downloaded RVA database, update key, downgrade policy, or external writable catalog. New exact records ship with a normal OpenGlass release. Unknown identities continue through the PDB path.
A future externally updateable catalog would require a separate signed format, key-rotation policy, rollback protection, schema-contract binding, size limits, and atomic deployment. It is intentionally outside the initial design.
Permanent coverage must include:
- exact identity hit and one-bit GUID mismatch;
- same file version with a different PE/PDB identity;
- architecture and module isolation;
- missing Required and missing Optional Symbols;
- duplicate and out-of-range indices;
- zero, overflowing, out-of-image, and wrong-section RVAs;
- all-or-nothing collection when a late entry is invalid;
- catalog rejection followed by PDB fallback;
- one module resolved while the other fails validation;
- deterministic import and code generation;
- stale resolution-contract rejection;
- both Legacy and MILComp Release builds.
Static validation does not replace real-OS validation of the injection and rendering path. Never install the service or inject into DWM merely to validate catalog generation or unit-level runtime behavior.