diff --git a/WhiteMagic/Hooking/Detour.cs b/WhiteMagic/Hooking/Detour.cs index 541ef41..f9fcb43 100644 --- a/WhiteMagic/Hooking/Detour.cs +++ b/WhiteMagic/Hooking/Detour.cs @@ -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);