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.
85 lines
2.4 KiB
C#
85 lines
2.4 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading.Tasks;
|
|
using WhiteMagic;
|
|
using WhiteMagic.Assembly;
|
|
using WhiteMagic.Native;
|
|
using Xunit;
|
|
|
|
namespace WhiteMagicTest;
|
|
|
|
/// <summary>
|
|
/// Tests for the high-level facade (<see cref="Magic"/>) and <see cref="RemotePointer"/>.
|
|
/// </summary>
|
|
public class HighLevelTests
|
|
{
|
|
private static readonly byte[] AddPayload = [0x89, 0xC8, 0x01, 0xD0, 0xC3];
|
|
|
|
[Fact]
|
|
public void OpenExternal_returns_session_for_current_process()
|
|
{
|
|
using var magic = Magic.Open(Process.GetCurrentProcess());
|
|
Assert.NotNull(magic.Memory);
|
|
Assert.False(magic.Memory.Handle.IsInvalid);
|
|
Assert.Same(magic.Memory.PatchManager, magic.PatchManager);
|
|
Assert.Same(magic.Memory.DetourManager, magic.DetourManager);
|
|
}
|
|
|
|
[Fact]
|
|
public void OpenInProcess_returns_session_for_self()
|
|
{
|
|
using var magic = Magic.OpenInProcess();
|
|
Assert.IsType<InProcessReader>(magic.Memory);
|
|
Assert.False(magic.Memory.Handle.IsInvalid);
|
|
}
|
|
|
|
[Fact]
|
|
public void Indexer_returns_remote_pointer_that_reads_and_writes_relative()
|
|
{
|
|
using var magic = Magic.OpenInProcess();
|
|
byte[] slot = new byte[16];
|
|
GCHandle pin = GCHandle.Alloc(slot, GCHandleType.Pinned);
|
|
try
|
|
{
|
|
IntPtr baseAddr = pin.AddrOfPinnedObject();
|
|
magic[baseAddr + 4].Write(0x12345678);
|
|
Assert.Equal(0x12345678, magic[baseAddr].Read<int>(4));
|
|
}
|
|
finally
|
|
{
|
|
pin.Free();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public async Task RemoteThread_ExecuteAsync_runs_payload_and_returns_result()
|
|
{
|
|
if (!Environment.Is64BitProcess)
|
|
{
|
|
return;
|
|
}
|
|
|
|
using var magic = Magic.OpenInProcess();
|
|
IntPtr payload = NativeMethods.VirtualAllocEx(
|
|
magic.Memory.Handle,
|
|
IntPtr.Zero,
|
|
4096,
|
|
MemoryAllocationType.Commit | MemoryAllocationType.Reserve,
|
|
MemoryProtectionType.ExecuteReadWrite);
|
|
|
|
Assert.NotEqual(IntPtr.Zero, payload);
|
|
|
|
try
|
|
{
|
|
magic.Memory.WriteBytes(payload, AddPayload);
|
|
int result = await magic.RemoteThread.ExecuteAsync<int>(payload, CallConvention.Cdecl, 10, 32);
|
|
Assert.Equal(42, result);
|
|
}
|
|
finally
|
|
{
|
|
NativeMethods.VirtualFreeEx(magic.Memory.Handle, payload, 0, MemoryFreeType.Release);
|
|
}
|
|
}
|
|
}
|