using System.ComponentModel; using System.Runtime.InteropServices; using WhiteMagic.Memory; using WhiteMagic.Native; namespace WhiteMagic.Injection; /// /// Injects raw machine code into a process's memory. /// public static class CodeInjector { /// /// Injects code at a specific address. /// /// The memory accessor. /// The target address. /// The machine code bytes to write. /// The address the code was written to (same as ). /// is empty. /// Write fails. public static IntPtr InjectAtAddress(MemoryBase memory, IntPtr address, byte[] code) { ArgumentNullException.ThrowIfNull(memory); ArgumentNullException.ThrowIfNull(code); if (code.Length == 0) throw new ArgumentException("Code cannot be empty.", nameof(code)); if (address == IntPtr.Zero) throw new ArgumentException("Address cannot be zero.", nameof(address)); // Write the code to the target address int written = memory.WriteBytes(address, code); if (written != code.Length) { int error = Marshal.GetLastPInvokeError(); throw new Win32Exception(error, $"WriteProcessMemory failed at {address} (wrote {written} of {code.Length} bytes)."); } return address; } /// /// Allocates executable memory and injects code into it. /// /// The memory accessor. /// The machine code bytes to inject. /// /// The memory protection. Defaults to . /// /// /// The base address of the allocated memory containing the code. /// The caller is responsible for freeing this memory (e.g., via ). /// /// is empty. /// Allocation or write fails. public static AllocatedMemory Inject( MemoryBase memory, byte[] code, MemoryProtectionType protection = MemoryProtectionType.ExecuteReadWrite) { ArgumentNullException.ThrowIfNull(memory); ArgumentNullException.ThrowIfNull(code); if (code.Length == 0) throw new ArgumentException("Code cannot be empty.", nameof(code)); // Allocate memory with the specified protection var allocated = new AllocatedMemory(memory, code.Length, protection); // Write the code to the allocated memory int written = memory.WriteBytes(allocated.BaseAddress, code); if (written != code.Length) { int error = Marshal.GetLastPInvokeError(); allocated.Dispose(); throw new Win32Exception(error, $"WriteProcessMemory failed (wrote {written} of {code.Length} bytes)."); } return allocated; } }