The_NOP's CrackMe #1
XOR Reversing
Written by Sphinx


Introduction


Ok, big deal. The sub-title's not new, but I was uninspired lately and I thought that this CrackMe is somewhat interesting
on how it uses XOR. Anyway, I'm just glad that the CrackMe's site just got updated coz a (descent) girl cracker or whatever
would probably be offended :-) Greets to them girls!



Tools required


SoftICE 3.25
TASM 5.0

Target's URL

http://royalaccezz.cjb.net



Essay


Ok. As usual, snoop! Ahhh, packed by UPX! But no need to unpack here just to get an external disassembly. SoftICE
would suffice :-) So run it nah. I entered Andrea as name and 12345 as serial. Btw, if you're technical (like me), the name
field has the property "ES_AUTOHSCROLL" turned off. Meaning, the text you type in will be limited by the size of the textbox. And the serial field has the property "TAB STOP" also turned off, which is bothersome :-) Oh yeah, it doesn't
accept anything else aside from numbers. A hint already :-) Bah! Enough technical crap, let's proceed noh? Ok. Simply breakpoint GetDlgItemTextA prior to hitting the "Validate" button and you'll end up in the program's code. Right after
hitting F12, you'll be at the line after the call to the API. But try noticing the previous lines, it proves to be interesting, so
we backtrace there.

0137:004010BD  PUSH    EBP                      ; these two lines are
0137:004010BE  MOV     EBP,ESP                  ; equivalent to ENTER :)
0137:004010C0  ADD     ESP,-08                  ; init the stack a bit
0137:004010C3  PUSH    00
0137:004010C5  LEA     EAX,[EBP-08]
0137:004010C8  PUSH    EAX
0137:004010C9  PUSH    05
0137:004010CB  PUSH    DWORD PTR [00403044]
0137:004010D1  CALL    USER32!GetDlgItemInt     ; convert serial to hex to eax
0137:004010D6  CMP     EAX,00                   ; have we entered anything?
0137:004010D9  JZ      00401129                 ; nope? jump badboy, else...
0137:004010DB  MOV     [EBP-08],EAX             ; save for later (ie. 3039h)
0137:004010DE  PUSH    14                       ; (max length of string to snatch)-1
                                                  ie. 14-1 = 13 (19 chars)
0137:004010E0  PUSH    00403048                 ; name buffer
0137:004010E5  PUSH    04                       ; name field handle
0137:004010E7  PUSH    DWORD PTR [00403044]     ; dialog handle
0137:004010ED  CALL    USER32!GetDlgItemTextA   ; read the name; eax = length
0137:004010F2  CMP     EAX,00                   ; have we entered anything?
0137:004010F5  JZ      00401129                 ; nope? jump to badboy too, else...
0137:004010F7  CMP     EAX,14                   ; have we entered <= 14 (20 chars)?
0137:004010FA  JLE     0040112C                 ; yep? jump to BUILDNAME

But notice that the name buffer will only accept 19 chars, so no matter what
happens, you'll always jump to BUILDNAME (which is just below this line).

BUILDNAME:
0137:0040112C  ADD     EAX,01                      ; increment name ptr
0137:0040112F  MOV     BYTE PTR [EAX+00403048],90  ; move a 90h to it
0137:00401136  CMP     EAX,14                      ; is eax <= 14 nah?
0137:00401139  JLE     0040112C                    ; nope? loop until it is
0137:0040113B  JMP     004010FC                    ; after, jump to CALC

So after, the username in memory will be:

DS:00403048 41 6E 64 72 65 61 00 90-90 90 90 90 90 90 90 90 Andrea.......... DS:00403058 90 90 90 90 90 90 00 00-00 00 00 00 00 00 00 00 ................
Note that after the name, there's a 00h, since it already incremented the name ptr even before moving a 90h there. CALC: 0137:004010FC MOV EAX,[EBP-08] ; eax = 3039 (usercode in hex) 0137:004010FF MOV EBX,[00403048] ; ebx = dword ptr [name], so ebx = 72646E41 ("rdnA") 0137:00401105 XOR EAX,EBX ; eax = eax xor ebx, so eax = 72645E78 0137:00401107 MOV EBX,[0040304C] ; ebx = dword ptr [name+4], so ebx = 90006165 (" ae") 0137:0040110D XOR EAX,EBX ; so, eax = E2643F1D 0137:0040110F MOV EBX,[00403050] ; ebx = dword ptr [name+8], so ebx = 90909090 0137:00401115 XOR EAX,EBX ; so, eax = 72F4AF8D 0137:00401117 MOV EBX,[00403054] ; ebx = dword ptr [name+0Ch], so ebx = 90909090 0137:0040111D XOR EAX,EBX ; so, eax = E2643F1D 0137:0040111F MOV EBX,[00403058] ; ebx = dword ptr [name+10h], so ebx = 90909090 0137:00401125 XOR EAX,EBX ; so, eax = 72F4AF8D 0137:00401127 LEAVE ; as opposed to the above :) 0137:00401128 RETF ; get out; ret to MAIN 0137:00401129 INC EAX ; eax = 1 (badflag!) 0137:0040112A LEAVE ; (same) 0137:0040112B RETF ; get out; ret to MAIN MAIN: ...(some crap)... 0137:00401077 CALL 004010BD ; yep, calls the routine above 0137:0040107C CMP EAX,00 ; is eax = 0? 0137:0040107F JZ 0040109F ; yeah? jump goodboy, else... 0137:00401081 PUSH 10 ; style 0137:00401083 PUSH 00403009 ; caption 0137:00401088 PUSH 0040301D ; "bad" text 0137:0040108D PUSH DWORD PTR [EBP+08] ; handle 0137:00401090 CALL USER32!MessageBoxA ; draw it 0137:00401095 POP EBX 0137:00401096 MOV EAX,00000001 0137:0040109B LEAVE 0137:0040109C RET 0010 0137:0040109F PUSH 10 ; style 0137:004010A1 PUSH 00403009 ; caption 0137:004010A6 PUSH 00403030 ; "good" text 0137:004010AB PUSH DWORD PTR [EBP+08] ; handle 0137:004010AE CALL USER32!MessageBoxA ; draw it 0137:004010B3 POP EBX 0137:004010B4 MOV EAX,00000001 0137:004010B9 LEAVE 0137:004010BA RET 0010
So our main task is to enter a serial that, after those long mumbo-jumbo calcs, eax should result to 0. How? See below :-)
Btw, I wonder why the good messagebox still displays with an "error" style. It's just logical that if I entered the right one, it should display something else :-)

Ok. Now we know that the first XOR value is user-defined, so you might think that we should brute force this program.
But NO! There's an easy and less time consuming way! We just need to understand how XOR works. Here's a sample:
A xor B = C     ->     1 xor 2 = 3
B xor C = A     ->     2 xor 3 = 1
C xor A = B     ->     3 xor 1 = 2

Simple eh? Well, it is. Anyway...

The program went...
1. 00003039 xor 72646E41 = 72645E78
2. 72645E78 xor 90006165 = E2643F1D
3. E2643F1D xor 90909090 = 72F4AF8D
4. 72F4AF8D xor 90909090 = E2643F1D
5. E2643F1D xor 90909090 = 72F4AF8D

So we could then say...
1. 90909090 xor 90006165 = 0090F1F5
2. 0090F1F5 xor 72646E41 = 72F49FB4 (1928634292 in dec)
Which means that 1928634292 is the correct serial! Try it. Kewl noh? Basically, you just have to do it backwards.
But, make sure you'll start from the right position. Hmmm, can't explain it well in text really, so I'll just paste here my
keygen source (calc only, coz the whole source is just too big as it's written in win32asm and not DOS asm anymore. :-)
CALC:

movzx eax, [nLen] cmp al, 8 jg @@2 mov eax, dword ptr [NameBuf+8] mov ebx, dword ptr [NameBuf+4] xor eax, ebx mov ebx, dword ptr [NameBuf] xor eax, ebx jmp @@print @@2: mov eax, dword ptr [NameBuf+10h] mov ebx, dword ptr [NameBuf+0Ch] xor eax, ebx mov ebx, dword ptr [NameBuf+8] xor eax, ebx mov ebx, dword ptr [NameBuf+4] xor eax, ebx mov ebx, dword ptr [NameBuf] xor eax, ebx @@print: ...(convert eax to dec and display it)...
That's it. Later, Sphinx.

Final Notes



Greets to:



McCodEMaN (thanks for the help)
tnHuAn (good luck :)
TRES2000
The_NOP




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!!









Essay written by Sphinx TRES2000. All Rights Reserved.