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.
58 lines
3.3 KiB
Markdown
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
|