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,77 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using WhiteMagic;
|
||||
using WhiteMagic.Execution;
|
||||
using Xunit;
|
||||
|
||||
namespace WhiteMagicTest.Execution;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for <see cref="InProcessInvoker"/> operating in-process.
|
||||
/// </summary>
|
||||
public class InProcessInvokerTests
|
||||
{
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate int AddDelegate(int a, int b);
|
||||
|
||||
private static int NativeAdd(int a, int b) => a + b;
|
||||
|
||||
[Fact]
|
||||
public void CreateFunction_calls_known_in_process_function()
|
||||
{
|
||||
using var reader = new InProcessReader();
|
||||
var invoker = new InProcessInvoker(reader);
|
||||
|
||||
var native = new AddDelegate(NativeAdd);
|
||||
IntPtr functionPointer = Marshal.GetFunctionPointerForDelegate(native);
|
||||
|
||||
AddDelegate callable = invoker.CreateFunction<AddDelegate>(functionPointer);
|
||||
int result = callable(5, 7);
|
||||
|
||||
Assert.Equal(12, result);
|
||||
GC.KeepAlive(native);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateFunction_rejects_zero_address()
|
||||
{
|
||||
using var reader = new InProcessReader();
|
||||
var invoker = new InProcessInvoker(reader);
|
||||
|
||||
ArgumentException ex = Assert.Throws<ArgumentException>(() => invoker.CreateFunction<AddDelegate>(IntPtr.Zero));
|
||||
Assert.Equal("address", ex.ParamName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Vtable_helper_reads_function_pointer_slot()
|
||||
{
|
||||
using var reader = new InProcessReader();
|
||||
var invoker = new InProcessInvoker(reader);
|
||||
|
||||
// Build a tiny fake vtable in a pinned buffer: two slots holding known pointers.
|
||||
IntPtr slot0 = Marshal.GetFunctionPointerForDelegate(new AddDelegate(NativeAdd));
|
||||
IntPtr slot1 = new IntPtr(0x12345678);
|
||||
|
||||
IntPtr[] vtable;
|
||||
if (reader.Is64Bit)
|
||||
{
|
||||
vtable = [slot0, slot1];
|
||||
}
|
||||
else
|
||||
{
|
||||
vtable = [slot0, slot1];
|
||||
}
|
||||
|
||||
GCHandle pin = GCHandle.Alloc(vtable, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
IntPtr vTableAddress = pin.AddrOfPinnedObject();
|
||||
Assert.Equal(slot0, invoker.ReadVTableFunction(vTableAddress, 0));
|
||||
Assert.Equal(slot1, invoker.ReadVTableFunction(vTableAddress, 1));
|
||||
}
|
||||
finally
|
||||
{
|
||||
pin.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user