├── LICENSE
├── ProcessExtensions.cs
└── README.md
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 differentrain
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/ProcessExtensions.cs:
--------------------------------------------------------------------------------
1 | /*
2 | MIT License
3 |
4 | Copyright (c) 2019 differentrain
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 |
25 | /*
26 | Requirements:
27 | Windows Vista or later;
28 | Intel CPU;
29 | C# 7.3
30 | .NET Frameworks 4.5;
31 |
32 | Build Options:
33 | Choose 'Any CPU' platform;
34 | Enable 'Allow unsafe code';
35 | Disable 'Prefer 32 bit'
36 |
37 | Some members may need administrative rights.
38 | */
39 | using Microsoft.Win32.SafeHandles;
40 | using System.Collections;
41 | using System.Collections.Concurrent;
42 | using System.Collections.Generic;
43 | using System.ComponentModel;
44 | using System.Globalization;
45 | using System.IO;
46 | using System.Runtime.CompilerServices;
47 | using System.Runtime.InteropServices;
48 | using System.Security.Cryptography;
49 | using System.Text;
50 | using System.Threading.Tasks;
51 | using System.Linq;
52 | using System.Linq.Expressions;
53 |
54 | namespace System.Diagnostics.ProcessExtensions
55 | {
56 | ///
57 | /// Represents the implementation for the class enhancement.
58 | ///
59 | ///
60 | /// Members in this class may need administrative rights.
61 | ///
62 | public class ProcessPlugin : IDisposable
63 | {
64 |
65 | #region properties & fields
66 |
67 | internal readonly IntPtr _maxMemory;
68 |
69 | private readonly bool _leaveOpen;
70 |
71 | ///
72 | /// Gets a reference to the underlying instance.
73 | ///
74 | public Process BaseProcess { get; private set; }
75 |
76 | ///
77 | /// Gets the allocated memories. see class.
78 | ///
79 | public AllocatedMemoryCollection AllocatedMemories { get; private set; }
80 |
81 | ///
82 | /// Gets a reference to an instance which provides advanced features.
83 | ///
84 | public AdvancedFeature Advanced { get; private set; }
85 |
86 | ///
87 | /// Gets the main window class name of the process.
88 | ///
89 | public string MainWindowClassName => InnerUtilities.GetWindowClassByHandle(BaseProcess);
90 |
91 | ///
92 | /// Gets a value indicates that whether the process opened with is an 64 bit process.
93 | ///
94 | public bool Is64BitProcess => Environment.Is64BitProcess ?
95 | InnerUtilities.NativeMethods.IsWow64Process(new HandleRef(BaseProcess, BaseProcess.Handle), out var isWow) && !isWow ?
96 | true :
97 | false :
98 | false;
99 |
100 |
101 | #endregion
102 |
103 | #region constructors
104 |
105 |
106 | ///
107 | /// Static constructor, meant to check environment.
108 | ///
109 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")]
110 | static ProcessPlugin()
111 | {
112 | if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess)
113 | {
114 | throw new PlatformNotSupportedException("Request 'Any CPU' platform and make sure that 'Prefer 32 bit' setting is disabled.");
115 | }
116 | }
117 |
118 | ///
119 | /// Initializes a new instance of the class, by using the specified instance.
120 | ///
121 | ///
122 | public ProcessPlugin(Process process) : this(process, false) { }
123 |
124 | ///
125 | /// Initializes a new instance of the class, by using the specified instance, and optionally leaves the instance open.
126 | ///
127 | /// The process instance.
128 | /// true to leave the object open after disposing the object; otherwise, false.
129 | public ProcessPlugin(Process process, bool leaveOpen)
130 | {
131 | BaseProcess = process ?? throw new ArgumentNullException(nameof(process));
132 | _leaveOpen = leaveOpen;
133 | _maxMemory = Is64BitProcess ?
134 | InnerUtilities.SystemInfo.MaximumApplicationAddress :
135 | new IntPtr((int)(InnerUtilities.SystemInfo.MaximumApplicationAddress.ToInt64() & 0x7FFFFFFF));
136 | AllocatedMemories = new AllocatedMemoryCollection(this);
137 | Advanced = new AdvancedFeature(this);
138 | }
139 | #endregion
140 |
141 | #region methods
142 |
143 | ///
144 | /// Gets the Module by specified module name.
145 | ///
146 | /// The module name, include the file name extension.
147 | ///
148 | public ProcessModuleAlter GetModuleByName(string moduleName) => InnerUtilities.GetModuleByName(BaseProcess, moduleName);
149 |
150 | ///
151 | /// Read a value of type from the specified address in process.
152 | ///
153 | /// The unmanged type.
154 | /// The address.
155 | ///
156 | public T ReadData(IntPtr address) where T : unmanaged => InnerUtilities.ReadData(BaseProcess, address);
157 | ///
158 | /// Read a sequence of values of type from the specified address in process.
159 | ///
160 | /// The unmanged type.
161 | /// The address.
162 | /// The number of elements in the sequence.
163 | ///
164 | public T[] ReadData(IntPtr address, int count) where T : unmanaged => InnerUtilities.ReadData(BaseProcess, address, count);
165 | ///
166 | /// Read a sequence of type from the specified address in process.
167 | ///
168 | /// The unmanged type.
169 | /// The address.
170 | /// The sequence to store the read values.
171 | /// The start index of .
172 | /// The count of type date to be read.
173 | public void ReadData(IntPtr address, T[] data, int startIndex, int count) where T : unmanaged => InnerUtilities.ReadData(BaseProcess, address, data, startIndex, count);
174 |
175 | ///
176 | /// Writes type data to the specified address in process.
177 | ///
178 | /// The unmanged type.
179 | /// The address.
180 | /// The date to be written.
181 | public void WriteData(IntPtr address, params T[] data) where T : unmanaged => InnerUtilities.WriteData(BaseProcess, address, data);
182 |
183 | ///
184 | /// Write a sequence of type from the specified address in process.
185 | ///
186 | /// The unmanged type.
187 | /// The address.
188 | /// The sequence to be wirtten.
189 | /// The start index of .
190 | /// The count of type date to be written in .
191 | public void WriteData(IntPtr address, T[] data, int startIndex, int count) where T : unmanaged => InnerUtilities.WriteData(BaseProcess, address, data, startIndex, count);
192 |
193 | ///
194 | /// Searches the specified bytes in process memory. means failed.
195 | ///
196 | /// The bytes to be searched.
197 | ///
198 | public IntPtr ScanBytes(byte[] pattern) => ScanBytes(pattern, IntPtr.Zero, _maxMemory, MemoryProtectionFilter.ExecuteRead);
199 | ///
200 | /// Searches the specified bytes in process memory, with the specified filter. means failed.
201 | ///
202 | /// The bytes to be searched.
203 | /// The filter.
204 | ///
205 | public IntPtr ScanBytes(byte[] pattern, MemoryProtectionFilter filter) => ScanBytes(pattern, IntPtr.Zero, _maxMemory, filter);
206 | ///
207 | /// Searches the specified bytes in process memory, with the specified start address. means failed.
208 | ///
209 | /// The bytes to be searched.
210 | /// The start address.
211 | ///
212 | public IntPtr ScanBytes(byte[] pattern, IntPtr addressStart) => ScanBytes(pattern, addressStart, _maxMemory, MemoryProtectionFilter.ExecuteRead);
213 | ///
214 | /// Searches the specified bytes in process memory, with the specified search scope. means failed.
215 | ///
216 | /// The bytes to be searched.
217 | /// The start address.
218 | /// The end address.
219 | ///
220 | public IntPtr ScanBytes(byte[] pattern, IntPtr addressStart, IntPtr addressEnd) => ScanBytes(pattern, addressStart, addressEnd, MemoryProtectionFilter.ExecuteRead);
221 | ///
222 | /// Searches the specified bytes in process memory, with the specified filter and search scope. means failed.
223 | ///
224 | /// The bytes to be searched.
225 | /// The start address.
226 | /// The end address.
227 | /// The filter.
228 | ///
229 | public IntPtr ScanBytes(byte[] pattern, IntPtr addressStart, IntPtr addressEnd, MemoryProtectionFilter filter) => InnerUtilities.ScanByteArray(BaseProcess, pattern, BytesFinder.FindIndex, addressStart, addressEnd, filter);
230 |
231 | ///
232 | /// Wildcard version. pattern supports wildcard(?) .
233 | ///
234 | ///
235 | ///
236 | public IntPtr ScanBytes(BytesFinder pattern) => ScanBytes(pattern, IntPtr.Zero, _maxMemory, MemoryProtectionFilter.ExecuteRead);
237 | ///
238 | /// Wildcard version. pattern supports wildcard(?) .
239 | ///
240 | ///
241 | ///
242 | ///
243 | public IntPtr ScanBytes(BytesFinder pattern, IntPtr addressStart) => ScanBytes(pattern, addressStart, _maxMemory, MemoryProtectionFilter.ExecuteRead);
244 | ///
245 | /// Wildcard version. pattern supports wildcard(?) .
246 | ///
247 | ///
248 | ///
249 | ///
250 | ///
251 | public IntPtr ScanBytes(BytesFinder pattern, IntPtr addressStart, IntPtr addressEnd) => ScanBytes(pattern, addressStart, addressEnd, MemoryProtectionFilter.ExecuteRead);
252 |
253 | ///
254 | /// Wildcard version. pattern supports wildcard(?) .
255 | ///
256 | ///
257 | ///
258 | ///
259 | ///
260 | ///
261 | public IntPtr ScanBytes(BytesFinder pattern, IntPtr addressStart, IntPtr addressEnd, MemoryProtectionFilter filter) => InnerUtilities.ScanByteArray(
262 | BaseProcess, null,
263 | new Func((x, y) => pattern.FindIndexIn(x)),
264 | addressStart, addressEnd, filter);
265 |
266 |
267 |
268 | ///
269 | /// Async version. The result also can be get form .
270 | ///
271 | ///
272 | ///
273 | ///
274 | public async Task ScanBytesAsync(byte[] pattern, Action callBack = null) => await ScanBytesAsync(pattern, IntPtr.Zero, _maxMemory, MemoryProtectionFilter.ExecuteRead, callBack);
275 | ///
276 | /// Async version. The result also can be get form .
277 | ///
278 | ///
279 | ///
280 | ///
281 | ///
282 | public async Task ScanBytesAsync(byte[] pattern, MemoryProtectionFilter filter, Action callBack = null) => await ScanBytesAsync(pattern, IntPtr.Zero, _maxMemory, filter, callBack);
283 | ///
284 | /// Async version. The result also can be get form .
285 | ///
286 | ///
287 | ///
288 | ///
289 | ///
290 | public async Task ScanBytesAsync(byte[] pattern, IntPtr addressStart, Action callBack = null) => await ScanBytesAsync(pattern, addressStart, _maxMemory, MemoryProtectionFilter.ExecuteRead, callBack);
291 | ///
292 | /// Async version. The result also can be get form .
293 | ///
294 | ///
295 | ///
296 | ///
297 | ///
298 | ///
299 | public async Task ScanBytesAsync(byte[] pattern, IntPtr addressStart, IntPtr addressEnd, Action callBack = null) => await ScanBytesAsync(pattern, addressStart, addressEnd, MemoryProtectionFilter.ExecuteRead, callBack);
300 | ///
301 | /// Async version. The result also can be get form .
302 | ///
303 | ///
304 | ///
305 | ///
306 | ///
307 | ///
308 | ///
309 | public async Task ScanBytesAsync(byte[] pattern, IntPtr addressStart, IntPtr addressEnd, MemoryProtectionFilter filter, Action callBack = null) => await Task.Run(() =>
310 | {
311 | var result = ScanBytes(pattern, addressStart, addressEnd, filter);
312 | callBack?.Invoke(result);
313 | return result;
314 | });
315 |
316 |
317 | ///
318 | /// Async wildcard version. The result also can be get form .
319 | ///
320 | ///
321 | ///
322 | ///
323 | public async Task ScanBytesAsync(BytesFinder pattern, Action callBack = null) => await ScanBytesAsync(pattern, IntPtr.Zero, _maxMemory, MemoryProtectionFilter.ExecuteRead, callBack);
324 | ///
325 | /// Async wildcard version. The result also can be get form .
326 | ///
327 | ///
328 | ///
329 | ///
330 | ///
331 | public async Task ScanBytesAsync(BytesFinder pattern, MemoryProtectionFilter filter, Action callBack = null) => await ScanBytesAsync(pattern, IntPtr.Zero, _maxMemory, filter, callBack);
332 | ///
333 | /// Async wildcard version. The result also can be get form .
334 | ///
335 | ///
336 | ///
337 | ///
338 | ///
339 | public async Task ScanBytesAsync(BytesFinder pattern, IntPtr addressStart, Action callBack = null) => await ScanBytesAsync(pattern, addressStart, _maxMemory, MemoryProtectionFilter.ExecuteRead, callBack);
340 | ///
341 | /// Async wildcard version. The result also can be get form .
342 | ///
343 | ///
344 | ///
345 | ///
346 | ///
347 | ///
348 | public async Task ScanBytesAsync(BytesFinder pattern, IntPtr addressStart, IntPtr addressEnd, Action callBack = null) => await ScanBytesAsync(pattern, addressStart, addressEnd, MemoryProtectionFilter.ExecuteRead, callBack);
349 | ///
350 | /// Async wildcard version. The result also can be get form .
351 | ///
352 | ///
353 | ///
354 | ///
355 | ///
356 | ///
357 | ///
358 | public async Task ScanBytesAsync(BytesFinder pattern, IntPtr addressStart, IntPtr addressEnd, MemoryProtectionFilter filter, Action callBack = null) => await Task.Run(() =>
359 | {
360 | var result = ScanBytes(pattern, addressStart, addressEnd, filter);
361 | callBack?.Invoke(result);
362 | return result;
363 | });
364 |
365 |
366 |
367 | ///
368 | /// Calls the remote function in target process.
369 | ///
370 | /// The address of the function.
371 | ///
372 | public RemoteCallState CallRemoteFunction(IntPtr address) => CallRemoteFunction(address, InnerUtilities.INFINITE_INT);
373 | ///
374 | /// Calls the remote function in target process.
375 | ///
376 | /// The address of the function.
377 | /// Timeout, in ms.
378 | ///
379 | public RemoteCallState CallRemoteFunction(IntPtr address, int timeOut) => InnerUtilities.CallRemoteFunc(BaseProcess, address, timeOut);
380 | ///
381 | /// Calls the remote function in target process.
382 | ///
383 | /// The address of the function.
384 | /// call back.
385 | ///
386 | public async Task CallRemoteFunctionAsync(IntPtr address, Action callBack = null) => await CallRemoteFunctionAsync(address, InnerUtilities.INFINITE_INT, callBack);
387 | ///
388 | /// Calls the remote function in target process.
389 | ///
390 | /// The address of the function.
391 | /// Timeout, in ms.
392 | /// call back.
393 | ///
394 | public async Task CallRemoteFunctionAsync(IntPtr address, int timeOut, Action callBack = null) => await Task.Run(() =>
395 | {
396 | var result = CallRemoteFunction(address, timeOut);
397 | callBack?.Invoke(result);
398 | return result;
399 | });
400 |
401 | ///
402 | /// Get a new instance of which is open the process with the specified main window name.
403 | /// returns null if not succeed.
404 | ///
405 | /// Main window name.
406 | ///
407 | public static Process GetProcessByWindow(string windowName) => GetProcessByWindow(windowName, null);
408 | ///
409 | /// Get a new instance of which is open the process with the specified main window name and class name.
410 | /// returns null if not succeed.
411 | ///
412 | /// Main window name.
413 | /// Main window class name.
414 | ///
415 | public static Process GetProcessByWindow(string windowName, string windowClass) => InnerUtilities.GetProcessByWindow(windowName, windowClass);
416 |
417 | #endregion
418 |
419 | #region IDisposable Support
420 | private bool _disposed = false;
421 | ///
422 | /// Dispose mode.
423 | ///
424 | ///
425 | protected virtual void Dispose(bool disposing)
426 | {
427 | if (!_disposed)
428 | {
429 | if (disposing)
430 | {
431 | if (BaseProcess != null)
432 | {
433 | AllocatedMemories.Dispose();
434 | Advanced.Dispose();
435 | if (!_leaveOpen)
436 | {
437 | BaseProcess.Dispose();
438 | }
439 | }
440 | }
441 | Advanced = null;
442 | AllocatedMemories = null;
443 | BaseProcess = null;
444 | _disposed = true;
445 | }
446 | }
447 |
448 | ///
449 | /// Dispose.
450 | ///
451 | public void Dispose()
452 | {
453 | Dispose(true);
454 | }
455 | #endregion
456 |
457 | #pragma warning disable CA1034 // Nested types should not be visible
458 | ///
459 | /// A class provieds some advanced features to get the process infomation.
460 | ///
461 | public sealed class AdvancedFeature
462 | #pragma warning restore CA1034 // Nested types should not be visible
463 | {
464 | private static readonly byte[] _Asmcode64 = new byte[]
465 | {
466 | 0x48,0x83,0xEC,0x20,0x65,0x4C,0x8B,0x04,0x25,0x60,0x00,0x00,0x00,0x4D,0x8B,0x40,0x18,0x4D,0x8B,0x40,0x20,0x4D,0x8B,0x00,0x49,0xBB,0x4B,0x00,0x45,0x00,0x52,0x00,0x4E,
467 | 0x00,0x49,0xB9,0x45,0x00,0x4C,0x00,0x33,0x00,0x32,0x00,0x48,0xB9,0x2E,0x00,0x44,0x00,0x4C,0x00,0x4C,0x00,0x4D,0x8B,0x00,0x49,0x8B,0x40,0x50,0x4C,0x39,0x18,0x75,0xF4,
468 | 0x4C,0x39,0x48,0x08,0x75,0xEE,0x48,0x39,0x48,0x10,0x75,0xE8,0x81,0x78,0x16,0x4C,0x00,0x00,0x00,0x75,0xDF,0x4D,0x8B,0x40,0x20,0x4D,0x31,0xC9,0x45,0x8B,0x48,0x3C,0x4D,
469 | 0x01,0xC1,0x45,0x8B,0x89,0x88,0x00,0x00,0x00,0x4D,0x01,0xC1,0x48,0x89,0x74,0x24,0x18,0x48,0x31,0xF6,0x41,0x8B,0x71,0x20,0x4C,0x01,0xC6,0x45,0x8B,0x51,0x24,0x4D,0x01,
470 | 0xC2,0x48,0x31,0xC9,0x48,0x31,0xC0,0x49,0xBB,0x47,0x65,0x74,0x50,0x72,0x6F,0x63,0x41,0xFF,0xC1,0xAD,0x4C,0x01,0xC0,0x4C,0x39,0x18,0x75,0xF5,0x81,0x78,0x08,0x64,0x64,
471 | 0x72,0x65,0x75,0xEC,0x81,0x78,0x0B,0x65,0x73,0x73,0x00,0x75,0xE3,0x48,0x8B,0x74,0x24,0x18,0x66,0x41,0x8B,0x0C,0x4A,0xFF,0xC9,0x45,0x8B,0x49,0x1C,0x4D,0x01,0xC1,0x45,
472 | 0x8B,0x0C,0x89,0x4D,0x01,0xC1,0x4C,0x89,0x0D,0xB9,0x05,0x00,0x00,0x49,0x8B,0xC8,0x48,0x8D,0x15,0xC6,0x02,0x00,0x00,0x41,0xFF,0xD1,0x4C,0x8B,0xC8,0x4C,0x89,0x0D,0xAA,
473 | 0x05,0x00,0x00,0xC7,0x05,0x78,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x8D,0x0D,0xB9,0x02,0x00,0x00,0xFF,0x15,0x93,0x05,0x00,0x00,0x48,0x85,0xC0,0x75,0x1A,0x90,0x90,
474 | 0x90,0x90,0x48,0x8D,0x0D,0xB5,0x02,0x00,0x00,0xFF,0x15,0x7D,0x05,0x00,0x00,0x48,0x85,0xC0,0x0F,0x84,0xBB,0x00,0x00,0x00,0x48,0x8B,0xC8,0x48,0x89,0x0D,0x3A,0x05,0x00,
475 | 0x00,0x48,0x8D,0x15,0xBB,0x02,0x00,0x00,0xFF,0x15,0x55,0x05,0x00,0x00,0x48,0x85,0xC0,0x0F,0x84,0x9B,0x00,0x00,0x00,0xC7,0x05,0x22,0x05,0x00,0x00,0x01,0x00,0x00,0x00,
476 | 0x48,0x89,0x35,0x4B,0x05,0x00,0x00,0x48,0x89,0x3D,0x24,0x05,0x00,0x00,0x48,0xBE,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x8D,0x3D,0x83,0x02,0x00,0x00,0x48,0x89,
477 | 0x47,0x28,0x48,0x8B,0x0D,0xF0,0x04,0x00,0x00,0x48,0x8D,0x14,0x3E,0xFF,0x15,0x0E,0x05,0x00,0x00,0x48,0x83,0xC6,0x28,0x48,0x89,0x04,0x3E,0x48,0x83,0xC6,0x08,0x48,0x81,
478 | 0xFE,0x70,0x02,0x00,0x00,0x75,0xDA,0x48,0x8B,0x35,0x02,0x05,0x00,0x00,0x48,0x8B,0x3D,0xDB,0x04,0x00,0x00,0xFF,0x15,0x6D,0x02,0x00,0x00,0x4C,0x8B,0xC8,0x4C,0x89,0x0D,
479 | 0xAB,0x04,0x00,0x00,0x48,0x8B,0xC8,0xFF,0x15,0x8A,0x02,0x00,0x00,0xC7,0x05,0xA0,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x8D,0x0D,0x45,0x00,0x00,0x00,0x48,0xBA,0x00,
480 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x15,0x99,0x02,0x00,0x00,0x48,0x83,0xC4,0x20,0xC3,0x48,0x83,0xEC,0x28,0x48,0x8D,0x0D,0xB9,0x04,0x00,0x00,0xFF,0x15,0xA3,0x04,
481 | 0x00,0x00,0x48,0x8B,0xC8,0x48,0x8D,0x15,0xE9,0x04,0x00,0x00,0xFF,0x15,0x8B,0x04,0x00,0x00,0x4C,0x8B,0xC8,0x4C,0x89,0x0D,0x91,0x04,0x00,0x00,0x48,0x83,0xC4,0x28,0xC3,
482 | 0xFF,0x15,0x8E,0x02,0x00,0x00,0x8B,0x0D,0x48,0x04,0x00,0x00,0x81,0xF9,0x80,0x03,0x00,0x00,0x74,0x30,0x90,0x90,0x90,0x90,0x4C,0x8D,0x05,0xB5,0x05,0x00,0x00,0x4A,0x89,
483 | 0x04,0x01,0x48,0x8B,0xC8,0xFF,0x15,0x98,0x02,0x00,0x00,0x8B,0x0D,0x22,0x04,0x00,0x00,0x4C,0x8D,0x05,0x9B,0x08,0x00,0x00,0x4A,0x89,0x04,0x01,0x83,0x05,0x10,0x04,0x00,
484 | 0x00,0x08,0xC3,0x48,0x83,0xEC,0x28,0x48,0x8D,0x0D,0x1C,0x04,0x00,0x00,0xC7,0x01,0x00,0x00,0x00,0x00,0x48,0x8B,0x0D,0xEF,0x03,0x00,0x00,0xFF,0x15,0xD1,0x01,0x00,0x00,
485 | 0x48,0x8B,0x0D,0xFA,0x03,0x00,0x00,0x48,0x8D,0x15,0xA3,0x04,0x00,0x00,0x4C,0x8D,0x05,0xDC,0x04,0x00,0x00,0xFF,0x15,0x76,0x02,0x00,0x00,0x48,0x83,0xC4,0x28,0xC3,0x48,
486 | 0x83,0xEC,0x28,0xE8,0xB9,0xFF,0xFF,0xFF,0x48,0x85,0xC0,0x74,0x30,0x90,0x90,0x90,0x90,0x48,0x8B,0x0D,0xB0,0x03,0x00,0x00,0x48,0x8B,0xD0,0xFF,0x15,0x7F,0x02,0x00,0x00,
487 | 0x48,0x85,0xC0,0x74,0x17,0x90,0x90,0x90,0x90,0x48,0x8B,0xC8,0xFF,0x15,0x9D,0x02,0x00,0x00,0x4C,0x8B,0xC8,0x4C,0x89,0x0D,0xAB,0x03,0x00,0x00,0x48,0x83,0xC4,0x28,0xC3,
488 | 0x48,0x83,0xEC,0x28,0xE8,0x76,0xFF,0xFF,0xFF,0x48,0x85,0xC0,0x74,0x3A,0x90,0x90,0x90,0x90,0x48,0x8B,0xC8,0x48,0x8D,0x15,0xB2,0x04,0x00,0x00,0x49,0xB8,0xFF,0xFF,0xFF,
489 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x15,0x92,0x02,0x00,0x00,0x48,0x85,0xC0,0x74,0x17,0x90,0x90,0x90,0x90,0x48,0x8B,0xC8,0xFF,0x15,0xB0,0x02,0x00,0x00,0x4C,0x8B,0xC8,0x4C,
490 | 0x89,0x0D,0x5E,0x03,0x00,0x00,0x48,0x83,0xC4,0x28,0xC3,0x48,0x83,0xEC,0x28,0xE8,0x29,0xFF,0xFF,0xFF,0x48,0x85,0xC0,0x74,0x6D,0x90,0x90,0x90,0x90,0x48,0x8B,0xC8,0x48,
491 | 0x8D,0x15,0x65,0x04,0x00,0x00,0x49,0xB8,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x15,0xA5,0x02,0x00,0x00,0x48,0x85,0xC0,0x74,0x4A,0x90,0x90,0x90,0x90,0x48,0x8B,
492 | 0xC8,0x83,0x3D,0x22,0x03,0x00,0x00,0x00,0x75,0x18,0x90,0x90,0x90,0x90,0xFF,0x15,0xB6,0x02,0x00,0x00,0xEB,0x12,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,
493 | 0x90,0xFF,0x15,0xD2,0x02,0x00,0x00,0x48,0x85,0xC0,0x74,0x17,0x90,0x90,0x90,0x90,0x48,0x8B,0xC8,0xFF,0x15,0x30,0x02,0x00,0x00,0x4C,0x8B,0xC8,0x4C,0x89,0x0D,0xDE,0x02,
494 | 0x00,0x00,0x48,0x83,0xC4,0x28,0xC3,0x47,0x65,0x74,0x4D,0x6F,0x64,0x75,0x6C,0x65,0x48,0x61,0x6E,0x64,0x6C,0x65,0x57,0x00,0x6D,0x00,0x6F,0x00,0x6E,0x00,0x6F,0x00,0x2E,
495 | 0x00,0x64,0x00,0x6C,0x00,0x6C,0x00,0x00,0x00,0x6D,0x00,0x6F,0x00,0x6E,0x00,0x6F,0x00,0x2D,0x00,0x32,0x00,0x2E,0x00,0x30,0x00,0x2D,0x00,0x62,0x00,0x64,0x00,0x77,0x00,
496 | 0x67,0x00,0x63,0x00,0x2E,0x00,0x64,0x00,0x6C,0x00,0x6C,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x67,0x65,0x74,0x5F,0x72,0x6F,0x6F,0x74,0x5F,0x64,0x6F,0x6D,0x61,0x69,
497 | 0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,
498 | 0x5F,0x74,0x68,0x72,0x65,0x61,0x64,0x5F,0x61,0x74,0x74,0x61,0x63,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
499 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x61,0x73,0x73,0x65,0x6D,0x62,0x6C,0x79,0x5F,0x66,0x6F,0x72,0x65,0x61,0x63,0x68,0x00,
500 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x61,0x73,
501 | 0x73,0x65,0x6D,0x62,0x6C,0x79,0x5F,0x67,0x65,0x74,0x5F,0x69,0x6D,0x61,0x67,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
502 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x69,0x6D,0x61,0x67,0x65,0x5F,0x67,0x65,0x74,0x5F,0x6E,0x61,0x6D,0x65,0x00,0x00,0x00,0x00,0x00,0x00,
503 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x63,0x6C,0x61,0x73,0x73,
504 | 0x5F,0x66,0x72,0x6F,0x6D,0x5F,0x6E,0x61,0x6D,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
505 | 0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x63,0x6C,0x61,0x73,0x73,0x5F,0x76,0x74,0x61,0x62,0x6C,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
506 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x76,0x74,0x61,0x62,0x6C,0x65,0x5F,0x67,
507 | 0x65,0x74,0x5F,0x73,0x74,0x61,0x74,0x69,0x63,0x5F,0x66,0x69,0x65,0x6C,0x64,0x5F,0x64,0x61,0x74,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
508 | 0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x63,0x6C,0x61,0x73,0x73,0x5F,0x67,0x65,0x74,0x5F,0x6D,0x65,0x74,0x68,0x6F,0x64,0x5F,0x66,0x72,0x6F,0x6D,0x5F,0x6E,0x61,0x6D,0x65,
509 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x63,0x6F,0x6D,0x70,0x69,0x6C,0x65,0x5F,0x6D,0x65,0x74,
510 | 0x68,0x6F,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,
511 | 0x6F,0x6E,0x6F,0x5F,0x63,0x6C,0x61,0x73,0x73,0x5F,0x67,0x65,0x74,0x5F,0x70,0x72,0x6F,0x70,0x65,0x72,0x74,0x79,0x5F,0x66,0x72,0x6F,0x6D,0x5F,0x6E,0x61,0x6D,0x65,0x00,
512 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x70,0x72,0x6F,0x70,0x65,0x72,0x74,0x79,0x5F,0x67,0x65,0x74,0x5F,0x67,
513 | 0x65,0x74,0x5F,0x6D,0x65,0x74,0x68,0x6F,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,
514 | 0x5F,0x70,0x72,0x6F,0x70,0x65,0x72,0x74,0x79,0x5F,0x67,0x65,0x74,0x5F,0x73,0x65,0x74,0x5F,0x6D,0x65,0x74,0x68,0x6F,0x64,0x00,0x00
515 | };
516 |
517 | #region fields
518 | private ProcessPlugin _plugin;
519 | private bool _injected = false;
520 | private IntPtr _allocMem;
521 | private readonly bool _X64;
522 |
523 |
524 | private int _callGetFuncOffset;
525 | private int _addrModuleNameOffset;
526 | private int _addrFunctionNameOffset;
527 | private int _addrNativeResultOffset;
528 | private int _callGetStaticFieldsOffset;
529 | private int _callGetMethodOffset;
530 | private int _callGetPropertyOffset;
531 | private int _addrImagePointerOffset;
532 | private int _addrNamespaceStrOffset;
533 | private int _addrMonoResultOffset;
534 | private int _addrParaOffset;
535 | private int _isMonoOffset;
536 | private int _asmIdxOffset;
537 | private int _addrImagesOffset;
538 | private int _addrNamesOffset;
539 | #endregion
540 |
541 | internal AdvancedFeature(ProcessPlugin plugin)
542 | {
543 | _plugin = plugin;
544 | _X64 = plugin.Is64BitProcess;
545 | }
546 |
547 | ///
548 | /// Gets or set whether these features have been enabled.
549 | ///
550 | public bool Enabled
551 | {
552 | get => _injected;
553 | set
554 | {
555 | if (value == _injected) return;
556 |
557 | if (value)
558 | {
559 | _allocMem = InnerUtilities.AllocMemory(_plugin, IntPtr.Zero, 4096);
560 |
561 |
562 | byte[] asmCodes;
563 |
564 | if (_X64)
565 | {
566 | _callGetFuncOffset = 0x1E0;
567 | _addrModuleNameOffset = 0x6A4;
568 | _addrFunctionNameOffset = 0x6E4;
569 | _addrNativeResultOffset = 0x69C;
570 | _callGetStaticFieldsOffset = 0x293;
571 | _callGetMethodOffset = 0x2D6;
572 | _callGetPropertyOffset = 0x323;
573 | _addrImagePointerOffset = 0x674;
574 | _addrNamespaceStrOffset = 0x724;
575 | _addrMonoResultOffset = 0x67C;
576 | _addrParaOffset = 0x684;
577 | _isMonoOffset = 0x66C;
578 | _asmIdxOffset = 0x664;
579 | _addrImagesOffset = 0x7E4;
580 | _addrNamesOffset = 0xAE4;
581 |
582 | asmCodes = _Asmcode64;
583 | }
584 | else
585 | {
586 |
587 | #region MyRegion
588 |
589 | _callGetFuncOffset = 0x163;
590 | _addrModuleNameOffset = 0x51F;
591 | _addrFunctionNameOffset = 0x59F;
592 | _addrNativeResultOffset = 0x507;
593 | _callGetStaticFieldsOffset = 0x1FB;
594 | _callGetMethodOffset = 0x230;
595 | _callGetPropertyOffset = 0x266;
596 | _addrImagePointerOffset = 0x513;
597 | _addrNamespaceStrOffset = 0x61F;
598 | _addrMonoResultOffset = 0x517;
599 | _addrParaOffset = 0x51B;
600 | _isMonoOffset = 0x4FB;
601 | _asmIdxOffset = 0x50F;
602 | _addrImagesOffset = 0x6DF;
603 | _addrNamesOffset = 0x85F;
604 |
605 | #endregion
606 |
607 | #region MyRegion
608 |
609 |
610 |
611 | var intAddr = _allocMem.ToInt32();
612 |
613 |
614 | var asmIndexAddress = BitConverter.GetBytes(intAddr + _asmIdxOffset);
615 | var isMonoAddress = BitConverter.GetBytes(intAddr + _isMonoOffset);
616 | var addrModuleNameAddress = BitConverter.GetBytes(intAddr + _addrModuleNameOffset);
617 | var addrFunctionNameAddress = BitConverter.GetBytes(intAddr + _addrFunctionNameOffset);
618 | var addrNativeResultAddress = BitConverter.GetBytes(intAddr + _addrNativeResultOffset);
619 | var addrImagesAddress = BitConverter.GetBytes(intAddr + _addrImagesOffset);
620 | var addrNamesAddress = BitConverter.GetBytes(intAddr + _addrNamesOffset);
621 | var addrMonoResultAddress = BitConverter.GetBytes(intAddr + _addrMonoResultOffset);
622 | var addrNamespaceStrAddress = BitConverter.GetBytes(intAddr + _addrNamespaceStrOffset);
623 | var addrAddrImagePointerAddress = BitConverter.GetBytes(intAddr + _addrImagePointerOffset);
624 | var addrParaAddress = BitConverter.GetBytes(intAddr + _addrParaOffset);
625 |
626 | var addrMemberStr = BitConverter.GetBytes(intAddr + 0x69F);
627 | var addrClassStr = BitConverter.GetBytes(intAddr + 0x65F);
628 | var addrGetProcAddress = BitConverter.GetBytes(intAddr + 0x4FF);
629 | var addrGetModuleHandleW = BitConverter.GetBytes(intAddr + 0x503);
630 | var addrGetDomain = BitConverter.GetBytes(intAddr + 0x32F);
631 | var addrThreadAttch = BitConverter.GetBytes(intAddr + 0x355);
632 | var addrDomainForeach = BitConverter.GetBytes(intAddr + 0x37B);
633 | var addrDomain = BitConverter.GetBytes(intAddr + 0x50B);
634 | var addrCallback = BitConverter.GetBytes(intAddr + 0x180);
635 | var addrGetImage = BitConverter.GetBytes(intAddr + 0x3A1);
636 |
637 | var addrGetImageName = BitConverter.GetBytes(intAddr + 0x3C7);
638 | var addrGetClass = BitConverter.GetBytes(intAddr + 0x3ED);
639 | var addrGetVtable = BitConverter.GetBytes(intAddr + 0x413);
640 | var addrGetStaticFields = BitConverter.GetBytes(intAddr + 0x439);
641 | var addrGetMethod = BitConverter.GetBytes(intAddr + 0x45F);
642 | var addrComMethod = BitConverter.GetBytes(intAddr + 0x485);
643 | var addrGetProperty = BitConverter.GetBytes(intAddr + 0x4AB);
644 | var addrGetter = BitConverter.GetBytes(intAddr + 0x4D1);
645 | var addrSetter = BitConverter.GetBytes(intAddr + 0x4F7);
646 |
647 | var strMonoDll = BitConverter.GetBytes(intAddr + 0x2D5);
648 | var strMonoDLLB = BitConverter.GetBytes(intAddr + 0x2E7);
649 | var strGetModuleHandleW = BitConverter.GetBytes(intAddr + 0x2C4);
650 | var strGetDomain = BitConverter.GetBytes(intAddr + 0x30D);
651 |
652 | #endregion
653 | asmCodes = new byte[] {0x31,0xC9,0x64,0x8B,0x41,0x30,0x8B,0x40,0x0C,0x8B,0x70,0x14,0xAD,0x96,0xAD,0x8B,0x58,0x28,0x81,0x3B,0x4B,0x00,0x45,0x00,0x75,
654 | 0xF3,0x81,0x7B,0x04,0x52,0x00,0x4E,0x00,0x75,0xEA,0x81,0x7B,0x08,0x45,0x00,0x4C,0x00,0x75,0xE1,0x81,0x7B,0x0C,0x33,0x00,0x32,
655 | 0x00,0x75,0xD8,0x81,0x7B,0x10,0x2E,0x00,0x44,0x00,0x75,0xCF,0x81,0x7B,0x14,0x4C,0x00,0x4C,0x00,0x75,0xC6,0x66,0x83,0x7B,0x18,
656 | 0x00,0x75,0xBF,0x8B,0x58,0x10,0x8B,0x53,0x3C,0x01,0xDA,0x8B,0x52,0x78,0x01,0xDA,0x8B,0x72,0x20,0x01,0xDE,0x31,0xC9,0x41,0xAD,
657 | 0x01,0xD8,0x81,0x38,0x47,0x65,0x74,0x50,0x75,0xF4,0x81,0x78,0x04,0x72,0x6F,0x63,0x41,0x75,0xEB,0x81,0x78,0x08,0x64,0x64,0x72,
658 | 0x65,0x75,0xE2,0x81,0x78,0x0B,0x65,0x73,0x73,0x00,0x75,0xD9,0x8B,0x72,0x24,0x01,0xDE,0x66,0x8B,0x0C,0x4E,0x49,0x8B,0x72,0x1C,
659 | 0x01,0xDE,0x8B,0x14,0x8E,0x01,0xDA,0x89,0x15, addrGetProcAddress[0],addrGetProcAddress[1],addrGetProcAddress[2],addrGetProcAddress[3],
660 | 0x68, strGetModuleHandleW[0],strGetModuleHandleW[1],strGetModuleHandleW[2],strGetModuleHandleW[3],0x53,0xFF,0xD2,0xA3,
661 | addrGetModuleHandleW[0], addrGetModuleHandleW[1], addrGetModuleHandleW[2], addrGetModuleHandleW[3],0xC7,0x05,
662 | isMonoAddress[0], isMonoAddress[1], isMonoAddress[2], isMonoAddress[3],0x00,0x00,0x00,0x00,0x68,
663 | strMonoDll[0],strMonoDll[1],strMonoDll[2],strMonoDll[3],0xFF,0x15,
664 | addrGetModuleHandleW[0], addrGetModuleHandleW[1], addrGetModuleHandleW[2], addrGetModuleHandleW[3],0x85,0xC0,0x0F,0x85,0x13,0x00,
665 | 0x00,0x00,0x68, strMonoDLLB[0],strMonoDLLB[1],strMonoDLLB[2],strMonoDLLB[3],0xFF,0x15,
666 | addrGetModuleHandleW[0], addrGetModuleHandleW[1], addrGetModuleHandleW[2], addrGetModuleHandleW[3],0x85,0xC0,0x0F,0x84,0x82,0x00,
667 | 0x00,0x00,0xA3, asmIndexAddress[0],asmIndexAddress[1],asmIndexAddress[2],asmIndexAddress[3],0x68,
668 | strGetDomain[0], strGetDomain[1], strGetDomain[2], strGetDomain[3],0x50,0xFF,0x15,
669 | addrGetProcAddress[0],addrGetProcAddress[1],addrGetProcAddress[2],addrGetProcAddress[3],0x85,0xC0,0x0F,0x84,0x69,0x00,0x00,0x00,
670 | 0xC7,0x05, isMonoAddress[0], isMonoAddress[1], isMonoAddress[2], isMonoAddress[3],0x01,0x00,0x00,0x00,0x56,0x57,0xBE,0x26,0x00,
671 | 0x00,0x00,0x8D,0x3D, strGetDomain[0], strGetDomain[1], strGetDomain[2], strGetDomain[3],0x89,0x47,0x22,0x8D,0x04,0x3E,0x50,0xFF,
672 | 0x35,asmIndexAddress[0],asmIndexAddress[1],asmIndexAddress[2],asmIndexAddress[3],0xFF,0x15,
673 | addrGetProcAddress[0],addrGetProcAddress[1],addrGetProcAddress[2],addrGetProcAddress[3],0x83,0xC6,0x22,0x89,0x04,0x3E,0x83,0xC6,
674 | 0x04,0x81,0xFE,0xEE,0x01,0x00,0x00,0x75,0xDF,0x5F,0x5E,0xC7,0x05, asmIndexAddress[0],asmIndexAddress[1],asmIndexAddress[2],asmIndexAddress[3],
675 | 0x00,0x00,0x00,0x00,0xFF,0x15, addrGetDomain[0],addrGetDomain[1],addrGetDomain[2],addrGetDomain[3],
676 | 0xA3, addrDomain[0],addrDomain[1],addrDomain[2],addrDomain[3],0x50,0xFF,0x15,
677 | addrThreadAttch[0],addrThreadAttch[1],addrThreadAttch[2],addrThreadAttch[3],0x6A,0x00,0x68,
678 | addrCallback[0],addrCallback[1],addrCallback[2],addrCallback[3],0xFF,0x15,
679 | addrDomainForeach[0],addrDomainForeach[1],addrDomainForeach[2],addrDomainForeach[3],0x83,0xC4,0x0C,0xC3,0x68,
680 | addrModuleNameAddress[0], addrModuleNameAddress[1], addrModuleNameAddress[2], addrModuleNameAddress[3],0xFF,0x15,
681 | addrGetModuleHandleW[0], addrGetModuleHandleW[1], addrGetModuleHandleW[2], addrGetModuleHandleW[3],0x68,
682 | addrFunctionNameAddress[0], addrFunctionNameAddress[1], addrFunctionNameAddress[2], addrFunctionNameAddress[3],0x50,0xFF,0x15,
683 | addrGetProcAddress[0],addrGetProcAddress[1],addrGetProcAddress[2],addrGetProcAddress[3],0xA3,
684 | addrNativeResultAddress[0],addrNativeResultAddress[1],addrNativeResultAddress[2],addrNativeResultAddress[3],0xC3,0x55,0x50,0x53,0x8B,0xEC,0x8B,
685 | 0x45,0x10,0x50,0xFF,0x15, addrGetImage[0], addrGetImage[1], addrGetImage[2], addrGetImage[3],0x50,0x8B,0x0D,
686 | asmIndexAddress[0],asmIndexAddress[1],asmIndexAddress[2],asmIndexAddress[3],0x81,0xF9,0x80,0x00,0x00,0x00,0x0F,0x84,0x20,0x00,0x00,0x00,0x89,0x04,
687 | 0x8D,addrImagesAddress[0],addrImagesAddress[1],addrImagesAddress[2],addrImagesAddress[3],0xFF,0x15,
688 | addrGetImageName[0],addrGetImageName[1],addrGetImageName[2],addrGetImageName[3],0x8B,0x0D,
689 | asmIndexAddress[0],asmIndexAddress[1],asmIndexAddress[2],asmIndexAddress[3],0x89,0x04,0x8D,
690 | addrNamesAddress[0], addrNamesAddress[1], addrNamesAddress[2], addrNamesAddress[3],0xFF,0x05,
691 | asmIndexAddress[0],asmIndexAddress[1],asmIndexAddress[2],asmIndexAddress[3],0x83,0xC4,0x08,0x8B,0xE5,0x5B,0x58,0x5D,0xC3,0xC7,0x05,
692 | addrMonoResultAddress[0],addrMonoResultAddress[1],addrMonoResultAddress[2],addrMonoResultAddress[3],0x00,0x00,0x00,0x00,0xFF,0x35,
693 | addrDomain[0],addrDomain[1],addrDomain[2],addrDomain[3],0xFF,0x15,
694 | addrThreadAttch[0],addrThreadAttch[1],addrThreadAttch[2],addrThreadAttch[3],0x68,
695 | addrClassStr[0], addrClassStr[1], addrClassStr[2], addrClassStr[3],0x68,
696 | addrNamespaceStrAddress[0],addrNamespaceStrAddress[1],addrNamespaceStrAddress[2],addrNamespaceStrAddress[3],0xFF,0x35,
697 | addrAddrImagePointerAddress[0],addrAddrImagePointerAddress[1],addrAddrImagePointerAddress[2],addrAddrImagePointerAddress[3],0xFF,0x15,
698 | addrGetClass[0],addrGetClass[1],addrGetClass[2],addrGetClass[3],0x83,0xC4,0x10,0xC3,0xE8,0xCB,0xFF,0xFF,0xFF,0x85,0xC0,0x0F,0x84,0x27,
699 | 0x00,0x00,0x00,0x50,0xFF,0x35, addrDomain[0],addrDomain[1],addrDomain[2],addrDomain[3],0xFF,0x15,
700 | addrGetVtable[0],addrGetVtable[1],addrGetVtable[2],addrGetVtable[3],0x83,0xC4,0x08,0x85,0xC0,0x0F,0x84,0x0F,0x00,0x00,0x00,0x50,0xFF,0x15,
701 | addrGetStaticFields[0],addrGetStaticFields[1],addrGetStaticFields[2],addrGetStaticFields[3],0xA3,
702 | addrMonoResultAddress[0],addrMonoResultAddress[1],addrMonoResultAddress[2],addrMonoResultAddress[3],0x83,0xC4,0x04,0xC3,0xE8,0x96,0xFF,0xFF,
703 | 0xFF,0x85,0xC0,0x0F,0x84,0x28,0x00,0x00,0x00,0x6A,0xFF,0x68,
704 | addrMemberStr[0],addrMemberStr[1],addrMemberStr[2],addrMemberStr[3],0x50,0xFF,0x15,
705 | addrGetMethod[0],addrGetMethod[1],addrGetMethod[2],addrGetMethod[3],0x83,0xC4,0x0C,0x85,0xC0,0x0F,0x84,0x0F,0x00,0x00,0x00,0x50,0xFF,0x15,
706 | addrComMethod[0],addrComMethod[1],addrComMethod[2],addrComMethod[3],0xA3,
707 | addrMonoResultAddress[0],addrMonoResultAddress[1],addrMonoResultAddress[2],addrMonoResultAddress[3],0x83,0xC4,0x04,0xC3,0xE8,0x60,0xFF,0xFF,
708 | 0xFF,0x85,0xC0,0x0F,0x84,0x50,0x00,0x00,0x00,0x68, addrMemberStr[0],addrMemberStr[1],addrMemberStr[2],addrMemberStr[3],
709 | 0x50,0xFF,0x15, addrGetProperty[0],addrGetProperty[1],addrGetProperty[2],addrGetProperty[3],0x83,0xC4,0x08,0x85,0xC0,0x0F,0x84,0x39,0x00,0x00,
710 | 0x00,0x50,0x83,0x3D, addrParaAddress[0],addrParaAddress[1],addrParaAddress[2],addrParaAddress[3],0x00,0x0F,0x85,0x0B,0x00,0x00,0x00,0xFF,0x15,
711 | addrGetter[0],addrGetter[1],addrGetter[2],addrGetter[3],0xE9,0x06,0x00,0x00,0x00,0xFF,0x15,
712 | addrSetter[0],addrSetter[1],addrSetter[2],addrSetter[3],0x83,0xC4,0x04,0x85,0xC0,0x0F,0x84,0x0F,0x00,0x00,0x00,0x50,0xFF,0x15,
713 | addrComMethod[0],addrComMethod[1],addrComMethod[2],addrComMethod[3],0xA3,
714 | addrMonoResultAddress[0],addrMonoResultAddress[1],addrMonoResultAddress[2],addrMonoResultAddress[3],0x83,0xC4,0x04,0xC3,0x47,0x65,0x74,0x4D,
715 | 0x6F,0x64,0x75,0x6C,0x65,0x48,0x61,0x6E,0x64,0x6C,0x65,0x57,0x00,0x6D,0x00,0x6F,0x00,0x6E,0x00,0x6F,0x00,0x2E,0x00,0x64,0x00,0x6C,0x00,0x6C,0x00,
716 | 0x00,0x00,0x6D,0x00,0x6F,0x00,0x6E,0x00,0x6F,0x00,0x2D,0x00,0x32,0x00,0x2E,0x00,0x30,0x00,0x2D,0x00,0x62,0x00,0x64,0x00,0x77,0x00,0x67,0x00,0x63,
717 | 0x00,0x2E,0x00,0x64,0x00,0x6C,0x00,0x6C,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x67,0x65,0x74,0x5F,0x72,0x6F,0x6F,0x74,0x5F,0x64,0x6F,0x6D,0x61,
718 | 0x69,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x74,0x68,0x72,0x65,
719 | 0x61,0x64,0x5F,0x61,0x74,0x74,0x61,0x63,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
720 | 0x6D,0x6F,0x6E,0x6F,0x5F,0x61,0x73,0x73,0x65,0x6D,0x62,0x6C,0x79,0x5F,0x66,0x6F,0x72,0x65,0x61,0x63,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
721 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x61,0x73,0x73,0x65,0x6D,0x62,0x6C,0x79,0x5F,0x67,0x65,0x74,0x5F,0x69,0x6D,
722 | 0x61,0x67,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x69,0x6D,0x61,0x67,0x65,0x5F,
723 | 0x67,0x65,0x74,0x5F,0x6E,0x61,0x6D,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,
724 | 0x6E,0x6F,0x5F,0x63,0x6C,0x61,0x73,0x73,0x5F,0x66,0x72,0x6F,0x6D,0x5F,0x6E,0x61,0x6D,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
725 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x63,0x6C,0x61,0x73,0x73,0x5F,0x76,0x74,0x61,0x62,0x6C,0x65,0x00,0x00,0x00,0x00,0x00,
726 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x76,0x74,0x61,0x62,0x6C,0x65,0x5F,0x67,
727 | 0x65,0x74,0x5F,0x73,0x74,0x61,0x74,0x69,0x63,0x5F,0x66,0x69,0x65,0x6C,0x64,0x5F,0x64,0x61,0x74,0x61,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,
728 | 0x5F,0x63,0x6C,0x61,0x73,0x73,0x5F,0x67,0x65,0x74,0x5F,0x6D,0x65,0x74,0x68,0x6F,0x64,0x5F,0x66,0x72,0x6F,0x6D,0x5F,0x6E,0x61,0x6D,0x65,0x00,0x00,
729 | 0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x63,0x6F,0x6D,0x70,0x69,0x6C,0x65,0x5F,0x6D,0x65,0x74,0x68,0x6F,0x64,0x00,0x00,0x00,0x00,0x00,
730 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x63,0x6C,0x61,0x73,0x73,0x5F,0x67,0x65,0x74,0x5F,
731 | 0x70,0x72,0x6F,0x70,0x65,0x72,0x74,0x79,0x5F,0x66,0x72,0x6F,0x6D,0x5F,0x6E,0x61,0x6D,0x65,0x00,0x00,0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x70,
732 | 0x72,0x6F,0x70,0x65,0x72,0x74,0x79,0x5F,0x67,0x65,0x74,0x5F,0x67,0x65,0x74,0x5F,0x6D,0x65,0x74,0x68,0x6F,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
733 | 0x00,0x00,0x00,0x6D,0x6F,0x6E,0x6F,0x5F,0x70,0x72,0x6F,0x70,0x65,0x72,0x74,0x79,0x5F,0x67,0x65,0x74,0x5F,0x73,0x65,0x74,0x5F,0x6D,0x65,0x74,0x68,
734 | 0x6F,0x64,0x00,0x00};
735 |
736 | }
737 |
738 | try
739 | {
740 | _plugin.WriteData(_allocMem, asmCodes);
741 | _plugin.CallRemoteFunction(_allocMem, 20000);
742 | _injected = true;
743 | }
744 | #pragma warning disable CA1031 // Do not catch general exception types
745 | catch
746 | {
747 | InnerUtilities.ReleaseMemory(_plugin.BaseProcess, _allocMem);
748 | _injected = false;
749 | }
750 | #pragma warning restore CA1031 // Do not catch general exception types
751 | }
752 | else
753 | {
754 | InnerUtilities.ReleaseMemory(_plugin.BaseProcess, _allocMem);
755 | _injected = false;
756 | }
757 | }
758 | }
759 |
760 | ///
761 | /// Indicates that whether the target process supports mono feature.
762 | ///
763 | public bool MonoSupported
764 | {
765 | get
766 | {
767 | if (!_injected) return false;
768 | try
769 | {
770 | var q = ReadRemotePtr(_isMonoOffset);
771 | if (q == IntPtr.Zero)
772 | {
773 | return false;
774 | }
775 | return true;
776 | }
777 | #pragma warning disable CA1031 // Do not catch general exception types
778 | catch
779 | {
780 | return false;
781 | }
782 | #pragma warning restore CA1031 // Do not catch general exception types
783 |
784 | }
785 | }
786 |
787 | ///
788 | /// Gets the target function address in the specified module.
789 | ///
790 | /// The module contains target function.
791 | /// The function name.
792 | ///
793 | public IntPtr GetFunctionAddress(string moduleName, string functionName)
794 | {
795 | if (!_injected) throw new InvalidOperationException("Not enabled.");
796 |
797 | var mBytes = GetStringBytes(moduleName, Encoding.Unicode, false);
798 | if (mBytes == null)
799 | {
800 | throw new ArgumentException("Invalid moduleName.", nameof(moduleName));
801 | }
802 | var fBytes = GetStringBytes(functionName, Encoding.ASCII, false);
803 | if (fBytes == null)
804 | {
805 | throw new ArgumentException("Invalid functionName.", nameof(functionName));
806 | }
807 | _plugin.WriteData(_allocMem + _addrModuleNameOffset, mBytes);
808 | _plugin.WriteData(_allocMem + _addrFunctionNameOffset, fBytes);
809 |
810 | CallFunction(_callGetFuncOffset);
811 | return ReadRemotePtr(_addrNativeResultOffset);
812 | }
813 |
814 | ///
815 | /// Gets all mono assemblies in the process root domain.
816 | ///
817 | ///
818 | public MonoAssembly[] GetMonoAssemblies() => GetMonoAssembliesCore(false);
819 |
820 | ///
821 | /// Gets 'Assembly-CSharp' assembly.
822 | ///
823 | ///
824 | public MonoAssembly GetAssemblyCSharp() => GetMonoAssembliesCore(true)[0];
825 |
826 | ///
827 | /// Gets the start address of static fields in the specified class.
828 | ///
829 | /// The assembly name.
830 | /// The namespace name, can be null.
831 | /// The class name. nested class requests the parent name, separated by '/'.
832 | ///
833 | public IntPtr GetStaticFields(MonoAssembly assembly, string namespaceName, string className)
834 | {
835 | var bytes = EnsureAsmAndNsNameAndClsName(assembly, namespaceName, className);
836 | _plugin.WriteData(_allocMem + _addrNamespaceStrOffset, bytes);
837 | WriteRemotePtr(_addrImagePointerOffset, assembly.Pointer);
838 | CallFunction(_callGetStaticFieldsOffset);
839 | return ReadRemotePtr(_addrMonoResultOffset);
840 | }
841 |
842 | ///
843 | /// Gets the compiled method address.
844 | ///
845 | /// The assembly name.
846 | /// The namespace name, can be null.
847 | /// The class name. nested class requests the parent name, separated by '/'.
848 | /// The method name.
849 | ///
850 | public IntPtr GetMethodAddress(MonoAssembly assembly, string namespaceName, string className, string memberName)
851 | {
852 | var bytes = EnsureMonoAllPara(assembly, namespaceName, className, memberName);
853 | _plugin.WriteData(_allocMem + _addrNamespaceStrOffset, bytes);
854 | WriteRemotePtr(_addrImagePointerOffset, assembly.Pointer);
855 | CallFunction(_callGetMethodOffset);
856 | return ReadRemotePtr(_addrMonoResultOffset);
857 | }
858 |
859 | ///
860 | /// Gets the address of property's Getter method.
861 | ///
862 | /// The assembly name.
863 | /// The namespace name, can be null.
864 | /// The class name. nested class requests the parent name, separated by '/'.
865 | /// The property name.
866 | ///
867 | public IntPtr GetPropertyGetterAddress(MonoAssembly assembly, string namespaceName, string className, string memberName)
868 | {
869 | var bytes = EnsureMonoAllPara(assembly, namespaceName, className, memberName);
870 | _plugin.WriteData(_allocMem + _addrNamespaceStrOffset, bytes);
871 | WriteRemotePtr(_addrImagePointerOffset, assembly.Pointer);
872 | WriteRemotePtr(_addrParaOffset, IntPtr.Zero);
873 | CallFunction(_callGetPropertyOffset);
874 | return ReadRemotePtr(_addrMonoResultOffset);
875 | }
876 |
877 | ///
878 | /// Gets the address of property's Setter method.
879 | ///
880 | /// The assembly name.
881 | /// The namespace name, can be null.
882 | /// The class name. nested class requests the parent name, separated by '/'.
883 | /// The property name.
884 | ///
885 | public IntPtr GetPropertySetterAddress(MonoAssembly assembly, string namespaceName, string className, string memberName)
886 | {
887 | var bytes = EnsureMonoAllPara(assembly, namespaceName, className, memberName);
888 | _plugin.WriteData(_allocMem + _addrNamespaceStrOffset, bytes);
889 | WriteRemotePtr(_addrImagePointerOffset, assembly.Pointer);
890 | WriteRemotePtr(_addrParaOffset, IntPtr.Zero + 1);
891 | CallFunction(_callGetPropertyOffset);
892 | return ReadRemotePtr(_addrMonoResultOffset);
893 | }
894 |
895 | private MonoAssembly[] GetMonoAssembliesCore(bool findMain)
896 | {
897 | EnsureMono();
898 |
899 | var length = _plugin.ReadData(_allocMem + _asmIdxOffset);
900 | var result = new MonoAssembly[length];
901 | var step = 4;
902 | if (_X64)
903 | {
904 | length >>= 3;
905 | step = 8;
906 | }
907 |
908 | var buf = new byte[64];
909 | for (int i = 0; i < length; i++)
910 | {
911 | _plugin.ReadData(ReadRemotePtr(_addrNamesOffset + step * i), buf, 0, 64);
912 | var nameTemp = Encoding.ASCII.GetString(buf);
913 | nameTemp = nameTemp.Substring(0, nameTemp.IndexOf('\0'));
914 | result[i] = new MonoAssembly(ReadRemotePtr(_addrImagesOffset + step * i), nameTemp);
915 | if (findMain && nameTemp.Equals("Assembly-CSharp"))
916 | {
917 | return new MonoAssembly[] { result[i] };
918 | }
919 | }
920 | if (findMain) return new MonoAssembly[1];
921 | return result;
922 | }
923 |
924 | private IntPtr ReadRemotePtr(int offset)
925 | {
926 | return new IntPtr(_X64 ? _plugin.ReadData(_allocMem + offset) : _plugin.ReadData(_allocMem + offset));
927 | }
928 |
929 | private void WriteRemotePtr(int offset, IntPtr value)
930 | {
931 | _plugin.WriteData(_allocMem + offset, _X64 ? value.ToInt64() : value.ToInt32());
932 | }
933 |
934 | private void CallFunction(int offset)
935 | {
936 | var callResult = _plugin.CallRemoteFunction(_allocMem + offset, 20000);
937 | if (!callResult.Succeed)
938 | {
939 | throw callResult.Exception;
940 | }
941 | }
942 |
943 | private void EnsureMono()
944 | {
945 | if (!MonoSupported) throw new InvalidOperationException("Not enabled or not mono.");
946 | }
947 |
948 | private byte[] EnsureMonoAllPara(MonoAssembly assembly, string namespaceName, string className, string memberName)
949 | {
950 | var firstBytes = EnsureAsmAndNsNameAndClsName(assembly, namespaceName, className);
951 | var secondByes = GetStringBytes(memberName, Encoding.ASCII, false);
952 | if (secondByes == null)
953 | {
954 | throw new ArgumentException("Invalid memberName.", nameof(memberName));
955 | }
956 | return firstBytes.Concat(secondByes).ToArray();
957 | }
958 |
959 | private byte[] EnsureAsmAndNsNameAndClsName(MonoAssembly assembly, string namespaceName, string className)
960 | {
961 | EnsureMono();
962 | if (assembly == null) throw new ArgumentNullException(nameof(assembly));
963 |
964 | var nsBytes = GetStringBytes(namespaceName, Encoding.ASCII, true);
965 | if (nsBytes == null)
966 | {
967 | throw new ArgumentException("Invalid namespaceName.", nameof(namespaceName));
968 | }
969 |
970 | var cBytes = GetStringBytes(className, Encoding.ASCII, false);
971 |
972 | if (cBytes == null)
973 | {
974 | throw new ArgumentException("Invalid className.", nameof(className));
975 | }
976 |
977 | return nsBytes.Concat(cBytes).ToArray();
978 | }
979 |
980 | private byte[] GetStringBytes(string str, Encoding code, bool canBeNull)
981 | {
982 | if (str == null)
983 | {
984 | if (canBeNull)
985 | {
986 | return new byte[64];
987 | }
988 | return null;
989 | }
990 |
991 | if (string.IsNullOrWhiteSpace(str)) return null;
992 |
993 | if (str[str.Length - 1] != '\0')
994 | {
995 | str += '\0';
996 | }
997 | var result = new byte[64];
998 | try
999 | {
1000 | code.GetBytes(str, 0, str.Length, result, 0);
1001 | return result;
1002 | }
1003 | #pragma warning disable CA1031 // Do not catch general exception types
1004 | catch
1005 | {
1006 | return null;
1007 | }
1008 | #pragma warning restore CA1031 // Do not catch general exception types
1009 | }
1010 |
1011 | #region IDisposable Support
1012 |
1013 | ~AdvancedFeature()
1014 | {
1015 | Dispose();
1016 | }
1017 |
1018 | internal void Dispose()
1019 | {
1020 | if (_injected)
1021 | {
1022 | Enabled = false;
1023 | }
1024 | _plugin = null;
1025 | GC.SuppressFinalize(this);
1026 | }
1027 | #endregion
1028 |
1029 | }
1030 |
1031 |
1032 |
1033 | #pragma warning disable CA1034 // Nested types should not be visible
1034 | ///
1035 | /// Represents the allcated memories in the target process.
1036 | ///
1037 | public sealed class AllocatedMemoryCollection : IEnumerable
1038 | #pragma warning restore CA1034 // Nested types should not be visible
1039 | {
1040 | #region properties & fields
1041 |
1042 | private ProcessPlugin _plugin;
1043 |
1044 | private List _list;
1045 |
1046 | ///
1047 | /// Gets the pointer of allocated memory by index.
1048 | ///
1049 | /// The index
1050 | ///
1051 | public IntPtr this[int index] => _list[index];
1052 |
1053 | ///
1054 | /// Gets a value indicates the count of allocated memories.
1055 | ///
1056 | public int Count => _list.Count;
1057 |
1058 | #endregion
1059 |
1060 | internal AllocatedMemoryCollection(ProcessPlugin plugin)
1061 | {
1062 | _plugin = plugin;
1063 | _list = new List();
1064 | }
1065 |
1066 | #region methods
1067 |
1068 | ///
1069 | /// Allocates memory in the target process with the specified size.
1070 | ///
1071 | /// Memory size.
1072 | public IntPtr Allocate(int size) => Allocate(IntPtr.Zero, size);
1073 |
1074 | ///
1075 | /// Allocates memory in the target process, which is located at the specified address, with the specified size.
1076 | ///
1077 | /// The location in where the memory should be allocated.
1078 | /// Memory size.
1079 | ///
1080 | public IntPtr Allocate(IntPtr expectedAddress, int size)
1081 | {
1082 | var result = InnerUtilities.AllocMemory(_plugin, expectedAddress, size);
1083 | _list.Add(result);
1084 | return result;
1085 | }
1086 |
1087 | ///
1088 | /// Free all allocated memories.
1089 | ///
1090 | public void FreeAll()
1091 | {
1092 | foreach (var item in _list)
1093 | {
1094 | InnerUtilities.ReleaseMemory(_plugin.BaseProcess, item);
1095 | }
1096 | _list.Clear();
1097 | }
1098 |
1099 | ///
1100 | /// Indicates that whether the pointer is exist.
1101 | ///
1102 | ///
1103 | ///
1104 | public bool Contains(IntPtr memAddress) => _list.Contains(memAddress);
1105 |
1106 | ///
1107 | /// Gets the index of the specified memory.
1108 | ///
1109 | /// The pointer to the memory.
1110 | ///
1111 | public int IndexOf(IntPtr memAddress) => _list.IndexOf(memAddress);
1112 |
1113 | ///
1114 | /// Free the memory by it's pointer.
1115 | ///
1116 | /// The specified pointer to be release.
1117 | ///
1118 | public bool Free(IntPtr memAddress)
1119 | {
1120 | try
1121 | {
1122 | return _list.Remove(memAddress);
1123 | }
1124 | finally
1125 | {
1126 | InnerUtilities.ReleaseMemory(_plugin.BaseProcess, memAddress);
1127 |
1128 | }
1129 | }
1130 |
1131 | ///
1132 | /// Free the memory by the specified index.
1133 | ///
1134 | /// The specified index.
1135 | public void FreeAt(int index)
1136 | {
1137 | var addr = _list[index];
1138 | _list.RemoveAt(index);
1139 | InnerUtilities.ReleaseMemory(_plugin.BaseProcess, addr);
1140 | }
1141 |
1142 | ///
1143 | /// Enumerator.
1144 | ///
1145 | ///
1146 | public IEnumerator GetEnumerator() => _list.GetEnumerator();
1147 |
1148 | ///
1149 | /// Enumerator.
1150 | ///
1151 | ///
1152 | IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
1153 |
1154 | #endregion
1155 |
1156 | #region Internal IDisposable Support
1157 |
1158 | private bool disposedValue = false;
1159 |
1160 | ~AllocatedMemoryCollection()
1161 | {
1162 | Dispose();
1163 | }
1164 |
1165 | internal void Dispose()
1166 | {
1167 | try
1168 | {
1169 | if (!disposedValue) FreeAll();
1170 | }
1171 | #pragma warning disable CA1031 // Do not catch general exception types
1172 | catch { }
1173 | #pragma warning restore CA1031 // Do not catch general exception types
1174 | finally
1175 | {
1176 | _list = null;
1177 | _plugin = null;
1178 | disposedValue = true;
1179 | GC.SuppressFinalize(this);
1180 | }
1181 | }
1182 |
1183 |
1184 | #endregion
1185 |
1186 |
1187 | }
1188 |
1189 |
1190 |
1191 | }
1192 |
1193 |
1194 | #pragma warning disable CA1027 // Mark enums with FlagsAttribute
1195 | ///
1196 | /// Represents which protection type of memory should be searched.
1197 | ///
1198 | public enum MemoryProtectionFilter
1199 | #pragma warning restore CA1027 // Mark enums with FlagsAttribute
1200 | {
1201 | ///
1202 | /// Not specified.
1203 | ///
1204 | None = 0,
1205 | /// Enables execute access to the committed region of pages.
1206 | ///
1207 | Execute = 0x10,
1208 | ///
1209 | /// Enables execute or read-only access to the committed region of pages.
1210 | ///
1211 | ExecuteRead = 0x20,
1212 | ///
1213 | /// Enables execute, read-only, or read/write access to the committed region of pages.
1214 | ///
1215 | ExecuteReadWrite = 0x40,
1216 | ///
1217 | /// Enables execute, read-only, or copy-on-write access to a mapped view of a file mapping object.
1218 | ///
1219 | ExecuteWriteCopy = 0x80,
1220 | ///
1221 | /// Enables read-only access to the committed region of pages.
1222 | ///
1223 | ReadOnly = 0x02,
1224 | ///
1225 | /// Enables read-only or read/write access to the committed region of pages.
1226 | ///
1227 | ReadWrite = 0x04,
1228 | ///
1229 | /// Enables read-only or copy-on-write access to a mapped view of a file mapping object.
1230 | ///
1231 | WriteCopy = 0x08
1232 | }
1233 |
1234 | ///
1235 | /// Represent the state of remote calling.
1236 | ///
1237 | public sealed class RemoteCallState
1238 | {
1239 | ///
1240 | /// Indicates that if the invoke is succeed.
1241 | ///
1242 | public bool Succeed { get; }
1243 | ///
1244 | /// Contains the error infomation, if succeed, this value is set to null.
1245 | ///
1246 | public string Message { get; }
1247 | ///
1248 | /// Contains the object to reference, if succeed, this value is set to null.
1249 | ///
1250 | public Win32Exception Exception { get; }
1251 | internal RemoteCallState(bool succeed, string message, Win32Exception exception)
1252 | {
1253 | Succeed = succeed;
1254 | Message = message;
1255 | Exception = exception;
1256 | }
1257 | }
1258 |
1259 | ///
1260 | /// Represents the another version of class.
1261 | ///
1262 | public sealed class ProcessModuleAlter
1263 | {
1264 | private FileVersionInfo _fileVersion = null;
1265 | private int _xxhash;
1266 |
1267 | ///
1268 | /// Gets the name of the process module.
1269 | ///
1270 | public string ModuleName { get; }
1271 | ///
1272 | /// Gets the full path to the module.
1273 | ///
1274 | public string FileName { get; }
1275 | ///
1276 | /// Gets the memory address where the module was loaded.
1277 | ///
1278 | public IntPtr BaseAddress { get; }
1279 | ///
1280 | /// Gets the memory address for the function that runs when the system loads and runs the module.
1281 | ///
1282 | public IntPtr EntryPointAddress { get; }
1283 | ///
1284 | /// Gets the amount of memory that is required to load the module.
1285 | ///
1286 | public int ModuleMemorySize { get; }
1287 |
1288 | ///
1289 | /// Gets version information about the module.
1290 | ///
1291 | public FileVersionInfo FileVersionInfo
1292 | {
1293 | get
1294 | {
1295 | if (_fileVersion == null)
1296 | {
1297 | _fileVersion = FileVersionInfo.GetVersionInfo(FileName);
1298 | }
1299 | return _fileVersion;
1300 | }
1301 | }
1302 |
1303 | internal ProcessModuleAlter(string baseName, string fileName, InnerUtilities.ModuleInfo moduleInfo)
1304 | {
1305 | BaseAddress = moduleInfo.BaseOfDll;
1306 | EntryPointAddress = moduleInfo.EntryPoint;
1307 | ModuleMemorySize = moduleInfo.SizeOfImage;
1308 | FileName = fileName;
1309 | ModuleName = baseName;
1310 | }
1311 |
1312 | ///
1313 | /// Converts the name of the module to a string.
1314 | ///
1315 | ///
1316 | public override string ToString() => string.Format(CultureInfo.CurrentCulture, "{0} ({1})", base.ToString(), this.ModuleName);
1317 |
1318 | ///
1319 | /// Get the XXhash32 value of module.
1320 | ///
1321 | ///
1322 | public override int GetHashCode()
1323 | {
1324 | if (_xxhash == 0)
1325 | {
1326 | _xxhash = GetModuleHash(FileName);
1327 | }
1328 |
1329 | return _xxhash;
1330 | }
1331 |
1332 | ///
1333 | /// Get the XXhash32 value of module.
1334 | ///
1335 | /// The full path of module.
1336 | ///
1337 | public static int GetModuleHash(string path)
1338 | {
1339 | using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
1340 | {
1341 | using (var xxh = new InnerUtilities.XXHash32())
1342 | {
1343 | xxh.ComputeHash(fs);
1344 | return (int)xxh.HashUInt32;
1345 | }
1346 | }
1347 | }
1348 | }
1349 |
1350 | ///
1351 | /// Represents a mono assembly.
1352 | ///
1353 | public sealed class MonoAssembly
1354 | {
1355 | internal IntPtr Pointer { get; }
1356 |
1357 | ///
1358 | /// The name of the assembly.
1359 | ///
1360 | public string Name { get; }
1361 |
1362 | internal MonoAssembly(IntPtr pointer, string name)
1363 | {
1364 | Pointer = pointer;
1365 | Name = name;
1366 | }
1367 | }
1368 |
1369 |
1370 | ///
1371 | /// Provides the extension methods of class.
1372 | ///
1373 | public static class ProcessModuleClassExtensions
1374 | {
1375 | ///
1376 | /// Compute the XXHash32 value of specified module.
1377 | ///
1378 | /// object.
1379 | ///
1380 | public static int GetXXHash(this ProcessModule module) => ProcessModuleAlter.GetModuleHash(module.FileName);
1381 | }
1382 |
1383 |
1384 |
1385 | ///
1386 | /// Represents a byte array finder with the immutable pattern.
1387 | ///
1388 | ///
1389 | /// Rules For String Pattern
1390 | /// Any space character (0x20) should be ignored.
1391 | /// A byte number must be expressed as two-digit hexadecimal number, excludes any prefix or postfix.
1392 | /// Question mark (0x3F) represents wildcard and must be in pairs, or it has a leading or trailing hexadecimal number.
1393 | ///
1394 | public class BytesFinder
1395 | {
1396 |
1397 |
1398 | private readonly PatternInfo _mPattInfo;
1399 |
1400 | ///
1401 | /// Initializes a new instance of the class for the specified bytes pattern.
1402 | ///
1403 | /// The bytes pattern to seek.
1404 | /// is null or empty.
1405 | public BytesFinder(byte[] pattern)
1406 | {
1407 | if (pattern == null || pattern.Length == 0) throw new ArgumentException("pattern is null or empty.", nameof(pattern));
1408 | _mPattInfo = new PatternInfo(pattern);
1409 | }
1410 |
1411 | ///
1412 | /// Initializes a new instance of the class for the specified pattern.
1413 | ///
1414 | /// The pattern to seek.
1415 | /// is null.
1416 | ///
1417 | /// The length of is 0 or not equal to this value division by 2.
1418 | /// - Or -
1419 | /// Unexpected char in .
1420 | ///
1421 | public BytesFinder(string pattern)
1422 | {
1423 | if (pattern == null) throw new ArgumentNullException(nameof(pattern), "pattern is null.");
1424 | _mPattInfo = new PatternInfo(pattern.Replace(" ", string.Empty)); //remove placeholder
1425 | }
1426 |
1427 | #region instance methods
1428 |
1429 | ///
1430 | /// Reports the zero-based index of the first occurrence of the pattern in the specified bytes.
1431 | ///
1432 | /// The bytes to search for an occurrence.
1433 | /// The zero-based index position of the occurrence if the pattern is found, otherwise, -1.
1434 | /// is null or empty.
1435 | public int FindIndexIn(byte[] source)
1436 | {
1437 | if (source == null || source.Length == 0) throw new ArgumentException("source is null or empty.", nameof(source));
1438 | return InnerFindIndex(source, in _mPattInfo, 0, source.Length);
1439 | }
1440 |
1441 | ///
1442 | /// Reports the zero-based index of the first occurrence of the pattern in the specified bytes.
1443 | /// The search starts at the specified position.
1444 | ///
1445 | /// The bytes to search for an occurrence.
1446 | /// The search starting position.
1447 | /// The zero-based index position of the occurrence if the pattern is found, otherwise, -1.
1448 | /// is null or empty.
1449 | ///
1450 | /// is less than 0.
1451 | /// - Or -
1452 | /// is greater than or equal to the length of .
1453 | ///
1454 | public int FindIndexIn(byte[] source, int startIndex)
1455 | {
1456 | Ensure_source_startIndex(source, startIndex);
1457 | return InnerFindIndex(source, in _mPattInfo, startIndex, source.Length);
1458 | }
1459 |
1460 | ///
1461 | /// Reports the zero-based index of the first occurrence of the pattern in the specified bytes.
1462 | /// The search starts at the specified position and examines a specified number of positions.
1463 | ///
1464 | /// The bytes to search for an occurrence.
1465 | /// The search starting position.
1466 | /// The number of positions to examine.
1467 | /// The zero-based index position of the occurrence if the pattern is found, otherwise, -1.
1468 | /// is null or empty.
1469 | ///
1470 | /// is less than 0.
1471 | /// - Or -
1472 | /// is greater than or equal to the length of .
1473 | /// - Or -
1474 | /// is less than or equal to 0.
1475 | /// - Or -
1476 | /// is greater than the length of source minus .
1477 | ///
1478 | public int FindIndexIn(byte[] source, int startIndex, int count)
1479 | {
1480 | Ensure_source_startIndex_count(source, startIndex, count);
1481 | return InnerFindIndex(source, in _mPattInfo, startIndex, count);
1482 | }
1483 |
1484 | #endregion
1485 |
1486 | #region static methods
1487 |
1488 | ///
1489 | /// Reports the zero-based index of the first occurrence of the specified pattern in the specified bytes source.
1490 | ///
1491 | /// The bytes to search for an occurrence.
1492 | /// The bytes pattern to seek.
1493 | /// The zero-based index position of the occurrence if the is found, otherwise, -1.
1494 | ///
1495 | /// is null or empty.
1496 | /// - Or -
1497 | /// is null or empty.
1498 | ///
1499 | public static int FindIndex(byte[] source, byte[] pattern)
1500 | {
1501 | if (source == null || source.Length == 0) throw new ArgumentException("source is null or empty.", nameof(source));
1502 | if (pattern == null || pattern.Length == 0) throw new ArgumentException("pattern is null or empty.", nameof(pattern));
1503 | using (var pattInfo = new PatternInfo(pattern))
1504 | {
1505 | return InnerFindIndex(source, in pattInfo, 0, source.Length);
1506 | }
1507 |
1508 | }
1509 |
1510 | ///
1511 | /// Reports the zero-based index of the first occurrence of the specified pattern in the specified bytes source.
1512 | /// The search starts at the specified position.
1513 | ///
1514 | /// The bytes to search for an occurrence.
1515 | /// The bytes pattern to seek.
1516 | /// The search starting position.
1517 | /// The zero-based index position of the occurrence if the is found, otherwise, -1.
1518 | ///
1519 | /// is null or empty.
1520 | /// - Or -
1521 | /// is null or empty.
1522 | ///
1523 | ///
1524 | /// is less than 0.
1525 | /// - Or -
1526 | /// is greater than or equal to the length of .
1527 | ///
1528 | public static int FindIndex(byte[] source, byte[] pattern, int startIndex)
1529 | {
1530 | if (pattern == null || pattern.Length == 0) throw new ArgumentException("pattern is null or empty.", nameof(pattern));
1531 | Ensure_source_startIndex(source, startIndex);
1532 | using (var pattInfo = new PatternInfo(pattern))
1533 | {
1534 | return InnerFindIndex(source, in pattInfo, startIndex, source.Length);
1535 | }
1536 | }
1537 |
1538 | ///
1539 | /// Reports the zero-based index of the first occurrence of the specified pattern in the specified bytes source.
1540 | /// The search starts at the specified position and examines a specified number of positions.
1541 | ///
1542 | /// The bytes to search for an occurrence.
1543 | /// The bytes pattern to seek.
1544 | /// The search starting position.
1545 | /// The number of positions to examine.
1546 | /// The zero-based index position of the occurrence if the is found, otherwise, -1.
1547 | ///
1548 | /// is null or empty.
1549 | /// - Or -
1550 | /// is null or empty.
1551 | ///
1552 | ///
1553 | /// is less than 0.
1554 | /// - Or -
1555 | /// is greater than or equal to the length of .
1556 | /// - Or -
1557 | /// is less than or equal to 0.
1558 | /// - Or -
1559 | /// is greater than the length of source minus .
1560 | ///
1561 | public static int FindIndex(byte[] source, byte[] pattern, int startIndex, int count)
1562 | {
1563 | if (pattern == null || pattern.Length == 0) throw new ArgumentException("pattern is null or empty.", nameof(pattern));
1564 | Ensure_source_startIndex_count(source, startIndex, count);
1565 | using (var pattInfo = new PatternInfo(pattern))
1566 | {
1567 | return InnerFindIndex(source, in pattInfo, startIndex, count);
1568 | }
1569 | }
1570 |
1571 |
1572 | ///
1573 | /// Reports the zero-based index of the first occurrence of the specified pattern in the specified bytes source.
1574 | ///
1575 | /// The bytes to search for an occurrence.
1576 | /// The pattern to seek.
1577 | /// The zero-based index position of the occurrence if the is found, otherwise, -1.
1578 | /// is null or empty.
1579 | /// is null.
1580 | ///
1581 | /// The length of is 0 or not equal to this value division by 2.
1582 | /// - Or -
1583 | /// Unexpected char in .
1584 | ///
1585 | public static int FindIndex(byte[] source, string pattern)
1586 | {
1587 | if (source == null || source.Length == 0) throw new ArgumentException("source is null or empty.", nameof(source));
1588 | return (new BytesFinder(pattern)).FindIndexIn(source);
1589 | }
1590 |
1591 | ///
1592 | /// Reports the zero-based index of the first occurrence of the specified pattern in the specified bytes source.
1593 | /// The search starts at the specified position.
1594 | ///
1595 | /// The bytes to search for an occurrence.
1596 | /// The pattern to seek.
1597 | /// The search starting position.
1598 | /// The zero-based index position of the occurrence if the is found, otherwise, -1.
1599 | /// is null or empty.
1600 | /// is null.
1601 | ///
1602 | /// The length of is 0 or not equal to this value division by 2.
1603 | /// - Or -
1604 | /// Unexpected char in .
1605 | ///
1606 | ///
1607 | /// is less than 0.
1608 | /// - Or -
1609 | /// is greater than or equal to the length of .
1610 | ///
1611 | public static int FindIndex(byte[] source, string pattern, int startIndex)
1612 | {
1613 | Ensure_source_startIndex(source, startIndex);
1614 | return (new BytesFinder(pattern)).FindIndexIn(source, startIndex);
1615 | }
1616 |
1617 | ///
1618 | /// Reports the zero-based index of the first occurrence of the specified pattern in the specified bytes source.
1619 | /// The search starts at the specified position and examines a specified number of positions.
1620 | ///
1621 | /// The bytes to search for an occurrence.
1622 | /// The pattern to seek.
1623 | /// The search starting position.
1624 | /// The number of positions to examine.
1625 | /// The zero-based index position of the occurrence if the is found, otherwise, -1.
1626 | /// is null or empty.
1627 | /// is null.
1628 | ///
1629 | /// The length of is 0 or not equal to this value division by 2.
1630 | /// - Or -
1631 | /// Unexpected char in .
1632 | ///
1633 | ///
1634 | /// is less than 0.
1635 | /// - Or -
1636 | /// is greater than or equal to the length of .
1637 | /// - Or -
1638 | /// is less than or equal to 0.
1639 | /// - Or -
1640 | /// is greater than the length of source minus .
1641 | ///
1642 | public static int FindIndex(byte[] source, string pattern, int startIndex, int count)
1643 | {
1644 | Ensure_source_startIndex_count(source, startIndex, count);
1645 | return (new BytesFinder(pattern)).FindIndexIn(source, startIndex, count);
1646 | }
1647 |
1648 |
1649 | #endregion
1650 |
1651 | private static int InnerFindIndex(byte[] source, in PatternInfo pattern, int startIndex, int count)
1652 | {
1653 | var patternLength = pattern.PatternLength;
1654 | var pattMaxIdx = patternLength - 1;
1655 | var maxLen = count - patternLength + 1;
1656 | unsafe
1657 | {
1658 | fixed (int* next = pattern.MoveTable)
1659 | {
1660 | fixed (byte* src = source)
1661 | {
1662 | while (startIndex < maxLen)
1663 | {
1664 | var mov = next[src[startIndex + pattMaxIdx]];
1665 | if (mov < patternLength)
1666 | {
1667 | startIndex += mov;
1668 | if (pattern.CheckWithPattern(source, startIndex)) return startIndex;
1669 | ++startIndex;
1670 | }
1671 | else
1672 | {
1673 | startIndex += patternLength;
1674 | }
1675 | }
1676 | return -1;
1677 | }
1678 | }
1679 | }
1680 | }
1681 |
1682 | private static void Ensure_source_startIndex(byte[] source, int startIndex)
1683 | {
1684 | if (source == null || source.Length == 0) throw new ArgumentException("source is null or empty.", nameof(source));
1685 | if (startIndex < 0) throw new ArgumentOutOfRangeException(nameof(startIndex), "startIndex is less than 0.");
1686 | if (startIndex >= source.Length) throw new ArgumentOutOfRangeException(nameof(startIndex), "startIndex is greater than or equal to the length of source.");
1687 | }
1688 |
1689 | private static void Ensure_source_startIndex_count(byte[] source, int startIndex, int count)
1690 | {
1691 | if (source == null || source.Length == 0) throw new ArgumentException("source is null or empty.", nameof(source));
1692 | if (startIndex < 0) throw new ArgumentOutOfRangeException(nameof(startIndex), "startIndex is less than 0.");
1693 | if (startIndex >= source.Length) throw new ArgumentOutOfRangeException(nameof(startIndex), "startIndex is greater than or equal to the length of source.");
1694 | if (count <= 0) throw new ArgumentOutOfRangeException(nameof(startIndex), "count is less than or equal to 0.");
1695 | if (count > source.Length - startIndex) throw new ArgumentOutOfRangeException(nameof(count), "count is greater than the length of source minus startIndex.");
1696 | }
1697 |
1698 | private readonly struct PatternInfo : IDisposable
1699 | {
1700 |
1701 | private static readonly ConcurrentBag _MoveTablePool = new ConcurrentBag();
1702 |
1703 | private delegate bool ComparePatternFunc(byte[] source, byte[] pattern, int index);
1704 |
1705 | #region expressions
1706 | private static readonly ParameterExpression _ExpParamSource = Expression.Parameter(typeof(byte[]), "source");
1707 | private static readonly ParameterExpression _ExpParamIndex = Expression.Parameter(typeof(int), "index");
1708 | private static readonly Expression _ExpSourceMaxCount = Expression.Subtract(Expression.ArrayLength(_ExpParamSource), _ExpParamIndex);
1709 |
1710 | private static readonly ParameterExpression _ExpUnusedParamBytesPattern = Expression.Parameter(typeof(byte[]), "unusedBytesPattern");
1711 | private static readonly BinaryExpression _ExpArrayItemIterator = Expression.ArrayIndex(_ExpParamSource, Expression.PostIncrementAssign(_ExpParamIndex));
1712 | private static readonly BlockExpression _ExpUnconditionalTrue = Expression.Block(Expression.PreIncrementAssign(_ExpParamIndex), Expression.Constant(true, typeof(bool)));
1713 | #endregion
1714 |
1715 | private readonly ComparePatternFunc Comparer;
1716 |
1717 | public readonly int PatternLength;
1718 |
1719 | public readonly byte[] BytesPattern;
1720 |
1721 | public readonly int[] MoveTable;
1722 |
1723 | public PatternInfo(byte[] pattern)
1724 | {
1725 | PatternLength = pattern.Length;
1726 | BytesPattern = pattern;
1727 | MoveTable = GetTableFormBag(PatternLength);
1728 | var pattMaxIdx = PatternLength - 1;
1729 |
1730 | unsafe
1731 | {
1732 | fixed (int* next = MoveTable)
1733 | {
1734 | fixed (byte* patt = pattern)
1735 | {
1736 | for (int i = 0; i < PatternLength; i++)
1737 | {
1738 | next[patt[i]] = pattMaxIdx - i;
1739 | }
1740 | }
1741 | }
1742 | }
1743 |
1744 | Comparer = new ComparePatternFunc(CompareCore);
1745 | }
1746 |
1747 | public PatternInfo(string pattern)
1748 | {
1749 | var strLen = pattern.Length;
1750 | if (strLen == 0 || (strLen & 1) == 1) throw new FormatException("The length of pattern is 0 or not equal to this value division by 2.");
1751 | var patternLength = strLen >> 1;
1752 | var maxMove = patternLength - 1;
1753 | var moveTable = GetTableFormBag(patternLength);
1754 |
1755 | Expression exp = Expression.LessThanOrEqual(
1756 | Expression.Constant(patternLength, typeof(int)),
1757 | _ExpSourceMaxCount);
1758 |
1759 | #region generates move table and comparison expression
1760 | unsafe
1761 | {
1762 | fixed (int* next = moveTable)
1763 | {
1764 | fixed (char* patt = pattern)
1765 | {
1766 | var iPatt = (int*)patt;
1767 |
1768 | var idx = 0;
1769 | while (idx < strLen)
1770 | {
1771 | var badMove = maxMove - (idx >> 1);
1772 | var currentChar = patt[idx++];
1773 | var nextChar = patt[idx++];
1774 | int nextDigit;
1775 | if (currentChar == '?')
1776 | {
1777 | if (nextChar == '?') //??
1778 | {
1779 | SetMultiBadMove(next, badMove, 0, 1); //update move table
1780 | //update expression
1781 | exp = Expression.AndAlso(exp, _ExpUnconditionalTrue);
1782 | }
1783 | else //?a
1784 | {
1785 | nextDigit = GetHexDigit(nextChar);
1786 | SetMultiBadMove(next, badMove, nextDigit, 0x10); //update move table
1787 | exp = MakeExpCmpDigit(exp, nextDigit, 0x0F); //update expression
1788 | }
1789 | }
1790 | else
1791 | {
1792 | var firstDigit = GetHexDigit(currentChar) << 4;
1793 |
1794 | if (nextChar == '?') //a?
1795 | {
1796 | SetMultiBadMove(next, badMove, firstDigit, 1); //update move table
1797 | exp = MakeExpCmpDigit(exp, firstDigit, 0xF0); //update expression
1798 | }
1799 | else //ab
1800 | {
1801 | nextDigit = GetHexDigit(nextChar);
1802 | var hexNum = (byte)(firstDigit | nextDigit);
1803 | next[hexNum] = badMove; //update move table
1804 | //update expression
1805 | exp = Expression.AndAlso(
1806 | exp,
1807 | Expression.Equal(
1808 | _ExpArrayItemIterator,
1809 | Expression.Constant(hexNum, typeof(byte))));
1810 | }
1811 | }
1812 | }
1813 | }
1814 | }
1815 | }
1816 | #endregion
1817 |
1818 | Comparer = Expression.Lambda(
1819 | exp, _ExpParamSource, _ExpUnusedParamBytesPattern, _ExpParamIndex)
1820 | .Compile();
1821 |
1822 | PatternLength = patternLength;
1823 | MoveTable = moveTable;
1824 | BytesPattern = null;
1825 | }
1826 |
1827 | public bool CheckWithPattern(byte[] source, int index) => Comparer(source, BytesPattern, index);
1828 |
1829 | private static Expression MakeExpCmpDigit(Expression exp, int digit, int mask) => Expression.AndAlso(
1830 | exp,
1831 | Expression.Equal(
1832 | Expression.And(
1833 | _ExpArrayItemIterator,
1834 | Expression.Constant((byte)mask, typeof(byte))),
1835 | Expression.Constant((byte)digit, typeof(byte))));
1836 |
1837 | private static bool CompareCore(byte[] source, byte[] pattern, int index)
1838 | {
1839 | var length = pattern.Length;
1840 | unsafe
1841 | {
1842 | fixed (byte* src = source, patt = pattern)
1843 | {
1844 | for (var i = 0; i < length; i++)
1845 | {
1846 | if (src[index + i] != patt[i])
1847 | {
1848 | return false;
1849 | }
1850 | }
1851 | return true;
1852 | }
1853 | }
1854 | }
1855 |
1856 | private unsafe static void SetMultiBadMove(int* moveTable, int badMove, int start, int step)
1857 | {
1858 | for (int i = start; i < 256; i += step)
1859 | {
1860 | moveTable[i] = badMove;
1861 | }
1862 | }
1863 |
1864 | private static int GetHexDigit(char number)
1865 | {
1866 | if (number >= '0' && number <= '9')
1867 | {
1868 | return number - '0';
1869 | }
1870 | else if ((number >= 'a' && number <= 'f') ||
1871 | (number >= 'A' && number <= 'F'))
1872 | {
1873 | return (number & 7) + 9; // 'a'=0x61, 'A'=0x41
1874 | }
1875 | throw new FormatException("Unexpected char in pattern.");
1876 | }
1877 |
1878 | private static int[] GetTableFormBag(int patternLength)
1879 | {
1880 | var result = _MoveTablePool.TryTake(out var item) ? item : new int[256];
1881 | unsafe
1882 | {
1883 | fixed (int* buffer = result)
1884 | {
1885 | for (int i = 0; i < 256; i++)
1886 | {
1887 | buffer[i] = patternLength;
1888 | }
1889 | }
1890 | }
1891 | return result;
1892 | }
1893 | public void Dispose()
1894 | {
1895 | _MoveTablePool.Add(MoveTable);
1896 | }
1897 | }
1898 | }
1899 |
1900 | internal static class InnerUtilities
1901 | {
1902 | public const int INFINITE_INT = -1;
1903 |
1904 | public static readonly NativeMethods.SysInfo SystemInfo = new NativeMethods.SysInfo();
1905 |
1906 |
1907 | static InnerUtilities()
1908 | {
1909 | NativeMethods.GetSystemInfo(SystemInfo);
1910 | }
1911 |
1912 |
1913 | public static Process GetProcessByWindow(string windowName, string windowClass)
1914 | {
1915 | var hWnd = NativeMethods.FindWindowEx(IntPtr.Zero, IntPtr.Zero, windowClass, windowName);
1916 |
1917 | if (hWnd == IntPtr.Zero)
1918 | {
1919 | var error = Marshal.GetLastWin32Error();
1920 | if (error == 2) return null; //2 = Not Founded
1921 | throw new Win32Exception(error);
1922 | }
1923 | NativeMethods.GetWindowThreadProcessId(hWnd, out var pid);
1924 | return Process.GetProcessById(pid);
1925 | }
1926 |
1927 | public static string GetWindowClassByHandle(Process process)
1928 | {
1929 | var sb = StringBuilderPool.Rent();
1930 | if (NativeMethods.GetClassName(process.MainWindowHandle, sb, 2048) == 0)
1931 | {
1932 | throw new Win32Exception(Marshal.GetLastWin32Error());
1933 | }
1934 | var className = sb.ToString();
1935 | StringBuilderPool.Return(sb);
1936 | return className;
1937 | }
1938 |
1939 | public static ProcessModuleAlter GetModuleByName(Process process, string moduleName)
1940 | {
1941 | if (string.IsNullOrWhiteSpace(moduleName)) throw new ArgumentException("moduleName is null or empty.", nameof(moduleName));
1942 |
1943 | var hr = new HandleRef(process, process.Handle);
1944 |
1945 | var size = 0;
1946 | if (!NativeMethods.EnumProcessModulesEx(hr, null, 0, ref size, NativeMethods.ModuleFilter.LIST_MODULES_ALL))
1947 | {
1948 | throw new Win32Exception(Marshal.GetLastWin32Error());
1949 | }
1950 |
1951 | var modules = new IntPtr[size / IntPtr.Size];
1952 | if (!NativeMethods.EnumProcessModulesEx(hr, modules, size, ref size, NativeMethods.ModuleFilter.LIST_MODULES_ALL))
1953 | {
1954 | throw new Win32Exception(Marshal.GetLastWin32Error());
1955 | }
1956 |
1957 | var sb = StringBuilderPool.Rent();
1958 | var moduleInfo = ModuleInfoPool.Rent();
1959 | try
1960 | {
1961 | foreach (var item in modules)
1962 | {
1963 | if (NativeMethods.GetModuleBaseName(hr, item, sb, 2048) == 0)
1964 | {
1965 | throw new Win32Exception(Marshal.GetLastWin32Error());
1966 |
1967 | }
1968 | if (!moduleName.Equals(sb.ToString()))
1969 | {
1970 | continue;
1971 | }
1972 |
1973 | if (NativeMethods.GetModuleFileNameEx(hr, item, sb, 2048) == 0)
1974 | {
1975 | throw new Win32Exception(Marshal.GetLastWin32Error());
1976 | }
1977 |
1978 | if (!NativeMethods.GetModuleInformation(hr, item, moduleInfo, ModuleInfo.Size))
1979 | {
1980 | throw new Win32Exception(Marshal.GetLastWin32Error());
1981 | }
1982 | return new ProcessModuleAlter(moduleName, sb.ToString(), moduleInfo);
1983 | }
1984 | return null;
1985 | }
1986 | finally
1987 | {
1988 | StringBuilderPool.Return(sb);
1989 | ModuleInfoPool.Return(moduleInfo);
1990 | }
1991 | }
1992 |
1993 | public static T ReadData(Process process, IntPtr address) where T : unmanaged
1994 | {
1995 | T data = default;
1996 | unsafe
1997 | {
1998 | void* p = &data;
1999 | AccessMemory(process, address, p, new IntPtr(Marshal.SizeOf()), NativeMethods.ReadProcessMemory);
2000 | }
2001 | return data;
2002 | }
2003 |
2004 | public static T[] ReadData(Process process, IntPtr address, int count) where T : unmanaged
2005 | {
2006 | var data = new T[count];
2007 | ReadData(process, address, data, 0, count);
2008 | return data;
2009 | }
2010 |
2011 | public static void ReadData(Process process, IntPtr address, T[] data, int startIndex, int count) where T : unmanaged
2012 | {
2013 | EnsureDateIndexCount(data, startIndex, count);
2014 | unsafe
2015 | {
2016 | fixed (void* p = data)
2017 | {
2018 | AccessMemory(process, address, p, new IntPtr(Marshal.SizeOf() * (count - startIndex)), NativeMethods.ReadProcessMemory);
2019 | }
2020 |
2021 | }
2022 | }
2023 |
2024 | public static void WriteData(Process process, IntPtr address, params T[] data) where T : unmanaged
2025 | {
2026 | WriteData(process, address, data, 0, data.Length);
2027 | }
2028 |
2029 | public static void WriteData(Process process, IntPtr address, T[] data, int startIndex, int count) where T : unmanaged
2030 | {
2031 | EnsureDateIndexCount(data, startIndex, count);
2032 | unsafe
2033 | {
2034 | fixed (void* p = data)
2035 | {
2036 | AccessMemory(process, address, p, new IntPtr(Marshal.SizeOf() * (count - startIndex)), NativeMethods.WriteProcessMemory);
2037 | }
2038 | }
2039 |
2040 | }
2041 |
2042 | public static IntPtr AllocMemory(ProcessPlugin plugin, IntPtr address, int size)
2043 | {
2044 | NativeMethods.AllocationOption options = NativeMethods.AllocationOption.Commit;
2045 | if (address != IntPtr.Zero)
2046 | {
2047 | if (!plugin.Is64BitProcess)
2048 | {
2049 | address = IntPtr.Zero;
2050 | }
2051 | else
2052 | {
2053 | address = ScanNearAddress(plugin, address, size);
2054 | if (address != IntPtr.Zero)
2055 | {
2056 | options |= NativeMethods.AllocationOption.Reserve;
2057 | }
2058 | }
2059 | }
2060 |
2061 | var hr = new HandleRef(plugin.BaseProcess, plugin.BaseProcess.Handle);
2062 | var result = NativeMethods.VirtualAllocEx(hr, address, new IntPtr(size), options, NativeMethods.MemoryProtection.ExecuteReadWrite);
2063 | if (result == IntPtr.Zero)
2064 | {
2065 | throw new Win32Exception(Marshal.GetLastWin32Error());
2066 | }
2067 | return result;
2068 | }
2069 |
2070 | public static void ReleaseMemory(Process process, IntPtr address)
2071 | {
2072 | try
2073 | {
2074 | var hr = new HandleRef(process, process.Handle);
2075 | NativeMethods.VirtualFreeEx(hr, address, IntPtr.Zero, NativeMethods.FreeOption.Release);
2076 | }
2077 | #pragma warning disable CA1031 // Do not catch general exception types
2078 | catch { }
2079 | #pragma warning restore CA1031 // Do not catch general exception types
2080 | }
2081 |
2082 | public static IntPtr ScanByteArray(Process process, byte[] pattern, Func checker, IntPtr addressStart, IntPtr addressEnd, MemoryProtectionFilter filter)
2083 | {
2084 | var hr = new HandleRef(process, process.Handle);
2085 | unsafe
2086 | {
2087 | var address = addressStart;
2088 | var memInfo = new NativeMethods.MemoryBasicInfo();
2089 | var miSize = NativeMethods.MemoryBasicInfo.Size;
2090 | while (address.ToPointer() < addressEnd.ToPointer())
2091 | {
2092 | if (!NativeMethods.VirtualQueryEx(hr, address, memInfo, miSize))
2093 | {
2094 | return IntPtr.Zero;
2095 | }
2096 | if (memInfo.State.HasFlag(NativeMethods.MemoryState.Commit) &&
2097 | !memInfo.Protect.HasFlag(NativeMethods.MemoryProtection.Guard) &&
2098 | !memInfo.Protect.HasFlag(NativeMethods.MemoryProtection.NoAccess) &&
2099 | memInfo.Protect.HasFlag((NativeMethods.MemoryProtection)filter))
2100 | {
2101 | var buffer = ReadData(process, memInfo.BaseAddress, memInfo.RegionSize.ToInt32());
2102 | var result = checker(buffer, pattern);
2103 | if (result != -1)
2104 | {
2105 | return memInfo.BaseAddress + result;
2106 | }
2107 | }
2108 | address = new IntPtr(memInfo.BaseAddress.ToInt64() + memInfo.RegionSize.ToInt64());
2109 | }
2110 | }
2111 | return IntPtr.Zero;
2112 | }
2113 |
2114 | private static IntPtr ScanNearAddress(ProcessPlugin plugin, IntPtr addressToRef, int size)
2115 | {
2116 | var hr = new HandleRef(plugin.BaseProcess, plugin.BaseProcess.Handle);
2117 |
2118 | var minMem = SystemInfo.MinimumApplicationAddress.ToInt64();
2119 | var maxMem = plugin._maxMemory.ToInt64();
2120 |
2121 |
2122 | var minAddr = addressToRef.ToInt64() - 0x70000000;
2123 | var maxAddr = addressToRef.ToInt64() + 0x70000000;
2124 |
2125 | if (minAddr > maxMem || minAddr < minMem) minAddr = minMem;
2126 |
2127 | if (maxAddr < minMem || maxAddr > maxMem) maxAddr = maxMem;
2128 |
2129 | var nowRef = minAddr;
2130 |
2131 | var targetAddr = addressToRef.ToInt64();
2132 | var allocGranularity = SystemInfo.AllocationGranularity;
2133 | var lastResult = 0L;
2134 |
2135 | var memInfo = new NativeMethods.MemoryBasicInfo();
2136 | var miSize = NativeMethods.MemoryBasicInfo.Size;
2137 |
2138 | unsafe
2139 | {
2140 | while (NativeMethods.VirtualQueryEx(hr, new IntPtr(nowRef), memInfo, miSize))
2141 | {
2142 | var memBase = memInfo.BaseAddress.ToInt64();
2143 |
2144 | if (memBase > maxAddr) break;
2145 |
2146 | var regionSize = memInfo.RegionSize.ToInt64();
2147 |
2148 | if (memInfo.State == NativeMethods.MemoryState.Free &&
2149 | regionSize > size)
2150 | {
2151 | var x = memBase;
2152 | var baseleft = memBase % allocGranularity;
2153 |
2154 | if (baseleft != 0)
2155 | {
2156 | var offset = allocGranularity - baseleft;
2157 | var tof = regionSize - offset;
2158 | if (tof >= size)
2159 | {
2160 | x += offset;
2161 | if (x < targetAddr)
2162 | {
2163 | x += tof - size;
2164 | if (x > targetAddr) x = targetAddr;
2165 | x -= x % allocGranularity;
2166 | }
2167 | if (Math.Abs(x - targetAddr) < Math.Abs(lastResult - targetAddr)) lastResult = x;
2168 | }
2169 | }
2170 | else
2171 | {
2172 | if (x < targetAddr)
2173 | {
2174 | x += regionSize - size;
2175 | if (x > targetAddr) x = targetAddr;
2176 | x -= x % allocGranularity;
2177 | }
2178 | if (Math.Abs(x - targetAddr) < Math.Abs(lastResult - targetAddr)) lastResult = x;
2179 | }
2180 | }
2181 |
2182 | var regionLeft = regionSize % allocGranularity;
2183 |
2184 | if (regionLeft != 0) regionSize += allocGranularity - regionLeft;
2185 |
2186 | var oldRef = nowRef;
2187 | nowRef = memBase + regionSize;
2188 | if (nowRef > maxAddr || oldRef > nowRef)
2189 | {
2190 | break;
2191 | }
2192 | }
2193 | }
2194 | return new IntPtr(lastResult);
2195 | }
2196 |
2197 | public static RemoteCallState CallRemoteFunc(Process process, IntPtr address, int timeOut)
2198 | {
2199 | var hr = new HandleRef(process, process.Handle);
2200 | var succeed = false;
2201 | string Msg = null;
2202 | Win32Exception ex = null;
2203 | using (var rhandle = NativeMethods.CreateRemoteThread(hr, IntPtr.Zero, IntPtr.Zero, address, IntPtr.Zero, NativeMethods.ThreadCreationFlags.None, out _))
2204 | {
2205 | if (rhandle.IsInvalid)
2206 | {
2207 | Msg = "Failed to create thread.";
2208 | ex = new Win32Exception(Marshal.GetLastWin32Error());
2209 | }
2210 |
2211 | switch (NativeMethods.WaitForSingleObject(rhandle, timeOut))
2212 | {
2213 | case NativeMethods.WaitObjectResult.WAIT_FAILED:
2214 | ex = new Win32Exception(Marshal.GetLastWin32Error());
2215 | Msg = "Unanticipated exception.";
2216 | break;
2217 | case NativeMethods.WaitObjectResult.WAIT_TIMEOUT:
2218 | Msg = "Timeout.";
2219 | if (!NativeMethods.TerminateThread(rhandle, 0))
2220 | {
2221 | ex = new Win32Exception(Marshal.GetLastWin32Error());
2222 | Msg += "\nAnd failed to kill remote thread.";
2223 | }
2224 | break;
2225 | default:
2226 | succeed = true;
2227 | break;
2228 | }
2229 | return new RemoteCallState(succeed, Msg, ex);
2230 | }
2231 | }
2232 |
2233 |
2234 | private unsafe delegate bool AccMemDel(HandleRef hProcess, IntPtr lpBaseAddress, void* lpBuffer, IntPtr nSize, out IntPtr lpNumberOfBytes);
2235 |
2236 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Interoperability", "CA1404:CallGetLastErrorImmediatelyAfterPInvoke")]
2237 | private unsafe static void AccessMemory(Process process, IntPtr address, [In] void* data, IntPtr size, AccMemDel action)
2238 | {
2239 | var hr = new HandleRef(process, process.Handle);
2240 |
2241 | if (!action(hr, address, data, size, out _))
2242 | {
2243 | var error = Marshal.GetLastWin32Error();
2244 | if (error == NativeMethods.ERROR_NOACCESS)
2245 | {
2246 | if (!NativeMethods.VirtualProtectEx(hr, address, size, NativeMethods.MemoryProtection.ExecuteReadWrite, out var oldProtect))
2247 | {
2248 | throw new Win32Exception(Marshal.GetLastWin32Error());
2249 | }
2250 |
2251 | try
2252 | {
2253 | if (!action(hr, address, data, size, out _))
2254 | {
2255 | throw new Win32Exception(Marshal.GetLastWin32Error());
2256 | }
2257 | }
2258 | finally
2259 | {
2260 | NativeMethods.VirtualProtectEx(hr, address, size, oldProtect, out var _);
2261 | }
2262 | }
2263 | else
2264 | {
2265 | throw new Win32Exception(
2266 | error,
2267 | $"{action.Method.Name}: Process={{{hr.Handle.ToString("X")}}}, Address={{{address.ToString("X")}}}");
2268 | }
2269 | }
2270 | }
2271 |
2272 |
2273 | private static void EnsureDateIndexCount(T[] data, int startIndex, int count)
2274 | {
2275 | if (data == null || data.Length < 1) throw new ArgumentException("data is null or empty.", nameof(data));
2276 | if (count < 1 || startIndex < 0 || data.Length - startIndex < count)
2277 | {
2278 | throw new ArgumentOutOfRangeException("startIndex is less than 0 or count is less than 1 or data length minus startIndex is less than count.");
2279 | }
2280 | }
2281 |
2282 | ///
2283 | /// Represents the class which provides a implementation of the xxHash32 algorithm.
2284 | ///
2285 | ///
2286 | public sealed class XXHash32 : HashAlgorithm
2287 | {
2288 | private const uint PRIME32_1 = 2654435761U;
2289 | private const uint PRIME32_2 = 2246822519U;
2290 | private const uint PRIME32_3 = 3266489917U;
2291 | private const uint PRIME32_4 = 668265263U;
2292 | private const uint PRIME32_5 = 374761393U;
2293 |
2294 | private static uint FuncGetLittleEndianUInt32(byte[] buffer, int index)
2295 | {
2296 | unsafe
2297 | {
2298 | fixed (byte* array = buffer)
2299 | {
2300 | return *(uint*)(array + index);
2301 | }
2302 | }
2303 | }
2304 |
2305 | private static uint FuncGetFinalHashUInt32(uint i) => (i & 0x000000FFU) << 24 | (i & 0x0000FF00U) << 8 | (i & 0x00FF0000U) >> 8 | (i & 0xFF000000U) >> 24;
2306 |
2307 | private uint _Seed32;
2308 |
2309 | private uint _ACC32_1;
2310 | private uint _ACC32_2;
2311 | private uint _ACC32_3;
2312 | private uint _ACC32_4;
2313 |
2314 | private uint _Hash32;
2315 |
2316 |
2317 | private int _RemainingLength;
2318 | private long _TotalLength = 0;
2319 | private int _CurrentIndex;
2320 | private byte[] _CurrentArray;
2321 |
2322 | ///
2323 | /// Initializes a new instance of the class by default seed(0).
2324 | ///
2325 | public XXHash32() => Initialize(0);
2326 |
2327 | ///
2328 | /// Initializes a new instance of the class, and sets the to the specified value.
2329 | ///
2330 | /// Represent the seed to be used for xxHash32 computing.
2331 | public XXHash32(uint seed) => Initialize(seed);
2332 |
2333 | ///
2334 | /// Gets the value of the computed hash code.
2335 | ///
2336 | /// Hash computation has not yet completed.
2337 | public uint HashUInt32 => State == 0 ? _Hash32 : throw new InvalidOperationException("Hash computation has not yet completed.");
2338 |
2339 | ///
2340 | /// Gets or sets the value of seed used by xxHash32 algorithm.
2341 | ///
2342 | /// Hash computation has not yet completed.
2343 | public uint Seed
2344 | {
2345 | get => _Seed32;
2346 | set
2347 | {
2348 |
2349 | if (value != _Seed32)
2350 | {
2351 | if (State != 0) throw new InvalidOperationException("Hash computation has not yet completed.");
2352 | _Seed32 = value;
2353 | Initialize();
2354 | }
2355 | }
2356 | }
2357 |
2358 | ///
2359 | /// Initializes this instance for new hash computing.
2360 | ///
2361 | public override void Initialize()
2362 | {
2363 | _ACC32_1 = _Seed32 + PRIME32_1 + PRIME32_2;
2364 | _ACC32_2 = _Seed32 + PRIME32_2;
2365 | _ACC32_3 = _Seed32 + 0;
2366 | _ACC32_4 = _Seed32 - PRIME32_1;
2367 | }
2368 |
2369 | ///
2370 | /// Routes data written to the object into the hash algorithm for computing the hash.
2371 | ///
2372 | /// The input to compute the hash code for.
2373 | /// The offset into the byte array from which to begin using data.
2374 | /// The number of bytes in the byte array to use as data.
2375 | protected override void HashCore(byte[] array, int ibStart, int cbSize)
2376 | {
2377 | if (State != 1) State = 1;
2378 | var size = cbSize - ibStart;
2379 | _RemainingLength = size & 15;
2380 | if (cbSize >= 16)
2381 | {
2382 | var limit = size - _RemainingLength;
2383 | do
2384 | {
2385 | _ACC32_1 = Round32(_ACC32_1, FuncGetLittleEndianUInt32(array, ibStart));
2386 | _ACC32_2 = Round32(_ACC32_2, FuncGetLittleEndianUInt32(array, ibStart + 4));
2387 | _ACC32_3 = Round32(_ACC32_3, FuncGetLittleEndianUInt32(array, ibStart + 8));
2388 | _ACC32_4 = Round32(_ACC32_4, FuncGetLittleEndianUInt32(array, ibStart + 12));
2389 | ibStart += 16;
2390 | } while (ibStart < limit);
2391 | }
2392 | _TotalLength += cbSize;
2393 |
2394 | if (_RemainingLength != 0)
2395 | {
2396 | _CurrentArray = array;
2397 | _CurrentIndex = ibStart;
2398 | }
2399 | }
2400 |
2401 | ///
2402 | /// Finalizes the hash computation after the last data is processed by the cryptographic stream object.
2403 | ///
2404 | /// The computed hash code.
2405 | protected override byte[] HashFinal()
2406 | {
2407 | if (_TotalLength >= 16)
2408 | {
2409 | _Hash32 = RotateLeft32_1(_ACC32_1) + RotateLeft32_7(_ACC32_2) + RotateLeft32_12(_ACC32_3) + RotateLeft32_18(_ACC32_4);
2410 |
2411 | }
2412 | else
2413 | {
2414 | _Hash32 = _Seed32 + PRIME32_5;
2415 | }
2416 |
2417 | _Hash32 += (uint)_TotalLength;
2418 |
2419 | while (_RemainingLength >= 4)
2420 | {
2421 | _Hash32 = RotateLeft32_17(_Hash32 + FuncGetLittleEndianUInt32(_CurrentArray, _CurrentIndex) * PRIME32_3) * PRIME32_4;
2422 |
2423 | _CurrentIndex += 4;
2424 | _RemainingLength -= 4;
2425 | }
2426 | unsafe
2427 | {
2428 | fixed (byte* arrayPtr = _CurrentArray)
2429 | {
2430 | while (_RemainingLength-- >= 1)
2431 | {
2432 | _Hash32 = RotateLeft32_11(_Hash32 + arrayPtr[_CurrentIndex++] * PRIME32_5) * PRIME32_1;
2433 | }
2434 | }
2435 | }
2436 | _Hash32 = (_Hash32 ^ (_Hash32 >> 15)) * PRIME32_2;
2437 | _Hash32 = (_Hash32 ^ (_Hash32 >> 13)) * PRIME32_3;
2438 | _Hash32 ^= _Hash32 >> 16;
2439 |
2440 | _TotalLength = State = 0;
2441 |
2442 | return BitConverter.GetBytes(FuncGetFinalHashUInt32(_Hash32));
2443 | }
2444 |
2445 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
2446 | private static uint Round32(uint input, uint value) => RotateLeft32_13(input + (value * PRIME32_2)) * PRIME32_1;
2447 |
2448 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
2449 | private static uint RotateLeft32_1(uint value) => (value << 1) | (value >> 31); //_ACC32_1
2450 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
2451 | private static uint RotateLeft32_7(uint value) => (value << 7) | (value >> 25); //_ACC32_2
2452 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
2453 | private static uint RotateLeft32_11(uint value) => (value << 11) | (value >> 21);
2454 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
2455 | private static uint RotateLeft32_12(uint value) => (value << 12) | (value >> 20);// _ACC32_3
2456 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
2457 | private static uint RotateLeft32_13(uint value) => (value << 13) | (value >> 19);
2458 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
2459 | private static uint RotateLeft32_17(uint value) => (value << 17) | (value >> 15);
2460 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
2461 | private static uint RotateLeft32_18(uint value) => (value << 18) | (value >> 14); //_ACC32_4
2462 |
2463 | private void Initialize(uint seed)
2464 | {
2465 | HashSizeValue = 32;
2466 | _Seed32 = seed;
2467 | Initialize();
2468 | }
2469 |
2470 | }
2471 |
2472 | private static class StringBuilderPool
2473 | {
2474 | private static readonly ConcurrentBag _Pool;
2475 |
2476 | #pragma warning disable CA1810 // Initialize reference type static fields inline
2477 | static StringBuilderPool() => _Pool = new ConcurrentBag();
2478 | #pragma warning restore CA1810 // Initialize reference type static fields inline
2479 |
2480 | public static StringBuilder Rent() => _Pool.TryTake(out var obj) ? obj : new StringBuilder(1024);
2481 |
2482 | public static void Return(StringBuilder sb)
2483 | {
2484 | sb.Clear();
2485 | _Pool.Add(sb);
2486 | }
2487 | }
2488 |
2489 | private static class ModuleInfoPool
2490 | {
2491 | private static readonly ConcurrentBag _Pool;
2492 |
2493 | #pragma warning disable CA1810 // Initialize reference type static fields inline
2494 | static ModuleInfoPool() => _Pool = new ConcurrentBag();
2495 | #pragma warning restore CA1810 // Initialize reference type static fields inline
2496 |
2497 | public static ModuleInfo Rent() => _Pool.TryTake(out var obj) ? obj : new ModuleInfo();
2498 |
2499 | public static void Return(ModuleInfo moduleInfo)
2500 | {
2501 | _Pool.Add(moduleInfo);
2502 | }
2503 | }
2504 |
2505 | [StructLayout(LayoutKind.Sequential)]
2506 | public sealed class ModuleInfo
2507 | {
2508 | public readonly IntPtr BaseOfDll = IntPtr.Zero;
2509 | public readonly int SizeOfImage = 0;
2510 | public readonly IntPtr EntryPoint = IntPtr.Zero;
2511 |
2512 | public static readonly int Size = Marshal.SizeOf();
2513 |
2514 | }
2515 |
2516 | public static class NativeMethods
2517 | {
2518 | [DllImport("user32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
2519 | public static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpszClass, string lpszWindow);
2520 |
2521 | [DllImport("user32.dll", CallingConvention = CallingConvention.Winapi)]
2522 | public static extern int GetWindowThreadProcessId(IntPtr hWnd, [Out] out int lpdwProcessId);
2523 |
2524 | [DllImport("user32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
2525 | public static extern int GetClassName(IntPtr hWnd, [In, Out] StringBuilder lpClassName, int nMaxCount);
2526 |
2527 | [DllImport("psapi.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
2528 | [return: MarshalAs(UnmanagedType.Bool)]
2529 | public static extern bool EnumProcessModulesEx(HandleRef hProcess,
2530 | [MarshalAs(UnmanagedType.LPArray)] [In][Out] IntPtr[] lphModule,
2531 | int cb,
2532 | [In, Out] ref int lpcbNeeded,
2533 | ModuleFilter dwFilterFlag);
2534 |
2535 | [DllImport("msvcrt.dll", EntryPoint = "memcmp", CallingConvention = CallingConvention.Cdecl)]
2536 | public static extern int Memcmp(byte[] b1, byte[] b2, int count);
2537 |
2538 |
2539 | [DllImport("psapi.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
2540 | public static extern int GetModuleBaseName(HandleRef hProcess, IntPtr hModule, [In, Out] StringBuilder lpBaseName, int nSize);
2541 |
2542 | [DllImport("psapi.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
2543 | public static extern int GetModuleFileNameEx(HandleRef hProcess, IntPtr hModule, [In, Out] StringBuilder lpFilename, int nSize);
2544 |
2545 | [DllImport("psapi.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
2546 | [return: MarshalAs(UnmanagedType.Bool)]
2547 | public static extern bool GetModuleInformation(HandleRef processHandle, IntPtr moduleHandle, [In, Out] ModuleInfo ntModuleInfo, int size);
2548 |
2549 | [DllImport("Kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
2550 | [return: MarshalAs(UnmanagedType.Bool)]
2551 | public unsafe static extern bool ReadProcessMemory(HandleRef hProcess, IntPtr lpBaseAddress, [In, Out] void* lpBuffer, [MarshalAs(UnmanagedType.SysInt)]IntPtr nSize, [Out, Optional, MarshalAs(UnmanagedType.SysInt)] out IntPtr lpNumberOfBytesRead);
2552 |
2553 | [DllImport("Kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
2554 | [return: MarshalAs(UnmanagedType.Bool)]
2555 | public unsafe static extern bool WriteProcessMemory(HandleRef hProcess, IntPtr lpBaseAddress, [In, Out] void* lpBuffer, [MarshalAs(UnmanagedType.SysInt)]IntPtr nSize, [Out, Optional, MarshalAs(UnmanagedType.SysInt)] out IntPtr lpNumberOfBytesWritten);
2556 |
2557 | [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
2558 | [return: MarshalAs(UnmanagedType.Bool)]
2559 | public static extern bool VirtualProtectEx(HandleRef hProcess, IntPtr lpAddress, [MarshalAs(UnmanagedType.SysInt)] IntPtr dwSize, MemoryProtection flNewProtect, [Out] out MemoryProtection lpflOldProtect);
2560 |
2561 | [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
2562 | public static extern IntPtr VirtualAllocEx(HandleRef hProcess, IntPtr lpAddress, [MarshalAs(UnmanagedType.SysInt)] IntPtr nSize, AllocationOption flAllocationType, MemoryProtection flProtect);
2563 |
2564 | [DllImport("kernel32.dll", SetLastError = false, CallingConvention = CallingConvention.Winapi)]
2565 | [return: MarshalAs(UnmanagedType.Bool)]
2566 | public static extern bool VirtualFreeEx(HandleRef hProcess, IntPtr lpAddress, [MarshalAs(UnmanagedType.SysInt)] IntPtr nSize, FreeOption dwFreeType);
2567 |
2568 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", MessageId = "return")]
2569 | [DllImport("kernel32.dll", SetLastError = false, CallingConvention = CallingConvention.Winapi)]
2570 | [return: MarshalAs(UnmanagedType.Bool)]
2571 | public static extern bool VirtualQueryEx(HandleRef hProcess, IntPtr lpAddress, [In] MemoryBasicInfo lpBuffer, IntPtr dwLength);
2572 |
2573 | [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
2574 | public unsafe static extern SafeWaitHandle CreateRemoteThread(HandleRef hProcess, IntPtr lpThreadAttributes, IntPtr dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, ThreadCreationFlags dwCreationFlags, out int threadID);
2575 |
2576 | [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
2577 | [return: MarshalAs(UnmanagedType.Bool)]
2578 | public static extern bool TerminateThread(SafeWaitHandle hThread, int dwExitCode);
2579 |
2580 | [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
2581 | public static extern WaitObjectResult WaitForSingleObject([In] SafeWaitHandle hHandle, [In] int dwMilliseconds);
2582 |
2583 | [DllImport("kernel32.dll", SetLastError = false, CallingConvention = CallingConvention.Winapi)]
2584 | [return: MarshalAs(UnmanagedType.Bool)]
2585 | public static extern bool IsWow64Process(HandleRef hProcess, [Out] out bool Wow64Process);
2586 |
2587 | [DllImport("kernel32", SetLastError = true)]
2588 | public static extern void GetSystemInfo(SysInfo lpSystemInfo);
2589 |
2590 | public const int ERROR_NOACCESS = 0x3E6;
2591 |
2592 |
2593 | ///
2594 | /// Process access rights.
2595 | ///
2596 | [Flags]
2597 | internal enum ProcessAccessOption : uint
2598 | {
2599 | All = 0x1F0FFF,
2600 | CreateProcess = 0x80,
2601 | CreateThread = 0x02,
2602 | DuplicateHandle = 0x40,
2603 | QueryInformation = 0x400,
2604 | QueryLimitedInformation = 0x1000,
2605 | SetInformation = 0x200,
2606 | SetQuota = 0x100,
2607 | SuspendResume = 0x800,
2608 | Terminate = 0x01,
2609 | VirtualMemoryOperation = 0x08,
2610 | VirtualMemoryRead = 0x10,
2611 | VirtualMemoryWrite = 0x20,
2612 | Synchronize = 0x100000
2613 | }
2614 |
2615 |
2616 | ///
2617 | /// Contains information about a range of pages in the virtual address space of a process.
2618 | ///
2619 | [StructLayout(LayoutKind.Sequential)]
2620 | public class MemoryBasicInfo
2621 | {
2622 | ///
2623 | /// The base address of the region of pages.
2624 | ///
2625 | public readonly IntPtr BaseAddress;
2626 |
2627 | ///
2628 | /// The base address of a range of pages.
2629 | ///
2630 | public readonly IntPtr AllocationBase;
2631 |
2632 | private readonly IntPtr _Arg1;
2633 | ///
2634 | /// The memory protection option when the region was initially allocated.
2635 | ///
2636 | public MemoryProtection AllocationProtect => IntPtr.Size == 4 ? (MemoryProtection)_Arg1.ToInt32() : (MemoryProtection)((uint)_Arg1.ToInt32() >> 32);
2637 |
2638 | ///
2639 | /// The size of the region beginning at the base address in which all pages have identical attributes, in bytes.
2640 | ///
2641 | [MarshalAs(UnmanagedType.SysInt)]
2642 | public readonly IntPtr RegionSize;
2643 |
2644 | ///
2645 | /// The state of the pages in the region.
2646 | ///
2647 | public readonly MemoryState State;
2648 |
2649 | ///
2650 | /// The access protection of the pages in the region.
2651 | ///
2652 | public readonly MemoryProtection Protect;
2653 |
2654 |
2655 | private readonly IntPtr _Arg2;
2656 |
2657 | ///
2658 | /// The type of pages in the region. The following types are defined.
2659 | ///
2660 | public MemoryType Type => IntPtr.Size == 4 ? (MemoryType)_Arg1.ToInt32() : (MemoryType)((ulong)_Arg1.ToInt64() >> 4);
2661 |
2662 | public static readonly IntPtr Size = new IntPtr(Marshal.SizeOf());
2663 |
2664 | }
2665 |
2666 |
2667 | ///
2668 | /// The state of the pages in the region.
2669 | ///
2670 | internal enum MemoryState : uint
2671 | {
2672 | ///
2673 | /// Indicates committed pages for which physical storage has been allocated, either in memory or in the paging file on disk.
2674 | ///
2675 | Commit = 0x1000,
2676 | ///
2677 | /// Indicates free pages not accessible to the calling process and available to be allocated.
2678 | ///
2679 | Free = 0x10000,
2680 | ///
2681 | /// Releases the specified region of pages.
2682 | ///
2683 | Reserve = 0x2000
2684 | }
2685 |
2686 | [Flags]
2687 | public enum MemoryProtection : uint
2688 | {
2689 | ///
2690 | /// Enables execute access to the committed region of pages.
2691 | ///
2692 | Execute = 0x10,
2693 | ///
2694 | /// Enables execute or read-only access to the committed region of pages.
2695 | ///
2696 | ExecuteRead = 0x20,
2697 | ///
2698 | /// Enables execute, read-only, or read/write access to the committed region of pages.
2699 | ///
2700 | ExecuteReadWrite = 0x40,
2701 | ///
2702 | /// Enables execute, read-only, or copy-on-write access to a mapped view of a file mapping object.
2703 | ///
2704 | ExecuteWriteCopy = 0x80,
2705 | ///
2706 | /// Disables all access to the committed region of pages.
2707 | /// An attempt to read from, write to, or execute the committed region results in an access violation.
2708 | ///
2709 | NoAccess = 0x01,
2710 | ///
2711 | /// Enables read-only access to the committed region of pages.
2712 | ///
2713 | ReadOnly = 0x02,
2714 | ///
2715 | /// Enables read-only or read/write access to the committed region of pages.
2716 | ///
2717 | ReadWrite = 0x04,
2718 | ///
2719 | /// Enables read-only or copy-on-write access to a mapped view of a file mapping object.
2720 | ///
2721 | WriteCopy = 0x08,
2722 | ///
2723 | /// Pages in the region become guard pages.
2724 | ///
2725 | Guard = 0x100,
2726 | ///
2727 | /// Sets all pages to be non-cachable.
2728 | ///
2729 | NoCache = 0x200,
2730 | ///
2731 | /// Sets all pages to be write-combined.
2732 | ///
2733 | WriteCombine = 0x400
2734 | }
2735 |
2736 | ///
2737 | /// The type of free operation.
2738 | ///
2739 | public enum FreeOption
2740 | {
2741 | ///
2742 | /// Decommits the specified region of committed pages.
2743 | ///
2744 | Decommit = 0x4000,
2745 | ///
2746 | /// Releases the specified region of pages.
2747 | ///
2748 | Release = 0x8000,
2749 | }
2750 |
2751 | ///
2752 | /// The type of memory allocation.
2753 | ///
2754 | [Flags]
2755 | public enum AllocationOption : uint
2756 | {
2757 | ///
2758 | /// Allocates memory charges (from the overall size of memory and the paging files on disk) for the specified reserved memory pages.
2759 | ///
2760 | Commit = 0x1000,
2761 | ///
2762 | /// Reserves a range of the process's virtual address space without allocating any actual physical storage in memory or in the paging file on disk.
2763 | ///
2764 | Reserve = 0x2000,
2765 | ///
2766 | /// Indicates that data in the memory range specified by lpAddress and nSize is no longer of interest.
2767 | ///
2768 | Reset = 0x80000,
2769 | ///
2770 | /// should only be called on an address range to which was successfully applied earlier.
2771 | /// It indicates that the data in the specified memory range specified by lpAddress and nSize is of interest to the caller and attempts to reverse the effects of .
2772 | ///
2773 | ResetUndo = 0x1000000,
2774 | ///
2775 | /// Allocates memory using large page support.
2776 | ///
2777 | LargePages = 0x20000000,
2778 | ///
2779 | /// Reserves an address range that can be used to map Address Windowing Extensions (AWE) pages.
2780 | ///
2781 | Physical = 0x400000,
2782 | ///
2783 | /// Allocates memory at the highest possible address.
2784 | ///
2785 | TopDown = 0x100000,
2786 |
2787 | }
2788 |
2789 | ///
2790 | /// Process access rights.
2791 | ///
2792 | [Flags]
2793 | public enum ProcessAccess
2794 | {
2795 | All = 0x1F0FFF,
2796 | CreateProcess = 0x80,
2797 | CreateThread = 0x02,
2798 | DuplicateHandle = 0x40,
2799 | QueryInformation = 0x400,
2800 | QueryLimitedInformation = 0x1000,
2801 | SetInformation = 0x200,
2802 | SetQuota = 0x100,
2803 | SuspendResume = 0x800,
2804 | Terminate = 0x01,
2805 | VirtualMemoryOperation = 0x08,
2806 | VirtualMemoryRead = 0x10,
2807 | VirtualMemoryWrite = 0x20,
2808 | Synchronize = 0x100000
2809 | }
2810 |
2811 | ///
2812 | /// The type of pages in the region.
2813 | ///
2814 | public enum MemoryType : uint
2815 | {
2816 | ///
2817 | /// Indicates that the memory pages within the region are mapped into the view of an image section.
2818 | ///
2819 | Image = 0x1000000,
2820 | ///
2821 | /// Indicates that the memory pages within the region are mapped into the view of a section.
2822 | ///
2823 | Mapped = 0x40000,
2824 | ///
2825 | /// Indicates that the memory pages within the region are private (that is, not shared by other processes).
2826 | ///
2827 | Private = 0x20000
2828 | }
2829 |
2830 |
2831 | public enum ModuleFilter
2832 | {
2833 | LIST_MODULES_DEFAULT = 0x00,
2834 | LIST_MODULES_32BIT = 0x01,
2835 | LIST_MODULES_64BIT = 0x02,
2836 | LIST_MODULES_ALL = 0x03
2837 | }
2838 |
2839 | [Flags]
2840 | public enum ThreadCreationFlags
2841 | {
2842 | None = 0,
2843 | CREATE_SUSPENDED = 0x00000004,
2844 | STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000
2845 | }
2846 |
2847 | public enum WaitObjectResult : uint
2848 | {
2849 | WAIT_OBJECT_0 = 0x00000000,
2850 | WAIT_TIMEOUT = 0x00000102,
2851 | WAIT_FAILED = 0xFFFFFFFF
2852 | }
2853 |
2854 | [StructLayout(LayoutKind.Sequential, Pack = 2)]
2855 | public sealed class SysInfo
2856 | {
2857 | private readonly uint OemId;
2858 | public ProcessorArchitecture ProcessorType => (ProcessorArchitecture)(OemId >> 16);
2859 | public ushort Reserved => (ushort)(OemId & 0xFFFF);
2860 |
2861 | public readonly int PageSize;
2862 |
2863 | public readonly IntPtr MinimumApplicationAddress;
2864 |
2865 | public readonly IntPtr MaximumApplicationAddress;
2866 |
2867 | public readonly IntPtr ActiveProcessorMask;
2868 |
2869 | public readonly int NumberOfProcessors;
2870 |
2871 | public readonly ProcessorType OrgProcessorType;
2872 |
2873 | public readonly int AllocationGranularity;
2874 |
2875 | public readonly short ProcessorLevel;
2876 |
2877 | public readonly short ProcessorRevision;
2878 | }
2879 |
2880 | public enum ProcessorArchitecture : ushort
2881 | {
2882 | PROCESSOR_ARCHITECTURE_AMD64 = 9,
2883 | PROCESSOR_ARCHITECTURE_ARM = 5,
2884 | PROCESSOR_ARCHITECTURE_ARM64 = 12,
2885 | PROCESSOR_ARCHITECTURE_IA64 = 6,
2886 | PROCESSOR_ARCHITECTURE_INTEL = 0,
2887 | PROCESSOR_ARCHITECTURE_UNKNOWN = 0xFFFF
2888 | }
2889 |
2890 | public enum ProcessorType : uint
2891 | {
2892 | PROCESSOR_INTEL_386 = 386,
2893 | PROCESSOR_INTEL_486 = 486,
2894 | PROCESSOR_INTEL_PENTIUM = 586,
2895 | PROCESSOR_INTEL_IA64 = 2200,
2896 | PROCESSOR_AMD_X8664 = 8664,
2897 | }
2898 |
2899 | }
2900 | }
2901 |
2902 | }
2903 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ProcessPlugin
2 | A .NET Framework project for the System.Diagnostics.Process class enhancement.
3 |
4 | This repo only have a single file,hence there is no need to release any boring binary file with your project.
5 |
6 | ## Requirements
7 | * Windows Vista or later;
8 | * Intel CPU;
9 | * C# 7.3
10 | * .NET Frameworks 4.5;
11 |
12 | ## Build Options
13 | * Choose 'Any CPU' platform;
14 | * Enable 'Allow unsafe code';
15 | * Disable 'Prefer 32 bit'
16 |
17 | ## Features
18 |
19 | `using System.Diagnostics.ProcessExtensions;`
20 |
21 | ### Process Main Window
22 |
23 | ```
24 | System.Diagnostics.Process proc = ProcessPlugin.GetProcessByWindow("main window title");
25 |
26 | var plugin = new ProcessPlugin(proc);
27 |
28 | //Main window class name
29 | string wcn = plugin.MainWindowClassName;
30 | ```
31 | ### Process Memory
32 |
33 | ```
34 | byte result = plugin.ReadData(IntPtr.Zero);
35 |
36 | plugin.WriteData(IntPtr.Zero, 0, 1, 2, 3);
37 |
38 | //returns the address of specified bytes in process memory.
39 | IntPtr codeAddress = plugin.ScanBytes(new byte[] { 1, 2, 3 });
40 |
41 | // allocated 1kb memory.
42 | IntPtr address1 = plugin.AllocatedMemories.Allocate(1024);
43 |
44 | // allocated 2kb memory, whose address is near the 'IntPtr.Zero'.
45 | IntPtr address2 = plugin.AllocatedMemories.Allocate(IntPtr.Zero,2048);
46 |
47 | plugin.AllocatedMemories.Free(address1);
48 |
49 | //free address2.
50 | plugin.AllocatedMemories.FreeAt(0);
51 | ```
52 | **remark** : `ProcessPlugin.ScanBytes` now supports wildcards, see detail: https://github.com/differentrain/YYProject.BytesSearch
53 |
54 | ### Process module
55 |
56 | ```
57 | //Both 32 bit and 64 bit module can be found.
58 | ProcessModuleAlter module = plugin.GetModuleByName("module name");
59 |
60 | var xxHash32 = module.GetHashCode();
61 | ```
62 |
63 |
64 | ### Remote Calling
65 |
66 | ` plugin.CallRemoteFunction(IntPtr.Zero);`
67 |
68 | ### Advanced Features
69 |
70 | ```
71 | plugin.Advanced.Enabled = true;
72 |
73 | IntPtr func = plugin.Advanced.GetFunctionAddress("kernel32", "LoadLibraryA");
74 |
75 | //if it's mono
76 | if (plugin.Advanced.MonoSupported)
77 | {
78 | var asm = plugin.Advanced.GetAssemblyCSharp();
79 |
80 | //Static fields start address.
81 | IntPtr sfAddress = plugin.Advanced.GetStaticFields(asm, "namespace", "class");
82 |
83 | IntPtr mAddress = plugin.Advanced.GetMethodAddress(asm, "namespace", "class", "method name");
84 |
85 | IntPtr pgAddress = plugin.Advanced.GetPropertyGetterAddress(asm, "namespace", "class", "property name");
86 |
87 | IntPtr psAddress = plugin.Advanced.GetPropertySetterAddress(asm, "namespace", "class", "property name");
88 | }
89 | ```
90 |
--------------------------------------------------------------------------------