How to get number of bytes written successfully? - c#

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

Related

Speed up C# native call pinvoke

mod note: I do not believe this to be a duplicate, due to me having already tried several mentioned solutions as described below.
Is there a way I can speed this up? I've already followed the Microsoft guides on this, and here's what I've done:
Added SuppressUnmanagedCodeSecurity
Placed this in a file named UnsafeNativeMethods.cs
Defined specific types for the method stub
Here is the method:
[DllImport("kernel32.dll")]
[SuppressUnmanagedCodeSecurity]
public static extern bool DeviceIoControl(
IntPtr hDevice,
uint IoControlCode,
[In] MemoryManager.MemOperation InBuffer,
int nInBufferSize,
[Out] byte[] OutBuffer,
uint nOutBufferSize,
ref int pBytesReturned,
IntPtr Overlapped
);
Here is the contents of MemOperation (the inbuffer that has to be marshal'd I'm guessing):
public struct MemOperation
{
public int Pid;
public int UserPid;
public int Size;
public int protection_mode;
public int allocation_type;
public IntPtr Addr;
public IntPtr WriteBuffer;
[MarshalAs(UnmanagedType.LPWStr)]
public string module_selection;
}
Here's is an example of usage:
public UnsafeNativeMethods.MEMORY_BASIC_INFORMATION QueryVirtualMemory(IntPtr address) {
var memOperation = new MemOperation();
byte[] buffer = new byte[48]; // 8 + 8 + 4 + 8 + 4 + 4 + 4 MEMORY_BASIC_INFORMATION
memOperation.Pid = this.Pid;
memOperation.Addr = address;
int bytes = 0;
bool res = UnsafeNativeMethods.DeviceIoControl(this.Handle, CtlCode(0x00000022, this.IOCTL_QUERY, 2, 0), memOperation, Marshal.SizeOf(memOperation), buffer, (uint)buffer.Length, ref bytes, IntPtr.Zero);
return GetStructure<UnsafeNativeMethods.MEMORY_BASIC_INFORMATION>(buffer);
}
In the profiler, my hotpath is the pinvoke. My application runs incredibly fast, as fast I think it can in C#. However, almost a third of all execution time is spent pinvoking due to how many memory operations the application is doing. I would like to cut this time down in any way possible, including unsafe ways.
I have seen that you can instead write a DeviceIoControl wrapper and import it from a C++ dll, however this did not lead to any changes for me, it appeared to function the exact same. Here's the source for that:
devicecontrol.cpp
#include <iostream>
#include "DeviceControl.h"
bool __cdecl DeviceIoRequestWrapper(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlappedk)
{
return DeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlappedk);
}
devicecontrol.h
#pragma once
#include <Windows.h>
extern "C" {
__declspec(dllexport) bool __cdecl DeviceIoRequestWrapper(
HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlappedk);
}
I am on .net 6.0 and the latest version of C#.
Proposed change to out buffer:
public unsafe UnsafeNativeMethods.MEMORY_BASIC_INFORMATION QueryVirtualMemory(IntPtr address) {
var memOperation = new MemOperation();
byte* buffer = stackalloc byte[48];
memOperation.Pid = this.Pid;
memOperation.Addr = address;
int bytes = 0;
bool res = UnsafeNativeMethods.DeviceIoControl(this.Handle, CtlCode(0x00000022, this.IOCTL_QUERY, 2, 0), memOperation, Marshal.SizeOf(memOperation), (IntPtr)buffer, 48, ref bytes, IntPtr.Zero);
return GetStructure<UnsafeNativeMethods.MEMORY_BASIC_INFORMATION>(buffer);
}
Where GetStructure is now:
public static unsafe T GetStructure<T>(byte* bytes) where T: unmanaged {
T structure = *(T*)bytes;
return structure;
}
Here's what helped the most and I'll accept this as the answer to my own thread in a few hours.
In addition to the above steps I mentioned, I have now done the following:
Converted MemOperation to be fully blittable. The string "module_selection" was only ever used once per program start, so I have instead now added a fully blittable version of MemOperation. Thank you #Flydog57
Changed buffer to be quickly allocated (non zero'd out), and pass a PTR, rather than allocating and then marshalling a byte[] to void/char* (which is what I think likely happens when you pass it a byte[] object). Thank you #Charlieface
Running the profiler in visual studio, it appears to have eliminated the hotpath. Now the total CPU % correctly lies within kernel32.dll (the deviceiocontrol call to the device). Whether this leads to tangible performance benefits, I don't know, don't have an easy way to setup a full benchmark for this.

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.

AccessViolationException in PInvoke function call

I'm trying to write a wrapper for C library but I'm really struggling with this error.
I tried many approaches, here is one of them:
[DllImport(DRIVER_FILENAME)]
[return: MarshalAs(UnmanagedType.U4)]
private static extern uint GetData(IntPtr handle,
[MarshalAs(UnmanagedType.LPArray), In()] int[] buffer,
[MarshalAs(UnmanagedType.U4)] uint size);
Here is function GetData from the library documentation:
LONG GetData(
IN HANDLE Handle,
OUT PULONG Buffer,
IN ULONG Size
);
Function returns continuous data (about 16KB/s) in buffer which size is given in bytes. Buffer is int[16384]. My code looks like this:
public static uint GetLibData(IntPtr handle, int[] buffer, uint size)
{
size *= 4;
uint sizeRead = GetData(handle, buffer, size);
sizeRead /= 4;
return sizeRead;
}
Problematic argument is buffer, I tried manage it previously in other ways, such as IntPtr bufferPtr and then allocating memory by Marshal.AllocHGlobal but I was getting the same error:
Attempted to read or write protected memory. This is often an
indication that other memory is corrupt.
How to correctly invoke this function?
The appropriate p/invoke declaration is
[DllImport(DRIVER_FILENAME)]
private static extern uint GetData(
IntPtr handle,
[Out] uint[] buffer,
uint size
);
It is your responsibility to allocate the buffer before you call the function:
uint[] buffer = new uint[16384];
uint bufferSize = buffer.Length*Marshal.SizeOf(typeof(uint));
uint sizeRead = GetData(handle, buffer, bufferSize);
uint lenRead = sizeRead/Marshal.SizeOf(typeof(uint));
The only thing that's not 100% clear is the calling convention. I'd guess that this library uses cdecl which would mean your DllImport should be
[DllImport(DRIVER_FILENAME, CallingConvention=CallingConvention.Cdecl)]
Try with the following PInvoke:
[DllImport(DRIVER_FILENAME)]
private static extern Int32 GetData
(
[In] IntPtr handle,
[Out] out IntPtr buffer,
[In] UInt32 size
);

How to use InternetQueryOption in C# interop?

In my C# code I want to use InternetQueryOption which is defined in MSDN such as:
BOOL InternetQueryOption(
__in HINTERNET hInternet,
__in DWORD dwOption,
__out LPVOID lpBuffer,
__inout LPDWORD lpdwBufferLength
);
In my C# code I wrote:
[DllImport("wininet.dll", SetLastError = true)]
static extern bool InternetQueryOption(
IntPtr hInternet,
uint dwOption,
IntPtr lpBuffer,
ref int lpdwBufferLength);
My C++ code:
...
HINTERNET hRequest = HttpOpenRequest(hConnect, "POST","/BM-Login/auth-cup", NULL, NULL, accept, secureFlags, 0);
DWORD dwFlags;
DWORD dwBuffLen = sizeof(dwFlags);
InternetQueryOption (hRequest, INTERNET_OPTION_SECURITY_FLAGS,
(LPVOID)&dwFlags, &dwBuffLen);
dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
dwFlags |= SECURITY_FLAG_IGNORE_REVOCATION;
dwFlags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
dwFlags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_WRONG_USAGE;
InternetSetOption (hRequest, INTERNET_OPTION_SECURITY_FLAGS,
&dwFlags, sizeof (dwFlags) );
...
How to write the same in C#? Thanks. (Sorry for my very bad English)
I'd recommend using manged code for this instead of doing this via interop. Have a look at the WebRequest Class. Also, have a look at my answer to the stackoverflow question C# https login and download file for a working example of how this class can be used.

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