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.
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace WhiteMagic.Execution;
|
||||
|
||||
/// <summary>
|
||||
/// Direct native-to-managed delegate calls for the in-process scenario.
|
||||
/// This is the third execution tier: no remote thread is created; the call runs
|
||||
/// synchronously on the current thread.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This class assumes the WhiteMagic consumer has already arranged to run inside the
|
||||
/// target process. Bootstrapping the managed loader (e.g., via a CLR host or native
|
||||
/// shim) that places WhiteMagic into a foreign process is a separate follow-up change
|
||||
/// and is not implemented here.</para>
|
||||
/// </remarks>
|
||||
public sealed class InProcessInvoker
|
||||
{
|
||||
private readonly MemoryBase _memory;
|
||||
|
||||
/// <summary>Creates an invoker bound to the supplied memory reader.</summary>
|
||||
public InProcessInvoker(MemoryBase memory)
|
||||
{
|
||||
_memory = memory ?? throw new ArgumentNullException(nameof(memory));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a managed delegate of type <typeparamref name="TDelegate"/> that calls
|
||||
/// the native function at <paramref name="address"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDelegate">A delegate type whose signature matches the native function.</typeparam>
|
||||
public TDelegate CreateFunction<TDelegate>(IntPtr address)
|
||||
where TDelegate : Delegate
|
||||
{
|
||||
if (address == IntPtr.Zero)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Function address cannot be zero.", nameof(address));
|
||||
}
|
||||
|
||||
return Marshal.GetDelegateForFunctionPointer<TDelegate>(address);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the vtable pointer stored at the start of an object in memory.
|
||||
/// </summary>
|
||||
/// <param name="objectAddress">The address of the object instance.</param>
|
||||
/// <returns>The address of the vtable.</returns>
|
||||
public IntPtr ReadVTable(IntPtr objectAddress)
|
||||
{
|
||||
return _memory.Read<IntPtr>(objectAddress);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a function pointer from a vtable by index.
|
||||
/// </summary>
|
||||
/// <param name="vTableAddress">The address of the vtable.</param>
|
||||
/// <param name="methodIndex">The zero-based index of the method slot.</param>
|
||||
/// <returns>The address in the specified vtable slot.</returns>
|
||||
public IntPtr ReadVTableFunction(IntPtr vTableAddress, int methodIndex)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(methodIndex);
|
||||
|
||||
int pointerSize = _memory.Is64Bit ? 8 : 4;
|
||||
IntPtr slotAddress = vTableAddress + (methodIndex * pointerSize);
|
||||
return _memory.Read<IntPtr>(slotAddress);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience helper that reads an object's vtable and returns the function
|
||||
/// address at the requested method index.
|
||||
/// </summary>
|
||||
public IntPtr GetObjectVTableFunction(IntPtr objectAddress, int methodIndex)
|
||||
{
|
||||
IntPtr vTable = ReadVTable(objectAddress);
|
||||
return ReadVTableFunction(vTable, methodIndex);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user