From da342d355ebc504e7027a9449b800e095539ae94 Mon Sep 17 00:00:00 2001 From: Kevin Bataille Date: Wed, 22 Jul 2026 19:12:24 +0200 Subject: [PATCH] Remove legacy BlackMagic specs --- openspec/specs/non-blocking-execute/spec.md | 45 ----------- openspec/specs/text-assembler/spec.md | 88 --------------------- 2 files changed, 133 deletions(-) delete mode 100644 openspec/specs/non-blocking-execute/spec.md delete mode 100644 openspec/specs/text-assembler/spec.md diff --git a/openspec/specs/non-blocking-execute/spec.md b/openspec/specs/non-blocking-execute/spec.md deleted file mode 100644 index e017bb0..0000000 --- a/openspec/specs/non-blocking-execute/spec.md +++ /dev/null @@ -1,45 +0,0 @@ -# non-blocking-execute Specification - -## Purpose -TBD - created by archiving change inject-and-assemble. Update Purpose after archive. -## Requirements -### Requirement: InjectAndExecuteEx creates remote thread without waiting - -`BlackMagic.InjectAndExecuteEx(IntPtr startAddress, IntPtr parameter)` injects code at `startAddress` into the opened process, creates a remote thread with `parameter`, and returns the thread handle immediately without waiting for the thread to exit. - -#### Scenario: successful non-blocking execution -- **WHEN** a process is open and `InjectAndExecuteEx(addr, param)` is called with a valid code address -- **THEN** a remote thread is created in the target process and a valid `SafeMemoryHandle` is returned - -#### Scenario: no process open -- **WHEN** no process is open and `InjectAndExecuteEx(addr, param)` is called -- **THEN** `null` is returned - -### Requirement: InjectAndExecuteEx single-parameter overload - -`BlackMagic.InjectAndExecuteEx(IntPtr startAddress)` calls `InjectAndExecuteEx(startAddress, IntPtr.Zero)`. - -#### Scenario: parameter-less non-blocking execution -- **WHEN** `InjectAndExecuteEx(addr)` is called with a valid address -- **THEN** the thread is created with parameter `IntPtr.Zero` - -### Requirement: InjectAndExecuteEx from assembly text - -`BlackMagic.InjectAndExecuteEx(string asm)` assembles the text via `AsmBuilder`, allocates remote memory, writes the bytes, calls `InjectAndExecuteEx` on the allocated address, and returns the thread handle. - -#### Scenario: execute assembly text non-blocking -- **WHEN** `InjectAndExecuteEx("nop")` is called with a process open -- **THEN** the text is assembled to bytes, written to remote memory, a thread is started, and the handle is returned - -#### Scenario: assembly failure -- **WHEN** `InjectAndExecuteEx("invalidinstruction")` is called -- **THEN** `ArgumentException` is thrown with the assembly error - -### Requirement: InjectAndExecute from assembly text (blocking convenience) - -`BlackMagic.InjectAndExecute(string asm)` assembles the text, allocates remote memory, writes the bytes, calls `Execute` (blocking, 10s timeout), and returns the exit code. - -#### Scenario: execute assembly text blocking -- **WHEN** `InjectAndExecute("mov eax, 42\nret")` is called with a process open -- **THEN** the text is assembled, injected, executed, and the thread exit code is returned - diff --git a/openspec/specs/text-assembler/spec.md b/openspec/specs/text-assembler/spec.md deleted file mode 100644 index 64d24ef..0000000 --- a/openspec/specs/text-assembler/spec.md +++ /dev/null @@ -1,88 +0,0 @@ -# text-assembler Specification - -## Purpose -TBD - created by archiving change inject-and-assemble. Update Purpose after archive. -## Requirements -### Requirement: AsmBuilder assembles x86 instruction text to byte array - -`AsmBuilder.Assemble(string source)` parses x86 assembly text and returns the corresponding `byte[]` machine code. - -#### Scenario: single instruction -- **WHEN** `AsmBuilder.Assemble("nop")` is called -- **THEN** the result is `[0x90]` - -#### Scenario: multiple instructions -- **WHEN** `AsmBuilder.Assemble("pushad\npopad")` is called -- **THEN** the result is `[0x60, 0x61]` - -#### Scenario: instruction with immediate operand -- **WHEN** `AsmBuilder.Assemble("mov eax, 1")` is called -- **THEN** the result is `[0xB8, 0x01, 0x00, 0x00, 0x00]` - -### Requirement: AsmBuilder supports register operands - -Supported registers: `eax`, `ecx`, `edx`, `ebx`, `esp`, `ebp`, `esi`, `edi` (and 8-bit: `al`, `cl`, `dl`, `bl`, `ah`, `ch`, `dh`, `bh`). - -#### Scenario: register-to-register move -- **WHEN** `AsmBuilder.Assemble("mov eax, ecx")` is called -- **THEN** the result is `[0x89, 0xC8]` (mov eax, ecx encoding) - -#### Scenario: register encoding -- **WHEN** registers are used in instructions -- **THEN** each register maps to its correct 3-bit encoding (eax=0, ecx=1, edx=2, ebx=3, esp=4, ebp=5, esi=6, edi=7) - -### Requirement: AsmBuilder supports labels and jumps - -Labels are defined with `@name:` and referenced with `jmp @name` or `je @name`. Forward and backward references are resolved in a second pass. - -#### Scenario: forward jump -- **WHEN** `AsmBuilder.Assemble("jmp @skip\nnop\n@skip:\nret")` is called -- **THEN** the jump skips exactly over the `nop` (2 bytes) and lands on `ret` - -#### Scenario: backward jump -- **WHEN** `AsmBuilder.Assemble("@loop:\nnop\njmp @loop")` is called -- **THEN** the jump targets the earlier label correctly - -#### Scenario: multiple labels -- **WHEN** multiple labels are used in one source -- **THEN** each label resolves to its correct byte offset - -### Requirement: AsmBuilder SetPassLimit controls iteration - -`AsmBuilder.SetPassLimit(int limit)` sets the maximum number of assembly passes for label resolution. Default is 10. If the limit is exceeded before all labels resolve, `InvalidOperationException` is thrown. - -#### Scenario: default pass limit -- **WHEN** no `SetPassLimit` is called -- **THEN** the assembler uses 10 passes maximum - -#### Scenario: custom pass limit -- **WHEN** `SetPassLimit(20)` is called -- **THEN** the assembler uses 20 passes maximum - -#### Scenario: pass limit exceeded -- **WHEN** forward references cannot resolve within the pass limit -- **THEN** `InvalidOperationException` is thrown with label resolution details - -### Requirement: AsmBuilder reports clear errors - -Unknown instructions, missing operands, and invalid register names produce `ArgumentException` with the line number and offending text. - -#### Scenario: unknown instruction -- **WHEN** `AsmBuilder.Assemble("xyzw")` is called -- **THEN** `ArgumentException` is thrown mentioning line 1 and "xyzw" - -#### Scenario: missing operand -- **WHEN** `AsmBuilder.Assemble("mov")` is called (no operands) -- **THEN** `ArgumentException` is thrown mentioning missing operand - -### Requirement: AsmBuilder supported instruction set - -The following x86 instructions are supported: -- **Data movement**: `mov`, `push`, `pop`, `pushad`, `popad`, `lea` -- **Arithmetic**: `add`, `sub`, `inc`, `dec`, `xor`, `and`, `or`, `cmp`, `test` -- **Control flow**: `jmp`, `je`, `jne`, `call`, `ret`, `nop`, `hlt` - -#### Scenario: all instructions produce valid bytes -- **WHEN** each supported instruction is assembled individually -- **THEN** it produces the correct x86 machine code encoding -