Crackme 1: Get The Password by HN1

Download URL: https://crackmes.one/crackme/5c9126c033c5d46ecd37c8f4

This crackme is a regular, non-packed PE executable, suitable as a starting point for people interested on the art of reverse engineering. It is a console application. After opening IDA to start the analysis, we can easily see that this program was written in assembly, as the structure is really straightforward.

Initial analysis

In this piece of code, we can see how the crackme stores the input, on a memory address, that I renamed to “password”. Renaming it will be pretty handy to follow what the application checks on the password.

By switching to the graph view, we can get a grasp of the flow of the execution, and therefore we can infer that it is a long chain of checks and jumps.

After reading the string on the specified offset, it executes the next two lines, which can potentially confuse a beginner.

What IDA identifies as “lpBuffer” is the buffer, or memory address, where the crackme stored whatever was input on the console. Then it proceeds to load the pointer to the string we input into the “special” ESI register. Said register is the “Extended Source Index” which is used to perform operations on indexed data, including strings. Strings are a series of bytes (in this case we forget Unicode) which are delimited in most cases by a terminator, which is usually the NUL byte of the ASCII table (0x00).

LODSB is one of the mnemonics that represents an operation which uses the special ESI register. Specifically, it loads the byte pointed by DS:ESI into AL, which is a part of the EAX register and then increments ESI to get ready to read the next byte, all in one instruction. Therefore we can do comparison checks against AL, which will contain the first character of the string and then the subsequent ones.

In this case, because we need to press enter to input the string, so the string contains 0x0D 0x0A at the end, which correspond, according to ASCII, to the carriage return (CR) and the line feed (LF), that represent the EOL (end of line) marker on Windows. Understanding this is crucial to learn how the software checks for the end of the string, as it is slightly different than the usual checks, which imply checking against the NUL character.

Reversing

Now that we know how the string is traversed, it is time to reverse how the application knows whether the string that we use as input is .

We can observe that after placing the current character on AL, we use CL to index the different characters. The value of ECX is 0 when the check starts, and then is incremented once on each pass of the loop. The blocks marked as blue do those checks, so we can infer that each character of the string is checked individually.

We can immediately observe as well that, in order to pass all the checks, the value of EDX has to be 0xA at the end of the traversal, which becomes obvious in this part of the code.

Now we have all the ingredients to fully reverse the password checking algorithm. We count all the blocks where EDX is incremented and we see that there are 10 of them, so we need to pass through all of them, and none of those that decrement IDX in order to obtain the validation message. We can mark those blocks with different colors for fast visualization and proceed to see what are the conditions that the string needs to fulfill in order to go through all of them. We can also infer that the password should have a minimum length of 10 characters.

We can then easily deduce the conditions applied to the string by just looking to the jumps and avoiding them going to the places where IDX is decremented. An example will be shown so you can understand this and then all the conditions will be enumerated. Then we will manually create a valid password and finally we will create the keygen to finish this off.

Example: character #1

In this case we can see that it increments EDX and then, if the current character value is not above (JA, jump if above) 0x47 then we decrease the value of EDX, making the character effectively invalid, as it won’t count towards the final check. At the end of both, we jump to the part of the code that loads the next character on the string.

So we have now the first condition that our password has to fulfill, the first character should have an ASCII code above 0x47 (G).

A similar analysis can be done with the rest of the characters, being aware that there are different types of jumps involved.

Conditions

The conditions that the password needs to comply with are the following:

  • password[0] > 0x47
  • password[1] < 0x6D
  • password[2] == 0x56
  • password[3] >= 0x66
  • password[4] <= 0x33
  • password[5] > 0x79
  • password[6] >= 0x38
  • password[7] < 0x4E
  • password[8] != 0x52
  • password[9] == 0x32

Testing our reversing

In order to test our reversing, we manually generate a password that fulfills all the conditions and see if it brings the desired results.

I proceed to test with “c:V{/{PHA2”, which gives the desired results, saying that the password is correct. Knowing the conditions, we are ready to start coding the keygen.

Keygen

I decided to use Python 3, because it is easy for me and also because it is almost a direct translation of the pseudocode. I limited the set of characters to those that are printable from the ASCII table, but it can be guaranteed that every generated password is valid. The code is the following.

Conclusions

This was an easy crackme that can be seen as a starting point for anyone that wants to delve into the world of reverse engineering and start playing the ultimate puzzle game.