/* the author and owner of this blog hereby allows anyone to test the security of this blog (on HTTP level only, the server is not mine, so let's leave it alone ;>), and try to break in (including successful breaks) without any consequences of any kind (DoS attacks are an exception here) ... I'll add that I planted in some places funny photos of some kittens, there are 7 of them right now, so have fun looking for them ;> let me know if You find them all, I'll add some congratz message or sth ;> */

At last! A technical post!.. in which, I'll describe the ESET crackme from this years edition of the CONFidence conference. The CONFidence crackme (made especially for the conference - it was NOT their old crackme that is available on the ESET website for some time now) is available for download below, so one can try to break it (it's a "recover the password" type of crackme) himself:

Download:confidence_eset_crackme.zip (the crackme, this is a post-conference compilation I received from Marcin, without some helpers that by mistake were present in the conference-compilation; btw, it works fine on XP, but has some issues on Vista)

Because the addresses of the new compilation are different then the addresses in the old one, at the bottom of this post one can download also the old binary, which breaking I will describe in this "tutorial" :)

Dear reader, if you plan to break the crackme yourself, STOP READING THIS PAGE NOW!!! :) Below I present the solution to the ESET CONFidence 2009 Crackme.

A

N

T

Y

S

P

O

I

L

E

R

First, a few words about the solution: as I have written in the previous post, I had three attempts to solve this crackme - the first two times I found out in the end that this is just not the right path. In this solution I'll omit the first two attempts, and focus on the correct solution.

As I've written earlier, the task was to recover/find the password, that, when fed to the crackme application, will display some message like "congratz!" (see the above screen). First, we'll start with recon - we'll use tools like PEiD (which of course I didn't have with me on the conference - I took an not-configured laptop with me, without most tools, and especially, without my source codes ;/), or Ent (this one I had with me). Below one can see the entropy chart from Ent (people who are not familiar with this kind of charts might be interested in reading this post):

As one can see, we do not have to deal with any non-trivial code encryption - it's good news - so, without hesitating any further, we can fed the executable into our favorite disassembler (that would be IDA Pro).

The Export list tells us that there are three starting points - 2x TLS callbacks and EP. This is where I made the mistake on Confi - I went straight to the EP, ignoring the TLS. Also this time I'll create some tension by heading straight to the EP :)

Let's start the analysis by finding the procedures responsible for acquiring the text string from the text field - GetWindowTextA, GetDlgItemTextA, etc - to do it, let's review the Import list. As one will find out, there is only one occurrence of GetDlgItemTextA:

At the VA 00401196 a call sub_403055 takes place, and the acquired string is passed in the argument. Next, depending on the result of the function call, one of two messages is displayed: "Congratulations..." or "Sorry...". So, the heart of all evil is the sub_403055 function.

Upon entering the function we are made aware that it's long. Very long. Veeeery very long. It has about 3000 lines of assembler code, mainly sub, xor, lea, ror, rol and add instructions. It looks like this:

To make it short: the input string address is passed into the ESI reg, then the EDI is pointed to an empty buffer that will contain the encoded input string, and then, DWORD by DWORD (lodsd) the input string is encoded, up to 5 DWORDs max (20 bytes). At the end, the encoded input string is compared with the original encoded password, thats located at VA 4070C2:

The first code sets the Trap Flag (CPU Step Mode). I first thought of it as some anti-debug trick and ignored, but, as I'll reveal in the moment, I was extremely wrong.

The second thing are the four NOPs, lying there, looking silly - why the hell does someone put 4 NOPs in the middle of the function? Is there some code injected runtime? Or some other evil trick executed?

And now we return to the TLS callbacks, or, to be more precise, to the TlsCallback_0 at VA 40233A. The first thing that comes into sight is the "loading imports" string, and there are more such strings here and there, that quite well explains what happens in the code. The Callback function is short, and it just calls a few functions, from which the most interesting one is sub_40120E.

In the mentioned function we see, inter alia, a call to CreateProcess functions with DEBUG_PROCESS flag and a debugger loop that handles i.a. EXCEPTION_SINGLE_STEP event that is generated by the Trap Flag setting code that we analyzed a few lines ago! The pieces finally start making sense! Let's sum up what we know until now:

- when we execute the crackme it never opens any window, instead, it creates another process from its executable and acts as it's debugger!- so we are talking 2 processes:- a child process - that shows the window, checks the password, and sets the Trap Flag- a parent process - that stays in the debugger loop and patiently awaits the TF activation

The bad thing about these things is that we cannot debug the child process using debugger API (sorry OllyDbg... but stealth debuggers like Obsidian or ring 0 debuggers will work of course, however, there is no need to use them anyway).

The mechanics of the above code works like this:- from the child's EIP address four bytes are acquired- if these 4 bytes are 90909090 (4x NOP - rings a bell ?) nothing is done (== the single step mode is turned off)- else, the TF flag is reset (TF is turned off after each 'trigger')- and then, the first instruction byte from EIP is checked:-- if its 35 (XOR EAX, imm32), then an additional SUB EAX, 2 is emulated/made (BEFORE the XOR instruction)-- if its 2D (SUB EAX, imm32), then an additional ADD EAX, 1 is made-- if its 05 (ADD EAX, imm32), then an additional XOR EAX, 10101010h is made- and the child process execution is resumed (for one instruction that is - since the TF flag was reset)

So, the cipher method has additional subtracts/additions/xors that are not visible in the listing (because they are performed by the external debugger!)... Cunnningg :)

OK! We have all the pieces to solve this mystery! There are a couple of actions we can now take, for example we could invert the listing, or make a brute force - I decided to do the later.

In such case, we'll have to start by copying the whole function containing the cipher, and then, using some regexps or sth, insert additional dec+dec, inc or xor instructions (it's best to do this in this order). After that we can remove the TF setting, and recompile (nasm it a good choice).

Now we create a simple C/C++ brute force that will:- load the compiled cipher into memory- fix some addresses here and there (to the original key and input/output buffers)- and, using the fact that there are only 4G of combinations minus the unprintable cases, runs the cipher in a loop

Because the encrypted password DWORDs are independent, we can search in one loop for a solution to all (5) password DWORDs. Such a brute force looks like this (the code is ugly, and was written with haste during the compo, so don't expect miss-code 2009 ;p):

As one can see it didn't find the last DWORD (since I excluded \0 from the "charset"), but that's not important. Now we have to arrange it in the right order, and guess the last 3 letters: You talkin' to m -> You talkin' to me?, and it's done! :)

Comments:

My friend linked me to this post and, instead of reading the spoiler, I fired up my reverse engineering tools to see what I could come up with. After a couple false starts and confusing detours, I discovered what was going on. Unlike you, I chained together a few shell commands and totally inverted the listing. So, I put the numbers in and out pops the result.

It was a very cool challenge, and I learned some neat tricks from it (like what TLS means, and a bit about debugging).

If you're curious, all the code I used, as well as my .idb (for IDA 4.51) file and whatnot, is here:http://svn.skullsecurity.org:81/ron/security/2009-eset-crackme/

A step by step writeup of what I ended up doing (including the hole I painted myself into and some 'fail!' and 'crash!' messages is here:http://svn.skullsecurity.org:81/ron/security/2009-eset-crackme/outline.txt

Thanks! I have no real training in reverse engineering -- I've barely even read about techniques. Everything I do is pretty much derived from trying things out and seeing what works.

Same goes to you @ techniques, though! Every time I read about how somebody else did something, I learn a bit.

I like how you used the bruteforce technique, actually. I had originally considered doing that, and had planned it all out. Then I actually looked over the code and realized it'd be super easy to reverse the operations, and way cooler, so I did that instead. I'm glad to see that both ways worked!

@Ron BowesAdditional great work to you then ;>I've considered making an inversion, but I was a little afraid I would miss some AND/SHL/SHR or similar instruction that is irreversible (I didn't have time to check all the instructions ;>), so I finally decided to do brute force ;>But as you say, it's good to know there is more then one way to do it! ;>

And it gave me the list of just 6 instructions, 5 of which can easily invert and one of which doesn't have to be (xor). Then, I used a shellscript to do the replaces automatically. Having a background in Linux and shellscripting helped me a lot, obviously -- I can process text files really fast when I need to.

That being said, when I actually ran it the first time, I was sure I would miss something, and that I'd have to start combing through line by line. I had the benefit of having unlimited time to work on it, though (I'd estimate I spent 4-5 hours total, across two days).

To go the other way, I wrote a bruteforcer. I'm sure it's possible to run that function backwards, but I don't know how.

I took tons notes as I went along, since you're probably interested in how I managed to finish this. But, unfortunately, they're a disaster right now. It's also way past my bedtime. I'll post a link to my notes tomorrow, after a good rest. I couldn't resist replying ASAP, though!

All right, all rested up I cleaned my notes and threw everything onto my svn server. Check it out:http://svn.skullsecurity.org:81/ron/security/2009-shaker-crackme/

You'll find code and everything there. If you want to go straight to the good stuff, try:http://svn.skullsecurity.org:81/ron/security/2009-shaker-crackme/shaker.txt

That's my step by step notes that I took as I was working. You can see the wrong/right paths I took there. I wrote it as I went, so it's pretty complete. The source for my key (that I already posted, but that turned kinda ugly) is here:http://svn.skullsecurity.org:81/ron/security/2009-shaker-crackme/shaker-bruteforce.c

Let me know what you think! And also, let me know how you solved it.. I'm really curious how close I was to any kind of a standard approach. My approach was to use a lot of debugging, but it could very easily have been defeated. I'm lucky that this was, in the end, a rather simple crackme -- if it was complex, PLUS the obfuscation, it would have been nightmarish. :)

Oh, and if you have any more cool crackme's, let me know! This was great fun in my spare time.

@RonGreat work!!! ;>Thanks for the solution, it's always good to learn some new points of view ;>I've solved this crackme with GDB and a trace'ing script hehe, so basically a similar way to your, except the tool was different.My friend j00ru has also used a similar way, only using OllyGDB ;>

Anyway, I'm afraid I don't have any more links to crackmes for you, since I don't did do many of those.Maybe some other reader could provide some links for the crackme-hungry Ron over here ? ;>>>

Oh, you can take a look at the Hacker Challenge (hackerchallenge.org) crackme's, however I have no idea where are they published ;<

For what it's worth, me and my friend abstracted this a bit, and managed to remove the bruteforce aspect from the equation. Now you put in an arbitrary string, and it instantly (O(n)) returns the result.