/// <summary> /// A simple method example which demonstrates the <see cref="IMemory"/> interface. /// </summary> /// <param name="memory">This object is used to perform memory read/write/free/allocate operations.</param> /// <param name="memoryLocation">Arbitrary location in memory where this tutorial will be held.</param> private static void MemorySourceExample(IMemory memory, IntPtr memoryLocation) { // Earlier in the program; we have been writing generics to the program's memory using the 'Memory' class // implementing the IMemory interface. Well... that isn't the only stock class that implements this interface. // The implementation of `Memory` is just one of them; one that lets you read/write inside the current process. // Others you can find within Reloaded.Memory.Sources. // Well; let's look at another IMemory implementation, one that lets you read/write a DIFFERENT process. IMemory anotherProcessMemory = new ExternalMemory(Process.GetCurrentProcess()); // ExternalMemory is yet another implementation of IMemory; allowing you to read from another process. // In this case we have pointed it at the current process - now let's show this working. // Write "1337" to memory address in external process. int leet = 1337; anotherProcessMemory.Write(memoryLocation, leet); // Read "1337" written by "another process" using our IMemory implementation (Memory) that reads from current process. memory.Read(memoryLocation, out int anotherLeet); // Implementing the IMemory interface is quite easy; especially with the many tools in the <Struct> class. // Extra note: Overloads for IMemory are implemented as Extension Methods // Make sure to add `using Reloaded.Memory.Sources;` in your own projects. }
/// <summary> /// Provides the implementation of a primitive DLL injector, supporting injection into /// suspended process. /// </summary> public BasicDllInjector(Process process) { // Set the Location and Handle to the Process to be Injected. _process = process; _memory = new ExternalMemory(process); _loadLibraryAddress = _process.Is64Bit() ? x64LoadLibraryAddress : x86LoadLibraryAddress; }
/// <summary> /// The legacy implementation of Rip. /// </summary> private static void LegacyRip(LegacyRipOptions options) { // Read emulated memory. var process = new ExternalMemory(Process.GetProcessesByName(options.ProcessName)[0]); process.ReadRaw((IntPtr)options.MinRamAddress, out var ps2Memory, 0x2000000); // Parse known file list. var sizeToFileMap = JsonFile.FromFileAsSizeToFileMap(options.JsonPath); // Read PCSX2 Logs using var fileStream = new FileStream(options.LogPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); var logData = new byte[fileStream.Length]; fileStream.Read(logData); var pcsx2CrashLog = Encoding.UTF8.GetString(logData); var pcsx2CrashLogInfo = new ParsedCrashLog(pcsx2CrashLog.Replace("\r\n", "\n")); // Pattern scan for archive: // Build search string. var searchPatternBuilder = new StringBuilder($"{(options.GroupNum != -1 ? options.GroupNum.ToString("X8") : "??")} 00 00 00 "); // Note: Assuming less than 255 items! var groupItemCountBytes = pcsx2CrashLogInfo.Metadata.Select(x => x.NoOfItems).ToArray(); var itemCountPattern = Utilities.BytesToScanPattern(groupItemCountBytes); searchPatternBuilder.Append(itemCountPattern); // Scan for potential matches. var scanner = new Scanner(ps2Memory); var patterns = Utilities.FindAllPatterns(scanner, new CompiledScanPattern(searchPatternBuilder.ToString())); int archiveOffset = patterns[0].Offset; // Handle multiple matches. if (patterns.Count > 1) { // Note: Not tested. Console.WriteLine("More than 1 match for possible archive data. Trying to reconstruct header and searching for ID. (Note: This code is not yet implemented, exiting!)"); return; } // Extract match from memory. if (sizeToFileMap.TryGetValue(pcsx2CrashLogInfo.FileSize, out var fileInfoList)) { // Get user picked entry from list. var entry = RipUserSelectEntryFromList(fileInfoList); // Save file. var slice = ps2Memory.AsSpan().Slice(archiveOffset, entry.UncompressedSize); RipWriteFileToFolder(options.OutputPath, entry, slice); } else { Console.WriteLine($"No known file in JSON found. File Size from Crashlog: 0x{pcsx2CrashLogInfo.FileSize:X}"); } }
/// <summary> /// Creates a signature scanner given a process and a module (EXE/DLL) /// from which the signatures are to be found. /// </summary> /// <param name="process">The process from which</param> /// <param name="module">An individual module of the given process, which</param> public Scanner(Process process, ProcessModule module) { var externalProcess = new ExternalMemory(process); externalProcess.ReadRaw(module.BaseAddress, out var data, module.ModuleMemorySize); _data = data; _gcHandle = GCHandle.Alloc(data, GCHandleType.Pinned); _dataPtr = (byte *)_gcHandle.AddrOfPinnedObject(); }
private long _getProcAddressReturnValuePtr; /* Address of GetProcAddress' return value. */ /// <summary> /// Builds the shellcode necessary to successfully call LoadLibraryW and GetProcAddress /// inside the address space of another executable. /// </summary> /// <param name="targetProcess">Process inside which to execute.</param> public Shellcode(Process targetProcess) { Safety.WaitForModuleInitialization(targetProcess); _privateBuffer = new MemoryBufferHelper(targetProcess).CreatePrivateMemoryBuffer(4096); _assembler = new Assembler.Assembler(); _memory = new ExternalMemory(targetProcess); _circularBuffer = new CircularBuffer(4096, _memory); _targetProcess = targetProcess; // Get arch of target process. PeFile targetPeFile = new PeFile(targetProcess.Modules[0].FileName); _machineType = (MachineType)targetPeFile.ImageNtHeaders.FileHeader.Machine; // Get Kernel32 load address in target. Module kernel32Module = GetKernel32InRemoteProcess(targetProcess); Kernel32Handle = (long)kernel32Module.BaseAddress; // We need to change the module path if 32bit process; because the given path is not true, // it is being actively redirected by Windows on Windows 64 (WoW64) if (_machineType == MachineType.I386) { StringBuilder builder = new StringBuilder(256); GetSystemWow64Directory(builder, (uint)builder.Capacity); kernel32Module.ModulePath = builder.ToString() + "\\" + Path.GetFileName(kernel32Module.ModulePath); } // Parse Kernel32 loaded by target and get address of LoadLibrary & GetProcAddress. PeFile kernel32PeFile = new PeFile(kernel32Module.ModulePath); var exportedFunctions = kernel32PeFile.ExportedFunctions; _loadLibraryWOffset = GetExportedFunctionOffset(exportedFunctions, "LoadLibraryW"); _getProcAddressOffset = GetExportedFunctionOffset(exportedFunctions, "GetProcAddress"); if (_loadLibraryWOffset == 0 || _getProcAddressOffset == 0) { throw new ShellCodeGeneratorException("Failed to find GetProcAddress or LoadLibraryW methods in target process' Kernel32."); } if (_machineType == MachineType.AMD64) { BuildLoadLibraryW64(); BuildGetProcAddress64(); } else { BuildLoadLibraryW86(); BuildGetProcAddress86(); } _assembler.Dispose(); _assembler = null; }
/// <summary> /// Tests the "Add" functionality of the <see cref="MemoryBuffer"/>; including /// the return of the correct pointer and CanItemFit. /// </summary> private unsafe void MemoryBufferAddGeneric(MemoryBuffer buffer, Process process) { // Setup test. ExternalMemory externalMemory = new ExternalMemory(process); // Disable item alignment. var bufferHeader = buffer.Properties; buffer.Properties = bufferHeader; // Get remaining space, items to place. int remainingBufferSpace = bufferHeader.Remaining; int structSize = Struct.GetSize <RandomIntStruct>(); int itemsToFit = remainingBufferSpace / structSize; // Generate array of random int structs. RandomIntStruct[] randomIntStructs = new RandomIntStruct[itemsToFit]; for (int x = 0; x < itemsToFit; x++) { randomIntStructs[x] = RandomIntStruct.BuildRandomStruct(); } // Fill the buffer and verify each item as it's added. for (int x = 0; x < itemsToFit; x++) { IntPtr writeAddress = buffer.Add(ref randomIntStructs[x], false, 1); // Read back and compare. externalMemory.Read(writeAddress, out RandomIntStruct actual); Assert.Equal(randomIntStructs[x], actual); } // Compare again, running the entire array this time. IntPtr bufferStartPtr = bufferHeader.DataPointer; for (int x = 0; x < itemsToFit; x++) { IntPtr readAddress = bufferStartPtr + (x * structSize); // Read back and compare. externalMemory.Read(readAddress, out RandomIntStruct actual); Assert.Equal(randomIntStructs[x], actual); } // The array is full, calling CanItemFit should return false. Assert.False(buffer.CanItemFit(ref randomIntStructs[0])); // Likewise, calling Add should return IntPtr.Zero. var randIntStr = RandomIntStruct.BuildRandomStruct(); Assert.Equal(IntPtr.Zero, buffer.Add(ref randIntStr, false, 1)); }
/// <summary> /// A simple method example which demonstrates struct Array operations. /// </summary> /// <param name="memory">This object is used to perform memory read/write/free/allocate operations.</param> /// <param name="memoryLocation">Arbitrary location in memory where this tutorial will be held.</param> private static void StructArrayExample(IMemory memory, IntPtr memoryLocation) { // Let's load a binary file from the disk and write it to memory. const int itemCount = 40; // Number of items in struct array (known). byte[] physicsData = File.ReadAllBytes($"phys.bin"); memory.WriteRaw(memoryLocation, physicsData); // Array Read & Write from/to Memory memory.Read(memoryLocation, out AdventurePhysics[] adventurePhysicsData, itemCount); memory.Write(memoryLocation, adventurePhysicsData); // Pointer to array in memory. Provides enhanced functionality over a standard pointer. var adventurePhysics = new ArrayPtr <AdventurePhysics>((ulong)memoryLocation); adventurePhysics.Get(out AdventurePhysics value, 0); // And of course read/writes work.. // Uh? Yeah, for performance the indexer is not overwritten. float speedCap = value.HorizontalSpeedCap; // Pointer to array in memory with known length. Provides even extra functionality. (Like foreach, LINQ) var adventurePhysicsFixed = new FixedArrayPtr <AdventurePhysics>((ulong)memoryLocation, itemCount); float averageAirAcceleration = adventurePhysicsFixed.Average(physics => physics.AirAcceleration); // LINQ // All of these classes support read/writes from arbitrary memory of course... // this is where `IMemory` comes in after all. IMemory anotherProcessMemory = new ExternalMemory(Process.GetCurrentProcess()); var physicsFixedOtherProcess = new FixedArrayPtr <AdventurePhysics>((ulong)memoryLocation, itemCount, false, anotherProcessMemory); float averageAirAcceleration2 = physicsFixedOtherProcess.Average(physics => physics.AirAcceleration); // What you just witnessed was LINQ over arbitrary structs inside memory of another process. // Foreach loop over structs in other processes? Of course. float greatestInitialJump = float.MinValue; float smallestInitialJump = float.MaxValue; foreach (var physics in physicsFixedOtherProcess) { if (physics.InitialJumpSpeed > greatestInitialJump) { greatestInitialJump = physics.InitialJumpSpeed; } if (physics.InitialJumpSpeed < smallestInitialJump) { smallestInitialJump = physics.InitialJumpSpeed; } } Console.WriteLine($"LINQ Over Arbitrary Memory: {averageAirAcceleration} (Average air Acceleration in Sonic Adventure-Heroes)"); Console.WriteLine($"LINQ Over Memory in Another Process: {greatestInitialJump - smallestInitialJump} (Sonic Adventure-Heroes Physics delta between jump speeds)"); }
/// <summary> /// Initializes a new instance of the <see cref="Injector"/> class. /// </summary> /// <param name="targetProcess">Process to inject.</param> public Injector(Process targetProcess) { this.targetProcess = targetProcess; this.extMemory = new ExternalMemory(targetProcess); this.circularBuffer = new CircularBuffer(4096, this.extMemory); this.privateBuffer = new MemoryBufferHelper(targetProcess).CreatePrivateMemoryBuffer(4096); using var kernel32Module = this.GetProcessModule("KERNEL32.DLL"); var kernel32PeFile = new PeFile(kernel32Module.FileName); var kernel32Exports = kernel32PeFile.ExportedFunctions; this.SetupLoadLibrary(kernel32Module, kernel32Exports); this.SetupGetProcAddress(kernel32Module, kernel32Exports); }
/// <summary> /// Creates a signature scanner given a process and a module (EXE/DLL) /// from which the signatures are to be found. /// </summary> /// <param name="process">The process from which to scan patterns in. (Not Null)</param> /// <param name="module">An individual module of the given process, which denotes the start and end of memory region scanned.</param> public Scanner(Process process, ProcessModule module) { // Optimization if (process.Id == _currentProcess.Id) { _dataPtr = (byte *)module.BaseAddress; _dataLength = module.ModuleMemorySize; } else { var externalProcess = new ExternalMemory(process); externalProcess.ReadRaw(module.BaseAddress, out var data, module.ModuleMemorySize); _gcHandle = GCHandle.Alloc(data, GCHandleType.Pinned); _dataPtr = (byte *)_gcHandle.Value.AddrOfPinnedObject(); _dataLength = data.Length; } }
private void AllocateFree() { for (int x = 0; x < 20; x++) { // Commit var buf = _bufferHelper.Allocate(4096); var extBuf = _externalBufferHelper.Allocate(4096); // Write something to start of buffers to test allocation. var bufMem = new Sources.Memory(); var extBufMem = new ExternalMemory(_externalBufferHelper.Process); bufMem.Write(buf.MemoryAddress, 5); extBufMem.Write(extBuf.MemoryAddress, 5); // Release _bufferHelper.Free(buf.MemoryAddress); _externalBufferHelper.Free(extBuf.MemoryAddress); } }
/// <summary> /// Tests the "Add" functionality of the <see cref="MemoryBuffer"/>, with raw data; /// including the return of the correct pointer and CanItemFit. /// </summary> private unsafe void MemoryBufferAddByteArray(MemoryBuffer buffer, Process process) { // Setup test. ExternalMemory externalMemory = new ExternalMemory(process); // Disable item alignment. var bufferHeader = buffer.Properties; buffer.Properties = bufferHeader; // Get remaining space, items to place. int remainingBufferSpace = bufferHeader.Remaining; var randomByteArray = RandomByteArray.GenerateRandomByteArray(remainingBufferSpace); byte[] rawArray = randomByteArray.Array; // Fill the buffer with the whole array. buffer.Add(rawArray, 1); // Compare against the array written. IntPtr bufferStartPtr = bufferHeader.DataPointer; for (int x = 0; x < remainingBufferSpace; x++) { IntPtr readAddress = bufferStartPtr + x; // Read back and compare. externalMemory.Read(readAddress, out byte actual); Assert.Equal(rawArray[x], actual); } // The array is full, calling CanItemFit should return false. Assert.False(buffer.CanItemFit(sizeof(byte))); // Likewise, calling Add should return IntPtr.Zero. byte testByte = 55; Assert.Equal(IntPtr.Zero, buffer.Add(ref testByte, false, 1)); }
/// <summary> /// The new implementation of Rip. /// </summary> private static void NewRip(RipOptions options) { // Read emulated memory. var process = new ExternalMemory(Process.GetProcessesByName(options.ProcessName)[0]); // Parse known file list. var sizeToFileMap = JsonFile.FromFileAsSizeToFileMap(options.JsonPath); // Read PCSX2 Logs using var fileStream = new FileStream(options.LogPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); var logData = new byte[fileStream.Length]; fileStream.Read(logData); // Get size, address from log. var pcsx2Log = Encoding.UTF8.GetString(logData); var memoryDumpRegex = new Regex(@"^Addr: ([\d]*) , Size: ([\d]*), DumpFlagAddr: ([\d]*) [\n\r]+", RegexOptions.Multiline); var lastMatch = memoryDumpRegex.Matches(pcsx2Log).Last(); var archiveOffset = Convert.ToInt32(lastMatch.Groups[1].Value); var fileSize = Convert.ToInt32(lastMatch.Groups[2].Value); var dumpFlagAddr = Convert.ToInt32(lastMatch.Groups[3].Value); // Extract match from memory. if (sizeToFileMap.TryGetValue(fileSize, out var fileInfoList)) { var entry = RipUserSelectEntryFromList(fileInfoList); process.ReadRaw((IntPtr)(options.MinRamAddress + archiveOffset), out var file, entry.UncompressedSize); RipWriteFileToFolder(options.OutputPath, entry, file); } else { Console.WriteLine($"No known file in JSON found. Allowing game to advance."); } process.SafeWrite <int>((IntPtr)(options.MinRamAddress + dumpFlagAddr), 1); }
/// <summary> /// Provides the implementation of a primitive DLL injector, supporting injection into /// suspended process. /// </summary> public BasicDllInjector(Process process) { // Set the Location and Handle to the Process to be Injected. _process = process; _memory = new ExternalMemory(process); }