C# WriteProcessMemory strange stackoverflow exception - c#

I'm using WinAPI function WriteProcessMemory from kernel32.dll to write to another process' memory.
It worked good for a few times, but then it just stopped working correctly.
I'm importing this function with this code:
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out int lpNumberOfBytesWritten);
And here's code that I'm using to write:
int bytesWritten;
WriteProcessMemory(hProcess, (IntPtr)dwAdress, data, (uint)size, out bytesWritten);
It just throws this exception:
System.OverflowException
Debug info:
debug info
Can anyone help me with this problem?

Your p/invoke is declared incorrectly. The final two parameters are SIZE_T, which is pointer sized. Your code should be:
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
byte[] lpBuffer,
UIntPtr nSize,
out UIntPtr lpNumberOfBytesWritten
);
Note that SIZE_T is an unsigned type, hence the use of UIntPtr. If using an unsigned type is not convenient you could switch the above to use IntPtr instead since you are never going to write more then 263 bytes.
The code that you presented does not test the return value of WriteProcessMemory. Please always checked return values for errors. For instance:
if (!WriteProcessMemory(...))
throw new Win32Exception();

Related

Writing a byte array to an address

Deleted my old post and decided to reupload with more direct questions.
I'm trying to write bytes to a memory address for my C# menu, writing singular a singular byte or int isn't an issue. I have an issue trying to write multiple bytes.
The code below is writing a singular byte to increase the player speed to 555, which works perfectly fine.
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, out IntPtr lpNumberOfBytesWritten);
byte[] memory = { 555 };
WriteProcessMemory(Game.hProc, Player.PlayerSpeedOffSet, memory, memory.Length, out _);
The part I'm having issues with is when I try and write multiple bytes to an address.
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, out IntPtr lpNumberOfBytesWritten);
byte[] memory = { 90, 90, 90 };
WriteProcessMemory(Game.hProc, Player.UnlimitedAmmoOffSet, memory, memory.Length, out _);
"90 90 90" being unlimted ammo and to disable it, i'd write to the same address with "89 50 04".
This worked just fine with memory.dll so the handle and offset is just fine, it's just something to do with my writing to memory.
Look at the definition of the function WriteProcessMemory:
BOOL WriteProcessMemory(
HANDLE hProcess,
LPVOID lpBaseAddress,
LPCVOID lpBuffer,
SIZE_T nSize,
SIZE_T *lpNumberOfBytesWritten
);
Note the type of the nSize parameter, it's SIZE_T. How wide is this type? You can look it up here: https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
typedef ULONG_PTR SIZE_T;
Okay, then what is the width of ULONG_PTR? The same documentation tells:
#if defined(_WIN64)
typedef unsigned __int64 ULONG_PTR;
#else
typedef unsigned long ULONG_PTR;
#endif
So, its either 32 bits or 64 bits wide, depending on whether the process calling this function is a 32-bit or 64-bit process. (In Windows, unsigned long is 32-bit wide.)
Now look at your P/Invoke definition:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, out IntPtr lpNumberOfBytesWritten);
You have defined nSize as a 32-bit integer. If your program is compiled to run as a 32-bit process, you got lucky and the 32-bit integer matches the 32-bit SIZE_T.
But if your program is running as a 64-bit process, your 32-bit integer does not match the 64-bit SIZE_T.
I hope using IntPtr instead of int for the nSize parameter should fix your issue.

Memory access violation while passing void* param to DLL function

I'm adding new disk device to system from my C# code, so I want to call
[System.Runtime.InteropServices.DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public extern static void SHChangeNotify(long wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2);
like below
MyWin32Functions.SHChangeNotify(0x00000100/*ADDRIVE*/, 0x0005/*PATHW*/, driveLetter, IntPtr.Zero);
dwItem1 is void* and we should pass a wchar_t* (pointing to null terminated string) containing drive root in this case; so driveLetter above is
string letter = "Z:\\";
byte[] data = Encoding.Default.GetBytes(letter);
byte[] zdata = new byte[data.Length + 1];
data.CopyTo(zdata, 0);
IntPtr p = System.Runtime.InteropServices.Marshal.AllocHGlobal(zdata.Length);
System.Runtime.InteropServices.Marshal.Copy(zdata, 0, p, zdata.Length);
(my code almost same as code in similiar case: How to call SHChangeNotify from C# without error 14007
but I get System.AccessViolationException)
Any suggestions what am I doing wrong?
The first parameter in your interop signature should be an int, not a long. Though the Win32 function is declared as LONG, a LONG in Win32 is 32-bit.
[System.Runtime.InteropServices.DllImport("Shell32.dll")]
public extern static void SHChangeNotify(int wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2);
This MSDN article shows the common mapping between Win32 types an .NET types for Platform Invoke.

convert C++ code to C#: SendMessageTimeout()

First of all docu for SendMessageTimeout:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644952%28v=vs.85%29.aspx
i have this C++ code and i want to convert it to C#:
LRESULT success = SendMessageTimeout(
HWND_BROADCAST,
WM_SETTINGCHANGE,
0,
(LPARAM) "Environment",
SMTO_ABORTIFHUNG,
5000,
NULL
);
What i did in C#:
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(
IntPtr hWnd,
uint Msg,
UIntPtr wParam,
IntPtr lParam,
uint fuFlags,
uint uTimeout,
out UIntPtr lpdwResult
);
SendMessageTimeout(
(IntPtr)0xFFFFFFFF, //HWND_BROADCAST
0x001A, //WM_SETTINGCHANGE
(UIntPtr)0,
(IntPtr)"Environment", // ERROR_1: can't convert string to IntPtr
0x0002, // SMTO_ABORTIFHUNG
5000,
out UIntPtr.Zero // ERROR_2: a static readonly field can not be passed ref or out
);
For your issues.
HWND_BROADCAST is 0xFFFF not 0xFFFFFFFF
You will have to allocate memory for the LPARAM value manually using Marshal.StringToHGlobalUni and then free it after the call using Marshal.FreeHGlobal. You must free this memory or it will leak. Marshal'd memory is not garbage collected.
For lpdwResult just create an IntPtr variable and pass that in. You can just ignore its value.
The code should be something like this:
IntPtr result = IntPtr.Zero;
IntPtr setting = Marshal.StringToHGlobalUni("Environment");
SendMessageTimeout(
(IntPtr)0xFFFF, //HWND_BROADCAST
0x001A, //WM_SETTINGCHANGE
(UIntPtr)0,
(IntPtr)setting,
0x0002, // SMTO_ABORTIFHUNG
5000,
out result
);
Marshal.FreeHGlobal(setting);
In general you need to be careful when freeing memory that you pass to a SendMessage call since you don't know what the receving window will do with the pointer that you pass to it. Howerver since WM_SETTINGCHANGE is a built in Windows message, Windows will handle this pointer for you.
SendMessage is a bit painful due to the non-descript argument types it uses. Necessary because it needs to do many jobs. Necessary in the C language, but not in C#. What you want to do here is take advantage of the C# language supporting overloads. The IntPtr arguments can just be reference type references, the pinvoke marshaller will properly convert them to a pointer and take care of the memory management hassle. So just craft another one that's compatible with the way you want to use it:
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(
IntPtr hWnd,
int Msg,
IntPtr wParam,
string lParam,
int fuFlags,
int uTimeout,
IntPtr lpdwResult
);
Now you can use:
SendMessageTimeout((IntPtr)0xffff, 0x001A, IntPtr.Zero, "Environment",
2, 5000, IntPtr.Zero);

Writing a memory scanner in C#

I'm trying to make a memory scanner in C#. I heard that I need the API functions WriteProcessMemory and ReadProcessMemory.
I called them :
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
byte[] lpBuffer,
UInt32 nSize,
ref UInt32 lpNumberOfBytesRead
);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
byte[] lpBuffer,
uint nSize,
out UIntPtr lpNumberOfBytesWritten);
All the examples for memory scanners I found on Google were very hard to understand. I've read a lot of articles saying that to find value addr you need to search at any memory byte. Now I need to get the program to open the process for reading and writing from memory.
Can I do that with GetProcessByName?
Yes, like so:
Process[] process = Process.GetProcessesByName("cmd");
byte[] memory = new byte[255];
uint bytesRead =0;
bool succes = ReadProcessMemory(
process[0].Handle,
process[0].MainModule.BaseAddress ,
memory ,
(uint) memory.Length ,
ref bytesRead);
You have to check if success is true. If not you have read nothing.

Need to use win32 api to copy files in c# - how do I do this?

I'm trying to copy some files around, and occasionally the lengths of the names exceeds the length that the System.IO.File.Copy method can accept (260 chars according to the exception that is getting thrown)
According to the research I've done, I should be able to use the win32 api's file methods in conjunction with \?\ prepended to paths to get a 32,000 character limit, but I'm not sure witch methods I need to import.
Can someone help me with this? I'm looking for something like (obviously a different function, but you get the idea):
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern SafeFileHandle CreateFileW(string lpFileName, uint dwDesiredAccess,
uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll",
CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.StdCall,
SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CopyFile(
[MarshalAs(UnmanagedType.LPWStr)] string lpExistingFileName,
[MarshalAs(UnmanagedType.LPWStr)] string lpNewFileName,
[MarshalAs(UnmanagedType.Bool)] bool bFailIfExists);
http://www.pinvoke.net/default.aspx/kernel32/CopyFile.html
Try using CopyFile.
For PInvoke syntax, you can check pinvoke.net.

Categories