0

我有一个MemRead读取内存并返回字节数组的方法

[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref byte lpBuffer, int dwSize, out int lpNumberOfBytesRead);


public static Span<byte> MemRead(this Process process, IntPtr address, int size)
{
if (process == null)
    throw new ArgumentException("Process is null");

Span<byte> buffer = new byte[size];
bool success = NativeMethods.ReadProcessMemory(process.Handle, address, ref MemoryMarshal.GetReference(buffer), size, out int lpNumberOfBytesRead);

if (!success)
    throw new Exception("ReadProcessMemory failed");

if (lpNumberOfBytesRead < size)
    throw new Exception($"ReadProcessMemory failed : {lpNumberOfBytesRead} bytes read out of {size}");

return buffer;
}

而且我有方法MemReadInt32,,MemReadBool...调用MemRead并进行转换

public static int MemReadInt32(this Process process, IntPtr address)
{
    return BitConverter.ToInt32(MemRead(process, address, 4));
}

现在我想在堆栈而不是堆上分配缓冲区,所以我更改了这一行

Span<byte> buffer = new byte[size];

Span<byte> buffer = stackalloc byte[size];

编译器会抛出错误,因为堆栈分配的数组不能暴露在声明范围之外。这是有道理的,这可以防止潜在的堆提升。

但是后来我不得不将转换代码放在与阅读代码相同的方法中。MemReadInt32并且每个, MemReadBool, ...都会重复读取代码

我怎样才能避免重复ReadMem代码,并且仍然获得堆栈分配?

4

1 回答 1

0

这是一个非常简单的解决方案,所以我可能会遗漏一些东西,但是为什么不将缓冲区作为参数呢?然后,您可以在调用者函数中 stackalloc 正确大小的 Span。否则我不认为有一种方法,因为函数的堆栈空间在返回后无法访问(除非将指针传递出去并希望数组仍然存在 - 尽管经过一些测试它似乎从未存在 - 也许 CLR覆盖它作为安全预防措施?)

于 2021-09-30T13:51:46.887 回答