|
1 | | -using System.Diagnostics; |
| 1 | +using System; |
| 2 | +using System.Collections.Generic; |
| 3 | +using System.Diagnostics; |
2 | 4 | using System.Linq; |
| 5 | +using System.Runtime.InteropServices; |
| 6 | +using Il2CppInterop.Common; |
3 | 7 | using Il2CppInterop.Common.XrefScans; |
| 8 | +using Microsoft.Extensions.Logging; |
4 | 9 |
|
5 | 10 | namespace Il2CppInterop.Runtime; |
6 | 11 |
|
7 | 12 | internal class MemoryUtils |
8 | 13 | { |
| 14 | + [DllImport("kernel32.dll", SetLastError = true)] |
| 15 | + internal static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead); |
| 16 | + |
| 17 | + [DllImport("kernel32.dll", SetLastError = true)] |
| 18 | + internal static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, uint flNewProtect, out uint lpflOldProtect); |
| 19 | + |
| 20 | + [DllImport("kernel32.dll", SetLastError = true)] |
| 21 | + internal static extern int VirtualQuery(IntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, uint dwLength); |
| 22 | + |
9 | 23 | public static nint FindSignatureInModule(ProcessModule module, SignatureDefinition sigDef) |
10 | 24 | { |
| 25 | + GetModuleRegions(module, out var protectedRegions); |
| 26 | + SetModuleRegions(protectedRegions, PAGE_EXECUTE_READWRITE); |
11 | 27 | var ptr = FindSignatureInBlock( |
12 | 28 | module.BaseAddress, |
13 | 29 | module.ModuleMemorySize, |
14 | 30 | sigDef.pattern, |
15 | 31 | sigDef.mask, |
16 | 32 | sigDef.offset |
17 | 33 | ); |
| 34 | + SetModuleRegions(protectedRegions); |
18 | 35 | if (ptr != 0 && sigDef.xref) |
19 | 36 | ptr = XrefScannerLowLevel.JumpTargets(ptr).FirstOrDefault(); |
20 | 37 | return ptr; |
@@ -45,11 +62,57 @@ public static unsafe nint FindSignatureInBlock(nint block, long blockSize, char[ |
45 | 62 | return 0; |
46 | 63 | } |
47 | 64 |
|
| 65 | + public static void GetModuleRegions(ProcessModule module, out List<MEMORY_BASIC_INFORMATION> protectedRegions) |
| 66 | + { |
| 67 | + protectedRegions = []; |
| 68 | + IntPtr moduleEndAddress = (IntPtr)((long)module.BaseAddress + module.ModuleMemorySize); |
| 69 | + var currentAddress = module.BaseAddress; |
| 70 | + while (currentAddress.ToInt64() < moduleEndAddress.ToInt64()) |
| 71 | + { |
| 72 | + var result = VirtualQuery(currentAddress, out var memoryInfo, (uint)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION))); |
| 73 | + if (result == 0) |
| 74 | + // Error occurred or reached the end of the module's memory space |
| 75 | + break; |
| 76 | + else |
| 77 | + protectedRegions.Add(memoryInfo); |
| 78 | + |
| 79 | + // Move to the next memory region |
| 80 | + currentAddress = (IntPtr)((long)memoryInfo.BaseAddress + (long)memoryInfo.RegionSize); |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + public static void SetModuleRegions(List<MEMORY_BASIC_INFORMATION> protectedRegions, uint? newProtection = null) |
| 85 | + { |
| 86 | + foreach (var region in protectedRegions) |
| 87 | + { |
| 88 | + var result = VirtualProtect(region.BaseAddress, (uint)region.RegionSize, newProtection ?? region.Protect, out _); |
| 89 | + if (!result) |
| 90 | + { |
| 91 | + var error = Marshal.GetLastWin32Error(); |
| 92 | + Logger.Instance.LogError("VirtualProtect failed with error code {error}", error); |
| 93 | + } |
| 94 | + } |
| 95 | + } |
| 96 | + |
| 97 | + public const uint PAGE_EXECUTE_READWRITE = 0x40; |
| 98 | + |
48 | 99 | public struct SignatureDefinition |
49 | 100 | { |
50 | 101 | public string pattern; |
51 | 102 | public string mask; |
52 | 103 | public int offset; |
53 | 104 | public bool xref; |
54 | 105 | } |
| 106 | + |
| 107 | + [StructLayout(LayoutKind.Sequential)] |
| 108 | + public struct MEMORY_BASIC_INFORMATION |
| 109 | + { |
| 110 | + public IntPtr BaseAddress; |
| 111 | + public IntPtr AllocationBase; |
| 112 | + public uint AllocationProtect; |
| 113 | + public IntPtr RegionSize; |
| 114 | + public uint State; |
| 115 | + public uint Protect; |
| 116 | + public uint Type; |
| 117 | + } |
55 | 118 | } |
0 commit comments