Wednesday, January 20, 2016

Reverse Engineering Online Games - Dragomon Hunter

Creating a Packet Logger for
Dragomon Hunter

Disclaimer: The reverse engineering of Dragomon Hunter has been done for educational purposes only. I do not condone that the information provided below be used for any type of malicious purpose. Any exploits found have been sent to Aeria Games or have already been fixed.

Overview:

In my first post, I'm going to demonstrate how to reverse engineer and create a packet logger and editor for the game Dragomon Hunter. Maybe in a future blog post I'll demonstrate how to send your own packets.
Starting with the packets is the easiest way to find the functions necessary for creating a bot that has the ability to move, buy items, find exploits, and whatever else you would like to do.
Dragomon Hunter is a new MMORPG published by Aeria Games. The methodology used here can be applied to any game, although most games today now come packaged with very intrusive anti-cheat softwares such as nProtect GameGuard, AhnLab HackShield, or XIGNCODE3. 
These anti-cheat softwares function similar to anti-virus software by scanning for known patterns of detected cheats and close the game if you are running any type of software that it deems to be cheating software. They also usually have a kernel mode driver that prevents you from using analysis software such as Ollydbg or Cheat Engine by hooking certain APIs in Ring 0 to stop you from using APIs such as OpenProcess, ReadProcessMemory, and WriteProcessMemory in Ring 3. (These APIs are often used for analysis.) Furthermore, these anti cheats use anti-debugging techniques and also run memory integrity scans to make sure you have not modified any of the code of the anti cheat or the game being protected. 
The easy way to get around these anti cheats would be to stop them from running, but 95% of the time, about 1-5 minutes into the game, you will be disconnected from the game server. This is because most anti cheats have what is often called a "heartbeat packet" to make sure the anti cheat is still running. The server sends a packet to your client with some data, which then calls a function of the anti cheat to run some algorithm depending on the anti-cheat, returns the correct data, and from there the data is sent back to the server. If the data sent back to the server is incorrect or not sent at all, you will be disconnected. It works similar to how software you might install requires a license key. If you insert an incorrect key, the software will not run. However, with these anti cheats, the code is usually heavily obfuscated and run under Virtual Machines with custom bytecode, making the algorithms very difficult to reverse.
You can read more about how this works in a paper specifically written for nProtect Gameguard by E.T. at the forum unknowncheats.me here: Defeating and Emulating INCA's nProtect GameGuard
In a future blog post, I will write about my analysis of and how to bypass the anti cheat XIGNCODE3, also known as the self-proclaimed "World's #1 Anti-Cheat." (one of the referenced strings in the anti cheat...)
Dragomon Hunter is an MMORPG overrun with bots farming gold, does not have any type of anti-cheat software, not packed, does not contain obfuscated code, and I figured it would be a good start for those looking to learn how to get into reversing online games and reverse engineering in general. So, let's get started!

NOTE: As of 1/28/16, Aeria Games added XIGNCODE3 to Dragomon Hunter which will stop you from doing the analysis shown below if you do not know how to bypass it. Currently, there is not a "heartbeat" packet which can be easily defeated by finding the function that initializes XIGNCODE3 and modifying it to return true without executing the initialization.
(As simple as placing mov eax, 1 and a return at the top of the function.)

What You Will Need:
Analysis:

WARNING: If we were analyzing some type of malware, the process I demonstrate below would be different and should be run under VMWare so you do not infect your computer. However, since this is from a trusted source, Aeria Games, it is not necessary in this case.

First, please make sure that Dragomon Hunter is updated to the latest version by running the launcher. 



Open Keygener Assistant, click the "Scanning" tab, and browse for Game.bin in the folder that you installed Dragomon Hunter. You will have to make sure that the drop down that says "Files of type:" has "All Files" selected or you will not find the file in Keygener Assistant as shown in the photo below. (Although it has a .bin extension, it is an .exe file according to the PE header)



Keygener assistant shows us that the Game.bin file is not packed and gives us the offsets of all the hash and crypto signatures it detected as well as the compiler used. Let's throw the game in IDA Pro to continue our analysis.





































IDA Pro analyzes the game properly and none of the code seems to be obfuscated.






































Imports section is in tact, not obfuscated.






































Strings do not appear to be encrypted either.

In most cases, if you were analyzing malware instead of a game, you would need to do further analysis to verify what I stated above.

The game appears to be created using the Gamebryo Game Engine (http://www.gamebryo.com/) from previous reversing knowledge of games I have obtained over the years and can also be concluded using the referenced strings in IDA as shown in the photo below.


When I'm analyzing online games, one of the first things I like to do is run the IDA Function String Associate plugin by Sirmabus. This plugin creates a comment at the top of each function which contains a referenced string. In IDA, press ALT+6 and the menu shown in the photo below will show.


Click "Continue" and the plugin will start analyzing. This could take a while as games can be very large. This game is only about 14MB so it should not take so long. After, you should see comments above each function that references a string as shown below.



Now that we've got all that settled, let's get to our main goal of creating a packet editor. The question is, where do we start? There are many different paths we can take in order to find the functions for sending and receiving packets. 
One type of methodology you could use would be to find a pointer some member, such as player coordinates, that would probably be used in a packet being sent to the server. You could then find our what code accesses this pointer, move your character, and trace until you find the code responsible for sending the player movement packet.
The best method is to start from the end. What do I mean by that? Since we are running on Windows, the last place the packet will end up if we are sending or the first place it will appear if we are receiving will be one of the Winsock functions exported by ws2_32.dll. So, I will demonstrate how to trace back from one of these functions to before the packet is encrypted on send and possibly in the future make a post on how to log received packets after they are decrypted.

Winsock Send APIs:
Winsock Receive APIs:
Now, let's check which of these functions the game imports. (The easiest way is to sort the imports by "Library" in IDA and scroll down to WS2_32)


Here we can see the game uses WSASend for sending packets and WSARecv for receiving packets.

Let's start with the send packet function by looking at the references to WSASend.


It appears there are two functions that call WSASend. Let's look at something I found in the first function.



If WSASend fails with a return value of -1 or 0xFFFFFFFF in hexadecimal, it will continue execution to WSAGetLastError and return from this function with a value of 0, meaning that the function returned false which will probably result in the game closing due to a packet error. If WSASend returns 0, meaning the packet was sent correctly, the game will jump and execute the code below.

There is a call to WSAAsyncSelect below the call to WSASend. I'm going to take an educated guess that there is probably more than one open connection when the game is running, maybe two since there are two functions that call WSASend. Seeing as how the parameter for the buffer count on WSASend is always 1, the game could also be using WSAAsyncSelect to let the game know the packet has been sent successfully to let the next packet be sent as well as maintain the order of the packets.

The line that has "mov [esi+288Ch], eax" before the call to WSAAsyncSelect is interesting as well. Maybe it is some type of mutex or member of the network structure or class that has to be set before another packet can be sent.

Let's look at the second function that calls WSASend.


call    ds:WSASend
cmp     eax, 0FFFFFFFFh
jnz     short loc_F1E730

Here we can see something similar to the first function. If we look further above in the function, we can see another call to WSAAsyncSelect.



mov     [eax+288Ch], esi

Again, we find what is probably same member of some network class or structure located at the pointer +0x288C. I am pointing this member out because we could possibly place a breakpoint via the memory viewer in Ollydbg at this address and trace back from a member of the network pointer.

At this point, I would like to start analyzing the game dynamically using Ollydbg. So, load up the game and attach Ollydbg to Game.bin.

Place a breakpoint on WSASend as shown below. (You can use the hotkey F2 in Olly to set a breakpoint)



I usually trace back by using the chat function of the game. Type "hello" into the game and press enter. Ollydbg will break on WSASend and you should see something similar to the photo below on the stack. (Also, make sure you do not leave the breakpoint on for too long or you will get disconnected from the server.)


Now, let's check if the packets are encrypted. Follow the address to the pointer of the WSABUF array. (pBuffers) In my case, this would be 0x0018FC10. 

Here's what a WSABUF struct looks like in C++:


"len" is the length of the buffer and "buf" is a pointer to the buffer. Seeing as we only have one buffer, (nBuffers = 1 and also shown before in IDA) the array would look like:
0x0018FC10 (pBuffers) + 0x00 = the length of the buffer (0x0018FC10)
0x0018FC10 (pBuffers) + 0x04 = pointer to the buffer (0x0018FC14)

Why do we add 4 to get to the pointer of the buffer? An unsigned long in 32-bit software has a size of 4 bytes. The pointer to the buffer is also a 4 byte address. 


Here we can see that the buffer has a size of 0x19 or 25 in decimal. The buffer is stored at 0x180C4940. Now let's follow the buffer in the memory view. I typed "hello" into the chat so if we can see this in plain text where the buffer is stored, it could be possible that the packets are not encrypted and our job of logging send packets could be finished.


It appears that the packet has most likely been encrypted as you cannot see "hello" in the ASCII section of the memory viewer. This is often the case in online games these days, although I have seen some today that still do not encrypt their packets.



Here's what happened when I typed "hello" again.


Well, that's interesting. It appears the encryption uses an initialization vector (IV) or starting variable (SV) which is why the output of the buffer is not always the same even though we are sending the same packet with the same data but the first two bytes of the buffer was the same. (0x17 0x00)

Let's try to send "hello1" and see what happens.


The "17 00" changed to "18 00" which might mean the first two bytes of the packet structure is most likely the packet size.

Now that we are aware the packets are encrypted, we are going to try and trace back to a function that takes the buffer before its encrypted and the size of the buffer so we can place our hook here to log the packets sent to the server. Usually the best place for this is right before the call to the function that encrypts the buffer. To do this, let's place a breakpoint on WSASend again, send a chat packet, and look at the stack to find the return address of the function. The return address will be the value at the top of the stack as shown above in the photo where we placed a breakpoint on WSASend the first time.

Ollydbg shows that the call was made from the second function we analyzed in IDA. Follow this function until the return to see where the function was called from.


If the packet was sent successfully, the function jumps to the end and if we trace further we end up in the WindowProc callback. It does not look like we are going to be able to trace back to the buffer before it is encrypted from here.

It appears that the game uses a window message to notify whether a packet is ready to be sent or has already been sent. There have been multiple instances using WSAAsyncSelect using the message parameter 0x9C40 to send a window message and in the photo above you can see a call to PostMessageW using a different message parameter of 0x9C41. Since the PostMessageW above only executes if the packet does not get sent, I am getting message 0x9C41 notifies the game that the packet was not sent.

Let's place a breakpoint on WSAAsyncSelect.


Go to the address that calls WSAAsyncSelect in Ollydbg. Let's take a look at this function.


This function looks interesting because of the call to WSAAsyncSelect and the pointer, assumed to be for their network class / struct, found in the ESI here is the same as found in the function that calls WSASend.

From my experience and reading the code, the calling convention of this function is a "thiscall" since the network pointer gets passed into the ESI via the ECX register at the top of the function and it has one other parameter that can be seen by the RETN 4 at the end of the function. Keygen Assistant told us that the game was compiled using MSVC++ which would mean that the "this" pointer, also known as our network pointer, is passed in the ECX and the function is responsible for cleaning the stack.

If we read the assembly code, it appears the second parameter is a pointer to a structure.

Place a breakpoint at the top of the function and let's analyze the parameter that's pushed onto the stack.


In the photo above, the pointer to the structure is shown. I will explain what the structure looks like below, but for now if we follow the second member of the structure in the memory view, let's see what we get.


Look there! We have the packet buffer before it was encrypted. There is also the 0x0017, size of the buffer, at the beginning of the packet from before when we sent "hello" and looked at the encrypted buffer.

The structure looks like the first parameter could be some hash of the buffer or some type ID used for clean-up later, the second member points to the beginning of the buffer, the third member is a pointer to the end of the buffer, and the fourth member looks like it could be a pointer to the end of the memory that was allocated for the buffer. If we subtract the second member from the third member (0x0E680279 - 0x0E680260) we get 0x19, which is the size of the entire buffer including the first two bytes that the server eventually reads. 

Let's test to make sure that this is actually the buffer before it gets encrypted. Modify the "hello" in the memory view to "hell1" and see what appears in game.



It appears that we successfully modified the buffer before it was sent to the server since the game does not show a message until you receive a chat packet.

In order to create a packet logger from here, you could simply place a jump to a callback in your code that will print out the contents of the packets. Looks like our job here is done!

What can be accomplished with this?

Now that you are successfully able to log and modify packets, you can analyze as well as modify the data sent between your client and the server. You can take it a step further and figure out how to send your own custom packets or even create your own custom game client by reversing the packet encryption. (Hint: The encryption function is called directly in the function I demonstrated above.) This often leads to finding exploits in the game by sending data not normally sent by the game client to accomplish things not intended by the developer of the game. You can also use the packets to trace back to functions such as chatting, moving, buying items, and more by directly calling the game functions instead of sending keystrokes. 

I will demonstrate a simple and very common exploit found in online games that I found while writing this blog post. Most online games today have some sort of "swear" filter because the game providers do not want you to curse at other players.

Here's what happens if we say the word "shit" in game.




The game compared the text I wrote against the swear filter and replaced it with garbage. Let's see what happens when I modify the buffer to actually say "shit."




It appears the game client is in control of the swear filter and I was able to send the word "shit" to the server. This is just one of the many exploits that can be accomplished. Playing around with the packets also accidentally led to crashing the channel I was logged into, along with the rest of the players, but this exploit was fixed within a few hours.

Conclusion

Game companies, as well as any other company, should put more effort into their cyber security. The best practice is to give the end user the least amount of control over what they are able to do. Instead of having the swear filter controlled by the game client, it should be controlled by the server. There will always be people trying to exploit, attack, and hack which can only be stopped with good security. Game companies often receive tons of complaints about people hacking, cheating, and botting which in turn leads to the players quitting, meaning the game company loses money. Unfortunately, most game companies tend not to spend money or focus on security. They often place one of the anti-cheats named above in the introduction to combat cheaters. This practice usually only stops the most novice of hackers and instead should focus more on the security of their servers. 

I hope you enjoyed and maybe learned a thing or two from my first post. In the future, I will also be posting about reverse engineering malware, cyber security, and reverse engineering other online games.

Please feel free to send me an e-mail at 0xbaadf00dsec@gmail.com or post a comment here on my blog.