using System.Runtime.InteropServices; using WhiteMagic.Native; namespace WhiteMagic; /// /// Shared ReadProcessMemory / WriteProcessMemory wrappers used by both /// and . Kept in a single /// location to keep the two readers byte-for-byte consistent on partial-read handling, /// write-return semantics, and failure modes. /// internal static class RpmHelper { /// /// Reads up to bytes from in /// the process identified by . Returns: /// /// An empty array if fails and /// reports zero bytes read. /// A truncated array of exactly bytesRead bytes when the call returns /// but the OS has placed a partial copy in the buffer /// (for example, ERROR_PARTIAL_COPY). /// The full buffer on success. /// /// public static byte[] ReadBytes(SafeMemoryHandle handle, IntPtr address, int count) { byte[] buffer = new byte[count]; bool ok = NativeMethods.ReadProcessMemory(handle, address, buffer, count, out nint bytesRead); if (!ok && bytesRead == 0) { return []; } if ((int)bytesRead < count) { // Either a successful short read, or a failed-but-partial RPM. In both // cases honor the bytes the OS actually produced rather than padding. byte[] partial = new byte[(int)bytesRead]; Buffer.BlockCopy(buffer, 0, partial, 0, (int)bytesRead); return partial; } return buffer; } /// /// Writes to in the process /// identified by . Returns the number of bytes actually /// written, or 0 on total failure. /// public static int WriteBytes(SafeMemoryHandle handle, IntPtr address, ReadOnlySpan bytes) { if (!NativeMethods.WriteProcessMemory(handle, address, bytes, bytes.Length, out nint written)) { return 0; } return (int)written; } }