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.
Related
I have a prototype of the following function: https://learn.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-GetUrlCacheGroupAttributeA
Which looks like this:
[DllImport("wininet", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "GetUrlCacheGroupAttributeA", CallingConvention = CallingConvention.StdCall)]
private static extern bool GetUrlCacheGroupAttribute(
long gid,
uint dwFlags,
uint dwAttributes,
IntPtr lpGroupInfo,
ref uint lpcbGroupInfo,
IntPtr lpReserved);
The lpdwGroupInfo might make more sense as out instead of ref but otherwise, I think this is correct.
What I don't understand is how I am expected to pass in a pointer for the INTERNET_CACHE_GROUP_INFO struct lpGroupInfo(which I have also defined/prototyped along with this function). I know how everything else is passed in, just this pointer confuses me.
The function states for the pointer the following:
lpGroupInfo - Pointer to an INTERNET_CACHE_GROUP_INFO structure that receives the requested information.
lpcbGroupInfo - Pointer to a variable that contains the size of the lpGroupInfo buffer. When the function returns, the variable contains the number of bytes copied to the buffer, or the required size of the buffer, in bytes.
Do I need to allocate memory via Marshal.AllocHGlobal or something? This seems to suggest I will only get the size of the struct after passing it in but how can I pass it in if it isn't first defined? I'm not at all clear on how to create the initial pointer and then how I am expected to Marshal.PtrToStructure it.
Simon's comment answered my question:
for functions where a struct buffer pointer is passed in as a parameter(intended to be modified by the function) and where it also outs the size of the buffer needed when it fails due to insufficient buffer size, the proper way to use these functions is to pass in these values initialized to the default values(IntPtr.Zero and 0), then when the function fails(you can confirm the error was due to buffer size), it will have set the buffer size required and you can call the function again after allocating memory to the pointer.
Here is a sample snippet:
private static void ClearUrlCacheGroups()
{
IntPtr enumHandle = FindFirstUrlCacheGroup(0, CACHEGROUP_SEARCH_ALL, IntPtr.Zero, 0, out long lpGroupId, IntPtr.Zero);
if (enumHandle != IntPtr.Zero)
{
bool foundNextGroup;
bool isDeleted;
uint cacheGroupInfoBufferSize = 0;
IntPtr cacheGroupInfoBuffer = Marshal.AllocHGlobal((IntPtr)cacheGroupInfoBufferSize);
do
{
bool getAttributeSucceeded = GetUrlCacheGroupAttribute(lpGroupId, 0, CACHEGROUP_ATTRIBUTE_GET_ALL, cacheGroupInfoBuffer, ref cacheGroupInfoBufferSize, IntPtr.Zero);
if (!getAttributeSucceeded && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
{
cacheGroupInfoBuffer = Marshal.ReAllocHGlobal(cacheGroupInfoBuffer, (IntPtr)cacheGroupInfoBufferSize);
getAttributeSucceeded = GetUrlCacheGroupAttribute(lpGroupId, 0, CACHEGROUP_ATTRIBUTE_GET_ALL, cacheGroupInfoBuffer, ref cacheGroupInfoBufferSize, IntPtr.Zero);
}
if (getAttributeSucceeded)
{
INTERNET_CACHE_GROUP_INFOA internetCacheEntry = (INTERNET_CACHE_GROUP_INFOA)Marshal.PtrToStructure(cacheGroupInfoBuffer, typeof(INTERNET_CACHE_GROUP_INFOA));
}
isDeleted = DeleteUrlCacheGroup(lpGroupId, CACHEGROUP_FLAG_FLUSHURL_ONDELETE, IntPtr.Zero);
foundNextGroup = FindNextUrlCacheGroup(enumHandle, ref lpGroupId, IntPtr.Zero);
}
while (foundNextGroup);
Marshal.FreeHGlobal(cacheGroupInfoBuffer);
}
}
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 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.
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?