using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Linq; using WhiteMagic; using WhiteMagic.Windows; using WhiteMagic.Assembly; using WhiteMagic.Discovery; namespace WhiteMagic.Examples; /// /// Example 5: High-Level API /// Demonstrates RemotePointer, RemoteModule, RemoteFunction, and other high-level APIs /// public class HighLevelAPI { /// /// Target process for examples /// private static Process? TargetProcess() { var processes = Process.GetProcessesByName("notepad"); if (processes.Length > 0) return processes[0]; Console.WriteLine("No Notepad process found. Please launch Notepad first."); return null; } /// /// Example 5.1: RemotePointer (Fluent Pointer Arithmetic) /// public static void RemotePointerExample() { Console.WriteLine("=== Example 5.1: RemotePointer (Fluent Pointer Arithmetic) ==="); var process = TargetProcess(); if (process == null) return; using var magic = Magic.Open(process); IntPtr baseAddress = magic.Memory.ImageBase; // Create a RemotePointer to base address var ptr = magic[baseAddress]; Console.WriteLine($"Created RemotePointer to: 0x{baseAddress:X}"); try { // Read different offsets from the same base int offset1 = ptr.Read(0x1000); Console.WriteLine($"Read int at offset 0x1000: {offset1}"); float offset2 = ptr.Read(0x2000); Console.WriteLine($"Read float at offset 0x2000: {offset2}"); // Write to offset bool writeSuccess = ptr.Write(42, 0x3000); Console.WriteLine($"Write int to offset 0x3000: {(writeSuccess ? "Success" : "Failed")}"); // Chained pointer reads (pointer → pointer → value) IntPtr ptr1 = ptr.Read(0x4000); if (ptr1 != IntPtr.Zero) { var ptr2 = magic[ptr1]; int nestedValue = ptr2.Read(0x50); Console.WriteLine($"Nested pointer read: 0x{baseAddress:X} → 0x{ptr1:X} → {nestedValue}"); } } catch (Exception ex) { Console.WriteLine($"✗ Operation failed (offset may be invalid): {ex.Message}"); } } /// /// Example 5.2: RemoteModule (Module Enumeration) /// public static void RemoteModuleExample() { Console.WriteLine("\n=== Example 5.2: RemoteModule (Module Enumeration) ==="); var process = TargetProcess(); if (process == null) return; using var magic = Magic.Open(process); // List all loaded modules using Process.Modules Console.WriteLine("Loaded modules:"); Console.WriteLine("─────────────────────────────────────────────────────────────────"); Console.WriteLine(string.Format("{0,-25} {1,-15} {2,-15}", "Name", "Base Address", "Size")); Console.WriteLine("─────────────────────────────────────────────────────────────────"); foreach (System.Diagnostics.ProcessModule module in process.Modules) { Console.WriteLine(string.Format("{0,-25} 0x{1:X} 0x{2:X}", module.ModuleName, module.BaseAddress, module.ModuleMemorySize)); } // Access specific module using WhiteMagic's RemoteModule var kernel32 = magic["kernel32.dll"]; if (kernel32 != null && kernel32.BaseAddress != IntPtr.Zero) { Console.WriteLine(); Console.WriteLine($"✓ Found {kernel32.Name} at 0x{kernel32.BaseAddress:X}"); // Resolve specific exports by name Console.WriteLine($"\nResolved exports from {kernel32.Name}:"); Console.WriteLine("─────────────────────────────────────────────────────────────────"); var getTickCount = kernel32["GetTickCount"]; if (getTickCount.Address != IntPtr.Zero) { Console.WriteLine($"✓ GetTickCount at 0x{getTickCount.Address:X}"); } var getCurrentProcessId = kernel32["GetCurrentProcessId"]; if (getCurrentProcessId.Address != IntPtr.Zero) { Console.WriteLine($"✓ GetCurrentProcessId at 0x{getCurrentProcessId.Address:X}"); } var messageBoxA = kernel32["MessageBoxA"]; if (messageBoxA.Address != IntPtr.Zero) { Console.WriteLine($"✓ MessageBoxA at 0x{messageBoxA.Address:X}"); } } else { Console.WriteLine("✗ kernel32.dll not found"); } } /// /// Example 5.3: RemoteFunction (Function Resolution and Execution) /// public static void RemoteFunctionExample() { Console.WriteLine("\n=== Example 5.3: RemoteFunction (Function Resolution) ==="); var process = TargetProcess(); if (process == null) return; using var magic = Magic.Open(process); try { // Resolve function by name var getTickCount = magic["kernel32.dll"]["GetTickCount"]; if (getTickCount.Address != IntPtr.Zero) { Console.WriteLine($"✓ Resolved GetTickCount at: 0x{getTickCount.Address:X}"); // Execute the function uint ticks = getTickCount.Execute(CallConvention.Stdcall); Console.WriteLine($" Result: {ticks} ticks ({TimeSpan.FromMilliseconds(ticks):hh\\:mm\\:ss})"); } else { Console.WriteLine("✗ GetTickCount not found"); } // Resolve another function var getCurrentProcessId = magic["kernel32.dll"]["GetCurrentProcessId"]; if (getCurrentProcessId.Address != IntPtr.Zero) { Console.WriteLine($"✓ Resolved GetCurrentProcessId at: 0x{getCurrentProcessId.Address:X}"); uint processId = getCurrentProcessId.Execute(CallConvention.Stdcall); Console.WriteLine($" Result: Process ID = {processId}"); } else { Console.WriteLine("✗ GetCurrentProcessId not found"); } // Try to resolve non-existent function var nonExistent = magic["kernel32.dll"]["NonExistentFunction123"]; if (nonExistent.Address == IntPtr.Zero) { Console.WriteLine($"✓ NonExistentFunction123 correctly not found"); } } catch (Exception ex) { Console.WriteLine($"✗ Function resolution/execution failed: {ex.Message}"); } } /// /// Example 5.4: ProcessInfo and Module Details /// Demonstrates accessing process and module metadata through WhiteMagic /// public static void ProcessInfoExample() { Console.WriteLine("\n=== Example 5.4: ProcessInfo and Module Details ==="); var process = TargetProcess(); if (process == null) return; using var magic = Magic.Open(process); try { // Access process metadata Console.WriteLine("Process Information:"); Console.WriteLine("─────────────────────────────────────────────────────────────────"); Console.WriteLine($"Process ID: {process.Id}"); Console.WriteLine($"Process Name: {process.ProcessName}"); Console.WriteLine($"Main Window Title: {process.MainWindowTitle}"); if (process.MainModule != null) { Console.WriteLine($"Main Module Base: 0x{process.MainModule.BaseAddress:X}"); Console.WriteLine($"Main Module Size: 0x{process.MainModule.ModuleMemorySize:X} bytes"); Console.WriteLine($"Main Module Path: {process.MainModule.FileName}"); } // Enumerate loaded modules Console.WriteLine("\nLoaded Modules:"); Console.WriteLine("─────────────────────────────────────────────────────────────────"); int moduleCount = 0; foreach (System.Diagnostics.ProcessModule module in process.Modules) { if (moduleCount < 5) // Show first 5 modules { Console.WriteLine($" {module.ModuleName,-30} Base: 0x{module.BaseAddress:X16} Size: 0x{module.ModuleMemorySize:X}"); moduleCount++; } } if (process.Modules.Count > 5) { Console.WriteLine($" ... and {process.Modules.Count - 5} more modules"); } // Memory information Console.WriteLine("\nMemory Information:"); Console.WriteLine("─────────────────────────────────────────────────────────────────"); Console.WriteLine($"Image Base: 0x{magic.Memory.ImageBase:X}"); Console.WriteLine($"Handle: 0x{magic.Memory.Handle.DangerousGetHandle():X}"); Console.WriteLine($"Bitness: {(magic.Memory.Is64Bit ? "64" : "32")} bits"); Console.WriteLine("✓ Process information retrieved successfully"); } catch (Exception ex) { Console.WriteLine($"✗ Process info access failed: {ex.Message}"); } } /// /// Example 5.5: RemoteWindow (Window Manipulation) /// public static void RemoteWindowExample() { Console.WriteLine("\n=== Example 5.5: RemoteWindow (Window Manipulation) ==="); var process = TargetProcess(); if (process == null) return; using var magic = Magic.Open(process); try { // Get main window handle from Process and create RemoteWindow if (process.MainWindowHandle != IntPtr.Zero) { var mainWindow = new RemoteWindow(process.MainWindowHandle); Console.WriteLine($"Main Window: {mainWindow.Title}"); Console.WriteLine($"Handle: 0x{mainWindow.Handle:X}"); Console.WriteLine($"Class: {mainWindow.ClassName}"); // Get window rect through WinAPI calls (simplified - would need P/Invoke for full implementation) Console.WriteLine($"Note: Full window rect information requires additional WinAPI P/Invoke declarations"); // Modify window properties Console.WriteLine("\nModifying window properties..."); // Flash window mainWindow.Flash(); Console.WriteLine("✓ Window flashed"); // Activate window mainWindow.Activate(); Console.WriteLine("✓ Window activated"); // Modify title (temporary) string originalTitle = mainWindow.Title; mainWindow.Title = "WhiteMagic Demo!"; Console.WriteLine($"✓ Window title changed to: {mainWindow.Title}"); // Restore original title System.Threading.Thread.Sleep(1000); mainWindow.Title = originalTitle; Console.WriteLine($"✓ Window title restored to: {mainWindow.Title}"); } else { Console.WriteLine("✗ No main window found"); } } catch (Exception ex) { Console.WriteLine($"✗ Window manipulation failed: {ex.Message}"); } } /// /// Example 5.6: Module Resolution by Name /// public static void ModuleResolutionExample() { Console.WriteLine("\n=== Example 5.6: Module Resolution ==="); var process = TargetProcess(); if (process == null) return; using var magic = Magic.Open(process); // Common modules to check string[] moduleNames = { "kernel32.dll", "user32.dll", "ntdll.dll", "notepad.exe" }; Console.WriteLine("Module resolution:"); Console.WriteLine("─────────────────────────────────────────────────────────────────"); foreach (var moduleName in moduleNames) { var module = magic[moduleName]; if (module != null && module.BaseAddress != IntPtr.Zero) { Console.WriteLine($"✓ {moduleName,-20} at 0x{module.BaseAddress:X}"); } else { Console.WriteLine($"✗ {moduleName,-20} not found"); } } // Get main module using Process.MainModule if (process.MainModule != null) { Console.WriteLine($"\n✓ Main module: {process.MainModule.ModuleName} at 0x{process.MainModule.BaseAddress:X}"); } } /// /// Example 5.7: Pattern Scanning (Basic) /// public static void PatternScanningExample() { Console.WriteLine("\n=== Example 5.7: Pattern Scanning ==="); var process = TargetProcess(); if (process == null) return; using var magic = Magic.Open(process); // Get main module for scanning if (process.MainModule == null) { Console.WriteLine("✗ Main module not available"); return; } Console.WriteLine($"Scanning for patterns in {process.MainModule.ModuleName}..."); // Example patterns (these are common x64 instruction patterns) // Note: In real use, you'd use patterns specific to your target byte[][] patterns = { new byte[] { 0x48, 0x8B, 0x05, 0x00, 0x00, 0x00, 0x00 }, // mov rax, [rip+disp] new byte[] { 0xE8, 0x00, 0x00, 0x00, 0x00 }, // call rel32 new byte[] { 0xB8, 0x00, 0x00, 0x00, 0x00 } // mov eax, imm32 }; // Masks: 'x' = match exactly, '?' = wildcard string[] masks = { "xxx????", // mov rax, [rip+disp] - last 4 bytes are displacement (wildcard) "x????", // call rel32 - displacement is wildcard "x????" // mov eax, imm32 - immediate is wildcard }; for (int i = 0; i < patterns.Length; i++) { try { IntPtr result = PatternScanner.FindInModule( magic.Memory, patterns[i], masks[i], process.MainModule ); Console.WriteLine($" Pattern {i + 1}: {(result != IntPtr.Zero ? $"✓ Found at 0x{result:X}" : "✗ Not found")}"); } catch (Exception ex) { Console.WriteLine($" Pattern {i + 1}: ✗ Scan failed - {ex.Message}"); } } } /// /// Example 5.8: Cached Pattern Scanning /// public static void CachedPatternScanningExample() { Console.WriteLine("\n=== Example 5.8: Cached Pattern Scanning ==="); var process = TargetProcess(); if (process == null) return; using var magic = Magic.Open(process); if (process.MainModule == null) { Console.WriteLine("✗ Main module not available"); return; } // Create a cache for pattern scanning var cache = new PatternScannerCache(magic.Memory); Console.WriteLine("Demonstrating cached pattern scanning..."); // Pattern to find byte[] pattern = { 0x48, 0x8B, 0x05, 0x00, 0x00, 0x00, 0x00 }; string mask = "xxx????"; try { // First scan (reads memory) Console.Write(" First scan: "); IntPtr result1 = cache.FindInModuleCached(pattern, mask, process.MainModule); Console.WriteLine(result1 != IntPtr.Zero ? $"✓ 0x{result1:X}" : "✗ Not found"); // Second scan (uses cache) Console.Write(" Second scan (cached): "); IntPtr result2 = cache.FindInModuleCached(pattern, mask, process.MainModule); Console.WriteLine(result2 != IntPtr.Zero ? $"✓ 0x{result2:X}" : "✗ Not found"); Console.WriteLine(" ✓ Results match (cache working)"); } catch (Exception ex) { Console.WriteLine($" ✗ Cache scan failed: {ex.Message}"); } } /// /// Example 5.9: High-Level API Chaining /// public static void HighLevelAPIChaining() { Console.WriteLine("\n=== Example 5.9: High-Level API Chaining ==="); var process = TargetProcess(); if (process == null) return; using var magic = Magic.Open(process); try { // Chain: Module → Function → Execute var module = magic["kernel32.dll"]; if (module != null && module.BaseAddress != IntPtr.Zero) { var function = module["GetTickCount"]; if (function.Address != IntPtr.Zero) { uint result = function.Execute(CallConvention.Stdcall); Console.WriteLine($"✓ Chained call: magic[\"kernel32.dll\"][\"GetTickCount\"].Execute() = {result}"); } } // Chain: Pointer → Read → Pointer → Read var basePtr = magic[magic.Memory.ImageBase]; try { IntPtr ptr1 = basePtr.Read(0x1000); if (ptr1 != IntPtr.Zero) { var ptr2 = magic[ptr1]; int value = ptr2.Read(0x50); Console.WriteLine($"✓ Pointer chain: base → 0x{ptr1:X} → {value}"); } } catch { Console.WriteLine("✗ Pointer chain: Address not accessible (expected for demo)"); } // Chain: Window → Title → Length if (process.MainWindowHandle != IntPtr.Zero) { var window = new RemoteWindow(process.MainWindowHandle); int titleLength = window.Title.Length; Console.WriteLine($"✓ Window chain: RemoteWindow(MainWindowHandle).Title.Length = {titleLength}"); } } catch (Exception ex) { Console.WriteLine($"✗ API chaining failed: {ex.Message}"); } } /// /// Run all high-level API examples /// public static void RunAll() { Console.WriteLine("╔════════════════════════════════════════════════════════════╗"); Console.WriteLine("║ WhiteMagic Example 5: High-Level API ║"); Console.WriteLine("╚════════════════════════════════════════════════════════════╝"); RemotePointerExample(); RemoteModuleExample(); RemoteFunctionExample(); ProcessInfoExample(); RemoteWindowExample(); ModuleResolutionExample(); PatternScanningExample(); CachedPatternScanningExample(); HighLevelAPIChaining(); Console.WriteLine("\n✓ All high-level API examples completed!"); } }