Warsow, first assault (part 1)

Warsow, first assault (part 1)

Introduction

I wrote this short post to give some news about my journey in the cheats development. Unfortunately, I didn’t have time to work on it. I just resumed my researches and I take this opportunity to write a very basic article in English.

The last hour, I made a simple proof of concept allowing to retrieve some data about an opponent on Warsow (a FPS game). To be more precise, the goal was to develop a tool that get the position of my opponents in real time just by reading the /proc/mem file.

Why did I choose Warsow? It’s the first time I try to develop a cheat for a game. I needed a game without anti-cheat or protection (anti-debug, etc.) to focus on the interesting parts. When I get better, I’ll try on bigger game (e.g. Team Fortress 2).

EDIT: at the beginning, I wanted to write a short article but I realized that I wrote more than expected (to such an extent that it will be split in two parts). If you have some knowledge about cheats, I think this post will not be interesting for you.

My setup

To explore the Warsow memory during a network game I launched two instances. The first one hosted the game (I’ll call it « opponent » or « server » in the rest of this article). The second one was just connected to the server (also called « us » or just « process »).

On the left, the opponent (and the server), on the right, us.

Because I’m too lazy, the server and the two instances are on the same computer. Usually, each of them is on a distinct computer.

In this article, our job is to retrieve interesting information about the first player (like its position) by analyzing the memory of our game.

Opponent information

In this step, we have to find where are the opponent information into the memory of our Warsow process. It may be interesting to wonder about how the developers choose to store player data. With some basic knowledge about C programming (yes, Warsow is coded in C), the most likely answer is that these ones are grouped into a struct, for example:

struct player
{
    float x;
    float y;
    float z;
    /* [...] */
};

However, we don’t really know what is shared by the server to other players. For example, it seems logical to share the position of each player, otherwise how would your game displays your opponents without this info? On the other hand, some data are not specifically mandatory. Think about the health of your enemies, this info could only be stored into the server. By playing the game, we can write a short list of mandatory shared attributes:

  • The position (x, y, z): as explained, if opponents are displayed by our client, their position are necessarily received from the server.
  • The name of the player: we can see it in various places.
  • The model: it is possible to change the player model (a pig, a fat guy, etc.).
  • The active weapon: when an opponent change his weapon, we can see the animation and the new weapon.
  • etc.

Now it is possible to assess the ease of finding these values into the process memory. For example, it’s not very easy to directly find the position without any hint. Each player starts at a different position that is not the origin. The player name can also be difficult. It may be used in several way without being linked to the player struct (e.g. when the player just connected, a message with its name is displayed). In fact, there is no obvious requirement for such a link between the name and the struct.

To be honest, I first tried to watch if the health of each player was shared. But my researches resulted in nothing (in fact, that’s not a surprise) . So I looked for another shared attribute and I found that the active weapon could be a good candidate. Indeed, in Warsow, there are only 8. Thus, we can assume that each weapon has an id (0 for the first one, 1 for the second, etc.) and try to localize this value into our game memory. Thus, to find the weapon field of the player struct, we can do that:

  1. In the opponent game, choose the first weapon.
  2. In our game memory, scan each cell with the value 0 (here, we assume that the weapon index starts at 0).
  3. In the opponent game, choose the second weapon.
  4. In our game memory, among each of the cells of the step 2, only keep those whose value change to 1.
  5. Continue the same steps with other weapons if needed.

To scan the game memory, I used the well-known Cheat Engine. Thanks to Wine and ceserver, it works well on Linux (with some minor bugs probably due to Wine).

If you try the previous steps you will find nothing. The first time I was wondering why? The data must be here! However, this one can be stored in some other ways, example: for an obscure reason, the first weapon can have the id 7, the second the id 6, etc. But simpler than that, the weapon id might just start at 1 (rather than 0). And actually, that was the good solution!

Below is a demonstration. The left window is the game of our opponent (and the server). On the right, this is our game. In the middle, it’s Cheat Engine that is attached to our game (the right one). We can see that when the opponent changes his weapon, the value in our game change too.

As explained before, the weapon id must be a simple field of the player struct. Now, we have to find where starts this structure. If you have some basics of assembler, it’s not very difficult. Often when we use a struct in assembler (us or the compiler), we use an indexed operands. In an indexed operand there are:

  • A base address: its the address of the first field of the struct.
  • An offset: it allows to move from the first field to an arbitrary field.

For example:

mov byte [rdi+0x04], 1

In such an instruction, the address of the struct is stored into rdi and the offset is 0x04.

Thus, in our game, we can find the base address of the player struct by analyzing the instruction that writes or access the weapon index:

Voilà! We just got the struct address of the player in the register rbx: 0x7f566fbf6820. Now, we have to find the x, y and z fields. They must be stored into the same structure than the weapon index. Cheat Engine can help us with its data structure dissector. Here is a demo:

In this video, we can see that some fields (inferred by Cheat Engine) change when the opponent moves. Now, it’s easy to spot the position:

  • x is at offset 0x1C.
  • y is at offset 0x20.
  • z is at offset 0x24.

Maybe you noticed some other strange fields whose value changes when the player moves and come back to 0 shortly after he stopped. Yes, it’s probably the velocity:

  • v(x) at 0x34.
  • v(y) at 0x38.
  • v(z) at 0x3C.

Note that Cheat Engine didn’t find the right data type (it founds 4 bytes rather than a float). These values was 0 during the dissecting and nothing can indicate that 4 consecutive null bytes is a float.

The middle end

In the next article, we will see how to get a pointers path starting from a static address and the code of the useless tool described into the introduction.

To conclude, a short demo:

Related articles

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.