diff --git a/WhiteMagic/Execution/RemoteThreadExecutor.cs b/WhiteMagic/Execution/RemoteThreadExecutor.cs index b584c1a..425ad2b 100644 --- a/WhiteMagic/Execution/RemoteThreadExecutor.cs +++ b/WhiteMagic/Execution/RemoteThreadExecutor.cs @@ -472,46 +472,42 @@ public sealed class RemoteThreadExecutor nuint mask = AllocationGranularity - (nuint)1; nuint aligned = (preferred + AllocationGranularity - (nuint)1) & ~mask; - for (int i = 0; i < NearAllocationAttempts; i++) + for (long delta = 0; delta <= (long)0x7FFF; delta++) { - nuint candidate; - if (i == 0) + long signedOffset = delta * (long)AllocationGranularity; + + // Try above, then below the target. Keep the original address as the first attempt. + for (int sign = 0; sign < 2; sign++) { - candidate = aligned; - } - else if ((i & 1) == 1) - { - candidate = aligned + (nuint)i * AllocationGranularity; - } - else - { - nuint offset = (nuint)i * AllocationGranularity; - if (offset > aligned) - { + if (delta == 0 && sign != 0) continue; + + long offset = sign == 0 ? signedOffset : -signedOffset; + nuint candidate = (nuint)((long)aligned + offset); + + // Avoid underflow to zero on below-target search. + if (offset < 0 && candidate >= aligned) + continue; + + IntPtr result = NativeMethods.VirtualAllocEx( + handle, + (IntPtr)(nint)candidate, + size, + MemoryAllocationType.Commit | MemoryAllocationType.Reserve, + MemoryProtectionType.ExecuteReadWrite); + + if (result != IntPtr.Zero) + { + long distance = (long)(nuint)(nint)result - (long)(nuint)(nint)preferredAddress; + if (distance >= int.MinValue && distance <= int.MaxValue) + return result; + + // The allocator gave us a nearby candidate but on the wrong side + // of the 2 GiB boundary; treat it as unusable and keep searching. + NativeMethods.VirtualFreeEx(handle, result, 0, MemoryFreeType.Release); } - - candidate = aligned - offset; - } - - IntPtr result = NativeMethods.VirtualAllocEx( - handle, - (IntPtr)(nint)candidate, - size, - MemoryAllocationType.Commit | MemoryAllocationType.Reserve, - MemoryProtectionType.ExecuteReadWrite); - - if (result != IntPtr.Zero) - { - return result; } } - return NativeMethods.VirtualAllocEx( - handle, - IntPtr.Zero, - size, - MemoryAllocationType.Commit | MemoryAllocationType.Reserve, - MemoryProtectionType.ExecuteReadWrite); - } + return IntPtr.Zero; } } diff --git a/WhiteMagic/Injection/DllInjector.cs b/WhiteMagic/Injection/DllInjector.cs index 6d87a26..50df5e3 100644 --- a/WhiteMagic/Injection/DllInjector.cs +++ b/WhiteMagic/Injection/DllInjector.cs @@ -383,7 +383,7 @@ public sealed class DllInjector if (value != IntPtr.Zero) return value; - Thread.Sleep(5); + System.Threading.Thread.Sleep(5); } return IntPtr.Zero; diff --git a/WhiteMagicTest/Injection/DllInjectorTests.cs b/WhiteMagicTest/Injection/DllInjectorTests.cs index 5ae8b86..71cf675 100644 --- a/WhiteMagicTest/Injection/DllInjectorTests.cs +++ b/WhiteMagicTest/Injection/DllInjectorTests.cs @@ -1,4 +1,5 @@ using System.Runtime.InteropServices; +using Thread = System.Threading.Thread; using WhiteMagic; using WhiteMagic.Injection; using WhiteMagic.Native; @@ -69,7 +70,7 @@ public class DllInjectorTests int osThreadId = 0; Exception? threadError = null; - var helper = new Thread(() => + var helper = new System.Threading.Thread(() => { try { @@ -80,7 +81,7 @@ public class DllInjectorTests // also be stopped once its original context is restored. while (!stopEvent.IsSet) { - Thread.Sleep(10); + System.Threading.Thread.Sleep(10); } } catch (Exception ex)