-
Active Member
wow classic
im looking for a bit of help, I cant seem to read any of classic memory. heres a simple test I don't for Player name but its not right. and advice is much help. thanks
using System; using System.Collections.Generic; using System.Diagnostics; usi - Pastebin.com
-
Active Member
Hello.
The player name is null terminated and in UTF8 encoding.
A little helper function that might be useful to you: (Don't know where it's from anymore)
Code:
private byte[] ReadNullTerminatedBytes(ulong address)
{
int returnLength = 0;
byte[] ret = new byte[0];
int size = 0;
byte b = 0;
while (true)
{
ReadProcessMemory(ProcessHandle, address++, out b, Marshal.SizeOf(b), out returnLength);
if (b == 0)
return ret;
else
{
Array.Resize(ref ret, size + 1);
ret[size++] = b;
}
}
}
public string ReadUTF8String(ulong address)
{
return Encoding.UTF8.GetString(ReadNullTerminatedBytes(address));
}
-
@mikeymike: You need to use UTF-8, not Unicode.
@SatyPardus:
Originally Posted by
SatyPardus
Hello.
The player name is null terminated and in UTF8 encoding.
A little helper function that might be useful to you: (Don't know where it's from anymore)
Code:
private byte[] ReadNullTerminatedBytes(ulong address)
{
int returnLength = 0;
byte[] ret = new byte[0];
int size = 0;
byte b = 0;
while (true)
{
ReadProcessMemory(ProcessHandle, address++, out b, Marshal.SizeOf(b), out returnLength);
if (b == 0)
return ret;
else
{
Array.Resize(ref ret, size + 1);
ret[size++] = b;
}
}
}
public string ReadUTF8String(ulong address)
{
return Encoding.UTF8.GetString(ReadNullTerminatedBytes(address));
}
While this code would work, its a horrible way of doing it.
- The code starts with a size 0 byte array
- it uses one read per byte
- it grows the array each time it doesn't find a termination byte
- it uses Mashal.sizeof() in a loop while the size is already known (its 1...)
- There is no upper limit for the string size to prevent uncontrolled run-off
Just read multiple bytes into a properly sized buffer. Reading 32 bytes at once for example will yield the player name in more than 99% of the scenarios (since there wont be many players that have a 4-byte UTF8 character for each character in their name - and even then, it would be a maximum of 49 bytes)
The following solution is still not perfect (i dont really use ReadProcessMemory). It assumes that the memory region that is being accessed is valid, readable, etc. Its also missing partial read checks.
Code:
private static string ReadString(IntPtr process, IntPtr address, Encoding encoding = null, int sizeLimit = 256, int batchSize = 32)
{
var buffer = new byte[batchSize];
var list = new List<byte>();
int nullIndex;
do
{
if (!ReadProcessMemory(process, address + list.Count, buffer, buffer.Length, out var numberOfBytesRead))
throw new InvalidOperationException("Unable to read memory");
nullIndex = Array.FindIndex(buffer, b => b == 0);
list.AddRange(buffer.Take(nullIndex == -1 ? numberOfBytesRead : nullIndex));
if (nullIndex >= 0)
break;
} while (list.Count < sizeLimit);
return (encoding ?? Encoding.UTF8).GetString(list.ToArray());
}
Last edited by xalcon; 10-26-2019 at 03:26 PM.
"Threads should always commit suicide - they should never be murdered" - DirectX SDK
-
Post Thanks / Like - 1 Thanks
mazer (1 members gave Thanks to xalcon for this useful post)
-
Active Member
ok what about reading GUID? I couldn't seem to get your method to work for name, but SatyPardus method did and his also might have worked for objMgr as well but not sure.
-
Active Member
So here is my memory read class. does not work any help?
Code:
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(IntPtr hProcess,
ulong lpBaseAddress, out byte lpBuffer, int dwSize, out int lpNumberOfBytesRead);
public static byte[] ReadBytes(IntPtr process, ulong address)
{
int returnLength = 0;
byte[] ret = new byte[0];
int size = 0;
byte b = 0;
while (true)
{
ReadProcessMemory(process, address++, out b, Marshal.SizeOf(b), out returnLength);
if (b == 0)
return ret;
else
{
Array.Resize(ref ret, size + 1);
ret[size++] = b;
}
}
}
public static ulong readUInt64(IntPtr process, IntPtr address)
{
byte[] ba = ReadBytes(process, (ulong)address.ToInt64());
return BitConverter.ToUInt64(ba, 0);
}
public static uint readUInt32(IntPtr process, IntPtr address)
{
byte[] ba = ReadBytes(process, (ulong)address.ToInt64());
return BitConverter.ToUInt32(ba, 0);
}
public static ushort readUInt16(IntPtr process, IntPtr address)
{
byte[] ba = ReadBytes(process, (ulong)address.ToInt64());
return BitConverter.ToUInt16(ba, 0);
}
public static float readFloat(IntPtr process, IntPtr address)
{
byte[] ba = ReadBytes(process, (ulong)address.ToInt64());
return BitConverter.ToSingle(ba, 0);
}
and im calling these
Code:
uint objManagerPointer = MemoryReader.readUInt32(WoW_Instance.getProcess().Handle, WoW_Instance.baseAddress + 0x232DED8);
ulong GUID = MemoryReader.readUInt64(WoW_Instance.getProcess().Handle, WoW_Instance.baseAddress. + 0x26243D0);
uint firstObj = MemoryReader.readUInt32(WoW_Instance.getProcess().Handle, new IntPtr(objManagerPointer + 0x18));
any help is much appreciated thanks.
-
Contributor
Originally Posted by
mikeymike
ok what about reading GUID? I couldn't seem to get your method to work for name, but SatyPardus method did and his also might have worked for objMgr as well but not sure.
struct GUID {
int guid1;
int guid2;
int guid3;
int guid4;
};
-
Active Member
but my read function isn't reading right I don't think.
Code:
uint objManagerPointer = MemoryReader.readUInt32(WoW_Instance.getProcess().Handle, WoW_Instance.baseAddress + 0x232DED8);
pretty sure that's reading wrong too.
-
Member
Originally Posted by
ChrisIsMe
struct GUID {
int guid1;
int guid2;
int guid3;
int guid4;
};
the Int128 implementation is also worth to mention:
WowMoPObjMgrTest/Int128.cs at master . tomrus88/WowMoPObjMgrTest . GitHub
usage can be found in the other source files
edit: there is a nuget package for Int128 and UInt128 too:
package name: UltimateOrb.Int128
GitHub - LEI-Hongfaan/UltimateOrb.Int128: Provides Int128 and UInt128.
Last edited by mazer; 10-27-2019 at 01:50 AM.
-
Active Member
With C# there are no need for any external library to obtain a int 128 bit class
Just use: BigInteger Struct (System.Numerics) | Microsoft Docs
Where you as well have access to Vector3, ViewMatrix4x4 and everything else needed for Vector math.
-
Active Member
Originally Posted by
mikeymike
but my read function isn't reading right I don't think.
Code:
uint objManagerPointer = MemoryReader.readUInt32(WoW_Instance.getProcess().Handle, WoW_Instance.baseAddress + 0x232DED8);
pretty sure that's reading wrong too.
Pointers are 64bit, så use UInt64 instead.
-
Ofc its not working. You should stop using code that you don't understand because your "ReadBytes" method is just wrong. It works for Null-Terminated strings but not for anything else.
"Threads should always commit suicide - they should never be murdered" - DirectX SDK
-
Member
Originally Posted by
NoxiaZ
good to know, didn't look further into this because i knew of the int128 stuff.
allready using system.numerics so switching to it may saves me one dependency.
-
Active Member
Originally Posted by
xalcon
Ofc its not working. You should stop using code that you don't understand because your "ReadBytes" method is just wrong. It works for Null-Terminated strings but not for anything else.
example please?
-
Originally Posted by
mikeymike
example please?
It's not like there are a million samples on the internet on how to read memory....
This code was part of an old project, I only updated some of the code to dotnet core 3.0
You might need VS2019 to open it.
xalcon/ClassicObjectManager - Gogs
Last edited by xalcon; 10-27-2019 at 01:50 PM.
"Threads should always commit suicide - they should never be murdered" - DirectX SDK