This protection originated on the Atari ST (or at least Wikipedia says it did). I first saw it on a game called Castle Master. The game itself was a piece of junk, but the protection had my attention from the beginning.
When you ran the protected game, the first thing that got executed was the Copylock loader which was attached to the game's .exe at the publisher. This loader would check some sectors on the floppy, and if everything was kosher, it would unencrypt the game, and jump to it to start it.
Now a quick tour through the X86 architecture in order to facilitate greater understanding of the subject matter to follow. The X86 has provisions in the hardware to assist in the debugging of programs. We are specifically referring to the interrupt (or INT) vectors. In DOS, these vectors pointed to a function that would handle things like a Divide by 0 error, a key press on the keyboard, or a timer tick happening. There were also a couple for use by debuggers. There were the single step interrupt (INT 1), and the general debug interrupt (INT 3). The way they worked is like this. When you were using a debugger, and wanted to break at a specific address, the debugger would replace the op-code at that address with the INT 3 call (which was a $CC op-code). Then, when the processor got to that address, it would call the function pointed to by the INT 3 vector in memory. (Which pointed to a function in the debugger which showed you the registers, the current instruction, and the like). Then, let's say that you want to single step some lines to watch the values change. When this was happening, the debugger would set the trace bit in the flags register. This caused the processor to execute 1 instruction, and then call the function pointed to by the INT 1 vector in memory. So, if you think about it, this allows you to execute a line, and see the results. Pretty handy if you ask me!
Now we'll talk about how Copylock used these to it's advantage. When you first starting executing the loader, it would setup the INT 1 & INT 3 vectors to point to a couple of it's internal functions, and then call INT 3 out of the blue. A closer examination of this code showed that it was there to enable/disable the decryption. (More on why this was necessary later). This set the trace flag as mentioned above, and then returned. Upon returning, 1 "normal" instruction would be executed, and then INT 1 would be called by the processor. (As it thinks a debugger is running). The interesting thing here is what the INT1 handler did! It would re-encrypt the last instruction, and unencrypt the NEXT instruction. Just in time for it to be executed. So, this meant that if you broke in with you handy debugger (Soft-Ice, or Turbo Debugger), then all you got to see was 1 instruction in the clear! As I said above, they used INT 3 to turn the encryption on and off. This was because being a DOS app, they had to call BIOS and DOS functions to get anything done, and since THEY weren't encrypted, they had to turn off the INT 1 handler before calling any function not belonging to them. Now, just in case you think that you could do all this INT handling manually, and look at the instructions, there were a bunch of loops, and useless crap added to make it painfully time consuming to do so. (And, with them owning both debugger INTs, you couldn't single step, or set a breakpoint either!).
Now a little about the disk protection itself:
The way the "verification track" was laid out on the key disk was as 1 long track. A normal track is broken up into sectors, and has a sector header, sector trailer on it. This track was written as 1 long track with no sector breaks in it. One of my big regrets was that I never tried the CopyIIPC option board on it to see if it would make a working copy. At the time nothing else would. The genius of this protection was that they encrypted the game with checksums from the sectors on the protected track. So, during the "verification phase", they would read a sector, and checksum it. They would then use this checksum as one of the keys for the decryption of the game. Thus, if the reads are wrong, the game won't work. Also, if you zipped up the game, and sent it to someone, they couldn't unpack it, as they didn't have a working copy, and thus didn't have the correct decryption keys.
This little piece of heaven took me a month to get worked out. Here's how I did it.
I wrote a loader that used the timer tick interrupt (INT 8, which triggered 18.xx times a second), to watch for the INT 1, INT 3 vectors to change. When they did, it grabbed the INT 3 address, and saved it off, and changed those it to point to me. When they turned the decryption ON, or OFF, I incremented an internal counter. After they did it X times, (I think it was 13), they were DONE with the protection check, and were ready to process the relocation table, and jump to the game's entry point. This is where the REAL weakness was exposed. When you, as the person at the game company, ran the Copylock installer, it read the header from the .exe file, and stored it inside the resulting executable. Furthermore, they left the relocation table in it's original form. So, when the last INT 3 happened, I opened an output file, wrote out the exe header (which he was nice enough to leave for me), followed by the relocation table, followed by the actual game code. Then, it closed the file, and returned from the interrupt. This was a nice "Smack in the face", as when I was done saving out the unprotected copy, the game ran as though "I was never there". :-)
OK, in case you are wondering how I found out about the code inside that nasty encryption, here's how: I loaded up the game using good old DOS debug, and modified the INT 1 handler so that when it wrote out the unencrypted bytes to the normal place, it also saved me a copy in HIGH memory away from anything that it might need to use. Then, when the game exited I just went into high memory, and saved it out, and ran it through a disassembler so that I could print it out, and chew on it.
This is the one protection that I'm the proudest of not only finding a way around, but actually making a tool that I gave to our European people to use on originals when they got them from the shops. (And it worked everytime!) The first use was on some crappy Soccer Manager game. They called me from the U.K. to have me talk them through using it. After that, they were off to the races!
But that's NOT where the story ends. A few months after my tool was distributed to our folks, we started seeing games that weren't wrapped by the Copylock wrapper, but instead had a function call in them that did all the nasty stuff mentioned above, and just returned a 1 or a 0 to state whether it had worked. As I noted in the NFO file for S.T.U.N. Runner, "Copylock in a call, the stupidest idea EVER!". It was only a shadow of it's old self, as you could just jump over the call, and the compare, and right into the game, and you were done.
Well, that's it for tonight. Hope you enjoyed this, and if you have any questions, feel free to ask!