PwnAdventures3 – Reversing games from Scratch

For those who don’t know PwnAdventures, I leave you here a link so you can read a bit about it and try it if you want. Basically, PwnAdventures was created for Ghost in the Shellcode CTF and it is a first-person, open-world MMORPG that takes place on an awesome island where you will have to face different challenges in order to win flags and finish the game. But the curious thing is that this game is intentionally vulnerable to all kinds of hacks: speed hack, unlimited money, and much more.

Despite playing CTFs and doing some casual reversing I don’t have much experience on reversing games and trying to cheat on them, but I found this opportunity really interesting, so I decided to give it a try. I will try to explain in this post and the followings all what I’ve learned during this process.

tl;dr

I haven’t read any write-ups because I don’t want to spoil myself. However, most of the write-ups I’ve read reverse the game using the PDB files. We are going to reverse the game logic without PDB files at the beginning in order to give it a feel of a realistic reversing case, then we will probably move further and use the PDB files to achieve even more awesome things in the game and get the flags.

Things we are going to do through the following posts:

  • Unlimited Mana
  • Infinite Health points
  • Endless cash (pwn coins)
  • Complete the “Unbearable Revenge” challenge
  • Speedhack
  • And more

I will be publishing multiple posts and explaining as much as I can about how I did to achieve all those things and all that I learned during this process.

Some basics:

If you are not familiar with PDB files:

PDB is an abbreviation for Program Data Base. As the name suggests, it is a repository (persistent storage such as databases) to maintain information required to run your program in debug mode. It contains many important relevant information required while you debug your code. It stores a list of all symbols in a module with their addresses.
GameLogic.dll without the PDB file.

 

GameLogic.dll with the PDB file loaded.

As you can see all the function names have been resolved, all the function parameters are also resolved and you have not only the names but also the variable types and much more. This makes reversing a hundred times easier but as you can imagine we won’t use this at least for a while, so we approach a more realistic case. Usually you will not have access to the PDB files when you are debugging, developers and companies do not usually release this information. Therefore, practicing without this files is the most realistic approach.

Game introduction:

As I mentioned before this game was made for a CTF in 2015 (http://ghostintheshellcode.com/2015-final/), and there were 7 different challenges:

We are going to try to resolve them all. To be honest, I haven’t solved them all yet but that’s the challenge for me: try to do them and explain them to you.

You can play and run the game on your computer or create a server where you can connect to it. Server and game files are available for Windows and Linux. I’m going to be using Windows files since most of the games run in Windows and I want to stick to a real scenario; and for now, I will also run the game standalone without a server. Of course, take into account that having a server opens up multiple new attack vectors and different things to try, but let’s go for the easier case for now.

I do recommend you to play it a few minutes so you can understand what you can do and what you can’t do, where you need to go and do, how the health and mana works and, where the challenges are.

Our first cheat

Once we create a character we can see we have 100 health points and 100 mana points. After play for a while and exploring the cave, we will get the first spell called “Fireballs”. If we shoot fireballs we lose mana points, and we only have 100. That’s not very much, what could we do?

The first thing that comes to my mind is to increase the amount of mana we have, how can we do that?

	6D2925C3 - 7C E6 - jl GameLogic.RandomFloat+318BB
	6D2925C5 - 2B C2  - sub eax,edx
	6D2925C7 - 89 86 BC000000  - mov [esi+000000BC],eax <<
	6D2925CD - 8B 11  - mov edx,[ecx]
	6D2925CF - 50 - push eax

	EAX=00000060
	EBX=07E81390
	ECX=008D86F0
	EDX=00000004
	ESI=07E81390
	EDI=008E3E58
	ESP=0081F3B8
	EBP=0081F3BC
EIP=6D2925CD

Wait, what…? Why are we seeing assembly code and how did you find this? Well, I used cheat engine (kudos for @alex91dotar for sharing tips about this tool), and if we want to reverse and cheat on this game we will need to identify the different pieces of code for each action we want to modify and analyze them.

Cheat engine is an open source memory scanner/hex editor/debugger. Cheat Engine is mostly used for cheating in computer games, and is sometimes modified and recompiled to evade detection.

Let’s install and attach cheat engine to our process. If we know that our mana points are always 100 when its full, we can try searching for all the “100” values in memory and then try to modify that value on the game in some way, so we can identify which of them is the one we want.

On Cheat Engine, click “First Scan”, set the value to 100 and the value type to 4 bytes ( it is probably stored as an int, the size of an int is really compiler dependent. A long time ago, when processors were 16 bits, an int was 2 bytes long. Nowadays, it’s most often 4 bytes long on 32-bit systems as well as 64-bit. However, it could be stored as another data type). We are going to get a lot of values.

We need a way to identify the correct value so maybe we can just fire some fireballs decrease the mana and see which memory address have decreased since the last scan. Let’s do it.

Mana points decreased to 46.

Now let’s select “Decreased value” on Scan Type and click “Next Scan”. We will have a smaller group of possible values. And one more time but with “Increased value” as Scan Type. We will repeat this last scan until we get values that are consistent with our current mana.

Later we will see why we have 3 values, but if we modify each of them separately we will see that just one of them modify the amount of mana we see in the game, let’s check it:

Right-click -> “Change value of selected addresses”.

200 points of mana

Great!! But wouldn’t it be better to have unlimited mana? Can we try to find out what instruction writes/increase this value and maybe overwrite it with NOPs?

Right-click -> “Find out what writes this address”.

Note that we will have to do this on the correct value of those 3. We will see that for two of the three values when we do “Find out what writes this address”, we will see a few instructions that modify this value constantly without any interaction with the game. Clearly, this is not what we are looking for. Let’s ignore those cases and try other of the three cases until we find one that doesn’t get modified if we don’t cast spells.

When you find the correct value you will see that you get two instructions that are modifying the Mana value:

One should be the case that consumes Mana and the other the one that regenerates it. Let’s analyze the first case:

  1. It got triggered two times (check Count column). Actually, I had cast two times the spell, thus we can assume it’s the case that subtracts mana from our actual value. Let’s confirm it:

 

		6D2925C3 - 7C E6 - jl GameLogic.RandomFloat+318BB
		6D2925C5 - 2B C2  - sub eax,edx
		6D2925C7 - 89 86 BC000000  - mov [esi+000000BC],eax <<
		6D2925CD - 8B 11  - mov edx,[ecx]
		6D2925CF - 50 - push eax
		
		EAX=00000060
		EBX=07E81390
		ECX=008D86F0
		EDX=00000004
		ESI=07E81390
		EDI=008E3E58
		ESP=0081F3B8
		EBP=0081F3BC
                EIP=6D2925CD

 

On the second line, it subtracts EDX to EAX. EAX has the value 60 (100 in decimal) and EDX is equal to 4. Perfect, it means that it decreases the value of EAX (100) in 4.

2.  The second case got triggered eight times, if you cast fireballs you will notice that each spell costs you 4 mana. However in this case, it will regenerate 8 points of mana until we reach 100 again:

		6D290952 - 83 F8 64 - cmp eax,64
		6D290955 - 0F4F C7  - cmovg eax,edi
		6D290958 - 89 83 2C010000  - mov [ebx+0000012C],eax <<
		6D29095E - FF B3 2C010000  - push [ebx+0000012C]
		6D290964 - 8B 06  - mov eax,[esi]
		
		EAX=00000061
		EBX=07E81320
		ECX=008D86F0
		EDX=00000000
		ESI=008D86F0
		EDI=00000064
		ESP=0081F5FC
		EBP=0081F6B0
EIP=6D29095E

 

On the first line compares EAX with 64 (100 in decimal), which is the maximum Mana possible. Then we have a cmovg instruction, which can be read as “compare EAX with 64, if it’s greater move EDI in EAX” (move 64 to EAX). If EAX is smaller, then it doesn’t move 64 to EAX and the value remains the same (61).  Finally, it moves the value of EAX to [ebx+0000012C]. Let’s see if we can check the value of that address. EBX is equal to 0x07E81320 + 0x12C = 0x07E8144C

0x07E8144C is the original address, one of the three we found at the beginning.  Now that we understand this, lets NOP the instructions where the game reduces our amount of mana. Let’s go back to our search “Find out what writes this address” and then “Right-click on the address -> Replace with code that does nothing (NOP)” for the case where we have the 6D2925C5 - 2B C2 - sub eax,edx instruction. And click OK.

This is an image from IDA where I did the same but manually, patching the file. You can do the same going to the instruction and then “Edit -> Path -> Change Byte”. Remember to NOP all the needed bytes which are: 89 86 BC000000 (6 Bytes).

	6D2925C5 - 2B C2  - sub eax,edx
	6D2925C7 - 89 86 BC000000  - mov [esi+000000BC],eax <<
	6D2925CD - 8B 11  - mov edx,[ecx]
6D2925CF - 50 - push eax

The result:

 

Yeahh!!! Spells don’t consume Mana anymore!

Next Post

In the next blog post we are going to modify our Health and try to make our selves invincible. I tried multiple things and learned a lot during the process. I will tell you not only how I did to avoid dying in the game but also a few things that I tried that didn’t work.

Useful content: