Files
whitemagic/openspec/changes/whitemagic-foundation/specs/remote-execution/spec.md
T
kbe 6fa12d8667 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.
2026-07-21 20:19:51 +02:00

58 lines
3.3 KiB
Markdown

## ADDED Requirements
### Requirement: Three-tier execution model
WhiteMagic SHALL provide three execution strategies selected by payload safety: `RemoteThreadExecutor` (via `CreateRemoteThread`), `MainThreadPump` (work marshalled onto the target's own thread), and `InProcessInvoker` (direct native-delegate calls when injected in-process).
#### Scenario: strategies are distinct and selectable
- **WHEN** a caller chooses an execution strategy
- **THEN** each of remote-thread, main-thread-pump, and in-process MUST be individually invokable
#### Scenario: main-thread pump is the documented default for state-sensitive calls
- **WHEN** documentation or API guidance describes calling functions that touch single-thread-affinity process state
- **THEN** it MUST direct callers to the main-thread pump, not `CreateRemoteThread`
### Requirement: Remote-thread execution for thread-agnostic payloads
`RemoteThreadExecutor` SHALL create a remote thread at a target address using a calling-convention-aware stub, wait for completion, and return the typed exit value. Its documentation MUST state that it is safe only for thread-agnostic payloads.
#### Scenario: execute with parameters and convention
- **WHEN** `Execute<int>(addr, CallConvention.Cdecl, arg1, arg2)` is called on a safe self-contained function
- **THEN** the target MUST be called with the arguments laid out per cdecl and the typed return value returned
#### Scenario: parameters marshalled and freed
- **WHEN** a `string` or struct parameter is passed to `Execute`
- **THEN** it MUST be allocated in the remote process, passed by pointer, and freed after the call completes
#### Scenario: no process open
- **WHEN** `Execute` is called with no process open
- **THEN** it MUST fail deterministically rather than crash
### Requirement: Crash-safe main-thread pump
`MainThreadPump` SHALL install a hook on a per-frame function in the target and, each time that function runs, drain a thread-safe queue of work items, executing each on the target's own thread and returning its result or exception to the requesting caller.
#### Scenario: work runs on the hooked thread
- **WHEN** a work item is queued and the hooked per-frame function next executes
- **THEN** the work item MUST run in the context of the thread that calls the per-frame function
#### Scenario: result returned to caller
- **WHEN** a caller queues a function returning a value and awaits its completion
- **THEN** the caller MUST receive the returned value
#### Scenario: exception propagated, pump survives
- **WHEN** a queued work item throws
- **THEN** the exception MUST be surfaced to the requesting caller AND subsequent queued items MUST still be processed
#### Scenario: uninstall restores the frame function
- **WHEN** the pump is disposed
- **THEN** the hooked per-frame function MUST be restored to its original bytes
### Requirement: In-process delegate invocation
`InProcessInvoker` SHALL convert a function address to a typed managed delegate and call it directly, without creating a thread or crossing a thread boundary.
#### Scenario: call as delegate
- **WHEN** `CreateFunction<TDelegate>(addr)` is called in-process and the returned delegate is invoked
- **THEN** the native function at `addr` MUST be called directly on the current thread with the delegate's marshalled arguments