1.
Finding correct serial(for lazy ones:)
Like an all other
proggies you can also crack this one on the few different ways.
Here I'll explain
only one, the most simplest way to find the correct serial!
Open W32dasm and
disassemble the file...
Now click on the
"Strn REF" button and search for some
strings that can make
your life better
:)
You must find "REGISTERED!"
string, if not found it now!
When you click on
it you'll see one address at the bottom of the window....note that address!
Now, save disassembly
text file and look at the code at address that you note.
You'll see this...
:00401538
7606
jbe 00401540
:0040153A
81E9FFFFFF7F
sub ecx, 7FFFFFFF
*
Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401538(C)
|
:00401540
890D70974000
mov dword ptr [00409770], ecx
:00401546
390D88974000
cmp dword ptr [00409788], ecx
:0040154C
7563
jne 004015B1(1)
:0040154E
8D44240C
lea eax, dword ptr [esp+0C]
*
Possible StringData Ref from Data Obj ->"REGISTERED!"
===>> Here
'good code' starts
|
:00401552
686C844000
push 0040846C
:00401557
50
push eax
...
...
*
Reference To: USER32.EnableWindow, Ord:00ABh
===>>
Enable 'Get done listed' button
|
:00401587
8B3554B24000
mov esi, dword ptr [0040B254]
:0040158D
FFD6
call esi
...
...
:004015AF
FFD6
call esi
===>>
The end of the code
*
Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040154C(C)
|
:004015B1
5F
pop edi(1)
:004015B2
5E
pop esi
:004015B3
5B
pop ebx
:004015B4
83C410
add esp, 00000010
:004015B7
C3
ret
You can see that
conditional jump(1)
just
before good code take us to the end of the code!
JNE means -- Jump
if NOT equal!...so what must be equal???
Look at the line
above....Program compare something here!...so these two values must be
same to register
the program!....probably one of these values has something with correct
serial!
So let's see what
can those numbers be...
First, type into
textboxes any random values.
Here is, for example,
what I type: Bjanes
ReFleXZ '99
998899
For serial number
I always use "998899" 'coz it's easy to remember hex value
of the same number.
Hex value of "998899"
is "F3DF3". So remember this number.
Press "CTRL-D"
to open Sice. Let's now set breakpoint at 401546....first we must enter
to the programs code.
So type "bpx
GetDlgItemTextA". Now press "Check" button. You're
now back in Sice. Press "F11" to return to
the programs code.
You can now delete breakpoint at GetDlgItemTextA so type "bc *".
Now we must set breakpoint
at 401546 where
program compares these two values; now, type "bpx 401546".
Press "CTRL-D" again.
Now, you land exactly
on the comparation routine!
...cmp
dword ptr [00409788], ecx...
Now, type "D
409788" to see what program compares here. Hmm...you'll see(if
you enter "998899" for
the code) in the
data window(hex value of chars) "F3..3D..0F"! First, notice
that all values stored in memory
are in the reverse
form. So, that value is actually "0F3DF3"!
Hmm....I saw that
number somewhere :)....yes, that's hex value of serial that I entered("998899")!
So if program here
compares 'fake' serial with some number and after that is good/bad guy
jump, this
second number must
be hex value of our correct serial!...Now, look at the ecx
register and write down
this second number.
In my case ecx contains "276DFDD". Disable all breakpoints
with "bd *" and leave Sice("CTRL-D")
.
Now, open CConvert
and convert that second number to decimal. Copy the result to the clipboard
and go to
the crackme again!...now
past the number to the "Code" texbox and press "Check" button.
BTW You can also
convert hex to decimal in the Sice typeing "? hex_value"!
You'll the get the result that looks like this: ....hex_value.....decimal_value.....'ASCII'...
So that decimal value is your correct serial!
Hmm....where I stop
explaining? :)....Yeah, you press the "Check" button and
look this...
You type in the
correct serial and the program is registred!
Great job!....but
try to change the date and register the program with same serial!...you
can't??
Hehe...Let's see
why...
2.
Making a KeyGen and understanding the code
If you're really
lazy, like me(I was writting this essay two weeks:), that don't even read
this part. You have your correct code and
that's all what you need.
But if you want
to learn something new(and you really can do that on this crackme), go
for a drink something and then come back :)
So....where to start?
Load the crackme
and type whatever you want into textboxes; Press "CTRL-D"
and set breakpoint at GetDlgItemTextA(if you really
don't know..."bpx
GetDlgItemTextA"). Now press the "Check" button.
Sice breaks. Press "F11" once to return to the programs
code. You can now disable
breakpoint("bd *").
BTW We use the GetDlgItemTextA
breakpoint to break Sice just when the program is reading your input from
the textboxes.
You'll now
see this part of code...
:00401400
68E8030000 push 000003E8
:00401405
A374974000 mov dword ptr [00409774], eax
:0040140A
51
push ecx
*
Reference To: USER32.GetDlgItemTextA, Ord:00EDh
|
:0040140B
FF1558B24000 Call dword ptr [0040B258]
;Here
program reads text from first
textbox('Name') and returns lenght to the EAX
:00401411
A3E8974000 mov dword ptr [004097E8], eax ;Here
program saves the lenght of a
<=
string=You land here!
:00401416
E885FFFFFF call 004013A0
;FIX THE LENGHT-- If the lenght is greater
then
30 then use only first 30 chars for calculation
:0040141B
8B0DE8974000 mov ecx, dword ptr [004097E8]
;Move
fixed lenght to the ECX
:00401421
8935EC974000 mov dword ptr [004097EC], esi
;Save
ESI("1") to the memory
Here first part of
calculation starts.
ESI is used as a
counter (loop this routine 'lenght of name' times). When the ESI is same
as ECX then exit the routine...
:00401427
3BCE cmp ecx,
esi
;Is
ESI same(or greater) as ECX??
:00401429
764A jbe 00401475
;If
yes, the jump to the end of the routine
:0040142B
8B15F0974000 mov edx, dword ptr [004097F0]
;EDX
= Another counter; Get it from memory("1")
:00401431
8B1D70974000 mov ebx, dword ptr [00409770]
;EBX
= Nothing yet
Now look carefuly
at this part of code. Here program generates one number from user name
that you entered.
*
Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401473(C)
|
:00401437
0FBEBAF7974000 movsx edi, byte ptr [edx+004097F7](1)
;EDI
= Next(first) char of user name
:0040143E
0FBE8257704000 movsx eax, byte ptr [edx+00407057]
;EAX
= One char from memory
:00401445
0FAFF8 imul edi,
eax
;Multiply
these two chars; EDI = EDI * EAX
:00401448
0FBE861F704000 movsx eax, byte ptr [esi+0040701F]
;EAX
= Another one char from memory
:0040144F
0FAFF8 imul edi,
eax
;Multiply
result with EAX; EDI = EDI * EAX
:00401452
0FAFFA imul edi,
edx
;Again,
multiply result with counter; EDI = EDI * EDX
:00401455
42
inc edx
;Incrase
counter; EDX = EDX + 1
:00401456
03DF
add ebx, edi
;Add
final result to the EBX; EBX = EBX + EDI
:00401458
46
inc esi
;Incrase
another counter; ESI = ESI + 1
:00401459
893D74974000 mov dword ptr [00409774], edi
;Save
sub-result(result from this loop)
:0040145F
8915F0974000 mov dword ptr [004097F0], edx
;Save
counter
:00401465
891D70974000 mov dword ptr [00409770], ebx
;Save
final result;Sum of all
results(from all loops)
:0040146B :0040146B
8935EC974000 mov dword ptr [004097EC], esi
;Save
second counter
:00401471
3BF1
cmp esi, ecx
;Is
'counter' >= 'lenght of name'??
:00401473
72C2
jb 00401437
;If
yes then goto end; If not then loop this again(1)
*
Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401429(C)
|
:00401475
5F
pop edi
;This
is the end of the routine
:00401476
5E
pop esi
:00401477
5B
pop ebx
:00401478
C3
ret
;Back
to main routine
This was the first
part of a calculation routine which final result is saved to memory at
409770. This number is really important 'coz
it's part of our correct serial!
Let's now explain
some things.
You probably don't
understand what chars does program take at 40143E and 401448.
Program takes first char, from string at memory address 407057.
Second char program takes from another string at 40701F.
String at
407057 = " fQObVwNOankJ5skqJvae3Ae5jdoETu5n02J6Ez85430PNSDAPjDrYgFaze9VDRjq"
|<== This will be String1
String
at 40701F = "?Etn5Pnc5AXi1DFlkYqnujsXNmvHdbcrqOoT8aaV5DkaymMRkPkoQ."
|<== This will be String2
First time program
takes first char from both strings. Every next time next char from string
was taken!
So what program
does here?
1. Get the lenght
of user name
2. Get next(first)
from user name
3. Get next(first)
char from String1
4. Multiply their
hex values
5. Get next(first)
char from String2
6. Multiply result(from
previous multiplying) with hex value of char
7. Multiply result
with a counter (sub_result)
8. Final_result
= Final_result + sub_result
9. Incrase all
counters
10. If NOT 'counter'
= 'lenght_of_user_name' then loop this again; jump to the 2nd line
Hope you now understand
this calculation better. So we can go to the another part.
Press "F10"
key until you get on: ....00401478
C3 ret....Now, press F10 ones
more.
You're now in the
main code of calculation.
You see this piece
of code....
:004019E4
C7057097400000000000 mov dword ptr [00409770], 00000000
:004019EE
8B74240C
mov esi, dword ptr [esp+0C]
:004019F2
56
push esi
:004019F3
E8E8F9FFFF
call 004013E0
;This
is calculation sub-routine for user name(we
just exit from here)
:004019F8
83C404
add esp, 00000004 ;'Fix'
the stack <== You land here
:004019FB
56
push esi
:004019FC
E87FFAFFFF
call 00401480
;This
is second calc sub-routine, it calculates
number from a group
I'm NOT going to
explain this second sub-routine 'coz it's exactly same as first one, where
program calculates number from user
name. Only difference is, that program here calculates number from group,
not user name.
There is only one
line important inside that calculation routine at 4019FC....
4019FC ...........................
..............calc
routine.......
.............................................
00401507
add dword ptr [00409770], edi
.............................................
As you can remember
at 409770 is stored result from first calc routine. In EDI is stored
result from second routine.
Here program adds
second result to first result and sum is saved back at 409770!...This
number is very important
'coz it's first
part of our correct serial. Now we need the second part.
Let's now analyze
the rest of main routine...
:00401A01
83C404
add esp, 00000004
;'Fix'
the stack again
:00401A04
A1E8974000
mov eax, dword ptr [004097E8] ;Hmmm....moves
lenght of name into EAX
:00401A09
83F803
cmp eax, 00000003
;Is
the lenght is less than 3?
:00401A0C
7307
jnb 00401A15
;If
yes, you're 'bad guy'!...If not then jump(2)
:00401A0E
33C0
xor eax, eax
;EAX
= 0; 'Bad guy'
:00401A10
5F
pop edi
:00401A11
5E
pop esi
:00401A12
C21000
ret 0010
;Exit
the routine :(
Look this part of
code carefuly 'coz it's very important...
*
Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401A0C(C)
|
:00401A15
0FAFC0
imul eax, eax(2)
;EAX
= EAX * EAX; EAX = lenght_of_name
* lenght_of_name
:00401A18
6A0A
push 0000000A
;Parameter
for GetDlgItemTextA
:00401A1A
A374974000
mov dword ptr [00409774], eax ;Save
EAX to the 409774!
:00401A1F
A1AC974000
mov eax, dword ptr [004097AC] ;Get
one number from the memory and
save it to the EAX!
:00401A24
6890974000
push 00409790
;Parameter
for GetDlgItemTextA
:00401A29
0FAF0574974000 imul
eax, dword ptr [00409774] ;Multiply
EAX with result of
multiplication at 401A15!
:00401A30
68EA030000
push 000003EA
;Parameter
for GetDlgItemTextA
:00401A35
A37C974000
mov dword ptr [0040977C], eax ;Save
the result to the memory!
:00401A3A
56
push esi
;Parameter
for GetDlgItemTextA
Now, we also have
second number for creating our correct serial. But how the program make
this second number?
1. Result1
= lenght_of_name * lenght_of_name
2. Result2
= number_taken_from_memory * Result1
So, the Result2
is final result of this calculation. But, what's the number that program
takes from memory at 401A1F?
I didn't see anywhere
that program saves or changes this number or that memory location.
I also put into
textboxes another informations and the number was same! So I thought that
number in memory is CONSTANT value!
I also made KeyGen with that number as a constant. But next day after I
publish my KeyGen I
received Email telling
me that KeyGen doesn't work! I test
it day before and it works perfectly! But another day it doesn't
work! So I go to
see where's the bug! And I found that
number that I though it was constant CHANGED!! So I put
breakpoint on memory
access to see where does program change
it!..."bpm 4097AC". I press "Check" button
and
Sice doesn't break!
So where's the clue?...Number is changed, but
program doesn't change it?...So I restart the program (breakpoint is still
active), and look this.....Sice BREAKS!! So,
this number is changed on the start of a program and
after that program
stays same!
Here is the code
where program changes that number...
:004015C3
53
push ebx
:004015C4
56
push esi
:004015C5
57
push edi
:004015C6
68D0974000
push 004097D0
;Where
to save the time
*
Reference To: KERNEL32.GetLocalTime, Ord:00E2h
<==
Hmmm....Get time :)
|
:004015CB
FF15C0B14000
Call dword ptr [0040B1C0]
;Call
GetLocalTime
:004015D1
33C0
xor eax, eax
;EAX
= 0
:004015D3
66A1D2974000
mov ax, word ptr [004097D2]
;Get
the ordinal number of
current
mounth!
:004015D9
0FBE88BF704000 movsx
ecx, byte ptr [eax+004070BF] ;Get
one char from memory
(explained
later) /ECX\
:004015E0
33C0
xor eax, eax
;EAX
= 0
:004015E2
890D74974000
mov dword ptr [00409774], ecx
;Save
ECX to the memory
:004015E8
C744240C30000000 mov [esp+0C],
00000030
;Nothing...
:004015F0
C744241003000000 mov [esp+10],
00000003
;...Important
:004015F8
66A1D6974000
mov ax, word ptr [004097D6]
;Get
current date!
:004015FE
33F6
xor esi, esi
;ESI
= 0
:00401600
89742418
mov dword ptr [esp+18], esi
;Clear
the...
:00401604
8974241C
mov dword ptr [esp+1C], esi
;...stack
:00401608
C744241420174000 mov [esp+14],
00401720
;Also...
:00401610
8B7C245C
mov edi, dword ptr [esp+5C]
;...Nothing...
:00401614
6A66
push 00000066
;...Important
:00401616
897C2424
mov dword ptr [esp+24], edi
;Still...
:0040161A
57
push edi
;...Nothing
:0040161B
0FBE809F704000 movsx
eax, byte ptr [eax+0040709F] ;Get
another char from memory
(explained
later) /EAX\
:00401622
0FAFC1
imul eax, ecx
;Multiply
these two chars
:00401625
A37C974000
mov dword ptr [0040977C], eax
;Save
result to the memory
:0040162A
A3AC974000
mov dword ptr [004097AC], eax
;Save
result to the memory
<==
Sice breaks here!
Let's analyze the
code...
There are also two
strings from where program takes those two chars. First char is taken at
4015D9 from string at 4070BF, and
second char is taken at 40161B from string at 40709F.
Let's see these two strings...
String at
4070BF = " 9803D2F7404E"
<== This will be String1
String at
40709F = " F3A4BF3B0503FB8BCB4F49803D5C740"
<== This will be String2
You can see that
first string has 12 characters, so this string is used for mounth. Second
string has 31 characters, so this one is
used for date!
Let's now explain
the calculation...
1. Get the
current month
2. Get the
char from String1 which is on the 'month' place
--- Example:
If now is a second mounth, program will take second char from String1....that's
"8"
If now is a eleventh mounth, program will take eleventh char from String1....that's
"4"
3. Get the
current date
4. Get the
char from String2 witch is on the 'date' place (same as for mounth, only
different String)
5. Multiply
these two chars
6. Save result
to the memory
Hope you understand
this part of code. Let's now back to the 'real' programs code...
*
Reference To: USER32.GetDlgItemTextA, Ord:00EDh
|
:00401A3B
FF1558B24000
Call dword ptr [0040B258] ;Get
the serial that you entered
:00401A41
6890974000
push 00409790
;Save
the location of serial
:00401A46
E8250F0000
call 00402970
;Convert
the serial to the hex!...result
is
located in EAX!
:00401A4B
83C404
add esp, 00000004
;'Fix'
the stack
:00401A4E
8B0DA8974000
mov ecx, dword ptr [004097A8]
:00401A54
A388974000
mov dword ptr [00409788], eax ;Save
hex value of serial into
the
memory
:00401A59
51
push ecx
:00401A5A
56
push esi
:00401A5B
E830F8FFFF
call 00401290
;Here
is a call to the comparation routine
..... ..... ..... ..... .....
..... ..... ..... ..... .....
.... nothing important after
this line ....
..... ..... ..... ..... .....
..... ..... ..... ..... .....
As you can see,
here program reads serial from the textbox and then converst it to the
hex.
Program then calls
comparation routine at 401A5B, so let's see what's inside that call...
*
Referenced by a CALL at Address:
|:00401A5B
|
:00401290
A19C974000
mov eax, dword ptr [0040979C] ;EAX
= lenght of group
:00401295
8B0DE8974000
mov ecx, dword ptr [004097E8] ;ECX
= lenght of name
:0040129B
8B542408
mov edx, dword ptr [esp+08]
:0040129F
A374974000
mov dword ptr [00409774], eax ;Save
the lenght of gruop
:004012A4
8B442404
mov eax, dword ptr [esp+04] ;EAX = Number
generated from system date
:004012A8
52
push edx
:004012A9
50
push eax
:004012AA
890D7C974000
mov dword ptr [0040977C], ecx ;Save
the lenght of name
:004012B0
C705A497400000000000 mov dword ptr [004097A4], 00000000
:004012BA
E861020000
call 00401520
;Call to a real comparation
:004012BF
83C408
add esp, 00000008
:004012C2
C3
ret
You already saw what's
inside the call at 4012BA, but let's step inside again...
*
Referenced by a CALL at Address:
|:004012BA
|
:00401520
83EC10
sub esp, 00000010
;'Fix' the stack
:00401523
8B0D70974000
mov ecx, dword ptr [00409770] ;ECX =
number generated from group
and
user name
:00401529
030DAC974000
add ecx, dword ptr [004097AC];ECX =
ECX + Number generated from date
:0040152F
53
push ebx
:00401530
56
push esi
:00401531
81F9FFFFFF7F
cmp ecx, 7FFFFFFF
;Is result greater then 7FFFFFFF??
:00401537
57
push edi
:00401538
7606
jbe 00401540
;If yes then execute next line
:0040153A
81E9FFFFFF7F
sub ecx, 7FFFFFFF
;ECX = ECX - 7FFFFFFF
*
Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401538(C)
|
:00401540
890D70974000
mov dword ptr [00409770], ecx ;Save
the ECX to the memory
:00401546
390D88974000
cmp dword ptr [00409788], ecx ;Compare
ECX with fake serial
:0040154C
7563
jne 004015B1
;If they aren't equal then jump to the
end
:0040154E
8D44240C
lea eax, dword ptr [esp+0C]
*
Possible StringData Ref from Data Obj ->"REGISTERED!"
|
:00401552
686C844000
push 0040846C
:00401557
50
push eax
So, what you can
see from this essay? At the beginning, when program is loading, it generates
one number based on system date. Program
generates one number from user name. Then generates another one from group,
After that program adds that two numbers and
saves sum. Then check is lenght of name greater than 3. If not, then you're
'bad'! Lenght of group can be less that 3. You
also mustn't put name of group into the textbox. Then program adds name
generated from date to the sum of first two numbers.
That's our corerct
serial in hex. You only must convert it to decimal and you have correct
serial!