IntroHave You heard / read about CONfidence? It’s two days IT security conference, organized annualy in Cracow, Poland. (Here you can read more…). It used to be a tradition, that ESET company prepares a CrackMe, for atendees of the conference. This year the rules were different: they published the CrackMe before, and decided to reward first 5 solvers by CONfidence tickets ^^. And it happend – I was the one of them :)… So, now I have a pleasure to describe for You what the CrackMe was about and how did i aproached it.

CrackMe

Here You can find original CrackMe: CONfidence CrackMe2012 (password to rar: ESET)
If you are not interested to unpack it, but just to play with algo, here i prepared unpacked version: Unpacked CrackMe
The CrackMe was writen in assembler and packed with MPRESS. It uses 2 custom hashing procedures – one of them was generated on the base of username.

Unpacking it was very easy – i did it just by stepping in OllyDbg, and then dumping the memory. No external tools for imports rebuilding were required.

Hashes are used to generate an MMX code, used in password verification.

The most (the only?) challenging part was to crack this MMX hash. It’s easy to spot this function, because it is called just before the decision, whether the password is correct or not. It’s result is compared with hash#1, and when it is equal, then our password is accepted. The address of the function is hidden in EAX…

First impresion was to brutforce it… But never mind, first impressions are often just delusions ;) Obviously, brutforcing this would take ages! So there must be some other way…
If You look closer, You see, that it’s not such a mess as it seems to be.
I always like to start by sorting out what’s searched and what’s given :)

MM0 and MM1 are filled with some “mysterious” hash – by simple experiments you can see that it is related with given password, but now we will not go into details of it…
In the registers [MM2, MM3] hash#2 is placed and in [MM4, MM5] hash#3. Note, that these registers are not changing till the end of the procedure. (When i noticed it, i got sure that it is reversable :))

Registers at the end of the function execution (changes are in highlighted)MM0,MM1 -> ?? (should be hash#1)MM2,MM3 -> hash#2MM4,MM5 -> hash#3

The registers MM7, MM8 are used as helpers in calculation…
The correct output should be the hash#1 placed in MM0, MM1…

In short words, we must input into MM0, MM1 something, which after all this operations will let us have hash#1 in MM0, MM1…

No other option – this long function must be reversed.
Let’s take a closer look.
There are 256 blocks of 6 instructions, which follows similar logic. See the samples below:

For every N-th block:1. Result from N-1 block (stored in MM0 or MM1) is moved to “helper register” – MM7 or MM62. Part of hash#2 or hash#3 os moved to “helper register” – MM6 or MM73. Some 3 operations are performed on this “hash part”4. Result of these operations is addes/substracted/xored with result of N-2 block, stored in MM0 or MM1

It gives us plenty of information! For every operation, we can easly calculate the value, with which MM0/MM1 is modified. And we KNOW the last value of MM0, MM1! It’s hash#1.

If take a closer look, you notice, that the only things we must do is:
– reverse the last instruction in every block (change from PADDB to PSUBB and so on…)
– set the blocks in opposit order (the last block must be the first one)
– then – if you give hash#1 as an input (in MM0, MM1) – you will get as an output the searched value (the encoded password :))

How to do it? There are many ways, and i am gona demontrate some more interesting examples later on. But, actually, the task specified by ESET was just to find the proper key for one’s name and surname (not to write a keygen). So i did it in very fast and dirty way – on the original exe. I coppied the piece of memory containing all these instruction, then reversed it by my small parsing tool (written in C++), and copied again at the place.

Left -bottom fragment of original;Right – top fragment of reversed

When i inserted hash#1 as the initial value of MM0 and MM1, it gave me at the end the searched – means – encoded password!

MM0 = AFEC FFD1 F7D1 9AE0
MM1 = 8597 249E 0642 1F2D

Now it’s not a big deal to decode it.

Password encoding/decoding

Password encoding goes along with password verification. It is very simple. Every character of the password is processed in a following way (let’s denote the processing function by f1: )

Great job too bad I don’t have time for making such articles :D I can recommend you to try this one http://crackme.esetnod32.ru/en/ it was on PositiveHackDays conference in Moscow and first level was more than I expected.