Copylok
by kilby
Published
by +Tsehp feb 2001
Work on
this protection system was slow, although the actual work on it only took about
five evenings (and two early mornings).
My five
evenings where spread out between mid December 2000 and mid Feb 2001, and
required me to learn about Dumping, PE file formats and IAT rebuilding.
This
research was the reason I victimised Crunch 2 by Bi Tarts .
There
isn't much if any information regarding Copylok, in the scene so heres what I
know.
This
information is taken from the only example of copylok I have which is Sudden
Strike (UK release)
Firstly
how do I recognise Copylok
Well
the CD has a visible ring on the data section, and the protected .exe file has
.icd sections.
This
accounts for why some 'crackers' claim that it is a version of Safedisc.
They
claim to use 128 bit encryption keys, it has been mentioned that once again the
TEA algorithm has been used (as in Safedisc.)
I only
found the old CreateFileA anti-softice code, though Duke (Hi there), says that
he has seen versions with better anti-softice code.)
The
wrapper decrypts itself in phases, and each phase is made up of many small
blocks (typically 0x64 to 0x72 bytes), and jumps all over memory like it has a
dose of crabs.
The CD
is easy to copy, despite what Panlok Ltd claim and I can't wait for them to
start using their uncopyable CD-Roms as a replacement for smart cards :)
You
can't run a straight dump the main .exe using pedump or icedump as the imports
have been screwed with.
Copylok
is becoming more common due to Take 2 Interactive using it, along with several
other European publishers, so it's time for an essay.
The
method I am going to use is a bit hack and slash, and requires an original (or
working clone) CD.
However
iNX offers the following information, for those without a suitable CD
--------------------
Anyway
I can tell you that the cd checks seems not very efficient because there is an
average of 10 sectors read and the bad one is always around the 7th or 8th
read.
If you start
sending back result error to aspi calls after the 7th, 6th read, the program
starts...
I would
guess they considered that a cd reader couldn't read some other sectors than
the effective bad one (maybe because the cd has got many many bad sctors interleaved
with good ones) and so they introduced some sort of tolerance.
--------------------
So as
Frank would say "Let's hit the fuckin road"
Tools
Used:
Softice (Our
old friend)
Icedump
Procdump
Revirgin (Our new friend)
Hex
Workshop
Sudden
Strike+CD
Pen
Paper
Sony
MZ-R55 playing Gomez.
Preparation:
In my
case I have to stop DBServer from running, along with the creative launcher
shit for my SB Live, so I don't get too many false breaks inder softice.
Method:
As I
couldn't be arsed to trace the whole damn thing we will make use of a hole in
Copyloks armour.
So what
kind soul will let us gain entry to the unwrapped .exe
Well
once again that kind individual is Microsoft, and in particular Visual C.
The
inital setup code of the wrapped file is Visual C, so let us assume that the
original file is also Visual C based.
Load
Icedump, this will hide us from the debugger checks.
Place a
breakpoint on GetVersion, then return to windoze.
Run
SuddenStrike.exe
Immeditely
sice breaks hit F11 and we see the following
:u 415d40 L 100
0167:00415D40 55 PUSH
EBP
; Entry
point of Executable
0167:00415D41 8BEC MOV
EBP,ESP
0167:00415D43 6AFF PUSH FF
0167:00415D45 68B0E74600 PUSH 0046E7B0
0167:00415D4A 684CB14100 PUSH 0041B14C
0167:00415D4F 64A100000000 MOV
EAX,FS:[00000000]
0167:00415D55 50 PUSH
EAX
0167:00415D56 64892500000000 MOV
FS:[00000000],ESP
0167:00415D5D 83C4A4 ADD
ESP,-5C
0167:00415D60 53 PUSH
EBX
0167:00415D61 56 PUSH
ESI
0167:00415D62 57 PUSH
EDI
0167:00415D63 8965E8 MOV
[EBP-18],ESP
0167:00415D66 FF15F8624700 CALL
[KERNEL32!GetVersion]
; The
call to GetVersion (Look at the address the call uses)
0167:00415D6C A3B4484700 MOV
[004748B4],EAX
; Where
we have ended up after F11
As we
can see typical Visual C setup code
We are
now in the .icd1 section of SuddenStrike
Hit F5
again to return to executing the code.
A
splash screen appears, and there is a few seconds pause.
Sice
breaks again, this time after hitting F11 we find that we are in WNASPI32,
(this dosn't matter to us as we are being lazy) so hit F5 again.
Another
pause and sice reappears hit F11 and we find the following;
0167:00402F8D FF1570A04000 CALL
[KERNEL32!GetVersion]
; Where
Get version was called from (Look at the address the call uses now)
0167:00402F93 33D2 XOR
EDX,EDX
If we
look back through this section of code we will see this;
:u
402f67 L 100
0167:00402F67 55
PUSH EBP
0167:00402F68 8BEC MOV
EBP,ESP
0167:00402F6A 6AFF PUSH FF
0167:00402F6C 6880A14000 PUSH 0040A180
0167:00402F71 68905B4000 PUSH 00405B90
0167:00402F76 64A100000000 MOV
EAX,FS:[00000000]
0167:00402F7C 50 PUSH
EAX
0167:00402F7D 64892500000000 MOV
FS:[00000000],ESP
0167:00402F84 83EC58 SUB
ESP,58
0167:00402F87 53 PUSH EBX
0167:00402F88 56 PUSH
ESI
0167:00402F89 57 PUSH
EDI
0167:00402F8A 8965E8 MOV
[EBP-18],ESP
0167:00402F8D FF1570A04000 CALL
[KERNEL32!GetVersion]
; Where
F11 placed us
0167:00402F93 33D2 XOR
EDX,EDX
More
Visual C setup code.
In
addition we are also in SuddenStrike.Text, this means that we are at the start
of the unwrapped file and we have found the OEP (Original Entry Point)
So we
dump the file, I prefer using icedump for this as we don't have to halt the exe
to dump it so;
/pedump
400000 2f67 f:\ssdumped.exe
The
2f67 is the RVA (Relative Virtual Address) of the programs entry point.
As we
can see the pointer to the import of GetVersion has moved from 004762F8 to
0004a070, this means that we are working with a new IAT
So lets
look at the IAT we know it lives around 0040A070
:d
40a070 l 20
0030:0040A070
1B 2F F9 BF E8 FF 42 00-4C 10 43 00 31 0E 43 00 ./....B.L.C.1.C.
0030:0040A080
CF 05 43 00 B3 02 43 00-83 F8 42 00 5C 1D 43 00 ..C...C...B.\.C.
Well
the address for GetVersion looks pretty normal BFF92F1B.
However
look at the following address at 40a074 it's pointing to 0042FFE8 which is a
strange address for a KERNEL32 call.
So lets
look at 0042FFE8
:u
42ffe8 l 10
0167:0042FFE8 A1E49CFCBF MOV
EAX,[BFFC9CE4]
0167:0042FFED FF742404 PUSH DWORD
PTR [ESP+04]
0167:0042FFF1 8B08 MOV
ECX,[EAX]
0167:0042FFF3
E90BD5B5BF JMP BFF8D503
So the
jmp at 0042FFF3 looks like it's jumping into the right area for a KERNEL32
import, so let's look at the code we are jumping to;
:u
bff8d4f8 l 20
KERNEL32!ExitProcess
0167:BFF8D4F8 A1E49CFCBF MOV
EAX,[BFFC9CE4]
0167:BFF8D4FD FF742404 PUSH DWORD
PTR [ESP+04]
0167:BFF8D501 8B08 MOV
ECX,[EAX]
0167:BFF8D503 80492220 OR BYTE
PTR [ECX+22],20
;
Address jumped to !
0167:BFF8D507 E8C3FCFFFF CALL BFF8D1CF
0167:BFF8D50C C20400 RET 0004
0167:BFF8D50F 8B442404 MOV
EAX,[ESP+04]
0167:BFF8D513 33D2 XOR
EDX,EDX
0167:BFF8D515 8B4854 MOV
ECX,[EAX+54]
As we
can see Copylok has;
1: Borrowed the first three instructions of
ExitProcess
2: Executed them locally
3: Jumped directly to the fourth instruction in
the 'REAL' routine
This is
known as redirection, and is used to make the reconstruction of the IAT more
difficult.
So what
can we do about this, well in times past it would have involved rebuilding the
real calls by hand, or writing a routine to do the job for us.
However
thanks to +Tshep we have a new friend which can do this for us, and that friend
is called ReVirgin.
For
using ReVirgin we need the start address and length of the IAT, although
revirgin can find this on normal programs and some protected apps (ASProtect
for example), we will hunt down the table just incase.
We know
that GetVersion sits around 40a070, so lets start hunting;
:d
40a000 l 170
0030:0040A000
E8 19 43 00 3C 13 43 00-E4 F2 42 00 00 00 00 00 ..C.<.C...B.....
0030:0040A010
4B E3 42 00 00 00 00 00-B0 01 42 00 00 00 00 00 K.B.......B.....
0030:0040A020
47 F8 42 00 91 00 42 00-20 1D 43 00 39 1B 43 00 G.B...B. .C.9.C.
0030:0040A030
34 19 43 00 88 12 43 00-A6 F7 42 00 30 F2 42 00 4.C...C...B.0.B.
0030:0040A040
3A E8 42 00 C8 E4 42 00-E3 E3 42 00 97 E2 42 00 :.B...B...B...B.
0030:0040A050
0C 00 42 00 FC 00 42 00-64 B0 46 00 BB 92 43 00 ..B...B.d.F...C.
0030:0040A060
C0 BC 46 00 E8 CD 42 00-18 2D 42 00 9F 00 43 00 ..F...B..-B...C.
0030:0040A070
1B 2F F9 BF E8 FF 42 00-4C 10 43 00 31 0E 43 00 ./....B.L.C.1.C.
0030:0040A080
CF 05 43 00 B3 02 43 00-83 F8 42 00 5C 1D 43 00 ..C...C...B.\.C.
0030:0040A090
75 1B 43 00 70 19 43 00-C4 12 43 00 6C F2 42 00 u.C.p.C...C.l.B.
0030:0040A0A0
76 E8 42 00 04 E5 42 00-D3 E2 42 00 38 01 42 00 v.B...B...B.8.B.
0030:0040A0B0
A0 B0 46 00 F7 92 43 00-FC BC 46 00 24 CE 42 00 ..F...C...F.$.B.
0030:0040A0C0
D8 BF FC BF 54 2D 42 00-DB 00 43 00 BF BF FC BF ....T-B...C.....
0030:0040A0D0
88 10 43 00 6D 0E 43 00-0B 06 43 00 EF 02 43 00 ..C.m.C...C...C.
0030:0040A0E0
BF F8 42 00 98 1D 43 00-17 C2 FC BF B1 1B 43 00 ..B...C.......C.
0030:0040A0F0
AC 19 43 00 00 13 43 00-A8 F2 42 00 B2 E8 42 00 ..C...C...B...B.
0030:0040A100
40 E5 42 00 0F E3 42 00-DF C2 FC BF 74 01 42 00 @.B...B.....t.B.
0030:0040A110
00 00 00 00 DC B0 46 00-91 55 F5 BF 33 93 43 00 ......F..U..3.C.
0030:0040A120 38 BD 46 00 60 CE 42 00-3D 57 F5 BF 90 2D
42 00 8.F.`.B.=W...-B.
0030:0040A130
17 01 43 00 C4 10 43 00-A9 0E 43 00 47 06 43 00 ..C...C...C.G.C.
0030:0040A140
2B 03 43 00 FB F8 42 00-8C 55 F5 BF 0D 58 F5 BF +.C...B..U...X..
0030:0040A150
D4 1D 43 00 ED 1B 43 00-00 00 00 00 EE E8 42 00 ..C...C.......B.
0030:0040A160
7C E5 42 00 00 00 00 00-00 00 00 00 00 00 00 40 |.B............@
If we
work backwards from 40a070 the data is consistant with an IAT down to 0040a000
The
data is also consistant up to 40a164, where we find the data terminated by ten
00 bytes
--------------------
This
isn't a lecture on IAT but here is some helpful information;
The IAT
data is in sections, each separated by 00 00 00 00
Each section
represents a set of imports from a .DLL
Therefore
if routines are being imported from KERNEL32, GDI32 and SHELL32
This
would result in an IAT with 3 sections each with 00 00 00 00 separating them,
the final import would be terminated with ten 00 bytes
--------------------
The IAT
base is 40a000 with a length of 164 bytes
The RVA
(Relative Virtual Address) is 40a000 - 400000 (the Image Base)
Lets
place SuddenStrike in a holding Pattern,
r
eip=402F67
A eip
jmp eip
Hit Esc
Hit F5
We are
now back in windoze, so start revirgin running;
Select
the task SuddenStrike, and look at the imports listed in the window on the
right hand side.
Hmmm no
redirections listed, so somebody is lying and it's not revirgin or me !
If you
look at the IAT Start RVA revirgin is showing us we can see that it's pointing
to the IAT used BEFORE the unwrapping took place.
Let us
enter the correct value into the fields;
IAT
Start RVA A000 (Address - Base Address)
IAT
Length 164
Hit the
IAT resolver button, and we see a lot more imports, most of which are marked as
redirected.
Now hit
the Resolve Again button, after a few seconds, you now get all the normal
addresses listed.
Hit
Save resolved, incase of crashes etc.
Now we
need to create the import table.
We need
to place this somewhere, looking at the original executable with procdump, the
original and now unused IAT looks fine so 761f8 was chosen.
I know
I should at this point kill the unused .sections and create a nice shiney new
one for the IT but it was 03:00 on Sunday morning and there was two beers still
left in the fridge.
So we
place 761F8 into the IT RVA field.
Remember
to write down the IT length (it was CC for me)
Hit IAT
Generator button.
You
will be prompted for filenames, give them sensible filenames, so you don't get
them mixed up, I used SSIAT and SSIT (not exactly easy to tell apart)
When
you have done this You may enter procdump (again), firstly kill the task
SuddenStrike.
Then
you choose Rebuild PE, on the file f:\ssdumped.exe.
Now
enter hex workshop (or your preferred hex editor), and paste the newly created
.bin files into the appropiate locations of ssdumped.exe
In the
case of SSIAT.BIN go to file offset a000 (remember 40A00 - 40000), highlight
164 bytes and choose Replace with file.
Starting
at 741F8 highlight1964 bytes (for that is the length of SSIT), and chose
Replace with file, and choose SSIT.BIN
Why not
761f8, well look at the section information, particularly at the Virtual &
Raw Offset fields, on the .data and .rsrc sections.
After
saving this change, choose PE Editor in procdump and open ssdumped.exe and go
into Directory and change the following fields:
Import
Table Length
000761F8 000000CC
Close
Procdump.
Double
click ssdumped.exe.
We
should now see a messagebox appearing stating
VStart
Error
Can't
load profile .\SudTest.ini
This
means that the file is working, simply copy ssdumped.exe into the suddenstrike
home directory.
I have
tested the file on 98 & 2K professional without any problems.
An
added advantage, is that if a full install was chosen, no CD is required in the
drive.
As I
mentioned earlier I should clean up the file so as the .icd1 & .icd2
sections are removed, and that the IT is in a tidy place (like a section of
it's own.)
With
the aid of revirgin the whole process is pretty smooth.
Thanks
to;
+Tsehp,
for revirgin and answering a couple of dumb questions
ArthaXerXes,
for the message board
R!sc,
for the essay on Settlers 3, supplied me with more IAT info than any other
source
Duke,
early copylok info
Hi to;
webmasta
of pGC
iNX
Regards,
Kilby...