Implement core diagnostic memory layer, execution helpers, and high-level facade slices

Implemented:
- Core: UTF-16 ReadString boundary/alignment fix, target bitness and process id on MemoryBase
- function interception: PatchManager, DetourManager, InstructionAnalyzer, MainThreadDispatcher
- Execution: BackgroundTaskExecutor, InProcessInvoker
- High-level: Magic facade, RemotePointer, async wrappers
- Discovery/external code loading/Window groundwork (PEB/TEB, pattern scanning, raw allocations, DLL external code loading, window/input)

Tests: 180 passing, 4 integration/interactive tests skipped.
This commit is contained in:
kbe
2026-07-21 23:43:14 +02:00
parent a0ca7050a2
commit 3f0bea6bd4
44 changed files with 5595 additions and 84 deletions
+24 -4
View File
@@ -1,4 +1,5 @@
using System.Diagnostics;
using Process = System.Diagnostics.Process;
using System.Runtime.InteropServices;
using WhiteMagic.Native;
@@ -13,6 +14,8 @@ public sealed class ExternalReader : MemoryBase
{
private readonly SafeMemoryHandle _handle;
private readonly IntPtr _imageBase;
private readonly bool _is64Bit;
private readonly int _processId;
private bool _disposed;
/// <summary>
@@ -31,16 +34,27 @@ public sealed class ExternalReader : MemoryBase
/// <param name="process">The target process.</param>
/// <param name="desiredAccess">The access rights to request. Defaults to
/// <see cref="DefaultAccess"/>.</param>
public ExternalReader(Process process, ProcessAccess desiredAccess = DefaultAccess)
public ExternalReader(System.Diagnostics.Process process, ProcessAccess desiredAccess = DefaultAccess)
{
_handle = NativeMethods.OpenProcess(desiredAccess, false, process.Id);
_processId = process.Id;
_handle = NativeMethods.OpenProcess(desiredAccess, false, _processId);
if (_handle.IsInvalid)
{
int error = Marshal.GetLastPInvokeError();
throw new InvalidOperationException(
$"OpenProcess failed for PID {process.Id}: error {error}");
$"OpenProcess failed for PID {_processId}: error {error}");
}
// Derive target bitness. A 64-bit host sees a 32-bit target as WOW64.
// A 32-bit host can only open 32-bit targets. If the API fails, fall
// back to the current process bitness (self-open path).
if (!NativeMethods.IsWow64Process(_handle, out bool wow64))
{
wow64 = false;
}
_is64Bit = Environment.Is64BitProcess && !wow64;
// Process.MainModule throws Win32Exception for a bitness-mismatched or protected
// target. A missing image base must not sink the whole reader — callers can still
// use absolute addresses when ImageBase is unknown.
@@ -60,6 +74,12 @@ public sealed class ExternalReader : MemoryBase
/// <inheritdoc />
public override SafeMemoryHandle Handle => _handle;
/// <inheritdoc />
public override bool Is64Bit => _is64Bit;
/// <inheritdoc />
public override int ProcessId => _processId;
/// <inheritdoc />
public override byte[] ReadBytes(IntPtr address, int count, bool isRelative = false)
{
@@ -84,7 +104,7 @@ public sealed class ExternalReader : MemoryBase
if (!_disposed)
{
_disposed = true;
_handle.Dispose();
base.Dispose();
}
}
}