[This chapter excerpt is printed with permission of Addison-Wesley Professional from the book Exploiting Online Games by Gary McGraw and Greg Hoglund. Please note that Gamasutra itself presents this excerpt as a service to professional game developers wanting to learn about exploitation techniques, and does not advocate using the below techniques to exploit games.]
Data, Data, Everywhere
Two kinds of things can be altered in a software program—the code itself and the data that the code interacts with. (Just to complicate matters, the code itself is, of course, a form of stored data.) Ultimately, everything is just data—a sea of perfectly choreographed 1s and 0s. This insight has huge ramifications for the online game hacker.
Any data that are sent to a game client can be accessed or modified. Once data exist in the game client, they are yours for the taking (and yours for manipulating)—even data you’re not supposed to see. For example, if the game client knows the location of a hidden secret potion, those data must exist in the game client somewhere even if the data are not apparent to you in the user interface. Making this even more fun, many times these game data can be manipulated and changed. For example, if the hidden magic potion is too far away, perhaps you can alter its location coordinates so that it conveniently ends up on the ground right in front of you!
Game clients display information to the game player through the user interface. However, the interface displays only part of the information that the client software possesses—the part that the player is supposed to see. There is often plenty more information under the hood. Assume that there is a magic potion, and that the potion has properties including strength, power, and duration. Under the hood, a software program is managing the magic potion. In our example, if the strength of the magic potion is greater than 100, you get an extra bonus. When you click the Drink button, the potion’s strength will be checked by the software and a bonus may be applied (but only if the condition is met).
As we noted earlier, at the deepest layer of the game client, everything is just data. Even the software itself is stored as data. The software that makes the potion decision is stored in one location, and the data that represent the potion’s strength are stored in a different location. This is typically how it is—executable software bytes are stored in a special area away from the rest of the data. To complete our example and see how all of this matters, if you wanted to fool this game into giving you a bonus, you could go into memory and alter the data that control the potion’s strength. If you set the potion strength data to a number greater than 100, then when the software executes (after you click the Drink button), it will give your character a bonus. You might do this with a fault injection engine or a debugger, or maybe just by poking a value into memory by hand.
The user interface displays only part of what the client software knows. Sometimes you’re supposed to see only pieces of what the software knows as part of the game. In this case, more information about the magic potion is available in the program than is ever displayed to the user. We can look at the software and the data to learn more.
This begs the question of how hard it really is to find out where the potion’s strength is stored. This may sound a bit like a needle-in-a-haystack problem. There are in many cases millions of bytes of data in a single running program. Simply taking a stroll around in the data without a guide turns out to be not very useful. You need some kind of guide to show you what kind of data you’re looking at, and even more specifically, how the data are used. Fortunately, a number of tools and techniques are at your disposal.
First, and most important, data get used. Data are either code or data operated on by code (and in some more complicated cases, both!). If the bits are code, they will be loaded into the CPU at some point and executed. Most disassemblers can find this code and mark it as code, and they’ll subsequently show you the instructions that the code translates to in assembly language. Figure 6–7 shows what assembly language looks like once binary has been through a disassembler.
Figure 6–7 - A disassembler takes binary code and creates assembly code that looks like this. The numbers in the left column are the memory locations where the machine code is located. The corresponding assembly language is in the right column.
But what about normal data? If you have disassembled the code, the code can provide hints as to the location of data. Figure 6–8 shows the code accessing a data location at 0001F574. Because of the way the code is structured, we now know that memory location 0001F574 stores some kind of data. As it turns out, most code contains volumes of information like this to help us find data of interest.
Figure 6–8 - Data are accessed by previously disassembled code, as shown here.
Data Exposure and Countermeasures
Obviously you can search for and alter data at will in any target game program. But remember that the game program can also search memory. The game may employ countermeasures that search for modifications made to its own code or data (e.g., through the use of integrity checking), and it can also scan for any injected code or data that you have placed into memory (using active malware scanning).
Many of the techniques we show you involve altering code, tweaking data bits, and injecting threads or DLLs into the game process. All of this activity can and will be detected by some game software. The obvious example is Blizzard’s Warden, which protects the WoW game. There are ways to hide from and defeat many, if not all, forms of scanning, but some of them can get quite complicated.
Data at Rest, Data in Motion
Sometimes data are at rest, say, in the memory of your computer. Sometimes data are in motion, say, as they whiz by on the network connection between two communicating programs. If you focus only on data in memory, you’ll be missing out on half the fun. By modifying data in packets that are coming and going, you can deeply affect game play just as readily as you can when you change local instances of data in your computer’s memory. In fact, if you know exactly how a given communication protocol works, you can rewrite the game client with a stand-alone client of your own.2 After all, what you really need is a program that takes in specific input and produces specific output.
Let’s make this concrete: Sometimes, by sniffing the right packets, you can determine the location of the secret potion without even using a debugger. Figure 6–9 illustrates an example of such a sniffer. The program, called WoWSniffer, clearly illustrates the ability to sniff chat messages in transit over the network. This is especially interesting because the communications over the network are supposed to be encrypted. Apparently, the author of WoWSniffer has cracked the encryption.
Figure 6–9 - The WoWSniffer program is shown here running against World of Warcraft. The messages displayed in the sniffer window have lots of information about the inner workings of the game client.
Looking Elsewhere for Data
Elsewhere in the book, we introduce the idea of aimbots. Recall that aimbots can provide a player with uncanny, superhuman aim. Aimbots work by detecting the 3D coordinates of your enemy and calculating at exactly what angle to point your weapon to hit him or her with the best possible shot. Automatically pointing your sniper rifle into your opponent’s left eye socket requires looking around in the data that store the 3D coordinates of objects being rendered in the game.
What makes aimbots particularly interesting is that they don’t just look at data in the game program; instead, they take advantage of how data interact with the video card. The video card itself has a boatload of onboard RAM that stores data structures for rendering 3D objects. (Of course, gamers make a point of having the latest in graphics technology to play their games.) As it turns out, aimbots can take advantage of the 3D data stored in the video card to find the 3D coordinates of objects in the game world. How creative!
Figure 6–10 shows how an aimbot can compute and maintain a carbon copy of all the objects being rendered in the video memory—even those objects not yet directly in the field of view. It does this by intercepting communications between the game and the Direct3D video library provided with Microsoft Windows.
Figure 6–10 - How an aimbot intercepts 3D coordinates as they are sent to the video subsystem in order to compute such things as enemy placement.
Getting All Around the Game
By now it should be clear that there are many places we can look around for interesting data in or near the game client. And there are even more places to mess around with these data. You can do this by sending information to the game client through the user interface (we’ll call this going over the game). You can do this by getting inside the game and looking around in memory (we’ll call this getting in the game). You can do this by getting between the game and the lower-level services it needs, such as video drivers (we’ll call this getting under the game). And you can even do this by sitting on the network between the game client and its server (we’ll call this standing way outside the game).
Here we go.
Going Over the Game: Controlling the User Interface
Elsewhere in the book, we present a very simple farming game bot that works by interacting with an MMO client interface. This is an extremely common technique and is thus worth another quick look.
The basic idea for getting over the game is to send events to the game client as if the events themselves were coming from the PC. That is, you can send messages to the client that look to it like normal keystrokes, mouse events, or other game-specific messages. This type of utility is sometimes called a macro. There are many macro programs available that can post mouse and keyboard events to the screen. Instead of showing you other people’s macro programs, we show you how to write your own. What follows are some easy examples to get you started.
The first example involves sending keyboard events to the game client just as if we were typing directly on the keyboard. This is important since this can be used to move your game character, click on hotkeys for actions and events, and even type into a chat window.
Here is a snippet of source code that posts a keystroke to the computer. This is handled globally and will post the keystroke regardless of which window is in the foreground or which application is running. This technique is commonly used by macro programs. Many game hacking and macro scripts use basic keyboard and mouse events to interact with the game client. The side effect of using this technique is that you can’t use the computer for anything else while you are doing your botting because this technique basically takes over the user interface while it runs.
MapVirtualKey(theScanCode, 0), 0, 0);
MapVirtualKey(theScanCode, 0), 0 |
This code snippet uses the API call keybd_event( ). This call takes the virtual scan code for the key you want to press. This is not the same thing as the ASCII code. The character you want to press needs to be mapped to its respective scan code before you use this API function.
Using Magic Key Sequences
WoW has a character class known as Paladin—quite possibly one of the most difficult classes to play in the game.3 The key to playing this class is the proper ordering of actions to maximize damage or to preserve mana (an in-game energy rating of sorts). The game offers hotkeys that can be linked to actions for your character. So, one kind of macro might be designed to execute a series of actions to maximize the effectiveness of the Paladin character. Such a sequence might go like this:
F1 key: cast spell Sanctity Aura—increases Holy Damage
F2 key: cast spell Seal of Holy Might
F3 key: cast spell Judgement
F4 key: cast spell Seal of Command
F5 key: cast spell Hammer of Justice
F6 key: cast spell Crusader Strike
There are a total of six key bindings set up. Now, using these keys in the correct order and timing could result in the following:
Begin fighting . . .
Wait 15 seconds while fighting
Continue fight for 15 more seconds, if target still alive, then
Repeat above as timers allow
Obviously, that’s a lot of keystrokes. At the time of this writing, this sequence would first cast a Sanctity Aura, increasing damage output. Then, the Seal of Holy Might is cast, which is then immediately Judged—effectively placing a curse that makes your opponent take extra damage for a period of time. Next, a Seal of Command is cast, and fighting continues. This spell causes even more damage, and then a Hammer of Justice stuns the target opponent. Next, another Judgment causes a burst of damage that is enhanced by the fact that the opponent is also stunned. The character repeats this sequence as long as the fight is on.
Variations of these kinds of techniques abound, but this gives you an idea of the kind of analysis you can perform up front to engineer your macro for maximum effectiveness. Your mileage may vary.
Controlling Mouse Droppings
We can cause the same effect with the mouse because, just like a keyboard, the mouse generates events as you use it. By sending these events to the game client, we can make it believe that a user is wielding the mouse.
The following source code snippet illustrates use of the mouse_event API call with some inline commentary.
DWORD LMouseClick(DWORD x, DWORD y, bool shift)
This code gets the width and height, in pixels, of the monitor or screen.
This code converts the client coordinates of the foreground window to screen coordinates, letting you move the game client window around—thereby avoiding the annoying problem of having to align the game client screen to the upper left corner of the monitor. Some macro programs require this, but here we show you how to avoid that annoyance.
p.x = x;
p.y = y;
The mouse_event call requires you to specify the coordinates in mikeys—the screen is divided into 65,536 (16 bits) mikeys for both x- and y-coordinates—so the upper left is (0,0) and the lower right is (65535, 65535).
DWORD mikeysX = p.x * 65535 / ix;
DWORD mikeysY = p.y * 65535 / iy;
This sets the mouse position on the screen.
MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
If you want, you can specify that the shift key is pressed before the mouse event. This is useful, for example, when you need to shift-right-click to auto-loot a bag and so on.
MapVirtualKey(VK_LSHIFT, 0), 0, 0);
The sleep here is optional; you may want to experiment with your target game.
You can substitute a parameter here to make this a right click instead of a left click. Look up the documentation on mouse_event to see all the available options.
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
If we used the shift, let’s put it back now.
MapVirtualKey(VK_LSHIFT, 0), 0 |
As you can see, wielding the mouse is just as automatic and easy as wielding the keyboard. This is a classic technique that’s as old as the hills.
So you know how to post mouse and keyboard events. How do we also get feedback from the game? For example, what if we want to know the health of a character or of a target opponent? You can learn many things by reading pixel colors from the screen. For example, health bars are typically red and located at a specific place on the screen. If you sample pixel colors from this area, you should be able to tell what value is present on the on-screen health indicator. You can use pixel sampling for a plethora of things, of course; this is just one example.
The following code snippet illustrates how to determine the color of a pixel:
COLORREF GetColorOfPixel(DWORD x, DWORD y)
HWND hWnd = GetForegroundWindow();
HDC hDC = GetDC(hWnd);
COLORREF cr = GetPixel(hDC, x, y);
The code first gets the topmost window—which will be the game’s client window since it must be topmost (and in focus) in order to interact with your keystroke and mouse messages. This works if the game is in windowed mode as opposed to full-screen mode. Most games support windowed mode. The COLORREF will have values for red, blue, and green, and these can be used to deduce any color.
Figure 6–11 shows an example technique for checking the health, mana, or other information displayed in bars on the WoW interface.
Figure 6–11 - By sampling pixel color at the locations on the bar marked with an X, you can keep track of health, mana, and other information displayed as bars on the WoW interface.
A botting or combat assist program can sample the colors at the locations indicated on the screen. Given a few samples, the botting program can determine whether the character is at full, medium, or low health.
Countermeasures against Macro Bots
Macro-botting programs have one advantage over other types of botting programs—they are easy to understand and build. That’s why they are particularly popular. They also have the advantage that they don’t manipulate the game’s program memory at all, so the game won’t be able to detect that it’s being hacked.
In fact, a macro program such as this is hardly a hack at all—it’s merely simulating a real player by pressing keys and clicking the mouse. Game programs that hope to catch players using macro programs like this must resort to scanning the processes and window names on the system. This might seem like a violation of privacy (and we believe it is), but it’s the only way games can hope to detect macro programs at this level.
Macro programs like this aren’t used just for games like WoW. They are also used for online poker, and in poker games there is often a lot of money at stake. Programs can automatically play cards just as easily as they can drive a Paladin in a fantasy world. In the case of the popular online poker site PartyPoker.com, rumor has it that the game producers resort to taking full screenshots of your computer monitor, including everything visible at the time the shot is taken, and sending those shots home for analysis. Talk about an invasion of privacy!
Hidingfrom Process Lists
Some games read your PC’s process list in hopes of finding a known macro program, such as the AC Tool or something similar. This doesn’t work very well because it is trivial to rename your process to something else. Simply rename the .exe file before launching it.
Sometimes scanning a process list is used for more than just determining process names—it is also used to find processes for subsequent memory scans. In this case, renaming the .exe isn’t going to work. You need to hide the process entirely. This can be accomplished by using a rootkit.4 Hiding a program is simple—simply download the easy-to-use and popular FU rootkit from . Running FU will allow you to hide a process.
Changing Window Names
Another method games use to scan for botting software is to read the text of all open windows. If you suspect your target game is doing something like this, you may want to download the tool called the Governor (which we introduce in Chapter 2) from the book’s Web site or at . This tool will inform you if the game is attempting to read memory of processes and/or window texts.
To defeat window texts, simply randomize the names of your windows so they can’t be trivially fingerprinted.
Wielding Rootkits for Stealth
The most powerful form of botting stealth can be obtained by using rootkits. Rootkits are programs designed to hide other programs and data on a computer. Rootkits are not intrinsically bad; they are just tools and, like any tool, they can be used by bad guys or good guys. For game hacking, rootkits are particularly useful. More information on how rootkits can be used to hide botting programs is given later.
Generating Windows Messages
Of course, games always have messages specific to the game. If you can generate these messages and get them to the game client, you can in some sense manipulate the game client right through the front door.