Skip to content

backend: trust the signature over a stale pinned RVA, and stop the guard log line claiming the shield is off - #51

Merged
adiazpar merged 2 commits into
doom-snapmap:mainfrom
mefisme:fix/trust-signature-over-stale-rva
Jul 28, 2026
Merged

backend: trust the signature over a stale pinned RVA, and stop the guard log line claiming the shield is off#51
adiazpar merged 2 commits into
doom-snapmap:mainfrom
mefisme:fix/trust-signature-over-stale-rva

Conversation

@mefisme

@mefisme mefisme commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What this changes

Two follow-ups to 8d50f80, both about the backend reporting build-pinned state honestly. One commit each.

1. ae_pick_engine_fn preferred a stale RVA over a good signature hit.

The helper cross-checks each signature-resolved engine leaf against a hardcoded fallback RVA, and on a
mismatch it REFUSED the signature and used the RVA. That is backwards on the only case it can fire in.
A mismatch means the recorded RVA no longer describes the running build -- either DOOM was patched, or
the value was wrong when written (the four addresses corrected in 8d50f80 were exactly that). In both
cases the RVA points into arbitrary code while the signature is correct, so preferring it guarantees the
outcome the cross-check exists to prevent.

The scan is not a loose match: sig_resolve_one enforces uniqueness across the whole executable range
and reports AMBIGUOUS rather than guessing, so a lone hit is a strong result. The RVA still makes drift
visible (the log line names the leaf and now says to re-derive it) and is still used when the scan misses
entirely, the one case with nothing better.

No behavior change on the pinned build -- both leaves routed through this helper resolve to their
recorded RVA, so the changed branch is never reached. It matters on a patched build, which is where the
old policy was harmful.

2. The rendernode-guard log line claimed the fault shield was off.

Every launch printed rendernode-guard: TEMP-DISABLED (shield-off diagnostic build). The shield was
turned off alongside the guard for the 2026-07-05 diagnostic, was cleared by it, and was re-enabled the
same day -- only the guard stayed off. The wording was never updated, so the log reported a shield state
that had not been true for weeks and reads as a serious regression to anyone scanning it.

Wording only: sh_palette_guard_install stays commented out exactly as it was, so guard behavior is
unchanged. The surrounding comment now states the shield is ACTIVE and records why the guard stays off
(the render-node root cause was fixed at the source in ae_apply_one).

Independent corroboration of 8d50f80

Worth noting since it was found separately: the four addresses in 8d50f80 were reproduced here from a
Steamless-unpacked image of the pinned build, arriving at the same four values. Two additional details
that support the "two builds" framing in that commit:

  • The pinned shipped DOOMx64vk.exe is SteamStub Variant 3.1 (x64) with an encrypted .text;
    searching the shipped file for any engine pattern returns 0 matches. SteamStub decrypts in place and
    does not relocate -- shipped and unpacked section tables are identical apart from .bind -- so the
    unpacked image's RVAs equal the running module's exactly.
  • Confirmed live: with module base 0x7FF6E31B0000, the prefab ctor resolved at 0x7FF6E36FD0A0
    (= RVA 0x54D0A0). The previously stored 0x11AC8D0 would require a base of 0x7FF6E25507D0, which
    is not 64 KB aligned and so is impossible for a loaded module.

Checklist

  • Clean-room: this is my own reverse-engineering / implementation -- no decompiled or copyrighted DOOM or
    original-SnapHak content is pasted into the repo.
  • No binaries added (.dll / .exe / .obj / .pdb / .zip ...) -- the source is the only deliverable.
  • Source stays pure ASCII (.c / .h / .cpp / .ps1).
  • Built + tested locally -- partial, please read:
    • build.ps1 clean.
    • C suite tests\run-tests.ps1 -Doom <unpacked pinned image>: all 16 native tests pass, sig_test
      59/59 unique, 0 RVA-mismatches, hooktol_test 3/3 hook-tolerant, 0 failures.
    • Go suite: gofmt -l clean, go vet ./... clean, go test ./... ok.
    • Not run: package.ps1 -> snapmap-plus install --local dist.
    • In-DOOM: these exact edits were run in DOOM before rebasing onto 8d50f80 -- backend attached,
      59/59 sigs resolved with rva-pinned 59, rva-shifted 0, both C2 sig lines MATCH, and SWF text
      copy/paste plus prefab stage-paste were exercised working. The branch build itself has not been run
      in-game; note that change 1 is unreachable on the pinned build and change 2 is text-only.
  • Docs updated in this PR for any behavior change -- no user-facing behavior changes on the pinned
    build; both changes are explained in-place in the code comments they touch.

mefisme and others added 2 commits July 28, 2026 14:31
ae_pick_engine_fn cross-checks each signature-resolved engine leaf against a
hardcoded fallback RVA and, on a mismatch, REFUSED the signature and used the
RVA instead. That is backwards on the only case it can actually fire in.

A mismatch means the recorded RVA no longer describes the running build --
either DOOM was patched, or the value was wrong when it was written (the four
addresses corrected in 8d50f80 were exactly that). In both cases the RVA points
into arbitrary code while the signature is correct, so preferring the RVA
guarantees the outcome the cross-check exists to prevent.

The scan is not a loose match: sig_resolve_one enforces uniqueness across the
whole executable range and reports AMBIGUOUS rather than guessing, so a lone hit
is a strong result.

The RVA still earns its place. It makes drift VISIBLE -- the log line names the
leaf and now tells you to re-derive it -- and it is still used when the scan
misses ENTIRELY, the one case where there is nothing better and the caller's own
guards have to carry the risk.

No behavior change on the pinned build: both leaves routed through this helper
resolve to their recorded RVA, so the changed branch is never reached. The fix
matters on a patched build, which is precisely where the old policy was harmful.

Build clean; 16/16 native tests, sig_test 59/59 unique with 0 RVA-mismatches,
hooktol_test 3/3 with 0 failures; gofmt/vet/go test clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… is off

The render-node guard has been commented out since the 2026-07-05 shield-off
diagnostic, and its log line still read:

  rendernode-guard: TEMP-DISABLED (shield-off diagnostic build)

The fault shield was turned off alongside the guard for that diagnostic, was
cleared by it, and was RE-ENABLED the same day -- see shield_install() at the end
of bootstrap_thread. Only the guard stayed off. The wording was never updated, so
every launch still reports a shield state that has not been true for weeks, and
it reads as a serious regression to anyone scanning the log.

Wording only. sh_palette_guard_install stays commented out exactly as it was, so
guard behavior is unchanged. The surrounding comment now states plainly that the
fault shield is ACTIVE and records why the guard stays off: the render-node root
cause (a reclassed node-less timeline keeping the pasted command's stale
render-node +0x70) was fixed at the source in ae_apply_one, which makes the guard
a redundant mitigation rather than a load-bearing one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@adiazpar adiazpar left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed against the diff, not the description. Both changes verified: ae_pick_engine_fn now returns the signature on mismatch, and the dllmain change is comment/log wording only with sh_palette_guard_install still commented out. Validated against the real pinned DOOMx64vk image rather than CI alone (CI has no game image): sig_test 59/59 unique, 0 RVA-mismatches, hooktol_test 3/3, all 16 native suites green. The zero mismatches independently confirm the changed branch is unreachable on the pinned build, so the policy change is inert here and only takes effect on a patched build.

@adiazpar
adiazpar merged commit 45a05e8 into doom-snapmap:main Jul 28, 2026
2 checks passed
@mefisme
mefisme deleted the fix/trust-signature-over-stale-rva branch July 29, 2026 04:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants