Brute Forcing Cheat Codes
Tony Hawk’s Underground 2 sent me down a pretty unexpected rabbit hole this last weekend.
I had just beaten the main game on PSP and unlocked a bunch of stuff, including one of the levels from Pro Skater 3 I had really enjoyed as a kid. But there were a lot more levels still locked and I realized that the game expected me to complete all the other difficulties to fully unlock everything.
I didn’t think this was much of a problem, I’d just look up cheat codes (remember those?) and check out all the locked levels that way. But for reasons that only the game devs will ever know, it wouldn’t be that simple.
I eventually stumbled on this repository on GitHub where I learned something interesting from the project’s README.
This project started after some discoveries while reverse engineering Tony Hawk’s Underground 2: Remix (the PSP port of the game). I was interested in how the game checked to see if a cheat code the user entered was valid, and found that unlike many other games, the game didn’t just do a string comparison with a list of cheat code strings. Instead, it performs a series of repeated CRC32 calculations on the input cheat string 100,000 times, calculating a sort of hash for each cheat code.
Really glad to see these game devs take their cheat code security seriously. Way to go guys.
The project also has a really handy table with the most complete list of cheat codes for all systems that I was able to find. And of course, the “unlock all levels” code for PSP was missing.
Fortunately the project maintainer, CB9001, had already done all the hard work involving reverse engineering the game and writing a program to brute force its cheat codes. All I needed was a word list and compute time. I enjoy the Tony Hawk games as much as anyone else, but that definitely beat having to complete the game multiple times.
I saw from one of the project’s merged pull requests that someone had gotten some success with the rockyou list, which I learned was a really large, well-known list of common passwords. It’s such a huge list that I couldn’t be sure if the person had gone through the entire thing, and really I just wanted to have all my bases covered. So I started there.
I broke the list up into separate, more manageable files. In case I ran into an error anywhere or needed to pause the process for some reason, it would be easier to pick up roughly where I left off. I also wrote a simple wrapper script to run the brute forcing program on each of those files and save the output to make it easier to check later.
So I let that run for a while. When it finally wrapped up I had a nice list of found cheat codes… none of which were the one I was looking for, and all of which had been documented already. I wasn’t terribly surprised. After all, I knew that someone else had tried the same, I just wanted to be sure the entire list had been covered.
I started looking into tools to generate custom word lists and found this tool called bopscrk.
I came up with a list of 20 or so words I thought might be likely to appear in the “unlock all levels” code and handed it off to bopscrk so it could do its thing. About 10 minutes later it gave me back a list several tens of thousands of words long. I was hoping one of them was the code I was after.
I gave this longer list to the brute forcing program and it wasn’t too long before it reported a newly found code: “w0rldt0ur”. I checked online and this appeared to be a new code. Lucky! I checked the annotated code hash list and this code just happened to be the exact one I was looking for. Even luckier! I tried it in-game and sure enough I suddenly had every level open to me.
So was it worth it?
I think so. A lot of the levels that had been locked ended up being ports of some of my favorites from previous games in the series.
And the game aside, it was pretty fun learning a little bit about basic password cracking with a little reward at the end. Realistically I know modern password security is more complex than this, but this was still a fun exercise that I think showed the importance of strong unique passwords. I didn’t expect just generating the word list to take as long as it did, and it could easily have taken much longer if I gave it more words to generate from. I also got really lucky that the code ended up being something so easy for a brute force attack like this to crack.
Comment via Fediverse