Search code examples
c#interoppinvoke

Send null terminated string as byte array to WriteProcessMemory() via P/Invoke


My P/Invoke WriteProcessMemory method currently looks like this:

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

I need to send a string to the bufferToWrite parameter, but it takes a byte[] so I'm converting it to a byte[] before passing it in.

My issue is that as .NET strings aren't null terminated, it won't write a terminating null to the remote memory. If I was doing this in unmanaged code I'd allocate the length of the string + terminating null, and put all that in the allocated memory since the "string" I'm reading includes the null. But the managed string doesn't include it.

Maybe I could allocate a buffer large enough to include a terminating null, then do another call to WriteProcessMemory to write the null; or I could create a byte[] large enough to hold the string + null, write both to the array, and pass it in like that.

But is there a more elegant solution to this problem?


Solution

  • Declare an overload like this:

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

    That way you force the marshaller to null terminate the string.

    You could pass the data as IntPtr and use Marshal.StringToPtrAnsi. But then you'd need to manage the memory.

    If the text is Unicode, use the CharSet.Unicode option.