Today I ran into some old screenshots of a problem I was having in 2013. Interesting problem! I was trying retrieve a piece of data that was located in another process memory space using the ReadProcessMemory API. I defined the API using PInvoke(Platform Invoke), a technique used to call native functions from .NET. The issue I was having was that only under Windows 8 I was getting a NullReferenceException and initially I had no clue why. I was creating a new UnmanagedMemoryObject instance to allocate a piece of unmanaged memory, and then calling ReadProcessMemory, passing a pointer to the native memory block. Suddenly, after the ReadProcessMemory call my unmanagedMemObject variable was NULL resulting in a NullReferenceException. Under Windows 7 the exact same code was running fine. After some time I finally figured out what was causing this specific issue. I defined the ReadProcessMemory API incorrectly:
[DllImport("kernel32.dll"), SetLastError = true] public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, IntPtr nSize, ref int lpNumberOfBytesRead);
And it should have been..
[DllImport("kernel32.dll"), SetLastError = true] public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, IntPtr nSize, ref IntPtr lpNumberOfBytesRead);
See the difference..? The reference to lpNumberOfBytesRead was originally defined as an int instead of an IntPtr. An int is 4 bytes and an IntPtr is 4 or 8 bytes depending on the operating system architecture (32 or 64 bits). So, under 32 bits operating systems the above code would have ran without a problem. Though, under 64 bits operating systems there is the possibility of corruption. What happens is that the API tries to write 8 bytes to the location of the lpNumberOfBytesRead variable. The lpNumberOfBytesRead is only 4 bytes big which results in undesired memory being overwritten.. In case of above example under Windows 8 it was overwriting my reference to unmanagedMemObject causing the unexpected NullReferenceException!
Moral of the story: When using PInvoke statements in your .NET application, double check the signatures 🙂 !!