task 2.9: implement InProcessReader with tests Add InProcessReader: direct pointer dereference (unsafe) against own process via Buffer.MemoryCopy. Implements MemoryBase API for in-process scenarios (injected managed DLL). 8 tests: ImageBase, Read/Write int, ReadBytes, WriteBytes, Read/Write struct, dispose lifecycle. All passing: 52 tests (7 Native + 12 MarshalCache + 11 MemoryBase + 8 String + 6 Addressing + 8 InProcessReader).
75 lines
2.0 KiB
C#
75 lines
2.0 KiB
C#
using System.Diagnostics;
|
|
using System.Runtime.InteropServices;
|
|
using WhiteMagic.Native;
|
|
|
|
namespace WhiteMagic;
|
|
|
|
/// <summary>
|
|
/// In-process memory reader that accesses the owning process's memory through
|
|
/// direct pointer dereference (<c>unsafe</c>). Use this reader from within a
|
|
/// managed DLL injected into the target process.
|
|
/// </summary>
|
|
public sealed class InProcessReader : MemoryBase
|
|
{
|
|
private readonly SafeMemoryHandle _handle;
|
|
private readonly IntPtr _imageBase;
|
|
private bool _disposed;
|
|
|
|
/// <summary>
|
|
/// Creates an in-process reader for the current process.
|
|
/// </summary>
|
|
public InProcessReader()
|
|
{
|
|
Process current = Process.GetCurrentProcess();
|
|
_handle = NativeMethods.OpenProcess(
|
|
ProcessAccess.VmRead | ProcessAccess.VmWrite | ProcessAccess.VmOperation | ProcessAccess.QueryInformation,
|
|
false,
|
|
current.Id);
|
|
|
|
_imageBase = current.MainModule?.BaseAddress ?? IntPtr.Zero;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override IntPtr ImageBase => _imageBase;
|
|
|
|
/// <inheritdoc />
|
|
public override SafeMemoryHandle Handle => _handle;
|
|
|
|
/// <inheritdoc />
|
|
public override unsafe byte[] ReadBytes(IntPtr address, int count, bool isRelative = false)
|
|
{
|
|
if (isRelative)
|
|
address = GetAbsolute(address);
|
|
|
|
byte[] buffer = new byte[count];
|
|
fixed (byte* ptr = buffer)
|
|
{
|
|
Buffer.MemoryCopy((void*)address, ptr, count, count);
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override unsafe int WriteBytes(IntPtr address, ReadOnlySpan<byte> bytes, bool isRelative = false)
|
|
{
|
|
if (isRelative)
|
|
address = GetAbsolute(address);
|
|
|
|
fixed (byte* ptr = bytes)
|
|
{
|
|
Buffer.MemoryCopy(ptr, (void*)address, bytes.Length, bytes.Length);
|
|
}
|
|
return bytes.Length;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override void Dispose()
|
|
{
|
|
if (!_disposed)
|
|
{
|
|
_disposed = true;
|
|
_handle.Dispose();
|
|
}
|
|
}
|
|
}
|