For the first time, I decided to try reverse engineering Linux binaries. I have to say that I’m not an expert in this field, if you find something in this post that is not correct please point it out!
There is an excellent site called
crackmes.one and I had it in my bookmarks for a really long time, but finally the time has come. Today, I’m going to show you how to reverse engineer a simple ELF binary and write an “exploit” for it in Python. The binary is going to be a Serial Key checker and the “exploit” will be a key generator. The goal is to understand the algorithm and write that keygen.
Don’t check the comments if you are afraid of serious spoilers!
Here is the link to the challenge: https://crackmes.one/crackme/5c2acb8933c5d46a3882b8d4
Apart from basic programming and little familiarity with C/C++ you don’t need anything. I won’t go into details with Assembly and more advanced concepts. However, you’ll need the following tools:
- Latest Ghidra (v. 9.0.4)
- Requires Java 11+
- Linux machine
I’m personally going to use CLion as an IDE (free for students!), which is an excellent development environment. My host machine is MacBook Pro, but the binary is compiled for Linux, so probably you’re better off with a virtual machine or Docker.
Go ahead and download the zipped package from the above-mentioned link. The password is going to be:
crackmes.one You’ll get a
Keygen.tar.gz file, which you have to extract to get the
I ran the simple
file command on the binary to determine the architecture and some additional information.
t0thkr1s :: ~/Downloads » file SimpleKeyGen SimpleKeyGen: ELF 64-bit LSB pie executable x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=4b657ffd4f43a704861b200c9f2235f8fe395e27, not stripped t0thkr1s :: ~/Downloads »
The file is, in fact, a 64-bit ELF binary for Linux. I also run the
strings command, which identified some hardcoded strings and the GCC compiler version.
t0thkr1s :: ~/Downloads » strings SimpleKeyGen /lib64/ld-linux-x86-64.so.2 libc.so.6 exit puts printf strlen __cxa_finalize __libc_start_main GLIBC_2.2.5 _ITM_deregisterTMCloneTable __gmon_start__ _ITM_registerTMCloneTable u3UH A\A]A^A_ %s [SERIAL] Good Serial Bad Serial ;*3$" GCC: (GNU) 8.2.1 20180831 --- strip ---
That’s all for now, let’s investigate further with Ghidra!
I created a new project called
SimpleKeyGen and added the binary using drag and drop. Double-click the file and you’re ready to go.
On the Symbol Tree panel, you can find the available functions, labels, etc… I located the
main function because it’s the entry point of the program. There is a truly cool feature about Ghidra. It contains a decompiler, which you can activate with
Window - Decompile: main.
As you can see, Ghidra did a pretty good job and restored the source code as much as possible. The program looks very simple. It calls a function with a parameter (first command-line argument) and checks the result, whether the serial key is valid or not. If the result equals zero, we found a correct serial key.
checkSerial function from the Symbol Tree, Ghidra will immediately display it in the Decompile view.
This function check if the provided parameter has a length of 16 (0x10 in hexadecimal). The parameter is obviously the serial key, so from now on I’m just referencing it as the serial. Then, it loops through the serial and increments the index by 2. There is a logical statement in the body, which is very important. It subtracts the index-th character in the serial and the index + 1-th character and checks, whether the result is -1 or not. If not, the serial wrong.
At this point, you should have some kind of idea, how this program works. I reconstructed the program in CLion, so you can compile the code and modify it easily.
Time to write a keygen program. I could have done it C++, but I decided to improve my Python skills. The following script will generate 10 different serial key and print them out.
I think it’s not the perfect solution, but it’s good enough for the purpose. I’m starting from the letter ‘a’ and incrementing the ASCII code every time by 1. The first round gives this:
abababababababab It a valid serial key because ‘a’(ASCII: 97) - ‘b’ (ASCII: 98) equals minus one. The easiest example would be
0101010101010101. 0 - 1 = -1 and this prevails for every character pair.
Feel free to experiment with the code!
I really hope that this post was helpful to you. If you have question/suggestions please reach out to me, I’d be happy to help. Have a nice day and happy hacking!
If you found this article helpful, please share to help others with similar interest find it! + Feedback and donations are always welcome!