
cyberbob's CrackMe #1
Bit Manipulation
Written by Sphinx
Introduction |
Tools required |
Target's URL |
http://crackmes.prv.pl (nice site with unsual CrackMes :-)
Essay |
OpenKey HKCU\Dexter NOTFOUNDSo it tries opening a key named Dexter in HKCU eh? So we create one and hope it's not another trick ;-) So spy again and now you should see:
OpenKey HKCU\Dexter SUCCESS QueryValueEx HKCU\Dexter\DeeDee NOTFOUNDSo now it searches for a a value named DeeDee. So I created one of binary type and filled it with crap like 0102030405.
...(parameters are pushed)... cs:004011E3 CALL ADVAPI32!RegQueryValueExA ; read it (contents of DeeDee) cs:004011E8 OR EAX,EAX cs:004011EA JNZ 00401225 ; jump if any error occursNow the first calculation follows.
cs:004011EC MOV ESI,[004042A9] ; esi = 04030201 (data buffer)
cs:004011F2 BSWAP ESI ; byte swap esi (changes the byte order), so
; esi = 01020304
cs:004011F4 POP EAX ; eax = 52656458 ("RedX")
; (from "pushing" it before RegOpenKeyExA)
cs:004011F5 ADD EAX,ESI ; eax = eax + esi
cs:004011F7 XOR EAX,ESI ; eax = eax ^ esi
cs:004011F9 XOR ESI,DEE00DEE ; esi = esi ^ DEE00DEE
cs:004011FF ROL ESI,C4 ; esi = rotl(esi, C4)
cs:00401202 XOR ESI,EAX ; esi = esi ^ eax
cs:00401204 SHR ESI,1 ; esi = esi << 1
cs:00401206 INC ESI ; esi++
cs:00401207 CMP ESI,7318C211 ; is esi == 7318C211?
cs:0040120D JNZ 0040121A ; no? jump badboy!
So our first task is to enter a dword value which, after thise calcs, should
result to 7318C211. So how are we supposed to reverse this?
Hmmm, I haven't. I just brute-forced here. Why so? coz the instructions are
too much dependent on the infos entered by the cracker or I was just
confused :-) So I coded a tiny brute-forcer in ASM. And here's just the main part:
xor esi, esi next: inc esi push esi mov eax, 'RedX' add eax, esi xor eax, esi xor esi, 0DEE00DEEh rol esi, 0C4h xor esi, eax shr esi, 1 inc esi cmp esi, 7318C211h pop esi jnz nextAs you can see, esi holds our "key". This shouldn't take that long until you find out it's 4E696E61 which reads Nina. So
cs:004012E1 PUSH 00000200 ; max string length to get
cs:004012E6 PUSH 00404498 ; dest buffer
cs:004012EB PUSH 00000BB8
cs:004012F0 PUSH DWORD PTR [EBP+08]
cs:004012F3 CALL USER32!GetDlgItemTextA
cs:004012F8 PUSH EAX ; eax = length, so save it
cs:004012F9 TEST EAX,EAX ; have we entered anything?
cs:004012FB JNZ 00401316 ; yah? jump to PART2, else...
cs:004012FD PUSH 30
cs:004012FF PUSH 004041A4
cs:00401304 PUSH 004041B1 ; "nothing entered" message
cs:00401309 PUSH DWORD PTR [EBP+08]
cs:0040130C CALL USER32!MessageBoxA
cs:00401311 JMP 004013CB
PART2:
cs:00401316 POP EBX ; ebx = 5 (from "push eax" above - the length!)
cs:00401317 SUB EBX,00BEEBEE ; ebx = ebx - BEEBEE
cs:0040131D MOV EAX,[00404498] ; eax = 34333231 ("4321" - first 4 chars)
cs:00401322 XOR EAX,EBX ; eax = eax ^ ebx
cs:00401324 ROL EAX,08 ; eax = rotl(eax, 8)
cs:00401327 ADD EAX,00000ADD ; eax = eax + ADD
cs:0040132C ADD EBX,32344D4E ; ebx = ebx + 32344D4E
cs:00401332 SUB EAX,EBX ; eax = eax - ebx
cs:00401334 CMP EAX,00 ; was the difference = 0?
cs:00401337 JNZ 004013A4 ; nope? jump badboy!
So our 2nd task is to enter a password whose first 4 chars (coz it only
uses the first dword), after those calcs, eax should result to 0 to pass.
So how to reverse this? Yah, this time I didn't brute forced coz it would
take too long to do so :-) And mov ebx, 28h ; yep, ebx has our chosen length sub ebx, 0BEEBEEh ; ebx = 28 - BEEBEE = FF41143A (used later) mov eax, '1234' ; note that I didn't care yet xor eax, ebx ; what eax should be at first rol eax, 8 ; coz my aim is to find out add eax, 0ADDh ; what ebx should be right? :) add ebx, 32344D4Eh ; ebx = FF41143A + 32344D4E = 31756188 (this is ebx) sub eax, ebx ; eax = eax - ebx (which sould equal to 0 to pass)So why did I choose 28h (or 40 in dec) as length? coz as I was snooping around (and inverting some jumps.. hehe). I saw:
Miky_~H_Warning Virus !_nice to meet you (note that those "_" are really 00's in memory)But I'll spoil you now coz it's another trick! Only the first 8 chars if that string is going to be used. I found that out while
mov eax, 31756188h ; eax = 31756188 (from above)
sub eax, 0ADDh ; eax = 31756188 - ADD = 317556AB (reversed)
ror eax, 8 ; eax = 317556AB ror 8 = AB317556 (reversed)
xor eax, 0FF41143Ah ; eax = AB317556 xor 0FF41143A (from above)
; eax = 5470616C ("Tpal")
So let's try it. But don't enter it as is. You have to enter it backwards
coz the prog will read them reversed. So enter lapT mov ebx, 12 ; chosen password length sub ebx, 0BEEBEEh push ebx add ebx, 32344D4Eh mov eax, ebx sub eax, 0ADDh ror eax, 8 pop ebx xor eax, ebx ; result is the first 4 letters of the passwordAfter running this piece of code, you'll see that eax = 70706148 which reads as Happ. Hmmm, getting more interesting ;-)
cs:00401339 NOP ; useless :)
cs:0040133A MOV EAX,[0040449C] ; eax = 34333231 ("4321")
cs:0040133F MOV EBX,[004044A0] ; ebx = 2A726157 ("*raW")
cs:00401345 XOR EAX,EBX ; eax = 34333231 xor 2A726157
; eax = 1E415366
cs:00401347 ROR EAX,08 ; eax = 1E415366 ror 8
; eax = 661E4153
cs:0040134A XOR EBX,50514934 ; ebx = 2A726157 xor 50514934
; ebx = 7A232863
cs:00401350 XCHG EAX,EBX ; eax = 7A232863 ("z#(c") and
; ebx = 661E4153 ("f-AS") (that "-" in there
; really is a 0x1E. I just can't type it :)
cs:00401351 XOR ECX,ECX ; clear ecx
cs:00401353 MOV CL,[004044A3] ; cl = 2A ("*")
cs:00401359 XOR CL,21 ; cl = 2A ^ 21
; cl = 0B
cs:0040135C MOV [00404498],EAX ; save eax ; overwrite 1st dword of my pwd in mem.
cs:00401361 MOV [0040449C],EBX ; save ebx ; overwrite 2nd dword of my pwd in mem.
cs:00401367 MOV ESI,00404498 ; my encrypted password
cs:0040136C MOV EDI,004042C8 ; original encrypted password
cs:00401371 CLD ; clear direction flag
cs:00401372 REPZ CMPSB ; repeat comparing bytes while ecx != 0
cs:00401374 JNZ 004013A4 ; jump to badboy if not equal!
Initially, my password was Happ1234War* right? And after the last
two instructions above, it'll now be c(#zSA-fWar*.
eax = 796B694D ("ykiM") ; coz it's read backwards
ebx = 00487E00 ("_H~_") ; remember those "_"?
So let's work backwards shall we? Note that at first, they should be
interchanged coz of the use of "xchg" later. So:
eax = 00487E00 ("_H~_")
ebx = 796B694D ("ykiM")
And where did it get the value of ecx? Yep, ecx determines how many
bytes to compare my encrypted password to the original encrypted password coz
of the use of "repnz cmpsb". And yep, it gets it from the 12th char
of the password. Btw, mov eax, 796B694Dh mov ebx, 00487E00h xchg eax, ebx ; nothing, I just wanted to do it ;) xor ebx, 50514934h rol eax, 8 xor eax, ebxThen after running this piece of code, you'll notice that:
eax = 61442079 ("aD y") and
ebx = 293A2079 ("): y")
So do you pheel it now :-) Yep, the password is composed of 2 real words!
So now to test it. Make the password read: Happy Day :)Punch the "Check" button and cross your fingers. Heh, it's correct! So that's it. It's cracked and I'm done :-) So cya!
Final Notes |