Skip to content

Commit 686c956

Browse files
committed
Fix VirtualQuery signature on x64
In WinAPI MEMORY_BASIC_INFORMATION is not a real struct but rather a macro that resolves either to _MEMORY_BASIC_INFORMATION32 or _MEMORY_BASIC_INFORMATION64, see https://github.com/Leandros/WindowsHModular/blob/master/include/win32/io.h#L120-L147 Because of this, hooking might fail because some valid memory pages will get skipped or some invalid pages might be used.
1 parent e4c9ae4 commit 686c956

File tree

1 file changed

+49
-12
lines changed

1 file changed

+49
-12
lines changed

BepInEx.IL2CPP/Hook/Allocator/WindowsPageAllocator.cs

+49-12
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ protected override nint AllocateChunk(nint hint)
2525
{
2626
while (true)
2727
{
28-
var mbi = new WinApi.MEMORY_BASIC_INFORMATION();
29-
if (WinApi.VirtualQuery(hint, ref mbi, Marshal.SizeOf<WinApi.MEMORY_BASIC_INFORMATION>()) == 0)
28+
if (WinApi.VirtualQuery(hint, out var mbi) == 0)
3029
{
3130
Logger.Log(LogLevel.Debug,
3231
$"Skipping analysing 0x{(long) hint:X8} because VirtualQuery failed: {Win32Error()}");
@@ -113,8 +112,31 @@ public enum ProtectConstant : uint
113112
// ReSharper restore InconsistentNaming
114113
}
115114

116-
[DllImport("kernel32", SetLastError = true)]
117-
public static extern int VirtualQuery(nint lpAddress, ref MEMORY_BASIC_INFORMATION lpBuffer, int dwLength);
115+
[DllImport("kernel32", EntryPoint = "VirtualQuery", SetLastError = true)]
116+
static extern int VirtualQuery32(nint lpAddress, ref MEMORY_BASIC_INFORMATION lpBuffer, int dwLength);
117+
118+
[DllImport("kernel32", EntryPoint = "VirtualQuery", SetLastError = true)]
119+
static extern int VirtualQuery64(nint lpAddress, ref MEMORY_BASIC_INFORMATION64 lpBuffer, int dwLength);
120+
121+
public static int VirtualQuery(nint lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer)
122+
{
123+
lpBuffer = new MEMORY_BASIC_INFORMATION();
124+
if (Environment.Is64BitProcess)
125+
{
126+
var mbi = new MEMORY_BASIC_INFORMATION64();
127+
var res = VirtualQuery64(lpAddress, ref mbi, Marshal.SizeOf<MEMORY_BASIC_INFORMATION64>());
128+
lpBuffer.BaseAddress = mbi.BaseAddress;
129+
lpBuffer.AllocationBase = mbi.AllocationBase;
130+
lpBuffer.AllocationProtect = mbi.AllocationProtect;
131+
lpBuffer.RegionSize = mbi.RegionSize;
132+
lpBuffer.State = mbi.State;
133+
lpBuffer.Protect = mbi.Protect;
134+
lpBuffer.Type = mbi.Type;
135+
return res;
136+
}
137+
138+
return VirtualQuery32(lpAddress, ref lpBuffer, Marshal.SizeOf<MEMORY_BASIC_INFORMATION>());
139+
}
118140

119141
[DllImport("kernel32", SetLastError = true)]
120142
public static extern nint VirtualAlloc(nint lpAddress,
@@ -127,15 +149,30 @@ public static extern nint VirtualAlloc(nint lpAddress,
127149

128150
[StructLayout(LayoutKind.Sequential)]
129151
// ReSharper disable once InconsistentNaming
130-
public readonly struct MEMORY_BASIC_INFORMATION
152+
public struct MEMORY_BASIC_INFORMATION
153+
{
154+
public nint BaseAddress;
155+
public nint AllocationBase;
156+
public uint AllocationProtect;
157+
public nint RegionSize;
158+
public PageState State;
159+
public uint Protect;
160+
public uint Type;
161+
}
162+
163+
[StructLayout(LayoutKind.Sequential)]
164+
// ReSharper disable once InconsistentNaming
165+
struct MEMORY_BASIC_INFORMATION64
131166
{
132-
public readonly nint BaseAddress;
133-
public readonly nint AllocationBase;
134-
public readonly uint AllocationProtect;
135-
public readonly nint RegionSize;
136-
public readonly PageState State;
137-
public readonly uint Protect;
138-
public readonly uint Type;
167+
public nint BaseAddress;
168+
public nint AllocationBase;
169+
public uint AllocationProtect;
170+
public uint __alignment1;
171+
public nint RegionSize;
172+
public PageState State;
173+
public uint Protect;
174+
public uint Type;
175+
public int __alignment2;
139176
}
140177
}
141178
}

0 commit comments

Comments
 (0)