通过P / Invoke

时间:2015-09-04 18:36:23

标签: c# interop pinvoke

我的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。但是托管字符串并不包含它。

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

但这个问题有更优雅的解决方案吗?

2 个答案:

答案 0 :(得分:2)

声明一个像这样的重载:

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

这样就强制marshaller将null终止字符串。

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

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

答案 1 :(得分:0)

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

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,或者你本地需要的任何东西(例如宽字符串)。