Reverse Engineering — My First Crackme

Kamran Saifullah
4 min readNov 15, 2021
https://crackmes.one/crackme/60d766c033c5d410b8843039

Reverse Engineering is really fun but one of the most difficult field in Cyber Security. You not only need to know the programming languages but are also required to have a good understanding of Assembly Language. Most commonly Intel Architectures.

This article is the first in the series of doing Reverse Engineering to crack different crackme challenges. In this article we are going to find the answers of our first challenge.

Understanding the file

As per the details shared by the author of the challenge, the language is C/C++, targeted architecture is x86–64 while the platform is Unix/Linux.

As i am using my MAC, so things are going to be bit changed cause of architecture difference but we can observe two things.

  1. It is an executable file.
  2. The architecture is x86–64

Looking at the strings

Once we understand the nature of the file, the second step is to check for the strings to check if we can find the low hanging fruits.

We can see that strings does not yielded much but we have one observation here. There is a string which is being accepted by the program.

Running The Program

As we don’t have much answers, lets run the program as it is executable.

We can see that this program indeeds awaits for the data to be provided and that data is password. But, as we dont know the password. We will need to analyze the program in a decompiler. Let’s go with “IDA Community”.

Decompiling/Pseudo Code

Load the program in IDA, go to views, open subviews, generate pseudocode. Now, IDA has provided us with a somewhat actual code.

So, we have the following code which we need to understand.

int __cdecl main(int argc, const char **argv, const char **envp)
{
if ( argc >= 2 )
{
if ( (unsigned int)strlen(argv[1]) == 6 && argv[1][2] == 37 )
{
printf(“Access granted!!!!!!!\n”);
return 0;
}
else
{
printf(“Access denied\n”);
return 0;
}
}
else
{
printf(“%s <password>\n”, *argv);
return 1;
}
}

Now, let’s try to read the code line by line.

if ( argc >= 2 )

To check if the arguments provided are 2 or more than 2.

if ( (unsigned int)strlen(argv[1]) == 6 && argv[1][2] == 37 )

This line checks the following two things.

  1. Whether the length of the password is 6 or not.
  2. If the length is 6 whether it starts with integer 37 or not.

Now, if you will try to run the program with password “370000” and all other combinations, it will not work because the logic is wrong!

First Solution

Now, that’s the key. If we write our own program to check how the values will be interpreted by the program, we can observe the following.

So, as per our program, the argv[1][2] is returning the value to be 0 because the values are being returned from the loop. If we run the edited version, we can observe that the values returned by argv[1][2] is an int while what we are trying to print is a character.

Changing the result data type from integer to string at first, we can see that it is returning 48.

So, the final program that we should be expecting is as below if we consider 370000 to be the password.

Secondly, the thing that we need to understand is that agrv[][] is an array of pointers to a string and they will point to a single instance of a string i.e. the values provided in an argument and will not point to 2 values at the same time. Example as below,

So, if we follow the logic, then the original program code argv[1][2] == shall either be pointing to 3 or 7 i.e. the program should be expecting 3 or 7 on the 3rd position of the string.

SOLUTION TO THE CRACKME

Thank you to Pratik Mehta for reaching me out with the solution of this challenge. As he mentioned, we can solve this challenge by passing % as the 3rd letter in a 6 characters string because 37 equals to % in ASCII for % sign.

--

--

Kamran Saifullah

Malware/RE/Firmware Analysis, App Sec/Off Sec, VAPT, Phishing Simulations/SE | Risk Management, IS Governance, Audits, ISO 27001 LI