using System.Runtime.InteropServices;
using WhiteMagic.Native;
namespace WhiteMagic.ProcessEnvironment;
///
/// Managed reader for a target process's Process Environment Block (PEB).
///
public sealed class ManagedPeb
{
private readonly MemoryBase _memory;
private readonly IntPtr _pebAddress;
///
/// Creates a PEB reader for the process associated with the specified memory facade.
///
public ManagedPeb(MemoryBase memory)
{
_memory = memory ?? throw new ArgumentNullException(nameof(memory));
_pebAddress = QueryPebAddress();
}
/// Returns the native address of the PEB in the target process.
public IntPtr ReadPebAddress() => _pebAddress;
/// Reads the BeingDebugged byte from the PEB.
public byte ReadBeingDebugged()
{
return _memory.Read(_pebAddress + 2);
}
/// Reads the ImageBaseAddress pointer from the PEB.
public IntPtr ReadImageBaseAddress()
{
int offset = _memory.Is64Bit ? 0x10 : 0x08;
return ReadPointer(offset);
}
/// Reads the PEB_LDR_DATA pointer from the PEB.
public IntPtr ReadLdrAddress()
{
int offset = _memory.Is64Bit ? 0x18 : 0x0C;
return ReadPointer(offset);
}
///
/// Determines whether the target process is running under WOW64.
///
public bool ReadIsWow64Process()
{
if (!NativeMethods.IsWow64Process(_memory.Handle, out bool wow64))
{
int error = Marshal.GetLastPInvokeError();
throw new InvalidOperationException($"IsWow64Process failed with error {error}.");
}
return wow64;
}
private IntPtr QueryPebAddress()
{
var info = new ProcessBasicInformation();
int status = NativeMethods.NtQueryInformationProcess(
_memory.Handle,
0,
ref info,
(uint)Marshal.SizeOf(),
out _);
if (status < 0 || info.PebBaseAddress == IntPtr.Zero)
{
throw new InvalidOperationException(
$"NtQueryInformationProcess failed to retrieve the PEB (NTSTATUS {status:X8}).");
}
return info.PebBaseAddress;
}
private IntPtr ReadPointer(int offset)
{
IntPtr address = _pebAddress + offset;
if (_memory.Is64Bit)
{
ulong raw = _memory.Read(address);
return new IntPtr((long)raw);
}
uint raw32 = _memory.Read(address);
return new IntPtr((int)raw32);
}
}