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.
Related
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'.
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.
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.
Ive been working on this the whole day, and im still stuck
i ported this code from c/c++ to c# im so close but i get these exceptions
Exception of type 'System.ExecutionEngineException' was thrown.
and
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
here is the code, the code is not cleaned up/optimized yet cause im still testing it
public unsafe static void GetHash(string data, byte[] hash)
{
byte[] input = System.Text.UnicodeEncoding.Unicode.GetBytes(data);
hash = new byte[128];
IntPtr hProv = IntPtr.Zero;
IntPtr hHash = IntPtr.Zero;
Crypto.CryptAcquireContext(ref hProv, string.Empty, string.Empty, Crypto.PROV_RSA_FULL, 0);
if (Crypto.CryptCreateHash(hProv, Crypto.CALG_SHA1, IntPtr.Zero, 0, ref hHash))
{
if (Crypto.CryptHashData(hHash, input, ((input.Length) + 1) * 2, 0))
{
byte[] buffer = new byte[20];
IntPtr pBuffer = IntPtr.Zero;
int length = 20;
if (Crypto.CryptGetHashParam(hHash, Crypto.HP_HASHVAL, ref pBuffer, ref length, 0))
{
Crypto.CryptDestroyHash(hHash);
Crypto.CryptReleaseContext(hProv, 0);
byte tail = 0;
unsafe
{
//no matter what i do it stops here!!!!! :(
//one error is "Exception of type 'System.ExecutionEngineException' was thrown."
//the other is "System.AccessViolationException crossed a native/managed boundary
//Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
try
{
//-------------------------- This is where the exepctions starts
//I have commented the code, cause im kinda getting tired of this Exception
//I tried 2 ways of getting a byte[] from a pointer
//the 1e way, does not work
//for (int i = 0; i < length; i++)
//buffer[i] = (byte)Marshal.ReadByte(pBuffer, i);
//the 2e way does not work
//System.Runtime.InteropServices.Marshal.Copy(pBuffer,buffer, 0, 20);
//--------------------------
}
catch (Exception ex)
{
}
}
//there is more code here, but i removed
//since i only want till where code goes sofare
}
}
}
}
hope anybody can help me out here,
Thnx in advance
JB
I fixed it without the use of unsafe or the fixed statement, what i did was 2 simple like most of the codings tmp issues
i have this class Crypto where i have all advapi.dll functions in and the function returned a pointer to the byte array in memory and this is what the function needed before my change.
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptGetHashParam(
IntPtr hHash,
Int32 dwParam,
ref IntPtr pbData, // this is where my problem was!!!!
ref Int32 pdwDataLen,
Int32 dwFlags
i changed the function to
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptGetHashParam(
IntPtr hHash,
Int32 dwParam,
Byte[] pbData, //i changed it from IntPtr to byte array
ref Int32 pdwDataLen,
Int32 dwFlags
and that solved my corrupt memory issue
Hope this issue helps some body else working with CryptGetHashParam
i ported this code from c/c++ cause there where no c# sample on the net, so here is one of the first.
thnx all for trying to help me out, but i fixed it myself
JB
I'm not certain, but it's likely because your .Net objects aren't pinned in memory. See this: http://dotnet.dzone.com/news/net-memory-control-use-gchandl. The gist of it is that .Net objects can be moving around in memory after you've passed them through interop, and when that happens stuff starts getting crazy.
Unfortunately I'm on a netbook at the moment and can't try it myself. Does that help?
I have two mdi applications, both of which retrieve their data from the same database.
The two applications need to be able to send messages to each other to keep in synch.
The messages being passed back and forth only contain a string telling the recieving application which piece of data in the database it should be looking at (a job number, and some additional related info).
Both applications have a message handler, instantiated when each program starts up.
When a message is sent from the VB6 app to the c# app it sees the message, and acts appropriately, but when I send the same type of message from the c# app to the VB6 app, it seems to see the message event, but when unpacking it, only sees part of the data, and then ignores the message.
I'm thinking I may be formatting something wrong on the c# end.
Here is the method that sends the message:
namespace InterProcessMessaging
{
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData;//a pointer to a number use this to identify your message
public IntPtr lpData;//a pointer to the address of the data
public IntPtr cbData;//a pointer to the number of bytes to be transferred
}
public class clsMessaging : System.Windows.Forms.NativeWindow, IDisposable
{
//API function to send async. message to target application
[DllImport("user32.dll", CharSet = CharSet.Ansi)]
public static extern IntPtr SendMessageA(IntPtr hwnd, Int32 wMsg, Int32 wParam, COPYDATASTRUCT lParam);
public void SendMessageToVB6(string sendMsg, string WindowsAppTitle)
{
try
{
IntPtr hwndTarget = FindWindow(null, WindowsAppTitle);
IntPtr pDWData = Marshal.AllocHGlobal(sizeof(Int32));//a pointer to a number used this to identify your message
Marshal.StructureToPtr(3, pDWData, true);//place the value 3 at this location
IntPtr pLPData = Marshal.StringToHGlobalAnsi(sendMsg.Trim());//a pointer to the address of the data
IntPtr pCBData = Marshal.AllocHGlobal(sizeof(Int32));//a pointer to the number of bytes to be transferred
Marshal.StructureToPtr(sendMsg.Trim().Length+1, pCBData, true);//place the size of the string at this location
COPYDATASTRUCT cds;//a structure containing the three pointers above
cds.dwData = pDWData;//a pointer to a number used this to identify your message (3)
cds.lpData = pLPData;//a pointer to the address of the data
cds.cbData = pCBData;//a pointer to the number of bytes to be transferred
if (!System.IntPtr.Zero.Equals(hwndTarget))
{
SendMessageA(hwndTarget, 74, 0, cds);
}
}
catch (Exception ex)
{
Debug.Print(ex.InnerException.ToString());
}
}
}
}
I would recommend to look into Named Pipes. In .NET you can use System.IO.Pipes for this purpose. In VB6 you can easily implement it with Win32API. Named Pipes is better way to make IPC than windows messaging. Also IPC via SendMessage has limitations on Vista and Win7.
You got that pretty wrong. Only COPYDATASTRUCT.lpData is a pointer. dwData indicates the message number. You pick your own, use 0 if you have only one. cbData is the size of the pointed-to data.
More problems, you are leaking the memory. The amount of memory you allocate doesn't match the size you pass. The string conversion is lossy and might not produce as many bytes as string.Length(). FindWindow is notoriously unreliable. Use a socket or a named pipe for this so you don't have to guess a name, WCF is best.
COPYDATASTRUCT cds;
cds.dwData = (IntPtr)3;
cds.lpData = Marshal.StringToHGlobalUni(sendMsg);
cds.cbData = 2 * (sendMsg.Length + 1);
SendMessageA(hwndTarget, 74, 0, cds);
Marshal.FreeHGlobal(cds.lpData);
This works:
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public UInt32 cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
[DllImport("User32.dll", EntryPoint = "SendMessage")]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);
IntPtr result;
byte[] sarr = System.Text.Encoding.Default.GetBytes(sendMsg);
int len = sarr.Length;
COPYDATASTRUCT cds;
cds.dwData = (IntPtr)3;
cds.lpData = sendMsg;
cds.cbData = (UInt32)len + 1;
result = SendMessage(hwndTarget, WM_COPYDATA, 0, ref cds);
Credit for this solution goes to Jim Kemp...who is not yet a member.
Thanks Jim!
I based the solution off of the example I found here:
http://boycook.wordpress.com/2008/07/29/c-win32-messaging-with-sendmessage-and-wm_copydata/