Cracking
Devoney's Crackme 2.0
-
by
Sunshine |
|
Download whole package here! (includes crackme and this tut)
First check what we gonna have to do: The exercise is to find a valid password which gives us somehow a secret text. To check if we got the correct secret text, we have to go to "http://members.lycos.nl/wietsite/fp.php?x=X" where 'X' is replaced with the secret text. I just chose any word, went to the site, and it just told me that I'm wrong :-( So we know what it's all about, let's start...
Ok, the crackme is coded in Assembler and just 2kb in size... nice! Starting it, we see just one input box and button, that's it. So I just left the input box empty, pressed the 'Go' button and got a really nice exception; so I restarted it, typed in anything, pressed the button and again I got an exception (altough this time it was another one ;-)
Let's crack this one...
So fire up Ollydbg
and load our target: at the entrypoint we see after calls to GetModuleHandle
and GetCurrentProcess (note that the handle to the current process
is saved @ 4030C8). Then a buffer is allocated, we see some calls to MultiByteToWideChar
and some structures are filled The window is created with DialogBoxIndirectParamA.
The window procedure starts @ 4011A2. Ok, nothing strange till now... Examining
it, we easily see that the WM_COMMAND message is handled from 4011CF
on (remember, it's the constant 0x111). Then the text from the input box is
taken, saved @ 403000 and a loop follows...
Scroll to the end of the loop, we see that there comes a call to WriteProcessMemory.
00401139
|. 837D 0C 01 CMP
[ARG.2],1 ; --
WM_CREATE? 0040132F FF35
21304000 PUSH DWORD PTR DS:[403021] --
pBytesWritten |
Hm... let's have
a detail look at it: 0x13 bytes from address 403009 are written to 401351 to
this process. What, 401351? That's the address after the WriteProcessMemory
call! So it's gonna be executed! That's means that the buffer at 403009 MUST
contain code!
Ok, 0x13 bytes are written, so the memory from 403009 till 40301C must be executable.
If we have some look at the loop, we see that our input string modifies this
memory range. Now it's clear why the crackme crashes: our serial produces garbage
in the memory buffer which are not valid opcodes.
Also note in the dump window in Ollydbg that right after our memory buffer,
at address 403025 there is the string "The Secret
Text is: 00000". If we look again at the loop, we see that this
string is also modified by our entered password.
At first, I thought I had to choose the password so that the memory buffer 403009 contains 0x90 (just nops). So the crackme would run fine and I could dump the secret text at 403025. Well, I tried it, but it didn't work :-( I visited the discussion board of this crackme at crackmes.de and luckily the user profdracula gave us the hint that in order to crack it, you have to know how to call a messagebox! Ah, ok... we should call a messagebox where we put in the string from address 403025.
Nice, so I decided that my code should look like the following. Note that the code consists of 19 bytes, exactly the number of bytes written by WriteProcessMemory! I think that's a hint, cause we could for example leave the caption blank, but then we would need less bytes.
00401351
6A 00
PUSH 0 00401353 68 25304000 PUSH CrackMe2.00403025 ; ASCII "The Secret Text is: 00000" 00401358 68 25304000 PUSH CrackMe2.00403025 ; ASCII "The Secret Text is: 00000" 0040135D 6A 00 PUSH 0 00401360 E8 32000000 CALL <JMP.&user32.MessageBoxA> |
So our buffer must look like this after the loop has processed our password:
00403009 = { 0x6A 0x00 0x68 0x25 0x30 0x40 0x00 0x68 0x25 0x30 0x40 0x00 0x6A 0x00 0xE8 0x32 0x00 0x00 0x00 } |
Here is the complete loop:
004011FC
|. BB FFFFFFFF MOV
EBX,-1 00401201 |. B9 FFFFFFFF MOV ECX,-1 00401206 |> 43 /INC EBX ; ebx = loop counter 00401207 |. 36:8A0C1A |MOV CL,BYTE PTR SS:[EDX+EBX] ; cl = password[i] 0040120B |. 84C9 |TEST CL,CL ; cl == 0 ? 0040120D |. 0F84 1C010000 |JE CrackMe2.0040132F ; -> bye 00401213 |. 83FB 00 |CMP EBX,0 ; i == 0? 00401216 |. 77 40 |JA SHORT CrackMe2.00401258 ; no? -> jump 00401218 |. 80E9 5B |SUB CL,5B ; cl -= 0x5B 0040121B |. 36:880D 0A304> |MOV BYTE PTR SS:[40300A],CL ; write cl to mem locations 00401222 |. 36:880D 0F304> |MOV BYTE PTR SS:[40300F],CL 00401229 |. 36:880D 14304> |MOV BYTE PTR SS:[403014],CL 00401230 |. 36:880D 16304> |MOV BYTE PTR SS:[403016],CL 00401237 |. 36:880D 19304> |MOV BYTE PTR SS:[403019],CL 0040123E |. 36:880D 1A304> |MOV BYTE PTR SS:[40301A],CL 00401245 |. 36:880D 1B304> |MOV BYTE PTR SS:[40301B],CL 0040124C |. 80C1 72 |ADD CL,72 ; cl += 0x72 0040124F |. 36:880D 3A304> |MOV BYTE PTR SS:[40303A],CL 00401256 |.^ EB AE |JMP SHORT CrackMe2.00401206 ; jump back to loop begin 00401258 |> 83FB 01 |CMP EBX,1 ; i == 1? 0040125B |. 77 1D |JA SHORT CrackMe2.0040127A ; no? -> jump 0040125D |. 80C1 0B |ADD CL,0B ; cl += 0x0B 00401260 |. 36:880D 09304> |MOV BYTE PTR SS:[403009],CL ; write cl to mem locations 00401267 |. 36:880D 15304> |MOV BYTE PTR SS:[403015],CL 0040126E |. 80E9 03 |SUB CL,3 ; cl -= cl 00401271 |. 36:880D 39304> |MOV BYTE PTR SS:[403039],CL 00401278 |.^ EB 8C |JMP SHORT CrackMe2.00401206 ; jump back to loop begin 0040127A |> 83FB 02 |CMP EBX,2 ; i == 2? 0040127D |. 77 20 |JA SHORT CrackMe2.0040129F ; no? -> jump 0040127F |. 80C1 25 |ADD CL,25 ; cl += 0x25 00401282 |. 36:880D 0B304> |MOV BYTE PTR SS:[40300B],CL ; write cl to mem locations 00401289 |. 36:880D 10304> |MOV BYTE PTR SS:[403010],CL 00401290 |. 80E9 03 |SUB CL,3 ; cl -= 0x03 00401293 |. 36:880D 3B304> |MOV BYTE PTR SS:[40303B],CL 0040129A |.^ E9 67FFFFFF |JMP CrackMe2.00401206 ; jump back to loop begin 0040129F |> 83FB 03 |CMP EBX,3 ; i == 3? 004012A2 |. 77 20 |JA SHORT CrackMe2.004012C4 ; no? -> jump 004012A4 |. 80E9 42 |SUB CL,42 004012A7 |. 36:880D 0D304> |MOV BYTE PTR SS:[40300D],CL ; ... and so on 004012AE |. 36:880D 12304> |MOV BYTE PTR SS:[403012],CL 004012B5 |. 80C1 35 |ADD CL,35 004012B8 |. 36:880D 3C304> |MOV BYTE PTR SS:[40303C],CL 004012BF |.^ E9 42FFFFFF |JMP CrackMe2.00401206 004012C4 |> 83FB 04 |CMP EBX,4 004012C7 |. 77 16 |JA SHORT CrackMe2.004012DF 004012C9 |. 80E9 21 |SUB CL,21 004012CC |. 36:880D 0E304> |MOV BYTE PTR SS:[40300E],CL 004012D3 |. 36:880D 13304> |MOV BYTE PTR SS:[403013],CL 004012DA |.^ E9 27FFFFFF |JMP CrackMe2.00401206 004012DF |> 83FB 05 |CMP EBX,5 004012E2 |. 77 0F |JA SHORT CrackMe2.004012F3 004012E4 |. 80C1 85 |ADD CL,85 004012E7 |. 36:880D 17304> |MOV BYTE PTR SS:[403017],CL 004012EE |.^ E9 13FFFFFF |JMP CrackMe2.00401206 004012F3 |> 83FB 06 |CMP EBX,6 004012F6 |. 77 0F |JA SHORT CrackMe2.00401307 004012F8 |. 80E9 2C |SUB CL,2C 004012FB |. 36:880D 0C304> |MOV BYTE PTR SS:[40300C],CL 00401302 |.^ E9 FFFEFFFF |JMP CrackMe2.00401206 00401307 |> 83FB 07 |CMP EBX,7 0040130A |. 77 19 |JA SHORT CrackMe2.00401325 0040130C |. 80E9 3A |SUB CL,3A 0040130F |. 36:880D 11304> |MOV BYTE PTR SS:[403011],CL 00401316 |. 80C1 3F |ADD CL,3F 00401319 |. 36:880D 3D304> |MOV BYTE PTR SS:[40303D],CL 00401320 |.^ E9 E1FEFFFF \JMP CrackMe2.00401206 00401325 |> 80E9 2B SUB CL,2B 00401328 |. 36:880D 18304> MOV BYTE PTR SS:[403018],CL |
Note that in the
loop the eight seven chars of the password are processed, and the ninth one
after the loop. Is the password longer, the other chars are ignored.
Let's examine what is done with the first char:
At 401218 0x5B are subtracted. Then this value is written at 40300A, 40300F
and so on... Well our buffer starts at 403009, so at 40300A, 40300F, ... there
must be a 0x00. So we get following equation:
char[0] -
0x5B must be 0x00 => char[0] = 0x5B = '[' |
For the other eight characters of the password, we do the same: look which value is subtracted/added, at which position in the buffer it's written and which opcode byte is has to be. So we get the following:
char[1]
+ 0x0B is written @403009 which must be 0x6A. char[2] + 0x25 is written
@40300B which must be 0x68. char[3] - 0x42 is written
@40300D which must be 0x30. char[4] - 0x21 is written
@40300E which must be 0x40. char[5] + 0x85 is written
@403017 which must be 0xE8. char[6] + 0x2C is written
@40300C which must be 0x25. char[7] + 0x3A is written
@403011 which must be 0x25. char[8] + 0x2B is written
@403018 which must be 0x32. |
So run the crackme, type in the input box "[_CracQ_]" and we get a nice messagebox: "The Secret Text is: greed". So take your prefered browser and go to http://members.lycos.nl/wietsite/fp.php?x=greed and we see the 'good boy' message.
Hm, "[_CracQ_]"
doesn't make much sense, "[_Crack_]" look much better. If you try
it you'll see it also works: the messagebox text remains the same, but the caption
becomes "Check
at http://members.lycos.nl/wietsite/fp.php?x=secret_text".
00401353 68
25304000 PUSH CrackMe2.00403025
becomes
00401353 68
3F304000 PUSH CrackMe2.0040303F
So I think this is the real solution, but both work! This was luck!
That was a really nice crackme. Hope you understood what I was talking about :-) Till the next time...
Sunshine, February 2k7
This site is part of Sunshine's Homepage