When running a video game or any application on your laptop, you execute instructions that has been writing by the developers for a specific purpose. Sometimes, the instructions restrict you: e.g. an evaluation version of an application that exit after 30 minutes, or your player in your MMORPG that cannot jump high enough to access hidden high location. The executed instructions are located on your computer, which you control. You can therefore change those instructions to bypass restrictions (e.g. cracking) but also to improve or add new functionalities. This requires you to open the binary, understand the functions (reverse engineering) and patch it.
In this post, we will not change complex logic of the binary, but simply modify one line in the instructions to improve the capabilities of our character by increasing its movements speed.
You can either walk (hold shift) or sprint (default) in Pwn Adventure 3. Let’s search in the binary for functions that contains speed, walk and sprint. In this example, I will use IDA, but you can also use Binary Ninja if you have the licence or Hopper, which has a free evaluation that can disassemble 64bit binaries.
The function Player::GetSprintMultiplier look particularly interesting as this looks like the function that tells the client how much faster is the sprint speed (default) compare to the walking speed (hold Shift).
According to msdn, non-scalar types (including floats and doubles) are returned in the XMM0 register. This means that the returned value for the function float Player::GetSprintMultiplier(Player *this) is stored in xmm0. The register xmm0 is set with the value of rax, which is itself set with the static value 3. The sprint multiplier is therefore x3.
Now, we would like to increase that number so we could sprint faster. Let say 10 times faster (3 x 10 = 30 = 0x1E). For this, we need to replace the instruction “mov rax, 3” with “mov rax, 0x1E“. In order to easily replace the instruction without costly tools (although radare2 could do the job perfectly), I developed a little script in python with the Capstone and Keystone frameworks.
First, we need to note down the offset of the instruction we want to overwrite.
The offset is 0x15ea64. We want to overwrite “mov rax, 3” with “mov rax, 0x1E“, so first we have to make sure that the initial instruction takes enough space in the binary so that the new instruction does not overwrite the following instruction (i.e. “cvtsi2ss xmm0, rax“). For this, I used Capstone:
from capstone import * offset = 0x15ea64 with open( 'libGameLogic.so', 'rb' ) as f: binary = f.read() cpt = 0 size = 0 md = Cs( CS_ARCH_X86, CS_MODE_64 ) for i in md.disasm( binary[ offset : offset+64 ], offset ): if not cpt: size = len(i.bytes) cpt += 1
Now that I have the size, I need to assemble the new instruction and verify that the new size fit into the current instruction size. For this, I use Keystone. If the new instruction fit, I just replace it with the old one and pad with NOPs if smaller.
from keystone import * ks = Ks(KS_ARCH_X86, KS_MODE_64) encoding, count = ks.asm(b'mov rax, 0x1e') if len( encoding ) <= size: # padding with NOPs if shorter encoding = encoding + [0x90]*( size - len(encoding) ) binary = binary[ : offset ] + ''.join(chr(c) for c in binary) + BIN[ offset+size : ]
Then I just need to save that new binary:
with open('libGameLogic.so', 'wb') as f: f.write(binary)
Although I knew that the size for “mov rax, 3” was the same as for “mov rax, 0x1e“, I decided to go through the verification process in order to build a more generic binary patch tool. You can find the final code in our GitHub page.
With this tool, you will just need to run the following command:
$ python binpatch.py -f libGameLogic.so -o 0x15ea64 -m 64 -i "movabs rax, 0x1e"
You then need to replace the library with the new patched binary (keep the same name) and restart the game. You now run 10 times faster.
Similar work done by LockBoxx with Radare2: http://lockboxx.blogspot.de/2015/01/ghost-in-shellcode-2015-ctf-writeup-pwn.html
Blog series: Introduction – Reverse Engineering Network Protocol – Pwn Adventure 3 Network Protocol – Building a Wireshark Parser – Asynchronous Proxy in Python – Intercepting Packets – Reverse Engineering Binary – Patching Binary – Hooking shared library