Go Back

Rift - The Entities

For the purpose of this blog I will refer to an older version of Rift (an open beta version, dated 20-2-2011), since the latest version is missing some of the IDA info (lazy :) and I expect you to have some IDA and debugging knowledge and I expect you to have the decompiler plugin as well.

Well I said I was going to blog about Rift, so here is the first in a few blogs about Rift. I will not have any code-samples for you to play with and you will have to lookup the latest pointers yourself (if you wish to play with this info). But I'll try to explain how I got the info that I needed.

The first thing I am usually interested in when looking at a new MMO is the way it stores its entities, you know the other players, the npcs, etc. Knowing how the game stores it's entities is vital for creating bots, radars, etc. It is not vital for float hacking, teleport hacking and speed hacking, but I usually stay away from those types of hacks.

We know what we are looking for, but the question quickly arises "how do you look for something like that", well luckily for us hackers most new MMO's have in-game commands and functions to help you out. Rift also has a command which helps you to find this and it's called "/target". With that nice command you can target anything in-game by name. As such this command must (somehow) loop through all the entities (or at least part of them) to find out which entity you want to target.

So the first thing we want to do is find the function responsible for the target-command, we open up IDA's string-list and look for "target" and we look at the references to "aTarget" (the variable name IDA gives it), one line stands out which is "mov eax, offset aTarget". If we visit the reference, we find a function which is pretty empty. If we check the reference of that function, we see its a virtual function of a class. With a bit of trial/error, it was easy to find out that the class in question is indeed the target-command class, and the 3rd virtual function is the actual SlashTarget function (we will call it SlashTarget from now on). The process of finding the correct function differs per game, but in this case it was easy.

If we open up SlashTarget we see a reasonably large function, which does a lot of things. Most of which we do not care about, the one thing we do care about though is the string "No target with the name: [%NAME]", it indicates that the target we are looking for does not exist. If we look a bit up (in the decompiled view) then we see that a function is called prior to the "if" that leads to the "No target" string. In this case it was sub_64A500. If we open up that function we see a "while (1)" loop.

I will spare you the details, while the loop does loop through all the entities. It is not looping through the actual entity list but rather a copy of it. Having no idea how it got this copy, I did something that I usually try to avoid (with a passion), I opened up OllyDBG set a breakpoint at the start of SlashTarget and at the end of SlashTarget, used the command and traced all instructions. This is a horrible way of reverse engineering, but it does work :) (note, I did have to enable "Remember memory" in the debugging -> run trace options of OllyDBG)

Ending up with a 100-150mb tracelog, you can understand why you'd want to avoid this. However it does give meaningful insight. The way I went about it was to do a "/target <someone>" and having the name in lowercase. This way I could see the difference between the entity name and the target-command argument. Now I looked for the first occurrence of <someone> in the correct case. From there I back-traced all the pointers to its origin.

The first occurrence of the pointer was inside the function (sub_6E0100) that copied the entity list. Back tracing where it was called I found out that it was indeed called from sub_64A500, and to be more precise this line "(*(void (__thiscall **)(void *, struct tm **))(*(_DWORD *)v8 + 0x18))(v8, &Tm);" (yeay for IDA screwing up half of rift by adding some TM structure).

It's reasonably easy to find out what function is at 0x18, if you look at the v8 you see its filled by a function a few lines above the call. If you look into that function then near the end you will see that it is actually setup by another function. Then if you dive into that function you'd see what the class v-table is. If you go to the v-table and get the function at 0x18 (the 6th function), the function should look like this. If you then dive into that function you will see sub_6E0100 being called.

If we inspect sub_6E0100 we'll probably agree that it's a bit of a nasty beast. At least it took me a few tries to get the data out correctly (at least I think I have it correct now). I can't remember how I exactly found out, but the EntityManager that I marked when looking for the v-table has the entity array that this function is looping through at offset-4 and the length (parameter a3) at offset-8. I am pretty sure that was from back-tracing the trace-log.

After a lot of trial and error (and trying to figure out how the freaking sub_6E0100 function worked), I came to this C# code:

var entityManager = memory.ReadInteger(_entityManager);
var entityArray = memory.ReadInteger(entityManager + 4);
var entityArrayLength = memory.ReadInteger(entityManager + 8);

var items = new List<int>();
for (var i = 0; i < entityArrayLength; i++)
{
    var entityArrayItem = entityArray + i * 0x18;
    int nextAddress = memory.ReadInteger(entityArrayItem + 0x10);
    if ((nextAddress & 1) == 1)
    {
        nextAddress ^= 1;
        if (nextAddress == 0)
            continue;
    }

    while (true)
    {
        items.Add(entityArrayItem);

        entityArrayItem = memory.ReadInteger(entityArrayItem + 0x10);

        if ((entityArrayItem & 1) == 1)
            entityArrayItem ^= 1;
        if (entityArrayItem == 0)
            break;
    }
}

I did a few compares a bit differently then the original Rift code, mostly because I wasn't getting the expected behavior in C# (mainly the ^= part).

Basically from analyzing the function I came to the conclusion that the EntityArray is not 'really' an array but more a hash table. The initial item's are in the array (0x18 bytes in size) and if more item's are in the same bucket, then the next item is stored at 0x10 . The entity id is stored at offset 0 (its a ulong) and the pointer to the entity itself is stored at offset 8.

Why the first bit is sometimes set when there is also a pointer in at 0x10 is a bit unclear to me. Perhaps someone else can shed some light on that ? :)

The above code sample does get all entities. My next blog (that I'll put up in a few days) will explain a bit about how Rift stores data for its entities (if you have a beta-exe still lying around, look for the "EntityComponent"'s).

This game takes OO very serious, things are stored so many level's deep it's very annoying :)

Posted by: Da_Teach on Saturday, March 5, 2011  •  Rift Decompiler IDA Pro

  • Facebook
  • Twitter
  • DZone It!
  • Digg It!
  • StumbleUpon
  • Technorati
  • Del.icio.us
  • NewsVine
  • Reddit
  • Blinklist
  • Add diigo bookmark
  • It's interesting the route you went through /target and its vtable. I was working the same angle with /targetexact. I'm not a fan of using hex-rays because information is often lost due to wonky register management, particularly in Rift; the _mkgmtime misname and TM structs all over the place are a┬átestament┬áto that ;-)

    Thanks for the post either way. My other projects take precedent over riffing on Rift and I've had to shelve REing it for a while. You should really give Olly some more love. A simple hardware breakpoint can save you ages in instances of things like a delegate managing routine. call edx will never show up as a reference to your vtable routine even though that's what gets called at runtime.

    _orca  •  17 Mar

  • very nice. I took the same route, working on the slash commands. They are easy to reverse and you can even call them from inside the process. You know you can simply remove the tm type, so ida wont fuck up the code. Da_Teach, if you like, contact me on mmoelites or join us at riftminion, so we can have a talk.

    HansW  •  18 Mar

  • Basically from analyzing the function I came to the conclusion that the EntityArray is not 'really' an array but more a hash table. The initial item's are in the array (0x18 bytes in size) and if more item's are in the same bucket, then the next item is stored at 0x10 . The entity id is stored at offset 0 (its a ulong) and the pointer to the entity itself is stored at offset 8.
     
    Why the first bit is sometimes set when there is also a pointer in at 0x10 is a bit unclear to me. Perhaps someone else can shed some light on that ? :)


    I just happened to see your rift blogs today.   I scanned through and noticed your question above.

    0x10 (in the class to which you're referring) is a bit field, not a pointer.   I use an old favorite (C) function like this to process bit fields such as that:

    char *GetBitFlags(unsigned int Flags)
    {
        char tmp[MAX_STRING] = {0};
        static char Output[MAX_STRING] = {0};
        unsigned int i = Flags;
        unsigned int bitval = 1;
     
        Output[0] = '\0';
        while (Flags  > 0)
        {
            if (Flags & 1)
            {
                sprintf(tmp, "%xh ", bitval);
                strcat(Output,tmp);
            }
            Flags >>= 1;
            bitval <<= 1;
        }
        return Output;
    }

    -----------------------------------


    (yeay for IDA screwing up half of rift by adding some TM structure).

    Also, I'm sure you probably figured it out, but for the benefit of everyone else, IDA is recognizing one of Rift's primary memory allocation (or reallocation) functions as __mkgmtime.   That's why 'tm' keeps appearing everywhere.


    Amadeus  •  10 Apr

  • you guys look way deeper into a game than i do, main thing i'm interested is gameplay not slash commands etc. well each to there own i guess

    tonbridge plasterer  •  12 Jul

  • You can use these tricks to get the website for the fifa 18 coins generator to work for the generation of coins of fifa 18 online here.

    jenny  •  16 Oct

  • You can be using the website for the free fifa 18 coins generator here.

    sadas  •  16 Oct

Post a comment!
  1. Formatting options