Oct 23, 2021
5 mins read
So far I’ve managed to have just enough reverse engineering skills as is useful to me at the time, but recently I’ve taken an interest in getting a bit more in depth.
My son was ill last week and home from daycare, so I took it upon myself to take the time to watch HackadayU: Reverse Engineering with Ghidra (~4 hours). I unfortunately didn’t have time to do any of the exercises, but I learned a lot.
In chatting with a friend I mentioned that it may be fun to write a NoCD crack for Nerf Arena Blast. If you’re unfamiliar with the term “NoCD”, it refers to circumventing a check like the following:
However, in the case of Nerf Arena Blast there isn’t much need to a NoCD crack as simply mounting a ripped ISO file resolves the warning. Additionally, when the installer is run it simply creates a config file that tells the game to check that a disk drive exists such as:
You can easily just change the text file to point to the game install location and it’ll run just fine. I could even just use the original CD I still own 22 years later:
But that’s not the point of this exercise and reallistically this CD is well overdue to crumble to dust and be useless. I wanted to reverse engineer the game and figure out how to (very unecessarily) patch the binary. Then, when a friend offered to make keygen music for my pointless NoCD crack we decided to just make a full retro keygen application out of it simply because it would be cool.
Let’s get started!
I’ll be targetting version 300 of Nerf.exe
I’ll load the exe into Ghidra and run analysis and just look for a jumping off point relevant to what I’m looking for, so I’ll look for where the following string is defined:
Please insert the Nerf CD-Rom into your drive and press OK to continue, or Cancel to exit.
Unfortunately I don’t find anything.
So then I just grep the entire directory the EXE is located in for the string:
$ grep -R "Please insert the Nerf CD-Rom into your drive and press OK to continue, or Cancel to exit." Window.int:InsertCdText=Please insert the Nerf CD-Rom into your drive and press OK to continue, or Cancel to exit.
And we see that there is a Window.int file that has a list of defined strings. In this case, the key for the string we’re looking for is InsertCdText. Let’s hop back in Ghidra and look for that string now.
We can see that we found exactly 1 instance of this string. If we look at the sections of code referencing this string we find the following code:
We can see that the string we are looking for is referenced, a call is made to open a MessageBox dialog, and that the program then exits (in the case the user fails the CD check). We’ve found our relevant section of code!
Let’s take a look at the function graph view of our function to see what surrounds it to see if we can identify where the actual “checking” logic exists.
We can see that 10908164 is where our InsertCdText and MessageBox are being used.
We can see that 10908198 has no branches coming off of it, so it’s likely the program exiting.
If we follow the arrows upstream of this logic we see 1090813a which contains:
10908140 83 3a 00 CMP dword ptr [EDX ],0x0 10908143 0f 85 94 JNZ LAB_109081dd 00 00 00
I recognize that CMP is the opcode to compare two operands and I’m guessing JNZ is a jump opcode which jumps to another section of code since it starts with “J” even though I don’t immeadiately recognize what it is.
A quick google search later, I confirm that JNZ is “Jump if not zero”, meaning it jumps to the next section of code if the result of CMP is not zero.
My naive intuition tells me I should be able to just replace this with a regular JMP instruction, so I do exactly that. This results in:
10908140 83 3a 00 CMP dword ptr [EDX ],0x0 10908143 e9 95 00 JMP LAB_109081dd 00 00 10908148 00 ?? 00h
I have no idea why the “??”, I’ll probably find out later in life that this was something important but I’m gonna ignore it because it’s not “!!” which would indicate that something was alarmingly wrong rather than a computer questioning my judgement??
So anyways we save the patched binary and run it and:
It runs just fine and bypasses the CD check!
In reality, all that my NoCD crack application needs to do is change 3 bytes in Nerf.exe
//NoCD Patch, change JNZ to JMP file = 0xE9 file = 0x95 file = 0x00
So all the rest of the code in the crack was to play a .WAV file, track keypresses, and display cool ASCII art.
Fortunately Ebiten has some off the shelf examples where I could effectively just drop in my needed assets and compile.
The whole process was a lot of fun and I got to involve my friends in writing a completely pointless keygen/crack that I learned a lot from.