using WhiteMagic.Hooking; using Xunit; namespace WhiteMagicTest.Hooking; /// /// Tests for covering the accepted x86/x64 prologue /// shapes and rejection of opcodes outside the covered set. /// public class PrologueDecoderTests { [Theory] [InlineData(false, new byte[] { 0x55 }, 1)] // push rbp [InlineData(false, new byte[] { 0x53 }, 1)] // push rbx [InlineData(false, new byte[] { 0x8B, 0xFF }, 2)] // mov edi, edi [InlineData(false, new byte[] { 0x8B, 0xEC }, 2)] // mov ebp, esp [InlineData(false, new byte[] { 0x83, 0xEC, 0x20 }, 3)] // sub esp, 0x20 [InlineData(false, new byte[] { 0x81, 0xEC, 0x00, 0x01, 0x00, 0x00 }, 6)] // sub esp, 0x100 [InlineData(true, new byte[] { 0x48, 0x8B, 0xEC }, 3)] // mov rbp, rsp [InlineData(true, new byte[] { 0x48, 0x83, 0xEC, 0x28 }, 4)] // sub rsp, 0x28 [InlineData(true, new byte[] { 0x48, 0x81, 0xEC, 0x78, 0x56, 0x34, 0x12 }, 7)] // sub rsp, 0x12345678 public void Decodes_covered_prologue_shapes(bool is64Bit, byte[] bytes, int expectedLength) { int length = PrologueDecoder.GetInstructionLength(bytes, is64Bit); Assert.Equal(expectedLength, length); } [Theory] [InlineData(false, new byte[] { 0x83, 0x05, 0x39, 0x00, 0x00, 0x00, 0x01 })] // add [rip+0x39], 1 — wrong modrm [InlineData(false, new byte[] { 0x83, 0x3D, 0x00, 0x00, 0x00, 0x00, 0x01 })] // cmp [rip], 1 — wrong modrm [InlineData(false, new byte[] { 0x81, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 })] // add [rip], 1 — wrong modrm [InlineData(false, new byte[] { 0x0F, 0x05 })] // syscall [InlineData(false, new byte[] { 0x90, 0x90 })] // nop public void Rejects_unsafe_or_uncovered_shapes(bool is64Bit, byte[] bytes) { int length = PrologueDecoder.GetInstructionLength(bytes, is64Bit); Assert.Equal(-1, length); Assert.Throws( () => PrologueDecoder.GetWholeInstructionLength(bytes, requiredBytes: 2, is64Bit)); } }