Fix thread namespace collision and tighten executable stub allocation
Fully qualifies System.Threading.Thread in DllInjector after introducing the WhiteMagic.Thread namespace, and replaces the broken+too-small near-allocation loop with a symmetric +/-2 GiB search so the x64 call stub always lands within rel32 range.
This commit is contained in:
@@ -472,46 +472,42 @@ public sealed class RemoteThreadExecutor
|
|||||||
nuint mask = AllocationGranularity - (nuint)1;
|
nuint mask = AllocationGranularity - (nuint)1;
|
||||||
nuint aligned = (preferred + AllocationGranularity - (nuint)1) & ~mask;
|
nuint aligned = (preferred + AllocationGranularity - (nuint)1) & ~mask;
|
||||||
|
|
||||||
for (int i = 0; i < NearAllocationAttempts; i++)
|
for (long delta = 0; delta <= (long)0x7FFF; delta++)
|
||||||
{
|
{
|
||||||
nuint candidate;
|
long signedOffset = delta * (long)AllocationGranularity;
|
||||||
if (i == 0)
|
|
||||||
|
// Try above, then below the target. Keep the original address as the first attempt.
|
||||||
|
for (int sign = 0; sign < 2; sign++)
|
||||||
{
|
{
|
||||||
candidate = aligned;
|
if (delta == 0 && sign != 0)
|
||||||
}
|
|
||||||
else if ((i & 1) == 1)
|
|
||||||
{
|
|
||||||
candidate = aligned + (nuint)i * AllocationGranularity;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nuint offset = (nuint)i * AllocationGranularity;
|
|
||||||
if (offset > aligned)
|
|
||||||
{
|
|
||||||
continue;
|
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(
|
return IntPtr.Zero; }
|
||||||
handle,
|
|
||||||
IntPtr.Zero,
|
|
||||||
size,
|
|
||||||
MemoryAllocationType.Commit | MemoryAllocationType.Reserve,
|
|
||||||
MemoryProtectionType.ExecuteReadWrite);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -383,7 +383,7 @@ public sealed class DllInjector
|
|||||||
if (value != IntPtr.Zero)
|
if (value != IntPtr.Zero)
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
Thread.Sleep(5);
|
System.Threading.Thread.Sleep(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using Thread = System.Threading.Thread;
|
||||||
using WhiteMagic;
|
using WhiteMagic;
|
||||||
using WhiteMagic.Injection;
|
using WhiteMagic.Injection;
|
||||||
using WhiteMagic.Native;
|
using WhiteMagic.Native;
|
||||||
@@ -69,7 +70,7 @@ public class DllInjectorTests
|
|||||||
int osThreadId = 0;
|
int osThreadId = 0;
|
||||||
Exception? threadError = null;
|
Exception? threadError = null;
|
||||||
|
|
||||||
var helper = new Thread(() =>
|
var helper = new System.Threading.Thread(() =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -80,7 +81,7 @@ public class DllInjectorTests
|
|||||||
// also be stopped once its original context is restored.
|
// also be stopped once its original context is restored.
|
||||||
while (!stopEvent.IsSet)
|
while (!stopEvent.IsSet)
|
||||||
{
|
{
|
||||||
Thread.Sleep(10);
|
System.Threading.Thread.Sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
Reference in New Issue
Block a user