Back in June of last year, Blizzard announced that it had suspended over 74,000 World of Warcraft Classic accounts that were found to be automating gameplay via botting. Bots attack the integrity of a game like WoW (stealing resources, inflating the server economy, monopolizing rare drops) that is built on time investment and patience. When I read this announcement, I was, to some extent, amused. After all, the game has been around for over 16 years, yet the botting problem appears to be one of the same.
So I got curious. How do you build a bot for a game like World of Warcraft? What about aimbots for FPS games? This will likely be broken up into a series of posts because there’s a lot of interesting shit to talk about. For now, we will go over the basics of memory scanning and editing.
My hope is that my writing here will be accessible to those of you without a programming background. Feel free to yell at me if that’s not the case.
Per usual, let’s introduce some basic terminologies to make future discussions a little bit easier.
To understand how a game bot is written, we have to understand memory editing. To understand memory editing, we first have to understand what happens when a game, or any program, is executed.
Modern operating systems uses a memory management scheme called virtual memory.
Unfortunately virtual memory is a bit of an overloaded term. In the technical sense, it is a technique whereby the operating system provides programs with an idealized abstraction of the available physical resources on a given machine. In this scheme, every process has its own virtual address space, and memory addresses in that address space are mapped to physical memory addresses by the kernel via techniques beyond the scope of this post. If you’re curious, I recommend reading this (WARNING: do not click if you have PTSD from OS).
In the non-technical sense, virtual memory is disk space used in place of RAM when compensating for shortages of physical memory (data are transferred from RAM to disk). In our case, we are interested in the technical defnition. This is important because we need to know what the virtual memory address space looks like.
A generic address space might look something like this:
Let’s go through what a simple, example program might look like on this address space to hammer the idea home. Imagine a very simple game:
I know this is a terrible game design and no one would ever play this game, but for the purposes of demonstration, please bear with me. This is what the address space for the game process might look like when the game is run:
So, how would you cheat the simple game I described above? You could theoretically do it one of the following three ways:
Let’s take strategy (3) for example. We will want to find the memory address of the global variable that denotes the healing amount, with a value of 5, and then edit that memory address to contain a value of say, 50, instead.
To do this, you might use something like Cheat Engine, which will look for the memory address of an object in a running program if you give it hints. In our case, we might tell it to look for a variable with an exact value of “5”. We might press space bar a few times to give Cheat Engine opportunities to land on the same memory address, every time we heal.
Let’s say Cheat Engine finds an answer for us and we are confident in the memory address of the variable denoting the healing amount. Now what? The tricky thing here is that each time the game program is restarted, the base memory address of the program changes. So we can’t simply reuse the same memory address each time. But we also wouldn’t want to have to look for the address of the desired variable every time the game is restarted – that would make our cheat practically useless.
Fortunately however, assuming the program code (the text itself) doesn’t change in between runs, a global variable will always be placed at the same offset from the base memory address of the program. So in our cheat, we’d want to retrieve the base memory address of the process, and edit the memory address at game_base_address + offset
to be 50, instead of a measly 5.
Inject this cheat into the game program using DLL injection (let’s not get into it here or I’m going to be writing for ages), and voila, as long as we keep pressing space bar, we will never lose the game!
I gave the example above to illustrate how memory scanning and memory editing serve as the foundation for hacking a game. But in reality, the task would be much more daunting than that.
For one, most games would be much, much more complicated in structure than what I’ve described above. Moreover, hacks for single player games might work this way, but something like this will not work for multiplayer games. This is because a lot of multiplayer games use the dedicated game server network model, where the game server holds the state of the world; as such, changing say, your character’s statistics, in the local copy of the game would not affect what other players see online.
All of this doesn’t even take into consideration of the other side of the same coin – cheat detection. Blatantly changing your character’s statistics will likely get you banned in a multiplayer game. So in programming game cheats, the developer would have to be creative in avoiding detection as well. Perhaps more on cheat prevention and detection techniques in a later post.
Botting however, is not a cheat in the traditional sense of the word. Instead of manipulating the game state to a competitive advantage, what you’re doing is writing a program that, when injected, would call the functions in the actual game in an automated, logical manner. For example, in the context of World of Warcraft, creating a program for a gathering bot would involve some combination of the following tasks:
Memory scanning:
Memory writing:
Logic to automate the bot:
To be honest, writing this post has taken far longer than what I had originally anticipated, and even at over two thousand words and an oversimplification of many of the technical details, I’ve barely scratched the surface. So I’m going to end it here for now.
With that said however, this topic, as an application of reverse engineering, assembly code analysis, memory manipulation, code injection, etc, has gotten me hooked to some extent. They say low-level programming is good for the soul… So I shall go learn more, and report back in due time.
Written on January 14th, 2021 by JY