You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
| Memory Utilities | Readability checks, region cache, safe pointer reads, typed SEH reads, PE module range queries |`memory.hpp`|
19
19
| MSVC RTTI Walker | Recover mangled type names from runtime vtables; pointer-table scan with caller-owned cache; reverse name-to-vtable resolver and cached identity handle |`rtti.hpp`|
20
20
| RTTI Self-Heal | Reverse-identify the object behind a pointer slot (typed-error and ordered candidate-fallback forms); self-heal a field offset after a patch shifts the struct layout; rigid multi-field drift solver; drift-telemetry report with a durable, diffable manifest (open-failure distinguished from corrupt) |`rtti_dissect.hpp`, `drift_manifest.hpp`|
21
-
| Anchor Registry | One declarative table over the self-healing backends (vtable-by-name, AOB/RIP cascade, in-code constant, string xref, pinned literal) plus two-signal quorum corroboration with sub-anchor independence checks, optional post-resolve validators and opt-in validator policies, a manifest quality diagnostic, and a per-game scan profile (broad-mode default, candidate order, backend deny-list), resolved and reported in a single pass |`anchors.hpp`, `profile.hpp`|
21
+
| Anchor Registry | One declarative table over the self-healing backends (vtable-by-name, AOB/RIP cascade, in-code constant, string xref, pinned literal) plus two-signal quorum corroboration with sub-anchor independence checks, optional post-resolve validators and opt-in validator policies, a manifest quality diagnostic, opt-in parallel table resolution, and a per-game scan profile (broad-mode default, candidate order, backend deny-list), resolved and reported in a single pass |`anchors.hpp`, `profile.hpp`|
22
22
| Event Dispatcher | Typed pub/sub with RAII subscriptions |`event_dispatcher.hpp`|
23
23
| Profiler | Scoped timing with Chrome Tracing export (zero-cost when disabled) |`profiler.hpp`|
24
24
| Format Utilities |`std::format` helpers for addresses, bytes, and VK codes; string trim |`format.hpp`|
@@ -45,6 +45,7 @@ DetourModKit is a full-featured C++23 toolkit designed to simplify common tasks
45
45
-`scan_readable_regions()` -- the data-section sibling of `scan_executable_regions()` -- sweeps every committed readable page (`.rdata` / `.data`, read-only heaps) to reach C++ vtables, RTTI type descriptors, and read-only metadata the executable-only sweep cannot see (guard / no-access / uncommitted pages are skipped); opt a cascade into it with `resolve_cascade(..., ScannerKind::Readable)`
46
46
- The region-walking sweeps (`scan_executable_regions` / `scan_readable_regions` and the module-scoped scans) carry a `pattern_len - 1` overlap across adjacent accepted `VirtualQuery` regions, so a signature that straddles a protection split (two adjacent regions whose base protections differ, e.g. after a sibling `VirtualProtect` carves up `.text`) is still found, without re-counting a match that lies wholly inside one region
47
47
-`scan_regions_batch()` / `scan_module_batch()` -- opt-in fork-join batch scanners that resolve many compiled patterns concurrently (whole process or one mapped image). Each `BatchScanItem` is one independent serial scan distributed across a transient worker pool, so a startup set of N signatures resolves in roughly the time of the slowest single scan rather than their sum; results come back in input order, each item fails closed on a null/empty pattern, zero occurrence, or no match, and patterns are shared read-only (a compiled `CompiledPattern` is immutable during scanning, so no cloning). Setup/control-plane only -- it spawns and joins threads, so never call it from a hook/input callback or under the loader lock
48
+
-`resolve_cascade_batch()` -- opt-in fork-join resolver for startup target tables. Each `CascadeRequest` dispatches to the existing serial cascade resolver (whole-process, module-scoped, with or without prologue fallback), so candidate priority, uniqueness checks, typed errors, and `winning_name` aliasing stay identical to the one-at-a-time calls while results come back in input order
48
49
- `resolve_cascade()` and the module-scoped `resolve_cascade_in_module()` -- ordered multi-candidate resolution (try signatures in priority order, return the first that resolves), with an optional hooked-prologue recovery pass that recovers both an `E9` near-jump and an `FF 25` RIP-relative indirect-jump overwritten prologue (so a target inline-hooked by another mod with either a near or a far jump is recovered); the `_in_module` variants confine the scan to one mapped image `[base, end)` and reject out-of-module resolutions, so a generic signature that also matches inside another injected module (a graphics overlay, a sibling mod) cannot shadow the correct in-module target. By default each candidate must match uniquely in the scanned scope: an ambiguous signature (more than one match) falls through to the next candidate instead of silently committing to an arbitrary match, so a too-loose pattern surfaces as a clean failure to fix rather than a wrong hook. Set `require_unique = false` per candidate only to opt out a deliberately non-unique, separately-verified candidate
49
50
-`resolve_cascade_in_host_module()` / `resolve_cascade_in_host_module_with_prologue_fallback()` -- one-line convenience overloads that scope a cascade to the host EXE (`host_module_range()`), removing the boilerplate of building the range at every call site. They return `ResolveError::InvalidRange` if the host range cannot be determined. Use them only when the target lives in the host EXE; for a game whose logic is in a separate module (an engine DLL), resolve that module's range and call `resolve_cascade_in_module()` instead
50
51
-`read_code_constant(cc, range?)` -- the code-side twin of the RTTI self-heal: declare an instruction site (an AOB cascade) plus which operand to read, and it decodes the live instruction and returns the current immediate or `[reg + disp]` displacement, so a hand-read array stride or struct displacement re-derives itself after a patch instead of being a baked literal. It always decodes (the `nominal` field is telemetry only, never a short-circuit, so a same-shape / different-value drift is reported as the new value), indexes the **visible** operands, resolves a RIP-relative operand to its absolute target, and fails closed (`DecodeFailed` / `UnexpectedShape` / `OperandOutOfRange`). Built on a Zydis decoder kept entirely inside the implementation, so no consumer needs Zydis headers
@@ -190,7 +191,7 @@ See the [Config Hot-Reload Guide](docs/config-hot-reload/README.md) for the thre
190
191
- One declarative table (`Anchors::Anchor[]`) over the self-healing backends, so every magic constant a mod depends on is declared once with its kind and inputs, then resolved and reported in a single pass instead of a scattered wall of hand-maintained offsets and per-call-site resolvers
191
192
- `AnchorKind` covers the backends that resolve from a module range alone: `VtableIdentity` (`Rtti::vtable_for_type`), `RipGlobal` (an AOB/RIP cascade returning an absolute address), `CodeOperand` (`Scanner::read_code_constant`), `StringXref` (`Scanner::find_string_xref`, the most update-resilient kind: the unique instruction or enclosing function that references an immutable string literal), and `Manual` (a pinned literal, surfaced as at-risk in a report). `Quorum` layers corroboration on top: it accepts a target only when two independent sub-anchors resolve and agree (exact or within a tolerance), so a coincidental match must fool both signals. `CallArgHome` is reserved for a future prologue-dataflow backend and reports `Unsupported`
192
193
- Any backend-resolved anchor may carry an optional `validator` (`bool(*)(value, context) noexcept`) that screens the resolved value and fails the anchor closed when it returns false, letting a caller assert a domain invariant a generic backend cannot know
193
-
- `Anchors::resolve(anchor, range?)` resolves one entry; `resolve_all(anchors, out, range?)` fills a parallel `ResolvedAnchor` report (`{label, kind, status, value}`). Resolution is idempotent and side-effect-free, so re-heal-on-miss is just re-running `resolve` on the failing anchor
194
+
- `Anchors::resolve(anchor, range?)` resolves one entry; `resolve_all(anchors, out, range?)` fills a `ResolvedAnchor` report (`{label, kind, status, value}`), and `resolve_all_parallel` does the same work through an opt-in fork-join table resolver. Profile-aware callers have matching `resolve_all_with_profile` and `resolve_all_with_profile_parallel` entry points. Resolution is idempotent and side-effect-free, so re-heal-on-miss is just re-running `resolve` on the failing anchor
194
195
- RTTI pointer-field offset healing (`heal_landmark`) is intentionally not a registry kind: it needs a runtime struct base resolved from another anchor, so it is driven directly once that base is known
0 commit comments