C# ReadProcessMemory - c#

I'm basically trying to figure out how to search for a value in a process without giving an exact offset. The process can be anything (notepad, iexplorer, msword, etc.). Just looking for search a value between the first and last memory address of a process instead of giving a specific offset, which is I had to find from another application like ollydbg.
Here's what I have
const int PROCESS_WM_READ = 0x0010;
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(int hProcess,
Int64 lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);
public static string search = "somestring";
static void Main(string[] args)
{
Process process = Process.GetProcessById(15728);
IntPtr processHandle = OpenProcess(PROCESS_WM_READ, false, process.Id);
int bytesRead = 0;
byte[] buffer = new byte[16];
ReadProcessMemory((int)processHandle, 0x20BC4ADE4C8, buffer, buffer.Length, ref bytesRead);
Console.WriteLine(Encoding.Unicode.GetString(buffer) +
" (" + bytesRead.ToString() + "bytes)");
if (Encoding.Unicode.GetString(buffer).Contains(somestring))
Console.WriteLine("Match");
else
Console.WriteLine("Didint Match");
Console.ReadLine();
}

You cannot avoid passing an address into ReadProcessMemory as it is required, and I don't believe there are any other APIs out there that allow you to read a process's memory.
So, what you have to do is pass in the base address. Rather than get the base address, you can calculate it yourself. This question can help.
Next you will need to find the size of the process's memory and pass that to the nSize parameter. But... that might be a bad idea because
you have to determine what that value is (I'm not sure how; you could brute force it by doing a binary search across the largest possible value and finding the largest value that doesn't force ReadProcessMemory to return false or perhaps using a performance counter or some other mechanism).
Deal with memory constraints of having to allocate a huge chunk of memory for your buffer.
So instead of reading all of the memory, make multiple calls to ReadProcessMemory with smaller buffer sizes. The algorithm could be something like
while not an error
read into a buffer, scanning it for your string
if found
return true;
bump the offset
If the above loop does not find your string, you're still not done because the string could have spanned the boundary between two buffers. To deal with this, create another loop that scan each boundary from boundary offset - string size to boundary offset + string size, returning true if found.

Related

Error read addres with function ReadProcessMemory c#

I have an error with reading the memory address of the game, where:
my code is this
public partial class MainWindow: Window
    {
        [DllImport ("kernel32.dll")]
        public static extern IntPtr OpenProcess (int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
        [DllImport ("kernel32.dll")]
        public static extern bool ReadProcessMemory (int hProcess, int lpBaseAddress, byte [] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);
        const int PROCESS_WM_READ = 0x0010;
        public MainWindow ()
        {
            arguments dir = new arguments ();
            Process process = Process.GetProcessesByName (dir.proccessname) [0];
            IntPtr processHandle = OpenProcess (PROCESS_WM_READ, false, process.Id);
            int bytesRead = 0;
            byte [] buffer = new byte [4];
            ReadProcessMemory ((int) processHandle, dir.heal_Act, buffer, buffer.Length, ref bytesRead);
        }
however, nothing reading appears:
in cheat engine read me the values
Read address with Cheat Engine
Where in the image appears the reading of the memory address and finally the value contained with 4 bytes in size
Read address with Cheat Engine
In addition, I do not know how the summation of the address is as shown in box 2 to obtain the contained value.
they could help me to propose the reading with the indicated address, since zero appears.
You need to run your process as administrator and you should compile this for the same architecture as the target process. If you're targetting x86, compile as x86.
Keep in mind your ReadProcessMemory define only takes 4 byte addresses as arguments, you will want to use IntPtr for the addresses so when you someday switch to x64 the args will be large enough for 64 bit pointers.
If these things don't solve your problem then you're offsets or addresses are wrong. In which case the best thing to do is to use the Visual Studio Debugger and compare what you see against what you see in Cheat Engine.
Also in your PROCESS_WM_READ you have a 'W' instead of a 'V'.

WriteProcessMemory - String length bug

Currently I'm writing a game trainer using C# (note that I'm only making one for fun, for a private server, and NOT for hacking the game to become the "best player ever") and it's working smoothly, but not the string.
When I write the string for the first time and I have 10 chars, it's working (it'll write for example: hellolady!). When I type 8 chars (for example hellolol) it will automatically write 10 chars, so the new string would be hellololy!.
I don't know why I get the problem, this is my WriteString:
public static bool WriteString(IntPtr handle, int address, string value)
{
int written;
byte[] data = Encoding.Default.GetBytes(value);
return WriteProcessMemory(handle, address, data, data.Length, out written);
}
My WriteProcessMemory:
[DllImport("Kernel32.dll")]
static extern bool WriteProcessMemory(IntPtr handle, int lpBaseAddress, byte[] lpBuffer, int nSize, out int lpNumberOfBytesWritten);
Hopefully somebody can help me with it.
Edit of the function which works, you have to use a null terminator at GetBytes, then it'll work.
public static bool WriteString(IntPtr handle, int address, string value)
{
int written;
byte[] data = Encoding.Default.GetBytes(value + "\0");
return WriteProcessMemory(handle, address, data, data.Length, out written);
}

C# ReadProcessMemory - Accessing/Reading Pointers

I have the code to read a value from Memory which works when the memory address points to a static 4 byte value, but i'm trying to access a 4 byte value which is in a dynamic location and so need to search for the pointer first then search again to get the 4 byte value.
Below is the code I have which should return the address of the Pointer but it just outputs 0...
bAddr = (IntPtr)0x0017C370; // Base address to find the Pointer (Currently: 0x00267A50)
ReadProcessMemory(hProc, bAddr, buffer, 4, out bytesRW);
output = BitConverter.ToInt32(buffer, 0);
txtOutput.Text = output.ToString();
Pseudo code I see working as:
bAddr = (IntPtr)0x0017C370; // Base address to find the Pointer (Currently: 0x00267A50)
ReadProcessMemory(hProc, bAddr, buffer, 4, out bytesRW);
output = BitConverter.ToInt32(buffer, 0);
bAddr = (IntPtr)output; // Should now contain the address 0x00267A50
ReadProcessMemory(hProc, bAddr, buffer, 4, out bytesRW);
output = BitConverter.ToInt32(buffer, 0);
txtOutput.Text = output.ToString();
Can anyone shed any light on to what I need to be doing to find an address and then search for that address to find a value?
This is a pretty classical mistake when using pinvoke to execute Win32 functions, you are not doing any error checking. So any failure is undiagnosable. First make sure you declared it properly:
[DllImport("user32.dll", SetLastError = true)]
static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
[In, Out] byte[] buffer, IntPtr size, out IntPtr lpNumberOfBytesRead);
Then execute it like this:
bool ok = ReadProcessMemory(...);
if (!ok) throw new System.ComponentModel.Win32Exception();
Now you'll know why it doesn't work. We can't otherwise help you figure out what goes wrong until you've at least tested it this way. The most basic problem is guessing the address wrong of course. And not having enough privileges, ReadProcessMemory is a highly privileged function for obvious reasons.

Why does ReadProcessMemory always return zeros?

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

How to get all memory address space used by a process?

I need to know all memory address space used by a process. The memory space will later be scanned to locate values within the process and identify their locations / addresses. My current process for this is to take each module's base address through its (base address + memory size).
I'm testing this on a process with a known value at a known address. When I look up that specific address, I get the value I expect. However, when I scan (what I believe to be) all address space used by the process, I can't find the value anywhere.
I know that a numeric value "4143000" exists at 0x0CF8DC38 and 0x0CF8DDDC. When I call ReadMemoryBytes(module, module.BaseAddress, 4, (IntPtr)(0x0CF8DC38)) I get back bytes (152, 55, 63, 0). When I call BitConverter.GetBytes(4143000) I get back the same set of bytes. When I use a different memory scanner on that process, I find that value at those addresses.
However, when I scan the "known addresses", I don't find this value anywhere. It doesn't look like my code is even finding those addresses in use by the process.
Thusly, my question is twofold:
How can I find these addresses within this process?
I'm concerned I may be dealing with absolute addresses in system memory versus relative addresses within a process. Am I doing this right?
.
// (in the calling method)
foreach (ProcessModule module in process.Modules) {
ParameterizedThreadStart pst = new ParameterizedThreadStart(p => SearchModule(module, value));
Thread t = new Thread(pst);
t.Start(); }
private unsafe void SearchModule(ProcessModule module, string value)
{
Process process = getProcess;
int iVal;
double dVal;
int.TryParse(value, out iVal);
double.TryParse(value, out dVal);
for (Int64 addr = (Int64)module.BaseAddress; addr + value.Length < (Int64)module.BaseAddress + module.ModuleMemorySize; addr++)
{
// Compare ints
if (iVal > 0)
{
byte[] ExpectedBytes = BitConverter.GetBytes(iVal);
byte[] ActualBytes = ReadMemoryBytes(module, (IntPtr)addr, (uint)ExpectedBytes.Length, (IntPtr)addr);
bool isMatch = true;
for (int i = 0; i < ExpectedBytes.Length; i++)
if (ExpectedBytes[i] != ActualBytes[i])
isMatch = false;
if (isMatch)
PossibleAddresses.Add((IntPtr)addr);
}
}
private byte[] ReadMemoryBytes(ProcessModule mod, IntPtr memAddress, uint size, IntPtr BaseAddress)
{
byte[] buffer = new byte[size];
IntPtr bytesRead;
unsafe
{
ReadProcessMemory(processPointer, BaseAddress, buffer, size, out bytesRead);
return buffer;
}
}
[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);
The addresses you're getting are pointers to the managed (CLR) heap. They won't generally map to absolute memory addresses and they can move from call to call as the GC decides to run.
If you use "unsafe" code, you can get relative pointers as well as managing your own memory space. It's still on the heap but at least you're guaranteed the GC won't modify your address space.
Do not expect to be able to access things on the heap from non-CLR code without extensive wrapping. There are ways to do IPC between CLR-managed processes but you'd have to write access proxies to the "outside world" if you want a non-CLR process to get to your memory.

Categories

Resources