Creating an Extensible Packet Manipulation System for an Online Game
Many reverse engineers get their first taste of reverse engineering by tinkering with video games. Games make fun targets because they have such a wide range of possible exploits and modification opportunities.
The most common way to modify a game’s behavior is by editing the binary directly. Usually, a debugger is employed to observe a particular routine with some sort of check that the user wishes to eliminate. As an example, perhaps a game checks if a user has a sufficient amount of mana power before allowing the player to cast a skill. Much of the time, this boils down to a compare and a conditional jump on the binary level. By modifying the code, the check can be modified in a way that always lets the player use the skill.
These sort of patches can be powerful, but are also limited in the scope of possible exploits. It becomes difficult to do much more than modify existing checks and change functions that are already in place.
A far more powerful type of modification is packet manipulation. To do this, hooks are usually placed on the Winsock (Windows’ socket system) send and receive functions. A user can then directly manipulate the incoming and outgoing packets. This opens up the possibility of finding exploits that were never possible with simple binary modification alone. This includes weaknesses in the packet protocol itself. For example, in a game I once played, the character ID was sent in the packet. By modifying this to other characters, one could remote control other players.
However, most games contain protection against this. On top of the usual anti-cheat systems, many games contain completely custom encryption/decryption routines for their packet systems. This makes hooking Winsock normally useless.
Reverse engineering must be employed on a per-game basis in these cases; one must manually locate the encryption/decryption functions and place hooks on those, or reverse engineer the algorithm completely.
Locating the Encryption and Decryption Routines
Usually, the encryption function can be locate fairly easily, because it is usually called right before the Winsock send function. To begin, I place a breakpoint on ws2_32.send.
This hits when a packet is sent, and I examine the stack. I view each of the call-return addresses, scanning for references at the beginning of each calling function. Usually the internal send function is easy to spot because of the large number of calls.
I verify the fact that this is called every time a send occurs, and then look at how the calls look from different functions.
Every instance of the call follows this format. I notice a call to the internal send is always preceded by some other call. I place a breakpoint on this call, and learn that it is the encrypt function. I check this by typing a known string into the game’s chat, and then viewing the pointer passed into the function. Prior to the call, it points to a structure containing the string, and by stepping through the function, I see that it is obviously some sort of cryptographic algorithm.
One oddity is that some sort of socket structure is placed into EAX before the call. This must happen, because the function relies on accessing EAX. I don’t know of any calling convention that uses EAX, so I assume it is some sort of compiler optimization.
The internal send function is probably a thiscall, because the socket structure is passed into ECX, as per calling conventions.
Now I begin looking for the decrypt function. I place a breakpoint on ws2_32.recv and wait for it to hit. This ended up being a bit more difficult, because I was not sure what a decrypted packet should look like. Eventually, I found a way to crash the client by receiving a packet it was not expecting (I injected a packet, which caused the server to send a response the client was not prepared for). By debugging after the crash, I found the function that was calling all the packet handlers based on a packet’s opcode. Stepping through this function, I found that the decryption function was called right before calling packet handlers.
I now had enough information to begin developing a hooking system.
Development of a Hooking System
Hooking these calls was easy enough, but I ran into a few problems I had to work around. Much of the headaches came from the strange calling conventions used, where the game passed in important values to calls via EAX or other registers. I just coded parts of the hooks in bare assembly to capture/place these values. I assume these were just optimizations on the compilers part, not the doing of the game’s developers.
I wanted to make the packet manipulation system extensible, with plugin support, rather than code a simple packet editor. I got this idea from using a similar system in another game, so this idea is hardly new.
When the system is loaded, it places hooks and then loads all DLLs in a directory called “mod”. These mods use a known API and export calls which are looped through every time a send or receive is hooked. The system also passes a function pointer to the mods that allows them to inject their own packets into the game.
Example code can be found on my GitHub. Note: This system is not usable alone; the game in question contains anti-cheat systems that will detect and protect against simple hook methods used here.