cyberbob's CrackMe #1
Bit Manipulation
Written by Sphinx


Introduction


Ok. This CrackMe uses some nice methods for password encryption through bit manipulation (ie. maths ;-) Btw, I think the rating of it as an "easy" CrackMe maybe a bit too low than what it really is IMHO :-) And we'll find out why later and decide what you think :-)

Tools required


SoftICE 3.25
RegMon 4.0
TASM 5.0
TR 2.52 (to debug my ASM files :-)

Target's URL

http://crackmes.prv.pl (nice site with unsual CrackMes :-)

Essay



Now snoop! And yes, it's MASM-coded and it's not packed or crypted so
we could fish for some strings. And hmmm, 
interesting, we could see a \\.\SICE. So we assume it uses the MeltICE trick at first. Now also try looking at the imports section so we'll have a list of APIs to break on :-) Strange? No refs to CreateFileA (or even _lopen). So how would it open the SoftICE VxD then? Answer. It doesn't. Yep, it's just a fake string residing in the file to fool us ;-) And there's even some functions from ADVAPI32.DLL. And even MessageBoxA and GetDlgItemTextA are there ;-) Good fishing eh?

So run it. At first, you'll see a blank form other than Dexter's icon and a menu. So try snooping that as well ;-) Now what? Since the MeltICE trick is fake, we'll use other infos we know. Let's monitor the app for registry access coz it has imported some remember? So running RegMon we see:
OpenKey         HKCU\Dexter             NOTFOUND
So 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      NOTFOUND         
So now it searches for a a value named DeeDee. So I created one of binary type and filled it with crap like 0102030405.

Breakpoint RegQueryValueExA before running the app (so be sure ADVAPI32.DLL is loaded). Or better yet, use Symbol Loader and just put a breakpoint there. (you know what I mean right? heh) Anyway, the snippet:
 ...(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 occurs
Now the first calculation follows.

Part 1:
 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   next 
As you can see, esi holds our "key". This shouldn't take that long until you find out it's 4E696E61 which reads Nina. So
we'll try that out. BUT no need to swap them here coz the app will read the backwards then will swap them using "bswap".
So now change the value of DeeDee to (in hex) 4E 69 6E 61. Run the prog and you'll see that a password field and some buttons emerged! I know this is kinda sloppy coz I brute forced. But it's not going to happen anymore. I promise ;-)

Part 2:

Now enter a dummy password. Btw, note that the property ES_AUTOSCROLL of the password field is disabled which means that the text you type in will be limited by the size of the textbox and by the size of the chars you type (eg. you could type in more i's than you would using w's. A hint? Dunno really. Think for yourself :-P So now what? Remember, we saw GetDlgItemTextA before? Yeah. So Let's try breakpointing it then after entering a fake password like 12345.
 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
if we're to brute force everything, it would take the fun and the challenge of the app :-) So there are 2 user-defined values:

  • length of the password
  • first 4 chars of it

    I suggest you look / examine more closely the code above and see what is happening with the eax and ebx registers coz I
    can't explain everything going on in my head ;-) Anyway, I coded yet another ASM source that would give the value of ebx first. Wby ebx first? coz as you can see, it's the least dependent of the two (ie. it only relies on the password length so it's
    the least modified / used register). So we'll use this info and reverse the algo :-) Btw, the choosing of the correct password length is kinda tricky as you will see later ;-) But first, the main code:
      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
    testing some cribs ;-) And I'll just continue with my first guess of 28h. So we know what's ebx. So I coded another one coz my standard calculator can't handle it ;-) The aim of the next code is to find out what eax should be (ie. the first 4 chars).
    Note that since we're reversing the algo, we'll also reverse some of the instructions (eg. add to sub, rol to ror)
      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
    as the first 4 chars of the 40-lengthed password. What happened? Kewl noh?

    But it's kinda tedious to use separate ASM files. So I merged the two :-) Then something occured to me. What if the password should REALLY be in human-readable form :-) So what word starts with lapT btw? :-) And hey, like I said, I
    can't document everything I did coz I tested several password with different lengths. Afterwards, I finally come up with a readable output when the length of the password is 12.
      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 password 
    After running this piece of code, you'll see that eax = 70706148 which reads as Happ. Hmmm, getting more interesting ;-)
    So now I'd enter a password of 12 chars with Happ as its first 4 chars. I entered Happ1234War* So part 2 done. Next?

    Part 3:

    Now we've come to the last part. Btw, a part of testing some password lengths, do you wonder (if you debug it yourself ;-)
    where I got War and why did I choose * as my 12th char. Well, just a thought :-)
     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*.
    So now you know where to snoop the real encrypted password :-) After comparing the contents of esi and edi registers, you'll find out that they're NOT equal (sux!) Anyway, after dumping and snooping it out, you'll know what eax and ebx
    should be after those mumbo-jumbo calcs above. Anyway, here they are:
     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,
    this what helped me determined the real password length :-) And I told way above that the Miky_~H_ string is the only
    one should be used in comparing the two passwords. So now what? We've to find out what the 2 parts really are before encryption ;-) So here's my reversed code of the algo above:
      mov   eax, 796B694Dh
      mov   ebx, 00487E00h
      xchg  eax, ebx                        ; nothing, I just wanted to do it ;)
      xor   ebx, 50514934h
      rol   eax, 8
      xor   eax, ebx 
    Then 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!

    Sphinx [sphinxter@edsamail.com.ph]

    Final Notes


    I hope it's not that too cryptic coz I know it's a bit messy and may even be a bit complicated. But it's not actually :-) It's just
    that it's this way I could present the solution :-) Sure it's kinda long yet it's an interesting CrackMe ;-) Much work for a simple result? Sure. But it was all worth it :-) hehehe


    Greets to:

    TRES2000 (nice guys :-)
    cyberbob (nice app :-)
    tnHuAn (for the url :-)
    You (for reading this :-)


    When ever there is a door,
    there is an entrance.
    And behind an entrance can no secret hide,
    when a cracker takes his knowledge for a ride
        McCodEMaN



    ObDuh

    The information in this essay is for educational purpose only!
    You are only allow to crack, reverse engineer, modify code and debugg programs that you legaly bought and then for personal use only!!
    To ignore this warning is a criminell act and can result in lawful actions!

    So please note!
    I take no responebility for how you use the information in this essay, i take NO responebility for what might happen to you or your computer!
    You use this information on your own risk!! I mean it!









    Essay written by Sphinx ŠTRES2000. All Rights Reserved.