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