It's not expected to be clear from this fragment alone (without all the subroutines), but what is going on here is a loop across tracks 1-8 inclusive. For each track, it is read fully and the length of the track is stored in a table at $3F71. Later, at PC $3CB6, these lengths are checked against a table located at $3D9B. The check is particularly interesting. For the copy protection to pass, a count is taken of each track length that falls within +-1 of the expectation, and this count must be 7 or 8. Immediately we see that this protection is not a precise technology. This is to be expected: discs are analog storage mediums underneath it all and there will be a bit of noise at the beginning or end of the track. From read-to-read, the same disc, drive and controller can and does see slight variations of track length. Looking at the load in beebjit, here are the encountered vs. expected lengths. (0x4A == 3122 bytes.)
My captured disc
3F71: 4A 4D 4B 4A 4B 4D 4D 4A
3D9B: 4A 4C 4B 4A 4B 4D 4C 4A
As can be seen, my disc reads almost exactly to expectations except track 2, which was 3125 bytes instead of the expected 3124. That's within the +-1 range so all 8 tracks pass the check (7 or more are required).
To spell it out, the protected loader expects the track length (in FM encoded bytes) for tracks 1-8 inclusive to be 3122, 3124, 3123, 3122, 3123, 3124, 3123, 3122. That's an incredible level of precision and accuracy of writing for 1985 technology. Each byte covers about 64us on a spinning disc, but disc drives of the era would often specify running RPM variation of "less than +-1.5%". At 300rpm, +-1.5% is +-3ms per rotation! In my experience, drives are much much better than that but still! How did 1985 technology cope??
One further note, on the WD1770 vs. Intel 8271 disc controllers. We've focused our analysis on the protection as seen by the WD1770. This disc also loads fine with an Intel 8271 controller. It uses a completely different code path to indirectly calculate track length in this case. It works because the padding bytes up to the end of the track are all 0x00 instead of the usual 0xFF. An "over-read" past the final sector on the track is used, and track length is detected by the change from reading 0x00 to 0xFF.
The genius twist
And then we realize the genius of this scheme. What if they didn't write the tracks with extreme precision, because the technology wasn't there? What if they just wrote the track any-old-how and then examined the result? I think this what they did:
- Format the disc. (That's it. Just format the disc normally and you've created a fiendishly protected disc.)
- Read the lengths of tracks 1-8 of the disc you just wrote.
- On a per-disc basis, generate, obfuscate and write the required table of expected track lengths into the loader on track 9.
What a trick! These discs are savagely hard to copy, even with dedicated hardware of the era. In fact, this trick is so clever that it requires us to revisit the fundamentals of disc protection. Here's our earlier statement:
- The disc is easy to read but hard to write.
But the Western Security Ltd. protection is quite easy to write -- you just format a disc. So perhaps we should say:
- The disc is easy to read but hard to recreate.
The Western Security protection is easy to write, easy to read but very hard to copy. One of the advantages of such a protection is that you could use a home computer to write it cheaply if the economics worked for you. That said, many discs I've seen appear to have duplicator markers typically found with expensive disc duplicating machines.
How can we support our theory? One way is to find a second disc of the same title, The Wizard's Revenge, and see if it differs at all. I did find one, and it does. My disc as per above:
Track 0 sectors 10 length 3124 fixups 1 CRC32 2E6B86E9
Track 1 sectors 10 length 3122 fixups 0 CRC32 37E30EC8
Track 2 sectors 10 length 3125 fixups 1 CRC32 F7BDE89B
Track 3 sectors 10 length 3123 fixups 0 CRC32 BB1E32C3
Track 4 sectors 10 length 3122 fixups 1 CRC32 2EC84AF1
Track 5 sectors 10 length 3123 fixups 0 CRC32 58FD732B
Track 6 sectors 10 length 3125 fixups 0 CRC32 43416F5A
Track 7 sectors 10 length 3125 fixups 1 CRC32 B3D8AB10
Track 8 sectors 10 length 3122 fixups 1 CRC32 8D02AC32
Track 9 sectors 10 length 3125 fixups 1 CRC32 75B1F57B
Track 10 sectors 10 length 3123 fixups 1 CRC32 D2B0A1EF
Additional captured disc:
Track 0 sectors 10 length 3126 fixups 1 CRC32 2E6B86E9
Track 1 sectors 10 length 3129 fixups 1 CRC32 37E30EC8
Track 2 sectors 10 length 3127 fixups 1 CRC32 F7BDE89B
Track 3 sectors 10 length 3127 fixups 1 CRC32 BB1E32C3
Track 4 sectors 10 length 3127 fixups 1 CRC32 2EC84AF1
Track 5 sectors 10 length 3129 fixups 1 CRC32 58FD732B
Track 6 sectors 10 length 3129 fixups 1 CRC32 43416F5A
Track 7 sectors 10 length 3128 fixups 1 CRC32 B3D8AB10
Track 8 sectors 10 length 3128 fixups 1 CRC32 8D02AC32
Track 9 sectors 10 length 3127 fixups 1 CRC32 1F5ABD44
Track 10 sectors 10 length 3128 fixups 0 CRC32 D2B0A1EF
As can be seen, the sector data (covered by the CRC32s) of the discs is the same except for track 9, which is where the table of expected track lengths resides. And the track lengths themselves are different. In both cases there's track length wobble and in the case of the latter discs, the tracks are all a little longer. This means that the drive that formatted the disc was running at a slightly slower RPM, enabling more bytes to be written in a single revolution.
And there's a second way to support the theory. I just asked Simon Hosler, who wrote a lot of Sherston Software games back in the 1980s, if he remembered anything. He recalls,
"Western Security – this wasn’t my system but I think it worked like this... It works because each disk drive runs at slightly different speeds. So when a drive creates a track on the disk – after it has added all of the headers and sectors etc, it has a bit of space to fill up, so adds a few extra ‘fill in’ bits that do nothing. The number of fill in bits will depend on the exact speed of the original formatting drive. So will be different if it was copied. I remember this system became a pain because disk drives were changing (?) all the time. [...] the system was called 'Fingerprinting'"
There remains the mystery of how a commercial duplicator could handle making these discs. One thing I've come across is references to a "Freeform" script [link], used in conjunction with Trace duplicators. I haven't been able to find a manual for this scripting language. There are some strange fragments in the memory of the loader after de-obfuscation; could it be related?
3F80: 54 70 00 41 44 44 20 20 20 20 20 72 00 4D 4F 56 Tp.ADD r.MOV
3F90: 45 54 4F 20 20 74 00 55 4E 49 54 20 20 20 20 75 ETO t.UNIT u
3FA0: 00 54 52 41 43 4B 20 20 20 76 00 53 45 43 54 4F .TRACK v.SECTO
3FB0: 52 20 20 77 00 54 4F 50 54 52 41 43 4B 78 00 55 R w.TOPTRACKx.U
Recreating Western Security style protected discs
I happen to have a couple of very different disc drives, so I thought I'd try them out. I formatted a disc in each drive, then had a look at the track lengths (in bytes) read back by a WD1772 disc controller in a real BBC Micro model B.
|Track 1 sectors 10 length 3137 fixups 1 CRC32 67F0950E|
Track 2 sectors 10 length 3138 fixups 1 CRC32 67F0950E
Track 3 sectors 10 length 3138 fixups 1 CRC32 67F0950E
Track 4 sectors 10 length 3139 fixups 1 CRC32 67F0950E
Track 5 sectors 10 length 3138 fixups 1 CRC32 67F0950E
Track 6 sectors 10 length 3140 fixups 1 CRC32 67F0950E
Track 7 sectors 10 length 3140 fixups 1 CRC32 67F0950E
Track 8 sectors 10 length 3139 fixups 1 CRC32 67F0950E
Track 9 sectors 10 length 3140 fixups 1 CRC32 67F0950E
Track 10 sectors 10 length 3140 fixups 1 CRC32 67F0950E
Track lengths from Mitsubishi MF504C:
Track 1 sectors 10 length 3119 fixups 1 CRC32 67F0950E
Track 2 sectors 10 length 3119 fixups 1 CRC32 67F0950E
Track 3 sectors 10 length 3118 fixups 0 CRC32 67F0950E
Track 4 sectors 10 length 3119 fixups 1 CRC32 67F0950E
Track 5 sectors 10 length 3119 fixups 1 CRC32 67F0950E
Track 6 sectors 10 length 3119 fixups 1 CRC32 67F0950E
Track 7 sectors 10 length 3119 fixups 1 CRC32 67F0950E
Track 8 sectors 10 length 3119 fixups 1 CRC32 67F0950E
Track 9 sectors 10 length 3118 fixups 1 CRC32 67F0950E
Track 10 sectors 10 length 3119 fixups 1 CRC32 67F0950E
These two drives definitely have unique fingerprints! The older drive has a bit more variance / wobble in individual track lengths. In fact, it seems to fit more bytes per track on the later sectors -- most of the latter tracks are length 3142. The older drive also generally fits 20 or so more bytes per track. This means it is spinning a little slower. By contrast, the newer drive runs like clockwork with minimal track-to-track variance. This might make it a little less suitable for generating varied per-disc fingerprints, but copying the disc on home computing hardware would still be tricky -- the machine used would need to have a similarly precise drive, and the drive would also need to be running at the exact same speed as the drive that made the original disc.
One last look at track lengths, this time from a Phantom Combat game disc, by Doctor Soft. This disc uses Western Security Ltd. protection:
|Track 1 sectors 10 length 3152 fixups 0 CRC32 67F0950E|
Track 2 sectors 10 length 3152 fixups 1 CRC32 67F0950E
Track 3 sectors 10 length 3152 fixups 0 CRC32 67F0950E
Track 4 sectors 10 length 3152 fixups 1 CRC32 67F0950E
Track 5 sectors 10 length 3151 fixups 0 CRC32 67F0950E
Track 6 sectors 10 length 3152 fixups 0 CRC32 67F0950E
Track 7 sectors 10 length 3150 fixups 0 CRC32 67F0950E
Track 8 sectors 10 length 3151 fixups 0 CRC32 67F0950E
This is disc protection hidden in plain sight. These 8 protected tracks are in fact 100% default format tracks (CRC32 67F0950E). There's the correct number of sectors and there are no deleted sectors. discbeast would show these tracks as plain green, aka. move on, nothing to see here!
There's a bit of track length wobble from track to track, but the tracks are also unusually long (the ideal is 3125 bytes). It is not clear whether the tracks were deliberately laid down a little long, but it definitely helps the disc protection. Any disc drive used to attempt to re-create these tracks is unlikely to be spinning at that speed because it is 0.8% slow and the disc drive motor technology is generally better than that. It's interesting to note that simple long track protection is just another variant in the Western Security scheme.
This disc was probably written from a BBC Micro itself, rather than a fancy duplication machine, as evidenced by the lack of a duplicator marker and by the fact the game data sectors show evidence of being written sector-at-a-time, not track-at-a-time. Who knows, maybe there was a deliberate attempt to find a slow drive; some older drives even have a twiddleable variable resistor to vary motor speed.
We've reviewed the most powerful BBC Micro model B disc protection scheme I found, across an audit of most of the copy protected discs released for the machine. It's clever in that you don't need specialized hardware to create the disc, or read the disc. But you're going to struggle to duplicate the disc.
My suspicion is that even modern hardware -- a Greaseweazle perhaps -- might struggle to hit byte-perfect precision, unless it is paired with a high quality disc drive that rotates very consistently (such as my Mitsubishi MF504C).
Talking again to Simon, as far as he's aware, this was the work of George Keeling, who I'd love to contact if only to tell him I think this work was awesome.
Subscribe To ScarybeastSecurity