From 77736698ab6ae17297dd82da17616b98fedbf93a Mon Sep 17 00:00:00 2001 From: Kevin Bataille Date: Wed, 22 Jul 2026 01:13:45 +0200 Subject: [PATCH] Add runtime x64 stack-alignment regression test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A non-faulting probe payload returns (rsp+8)&15 from the callee, which is 0 only when the stub delivers callee entry rsp ≡ 8 (mod 16) per the Microsoft x64 ABI. Proves the stub frame alignment end-to-end through CreateRemoteThread without risking a #GP that would crash the in-process test host. Verified to fail against the old fixed-0x20 frame. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Execution/RemoteThreadExecutorTests.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) 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() {