|
|
I'm back :P I hope you will like this tutorial since it's my first one for
a game. This tutorial is not as usual, this time i'm gonna teach you how to
crack a game - Age of Empires. This one is not as easy as my "old" tutorials
and therefor I included quite a lot of code. I also put a lot of comments,
to make it easier for you. (newbie cough cough) :) For all of you to
understand this I will advice you to read it several times and understand
all of it.
TOOLS:
SoftIce 3.24
HIEW 5.92
Please do not ask for instructions as to where to download these programs, please search for them yourselves.
This game has, as you probably already know, a cd-check when it's launched.
This we don't like and we're therefore going to find a way around it.
Normally we would only use W32Dasm when cracking this kind of protection,
but not in this case. Actually it's just as easy in SoftIce (at least I think
so). Of course you could try using W32Dasm and if you decide to do this I
will give you a small hint. When programming it Microsoft did not use a normal
text-box, they used graphic. So now you know ;)
Ok..let's start. If you're a newbie go through this step by step.
1. Before using SoftICE you'll have to modify the WINICE.DAT
file. Just delete the semi-colons before the EXP instructions, where USER32,
GDI32, KERNEL32
are mentioned. Now SoftICE will load these export functions.
2. Launch SoftICE and open EMPIRES.EXE
3. Load it. (Modules->load) and ignore
irrelevant error messages.
4. Soft-ICE pops up. Set a breakpoint
on the function GetDriveTypeA (returns eax=5 if CDROM,eax=3 if Fixed HDD) by
typing : bpx getdrivetypea [ENTER]
The 'a' on the end of the function means, that we are talking about a 32-Bit
application. Getdrivetype would work for a 16-Bit App.
5. Hit [CONTROL-D] to go back to the
game. If SoftICE pops up again - ignore it. Just push [CONTROL-D] until you
get to the main menu.
6. So now you are at the main menu -
hit the 'Single Player' Button.
7. If you've done everything right -
Soft-ICE pops up at the desired function. Hit [F11].
8. Now you're at the place, where GetDriveTypeA
has been called from !. Look around a bit.([CONTROL-(],[CONTROL-(])
9. Here is what you should see :
:004D65F6
|
FF1554267000
|
Call [Kernel32!GetDriveTypeA] -> calls the function
|
:004D65FC
|
83F805
|
cmp eax, 00000005 -> If CDROM - drive resent
|
:004D65FF
|
7404
|
je 004D6605 -> jump to ...
|
:004D6601
|
33C0
|
xor eax, eax -> if not : eax=0 ..
|
:004D6603
|
EB53
|
jmp 004D6658 -> ... and return.
|
:004D6605
|
8D84241C010000
|
lea eax, dword ptr [esp+0000011C] -> Volume-check ...
|
:004D660C
|
6800010000
|
push 00000100
|
:004D6611
|
8D4C241C
|
lea ecx, dword ptr [esp+1C]
|
:004D6615
|
50
|
push eax
|
:004D6616
|
8D54241C
|
lea edx, dword ptr [esp+1C]
|
:004D661A
|
51
|
push ecx
|
:004D661B
|
8D44241C
|
lea eax, dword ptr [esp+1C]
|
:004D661F
|
52
|
push edx
|
:004D6620
|
8D4C242C
|
lea ecx, dword ptr [esp+2C]
|
:004D6624
|
50
|
push eax
|
:004D6625
|
6800010000
|
push 00000100
|
:004D662A
|
51
|
push ecx
|
:004D662B
|
57
|
push edi
|
:004D662C
|
FF1558267000
|
Call [Kernel32!GetVolumeInformationA] -> Volume-check
|
:004D6632
|
85C0
|
test eax, eax -> is a CD-ROM in the drive ?
|
:004D6634
|
B800000000
|
mov eax, 00000000 -> eax=0
|
:004D6639
|
741D
|
je 004D6658 -> no ! return with eax=0 !
|
:004D663B
|
8B460C
|
mov eax, dword ptr [esi+0C]
|
:004D663E
|
8D4C241C
|
lea ecx, dword ptr [esp+1C] -> ecx = CD-ROM label
|
:004D6642
|
05FD020000
|
add eax, 000002FD -> eax = Label (AOE)
|
:004D6647
|
50
|
push eax
|
:004D6648
|
51
|
push ecx
|
:004D6649
|
E802D60500
|
call 00533C50 -> very interesting call ...
|
:004D664E
|
83C408
|
add esp, 00000008
|
:004D6651
|
83F801
|
cmp eax, 00000001 -> if eax=1 ... set register flags
|
:004D6654
|
1BC0
|
sbb eax, eax -> eax=eax-(eax+c)
|
:004D6656
|
F7D8
|
neg eax -> 'invert' eax
|
:004D6658
|
5D
|
pop ebp
|
:004D6659
|
5F
|
pop edi
|
:004D665A
|
5E
|
pop esi
|
:004D665B
|
5B
|
pop ebx
|
:004D665C
|
81C40C020000
|
add esp, 0000020C
|
:004D6662
|
C20400
|
ret 0004 -> ... and return
|
You can step through the code (execute it line by line) by pressing [F10]
and trace into a call (going into a function) by pressing [F8].You can view
the 'contents' of a variable by typing d [variable] (e.g. d eax). You can
also set variables, by typing r [variable]=[value] (e.g.r eax=1). You can
also toggle register-flags, by typing r fl [register] (e.g.r fl z -> inverts
result of a compare (cmp)).
As you can see, the program checks if you have a CD-ROM drive and returns
the drive letter if so.
Then it retrieves various info about the inserted CD-ROM (if it is inserted).
If an error occurs it sets eax=0 and returns.
All right. What now? Let's take a quick look into the mysterious call (only
at the end of it) :
:00533C50
|
55
|
push ebp
|
:00533C51
|
8BEC
|
mov ebp, esp
|
:00533C53
|
57
|
push edi
|
:00533C54
|
56
|
push esi
|
:00533C55
|
53
|
push ebx
|
:00533C56
|
8B750C
|
mov esi, dword ptr [ebp+0C]
|
:00533C59
|
8B7D08
|
mov edi, dword ptr [ebp+08]
|
:00533C5C
|
8D05D08E5600
|
lea eax, dword ptr [00568ED0]
|
:00533C62
|
83780800
|
cmp dword ptr [eax+08], 00000000
|
:00533C66
|
753B
|
jne 00533CA3
|
:00533C68
|
B0FF
|
mov al, FF
|
:00533C6A
...
|
8BC0
|
mov eax, eax
|
:00533CC6
|
E845070000
|
call 00534410
|
:00533CCB
|
83C404
|
add esp, 00000004
|
:00533CCE
|
38C3
|
cmp bl, al
|
:00533CD0
|
74DA
|
je 00533CAC
|
:00533CD2
|
1BC0
|
sbb eax, eax
|
:00533CD4
|
83D8FF
|
sbb eax, FFFFFFFF
|
:00533CD7
|
5B
|
pop ebx
|
:00533CD8
|
5E
|
pop esi
|
:00533CD9
|
5F
|
pop edi
|
:00533CDA
|
C9
|
leave
|
:00533CDB
|
C3
|
ret
|
The above function is rather complicated. You wouldn't want to know what
it does... ;-)
Anyway, if you go through it several times, changing some variables and flags,
you'll arrive at the conclusion, that the value of eax (when the call returns)
can be either 0, FFFFFFFF or 1.(If you inserted the wrong CD - it is 1 or
FFFFFFFF).
We can assume at this point, that the value 0 means, that we have inserted
the right CD ... let's try it out !
When you are debugging and you are at the end of the function (e.g. 533CDA)
type: r eax=0 [ENTER] and press [CONTROL-D] in order to let it go on.It works,
you've made it !
Well, if you're not so sure about this business (WHY did it work ???) go
on reading ... if you are sure or just don't care - jump to the cracking section.
Okay, so you want to be a cracker...Lets assume, you haven't changed anything
(and have inserted the wrong CD), then the call will return eax=1.Let's look
again at the code after the call returns :
:004D664E
|
83C408
|
add
|
esp, 00000008
|
:004D6651
|
83F801
|
cmp
|
eax, 00000001 -> if eax=1 . set Z ;or C if eax=0
|
:004D6654
|
1BC0
|
sbb
|
eax, eax -> eax=1-1 => eax=0
|
:004D6656
|
F7D8
|
neg
|
eax -> 'invert' eax => eax=0
|
:004D6658
|
5D
|
pop
|
ebp
|
:004D6659
|
5F
|
pop
|
edi
|
:004D665A
|
5E
|
pop
|
esi
|
:004D665B
|
5B
|
pop
|
ebx
|
:004D665C
|
81C40C020000
|
add
|
esp, 0000020C
|
:004D6662
|
C20400
|
ret
|
0004 -> ... and return
|
So the whole function returns an eax=0 if the CD is wrong...Hmmm.... Usually,
when looking at simple protections, you'll see that when an eax=0 means WRONG
then an eax=1 will mean ALL RIGHT.
Let's see, what happens if the call returns with an eax=0 ....
:004D6651 83F801
|
cmp eax, 00000001
|
-> if eax=1 ... (set C=1)
|
:004D6654 1BC0
|
sbb eax, eax
|
-> eax=eax-(eax+c) => eax=0-1=FFFFFFFF
|
:004D6656 F7D8
|
neg eax
|
-> 'invert' eax => eax=1
|
Looks like this is another simple protection-scheme ... Now you have basically
two ways to crack this game:
You can set eax=1 in the function or you can set eax=0 in the call. It is
possible, that the game might make a check during the gameplay with this call
but with another function.
Considering this, it would be best to insert a 'mov eax=0' instruction into
the call, somewhere at the end (or beginning, followed by a 'return'). But
this game won't make a check ! (You can try it out ...) So you can just as
well insert a 'mov eax=1' instruction in the function, somewhere at the end
(or beginning, followed by a 'return'). It is up to you. I've chosen the first
possibility.
I'll try to explain how to do it:
1. The easiest way is to write down a long sequence of the hexadecimal-code,
in order to locate this fragment in the exe-file.(e.g. 8D05D08E560083780800
-this is taken from 533C5C to 533C62) You could just as well read the
local offset from SoftICE - it can be a bit confusing though.
- Launch hiew (HIEW EMPIRES.EXE), press [F4] and then [F2], in
order to view the text in hex-mode.
- Search for the string, you've written down.([F7])
- Now switch to decode-mode ([F4],[F3]) - you're right there
- shortly after the beginning of the call.
- Go to the 'mov esi,[ebp][0000C]' instruction (it will be overwritten,
but that doesn't matter)
- Press [F3] followed by [TAB]
- Now you can type the command 'mov eax,0h' - you surely remember
why, don't you. The hex-code of this command should look like : B800000000
Now it should jump to the end of the call - type ‚jmp xxxxxx' , where xxxx
represents the end of the call.The adress will vary so you have to look
for it yourself.In our listing, it is at 533CD7.Look at this code and look
for it in hiew. Then you'll have the needed address...
- Press [ESC] to end assembly, [F9] to save it, quit HIEW and
launch the game...
- It works !!!!
I hope I made myself a bit clear and that you understand just 80% of it.
This crack could without a doubt be done more elegantly, but I'll leave it
up to you to find the easiest way.
All for now....
|
|