Archive

Archive for May, 2011

Messing with Protocols: Preliminary (1/3)

May 27th, 2011 No comments

This next series of posts will focus on looking at a game’s protocol. Specifically, the packet structure and some basic steps into the world of packet reversing. I will focus on explaining how a specific packet (a chat packet) is built in-game and how understanding the packet structure can let someone do some fun and unexpected things. It should be noted that this won’t be an article in server emulation as that is much too complex and time consuming to both perform and write about. The steps and methodologies discussed though can aid in beginning to fully reverse a protocol and begin a project in server emulation. This whole series will be broken down into three parts:

  • A preliminary post (this one) discussing how to perform a high level inspection of a protocol.
  • Reverse engineering the target application to see where and how a specific packet is built.
  • Example programs that could be written to send your own packets or modify parts of incoming/outgoing packets.

To start off, the target will be Age of Empires II: The Conquerors Expansion. This was chosen because the chat packets of the protocol are unencrypted so there won’t be any large sidetrack about hunting down encryption keys or reversing algorithms. There are other factors like the game being dead (developing studio disbanded), and it being one of the few multiplayer games that I own. That said, it’s time for some analysis. One of the better tools for this job is WPE Pro. It’s extremely easy to use and provides a simple interface that displays everything that is needed. To get started, I created a LAN game with myself and used WPE to log packets on one instance. Below is an example of some chat packets that were sent. These can be analyzed for patterns and guesses at the different parts of it can be taken and later verified or discarded. The hex dump of the packets is shown below, with the sent chat in blue and the changes between the packets highlighted in red:
D8 26 D9 16 00 00 00 00 43 17 00 00 06 00 00 00 E7 07 00 00 01 DC 59 59 4E 4E 4E 4E 4E 4E 32 00 01 00 00 00 01 41 00 00 24 DC 18
D8 26 D9 16 00 00 00 00 43 18 23 02 06 00 00 00 E8 07 00 00 01 DC 59 59 4E 4E 4E 4E 4E 4E 32 00 02 00 00 00 01 41 41 00 24 DC 18 00
D8 26 D9 16 00 00 00 00 43 19 18 00 06 00 00 00 E9 07 00 00 01 DC 59 59 4E 4E 4E 4E 4E 4E 32 00 03 00 00 00 01 41 41 41 00 DC 18 00 80
D8 26 D9 16 00 00 00 00 43 1A 18 00 06 00 00 00 EA 07 00 00 01 DC 59 59 4E 4E 4E 4E 4E 4E 32 00 04 00 00 00 01 41 41 41 41 00 18 00 80 DC
D8 26 D9 16 00 00 00 00 43 1B 23 02 06 00 00 00 EB 07 00 00 01 DC 59 59 4E 4E 4E 4E 4E 4E 32 00 05 00 00 00 01 41 41 41 41 41 00 00 80 DC 54
These packets show sending “A”, “AA”, “AAA”, “AAAA”, and “AAAAA” to the chat, which can be seen (0x41 characters). One thing to immediately note is that the name of the player sending the chat is not contained in the packet. That means that there is some field in the packet which denotes who is sending the packet. There also appear to be a few flags that serve as counters. The first packet contains 0x17 and 0xE7, the next one increments these bytes to 0x18 and 0xE8, the one afterwards to 0x19 and 0xE9, and so on. There is also a lone field in the packet which matches the size of the chat being sent. Lastly, there are some unknown values which seem to change with each packet sent. To get a better understanding of things, it is better to log packets over multiple instances/connections. The game was restarted and the same five packets were sent. Reproduced below are the five packets with their differences and chat highlighted. Additionally, the logging was done from sending chat as the second player in the game session.
DD BF 35 17 00 00 00 00 43 07 00 00 06 00 00 00 A7 0F 00 00 02 DC 59 59 4E 4E 4E 4E 4E 4E 4B 00 01 00 00 00 01 41 00 00 24 DC 18
DD BF 35 17 00 00 00 00 43 08 3D 02 06 00 00 00 A8 0F 00 00 02 DC 59 59 4E 4E 4E 4E 4E 4E 4B 00 02 00 00 00 01 41 41 00 24 DC 18 00
DD BF 35 17 00 00 00 00 43 09 18 00 06 00 00 00 A9 0F 00 00 02 DC 59 59 4E 4E 4E 4E 4E 4E 4B 00 03 00 00 00 01 41 41 41 00 DC 18 00 80
DD BF 35 17 00 00 00 00 43 0A 18 00 06 00 00 00 AA 0F 00 00 02 DC 59 59 4E 4E 4E 4E 4E 4E 4B 00 04 00 00 00 01 41 41 41 41 00 18 00 80 DC
DD BF 35 17 00 00 00 00 43 0B 3D 02 06 00 00 00 AB 0F 00 00 02 DC 59 59 4E 4E 4E 4E 4E 4E 4B 00 05 00 00 00 01 41 41 41 41 41 00 00 80 DC 54
Changes appeared to have happened within the expected offsets in the packets. Comparing differences between two packets from two different sessions:
D8 26 D9 16 00 00 00 00 43 1B 23 02 06 00 00 00 EB 07 00 00 01 DC 59 59 4E 4E 4E 4E 4E 4E 32 00 05 00 00 00 01 41 41 41 41 41 00 00 80 DC 54
DD BF 35 17 00 00 00 00 43 0B 3D 02 06 00 00 00 AB 0F 00 00 02 DC 59 59 4E 4E 4E 4E 4E 4E 4B 00 05 00 00 00 01 41 41 41 41 41 00 00 80 DC 54
The 0x1B and 0x0B flags are highlighted differently because they’re supposed to be the same. There were some intermediate messages sent between testing in one of the sessions and it threw off the counter. Everything else should be normal. One of the “unexpected” changes was that 0x01 changed to 0x02 and 0x32 changed to 0x4B. Since the only change aside from a new session was that the sending player was in the second player slot, it might be reasonable to guess that the byte that changed from 0x01 to 0x02 holds the number of the player who is sending the chat. The change in the other byte is unknown. The other unexpected change was that the first four bytes of the packet also changed. For the sake of not having to explain, I’ll simply mention that the first four, possibly eight, bytes appear to be a session key since they precede all packets sent throughout the game (not just chat ones). The actual value of the key is calculated external to the game, in the DirectPlay networking library. Finding out how the key is negotiated is still something that I am working on and won’t be covered in this series of posts — perhaps at a future date as my progress develops. The downside to not knowing how to calculate this is that in order to send custom packets to the client the connection must already exist. Obtaining the key is not really a problem however as sendto/recvfrom can be hooked and the key stored. The next thing to note is about the last four bytes of the packet. These are also external to game and appended by DirectPlay. From my testing, these four bytes appear to be a checksum on the size of the packet. For example, sending “a”, “b”, “q”, “$”, or any one character chat text will append 00 24 DC 18 to the packet. All two character texts have the same bytes appended at the end, and so on. The last thing is about the eight bytes after the player index. In the samples these bytes 0x59 and 0x4E. For a high level analysis, it is important to test as many things as possible. The in-game chat has three options: all (default), team, and enemy. Testing sending messages using these three options reveals that these eight bytes are the “audience” flags of who of the at most eight players in a game can see the chat message. Given that a majority of the packet has been understood and guessed at, this completes the high level preliminary analysis. A sample packet is shown below and guessed at or known fields are highlighted.
DD BF 35 17 00 00 00 00 43 0B 3D 02 06 00 00 00 AB 0F 00 00 02 DC 59 59 4E 4E 4E 4E 4E 4E 4B 00 05 00 00 00 01 41 41 41 41 41 00 00 80 DC 54

Red indicates a session key.
Blue indicates some sort of counter bytes.
Pink indicates the player sending the chat.
Green indicates who is to receive the message.
Yellow indicates the length of the chat string.
Grey indicates the chat string and the null terminator.
Teal indicates the trailing checksum.
Orange indicates unknown bytes that were constant across multiple sessions.
Black indicates unknown bytes that were variable across multiple sessions.

One last point to make is that at a high level, how some of these bytes are interpreted could be off. For example, the size of the packet shown as 0x05 could actually be given two bytes, 0x00 and 0x05 in the packet, making that orange unknown byte part of the size. The 0x06, 0x00, 0x00, 0x00 bytes could actually be a DWORD instead of four unique, unrelated properties, and so on. The high level analysis is good for getting started but the actual application will require reverse engineering to fully know what is going on. This will be the topic of the next post.

A downloadble PDF of this post can be found here.

Categories: Game Hacking, Reverse Engineering Tags:

Quick Post: Auto-updating with Signature Scanning

May 26th, 2011 No comments

One common problem with developing hacks or external modifications for games/applications is when the target application gets modified through patches, new versions, or so on. This might render offsets, structures, functions, or anything important that is used in the hack as useless if it is hardcoded. For example, assume that the hack puts a hook on a function at 0x1234ABCD. One day, a new version of the application is released and the new compiled version no longer has this function at 0x1234ABCD, but it’s at some different address, 0x12345678. Now the hack no longer works, and in the worst case, even crashes the application when used. This becomes annoying because some applications are frequently updated, which in turn requires frequent updates on the part of the hack developer. Even if the updates aren’t too frequent, it can be unnecessarily inconvenient to hunt down where the structures, functions, and so on ended up. One solution to this is called signature scanning. This technique is nothing new or special and has been used by both hack developers and anti-virus programs for many years (anti-viruses probably much longer than in hacks). It relies on finding parts of a program through scanning for certain byte patterns. For example, anti-virus programs rely partially on signature scanning when they scan files since each virus or variant can be identified with a sequence of bytes unique to it. Byte strings from scanned programs are taken and hashed. This hash is compared with known virus hashes in a database and if there is a match then there is a good chance that the application is a virus or has been infected. This of course ignores additional heuristics and scanning methods incorporated into anti-virus programs, but is still at a very basic level a key component of how they all work. This same methodology can be applied to developing game hacks or external modifications to applications in general since functions, structures, and so on also have unique byte patterns identifying them.

Shown above is part of a function that could serve as a signature. No other function in the application performs this unique set of instructions so assuming that this function does not change (the actual code within it is modified or things like new optimization settings or compilers being used) then it can always be identified with \x55\x8B\xEC\x51\x6A\x10\...\xD9\x59\x04 regardless of any updates of patches to the application. However, this technique is not without its downsides: scanning an entire file or image is costly in terms of speed. Thus, it is a pretty bad idea to develop a hack that scans an image for a signature each time it is loaded since that can slow things down a lot. What I personally do is keep an external config file that holds signatures and the offset (RVA) into the image at which they’re located. Then when a hack is loaded it can read in the config file and check that the signature exists where it’s supposed to. If it doesn’t then the hack will perform a scan on the whole image and write back into the config file where the new signature exists. This is only one way of doing it though so to each their own. Since the implementation is just searching for a substring, I feel that there’s really no need to put one here. Important things to note though for developing signature scanners:

  • Signature scanners should have some wildcard usage built in. Whether EAX, EBX and so on is used to hold a temporary value is irrelevant. For example, MOV EAX, 123 as a byte string is B823010000 and MOV EBX, 123 is BB23010000. The important part of those instructions is the 123 immediate value, so the B8 or BB byte is irrelevant. The signature can then be \x??\x23\x01\x00\x00. How \x?? is treated is implementation dependent.
  • Usually the most important parts of a signature are any references to other code, structures, local variables, etc. Getting a signature containing these will increase the chance of it being found. However, references to other code is a bit dangerous since relative distances can change between new versions of a target application.
  • A signature, by definition, should be unique. Using PUSH EBP ; MOV EBP, ESP is a bad idea.

A downloadable PDF of this post can be found here.