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.
Related
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.
Don't know why but for some ReadProcessMemory always returns false. Always import it like this:
[DefaultDllImportSearchPaths(Kernel32.Path)]
[DllImport(Kernel32.Dll)]
private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int nSize, IntPtr lpNumberOfBytesRead);
Here are the result of running ReadProcessMemory(IntPtr HandleWithAllAccess, IntPtr ProcessBaseAddress, byte[] BufferSizeOf500, int TheSize500, IntPtr.Zero);
https://preview.ibb.co/eK8189/Screenshot_890.png
Note: just so people don't start asking unrelated questions, Kernel32 is a class with the dll name and the path where to find it
The read operation crossed into a inaccessible area of the process, that's why it returned false. Thank you Jeroen Mostert for linking the documentation and I will set the SetLastError to true from now on.
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.
I'm trying to write a DWORD to registry using c#.
Using p/invoke because of registry reddirection.
I've searched for this issue and finally could get it working but i don't understand.
[DllImport("advapi32.dll", SetLastError = true)]
static extern uint RegSetValueEx(
IntPtr hKey,
[MarshalAs(UnmanagedType.LPStr)]
string lpValueName,
int Reserved,
RegistryValueKind dwType,
ref IntPtr lpData,
int cbData);
int checkreturn = RegOpenKeyEx(HKeyLocalMachine, #"SOFTWARE\Test", 0, (int) RegistrySecurity.KEY_WOW64_64KEY | (int) RegistrySecurity.KEY_SET_VALUE, ref keyHandle);
const int dataStored = 0;
IntPtr p = new IntPtr(dataStored);
int size = Marshal.SizeOf(dataStored);
uint checkreturn2 = RegSetValueEx(keyHandle, "valueName", 0, RegistryValueKind.DWord, ref p, size);
This works if i put out or ref on lpData parameter, if i don't it returns error 998 (ERROR_NOACCESS), why is that? The same thing happens if i change the IntPtr to int, and pass the actual value, but this time i get an first exception AccessViolation on my code.
the winapi declaration for that it's *lpData, which i assume is what passing a IntPtr is.
_In_ const BYTE *lpData,
The api requires a pointer to the data plus the size of the data. You can't pass an int, or a char, or a bool. You need to pass a pointer to the data. If you pass something else, the API will interpret it as a pointer to the data, and random results will happen.
With P/Invoke, a ref to something is translated to a pointer to that something.
Now, you can
[DllImport("advapi32.dll", SetLastError = true)]
static extern uint RegSetValueEx(
IntPtr hKey,
[MarshalAs(UnmanagedType.LPStr)]
string lpValueName,
int Reserved,
RegistryValueKind dwType,
ref uint lpData,
int cbData);
and then in cbData pass sizeof(uint) and this will work, because a ref for P/Invoke is a ref.
Only thing, I would suggest removing the
[MarshalAs(UnmanagedType.LPStr)]
because without it the P/Invoke will use the Unicode version of the method, that is more correct.
Given the code below, ReadProcessMemory always returns an array of zeros. I'm trying to locate a string (which may be numeric) in a running process and identify all the locations where that string exists. But ReadProcessMemory always returns an array of zeros. Why is that?
I've tried running VS as administrator and removing the unsafe block.
processPointer has a correct value for the process handle.
BaseAddress does correctly iterate by one, and appears to be the memory location I'm looking for.
Despite obviously not finding any matches, it does run fairly quickly. Several seconds for a 72MB process.
.
// (other stuff in method...)
IntPtr baseAddress = process.MainModule.BaseAddress;
IntPtr lastAddress = baseAddress + process.MainModule.ModuleMemorySize;
processPointer = OpenProcess((uint)(0x0020), 1, (uint)PID);
for (int addr = (int)baseAddress; addr + value.Length < (int)lastAddress; addr++)
{
string ActualValue = ReadMemory((IntPtr)addr, (uint)value.Length, (IntPtr)addr);
if (string.IsNullOrEmpty(ActualValue)) continue;
if (ActualValue.Trim().ToLower() == value.Trim().ToLower())
PossibleAddresses.Add((IntPtr)addr);
}
// (other stuff in method...)
CloseHandle(processPointer);
private string ReadMemory(IntPtr memAddress, uint size, IntPtr BaseAddress)
{
byte[] buffer = new byte[size];
IntPtr bytesRead;
unsafe
{
ReadProcessMemory(processPointer, BaseAddress, buffer, size, out bytesRead);
return BitConverter.ToString(buffer); // always "00-00-00-00....."
}
return Encoding.Default.GetString(buffer); // Another way I tried to read the data
}
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Int32 bInheritHandle, UInt32 dwProcessId);
[DllImport("kernel32.dll")]
public static extern Int32 CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
public static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesRead);
I was opening the handle with the wrong access type. 0x0010 is to read; 0x0020 is to write. I was hoping to get read/write with one open, but it looks like I'll have to handle that separately.
source: http://www.codeproject.com/script/Articles/ViewDownloads.aspx?aid=15680