What's going on everybody!? We have another Windows challenge today. This one comes from the website crackmes.one. It's pretty simple but I think it was pretty interesting to say the least. As the name implies, we have to create a working keygen. As with all of my walkthroughs there is a YouTube video dedicated to this challenge. You can check it out below:
Optional Materials to Follow Along
If you want to follow along feel free to download the VM I provide. You can find instructions on importing the VM here. If you don't want to use my VM that's fine, my feelings won't be shattered. But you will at least need the binary. You can download the binary here. The binary comes in a password protected file. The password is crackmes.one.
You'll also need a disassembler. I recommend IDA or Ghidra. With all of that out of the way, let's get reversing!
Let's start our initial triage by looking at the Readme file provided with the binary.
There isn't much in the Readme file. There are some rules the author placed on us. We are not allowed to brute force the key, we are not allowed to patch the binary, and we must create a working keygen. We have yet to patch anything and bruteforcing is beneath us right? So, this shouldn't be too difficult. The author signs his name: papanyquiL. Let's go ahead and get some initial information about this binary. Let's run die on this bad boy! If you're using my VM simply right-click on the binary and select detect it easy.
Similar to the last Windows challenge, we are dealing with a .NET executable. Additionally, this is a 32-bit binary. Let's go ahead and take a look at the Imports this binary uses.
Just like the last challenge, it is only importing
_CorExeMain. This is not unusual for small binaries to only import this one library. Let's take a look at the strings.
We see some interesting strings:
CheckSerial_Click. These will likely lead us down the correct path to understand how to create a keygen. Now that we have something to focus on, let's open this binary up in
dnSpy. Remember this is a 32-bit binary, so we will have to launch the 32-bit version of
Static Analysis with dnSpy
Once you open the binary, navigate to Form1 and locate the
InitializeComponent() function. It should look like this:
Everything looks pretty standard here. Something important to note is our user input will be
textbox1 and the password
textbox2. But wait a second. Something is a little off! Notice anything interesting? Look at line 114. The text for the Exit button is "&Check". Similarly, the text for the CheckSerial button is "Exit." It looks like papanyquiL was trying to pull a fast one on us! Instead of analyzing the
CheckSerial_Click function, let's look at the
It appears we were correct! The
Exit_Click_1 function calls the
CreateSerial function. Let's take a look at what this function does.
So it appears this function performs some action on the text variable and closes the app. Do you notice anything funky about the
for loop? It looks pretty standard but look at the variable
text. It's initialized to an empty string. So, the check
i < text.Length actually won't do anything. So it just calls the
CloseApp function. It appears I led you down the wrong path. Sorry... or did I (cue suspenseful music). Let's take a look at this "CloseApp" function.
Egad! It appears we've been had! The
CloseApp function doesn't close the app at all! It's performing some manipulation on the
text string which is initialized to the author's name: papanyquiL! The
for loop is going to take our username, and perform a series of replacements. This will be appended to the
text variable. So, at the end of this
for loop, the
text variable will hold "papanyquiL" + our manipulated username. We then see our password (textBox2) is compared to this
text variable. So, we need to provide a username/password combination that will yield the correct password. Fortunately, we have all we need to create a proper username/password combination. We can do 1 of two things, use .NET to create a password based on a username we provide by copying the code here. Alternatively, we can use Python. Since I'm not very familiar with .NET I took the Python route. The following Python code will produce a valid username for any username we provide:
# -*- coding: cp1252 -*- text = "papanyquiL"; username = raw_input("Enter a username: ") for i in range(0, len(username)): text = text + (username + str(1) + str(3)).replace(" ", "").replace("a", "@").replace("b", "1").replace("c", "*").replace("d", "4") \ .replace("e", "!").replace("f", "#").replace("g", "-").replace("h", "%").replace("i", "£").replace("j", "$").replace("k", "^").replace("l", "'") \ .replace("m", ".").replace("n", "~").replace("o", "+").replace("p", "=").replace("q", "2").replace("r", "\\").replace("s", "9").replace("t", "/") \ .replace("u", "6").replace("v", ":").replace("w", "8").replace("x", "]").replace("y", "7").replace("z", "[") + str((len(username) ^ i)); print text
Let's test it out shall we!?
Now, run the KeyMe.exe binary and insert "Jaybailey216" as the username and that mess as the password!
And the verdict is...
And we did it!
Alright and that's it for this challenge! I hope you enjoyed reading this and more importantly I hope you learned something today. This was a fairly simple challenge but I do like that the author tried to throw us down a few rabbit holes. If you have any questions feel free to reach out to me on Twitter, Instagram, or Discord: jaybailey216#6540. If you have a challenge you would like me to try, let me know and I'll give it a shot! I'll see you all next time!
Peace out! ✌🏾