using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; using WhiteMagic; using WhiteMagic.Execution; namespace WhiteMagic.Examples; /// /// Sample struct for demonstrating struct marshalling /// [StructLayout(LayoutKind.Sequential)] public struct PlayerInfo { public int Health; public float PositionX; public float PositionY; public int Level; public uint Experience; } /// /// Example 1: Basic Memory Operations /// Demonstrates reading and writing memory of various types /// public class BasicMemoryOperations { /// /// Target process for examples (Notepad is safe and always available) /// private static Process? TargetProcess() { // Try to find Notepad 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 1.1: Reading and writing primitive types /// public static void ReadWritePrimitives() { Console.WriteLine("=== Example 1.1: Read/Write Primitives ==="); var process = TargetProcess(); if (process == null) return; using var magic = Magic.Open(process); // Example: Read an integer from a hypothetical address // (In real use, you'd find the actual address via pattern scanning or offsets) IntPtr testAddress = magic.Memory.ImageBase + 0x1000; // Read different primitive types try { int intValue = magic.Memory.Read(testAddress); Console.WriteLine($"Read int from 0x{testAddress:X}: {intValue}"); float floatValue = magic.Memory.Read(testAddress); Console.WriteLine($"Read float from 0x{testAddress:X}: {floatValue}"); double doubleValue = magic.Memory.Read(testAddress); Console.WriteLine($"Read double from 0x{testAddress:X}: {doubleValue}"); bool boolValue = magic.Memory.Read(testAddress); Console.WriteLine($"Read bool from 0x{testAddress:X}: {boolValue}"); } catch (Exception ex) { Console.WriteLine($"Note: Read failed (address may be invalid): {ex.Message}"); } // Write example bool writeSuccess = magic.Memory.Write(testAddress, 42); Console.WriteLine($"Write to 0x{testAddress:X}: {(writeSuccess ? "Success" : "Failed")}"); } /// /// Example 1.2: Reading and writing arrays /// public static void ReadWriteArrays() { Console.WriteLine("\n=== Example 1.2: Read/Write Arrays ==="); var process = TargetProcess(); if (process == null) return; using var magic = Magic.Open(process); IntPtr arrayAddress = magic.Memory.ImageBase + 0x2000; // Read array of integers try { int[] intArray = magic.Memory.Read(arrayAddress, 10); Console.WriteLine($"Read {intArray.Length} integers from 0x{arrayAddress:X}"); Console.WriteLine($"First few values: {string.Join(", ", intArray[..Math.Min(5, intArray.Length)])}"); } catch (Exception ex) { Console.WriteLine($"Note: Array read failed (address may be invalid): {ex.Message}"); } // Write array of integers int[] writeArray = { 1, 2, 3, 4, 5 }; bool writeSuccess = magic.Memory.Write(arrayAddress, writeArray); Console.WriteLine($"Write {writeArray.Length} integers to 0x{arrayAddress:X}: {(writeSuccess ? "Success" : "Failed")}"); } /// /// Example 1.3: Reading and writing strings /// public static void ReadWriteStrings() { Console.WriteLine("\n=== Example 1.3: Read/Write Strings ==="); var process = TargetProcess(); if (process == null) return; using var magic = Magic.Open(process); IntPtr stringAddress = magic.Memory.ImageBase + 0x3000; // Read ANSI string string ansiString = magic.Memory.ReadString(stringAddress, Encoding.ASCII, maxLength: 256); Console.WriteLine($"Read ANSI string from 0x{stringAddress:X}: \"{ansiString}\""); // Read Unicode string string unicodeString = magic.Memory.ReadString(stringAddress, Encoding.Unicode, maxLength: 256); Console.WriteLine($"Read Unicode string from 0x{stringAddress:X}: \"{unicodeString}\""); // Write string bool writeSuccess = magic.Memory.WriteString(stringAddress, "Hello, WhiteMagic!", Encoding.ASCII); Console.WriteLine($"Write string to 0x{stringAddress:X}: {(writeSuccess ? "Success" : "Failed")}"); } /// /// Example 1.4: Reading and writing raw bytes /// public static void ReadWriteBytes() { Console.WriteLine("\n=== Example 1.4: Read/Write Bytes ==="); var process = TargetProcess(); if (process == null) return; using var magic = Magic.Open(process); IntPtr address = magic.Memory.ImageBase + 0x4000; // Read bytes byte[] buffer = magic.Memory.ReadBytes(address, 16); Console.WriteLine($"Read {buffer.Length} bytes from 0x{address:X}"); Console.WriteLine($"Hex: {BitConverter.ToString(buffer)}"); // Write bytes byte[] patchBytes = { 0x90, 0x90, 0x90 }; // NOP x3 int bytesWritten = magic.Memory.WriteBytes(address, patchBytes); Console.WriteLine($"Wrote {bytesWritten} bytes to 0x{address:X}"); } /// /// Example 1.5: Using RemotePointer for fluent addressing /// public static void RemotePointerUsage() { Console.WriteLine("\n=== Example 1.5: RemotePointer Fluent Addressing ==="); var process = TargetProcess(); if (process == null) return; using var magic = Magic.Open(process); // Create a pointer to module base var modulePtr = magic[magic.Memory.ImageBase]; // Read offsets from module base try { int offset1 = modulePtr.Read(0x1000); Console.WriteLine($"Read int at module_base + 0x1000: {offset1}"); // Chained reads (pointer -> value -> offset) IntPtr nestedPtr = modulePtr.Read(0x2000); if (nestedPtr != IntPtr.Zero) { var nestedPtrObj = magic[nestedPtr]; int nestedValue = nestedPtrObj.Read(0x50); Console.WriteLine($"Read nested pointer value: {nestedValue}"); } } catch (Exception ex) { Console.WriteLine($"Note: Read failed (offset may be invalid): {ex.Message}"); } } /// /// Example 1.6: Relative addressing /// public static void RelativeAddressing() { Console.WriteLine("\n=== Example 1.6: Relative Addressing ==="); var process = TargetProcess(); if (process == null) return; using var magic = Magic.Open(process); IntPtr moduleBase = magic.Memory.ImageBase; // Absolute addressing (default) int absValue = magic.Memory.Read(moduleBase + 0x1000); Console.WriteLine($"Absolute read at 0x{moduleBase + 0x1000:X}: {absValue}"); // Relative addressing (relative to module base) int relValue = magic.Memory.Read(0x1000, isRelative: true); Console.WriteLine($"Relative read at offset 0x1000: {relValue}"); // They should be the same Console.WriteLine($"Values match: {absValue == relValue}"); } /// /// Example 1.7: Error handling /// public static void ErrorHandling() { Console.WriteLine("\n=== Example 1.7: Error Handling ==="); var process = TargetProcess(); if (process == null) return; using var magic = Magic.Open(process); // Try to read from invalid address try { int invalidRead = magic.Memory.Read(unchecked((IntPtr)0xdeadbeef)); Console.WriteLine($"Read from invalid address (shouldn't reach here): {invalidRead}"); } catch (Exception ex) { Console.WriteLine($"✓ Caught expected exception: {ex.GetType().Name}"); } // Try to write to read-only memory (will return false) bool writeSuccess = magic.Memory.Write(magic.Memory.ImageBase, 42); Console.WriteLine($"Write to read-only memory: {(writeSuccess ? "Unexpected success" : "✓ Expected failure")}"); // Try to read string from invalid address string invalidString = magic.Memory.ReadString(unchecked((IntPtr)0xdeadbeef), Encoding.ASCII); Console.WriteLine($"Read string from invalid address: \"{invalidString}\" (empty = graceful failure)"); } /// /// Example 1.8: Working with custom structs /// public static void CustomStructs() { Console.WriteLine("\n=== Example 1.8: Custom Structs ==="); var process = TargetProcess(); if (process == null) return; using var magic = Magic.Open(process); IntPtr structAddress = magic.Memory.ImageBase + 0x5000; try { // Read struct PlayerInfo player = magic.Memory.Read(structAddress); Console.WriteLine($"Read PlayerInfo:"); Console.WriteLine($" Health: {player.Health}"); Console.WriteLine($" Position: ({player.PositionX}, {player.PositionY})"); Console.WriteLine($" Level: {player.Level}"); Console.WriteLine($" Experience: {player.Experience}"); // Write struct PlayerInfo updatedPlayer = player with { Health = 100, Level = player.Level + 1 }; bool writeSuccess = magic.Memory.Write(structAddress, updatedPlayer); Console.WriteLine($"Write updated PlayerInfo: {(writeSuccess ? "Success" : "Failed")}"); } catch (Exception ex) { Console.WriteLine($"Note: Struct read/write failed (address may be invalid): {ex.Message}"); } } /// /// Run all basic memory operation examples /// public static void RunAll() { Console.WriteLine("╔════════════════════════════════════════════════════════════╗"); Console.WriteLine("║ WhiteMagic Example 1: Basic Memory Operations ║"); Console.WriteLine("╚════════════════════════════════════════════════════════════╝"); ReadWritePrimitives(); ReadWriteArrays(); ReadWriteStrings(); ReadWriteBytes(); RemotePointerUsage(); RelativeAddressing(); ErrorHandling(); CustomStructs(); Console.WriteLine("\n✓ All basic memory operation examples completed!"); } }