using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; using static Dalamud.Injector.NativeFunctions; namespace Dalamud.Injector { /// /// Pin an arbitrary string to a remote process. /// internal class RemotePinnedData : IDisposable { private readonly Process process; private readonly byte[] data; private readonly IntPtr allocAddr; /// /// Initializes a new instance of the class. /// /// Process to write in. /// Data to write. public unsafe RemotePinnedData(Process process, byte[] data) { this.process = process; this.data = data; this.allocAddr = VirtualAllocEx( this.process.Handle, IntPtr.Zero, this.data.Length, AllocationType.Commit, MemoryProtection.ReadWrite); if (this.allocAddr == IntPtr.Zero || Marshal.GetLastWin32Error() != 0) { throw new Exception("Error allocating memory"); } var result = WriteProcessMemory( this.process.Handle, this.allocAddr, this.data, this.data.Length, out _); if (!result || Marshal.GetLastWin32Error() != 0) { throw new Exception("Error writing memory"); } } /// /// Gets the address of the pinned data. /// public IntPtr Address => this.allocAddr; /// public void Dispose() { if (this.allocAddr == IntPtr.Zero) { return; } var result = VirtualFreeEx( this.process.Handle, this.allocAddr, 0, AllocationType.Release); if (!result || Marshal.GetLastWin32Error() != 0) { throw new Exception("Error freeing memory"); } } } }