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:
kbe
2026-07-22 02:49:51 +02:00
co-authored by Claude Opus 4.8
parent eda467bc46
commit 678cb00895
7 changed files with 438 additions and 2 deletions
@@ -35,6 +35,32 @@ public sealed class RemoteThreadExecutorTests
0xC3
];
// Five-arg callee that also executes an alignment-sensitive SSE instruction, proving
// the stub delivers a 16-byte-aligned stack the CPU actually accepts (movaps #GPs on a
// misaligned address) alongside correct register+stack argument placement.
// sub rsp, 24 ; entry rsp ≡ 8 (mod 16) -> rsp ≡ 0 (16-aligned), 16-byte
// ; scratch at [rsp..rsp+16) that clears the return slot ([rsp+24])
// movaps [rsp], xmm0 ; aligned 16-byte store — faults unless rsp is 16-aligned
// add rsp, 24 ; restore
// mov eax, ecx
// add eax, edx
// add eax, r8d
// add eax, r9d
// add eax, [rsp+0x28] ; 5th arg above the shadow space
// ret
private static readonly byte[] SseAlignedSumPayload =
[
0x48, 0x83, 0xEC, 0x18,
0x0F, 0x29, 0x04, 0x24,
0x48, 0x83, 0xC4, 0x18,
0x89, 0xC8,
0x01, 0xD0,
0x44, 0x01, 0xC0,
0x44, 0x01, 0xC8,
0x03, 0x84, 0x24, 0x28, 0x00, 0x00, 0x00,
0xC3
];
// xor eax, eax
// cmp byte ptr [rcx+rax], 0
// je done
@@ -110,6 +136,21 @@ public sealed class RemoteThreadExecutorTests
Assert.Equal(0, misalign);
}
[Fact]
public void Execute_runs_sse_callee_with_five_args()
{
if (!Environment.Is64BitProcess)
{
return;
}
// Correct result (150) requires BOTH the 5th arg reaching [rsp+0x28] AND the
// aligned movaps not faulting. A broken frame size/alignment either mis-sums or
// #GPs in the callee.
int result = RunPayload(SseAlignedSumPayload, CallConvention.Cdecl, 10, 20, 30, 40, 50);
Assert.Equal(150, result);
}
[Fact]
public void Execute_marshals_string_as_utf8_pointer()
{