Reverse Engineering Trash RTS - Creating a Chat Bot - P1

Introduction

About 15 years ago, during my early teens, I came across a realtime strategy (RTS) game called Trash. I spent years playing it and I think I became pretty good at it. The game included a lobby where players could chat and create game instances that other players could join. Unrelated, but relevant, it was around that time that I developed an interest in programming and figuring out how computers worked.

I remember one of the other players (Sacha) doing really cool things like creating “bots” that could respond to messages. He taught me a lot at the time (about programming) and introduced me to OllyDbg; at the time I had no clue what was going on and I think I remember solving a crackme by randomly changing jxx instructions. Soon after, I was playing with the Win32 API and sockets. I remember wanting to create a bot of my own. I tried. I failed. I remember looking at the packets in Wireshark and not having a clue as to what was going on because of all the binary data surrounding the text I’d see. I also remember opening Trash.exe in OllyDbg and not being able to find where it was constructing messages.

At the point in time, I think the learning curve was a bit too steep for me. I didn’t know enough. Now, about 10 years later, I decided that I would give it another shot. This blog post is me describing the parts of my process that worked and ultimately, what the outcome was.

Goal

My goal was to create a chat bot. However, that was a bit too vague and I decided to decide on what the MVP would look like. I came up with a really simple list of requirements that I could build on later.

  1. Given a username and password, the bot should be able to connect to the game lobby and appear as any other user would (in the member list).
  2. The bot should be able to receive chat messages sent by other users to the game lobby.
  3. The bot should be able to know when a user joins the lobby.
  4. The bot should be able to send messages to the lobby.
  5. Combining 3+4: When a user joins the lobby, the bot should send a message to the lobby saying, “Welcome, <user>!”
  6. Combining 2+4: When a user says “Hello” to the lobby, the bot should send a message to the lobby saying, “Hello, <user>!”

What do we know?

Luckily for me, I had a lot of experience actually using the game client and I had attempted to create a bot before. This gave me a bit of a headstart. I parsed through all of the details I could remember and made note of the things that seemed relevant.

  1. The game client uses UDP for everything (login + chat + gameplay). However, the game also used a library called RakNet. The only thing I really needed to know about RakNet was that it created a layer above UDP that then encapsulated the actual Trash data.
  2. I remembered that when viewing packets in Wireshark, I could see details like my username, password and outgoing/incoming chat messages in plaintext (although it was surrounded by binary data). This means that there wasn’t any encryption being used. That would make my life a lot easier.
  3. If you tried to connect to the lobby without a balance file (local .txt file that contained a lot of game-related data) that didn’t match the official one, it would stop the login process and force you to download the official one. This meant that the balance file was checked somehow when connecting to the lobby.

Where to begin?

Login process

Observing the data

Wireshark - what can we tell? data in plaintext, with crap surrounding it

Probably mostly raknet

Approach

Don’t try to reverse engineer RakNet Let’s re-use the existing RakNet DLL and build on top of that.

RakNet Research

We don’t have documentation for the version being used. While the internals may have changed quite a bit and some of the apis might have as well, there should be enough similiarity to give us some hints.

Figure out which functions are typically called, etc

Observing what actually happens

x64dbg

Which functions are called?

RakPeer

What arguments does it take? Which ones do we care about? What’s the functions calling convention?

GetSocketDescriptor

Startup

Connect

Send

Receive

Building bridges

Putting it all together