using System.Runtime.InteropServices; using WhiteMagic; using WhiteMagic.Discovery; using WhiteMagicTest; namespace WhiteMagicTest.Discovery; /// /// Tests for . /// public class PatternScannerTests { private static InProcessReader CreateReader() { return new InProcessReader(); } [Fact] public void Find_exact_pattern_returns_correct_address() { using var reader = CreateReader(); // Create a buffer with known bytes byte[] buffer = new byte[256]; buffer[10] = 0xDE; buffer[11] = 0xAD; buffer[12] = 0xBE; buffer[13] = 0xEF; GCHandle pin = GCHandle.Alloc(buffer, GCHandleType.Pinned); try { IntPtr addr = pin.AddrOfPinnedObject(); IntPtr end = addr + buffer.Length; // Search for the exact pattern byte[] pattern = { 0xDE, 0xAD, 0xBE, 0xEF }; IntPtr found = PatternScanner.Find(reader, pattern, null, addr, end); Assert.Equal(addr + 10, found); } finally { pin.Free(); } } [Fact] public void Find_with_wildcard_mask_ignores_wildcard_bytes() { using var reader = CreateReader(); // Create a buffer with known bytes byte[] buffer = new byte[256]; buffer[20] = 0x12; buffer[21] = 0x34; // This byte is wildcard buffer[22] = 0x56; buffer[23] = 0x78; GCHandle pin = GCHandle.Alloc(buffer, GCHandleType.Pinned); try { IntPtr addr = pin.AddrOfPinnedObject(); IntPtr end = addr + buffer.Length; // Search with wildcard mask (x = match, ? = wildcard) byte[] pattern = { 0x12, 0x00, 0x56, 0x78 }; string mask = "x?xx"; // Second byte is wildcard IntPtr found = PatternScanner.Find(reader, pattern, mask, addr, end); Assert.Equal(addr + 20, found); } finally { pin.Free(); } } [Fact] public void Find_pattern_not_found_returns_zero() { using var reader = CreateReader(); // Create a buffer without the target pattern byte[] buffer = new byte[256]; for (int i = 0; i < buffer.Length; i++) buffer[i] = 0xAA; GCHandle pin = GCHandle.Alloc(buffer, GCHandleType.Pinned); try { IntPtr addr = pin.AddrOfPinnedObject(); IntPtr end = addr + buffer.Length; // Search for pattern that doesn't exist byte[] pattern = { 0xDE, 0xAD, 0xBE, 0xEF }; IntPtr found = PatternScanner.Find(reader, pattern, null, addr, end); Assert.Equal(IntPtr.Zero, found); } finally { pin.Free(); } } [Fact] public void Find_empty_pattern_throws() { using var reader = CreateReader(); byte[] pattern = Array.Empty(); var ex = Assert.Throws(() => PatternScanner.Find(reader, pattern, null, IntPtr.Zero, (IntPtr)1000)); Assert.Contains("Pattern cannot be empty", ex.Message); } [Fact] public void Find_mask_length_mismatch_throws() { using var reader = CreateReader(); byte[] pattern = { 0xDE, 0xAD, 0xBE, 0xEF }; string mask = "xxx"; // Wrong length var ex = Assert.Throws(() => PatternScanner.Find(reader, pattern, mask, IntPtr.Zero, (IntPtr)1000)); Assert.Contains("Mask length", ex.Message); } [Fact] public void Find_invalid_mask_char_throws() { using var reader = CreateReader(); byte[] pattern = { 0xDE, 0xAD, 0xBE, 0xEF }; string mask = "axxx"; // 'a' is invalid var ex = Assert.Throws(() => PatternScanner.Find(reader, pattern, mask, IntPtr.Zero, (IntPtr)1000)); } [Fact] public void Find_null_mask_treats_all_as_exact() { using var reader = CreateReader(); byte[] buffer = new byte[256]; buffer[50] = 0xAB; buffer[51] = 0xCD; GCHandle pin = GCHandle.Alloc(buffer, GCHandleType.Pinned); try { IntPtr addr = pin.AddrOfPinnedObject(); IntPtr end = addr + buffer.Length; // Null mask should behave like "xx" (exact match) byte[] pattern = { 0xAB, 0xCD }; IntPtr found = PatternScanner.Find(reader, pattern, null, addr, end); Assert.Equal(addr + 50, found); } finally { pin.Free(); } } [Fact] public void FindInModule_scans_current_process_module() { using var reader = CreateReader(); // Get the current process's main module var currentProcess = System.Diagnostics.Process.GetCurrentProcess(); var mainModule = currentProcess.MainModule; Assert.NotNull(mainModule); // MZ header is always at the start of the main module byte[] pattern = { 0x4D, 0x5A }; IntPtr found = PatternScanner.FindInModule(reader, pattern, null, mainModule); Assert.Equal(mainModule.BaseAddress, found); } }