Solving ESET’s CONFidence 2012 Crackme

Introconfidence_2012
Have 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 attendees 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 happened – 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 approached 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.

Tools used

  •  PEid (optional)
  • ImmunityDbg / OllyDbg – with OllyDump plugin (for unpacking)
  •  Tiny self-made tools writen in C++ (i will describe them further)

What CrackMe does
– gets the username (length of username: from 4 to 31)
– gets the password (must be exactly 24 characters long, containing characters [A-Za-o])
– generates 3 MD5 hashes in following manner:
#1 -> md5(username)
#2 -> md5(#1)
#3 -> md5(#2)

input: hasherezade

hash#1 = D88EB947A504FCF6C3D9DCA5F84DE42A
hash#2 = 12EB2430F671103B94D11F34D375CC0D
hash#3 = B23D343E81CEE206B9D180B7B0189010

Sample Md5 generator

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…

The function is placed at memory address 0x403090 (till 0x404355). 1536 MMX instructions… Looks long and messy? Think so…

It’s just a begining…

First impression 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 🙂

Searched and given:

Input is placed in registers MM0 to MM5.

Output – placed in: MM0 to MM1

Registers at the begining of function execution:
MM0,MM1 -> ? (our password in processed form)
MM2,MM3 -> hash#2
MM4,MM5 -> hash#3
(mind endians!)

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#2
MM4,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 MM6
2. Part of hash#2 or hash#3 os moved to “helper register” – MM6 or MM7
3. 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 gonna demonstrate 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 copied 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: )

f1:
if pass[i] in [a-o] : value = pass[i] – 0x41 – 0x6
if pass[i] in [A-Z] : value = pass[i] – 0x41
otherwise – incorrect password

But not only they are processed, they are also added into a polynomial… Password is divided into chunks of 3 characters :

3 chars of password ->
( f1(pass[n]) * 0x29 +f1( pass[n+1] ) ) * 0x29 + f1(pass[n+2]) –>
4 bytes of the “encoded password”

To illustrate, how it can be reversed, I placed here a source of my  Simple Chunk Decoder.

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

9AE0 F7D1 FFD1 AFEC  1F2D 0642 249E 8597

Password decoded by the Simple Chunk Decoder

Now just copy the password into the field… And it’s done!

P. S.

  • Due to the fact, that some people are interested, I am preparing a new post on keygenning this crackme – including analysis of the MMX instructions  generating code.
  •  If You want to see alternative solution, take a look on Vnd’s homepage

About hasherezade

Programmer and researcher, interested in InfoSec.
This entry was posted in CONfidence, CrackMe and tagged , , . Bookmark the permalink.

13 Responses to Solving ESET’s CONFidence 2012 Crackme

  1. Pingback: Security News » ESET CrackMe CONfidence 2012

  2. iNfLuEnCe says:

    Nice article, it’s great that people who share the knowledge still exist :). One question though; why not translate this art to polish, so it’ll be more accessible for more polish people? 😉

    • hasherezade says:

      Jasne, jak tylko będę mieć torchę czasu to przetłumaczę 🙂 Docelowo zamierzam blogować równolegle po polsku i angielsku, ale gorzej z czasem – trudno mi znaleźć wolną chwilę, żeby napisać jednego posta, a co dopiero dwa… Obiecuję jednak, że do przyszłego poniedziałku będzie i po polsku 🙂 BTW – starałam się wszystko ilustrować przykładami, tak żeby nawet osoba ze słabym angielskim mogła się połapać… Nie wiem na ile mi się udało

  3. int0h says:

    Great job too bad I don’t have time for making such articles 😀 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.

  4. vnd says:

    Dobra robota 🙂 na początku też myślałem o bruteforce na haśle, ale ilość kombinacji (41^24) mnie trochę zniechęciła 😉 Próbowałaś analizować generator funkcji “hashującej”? Przyznam szczerzę, że po wyciągnięciu seriala dla właśnej nazwy użytkownika już mi się nie chciało brąć dalej w Ollym, szczególnie, że było tam dużo różnego rodzaju śmieci, które celowo miały utrudnić analizę kodu…

  5. g says:

    generacja tego kodu mmxowego prosta jest (tylko trzeba sobie najpierw zdeobfuskowac). a ze generacja prosta to keygen tez prosty.

    @hasherezade: gratki

  6. apuromafo says:

    Interesting use of MMX,in normal tutorials not are used,
    if you have time, can check this http://crackmes.de/users/mopy/simple_math_keygenme_p/
    maybe you can solve
    Best Regards Apuromafo
    pd:i will link this entry in Apuromafo.com.ar

  7. Pingback: Solving ESET’s CONfidence 2012 Crackme « hasherezade’s 1001 nights | Apuromafo

  8. Pingback: Keygenning ESET’s CONfidence 2012 Crackme « hasherezade's 1001 nights

  9. Pingback: Outils, services, sites à (re)découvrir 2012 S29 | La Mare du Gof

  10. Denis says:

    Oh man, I had an interview crackme that had the solution similar to this. Welp, it was much easier than this one but it had the same flow. I had to call some functions in reverse order and reverse some instructions add -> sub.

Leave a reply to g Cancel reply