One of the things I was curious about when I started this project was the Questron copy protection. I was able to make a working copy, but what was it about the copying program that made it work where a simple file copy failed? As I’ve been digging into the Questron disks, I’m starting to find the answers.
I suspect that Questron uses a variety of copy protection tricks, but the first one I found is in the file “ME”, which is a BASIC file which handles most of the menu system that’s shown when you start the game. There’s actually a lot of very obfuscated spaghetti code in this file, and I haven’t figured all of it out yet (I’m actually trying to trace the process that happens when the game loads a save game file, but I haven’t had a lot of luck with it yet).
Near the beginning of the file there’s a line that really stands out from the surrounding code:
55 open 15,8,15: open 5,8,5,"#": print#15,"u1:";5;0;33;5: input#15,z: if z = 0 then sys 64738
I’ve added some spaces so it’s more legible – deleting white space is actually an optimization strategy for this BASIC interpreter. Anyway, this line does some really interesting things with the 1541 disk drive’s DOS. I’ll do my best to explain this step by step.
First, there are the two “open” commands. We’re opening two files handles talking to device 8, which is the first floppy disk attached to the computer. The disk drive supports multiple “channels” of communication that can be open simultaneously. Channel 15 is the “command channel” – it’s used for sending commands to the disk drive and reading the drive’s status messages. Channel 5 is used to send data between the computer and the disk drive.
The next bit, “print#15,”u1:”;5;0;33;5″, is sending a message on the command channel. It’s telling the drive to read a particular block of data on the disk, and send that data to the C64 over channel 5. The interesting thing is that we’re not specifying a file name to read; we’re actually telling the drive to read a particular physical location on the disk. Specifically, the program is asking for sector 5 of track 33.
Next, you’d expect to see a block of code to read the sector data over file handle 5. But instead, we’ve got “input#15,z” – it’s reading a single integer from the command channel and saving it in the variable z. When the C64 reads from the 1541’s command channel, it’s requesting the drive’s error status.
Finally, “if z = 0 then sys 64738”. It turns out that an error status of 0 means “OK”. Well that sounds good. Obviously we’re just being diligent and checking our return value before going on to our reading routine at… wait… 64738?
So here’s the interesting part. Memory location 64738 isn’t part of the Questron software. It’s part of the C64 KERNAL. Specifically, it’s the KERNAL routine that performs a system reset. Yes, if the read operation is successful, we reset the computer. That’s not suspicious at all.
It turns out that track 33, sector 5, is broken – in fact, it’s been deliberately sabotaged. Each sector on disk has a short header, which records the track and sector numbers, along with a checksum. The checksum is the XOR of all 256 data bytes in the sector. It’s not a very good technique, but it’ll detect any single-bit error in the data. For track 33, sector 5, on side 1 of Questron, the data checksum is deliberately wrong. So if you’re using an actual Questron disk, when it runs line 55, it’ll read an error status of 23 (checksum error in data block) instead of 0, and it won’t jump to 64738 and reset the computer.
Apparently, having an error like this deliberately manufactured onto the disk was a popular early form of copy protection. Of course, this led to an arms race, and a generation of “nybble copiers” came along that were able to read that data, not care about the fact that it didn’t make sense, and write it down to the fresh copy of the disk.
I said before that Questron is using multiple checks. Another one I’ve found evidence for is built into track 35. In addition to the checksums and track and sector numbers, each sector header contains a two-character “format id”. This value should be the same for every sector on the same disk – it’s set when the disk is formatted. On side 1 of Questron, the format id is “2D” – except for the sectors on track 35, where it suddenly changes to “D2”. I haven’t found any code yet that checks for this difference, but I’ll bet it’s in there somewhere.