Add optional Iced backend: arbitrary text assembly and full prologue validation

Section 8 of the whitemagic-foundation change.

- 8.1: reference Iced 1.21.0 behind IcedAssembler:IAssembler. The default
  StubAssembler path never touches Iced; only constructing IcedAssembler pulls
  it into a behavioral path.
- 8.2: IcedAssembler.Assemble bridges Intel-syntax text onto Iced's fluent
  Assembler by reflection (Iced ships no text parser). Registers, immediates and
  labels are supported with origin-relative encoding; memory operands throw
  NotSupportedException.
- 8.3: IcedAssembler.GetPrologueLength decodes arbitrary instructions via Iced's
  Decoder. DetourManager.PrologueLengthResolver (new delegate) defaults to the
  built-in PrologueDecoder and is swappable to the Iced resolver, threaded into
  each Detour. This lifts the "partial boundary safety" caveat on the hooking
  slice when Iced is opted in.

Also gitignore test-run TestResults artifacts.

Tests: 221 passing, 4 skipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
kbe
2026-07-22 08:56:31 +02:00
co-authored by Claude Opus 4.8
parent af7e3dc1b9
commit 30d5a9a5ec
9 changed files with 459 additions and 8 deletions
+10 -2
View File
@@ -16,6 +16,7 @@ namespace WhiteMagic.Hooking;
public sealed class Detour : IDisposable
{
private readonly MemoryBase _memory;
private readonly PrologueLengthResolver _prologueLength;
/// <summary>The unique name of this detour.</summary>
public string Name { get; }
@@ -43,14 +44,21 @@ public sealed class Detour : IDisposable
/// <summary><see langword="true"/> while the detour bytes are live at <see cref="Target"/>.</summary>
public bool IsApplied { get; private set; }
internal Detour(MemoryBase memory, string name, IntPtr target, Delegate hook)
internal Detour(
MemoryBase memory,
string name,
IntPtr target,
Delegate hook,
PrologueLengthResolver prologueLength)
{
ArgumentNullException.ThrowIfNull(hook);
ArgumentNullException.ThrowIfNull(prologueLength);
_memory = memory;
Name = name;
Target = target;
Hook = hook;
_prologueLength = prologueLength;
}
/// <summary>
@@ -83,7 +91,7 @@ public sealed class Detour : IDisposable
"Could not read enough bytes from the target function to install a detour.");
}
int preserveLength = PrologueDecoder.GetWholeInstructionLength(prologue, detourLength, _memory.Is64Bit);
int preserveLength = _prologueLength(prologue, detourLength, _memory.Is64Bit);
OverwrittenBytes = new byte[preserveLength];
Buffer.BlockCopy(prologue, 0, OverwrittenBytes, 0, preserveLength);