Jump to content
Nytro

Solving ESET’s CONfidence 2012 Crackme

Recommended Posts

Posted

Solving ESET’s CONfidence 2012 Crackme

Solving ESET’s CONfidence 2012 Crackme 12 comments

Intro

Have You heard / read about CONfidence? It’s two days IT security conference, organized annualy in Cracow, Poland.confidence_2012_23_24_may_for_black_BG.png (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 icon_smile.gif?m=1129645325g … So, now I have a pleasure to describe for You what the CrackMe was about and how did i aproached it.

CrackMe

eset_cm2012.jpg?w=1000

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…

call_eax1.png?w=1000

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

mmx_begin.jpg?w=1000

It’s just a begining…

First impresion was to brutforce it… But never mind, first impressions are often just delusions icon_wink.gif?m=1129645325g 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 icon_smile.gif?m=1129645325g

Searched and given:

bgn1.jpg?w=1000Input is placed in registers MM0 to MM5.

end1.jpg?w=1000Output – placed in: MM0 to MM1

registers_begin11.png?w=1000

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 icon_smile.gif?m=1129645325g )

registers_end.png?w=1000

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:

blocks1.png?w=1000

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 icon_smile.gif?m=1129645325g )

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.

revers1.png?w=1000

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: )

encoding.png?w=1000

f1:

if pass in [a-o] : value = pass – 0×41 – 0×6

if pass in [A-Z] : value = pass – 0×41

otherwise – incorrect password

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

3 chars of password ->

( f1(pass[n]) * 0×29 +f1( pass[n+1] ) ) * 0×29 + f1(pass[n+2]) –>

4 bytes of the “encoded password”

To ilustrate, 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

pass.png?w=1000

Password decoded by the Simple Chunk Decoder

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

solved.jpg?w=372&h=188

Post Scriptum

  • Due to the fact, that some people are interested, I am prepairing 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

Sursa: Solving ESET’s CONfidence 2012 Crackme | hasherezade's 1001 nights

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...