Late last year, EH-Net and eLearnSecurity threw out a little challenge to our readers as a way to make a gentle introduction to the topic of reverse engineering and also to announce eLS’s new course, Advanced Reverse Engineering Software (ARES). Below you will find the Reverse Engineering 101 Contest Solution not only in video format by challenge and course designer Kyriakos Economou but also the full winning entry by EH-Netter, Gerardo Iglesias Galvan. Congratulations to Gerardo and be sure to keep us posted on your progress through the free course you won through EH-Net.
Thanks to everyone who played, whether you submitted a solution or not. If you couldn’t solve it, no worries. It only means that you have the passion but you miss the knowledge, and this is what eLS guarantees to offer to you. Still, if you managed to solve it, then you know that there is so much still to learn. eLS guarantees that through the ARES course, you will learn much more in order to enhance your technical skills. If you didn’t try at all, now is your chance to start learning. Watch the video and read the write-up and hopefully it will spark your interest in diving deeper into this fantastic field of ethical hacking.
Reverse Engineering 101 Contest Solution Video
by Kyriakos Economou
on the EH-Net YouTube Channel
Reverse Engineering 101 Contest Solution Write-up
by Gerardo Iglesias Galvan
The goal of the challenge is to create a valid key file named “eLearnSecurity.dat”.
First we tried to perform a dynamic analysis by running the application inside Immunity Debugger, however the application crashed inside the debugger (Figure 1). Further inspection showed that the application makes use of anti-debugging techniques, specifically it leverages the SetUnhandledExceptionFilter() technique. The initial analysis also showed that the application uses anti-disassembly tricks to thwart disassembly in IDA Pro and Immunity.
The initial approach to tackle the challenge is that we know the application will read a file, therefore we can expect it to make use of Windows APIs to get access to the file. By inspecting the imported functions in IDA Pro we notice at least two interesting functions: CreateFileA and ReadFile (Figure 2).
If we inspect the cross references to ReadFile we find four of them (Figure 3). We follow the first cross reference at address 0x004014A1 and find a few instructions earlier calls to CreateFileA and GetFileSize (Figure 4 and Figure 5).
A closer look at the CreateFileA call and we see that it uses as argument for the file to open “eLearnSecurity.dat” (Figure 5), so we have found the code that will open and read the contents of our key file.
We create a function with the instructions located around the identified code and get the graph shown in Figure 6.
The first thing we notice after analyzing the newly created function is that after the application has got a handle to the key file, it verifies the file has a length of 16 bytes (Figure 7 – addresses 0x00401481 through 0x0040148A) with the help of GetFileSize. If the check is successful it proceeds to read 16 bytes from the file (address 0x004014A1).
Later in the code we see a series of XOR operations and a check against a constant value, followed by two branches, one that will return EAX=0 and the other EAX=1, so we can conclude this is the code that will validate the key file.
The analysis of this portion of code yields the next pseudo-code:
file_contents = ReadFile(“eLearnSecurity.dat”)
chunk1 = file_contents[0:3]
chunk2 = file_contents[4:7]
var1= chunk1 XOR chunk2 XOR chunk3 XOR chunk4
var2 = var1 XOR dword_41A40C XOR dword_41A408 XOR dword_41A404 XOR dword_41A400 XOR dword_41B2C4
if var2 == 0x4C833425
In short, the algorithm takes the contents of the file and splits them up into four chunks of four bytes each one. The four chunks are XORed and the resulting value is XORed again with five global variables. Finally this value is compared against 0x4C833425, if the value matches then the validation is successful.
Since we control the file contents, we should find out the value of the five variables. In fact we only care about the value of ECX after the last XOR at address 0x004014D3 (Figure 8).
Unfortunately we cannot find the values of these variables through static analysis since one of them (dword_41B2C4) is not initialized and the other four are modified during runtime (we know this by inspecting the cross references to the variables), therefore we need some dynamic analysis. We chose not to deal with the anti-debugging tricks implemented by the application and instead opted for a faster solution: using dynamic binary instrumentation with the help of Intel’s Pin.
The written pintool is very simple (Figure 9), it only instruments at instruction level and analyzes the address, when it hits a instruction at a location between 0x004014BB and 0x004014D9 it prints the address and the current value of register ECX. We set the 16 bytes of our file “eLearnSecurity.dat” to 0x00 and run the app with the pintool (Figure 10).
We get that the final value of ECX before the check is 0xCF6FC79D, if we XOR this value against 0x4C833425 (the expected value for a successful validation) we get the value we must obtain when XORing the four chunks from the key file (Figure 11).
In order to complete the validation of the key file we can use the value 0x83ECF3B8 and set the rest to 0x00 as it is shown in Figure 12 (the value is reversed due to the endianess).
Hope the Reverse Engineering 101 Contest Solution was educational and that you enjoyed this small step into reverse engineering. Be sure to share your thoughts in the forums.
Thanks and keep learning,
Donald C. Donzal
The Ethical Hacker Network Online Magazine