From 91e5e05de4f51f7035586b23e36720795c72badb Mon Sep 17 00:00:00 2001 From: Gregory Lirent Date: Fri, 26 Jun 2026 07:57:35 +0300 Subject: [PATCH] Scope gva_code_xref by an explicit prot_any argument It hard-coded VR_X, so a target whose page tables expose no executable region silently yielded zero xrefs. Callers now pass the scope (VR_X to restrict to code, VR_R when the X bit is unavailable); the decoder and exact target match remain the correctness gate. Mirrors the prot_any parameter gva_imm_xref already carries. --- include/scan.h | 21 ++++++++++++--------- src/handlers/codescan.c | 4 ++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/include/scan.h b/include/scan.h index bdbb458..e0f885a 100644 --- a/include/scan.h +++ b/include/scan.h @@ -70,18 +70,21 @@ int gva_sig_scan_multi(vmie_mem* m, uintptr_t cr3, uint64_t lo, uint64_t hi, uint32_t prot_any, const sigset* s, sig_multi_hit* out, int max); -/* code-xref: every instruction in the X-regions of [lo,hi] whose near rel - * branch or RIP-relative memory operand resolves to `target_va`. Brute-scans - * each byte offset with the light x86-64 decoder (x86dec.h, NOT a full - * disassembler): an E8/E9/EB/Jcc rel branch matches when next_rip + rel == +/* code-xref: every instruction in the regions of [lo,hi] kept by `prot_any` + * whose near rel branch or RIP-relative memory operand resolves to `target_va`. + * Brute-scans each byte offset with the light x86-64 decoder (x86dec.h, NOT a + * full disassembler): an E8/E9/EB/Jcc rel branch matches when next_rip + rel == * target_va, and any RIP-relative operand (ModRM mod=00, rm=101) matches when * next_rip + disp32 == target_va (this covers lea/mov and any other rip-rel - * form). Records each matching instruction-start VA. The sweep forces VR_X and - * carries a >=15-byte overlap (max x86 instruction length) so no instruction is - * cut at a window seam. Writes up to `max` VAs to `out` (NULL to count only) and - * returns the TOTAL number of matches, or -1 on bad input. */ + * form). Records each matching instruction-start VA. The sweep is scoped by + * `prot_any` (pass VR_X to restrict to code; pass VR_R when the target's + * page-table X bit is unavailable - the decoder and exact target match keep the + * result correct, only more bytes are decoded) and carries a >=15-byte overlap + * (max x86 instruction length) so no instruction is cut at a window seam. Writes + * up to `max` VAs to `out` (NULL to count only) and returns the TOTAL number of + * matches, or -1 on bad input. */ int gva_code_xref(vmie_mem* m, uintptr_t cr3, uint64_t lo, uint64_t hi, - uint64_t target_va, uint64_t* out, int max); + uint32_t prot_any, uint64_t target_va, uint64_t* out, int max); /* immediate / constant xref: every instruction in [lo,hi] (kept by the * protection filter `prot_any`; pass VR_X to restrict to code) whose IMMEDIATE diff --git a/src/handlers/codescan.c b/src/handlers/codescan.c index a0943ab..58abb24 100644 --- a/src/handlers/codescan.c +++ b/src/handlers/codescan.c @@ -115,10 +115,10 @@ static int xref_sweep_cb(void* u, const uint8_t* data, size_t len, } int gva_code_xref(vmie_mem* m, uintptr_t cr3, uint64_t lo, uint64_t hi, - uint64_t target_va, uint64_t* out, int max) { + uint32_t prot_any, uint64_t target_va, uint64_t* out, int max) { struct xref_cb c; memset(&c, 0, sizeof c); c.target = target_va; c.out = out; c.max = max; - if (gva_sweep(m, cr3, lo, hi, VR_X, X86_MAX_INSN, xref_sweep_cb, &c) < 0) { + if (gva_sweep(m, cr3, lo, hi, prot_any, X86_MAX_INSN, xref_sweep_cb, &c) < 0) { return -1; } return c.n;