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>
65 lines
2.1 KiB
C#
65 lines
2.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace WhiteMagic.Hooking;
|
|
|
|
/// <summary>
|
|
/// Manages named inline detours against a <see cref="MemoryBase"/>.
|
|
/// Detours only work when operating in-process; applying a detour to an
|
|
/// external target will fail because the hook delegate lives in the host process.
|
|
/// </summary>
|
|
public sealed class DetourManager
|
|
{
|
|
private readonly MemoryBase _memory;
|
|
private readonly Dictionary<string, Detour> _detours = new();
|
|
|
|
/// <summary>Creates a detour manager bound to the supplied memory reader.</summary>
|
|
public DetourManager(MemoryBase memory)
|
|
{
|
|
_memory = memory;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resolves how many whole prologue-instruction bytes a splice must preserve. Defaults
|
|
/// to the built-in <see cref="PrologueDecoder"/>, which covers only the common prologue
|
|
/// shapes and rejects anything else. Assign <c>new IcedAssembler().GetPrologueLength</c>
|
|
/// to validate arbitrary prologues via the optional Iced disassembler.
|
|
/// </summary>
|
|
public PrologueLengthResolver PrologueLengthResolver { get; set; } =
|
|
PrologueDecoder.GetWholeInstructionLength;
|
|
|
|
/// <summary>
|
|
/// Creates a new detour and registers it with the manager.
|
|
/// The <paramref name="hook"/> delegate's type must match the native signature of
|
|
/// <paramref name="target"/>.
|
|
/// </summary>
|
|
public Detour Create(string name, IntPtr target, Delegate hook)
|
|
{
|
|
var detour = new Detour(_memory, name, target, hook, PrologueLengthResolver);
|
|
_detours[name] = detour;
|
|
return detour;
|
|
}
|
|
|
|
/// <summary>Looks up a detour by name.</summary>
|
|
public Detour? this[string name]
|
|
{
|
|
get
|
|
{
|
|
_detours.TryGetValue(name, out Detour? detour);
|
|
return detour;
|
|
}
|
|
}
|
|
|
|
/// <summary>All detours registered in this manager.</summary>
|
|
public IEnumerable<Detour> All => _detours.Values;
|
|
|
|
/// <summary>Removes every applied detour, restoring original bytes.</summary>
|
|
public void RemoveAll()
|
|
{
|
|
foreach (Detour detour in _detours.Values)
|
|
{
|
|
detour.Remove();
|
|
}
|
|
}
|
|
}
|