Files
kbe 3f0bea6bd4 Implement core diagnostic memory layer, execution helpers, and high-level facade slices
Implemented:
- Core: UTF-16 ReadString boundary/alignment fix, target bitness and process id on MemoryBase
- function interception: PatchManager, DetourManager, InstructionAnalyzer, MainThreadDispatcher
- Execution: BackgroundTaskExecutor, InProcessInvoker
- High-level: Magic facade, RemotePointer, async wrappers
- Discovery/external code loading/Window groundwork (PEB/TEB, pattern scanning, raw allocations, DLL external code loading, window/input)

Tests: 180 passing, 4 integration/interactive tests skipped.
2026-07-21 23:43:14 +02:00

86 lines
3.3 KiB
C#

using System.ComponentModel;
using System.Runtime.InteropServices;
using WhiteMagic.Memory;
using WhiteMagic.Native;
namespace WhiteMagic.Injection;
/// <summary>
/// Injects raw machine code into a process's memory.
/// </summary>
public static class CodeInjector
{
/// <summary>
/// Injects code at a specific address.
/// </summary>
/// <param name="memory">The memory accessor.</param>
/// <param name="address">The target address.</param>
/// <param name="code">The machine code bytes to write.</param>
/// <returns>The address the code was written to (same as <paramref name="address"/>).</returns>
/// <exception cref="ArgumentException"><paramref name="code"/> is empty.</exception>
/// <exception cref="Win32Exception">Write fails.</exception>
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;
}
/// <summary>
/// Allocates executable memory and injects code into it.
/// </summary>
/// <param name="memory">The memory accessor.</param>
/// <param name="code">The machine code bytes to inject.</param>
/// <param name="protection">
/// The memory protection. Defaults to <see cref="MemoryProtectionType.ExecuteReadWrite"/>.
/// </param>
/// <returns>
/// The base address of the allocated memory containing the code.
/// The caller is responsible for freeing this memory (e.g., via <see cref="AllocatedMemory.Dispose"/>).
/// </returns>
/// <exception cref="ArgumentException"><paramref name="code"/> is empty.</exception>
/// <exception cref="Win32Exception">Allocation or write fails.</exception>
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;
}
}