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.
This commit is contained in:
kbe
2026-07-22 22:26:07 +02:00
parent 040a51bf03
commit 6300bebe33
17 changed files with 4906 additions and 1 deletions
+321
View File
@@ -0,0 +1,321 @@
# WhiteMagic Architecture
## Overview
WhiteMagic is built as a layered architecture that provides multiple levels of abstraction over Windows process-introspection APIs. This design allows consumers to choose the right level of control for their use case, from low-level memory operations to high-level ergonomic APIs.
## Layer Structure
```
┌──────────────────────────────────────────────────────────────┐
│ Magic (Facade) │
│ High-level entry point: Magic.Open(), Magic.OpenInProcess() │
└───────────────────────┬──────────────────────────────────────┘
┌───────────────┴───────────────┐
│ │
┌───────▼─────────┐ ┌────────▼────────┐
│ MemoryBase │ │ High-Level API │
│ (Abstract) │ │ │
├─────────────────┤ ├─────────────────┤
│ ExternalReader │ │ RemotePointer │
│ InProcessReader │ │ RemoteModule │
│ │ │ RemoteFunction │
│ ┌──────────────┐│ │ ManagedPeb/TEB │
│ │ Hooking ││ │ Window/Input │
│ │ DetourMgr ││ └─────────────────┘
│ │ PatchMgr ││
│ └──────────────┘│
└─────────┬───────┘
┌─────▼─────┬───────────┬───────────┐
│ │ │ │
┌───▼────┐ ┌────▼──┐ ┌──────▼──┐ ┌──────▼───┐
│Native │ │Discov.│ │Execution│ │Assembly │
│P/Invoke│ │Scan/PE│ │3-tier │ │IAssembler│
└────────┘ └───────┘ └─────────┘ └──────────┘
```
## Core Layer
### MemoryBase (Abstract)
The foundation of WhiteMagic is the `MemoryBase` abstract class, which defines the contract for all memory operations:
**Key responsibilities:**
- Abstract memory read/write operations
- Host for `MarshalCache<T>` optimization
- Owner of `PatchManager` and `DetourManager`
- Relative/absolute addressing support
**Design decision (D1):** Dual-mode readers share the same abstract interface, allowing high-level code (pattern scanning, patching, etc.) to work in both external and in-process modes without changes.
### ExternalReader
Implements `MemoryBase` for out-of-process operations:
**Mechanism:** Uses `ReadProcessMemory`/`WriteProcessMemory` via P/Invoke
**Handle:** `SafeMemoryHandle` to target process
**Use case:** Primary mode for automation hosts
### InProcessReader
Implements `MemoryBase` for injected code:
**Mechanism:** Uses `ReadProcessMemory`/`WriteProcessMemory` on self-handle
**Handle:** `SafeMemoryHandle` to current process
**Use case:** Once a managed DLL is injected, enables delegate calls and detours
**Design decision (D1 revision):** InProcessReader uses RPM-on-self instead of unsafe direct pointer deref because .NET cannot catch `AccessViolationException`, so a bad deref kills the host with no soft-failure path. The in-process speed win moves to the delegate-call and detour paths, not the reader.
## Discovery Layer
### PatternScanner
Scans target memory for byte patterns with wildcard support:
**Features:**
- IDA-style hex patterns (`48 8B ? ? ? ? ?`)
- Optional caching to avoid repeated scans
- Module-relative or absolute addressing
### PeHeaderParser
Parses PE headers to extract export information:
**Features:**
- Export table parsing
- Forwarder resolution (e.g., `kernel32!HeapAlloc``NTDLL.RtlAllocateHeap`)
- Ordinal export support
## Execution Layer (Three-Tier Model)
### RemoteThreadExecutor
**Mechanism:** `CreateRemoteThread` + hand-assembled convention stubs
**Use for:** Thread-agnostic payloads (pure WinAPI, self-contained code, DLL injection)
**Risk:** NOT crash-safe for single-threaded target state
### MainThreadPump
**Mechanism:** Detour on per-frame function + work queue
**Use for:** State-sensitive calls (default for target-state access)
**Safety:** Crash-safe — runs on target's own thread
**How it works:**
1. Installs a detour on a per-frame function (e.g., D3D `EndScene`)
2. Each frame, the hook drains a thread-safe queue
3. Work items run synchronously in target's context
4. Results/exceptions returned via `TaskCompletionSource`
### InProcessInvoker
**Mechanism:** `Marshal.GetDelegateForFunctionPointer`
**Use for:** In-process delegates after injection
**Benefit:** Zero thread-crossing overhead
## Hooking Layer
### DetourManager
**Scope:** In-process only
**Features:**
- Inline `E9 jmp` detours over function prologues
- `CallOriginal` support via trampoline
- `Apply`/`Remove` operations
- Auto-restore on `Dispose`
**Safety:** Prologue validation via `IAssembler.GetPrologueLength` (optional Iced backend)
### PatchManager
**Scope:** Both external and in-process
**Features:**
- Named byte patches
- `Apply`/`Remove`/`IsApplied`
- Auto-restore on `Dispose`
## Assembly Layer
### IAssembler Seam
Abstracts text → machine code generation:
**Implementations:**
- `StubAssembler` (default): Hand-emits calling-convention stubs, no dependency
- `IcedAssembler` (optional): Wraps Iced for arbitrary assembly
**Design decision (D3):** Keeps default configuration dependency-free; only callers needing arbitrary asm opt into Iced.
### Convention Stubs
`StubAssembler` emits x86/x64 calling-convention trampolines:
**Conventions supported:** cdecl, stdcall, thiscall, fastcall, x64 (Microsoft)
**Encoding:** Deterministic byte emission, no parsing required
## High-Level Layer
### RemotePointer
Indexer-based pointer arithmetic:
```csharp
var ptr = magic[baseAddress];
int value = ptr.Read<int>(offset);
ptr.Write(999, offset);
```
### RemoteModule/RemoteFunction
Module and export resolution:
```csharp
var module = magic["user32"];
var fn = module["MessageBoxA"];
int result = fn.Execute<int>(CallConvention.Stdcall, args...);
```
### ManagedPeb/ManagedTeb
Managed views of Process Environment Block and Thread Environment Block:
**Features:**
- Typed field access
- No manual structure marshalling
### Window/Input
Window mutation and input simulation:
**Features:**
- Move/resize/title/activate/flash windows
- Keyboard/mouse input without focus (where supported)
## Optimization Layer
### MarshalCache<T>
Per-type metadata caching:
**Cached data:**
- `Size` (managed blittable width)
- `MarshalSize` (unmanaged interop width)
- `TypeRequiresMarshal` (needs `Marshal.PtrToStructure`)
- `IsIntPtr` (for special handling)
**Performance:** Avoids per-call reflection and `Marshal.SizeOf` overhead
## Thread Safety
### ExternalReader
**Thread-safe:** Yes (RPM/WPM are thread-safe)
**Synchronization:** None required
### InProcessReader
**Thread-safe:** Yes (RPM-on-self is thread-safe)
**Synchronization:** None required
### MainThreadPump
**Thread-safe:** Yes (uses `ConcurrentQueue`)
**Synchronization:** Lock-free queue + `TaskCompletionSource`
### DetourManager/PatchManager
**Thread-safe:** No
**Synchronization:** Caller must synchronize
## Lifetime Management
All disposable resources follow RAII:
```csharp
using var magic = Magic.Open(process);
// All handles, patches, and detours auto-restore on disposal
```
**Resources cleaned up:**
- Process handles (`SafeMemoryHandle`)
- Applied patches (`PatchManager`)
- Active detours (`DetourManager`)
- Allocated memory (`AllocatedMemory`)
## Error Handling
**Strategy:** Explicit failures, silent success
- **Read operations:** Throw on failure (Win32Exception)
- **Write operations:** Return `false` on failure
- **String reads:** Return `string.Empty` on failure
- **Invalid handles:** Throw `InvalidOperationException`
**Rationale:** Writes to another process can legitimately fail (protection changed, process exited); silent retry is often the right strategy. Reads are typically expected to succeed, so exceptions surface the problem immediately.
## Extensibility Points
### IAssembler
Plug in custom assemblers:
```csharp
public interface IAssembler
{
byte[] Assemble(string assemblyText, ulong origin = 0);
}
```
### DetourManager.PrologueLengthResolver
Custom prologue validation:
```csharp
magic.DetourManager.PrologueLengthResolver = (address, minBytes) =>
// Custom validation logic
return requiredLength;
```
## Performance Characteristics
### Memory Access
| Operation | Cost | Notes |
|-----------|------|-------|
| `Read<T>` (blittable) | Low | `MemoryMarshal.Read`, no alloc |
| `Read<T>` (marshalled) | Medium | `Marshal.PtrToStructure` |
| `Read<T>` (array) | Medium-High | Per-element marshalling |
| `ReadBytes` | Low | Direct buffer copy |
| `ReadString` | Medium | Encoding + allocation |
### Execution
| Method | Latency | Safety |
|--------|---------|--------|
| `RemoteThreadExecutor` | ~1-2ms | Thread-agnostic only |
| `MainThreadPump` | ~1 frame (16-33ms) | Crash-safe |
| `InProcessInvoker` | <1μs | In-process only |
### Pattern Scanning
| Mode | Cost | Notes |
|------|------|-------|
| Uncached | High | Scans entire module |
| Cached | Low | O(1) after first scan |
## Design Principles
1. **Safety by default:** MainThreadPump prevents crashes from thread-affinity violations
2. **Bitness-agnostic:** Works on x86 and x64 without code changes
3. **No native dependencies:** Default configuration is pure managed
4. **Explicit operations:** Clear failure modes, no hidden retries
5. **Resource safety:** RAII-based cleanup prevents leaks
6. **Extensibility:** Seam points for assemblers, validators
## Further Reading
- [Execution Models](./execution-models.md) — Deep dive on the three-tier execution strategy
- [Memory Access](./memory-access.md) — MemoryBase readers and MarshalCache optimization
- [Function Hooking](./hooking.md) — DetourManager and PatchManager internals
- [Assembly Seam](./assembly-seam.md) — IAssembler abstraction and Iced integration