Reading memory from another process on Mac - c#

I'm building a library for reading memory that I'd like to expand to Mac OS.
Among many other functions, the one main function used by many of the methods is ReadProcessMemory;
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ReadProcessMemory(
[In] IntPtr hProcess,
[In] IntPtr lpBaseAddress,
[Out] byte[] lpBuffer,
[In] SIZE_T nSize,
[Out] out SIZE_T lpNumberOfBytesRead
);
I'm now wondering what the equivalent for this is on Mac. Looking around online (of course it's hardly documented at all), I think the method signature should look something like this;
[DllImport("...")]
[return: MarshalAs(UnmanagedType.I4)]
static extern int vm_read_overwrite(
[In] IntPtr target_task,
[In] IntPtr address,
[In] SIZE_T size,
[Out] byte[] data,
[Out] out SIZE_T outsize
);
vm_read_overwrite is also what's used by several Rust libraries.
What library/package is vm_read_overwrite part of? Is the signature correct? Perhaps additionally, can I use conditional compilation to use the different functions, or do I have to use RuntimeInformation.IsOSPlatform?

[DllImport("libc")]
static extern int vm_read_overwrite(
[In] IntPtr target_task,
[In] IntPtr address,
[In] uint size,
[Out] byte[] data,
[Out] out uint outsize
);
This works on my machine. Hope it helps.

Related

SetFilePointer Strange Issue

I am trying to read sector from physical drive. but set file pointer is giving some strange error after some time
[DllImport("kernel32.dll", EntryPoint = "SetFilePointer", CallingConvention = CallingConvention.StdCall)]
static extern uint SetFilePointer(
[In] IntPtr hFile,
[In] int lDistanceToMove,
[In,Out] int lpDistanceToMoveHigh,
[In] EMoveMethod dwMoveMethod);
public void SetFilePointer(LARGE_INTEGER li)
{
SetFilePointer((IntPtr)handle, li.LowPart, li.HighPart, EMoveMethod.Begin);
}
//values
HighPart 381 int
LowPart -1323466752 int
If passed highPart as zero then its working . in C version its able to download without any issue. but in c# version when ever highvalue is not zero it gives exception.
Additional information: Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.
can you please suggest any correction
Update solved
as #mjwills suggested i have to change the signature to
[DllImport("kernel32.dll", EntryPoint = "SetFilePointer")]
static extern uint SetFilePointer(
[In] Microsoft.Win32.SafeHandles.SafeFileHandle hFile,
[In] int lDistanceToMove,
[In, Out] ref int lpDistanceToMoveHigh,
[In] EMoveMethod dwMoveMethod);
public void SetFilePointer(LARGE_INTEGER li)
{
SetFilePointer(shandle, li.LowPart, ref li.HighPart, EMoveMethod.Begin);
}

64bit ReadProcessMemory access denied

I've tried running this with Process.EnterDebugMode(), but it also doesn't work.
I want to read out the Notepad-memory but I don't know how to access it, or if the 64bit system is doing troubles.
This is what I've done:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
public class MemoryRead
{
[DllImport("kernel32.dll")]
static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
static extern bool ReadProcessMemory(int hProcess, Int64 lpBaseAddress, byte[] buffer, int size, ref int lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
static extern bool CloseHandle(IntPtr hObject);
static void Main(string[] args)
{
var pid = 10956; //notepad.exe
var processHandle = OpenProcess(0x10, false, pid);
byte[] buffer = new byte[24];
int bytesRead = 0;
ReadProcessMemory((int)processHandle, 0x21106B35770, buffer, buffer.Length, ref bytesRead); //0x21106B35770 is the address where "hello world" is written in notepad
Console.WriteLine(Encoding.Unicode.GetString(buffer) +
" (" + bytesRead.ToString() + "bytes)");
Console.ReadLine();
CloseHandle(processHandle);
Console.ReadLine();
}
}
Your PInvoke declaration of ReadProcessMemory is incorrect (though it should work on a 32 bit system).
As can be seen from the native declaration of this function
BOOL WINAPI ReadProcessMemory(
_In_ HANDLE hProcess,
_In_ LPCVOID lpBaseAddress,
_Out_ LPVOID lpBuffer,
_In_ SIZE_T nSize,
_Out_ SIZE_T *lpNumberOfBytesRead
);
its first parameter is HANDLE, and it is a PVOID:
A pointer to any type.
This type is declared in WinNT.h as follows:
typedef void *PVOID;
And pointer to anything in 64-bit process is a 64-bit value - IntPtr.
Basically the same goes to the size and lpNumberOfBytesRead parameters - they are 64 bit as well in a 64 bit process.
Thus your declaration should be something like:
[[DllImport("kernel32.dll", SetLastError = true)]]
[return: MarshalAs(UnmanagedType.Bool)]
static extern Boolean ReadProcessMemory(
[In] IntPtr hProcess,
[In] IntPtr lpBaseAddress,
[Out] Byte[] lpBuffer,
[In] UIntPtr nSize,
[Out] out UIntPtr lpNumberOfBytesRead
);
P.S.: And a bit of shameless self-promotion - if you ever have to work a lot with PInvoke, then there are a few good recommendations I've learned a hard way.

Memory address from string

I have function to write memory, but I want to import address from string, how to do this?
Code:
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteProcessMemory(int hProcess, int lpBaseAddress,
byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesWritten);
and this:
WriteProcessMemory((int)processHandle, 0xffffffff, buffer, buffer.Length, ref bytesWritten);
I want to replace this "0xffffffff" to string, but I don't know how to do this. I try convert string with address to int, but this not working.
Use something like:
string str = "0xffffffffffffffff";
if (str.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
str = str.Substring(2);
}
IntPtr ptr = (IntPtr)long.Parse(str, NumberStyles.HexNumber);
Note that long.Parse doesn't support the 0x, so if present I remove it.
I'm using the long.Parse to support 64bit systems and 32bits systems.
Note that the PInvoke signature you are using is wrong... It will work for 32 bits, but the general one compatible with 32 and 64 bits is:
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
byte[] lpBuffer,
IntPtr dwSize,
out IntPtr lpNumberOfBytesWritten);
If you need to manipilate the IntPtr you should always convert them to long, because a IntPtr can be 32 or 64 bits, so a long can always contain it.

RegistryKey last write time

Using Microsoft.Win32.RegistryKey (or any related classes), how can I query the last write time of a registry key?
You will need to use P/Invoke to make a call to the Win32 API:
MSDN: RegQueryInfoKey function
Signature from pinvoke.net:
[DllImport("advapi32.dll", EntryPoint="RegQueryInfoKey", CallingConvention=CallingConvention.Winapi, SetLastError=true)]
extern private static int RegQueryInfoKey(
UIntPtr hkey,
out StringBuilder lpClass,
ref uint lpcbClass,
IntPtr lpReserved,
out uint lpcSubKeys,
out uint lpcbMaxSubKeyLen,
out uint lpcbMaxClassLen,
out uint lpcValues,
out uint lpcbMaxValueNameLen,
out uint lpcbMaxValueLen,
out uint lpcbSecurityDescriptor,
IntPtr lpftLastWriteTime);

DLLImport in C# has incorrect call

I am getting a PInvokeStackImbalance: 'PInvokeStackImbalance was detected
Message: A call to PInvoke function 'ConvertedClass::MapViewOfFile' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.'
I am fairly new to DLL use, and just managed to work out a few tutorials today.
Any help would be appreciated.
using System.Runtime.InteropServices;
//dll
[DllImport("kernel32", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
public static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, FileMapAccessRights dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, ulong dwNumberOfBytesToMap;)
string szSharedMemory = "FUNKY_BUSINESS";
//other dll call is successful and returns value
IntPtr hMem = OpenFileMapping(FileMapAccessRights.Write, FALSE, szSharedMemory);
///BOOM.. not this one
IntPtr pvHead = MapViewOfFile(hMem, FileMapAccessRights.Write, 0, 0, 0);
Edit: It was a bad argument.. The 5th arg should be UIntPtr instead of ulong.
this is how i feel right now
The final parameter is SIZE_T. That's unsigned, and 32 bits in a 32 bit process and 64 bits in a 64 bit process. So the best solution is to use UIntPtr for the final parameter.
I would use the following:
[DllImport("kernel32")]
public static extern IntPtr MapViewOfFile(
IntPtr hFileMappingObject,
FileMapAccessRights dwDesiredAccess,
uint dwFileOffsetHigh,
uint dwFileOffsetLow,
UIntPtr dwNumberOfBytesToMap
);
Your code uses ulong which is always 64 bits wide. And your process is a 32 bit process which explains why the P/invoke marshaller has detected a stack imbalance.
The 5th parameter should be an uint, not ulong.
public static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, FileMapAccessRights dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, uint dwNumberOfBytesToMap;)
For P/Invoke, you can use sample code from pinvoke.net.
http://www.pinvoke.net/default.aspx/kernel32.mapviewoffile

Categories

Resources