fix(scanner): tighten prologue fallback to require unique match - #80
Conversation
Raise kPrologueFallbackMinTailLiterals from 5 to 10 and kPrologueFallbackMaxHits from 4 to 1 so the rewritten near-JMP pattern must resolve to exactly one site backed by ten literal tail bytes. Adds boundary regressions for the nine-byte tail and two-match cases.
📝 WalkthroughWalkthroughThis PR tightens the prologue-fallback pattern matching by raising the minimum literal tail requirement from 5 to 10 bytes and lowering the maximum hit count from 4 to 1, with matching documentation clarifications and expanded test coverage including new regression tests. ChangesPrologue-Fallback Threshold and Guardrail Tightening
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
tests/test_scanner.cpp (1)
2035-2036: ⚡ Quick winMove byte-template comments above the lines and state rationale
These inline trailing comments are “what” comments; convert them to line-above “why” comments to match project comment conventions.
Suggested edit
- constexpr std::uint8_t kAmbiguousTemplate[] = { - 0xE9, 0x00, 0x00, 0x00, 0x00, // JMP rel32 - 0xA5, 0xB6, 0xC7, 0xD8, 0xE9, 0xFA, 0x0B, 0x1C, 0x2D, 0x3E, 0x4F, // unique 11-byte tail - }; + constexpr std::uint8_t kAmbiguousTemplate[] = { + // Starts with a hook-shaped E9 rel32 prologue so fallback rebuilding can match this layout. + 0xE9, 0x00, 0x00, 0x00, 0x00, + // Tail is intentionally uncommon to avoid incidental matches in executable pages. + 0xA5, 0xB6, 0xC7, 0xD8, 0xE9, 0xFA, 0x0B, 0x1C, 0x2D, 0x3E, 0x4F, + }; - constexpr std::uint8_t kTemplate[] = { - 0xE9, 0x00, 0x00, 0x00, 0x00, // JMP rel32 - 0x71, 0x82, 0x93, 0xA4, 0xB5, 0xC6, 0xD7, 0xE8, 0xF9, 0x0A, 0x1B, // unique 11-byte tail - }; + constexpr std::uint8_t kTemplate[] = { + // Uses E9 rel32 prologue shape to exercise fallback rewrite matching. + 0xE9, 0x00, 0x00, 0x00, 0x00, + // Tail uniqueness keeps the test focused on the two seeded matches. + 0x71, 0x82, 0x93, 0xA4, 0xB5, 0xC6, 0xD7, 0xE8, 0xF9, 0x0A, 0x1B, + };As per coding guidelines: Inline comments (
//) used inside function bodies must explain why, not what. Place on the line above the code they describe.Also applies to: 2099-2100
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/test_scanner.cpp` around lines 2035 - 2036, Change the inline trailing “what” comments on the byte array lines (the lines containing the JMP rel32 sequence "0xE9, 0x00, 0x00, 0x00, 0x00" and the unique tail "0xA5, 0xB6, 0xC7, 0xD8, 0xE9, 0xFA, 0x0B, 0x1C, 0x2D, 0x3E, 0x4F") so that the descriptive text moves to a separate line above each statement and explains why that byte pattern is present (test intent/ rationale) rather than what the bytes are; update the two occurrences mentioned (current block and the one around the 2099–2100 region) to follow the project convention of line-above “why” comments.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@tests/test_scanner.cpp`:
- Around line 2035-2036: Change the inline trailing “what” comments on the byte
array lines (the lines containing the JMP rel32 sequence "0xE9, 0x00, 0x00,
0x00, 0x00" and the unique tail "0xA5, 0xB6, 0xC7, 0xD8, 0xE9, 0xFA, 0x0B, 0x1C,
0x2D, 0x3E, 0x4F") so that the descriptive text moves to a separate line above
each statement and explains why that byte pattern is present (test intent/
rationale) rather than what the bytes are; update the two occurrences mentioned
(current block and the one around the 2099–2100 region) to follow the project
convention of line-above “why” comments.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9d9dfa0d-6685-445c-96fa-8be8b76f00a1
📒 Files selected for processing (3)
docs/misc/aob-signatures.mdsrc/scanner.cpptests/test_scanner.cpp
Summary
kPrologueFallbackMinTailLiteralsfrom 5 to 10 so the rebuiltE9 ?? ?? ?? ??pattern carries enough literal context to disambiguate from incidental near-JMPs in a multi-MB.textsection.kPrologueFallbackMaxHitsfrom 4 to 1 so a sibling-mod inline-hook recovery only proceeds when the rewritten pattern resolves to exactly one site. Two-or-more is nowNoMatchinstead of silently picking the first.docs/misc/aob-signatures.mdwith the new thresholds, the rationale for each, and a safety note distinguishing sibling inline-hook recovery from game-patch survival (withresolve_cascadeas the strict alternative).Tests
PrologueFallbackHitFindsHookedPrologue: tail extended to 10 bytes to satisfy the new floor.PrologueFallbackRejectsAmbiguousTail: seeds 2 copies (was 5) with an 11-byte unique tail to trip the tightened uniqueness ceiling.PrologueFallbackRejectsNineByteTail: boundary regression that a 9-byte literal tail surfacesPrologueFallbackNotApplicable.PrologueFallbackRejectsExactlyTwoMatches: boundary regression that exactly two matches now resolve toNoMatch.Risk
Cold-path tightening. Behavior changes only when the cascade missed and the fallback would previously have engaged on a short or ambiguous tail; in those cases the API now returns
PrologueFallbackNotApplicableorNoMatchinstead of an unstable address.Summary by CodeRabbit
Bug Fixes
Tests