This is the eighth part of the Flare-On 6 CTF WriteUp Series.
8 - snake
The challenge reads
The Flare team is attempting to pivot to full-time twitch streaming video games instead of reverse engineering computer software all day. We wrote our own classic NES game to stream content that nobody else has seen and watch those subscribers flow in. It turned out to be too hard for us to beat so we gave up. See if you can beat it and capture the internet points that we failed to collect.
Different from others, challenge 8 deals with reversing a NES Rom named snake.nes. We will be using the Mesen emulator for running the Rom. Among other features, Mesen supports debugging the assembly code which is integral for our purpose. The processor on the NES runs 6502 assembly. Without further ado, let's give the game a try.
It's a typical snake game. The game is comprised of multiple levels. We progress to the next level when the snake has grown sufficiently long. With each level it becomes progressively harder to play as the snake moves faster.
Finding the snake length in memory
Now that we know how the game works it is worth wondering whether is it possible to finish a level without playing at all? Internally, the game must store the current length of the snake somewhere in memory. If we can modify that value we may be able to bypass playing a level.
Mesen offers cheating functionality like the venerable Cheat Engine. Start a new Game and pause it immediately. Now go to Tools -> Cheats. Initially, the length of the snake is 0. In the Cheat Finder tab, we add a filter for Current Value is Equal to 0.
We play the game and eat the food once. The snake's length is now 1. Now we add a filter for current value is equal to 1. We get three possible memory locations.
Continuing in the same way, we just get a single hit when the snake's length is 2.
Thus 0x25 is the address of the memory where the length of the snake is stored. Now we need to locate the code that writes to this address. This can be done in Mesen by setting a Write Breakpoint. Open the Memory viewer in Debug view and navigate to address 0x25 where the snake length is stored.
Right click and set a breakpoint on write as shown in Figure 7.
We continue playing the game and just after the snake eats the food the breakpoint triggers.
The code at C830 tried to write to the address at 0x25 which triggered the breakpoint. After incrementing the length it goes on to check if it equals 0x33. If not it jumps to C85B. Thus our snake has to be 0x33 units long in order to progress to the next level. We can set the memory to 0x33 to cheat our way to the next level, but there is an even easier way.
Recall, that the game is comprised of multiple levels. The code from C837 to C840 increments the current level when our snake is of length 0x33. At C840 the current level number is compared with 4 which implies there are that many levels. If our current level number is not 4, we jump to C84C or else we continue normally to C844.
Winning the game
If we set the Instruction Pointer to C844 we can bypass playing the game totally. This can be done in Mesen using "Set Next Statement" in the right click pop up menu. Jumping to the address and resuming execution we are pleasantly greeted with the flag.