Implement RemoteModule/RemoteFunction and prove x64 ABI at runtime
Task 7.2: export resolution + module/function facade. - PeHeaderParser.GetExportAddress walks the PE32/PE32+ export directory and follows export forwarders (e.g. kernel32!HeapAlloc -> NTDLL.RtlAllocateHeap) into other loaded modules; ordinal and unresolvable API-set forwarders throw NotSupportedException. - RemoteModule resolves a module base via Process.Modules (name match tolerant of .dll/case); RemoteFunction executes via RemoteThreadExecutor by default, exposes Address for pump routing and CreateDelegate<T> for in-process. - Magic gains a string indexer: magic["user32"]["MessageBoxA"]. Task 3.8: add the missing live-execution ABI test - an SSE callee whose aligned movaps #GPs unless the stub delivers a 16-byte-aligned stack, combined with a 5th stack argument. Runtime-proves shadow space, alignment, and arg placement. Tests: 214 passing, 4 skipped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
using System.Threading.Tasks;
|
||||
using WhiteMagic.Assembly;
|
||||
using WhiteMagic.Execution;
|
||||
|
||||
namespace WhiteMagic;
|
||||
|
||||
/// <summary>
|
||||
/// An exported function resolved in the target process, obtained via
|
||||
/// <c>magic["module"]["function"]</c>. Executes through one of the session's execution
|
||||
/// strategies.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default <see cref="Execute{T}"/> path uses the always-available
|
||||
/// <see cref="RemoteThreadExecutor"/> (<c>CreateRemoteThread</c>), which is safe for
|
||||
/// thread-agnostic exports. For a call that touches single-threaded target state, obtain
|
||||
/// the <see cref="Address"/> and route it through a <see cref="MainThreadPump"/>, or use
|
||||
/// <see cref="CreateDelegate{TDelegate}"/> when running in-process.
|
||||
/// </remarks>
|
||||
public sealed class RemoteFunction
|
||||
{
|
||||
private readonly Magic _magic;
|
||||
|
||||
/// <summary>The export name this function was resolved from.</summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>The absolute address of the function in the target process.</summary>
|
||||
public IntPtr Address { get; }
|
||||
|
||||
internal RemoteFunction(Magic magic, string name, IntPtr address)
|
||||
{
|
||||
_magic = magic;
|
||||
Name = name;
|
||||
Address = address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls the function via a remote thread and returns its result cast to
|
||||
/// <typeparamref name="T"/>.
|
||||
/// </summary>
|
||||
/// <param name="convention">The calling convention (ignored on x64 targets).</param>
|
||||
/// <param name="args">Arguments to pass; primitives, pointers, enums, strings and
|
||||
/// structs are supported.</param>
|
||||
public T Execute<T>(CallConvention convention, params object?[] args)
|
||||
{
|
||||
return _magic.RemoteThread.Execute<T>(Address, convention, args);
|
||||
}
|
||||
|
||||
/// <summary>Asynchronous variant of <see cref="Execute{T}"/>.</summary>
|
||||
public Task<T> ExecuteAsync<T>(CallConvention convention, params object?[] args)
|
||||
{
|
||||
return _magic.RemoteThread.ExecuteAsync<T>(Address, convention, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a managed delegate bound to this function for the in-process scenario.
|
||||
/// Only valid when the session was opened in-process.
|
||||
/// </summary>
|
||||
public TDelegate CreateDelegate<TDelegate>() where TDelegate : Delegate
|
||||
{
|
||||
return new InProcessInvoker(_magic.Memory).CreateFunction<TDelegate>(Address);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user