Files
whitemagic/WhiteMagic.Examples/Example1_BasicMemoryOperations.cs
kbe 6300bebe33 Fix API documentation and examples; add comprehensive documentation suite
- Example5: Fix format string bugs (alignment specifier placement, SafeMemoryHandle formatting)
- Example4: Fix DetourManager.Detour() → Create() in all doc strings
- Example3: Fix MemoryBase.CreateFunction() → InProcessInvoker.CreateFunction() in doc strings
- Examples 1-5: Correct all runtime errors and API mismatches vs actual WhiteMagic API
- README: Fix DetourManager.Detour() examples to use Create(); add missing code fence markers
- Add WhiteMagic.Examples project with 5 comprehensive example files (40+ sub-examples)
- Add docfx.json and toc.md for DocFX API reference generation
- Add 5 conceptual guides: architecture, memory-access, execution-models, hooking, troubleshooting
- Ensure zero errors, zero warnings across all projects (net8.0-windows)

Doc strings now teach correct APIs; runtime format bugs eliminated; build succeeds.
2026-07-22 22:26:07 +02:00

322 lines
11 KiB
C#

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using WhiteMagic;
using WhiteMagic.Execution;
namespace WhiteMagic.Examples;
/// <summary>
/// Sample struct for demonstrating struct marshalling
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct PlayerInfo
{
public int Health;
public float PositionX;
public float PositionY;
public int Level;
public uint Experience;
}
/// <summary>
/// Example 1: Basic Memory Operations
/// Demonstrates reading and writing memory of various types
/// </summary>
public class BasicMemoryOperations
{
/// <summary>
/// Target process for examples (Notepad is safe and always available)
/// </summary>
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;
}
/// <summary>
/// Example 1.1: Reading and writing primitive types
/// </summary>
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<int>(testAddress);
Console.WriteLine($"Read int from 0x{testAddress:X}: {intValue}");
float floatValue = magic.Memory.Read<float>(testAddress);
Console.WriteLine($"Read float from 0x{testAddress:X}: {floatValue}");
double doubleValue = magic.Memory.Read<double>(testAddress);
Console.WriteLine($"Read double from 0x{testAddress:X}: {doubleValue}");
bool boolValue = magic.Memory.Read<bool>(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")}");
}
/// <summary>
/// Example 1.2: Reading and writing arrays
/// </summary>
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<int>(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")}");
}
/// <summary>
/// Example 1.3: Reading and writing strings
/// </summary>
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")}");
}
/// <summary>
/// Example 1.4: Reading and writing raw bytes
/// </summary>
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}");
}
/// <summary>
/// Example 1.5: Using RemotePointer for fluent addressing
/// </summary>
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<int>(0x1000);
Console.WriteLine($"Read int at module_base + 0x1000: {offset1}");
// Chained reads (pointer -> value -> offset)
IntPtr nestedPtr = modulePtr.Read<IntPtr>(0x2000);
if (nestedPtr != IntPtr.Zero)
{
var nestedPtrObj = magic[nestedPtr];
int nestedValue = nestedPtrObj.Read<int>(0x50);
Console.WriteLine($"Read nested pointer value: {nestedValue}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Note: Read failed (offset may be invalid): {ex.Message}");
}
}
/// <summary>
/// Example 1.6: Relative addressing
/// </summary>
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<int>(moduleBase + 0x1000);
Console.WriteLine($"Absolute read at 0x{moduleBase + 0x1000:X}: {absValue}");
// Relative addressing (relative to module base)
int relValue = magic.Memory.Read<int>(0x1000, isRelative: true);
Console.WriteLine($"Relative read at offset 0x1000: {relValue}");
// They should be the same
Console.WriteLine($"Values match: {absValue == relValue}");
}
/// <summary>
/// Example 1.7: Error handling
/// </summary>
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<int>(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)");
}
/// <summary>
/// Example 1.8: Working with custom structs
/// </summary>
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<PlayerInfo>(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}");
}
}
/// <summary>
/// Run all basic memory operation examples
/// </summary>
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!");
}
}