How do I r/w process memory via scanning and replacing solely arrays of bytes?
This question may seem extremely noob-ish, I apologize. I've been periodically attempting for the past three months to figure out how to read/write another process memory, or the application running's process memory, simply via arrays of bytes. As far as I know, C# doesn't have the capability to read/write memory process, so it must call the win32 API 开发者_Python百科dlls via P/Invoke.
[DllImport("kernel32.dll")]
static extern Int32 ReadProcessMemory(IntPtr OpenedHandle, IntPtr lpBaseAddress, byte[] lpBuffer, UInt32 size, out IntPtr lpNumberOfBytesRead);
My goal is to search and replace a few arrays of bytes as simply and efficiently as you would in Cheat Engine. I would normally have two vars either separate or within an array:
private string original = "d0 d0 66 ae 0b 68 b9 0a";
private string replace = "d0 02 02 24 00 68 b9 0a";
In the ReadProcessMemory
call, I'm not understanding why lpBaseAddress
is necessary. The OpenHandle
I would normally place the string of the application, since I am directly editing it. lpBuffer
I assume is the actual array of bytes to read/write. The size
I am not so sure about, and the lpNumberOfBytesRead
is the number to read? Reciprocal questioning for WriteProcessMemory
as well.
[DllImport("kernel32.dll")]
private static unsafe extern Boolean WriteProcessMemory(IntPtr hProcess, uint lpBaseAddress, byte[] lpBuffer, int nSize, void* lpNumberOfBytesWritten);
I'd like to cite some of the tutorials I have read, but it seems they no longer exist or have been replaced. Again, I sincerely apologize for asking such a seemingly amateur question, however S.O. was my last resort.
As far as I know, C# doesn't have the capability to read/write memory process, so it must call the win32 API dlls via P/Invoke.
Correct, and you've found the right Win32 APIs to do so.
I would normally have two vars either separate or within an array:
private string original = "d0 d0 66 ae 0b 68 b9 0a";
private string replace = "d0 02 02 24 00 68 b9 0a";
For ReadProcessMemory
and WriteProcessMemory
, you won't use strings, you'll use actual arrays of bytes (byte[]
) as seen in the P/Invoke function signatures you listed. Your UI or command-line tool can take strings, but you'll need to convert them into byte arrays.
If you haven't yet, you should read the MSDN documentation for ReadProcessMemory
and WriteProcessMemory
. They give a good description of what's expected for each parameter, what happens, and what's returned.
In the ReadProcessMemory call, I'm not understanding why lpBaseAddress is necessary. The OpenHandle I would normally place the string of the application, since I am directly editing it.
First, the OpenHandle
parameter expects a handle to a process, not the file name, which is what I think you're referring to. You can get the handle to a running process by using the Win32 OpenProcess
API (P/Invoke signature can be found here). To read and write memory in the process, you'll need at least PROCESS_VM_READ
and PROCESS_VM_WRITE
access.
lpBuffer I assume is the actual array of bytes to read/write. The size I am not so sure about, and the lpNumberOfBytesRead is the number to read? Reciprocal questioning for WriteProcessMemory as well.
For ReadProcessMemory
, lpBaseAddress
specifies where in the target process' memory you want to read from. lpBuffer
gets filled with the memory contents of the target process. size
specifies how many bytes to read. lpNumberOfBytesRead
is an output argument telling you how many bytes were actually read as part of the operation. In success cases, this should match the size
of the buffer you specify.
Given that, you should be able to figure out what all the parameters to WriteProcessMemory
do.
More to the point of how to achieve what you're trying to do: you're trying to do a search-and-replace operation. The search portion is going to be the toughest. There are two major approaches I can think of:
You can do a full scan on the process' memory (literally from address zero up to the 2/3GB limit (for 32-bit processes)) looking for your bytes. This is the slowest but easiest way.
Using heap information, you can limit your scan to known allocated addresses. This is a faster but much more complicated approach. Since you're running on Windows, the process you're targeting is likely going to be using the Windows heap for memory management. Windows provides an API,
HeapWalk
, to walk the heaps (and objects) that are allocated in a process. Unfortunately, this requires a handle to a heap, and theGetProcessHeap
/GetProcessHeaps
methods only return a handle to the calling process' heaps (they don't work for remote processes). So, if you wanted heap information for a remote process, you'd need to inject a thread into the remote process to gather this information for you (i.e. by usingCreateRemoteThread
). Once you have the valid heap addresses, you could just scan those from your search-and-replace app.
精彩评论