By Joncarlo Alvarado
All software tampering that occurs for the purpose of this article was done strictly for educational purposes. No software was distributed and all experiments were conducted within a Windows 7 virtual machine.
What is software cracking?
Software cracking or breaking involves modifying a program with the goal of circumventing some feature. This is most commonly some sort of copy protection feature. For example, a video game cracker may want to circumvent the need for a product key before installing a video game. To accomplish this goal a cracker would typically reverse engineer the compiled program using a debugger or disassembler such as x64dbg, OllyDbg, GDB, or IDA. They would then be able to write a patch for that program or possibly even a keygen which is a program that generates valid product keys. Writing a keygen would require a cracker to completely reverse-engineer the algorithm that validates the entered key and understand it well enough to write a program that can create valid keys. In order to study the kind of a process a cracker undergoes to crack a game I will be demonstrating the process I underwent to crack a popular video game from nearly two decades ago.
Let’s take a look at our program’s normal execution
I started by making an effort to study the normal execution of the video game I was targeting. You can see some examples of the video game’s execution below:
From there I could determine visual points of the program’s execution that were of importance to me. An example would be the the “CDKey:” window you see in the third image displayed above. I determined that the program required a name and a 26-digit key. Without a valid key one would be unable to install the video game and be met with the error message seen in the image displayed below.
Opening your program in a debugger
For this demonstration I will be using x64dbg but most debuggers/disassemblers share the same functionality. I can open the video game installer using x64dbg which is a good sign. Modern video games often have protections in place that prevent them from being opened in a debugger. There are two breakpoints that are set by default in the program’s execution. One is the entry breakpoint and the other is a TLS Callback breakpoint. I disabled both of these breakpoints and continued executing the code. The only point of the program’s execution that matters to me occurs later in the program. When we arrive at the “CDKey:” prompt we input a key of all “A” characters and press enter. When we see our usual error message we know that our video game installer has processed our CDKey and determined it to be invalid. This means the key was in-memory and our debugger most likely noticed it.
Finding addresses of interest
While searching for addresses and instructions of interest I made sure I narrowed it down to the installer.exe module. That was going to be the only program that dealt with validating my key. Whenever the program called other DLLs, I stepped over the execution. I used x64dbg to search for string references in the installer.exe module.
Out of many interesting string references found I noticed the key I entered. I used x64dbg to jump to where this string was referenced and set a breakpoint there. Now I can go back to the the initial “CDKey:” prompt and try to enter my key again. The program should stop at my breakpoint and I will be able to analyze the instructions that process my key. I was able to identify the loop that handled all user input during installation. I was also able to identify several functions that were called while processing my key. Within these functions, several other functions were called. I had to cut through a forest of functions to find the instructions that matter most to me. That was the next step of my journey.
Poking and prodding
From here on out I worked mainly by tracing the flow of execution from the start of the loop I had identified and modifying select instructions while the program was executing. There were two main kinds of changes I made. I either replaced functions calls with NOPs or I modified jump instructions such that they jumped under the opposite conditions than usual. This was an arduous process that had many interesting results. I was able to make modifications that returned the user to the initial install screen after accepting the end user license agreement. I made other modifications that caused empty dialog boxes to appear and buttons to stop working. When I made a modification that caused the error message to change to one that claimed my name was too long when it was only five characters I suspected I was getting close.
Putting it all together
While the tracing the program’s execution I was able to identify the function that caused the invalid cd key error message. This was a huge clue for figuring out to install this game without a valid cd key. There was a JLE instructions In the instructions before this function when it was called. This jump was never taken but if it was then the function would not be called in this scenario. I modified the instruction to a JG and tried continuing the flow of my execution to its completion. However, my only reward was the screen displayed below.
Luckily there were three other instructions of interest I had modified that still be useful. I found these instructions located after a series of functions that dealt with my key. These instructions were three JB instructions that determined whether or not certain pointers were stored in the EDI, EAX, and ESI registers. Changing any one of these jumps to the opposite instruction caused one of several different error messages to appear that complained about the information given. I had a feeling changing all of these JB instructions as well as changing the JLE instruction I had found earlier would lead me to the result I wanted. However, when I tried executing the program with these modifications I was met with an “Exception_Access_Violation” .
A little bit of determination
At this point I was sure what else to try but I wanted to continue pursuing this combination of modifications. My new goal became to avoid the instruction that caused this violation. I identified the function call that caused this error while the program was running with my modifications. I decided to replace that function call with NOPs and see if the program would continue running. At first, I was worried when I was hit with another error
() but I got lucky and this error didn’t stop the program’s execution. Finally I was met with the remarkably beautiful prompt displayed below. I evaded the need for a cd key and was able to install the game.
The final result and limitations
I was able to continue to install the game and was left with a successful installation message like the one displayed in the image below.
After changing compatibility and graphics settings I was able to successfully start the game within the Windows 7 virtual machine I was working in. I was able to launch the game and had full single player functionality. However, in this cracked version of the game you could not authenticate to official game servers due to the fact that your key would be transmitted to those servers for authentication where it would likely fail the verification process.
I look forward to further studying the reverse engineering that goes into cracking software as well as studying the different ways in which video game developers implement copy protections. I would also like to practice writing my own patches and keygens in the future. At the end of the day I think studying how to crack video games can help video game developers learn how to better protect their intellectual property. I in no way meant to infringe upon anyone’s intellectual property while cracking this game and did so for educational purposes only.