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
+11 -8
View File
@@ -66,19 +66,22 @@ public sealed class Detour : IDisposable
int pointerSize = _memory.Is64Bit ? 8 : 4; int pointerSize = _memory.Is64Bit ? 8 : 4;
int detourLength = pointerSize == 8 ? 14 : 5; int detourLength = pointerSize == 8 ? 14 : 5;
// Try to read detourLength + 16 bytes for the prologue decoder. // The prologue decoder may need to see bytes past the minimum detour length
// If the target is near a page boundary, this might fail, so fall back to the minimum. // to identify the whole instruction that crosses the splice point. Prefer a
byte[] prologue = _memory.ReadBytes(Target, detourLength + 16); // generous read, but if the target sits near an unmapped page boundary, read
if (prologue.Length < detourLength) // only up to that boundary so ReadProcessMemory does not fail entirely.
{ int preferredBuffer = detourLength + 16;
// Second attempt: read only the minimum required bytes int pageSize = Environment.SystemPageSize;
prologue = _memory.ReadBytes(Target, detourLength); 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) if (prologue.Length < detourLength)
{ {
throw new InvalidOperationException( throw new InvalidOperationException(
"Could not read enough bytes from the target function to install a detour."); "Could not read enough bytes from the target function to install a detour.");
} }
}
int preserveLength = PrologueDecoder.GetWholeInstructionLength(prologue, detourLength, _memory.Is64Bit); int preserveLength = PrologueDecoder.GetWholeInstructionLength(prologue, detourLength, _memory.Is64Bit);
OverwrittenBytes = new byte[preserveLength]; OverwrittenBytes = new byte[preserveLength];