Copylok by Kilby

published by +Tsehp

Updated 010311

This update is due to some confusion I have caused inserting the IT
This was pointed out by BlackBird.

Although I included the following line:

Why not 761f8, well look at the section information, particularly at the Virtual & Raw Offset fields, on the .data and .rsrc sections.

I now realise this was much too obscure, and did not help anybody in the slightest.

Additionally there is a note at the end of the file which points out an error of judgement which I made regarding the placement of the IT.

---------------------


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.

Here is what the section table of the file is like;

VSize	=	Virtual Size
PSize	=	Physical Size
RVA	=	Relative Virtual Address
POffset	=	Physical Offset

Name	VSize		Psize		RVA		POffset
.text	00009000	00009000	00001000	00001000
.rdata	00002000	00001014	0000a000	0000a000
.data	00003000	00001224	0000c000	0000c000
.rsrc	00002000	00000808	0000f000	0000e000
.icd1	00056000	00064e30	00011000	0000f000
.idata	00001000	00000a10	00076000	00074000
.icd2	00008000	00007338	00077000	00075000
.idata	00001000	00001000	0007f000	0007d000

The VSize is the amount allocated for that section in RAM
The PSize is the amount allocated for that section on disk.

Usually they contain the same value.

In the case of this file they are different in some places.

.rdata the size in RAM is 2000 and on disc it is 1014, however the disk file is only padded to the nearest 1000 byte value, which is 2000.

This means that the base address of the next section (.rsrc) is different on disk.

The base address in RAM is F000 while on disk it is E000

This will affect where we place the contents of the Import Table

Normally we 'fix the dump' so as the VOffset and the POffset are the same, unfortunitly this appears to cause errors on this particular target.


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 40A000 - 400000), highlight 164 bytes and choose Replace with file.

As we have chosen 761F8 (IN RAM) as the position for the IT we must look at the section information for .idata,

Name	VSize		Psize		RVA		POffset
.idata	00001000	00000a10	00076000	00074000
.icd2	00008000	00007338	00077000	00075000
.idata	00001000	00001000	0007f000	0007d000

We can see that the 761f8 is in the section .idata, and that .idata will be at offset 76000 in RAM, but at 74000 on disk.

This gives us a difference of 2000 bytes, so rather than pasting the new IT at file offset 761f8 we have to subtract 2000 from that file offset, arriving at 741F8


ATTENTION: read the note at the end of this file

Starting at 741F8 highlight 1964 bytes (for that is the length of SSIT), and chose Replace with file, and choose SSIT.BIN


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.



Note:
------------------------------------------

I will be honest and say that I would have done things differently now, with the benefit of hindsight.

Although the first .idata contained the original import data and the last three sections (four actually) you should not really dump data across sections.

I should have deleted at least the last 3 sections (.idata, .icd2, .idata) then created a new section containing the IT created by revirgin.

But this was the first rebuild I had done and it was 03:00 and I was sick of looking at Sudden Strike.


------------------------------------------





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;

All in pGC
iNX


Regards,

Kilby...