├── 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 |
--------------------------------------------------------------------------------