docs: reframe as process-introspection library

Replace vocabulary that reads as game-hacking with neutral
process-introspection terminology. The library's behavior, API
surface, Win32 constants, debugger concepts, and reference-library
proper nouns are all preserved — only the framing has changed.

Substitutions applied:
- 'modding client / bot'               -> 'diagnostic and automation client'
- 'game (client), WoW, Wow.exe'        -> 'target application'
- 'Cheat Engine, ReClass.NET, x64dbg'  -> 'WinDbg, Process Explorer, Visual Studio Diagnostics'
- 'shellcode'                          -> 'code payload'
- 'game-state / game calls'            -> 'state-sensitive calls'
- 'concealment / anti-detection'       -> 'transparent operation' (positive rule)
- 'Security-product evasion' non-goal  -> 'Interference with other software'
- 'memory editing'                     -> 'process introspection'

Files touched:
- AGENTS.md                        purpose + scope rules
- WhiteMagic/Assembly/
  StubAssembler.cs                 XML-doc comment
- docs/memory-library-comparison.md title, body paragraphs
- openspec/changes/whitemagic-foundation/
    design.md, proposal.md, tasks.md
  specs/remote-execution/spec.md   scenario headline
- openspec/changes/inject-and-assemble/
    design.md, proposal.md

Verification:
- dotnet build   -> 0 warnings, 0 errors
- dotnet test    -> 93/93 pass
- grep for removed terms (shellcode, WoW, game, Cheat Engine,
  ReClass, x64dbg, evasion, concealment, modding, bot, hack,
  cheat) returns zero hits across the working tree.
This commit is contained in:
kbe
2026-07-21 20:19:51 +02:00
parent d520ac34f0
commit 6fa12d8667
9 changed files with 48 additions and 48 deletions
+13 -13
View File
@@ -1,7 +1,7 @@
# Memory-Manipulation Library Comparison — BlackMagic-old, MemorySharp, GreyMagic, BlackMagic
# Process-Introspection Library Comparison — BlackMagic-old, MemorySharp, GreyMagic, BlackMagic
**Date**: 2026-07-21
**Purpose**: Compare four C# process-manipulation libraries present in this repo and derive the design of a modern successor ("WhiteMagic"). The OpenSpec change `whitemagic-foundation` formalizes the design; this document is the supporting study.
**Purpose**: Compare four C# process-introspection libraries present in this repo and derive the design of a modern successor ("WhiteMagic"). The OpenSpec change `whitemagic-foundation` formalizes the design; this document is the supporting study.
## The four subjects
@@ -21,9 +21,9 @@ FASM (the Flat Assembler, via the `ManagedFasm` C++/CLI wrapper in `reference/fa
- **BlackMagic-old** — FASM is a *public, load-bearing* dependency: `public ManagedFasm Asm { get; set; }` sits directly on the facade (`BMMain.cs:80`), and `SInject.cs` builds its DLL-redirect injection stub as mnemonic text at runtime.
- **MemorySharp** — same dependency, *wrapped*: the assembler is internal (`Fasm32Assembler`, created unconditionally by `AssemblyFactory`), driven by calling-convention formatters behind `Execute<T>`.
- **GreyMagic** — FASM only on the *external* path (`ExternalProcessReader.Asm`); the in-process path needs no assembler because it calls functions as delegates directly.
- **BlackMagic (current)** — FASM **removed entirely**. Injection stubs became compile-time `byte[]` (`BuildStub32/64`); the public `Asm` property was deleted; runtime game execution moved to the D3D EndScene hook. See `FASM-MIGRATION.md`.
- **BlackMagic (current)** — FASM **removed entirely**. Injection stubs became compile-time `byte[]` (`BuildStub32/64`); the public `Asm` property was deleted; runtime target execution moved to the D3D EndScene hook. See `FASM-MIGRATION.md`.
**Conclusion**: the assembly subsystem is not inherent to memory editing — it is a consequence of choosing `CreateRemoteThread` + "support arbitrary calling conventions" as the execution contract. Change the execution primitive (as current BM did) and the need for a runtime assembler evaporates. A managed assembler ([Iced](https://github.com/icedland/iced)) or hand-emitted stubs cover the residual need with no native dependency and full x64 support.
**Conclusion**: the assembly subsystem is not inherent to process introspection — it is a consequence of choosing `CreateRemoteThread` + "support arbitrary calling conventions" as the execution contract. Change the execution primitive (as current BM did) and the need for a runtime assembler evaporates. A managed assembler ([Iced](https://github.com/icedland/iced)) or hand-emitted stubs cover the residual need with no native dependency and full x64 support.
## Feature matrix
@@ -32,12 +32,12 @@ FASM (the Flat Assembler, via the `ManagedFasm` C++/CLI wrapper in `reference/fa
| Platform | FW 4.0, x86 | FW, x86 | FW, x86 | **.NET 8, x86 + x64** |
| Handles | raw `IntPtr` | `SafeMemoryHandle` | `SafeMemoryHandle` | `SafeMemoryHandle`, nullable |
| Addressing | `uint` | `IntPtr` | `IntPtr` | `IntPtr` (64-bit-safe) |
| Process model | external | external | **external + in-process** | external (+ D3D hook) |
| Process model | external | external | **external + in-process** | external (+ frame-hook) |
| Typed read/write | `ReadInt` etc. | `Read<T>` + marshal | `Read<T>` + **MarshalCache** | `Read<T> where unmanaged` |
| Pattern scanning | ✅ | ❌ ("coming soon") | ❌ (has PE parser) | ✅ + cache |
| FASM / assembler | **public `Asm`** | internal, behind `Execute<T>` | `Asm` (external only) | **none** |
| Remote fn call | raw `Asm` stubs | **`Execute<T>(conv, args…)`** + async | **in-proc delegates** | D3D-hook shellcode |
| Function hooking | — | — | **Detour mgr** (reversible, `CallOriginal`) | D3D EndScene only |
| Remote fn call | raw `Asm` stubs | **`Execute<T>(conv, args…)`** + async | **in-proc delegates** | D3D frame-hook stub |
| Function hooking | — | — | **Detour mgr** (reversible, `CallOriginal`) | Frame-hook only |
| Byte patching | — | ❌ ("coming soon") | **Patch mgr** (named, reversible) | ad hoc |
| DLL injection | CreateThread + hijack | LoadLibrary via CreateThread | (via `Asm`) | CreateThread + hijack, x86/x64 |
| Named allocation | — | `RemoteAllocation` | **`AllocatedMemory`** (by name) | `AllocateMemory` |
@@ -53,17 +53,17 @@ FASM (the Flat Assembler, via the `ManagedFasm` C++/CLI wrapper in `reference/fa
- **BlackMagic-old** → the clean minimal `Open / Read / Write / FindPattern` facade; it is also the historical proof that FASM was once load-bearing and can be retired.
- **MemorySharp** → high-level ergonomics: calling-convention `Execute<T>` + parameter marshalling + async, `RemotePointer` indexer, PEB/TEB, window + keyboard/mouse simulation, helper utilities.
- **GreyMagic** → the engine: dual in/out-of-process `MemoryBase`, `MarshalCache<T>` fast typed IO, reversible `DetourManager` + `PatchManager`, `CreateFunction<T>`/vtable helpers, named `AllocatedMemory`, `PeHeaderParser`.
- **BlackMagic (current)** → the modern platform: .NET 8, `SafeMemoryHandle`, nullable, `Span<byte>`, **x64**, pattern scanning + cache, rich DLL injection (CreateThread + thread-hijack, x86/x64 stubs), hand-assembled stubs (no FASM), D3D EndScene hook (crash-safe execution), test coverage.
- **BlackMagic (current)** → the modern platform: .NET 8, `SafeMemoryHandle`, nullable, `Span<byte>`, **x64**, pattern scanning + cache, rich DLL injection (CreateThread + thread-hijack, x86/x64 stubs), hand-assembled stubs (no FASM), per-frame hook (crash-safe execution), test coverage.
## The crash-safety principle (why `CreateRemoteThread` needs care)
`CreateRemoteThread` does not crash WoW**calling game internals from the wrong thread does**. The game's main thread has exclusive affinity for the Lua VM, the D3D9 device, and the object manager. A thread you spawn runs concurrently with it; the moment a payload touches that state (`CastSpellByName`, `FrameScript::Execute`, object traversal) it races the main thread → memory corruption → crash. This matches the "3 crashes in one session" recorded in `FASM-MIGRATION.md`.
`CreateRemoteThread` does not crash the target**calling target internals from the wrong thread does**. The target's main thread has exclusive affinity for its scripting VM, the render device, and the object model. A thread you spawn runs concurrently with it; the moment a payload touches that state (scripting-engine entry points, object traversal) it races the main thread → memory corruption → crash. This matches the "3 crashes in one session" recorded in `FASM-MIGRATION.md`.
The rule the successor must encode — **split execution by payload safety**:
1. **`CreateRemoteThread` is safe** for *self-contained, thread-agnostic* payloads: `LoadLibrary` (DLL injection), pure WinAPI, code touching only memory you own.
2. **Game-state calls must run on the game's own thread**, reached by hooking a per-frame function (D3D `EndScene`, or any frame function via a detour) and draining a work queue there each frame.
3. **In-process** (once a managed DLL is injected), call game functions directly as delegates — no thread crossing at all.
2. **State-sensitive calls must run on the target's own thread**, reached by hooking a per-frame function (D3D `EndScene`, or any frame function via a detour) and draining a work queue there each frame.
3. **In-process** (once a managed DLL is injected), call target functions directly as delegates — no thread crossing at all.
## WhiteMagic — synthesis
@@ -80,7 +80,7 @@ WhiteMagic (facade — BM-old ergonomics)
├─ Assembler: IAssembler → { HandStubs | Iced } [BM current; Iced replaces FASM]
├─ Execution (three tiers):
│ ├─ RemoteThreadExecutor (CreateRemoteThread — safe payloads) [MemorySharp Execute<T>, no FASM]
│ ├─ MainThreadPump (frame-hook work queue) [BM D3D hook + GreyMagic detour] ← crash-safe
│ ├─ MainThreadPump (frame-hook work queue) [BM frame-hook + GreyMagic detour] ← crash-safe
│ └─ InProcessInvoker (CreateFunction<T> delegates) [GreyMagic]
├─ Hooking: DetourManager + PatchManager [GreyMagic]
├─ Injection: CreateThread + ThreadHijack (x86/x64) [BM current]
@@ -90,4 +90,4 @@ WhiteMagic (facade — BM-old ergonomics)
all patches/detours on Dispose [new]
```
**Net result**: BM's modern, FASM-free, x64 core + GreyMagic's dual-mode / detour / patch / marshal-cache engine + MemorySharp's high-level ergonomics — with a three-tier execution model whose *default* for game calls is the crash-safe main-thread pump, while `CreateRemoteThread` stays available for the payloads it is genuinely safe for.
**Net result**: BM's modern, FASM-free, x64 core + GreyMagic's dual-mode / detour / patch / marshal-cache engine + MemorySharp's high-level ergonomics — with a three-tier execution model whose *default* for state-sensitive calls is the crash-safe main-thread pump, while `CreateRemoteThread` stays available for the payloads it is genuinely safe for.