diff --git a/WhiteMagicTest/Execution/RemoteThreadExecutorTests.cs b/WhiteMagicTest/Execution/RemoteThreadExecutorTests.cs index 0f456e7..cb462b5 100644 --- a/WhiteMagicTest/Execution/RemoteThreadExecutorTests.cs +++ b/WhiteMagicTest/Execution/RemoteThreadExecutorTests.cs @@ -56,6 +56,15 @@ public sealed class RemoteThreadExecutorTests // ret private static readonly byte[] PointSumPayload = [0x8B, 0x01, 0x03, 0x41, 0x04, 0xC3]; + // Measures the callee's entry stack alignment without faulting. + // mov eax, esp + // add eax, 8 + // and eax, 0x0F + // ret + // Returns (rsp + 8) & 15, which is 0 iff callee entry rsp ≡ 8 (mod 16) — the + // Microsoft x64 ABI guarantee the stub must deliver. + private static readonly byte[] AlignProbePayload = [0x89, 0xE0, 0x83, 0xC0, 0x08, 0x83, 0xE0, 0x0F, 0xC3]; + [StructLayout(LayoutKind.Sequential)] private struct Point { @@ -87,6 +96,20 @@ public sealed class RemoteThreadExecutorTests Assert.Equal(15, result); } + [Fact] + public void Execute_delivers_16byte_aligned_stack_to_callee() + { + if (!Environment.Is64BitProcess) + { + return; + } + + // Stub entry rsp ≡ 8 → sub rsp, K (K ≡ 8) → rsp ≡ 0 → call → callee entry rsp ≡ 8. + // So (rsp + 8) & 15 == 0 when the frame math is right; a bad K (e.g. 0x20) yields 8. + int misalign = RunPayload(AlignProbePayload, CallConvention.Cdecl); + Assert.Equal(0, misalign); + } + [Fact] public void Execute_marshals_string_as_utf8_pointer() {