Fix fallback read too short for sparse prologues in redirection helper

Replace the two-attempt read with a single read sized to the smaller of:
- detourLength + 16 (the decoder's preferred window), and
- bytes remaining in the current page (so ReadProcessMemory does not fail whole read).

Reading only detourLength bytes could leave the instruction analyzer without enough
bytes to resolve a multi-byte instruction that crosses the splice point on
sparse prologues. Reading up to the page boundary gives the largest safe window.

Tests: 199 passing, 4 integration/interactive skipped.
This commit is contained in:
kbe
2026-07-22 01:36:52 +02:00
parent 64be4f8275
commit d04428b42e
+13 -10
View File
@@ -66,18 +66,21 @@ public sealed class Detour : IDisposable
int pointerSize = _memory.Is64Bit ? 8 : 4;
int detourLength = pointerSize == 8 ? 14 : 5;
// Try to read detourLength + 16 bytes for the prologue decoder.
// If the target is near a page boundary, this might fail, so fall back to the minimum.
byte[] prologue = _memory.ReadBytes(Target, detourLength + 16);
// The prologue decoder may need to see bytes past the minimum detour length
// to identify the whole instruction that crosses the splice point. Prefer a
// generous read, but if the target sits near an unmapped page boundary, read
// only up to that boundary so ReadProcessMemory does not fail entirely.
int preferredBuffer = detourLength + 16;
int pageSize = Environment.SystemPageSize;
int pageOffset = (int)(Target.ToInt64() & (pageSize - 1));
int bytesToPageBoundary = pageSize - pageOffset;
int readSize = Math.Min(preferredBuffer, bytesToPageBoundary);
byte[] prologue = _memory.ReadBytes(Target, readSize);
if (prologue.Length < detourLength)
{
// Second attempt: read only the minimum required bytes
prologue = _memory.ReadBytes(Target, detourLength);
if (prologue.Length < detourLength)
{
throw new InvalidOperationException(
"Could not read enough bytes from the target function to install a detour.");
}
throw new InvalidOperationException(
"Could not read enough bytes from the target function to install a detour.");
}
int preserveLength = PrologueDecoder.GetWholeInstructionLength(prologue, detourLength, _memory.Is64Bit);