├── HexPattern.cs ├── IMemoryPattern.cs ├── ProcessStream.cs └── readme.md /HexPattern.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ProcessMemory 8 | { 9 | public class HexPattern : IMemoryPattern 10 | { 11 | public string[] Pattern { get; private set; } 12 | public byte?[] PatternBytes { get; private set; } 13 | 14 | public long Length => PatternBytes.Length; 15 | 16 | public HexPattern(string pattern) { 17 | //Split pattern into an array for each space. 18 | Pattern = pattern.Split(' '); 19 | 20 | byte?[] bytes = new byte?[Pattern.Length]; 21 | 22 | //Loop through each pattern string 23 | for (int i = 0; i < Pattern.Length; i++) { 24 | //If pattern at index is == ?? then we set that byte to null 25 | if (Pattern[i].Equals("??")) 26 | { 27 | bytes[i] = null; 28 | } 29 | else 30 | { 31 | bytes[i] = Convert.ToByte(Pattern[i], 16); 32 | } 33 | //If pattern is not == ?? then convert it to a byte 34 | } 35 | PatternBytes = bytes; 36 | } 37 | 38 | public long FindMatch(byte[] source, long length) { 39 | bool allTheSame; 40 | for (int i = 0; i + PatternBytes.Length <= length; i++) { 41 | allTheSame = true; 42 | for (int jj = 0; jj < PatternBytes.Length; jj++) { 43 | if (PatternBytes[jj] == null) 44 | continue; 45 | 46 | if (source[i + jj] != PatternBytes[jj]) { 47 | allTheSame = false; 48 | break; 49 | } 50 | } 51 | 52 | if (allTheSame) 53 | return i; 54 | } 55 | 56 | return -1; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /IMemoryPattern.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ProcessMemory 8 | { 9 | public interface IMemoryPattern 10 | { 11 | /// 12 | /// The function to find a match for a pattern 13 | /// 14 | /// The byte array to search in. 15 | /// Returns the start index of the found pattern if pattern isn't find it should return -1. 16 | long FindMatch(byte[] source, long length); 17 | long Length { get; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ProcessStream.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Threading; 9 | 10 | 11 | namespace ProcessMemory 12 | { 13 | public class ProcessStream 14 | { 15 | [DllImport("kernel32.dll")] 16 | public static extern int VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, uint dwLength); 17 | 18 | [StructLayout(LayoutKind.Sequential)] 19 | public struct MEMORY_BASIC_INFORMATION 20 | { 21 | public IntPtr BaseAddress; 22 | public IntPtr AllocationBase; 23 | public uint AllocationProtect; 24 | public IntPtr RegionSize; 25 | public uint State; 26 | public uint Protect; 27 | public uint Type; 28 | } 29 | 30 | [Flags] 31 | public enum ProcessAccessFlags : uint 32 | { 33 | All = 0x001F0FFF, 34 | Terminate = 0x00000001, 35 | CreateThread = 0x00000002, 36 | VMOperation = 0x00000008, 37 | VMRead = 0x00000010, 38 | VMWrite = 0x00000020, 39 | DupHandle = 0x00000040, 40 | SetInformation = 0x00000200, 41 | QueryInformation = 0x00000400, 42 | Synchronize = 0x00100000 43 | } 44 | 45 | [DllImport("kernel32.dll", SetLastError = true)] 46 | public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, IntPtr dwSize, out IntPtr lpNumberOfBytesRead); 47 | 48 | [DllImport("kernel32.dll", SetLastError = true)] 49 | public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten); 50 | 51 | [DllImport("kernel32.dll")] 52 | public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId); 53 | 54 | [DllImport("kernel32.dll")] 55 | public static extern int CloseHandle(IntPtr hProcess); 56 | 57 | private Process process; 58 | private IntPtr processHandle; 59 | 60 | public IntPtr Handle => processHandle; 61 | public Process Process => process; 62 | 63 | public ProcessStream(Process process) { 64 | this.process = process; 65 | processHandle = OpenProcess(ProcessAccessFlags.All, false, process.Id); 66 | } 67 | 68 | public List QueryMemoryRegions() { 69 | long currentAddress = 0; 70 | MEMORY_BASIC_INFORMATION MemInfo = new MEMORY_BASIC_INFORMATION(); 71 | List regions = new List(); 72 | 73 | while (true) { 74 | try { 75 | int MemDump = VirtualQueryEx(Handle, (IntPtr)currentAddress, out MemInfo, 28); 76 | if (MemDump == 0) break; 77 | if ((MemInfo.State & 0x1000) != 0 && (MemInfo.Protect & 0x100) == 0) 78 | regions.Add(MemInfo); 79 | currentAddress = (long)MemInfo.BaseAddress + (long)MemInfo.RegionSize; 80 | } catch { 81 | break; 82 | } 83 | } 84 | 85 | return regions; 86 | } 87 | 88 | public uint WriteMemory(long address, byte[] data, uint length) { 89 | UIntPtr bytesWritten; 90 | WriteProcessMemory(processHandle, (IntPtr)address, data, length, out bytesWritten); 91 | return bytesWritten.ToUInt32(); 92 | } 93 | 94 | public long PatternScan(IMemoryPattern pattern) { 95 | return PatternScan(pattern, 4096 * 2, 0x100000000); 96 | } 97 | 98 | public long PatternScan(IMemoryPattern pattern, int scanBufferSize, long scanSize) { 99 | long startAddress = (long)process.MainModule.EntryPointAddress; 100 | long endAddress = startAddress + scanSize; 101 | 102 | long currentAddress = startAddress; 103 | 104 | byte[] buffer = new byte[scanBufferSize]; 105 | 106 | while (currentAddress < endAddress) { 107 | ReadMemory(currentAddress, buffer, scanBufferSize); 108 | long index = pattern.FindMatch(buffer, buffer.Length); 109 | if (index != -1) 110 | return currentAddress + index; 111 | currentAddress += scanBufferSize; 112 | } 113 | 114 | return -1; 115 | } 116 | 117 | public long PatternScan(IMemoryPattern pattern, long startAddress, int scanBufferSize, long scanSize) 118 | { 119 | // long startAddress = (long)process.MainModule.EntryPointAddress; 120 | long endAddress = startAddress + scanSize; 121 | 122 | long currentAddress = startAddress; 123 | 124 | byte[] buffer = new byte[scanBufferSize]; 125 | 126 | while (currentAddress < endAddress) 127 | { 128 | ReadMemory(currentAddress, buffer, scanBufferSize); 129 | long index = pattern.FindMatch(buffer, buffer.Length); 130 | if (index != -1) 131 | return currentAddress + index; 132 | currentAddress += scanBufferSize; 133 | } 134 | 135 | return -1; 136 | } 137 | 138 | public long PatternScan(IMemoryPattern pattern, long startAddress, int scanBufferSize, long scanSize, int ms) 139 | { 140 | Stopwatch stopwatch = new Stopwatch(); 141 | stopwatch.Start(); 142 | long address = -1; 143 | do 144 | { 145 | // long startAddress = (long)process.MainModule.EntryPointAddress; 146 | long endAddress = startAddress + scanSize; 147 | 148 | long currentAddress = startAddress; 149 | 150 | byte[] buffer = new byte[scanBufferSize]; 151 | 152 | while (currentAddress < endAddress && stopwatch.ElapsedMilliseconds < ms) 153 | { 154 | ReadMemory(currentAddress, buffer, scanBufferSize); 155 | long index = pattern.FindMatch(buffer, buffer.Length); 156 | if (index != -1) 157 | { 158 | // return currentAddress + index; 159 | address = currentAddress + index; 160 | break; 161 | } 162 | currentAddress += scanBufferSize; 163 | } 164 | 165 | } while (address == -1 && stopwatch.ElapsedMilliseconds < ms); 166 | 167 | stopwatch.Stop(); 168 | 169 | return address; 170 | } 171 | 172 | public byte[] ReadMemory(long address, long size) { 173 | byte[] ret = new byte[size]; 174 | IntPtr read; 175 | ReadProcessMemory(processHandle, (IntPtr)address, ret, (IntPtr)size, out read); 176 | return ret; 177 | } 178 | 179 | public long ReadMemory(long address, byte[] buffer, long size) { 180 | IntPtr read; 181 | ReadProcessMemory(processHandle, (IntPtr)address, buffer, (IntPtr)size, out read); 182 | return (long)read; 183 | } 184 | 185 | public float ReadFloat(long address) { 186 | return BitConverter.ToSingle(ReadMemory(address, sizeof(float)), 0); 187 | } 188 | 189 | public int ReadInt32(long address) { 190 | return BitConverter.ToInt32(ReadMemory(address, sizeof(int)), 0); 191 | } 192 | 193 | public uint ReadUInt32(long address) { 194 | return BitConverter.ToUInt32(ReadMemory(address, sizeof(uint)), 0); 195 | } 196 | 197 | public long ReadInt64(long address) { 198 | return BitConverter.ToInt64(ReadMemory(address, sizeof(long)), 0); 199 | } 200 | public ulong ReadUInt64(long address) { 201 | return BitConverter.ToUInt64(ReadMemory(address, sizeof(ulong)), 0); 202 | } 203 | 204 | public double ReadDouble(long address) { 205 | return BitConverter.ToDouble(ReadMemory(address, sizeof(double)), 0); 206 | } 207 | 208 | /* Add your Vector3 to enable this one */ 209 | /*public Vector3 ReadVector3(long address) 210 | { 211 | //3 floats contiguously in memory 212 | byte[] buffer = new byte[3 * 4]; 213 | 214 | //read memory into buffer 215 | Global.stream.ReadMemory(address, buffer, 3 * 4); 216 | 217 | //convert bytes to floats 218 | return new Vector3( 219 | BitConverter.ToSingle(buffer, (0 * 4)), 220 | BitConverter.ToSingle(buffer, (1 * 4)), 221 | BitConverter.ToSingle(buffer, (2 * 4)) 222 | ); 223 | }*/ 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # ProcessMemory 4 | Little shitty library i ~~made~~ took from (https://github.com/CSharpProgramming/ProcessMemory and updated for my needs) that can do the following: Read, Write, Query memory regions and AOB Scan Processes 64Bit and 32Bit. 5 | 6 | Example for those who need it i guess 7 | 8 | ```csharp 9 | ProcessStream stream = new ProcessStream(Process.GetProcessesByName("NAME_OF_PROCESS").First()); 10 | //Each byte is separated by a space, and each ?? indicates an wildcard 11 | HexPattern p = new HexPattern("?? ?? 0x32 ?? 0x43"); 12 | long address = stream.PatternScan(p); 13 | ``` 14 | 15 | or 16 | 17 | ```csharp 18 | HexPattern matrixPat = new HexPattern("00 0A FC 01 00 00 00 00 00 0A FB 01 00 00 00 00"); 19 | pointerMatrix = Global.stream.PatternScan(matrixPat, 0x00000000, 4096 * 3, 0x600000000); 20 | if (pointerMatrix != -1) 21 | { 22 | pointerMatrix += 0x60; 23 | } 24 | ``` 25 | 26 | Changes from original lib: 27 | 28 | 1. Fixed memory scanning (now it is not attaching to process base module) 29 | 2. Overloaded `PatternScan` to make limited by ms scans. 30 | 3. Added `public Vector3 ReadVector3(long address)` just add your Vector3 to namespace or add `use your object.vector3` and uncomment it. 31 | --------------------------------------------------------------------------------