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); } }