Skip to content

Instantly share code, notes, and snippets.

@BinToss
Last active May 11, 2023 04:31
Show Gist options
  • Save BinToss/5a82780d171b54873befe792b6aa98aa to your computer and use it in GitHub Desktop.
Save BinToss/5a82780d171b54873befe792b6aa98aa to your computer and use it in GitHub Desktop.
What happens if we supply a buffer to ReadProcessMemory, but it's smaller than the requested amount of bytes?
#!meta
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
#!csharp
/** Q: What happens if we supply a buffer to ReadProcessMemory, but it's smaller than the requested amount of bytes?
A: The buffer is filled to capacity and the Read operation continues until it has read the specified amount of bytes.
*/
using Microsoft.DotNet.Interactive;
using Microsoft.Win32.SafeHandles;
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
unsafe
{
BOOL succ = false;
ulong bigboi= ulong.MaxValue;
HANDLE h = new(nint.MaxValue);
var gch = GCHandle.Alloc(h, GCHandleType.Pinned);
nuint lpNumberOfBytesRead;
succ = ReadProcessMemory(System.Diagnostics.Process.GetCurrentProcess().SafeHandle, &bigboi, (void*)gch.AddrOfPinnedObject(), 80, &lpNumberOfBytesRead);
((bool)succ).Display();
new System.ComponentModel.Win32Exception().ToString().Display();
h.Display();
lpNumberOfBytesRead.Display();
/** OUTPUT:
True
System.ComponentModel.Win32Exception (0x80004005): The operation completed successfully.
Submission#3+HANDLE
IsNull
False
Value
9223372036854775807
80
*/
}
public readonly partial struct HANDLE : IEquatable<HANDLE>
{
public readonly IntPtr Value;
public HANDLE(IntPtr value) => this.Value = value;
public static HANDLE Null => default;
public bool IsNull => Value == default;
public static implicit operator IntPtr(HANDLE value) => value.Value;
public static explicit operator HANDLE(IntPtr value) => new HANDLE(value);
public static bool operator ==(HANDLE left, HANDLE right) => left.Value == right.Value;
public static bool operator !=(HANDLE left, HANDLE right) => !(left == right);
public bool Equals(HANDLE other) => this.Value == other.Value;
public override bool Equals(object obj) => obj is HANDLE other && this.Equals(other);
public override int GetHashCode() => this.Value.GetHashCode();
}
public readonly partial struct BOOL : IEquatable<BOOL>
{
public readonly int Value;
public BOOL(int value) => this.Value = value;
public static implicit operator int(BOOL value) => value.Value;
public static explicit operator BOOL(int value) => new BOOL(value);
public static bool operator ==(BOOL left, BOOL right) => left.Value == right.Value;
public static bool operator !=(BOOL left, BOOL right) => !(left == right);
public bool Equals(BOOL other) => this.Value == other.Value;
public override bool Equals(object obj) => obj is BOOL other && this.Equals(other);
public override int GetHashCode() => this.Value.GetHashCode();
public BOOL(bool value) => this.Value = value ? 1 : 0;
public static implicit operator bool(BOOL value) => value.Value != 0;
public static implicit operator BOOL(bool value) => new BOOL(value);
}
/// <inheritdoc cref="ReadProcessMemory(HANDLE, void*, void*, nuint, nuint*)"/>
[SupportedOSPlatform("windows5.1.2600")]
public static unsafe BOOL ReadProcessMemory(SafeHandle hProcess, void* lpBaseAddress, void* lpBuffer, nuint nSize, nuint* lpNumberOfBytesRead)
{
bool hProcessAddRef = false;
try
{
HANDLE hProcessLocal;
if (hProcess is object)
{
hProcess.DangerousAddRef(ref hProcessAddRef);
hProcessLocal = (HANDLE)hProcess.DangerousGetHandle();
}
else
throw new ArgumentNullException(nameof(hProcess));
return ReadProcessMemory(hProcessLocal, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead);
}
finally
{
if (hProcessAddRef)
hProcess.DangerousRelease();
}
}
/// <summary>Reads data from an area of memory in a specified process. The entire area to be read must be accessible or the operation fails.</summary>
/// <param name="hProcess">A handle to the process with memory that is being read. The handle must have PROCESS_VM_READ access to the process.</param>
/// <param name="lpBaseAddress">A pointer to the base address in the specified process from which to read. Before any data transfer occurs, the system verifies that all data in the base address and memory of the specified size is accessible for read access, and if it is not accessible the function fails.</param>
/// <param name="lpBuffer">A pointer to a buffer that receives the contents from the address space of the specified process.</param>
/// <param name="nSize">The number of bytes to be read from the specified process.</param>
/// <param name="lpNumberOfBytesRead">A pointer to a variable that receives the number of bytes transferred into the specified buffer. If *lpNumberOfBytesRead* is **NULL**, the parameter is ignored.</param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero. If the function fails, the return value is 0 (zero). To get extended error information, call [GetLastError](../errhandlingapi/nf-errhandlingapi-getlasterror.md). The function fails if the requested read operation crosses into an area of the process that is inaccessible.</para>
/// </returns>
/// <remarks>
/// <para><see href="https://docs.microsoft.com/windows/win32/api//memoryapi/nf-memoryapi-readprocessmemory">Learn more about this API from docs.microsoft.com</see>.</para>
/// </remarks>
[DllImport("KERNEL32.dll", ExactSpelling = true, SetLastError = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
[SupportedOSPlatform("windows5.1.2600")]
public static extern unsafe BOOL ReadProcessMemory(HANDLE hProcess, void* lpBaseAddress, void* lpBuffer, nuint nSize, [Optional] nuint* lpNumberOfBytesRead);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment