IntelSDM / RustDMACheat

Small DMA Cheat For Rust
MIT License
182 stars 55 forks source link

How Do You Get Entity Position? #4

Closed ConnorMAD closed 9 months ago

ConnorMAD commented 9 months ago

Hi, I'm learning and I'm analyzing your code, I've seen a lot of things in it, could you help me with just one thing? How to get the position of entities?

IntelSDM commented 9 months ago

Getting Player Position

void BasePlayer::UpdatePosition(VMMDLL_SCATTER_HANDLE handle)
{
    TargetProcess.QueueScatterReadEx(handle, PlayerModel + Position, reinterpret_cast<void*>(&TransformPosition), sizeof(Vector3));
}

Caching the playerlist, do this every 3-5 seconds.


void BasePlayer::CachePlayerList()
{
    if (VisiblePlayerList == 0)
        return;
    std::vector<std::shared_ptr<BasePlayer>> templayerlist;
    uint32_t size = TargetProcess.Read<uint32_t>(VisiblePlayerList + VisiblePlayerListSize);
    uint64_t buffer = TargetProcess.Read<uint64_t>(VisiblePlayerList + VisiblePlayerListBuffer);
    if (size == 0 || buffer == 0)
        return;
    std::vector<uint64_t> playerlist;
    playerlist.resize(size);
    auto handle = TargetProcess.CreateScatterHandle();
    for (int i = 0; i < size; i++)
    {
        TargetProcess.QueueScatterReadEx(handle, buffer + (0x20 + (i * 8)), reinterpret_cast<void*>(&playerlist[i]), sizeof(uint64_t));
    }
    TargetProcess.ExecuteScatterRead(handle);
    TargetProcess.CloseScatterHandle(handle);
    handle = TargetProcess.CreateScatterHandle();
    for (int i = 0; i < size; i++)
    {
        if (playerlist[i] == NULL)
            continue;
        templayerlist.push_back(std::make_shared<BasePlayer>(playerlist[i], handle));
    }
    TargetProcess.ExecuteScatterRead(handle);
    TargetProcess.CloseScatterHandle(handle);
    PlayerList = templayerlist;
}

Looping PlayerList

std::shared_ptr<CheatFunction> PlayerLoop = std::make_shared<CheatFunction>(0, []()
{
    if (!BaseLocalPlayer->IsPlayerValid())
        return;

    if (BaseLocalPlayer->PlayerList.size() == 0)
        return;
    auto handle = TargetProcess.CreateScatterHandle();
    int count = 0;
    std::vector<std::shared_ptr<BasePlayer>> templayerlist = BaseLocalPlayer.get()->PlayerList;
    for (int i = 0; i < templayerlist.size(); i++)
    {
        std::shared_ptr<BasePlayer> player = templayerlist[i];
        count += player->IntializeClasses(handle);
    }
    if (count != 0)
        TargetProcess.ExecuteScatterRead(handle);
    TargetProcess.CloseScatterHandle(handle);

    handle = TargetProcess.CreateScatterHandle();
    for (int i = 0; i < templayerlist.size(); i++)
    {
        std::shared_ptr<BasePlayer> player = templayerlist[i];
        if (!player->IsPlayerValid())
            continue;
        player->UpdatePosition(handle);
    }
    TargetProcess.ExecuteScatterRead(handle);
    TargetProcess.CloseScatterHandle(handle);
    json jsoned;
    CurrentMatrix = Camera->GetViewMatrix();
    for (int i = 0; i < templayerlist.size(); i++)
    {
        std::shared_ptr<BasePlayer> player = templayerlist[i];
        if (player->IsLocalPlayer() || !player->IsPlayerValid())
            continue;
        Vector3 position = player->GetPosition();
        if (position == Vector3(0, 0, 0))
            continue;
        Vector2 screenpos = WorldToScreen(position);
        if (screenpos.x == 0 && screenpos.y == 0)
            continue;
        TestObjectJson testobject;

        testobject.X = screenpos.x;
        testobject.Y = screenpos.y;
        testobject.Name = "Player";
        testobject.Type = 1;
        json entry;
        testobject.ToJson(entry);
        jsoned.push_back(entry);
    }
    std::lock_guard<std::mutex> lock(TCPClient->HandlerLock);
    {
        if (TCPClient->SendPackets && !jsoned.is_null())
        {
            TCPClient->SendText(jsoned.dump());
        }
    }
});

More offsets you need for baseplayer

    uint64_t VisiblePlayerList = 0x20; //   private static ListDictionary<ulong, global::BasePlayer> visiblePlayerList;
    uint64_t VisiblePlayerListBuffer = 0x18; // list value 
    uint32_t VisiblePlayerListSize = 0x10; // list size

    uint64_t PlayerModel = 0x678; //public PlayerModel playerModel;
    uint64_t Position = 0x1B8; // PlayerModel -> internal Vector3 position;
    bool Initialized = false;
    Vector3 TransformPosition = Vector3(0, 0, 0);

I have missed the calls for getting playermodel address and all the typical reads to it but you can just read them in the baseplayer constructor. All the offsets you need are there and all the code is there to get all the player positions

ConnorMAD commented 9 months ago

wow, thank you so much. Another thing I was unsure about, these offsets: uint64_t VisiblePlayerList = 0x20; // private static ListDictionary<ulong, global::BasePlayer> visiblePlayerList; uint64_t VisiblePlayerListBuffer = 0x18; // list value uint32_t VisiblePlayerListSize = 0x10; // list size

Where were they taken from? because 0x20 is linked to VisiblePlayerList Sorry for the questions, I believe they are silly, but I am learning and I am still new, I would like to learn more about reverse engineering.

IntelSDM commented 9 months ago

So 0x20 is from Baseplayer. Baseplayer + 0x20 is the address to the list datatype that contains the list of players. To explain the other values I need to say this, Whenever you store a list or an array it's just a class /struct(depending on C++ or C) so since we aren't just reading into the values, we are reading the C# List class. There are a few variables in The List class, but the ones we need for unity hacking are the size and the buffer. The size is the size of the list and the buffer is the actual datatypes in a raw array format. These values shouldn't ever change unless for some reason Microsoft updates the .NET framework's List class. So that's where and why we read 0x18 and 0x10 from any lists we want to read within Unity games or hell most games that don't just use a flat-out array.

ConnorMAD commented 9 months ago
                            if "BasePlayer" or "NPCPlayer" in szName:
                                try:
                                    TEMPTEMP = self.mem.read_ulonglong((pObject + 0x18))
                                    temp_pObject = self.mem.read_ulonglong((TEMPTEMP + 0x28))
                                    print(temp_pObject)
                                    name = self.mem.read_ulonglong(temp_pObject + off_displayname)
                                    intname = self.mem.read_int(name + 0x10)
                                    name_ = ""

                                    for i in range(intname):
                                        name_ += str(self.mem.read_string(name + 0x14 + i))

                                    if temp_pObject == LocalPlayer:
                                        pass
                                    else:
                                        pos_ = self.mem.read_ulonglong(temp_pObject + off_playermodel)
                                        pos = self.read_vec3(pos_ + 0x1B8)
                                        health = int(self.mem.read_float(temp_pObject + 0x25C))
                                        self.entities.append(Entity(pos, "Player", health = health, playername = name_))
                                        continue

what i doing wrong?

ConnorMAD commented 9 months ago

I can get the positions, but the names are not

IntelSDM commented 9 months ago

I haven't gotten around to working on my other version of this for ESP for a while as I have other projects to complete so i don't read the displayname but print out the values for each of your reads and put them in ReClass.net in a none EAC build of the game. You will see the addresses for everything in the class you are looking at and the contents of each byte and if it's heaped or not. I am going to guess its this code though:

                                    for i in range(intname):
                                        name_ += str(self.mem.read_string(name + 0x14 + i))

That looks completely wrong and will not work, Look in consolecommands.cpp and you will see how I read strings. Do it the exact same way, read it as a char array, they should have them in python, something like this:

myArray = "\0" * 100

https://stackoverflow.com/questions/34675555/python-char-array-declaration Just convert the char array back to a string.

ConnorMAD commented 9 months ago

i got it, thanks. Last thing, I promise, it has helped me a lot

                        if overlay.esp:
                            if i % 100 == 0:
                                camera = self.mem.read_ulonglong(self.gameassembly_base + 0x3417CD8)
                                matrix4x4 = []
                                print(matrix4x4)
                                for j in range(16):
                                    matrix4x4.append(self.mem.read_float(self.mem.read_ulonglong(camera + 0x18) + 0xDC + 0x4 * j))
                                overlay.matrix4x4 = matrix4x4

I'm using a matrix to store and then send to my wts, but I'm having difficulty reading the data to send

IntelSDM commented 9 months ago

Firstly, Don't read the camera constantly, It also appears you are reading from the camera manager which is honestly just a mess. Read from MainCamera.

MainCamera::MainCamera()
{
    printf("[MainCamera] Initialized\n");
    uint64_t maincamera = TargetProcess.Read<uint64_t>(TargetProcess.GetModuleAddress(L"GameAssembly.dll") + Class); // Get Class Start Address
    printf("[MainCamera] MainCamera: 0x%llX\n", maincamera);
    this->StaticField = TargetProcess.Read<uint64_t>(maincamera + StaticField); // Set Static Padding
    printf("[MainCamera] Static Fields: 0x%llX\n", StaticField);
    this->Camera = TargetProcess.Read<uint64_t>(StaticField + Camera); // Current MainCamera
    printf("[MainCamera] Camera: 0x%llX\n", Camera);
    this->CameraGamoObject = TargetProcess.Read<uint64_t>(Camera + CameraGamoObject); // get the native gameobject
    printf("[MainCamera] CameraGamoObject: 0x%llX\n", CameraGamoObject);

}
bool MainCamera::IsValid()
{
    return Camera != 0;
}
ViewMatrix MainCamera::GetViewMatrix()
{
    ViewMatrix viewmatrix;
    viewmatrix = TargetProcess.Read<ViewMatrix>(CameraGamoObject + ViewMatrixOffset);
    return viewmatrix;
}
class MainCamera
{
    /*
    Script.json
    "Address": 55074032,
      "Name": "MainCamera_TypeInfo",
      "Signature": "MainCamera_c*"
    */
    uint64_t Class = 0x3485CF0;
    //Dump.cs / DummyDLL
    uint64_t StaticField = 0xB8;// Static Padding To Access Static Fields
    uint64_t Camera = 0x0;// public static Camera mainCamera
    uint64_t CameraGamoObject = 0x10;
    uint64_t ViewMatrixOffset = 0x2E4;
    ViewMatrix CacheMatrix;
public:
    MainCamera();
    bool IsValid();
    ViewMatrix GetViewMatrix();
};
struct ViewMatrix
{
public:
    float matrix[4][4];

    Vector3 Transform(const Vector3 vector) const;
};
ConnorMAD commented 9 months ago

you are amazing, really thank you for your help!

ConnorMAD commented 9 months ago
                        if overlay.esp:
                            if i % 100 == 0:
                                camera = self.mem.read_ulonglong(self.gameassembly_base + 0x3485CF0)
                                matrix4x4 = []

                                for j in range(16):
                                    # Correção aqui: Use self.read_chain
                                    camera_manager = read_chain(self, camera, [0xB8, 0x0, 0x10])
                                    camera_managerr = self.mem.read_float(camera_manager) + 0x2E4
                                    matrix4x4.append(camera_managerr * j)
                                print(overlay.matrix4x4)
def read_chain(self, address, offsets):
    current = address
    for offset in offsets[:-1]:
        current = self.mem.read_ulonglong(current + offset)
        if current == 0:
            return None
    return self.mem.read_ulonglong(current + offsets[-1])

what am i doing wrong?

ConnorMAD commented 9 months ago

i got it:

                        if i % 100 == 0:
                            camera = self.mem.read_ulonglong(self.gameassembly_base + 0x3485CF0)
                            matrix4x4 = []

                            for j in range(16):
                                # Correção aqui: Use self.read_chain
                                camera_manager = read_chain(self, camera, [0xB8, 0x0, 0x10])
                                camera_managerr = camera_manager + 0x2E4
                                camera_managerrr = self.mem.read_float(camera_managerr + (j * 4))

                                matrix4x4.append(camera_managerrr)
                                overlay.matrix4x4 = matrix4x4
                            print(overlay.matrix4x4)