通过P/Invoke将以null结尾的字符串作为字节数组发送给WriteProcessMemory()

本文关键字:数组 字节数 字节 WriteProcessMemory Invoke 将以 null 字符串 结尾 通过 | 更新日期: 2023-09-27 18:11:27

我的p/Invoke WriteProcessMemory方法目前是这样的:

        [DllImport("kernel32", SetLastError = true)]
        [return : MarshalAs(UnmanagedType.Bool)]
        static extern bool WriteProcessMemory(
            IntPtr hProcess,
            IntPtr baseAddress,
            byte[] bufferToWrite,
            uint numBytesToWrite,
            out IntPtr numBytesWritten
            );

我需要发送一个字符串到bufferToWrite参数,但它需要一个byte[],所以我在传递它之前将其转换为byte[]

我的问题是,作为。net字符串不是null终止,它不会写一个终止空到远程内存。如果我在非托管代码中这样做,我会分配字符串的长度+终止null,并将所有这些放在分配的内存中,因为我正在读取的"字符串"包括null。但是托管字符串不包含它。

也许我可以分配一个足够大的缓冲区来包含一个终止null,然后再调用WriteProcessMemory来写null;或者我可以创建一个足够大的byte[]来容纳字符串+ null,把它们都写入数组,然后像这样传递给它。

但是对于这个问题是否有更优雅的解决方案呢?

通过P/Invoke将以null结尾的字符串作为字节数组发送给WriteProcessMemory()

像这样声明一个重载:

[DllImport("kernel32", SetLastError = true)]
[return : MarshalAs(UnmanagedType.Bool)]
static extern bool WriteProcessMemory(
    IntPtr hProcess,
    IntPtr baseAddress,
    string bufferToWrite,
    uint numBytesToWrite,
    out uint numBytesWritten
);

这样可以强制编组程序以null终止字符串。

您可以将数据作为IntPtr传递,并使用Marshal.StringToPtrAnsi。但是你需要管理内存。

如果文本是Unicode,则使用CharSet.Unicode选项。

您还可以分配字符串加上空终止符。例如,如果你想写字符串

string szToWrite = "This is what I want to write";

我会将其转换为byte[],例如使用ASCII转换

byte[] aBytes = Encoding.ASCII.GetBytes(szToWrite);

然后将它与一个额外的空字节连接。

aBytes = aBytes.Concat(new byte[] { 0x00 }).ToArray();

如果你想,创建你自己的函数WriteProcessMemoryString,让它接受string而不是byte[],并使用与上面相同的概念。还要注意,你可能想要有一个不同于ASCII的编码,例如UTF7/UTF8,或任何你需要的东西(例如宽字符字符串)。