Writing a byte array to an address - c#

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.

Related

What is the hex value of PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON?

I would like to use the UpdateProcThreadAttribute() API call in a C# program, but I can't find the hex value of PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON. I was only able to find (0x00000001ui64 << 44) on Microsoft's website, but I don't know how I can implement this into my code and use it as an IntPtr, according to PInvoke.net.
In C/C++, 0x00000001ui64 is an unsigned 64bit integer with a value of 1, and << 44 is left-shifting that value by 44 bits. A left-shift is equivalent to multiplying by 2, so the result of multiplying 1 by 2 44 times is 17592186044416, which in hex is 0x100000000000UL, or 0x1000_0000_0000UL for readibility.
FYI, C# has the same bit-shift operators that C/C++ has.
LPPROC_THREAD_ATTRIBUTE_LIST is a pointer to a PROC_THREAD_ATTRIBUTE_LIST structure. Call InitializeProcThreadAttributeList() 1 time to determine how large that list needs to be, then allocate memory of that size, and call InitializeProcThreadAttributeList() again to initialize the list.
For example (also see .NET : How to PInvoke UpdateProcThreadAttribute):
const int PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY = 0x20007;
const long PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON = 0x100000000000L;
[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool InitializeProcThreadAttributeList(
IntPtr lpAttributeList,
int dwAttributeCount,
int dwFlags,
ref IntPtr lpSize);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool DeleteProcThreadAttributeList(IntPtr lpAttributeList);
[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UpdateProcThreadAttribute(
IntPtr lpAttributeList,
uint dwFlags,
IntPtr Attribute,
IntPtr lpValue,
IntPtr cbSize,
IntPtr lpPreviousValue,
IntPtr lpReturnSize);
...
IntPtr attrListSize = 0;
InitializeProcThreadAttributeList(
IntPtr.Zero,
1,
0,
ref attrListSize);
IntPtr attrList = Marshal.AllocHGlobal(attrListSize);
InitializeProcThreadAttributeList(
attrList,
1,
0,
ref attrListSize);
IntPtr lpValue = Marshal.AllocHGlobal(sizeof(long));
Marshal.WriteInt64(lpValue, PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON);
UpdateProcThreadAttribute(
attrList,
0,
(IntPtr)PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY,
lpValue,
sizeof(long),
IntPtr.Zero,
IntPtr.Zero
);
// use attrList as needed, ie in STARTUPINFOEX.lpAttributeList ...
DeleteProcThreadAttributeList(attrList);
Marshal.FreeHGlobal(lpValue);
Marshal.FreeHGlobal(attrList);

Get pointer (IntPtr) from a Span<T> staying in safe mode

I would like to use Span and stackalloc to allocate an array of struct and pass it to an interop call. Is it possible to retrieve a pointer (IntPtr) from the Span without being unsafe ?
Here is how i did it without unsafe:
i just changed lpBuffer to ref byte instead of byte[] (for c++ user COULD represent it as uint8_t*)
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool ReadProcessMemory(nint hProcess, nuint lpBaseAddress, ref byte lpBuffer, int dwSize, out int lpNumberOfBytesRead);
Span<byte> bytes = stackalloc byte[8];
// Get reference to first byte in the span (for c++ user we COULD represent it as `uint8_t*`)
ref byte bytesReference = ref MemoryMarshal.AsRef<byte>(bytes);
// You can pass `ref MemoryMarshal.AsRef<byte>(bytes)` to the function directly
bool success = Win32.ReadProcessMemory(_processHandle, address, ref bytesReference, cSize, out int numberOfBytesRead);
lpBuffer could be in byte instead of ref byte as that will allow you to use ReadOnlySpan
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(nint hProcess, nuint lpBaseAddress, in byte lpBuffer, int dwSize, out int lpNumberOfBytesWritten);
ReadOnlySpan<byte> bytes = stackalloc byte[8];
ref readonly byte bytesReference = ref MemoryMarshal.AsRef<byte>(bytes);
// You can pass `in MemoryMarshal.AsRef<byte>(bytes)` to the function directly
Win32.WriteProcessMemory(_processHandle, address, in bytesReference, bytes.Length, out int numberOfBytesWritten);
Notes:
[+] You could use GetPinnableReference instead of MemoryMarshal.AsRef but it is not intended to be called by user code.
[+] ReadProcessMemory Windows API function.
[+] ReadProcessMemory(kernel32) pinvoke Original implementation.

C# WriteProcessMemory strange stackoverflow exception

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();

How to get number of bytes written successfully?

I'm doing a project that convert code from C++ to C# for printer.
I replace WriteFile() in C++ with SerialPort.Write() in C#.
C#
public void Write(
byte[] buffer,
int offset,
int count
)
C++
BOOL WINAPI WriteFile(
_In_ HANDLE hFile,
_In_ LPCVOID lpBuffer,
_In_ DWORD nNumberOfBytesToWrite,
_Out_opt_ LPDWORD lpNumberOfBytesWritten,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
In C++ i can get number of bytes written in lpNumberOfBytesWritten. How to do the same thing in C#?
In c# We can use API call like below,
[DllImport("kernel32.dll")]
static extern bool WriteFile(IntPtr hFile, byte [] lpBuffer,
uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten,
[In] ref System.Threading.NativeOverlapped lpOverlapped);
For more information see http://www.pinvoke.net/default.aspx/kernel32.writefile

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.

Categories