C# pointer offset > 255 - ProcessMemoryReader - c#

I know there are many tutorials out there showing you how to use the "ProcessMemoryReader" functions. But this problems seems to be unique or not solved yet.
For quite a while I've been digging into other people's code to find a way to use multiple offsets.
And I thought that using multiple offsets was the problem for me, but I think it's a problem with the fact that my offset value is bigger than 255.
The game I'm trying to get the memory values from is called "Assault Cube".
As I wasn't sure whether I got the right offset values I googled what others results where.
They seem to be exactly the same:
http://cheatengine.org/tables/moreinfo.php?tid=1142 (You can view the .ct file with notepad if you don't have cheat engine installed.)
Here is my code, using the ProcessMemoryReader.cs.
private void timer1_Tick(object sender, EventArgs e)
{
int bytesread;
int pointerbase;
byte[] memory;
Process[] myprocess = Process.GetProcessesByName("ac_client");
if (myprocess.Length != 0)
{
preader.ReadProcess = myprocess[0];
preader.OpenProcess();
//Ammo
memory = preader.ReadProcessMemory((IntPtr)0x4DF73C, 4, out bytesread);
pointerbase = BitConverter.ToInt32(memory, 0);
pointerbase += 0x00; //0 // 14 // 378
byte[] memory1 = preader.ReadProcessMemory((IntPtr)pointerbase, 4, out bytesread);
int pointerbase1 = BitConverter.ToInt32(memory1, 0);
pointerbase1 += 0x14; //0 // 14 // 378
byte[] memory2 = preader.ReadProcessMemory((IntPtr)pointerbase1, 4, out bytesread);
int pointerbase2 = BitConverter.ToInt32(memory2, 0);
pointerbase2 += 0x378; //00 // 14 // 378
byte[] memory3 = preader.ReadProcessMemory((IntPtr)pointerbase2, 4, out bytesread);
int valueis = BitConverter.ToInt32(memory3, 0);
label1.Text = valueis.ToString();
}
Though with a single pointer the process works fine, for example:
//HP
memory = preader.ReadProcessMemory((IntPtr)0x4DF73C, 4, out bytesread);
pointerbase = BitConverter.ToInt32(memory, 0);
pointerbase += 0xf4;
byte[] memory1 = preader.ReadProcessMemory((IntPtr)pointerbase, 4, out bytesread);
int valueis = BitConverter.ToInt32(memory1, 0);
label2.Text = valueis.ToString();
So that works, it's pretty straight forward what's happening here, but I can't figure how to read the Ammo code with the multiple offsets.

I'm not familiar with CheatEngine and it's table format, but I do not get the impression it's pointing to the memory addresses that you are using.
You read 4 bytes at 0x4DF73C, which is used as the new memory address for the next read. This is repeated a few times. Basically, you're reading information from a pointer to a pointer to a pointer. Are you sure this is what is intended?
There's no reason whatsoever that an offset value greater than 255 would be a problem.

Use FindDMAAddy to walk the pointer chain for you, here is a working example, make sure you run as admin:
public static IntPtr FindDMAAddy(IntPtr hProc, IntPtr ptr, int[] offsets)
{
var buffer = new byte[IntPtr.Size];
foreach (int i in offsets)
{
ReadProcessMemory(hProc, ptr, buffer, buffer.Length, out
var read);
ptr = (IntPtr.Size == 4) ? IntPtr.Add(new IntPtr(BitConverter.ToInt32(buffer, 0)), i) : ptr = IntPtr.Add(new IntPtr(BitConverter.ToInt64(buffer, 0)), i);
}
return ptr;
}
var modBase = GetModuleBaseAddress(proc.Id, "ac_client.exe");
var ammoAddr = FindDMAAddy(hProc, (IntPtr)(modBase + 0x10f4f4), new int[] { 0x374, 0x14, 0 });
Console.WriteLine("Ammo address " + "0x" + ammoAddr.ToString("X"));
int newAmmo = 1337;
byte[] buffer = new byte[4];
ReadProcessMemory(proc.Handle, ammoAddr, buffer, 4, out _);
Console.WriteLine("Ammo value " + BitConverter.ToInt32(buffer, 0).ToString());
WriteProcessMemory(hProc, ammoAddr, newAmmo, 4, out _);

Related

C# Multilevel pointers wrong last calc

I am currently trying to implement memory read in C# on base pointers found using Cheat Engine. I am 100% sure I have found the right pointers and offsets since they work just fine in Cheat-Engine, even between restarts.
I am now implementing it in C#, have not had any issues with single level points, but for some reason I can't get my last multilevel pointer to work.
It all goes well until the last value it has to add and then it returns something "random" to me, these are the pointers I have found and I can see it works in Cheat Engine.
This is my implementation in C#:
public static int ReadFromPointer(int address, int[] offsets)
{
Console.WriteLine("----------");
Console.WriteLine("Address: " + address);
int ptr = ReadPointer(address);
Console.WriteLine($"Pointer returned as int: {ptr}, hex: {ptr:X}");
foreach (var offset in offsets)
{
Console.WriteLine($"Adding offset: {offset:X} to Pointer: {ptr:X}");
ptr = ReadPointer(ptr + offset);
Console.WriteLine($"Pointer returned as int: {ptr}, hex: {ptr:X}");
}
Console.WriteLine("----------");
return ptr;
}
private static int ReadPointer(int adress)
{
int ptrNext;
int bytesRead = 0;
byte[] _Value = new byte[4];
ReadProcessMemory((IntPtr)ProcessHandle, (IntPtr)adress, _Value, IntPtr.Size, ref bytesRead);
ptrNext = BitConverter.ToInt32(_Value, 0);
return ptrNext;
}
and I call it using the following:
var valueToFind = ProcessHelper.ReadFromPointer((int)baseAddress + 0x00C45A5C, new []{ 0xEC, 0x1C, 0x178, 0x74, 0x458 });
Now here comes the "random" part, every pointer is added correctly except the last when it has to add 0x458 to pointer 1E138F80, this should return 1E1393D8, but ends up returning "41C00000"
I am unsure if it's due to my last pointer no longer being 4 bytes or if a conversion is somehow happening that mixes it up.
Any help here would be greatly appreciated!
Your problem is, after you add the last offset you are de-referencing it again as if this address points to the variable you are trying to get the address of. In fact, at this point the address is the address of your variable, not a pointer to it. When the last offset is added, you should stop and print that variable instead.
I am pretty sure that changing:
foreach (var offset in offsets)
to
for (var i = 0; i < offsets.Length; ++i)
and changing
ptr = ReadPointer(ptr + offset);
to
ptr = ReadPointer(ptr + offset[i]);
will fix it.
Print after this for loop concludes and, it should print the correct address.
If that fails, I have prepared a replacement function for you:
public static IntPtr FindDMAAddy(IntPtr hProc, IntPtr ptr, int[] offsets)
{
var buffer = new byte[IntPtr.Size];
foreach (int i in offsets)
{
ReadProcessMemory(hProc, ptr, buffer, buffer.Length, out var read);
ptr = (IntPtr.Size == 4)
? IntPtr.Add(new IntPtr(BitConverter.ToInt32(buffer, 0)), i)
: ptr = IntPtr.Add(new IntPtr(BitConverter.ToInt64(buffer, 0)), i);
}
return ptr;
}

C#. How fast insert Byte to Struct all time?

Code For NET 2.0.
I write function ByteArrayToObject for insert offset bytes in struct, but is it possible to quickly?
Is planned that there will be a lot of structures in which it is necessary to append the changed network information. If I can insert these bytes quickly to the right place, it will be organized in the protocol as one big structure.
Thank you for any help.
In my case, I do not like that every time to replace the bytes that have to do all the copy of the object func ObjectToByteArray.
/// <summary> Convert an object struct to a byte array </summary>
private static byte[] ObjectToByteArray(Object obj)
{
var size = Marshal.SizeOf(obj);
// Both managed and unmanaged buffers required.
var bytes = new byte[size];
var ptr = Marshal.AllocHGlobal(size);
// Copy object byte-to-byte to unmanaged memory.
Marshal.StructureToPtr(obj, ptr, false);
// Copy data from unmanaged memory to managed buffer.
Marshal.Copy(ptr, bytes, 0, size);
// Release unmanaged memory.
Marshal.FreeHGlobal(ptr);
return bytes;
}
/// <summary> Need Faster ? </summary>
public static T ByteArrayToObject<T>(ref T obj, int StartOffset, params byte[] bytes)
{
int size = Marshal.SizeOf(obj);
int Length = (bytes.Length > size) ? size : bytes.Length;
byte[] Allbytes = ObjectToByteArray(obj);
Array.Copy(bytes, 0, Allbytes, StartOffset, Length - StartOffset);
var ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(Allbytes, 0, ptr, Length );
obj = (T)Marshal.PtrToStructure(ptr, typeof(T));
Marshal.FreeHGlobal(ptr);
return obj;
}
Example use
[Serializable]
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1, CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
struct Protocol
{
public byte f0;
public byte f1;
public short f2;
public byte f3;
public long f4;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 20000)]
public int[] Array; // 20000
}
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
for (byte i = 1; i < 10; i++)
{
sw.Reset();
sw.Start();
ob = ByteArrayToObject<Protocol>(ref ob,1, i, 0x11, i, 0x22, i);
sw.Stop();
Console.WriteLine("Tick =" + sw.ElapsedTicks);
}
Output
Tick =9940
Tick =686
Tick =593
Tick =474
Tick =562
Tick =5283
Tick =193
Tick =173
Tick =164
This is too long for a comment, but to expand on the unsafe approach:
unsafe struct Ex
{
public byte f0,f1,f2,f3,f4;
public fixed int buffer[20000];
}
class Program
{
public static unsafe void ByteArrayToEx(Ex* obj, int offset, params byte[] bytes)
{
// you should add some safely nets here sizeof(Ex) should used for size of struct
byte* p = (byte*)obj;
foreach (var b in bytes)
{
p[offset++] = b;
}
// dont return value, it is expensive!
}
unsafe static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
Console.WriteLine(Stopwatch.Frequency);
Ex e = new Ex { f0 = 0, f1 = 1, f2 = 2, f3 = 3, f4 = 4 };
ByteArrayToEx(&e, 2, 5, 6, 7);
for (int i = 0; i < 10; i++) {
sw.Restart();
ByteArrayToEx(&e, 2, (byte) i, 6, 7);
sw.Stop();
Console.WriteLine(sw.ElapsedTicks);
}
}
}
This may or may not work for you. Also dont return the value. You are already mutating the pointer to it. Returning a copy of such a big struct adds 10 ticks to every call to it.
Also, you need to do at least 1 warmup when bench marking. That is why the first number is so poor.
Results on my PC:
3312929
4
2
0
0
0
0
0
0
0
0
Rewrote a little
public static unsafe void ByteArrayToEx(ref Ex value, int offset, params byte[] bytes)
{
// you should add some safely nets here sizeof(Ex) should used for size of struct
fixed (Ex* obj = &value)
{
byte* p = (byte*)obj;
foreach (var b in bytes)
{
p[offset++] = b;
}
}
// dont return value, it is expensive!
}

problems with .Net File Mapping

There are two processes:
Win32, C++ - writer
.Net 4.5, C# - reader
first process creates a buffer and sharing for second process.
(int)(buffer+0) - until when you can write.
(int)(buffer+4) - until when you can read.
... - block [size_mess][mess]
record circularity, ie when you reach the end of the buffer, seek to the beginning.
at some point occur error.
1 process waits for data to be read.
2 process reads a block, but reading the old data (which were recorded during the previous pass).
tried used MemoryMappedViewAccessor, MemoryMappedViewStream... without effect
possible of delay due to .NET?
unsafe public void LoadFromMemory(string name)
{
const UInt32 capacity = 1200;
const UInt32 maxsize = 1024;
MemoryMappedFile mf = MemoryMappedFile.OpenExisting(name,MemoryMappedFileRights.FullControl);
MemoryMappedViewStream stream = mf.CreateViewStream(0, capacity,MemoryMappedFileAccess.ReadWrite);
BinaryReader reader = new BinaryReader(stream);
byte* bytePtr = null;
stream.SafeMemoryMappedViewHandle.AcquirePointer(ref bytePtr);
int size = 0;
long pos_begin = 0x10;
long pos_max = Interlocked.CompareExchange(ref *((int*)(bytePtr + 4)), 0, 0);
while (<work>)
{
while (pos_begin >= pos_max)
{
pos_max = Interlocked.CompareExchange(ref *((int*)(bytePtr+4)), 0, 0);
}
size = (bytePtr[pos_begin + 1] << 8) + bytePtr[pos_begin];
stream.Seek(pos_begin + 2, SeekOrigin.Begin);
work(reader);
//if here put a breakpoint,
//in time of error size ! = Watch.bytePtr[pos_begin] and all other data
if (pos_begin + size > maxsize) pos_begin = 0x10; // to beginning
else pos_begin += size;
Interlocked.Exchange(ref *((int*)bytePtr), (int)pos_begin); // for first process
}
}

C# Copy variables into buffer without creating garbage?

Is it possible in C# .Net (3.5 and above) to copy a variable into a byte[] buffer without creating any garbage in the process?
For instance:
int variableToCopy = 9861;
byte[] buffer = new byte[1024];
byte[] bytes = BitConverter.GetBytes(variableToCopy);
Buffer.BlockCopy(bytes, 0, buffer, 0, 4);
float anotherVariableToCopy = 6743897.6377f;
bytes = BitConverter.GetBytes(anotherVariableToCopy);
Buffer.BlockCopy(bytes, 0, buffer, 4, sizeof(float));
...
creates the byte[] bytes intermediary object which becomes garbage (presuming a ref is no longer held to it)...
I wonder if using bitwise operators the variable can be copied directly into the buffer without creating the intermediary byte[]?
Use pointers is the best and the fastest way:
You can do this with any number of variables, there is no wasted memory, the fixed statement has a little overhead but it's too small
int v1 = 123;
float v2 = 253F;
byte[] buffer = new byte[1024];
fixed (byte* pbuffer = buffer)
{
//v1 is stored on the first 4 bytes of the buffer:
byte* scan = pbuffer;
*(int*)(scan) = v1;
scan += 4; //4 bytes per int
//v2 is stored on the second 4 bytes of the buffer:
*(float*)(scan) = v2;
scan += 4; //4 bytes per float
}
Why can't you just do:
byte[] buffer = BitConverter.GetBytes(variableToCopy);
Note that the array here is not an indirection into the storage for the original Int32, it is very much a copy.
You are perhaps worried that bytes in your example is equivalent to:
unsafe
{
byte* bytes = (byte*) &variableToCopy;
}
.. but I assure you that it is not; it is a byte by byte copy of the bytes in the source Int32.
EDIT:
Based on your edit, I think you want something like this (requires unsafe context):
public unsafe static void CopyBytes(int value, byte[] destination, int offset)
{
if (destination == null)
throw new ArgumentNullException("destination");
if (offset < 0 || (offset + sizeof(int) > destination.Length))
throw new ArgumentOutOfRangeException("offset");
fixed (byte* ptrToStart = destination)
{
*(int*)(ptrToStart + offset) = value;
}
}

Manually unpinning a byte[] in C#?

In the following code, it seems that the client.Connect.Receive is pinning the "byte[] result" permanently, causing the memory to never be freed (as it's always pinned). I'm looking for a way to tell C# that result no-longer needs to be pinned after it's usage in this.OnReceive, but I can't find the built-in function or keyword to do this.
Does anyone know how I can get C# to unpin the byte[] array? (this is one of the sources of memory leaks in my C# application)
this.m_TcpListener = new TcpListener(this.p_TcpEndPoint.Port);
this.m_TcpThread = new Thread(delegate()
{
try
{
this.m_TcpListener.Start();
while (this.p_Running)
{
TcpClient client = this.m_TcpListener.AcceptTcpClient();
new Thread(() =>
{
try
{
// Read the length header.
byte[] lenbytes = new byte[4];
int lbytesread = client.Client.Receive(lenbytes, 0, 4, SocketFlags.None);
if (lbytesread != 4) return; // drop this packet :(
int length = System.BitConverter.ToInt32(lenbytes, 0);
int r = 0;
// Read the actual data.
byte[] result = new byte[length];
while (r < length)
{
int bytes = client.Client.Receive(result, r, length - r, SocketFlags.None);
r += bytes;
}
Console.WriteLine("Received TCP packet from " + (client.Client.RemoteEndPoint as IPEndPoint).Address.ToString() + ".");
this.OnReceive(client.Client.RemoteEndPoint as IPEndPoint, result, length);
}
catch (SocketException)
{
// Do nothing.
}
client.Close();
}).Start();
//this.Log(LogType.DEBUG, "Received a message from " + from.ToString());
}
}
catch (Exception e)
{
if (e is ThreadAbortException)
return;
Console.WriteLine(e.ToString());
throw e;
}
}
);
this.m_TcpThread.IsBackground = true;
this.m_TcpThread.Start();
You can pin/unpin it yourself, thusly:
//Pin it
GCHandle myArrayHandle = GCHandle.Alloc(result,GCHandleType.Pinned);
//use array
while (r < length)
{
int bytes = client.Client.Receive(result, r, length - r, SocketFlags.None);
r += bytes;
}
//Unpin it
myArrayHandle.Free();
But I'd personally be pretty surprised that client.Connect.Receive pins it "for all time". I've used it before (as I'm sure many have) and not run into an issue of this type. Alternately, if you're certain that's the problem, then instead of allocating a new result array each time, you can re-use one across the entire while loop (allocate it up where you start the listener, and only use lenbytes bytes each time).

Categories

Resources