Steinberg Protection

From Software Archive
Jump to navigation Jump to search

Steinberg Research used two different disk protection schemes on its C64 software from 1984 to 1986. Both are built into a small autostarting loader (usually the file fl0, on Multitrack lo1), and the main program is only started after the check has passed.

All Steinberg software supports the DATEL type MIDI cartridge. For testing in VICE enable it with -midi -miditype 2 (or in the settings: MIDI emulation, type DATEL/Siel/JMS).

Scheme Releases Disk feature Check
A: hidden track 37 Multitrack 2.1, SES DX7 Editor, Korg 8-Track Sequencer, WAVE DW6000 Editor, CASIO Cosmo Synthesizer Editor, Pro16 PLUS V2.0 Track 37 is a copy of track 34 (headers say track 34), but sector 11 holds 256 bytes of encrypted code Drive code moves the head from track 34 to track 37 without telling the DOS. A normal read of track 34 sector 11 then returns the hidden sector, which is decrypted and executed.
B: read errors on tracks 33-35 Track Star, Hohner Midi Sequencer, Korg Poly 800 II Editor, Pro16 2.4, Pro16 PLUS V2.4 Track 33: a single sector header, no usable data. Track 34: 17 headers without data blocks. Track 35: 19 sectors written at the speed zone 2 bit rate. One of three reads, chosen at random: 33/0 must give error 21, 34/0 error 22, 35/0 error 27
none MusicData Midi Sequencer Tracks 33-35 contain errors, but the program never reads beyond track 20 -

Scheme A: hidden track 37

Disk

  • Track 34 is formatted with 17 empty sectors.
  • Track 37 is a copy of track 34, including the headers that say "track 34" and the same disk ID. The only difference is sector 11, which contains 256 bytes of encrypted code (the key sector).
  • A D64 cannot hold this. A G64 or P64 must contain track 37.

Check

The loader runs in screen memory ($0400-$07FF) and decrypts itself in several stages.

  1. Pre-check. The loader reads sector 11 of tracks 16, 25 and 34 (U1 and B-P). If one of them starts with the bytes $20 $D9 (the start of the key sector), the loader crashes the machine on purpose. This detects copies that carry the key sector on a normal track, for example copies made by a copier that follows the headers (track 37 claims to be track 34), or a crack that puts the sector at 34/11. On the original, 16/11 is an ordinary file block and 25/11 and 34/11 are empty.
  2. Head trick. The loader writes 61 bytes of drive code to $0700 (single byte M-W commands) and starts it with M-E. The drive code sets the drive's "current track" ($22) to 0, so that the DOS does not seek on the next job. It then moves the head three tracks further, from track 34 to track 37.
  3. Read. The loader sends U1 2 0 34 11. Because the head is on track 37 and its headers say track 34, the DOS accepts the track and returns the key sector instead of the empty sector 11 of track 34. I0 puts the drive back into a normal state.
  4. Decrypt and run. The loader checks two bytes of the sector ($43 $C5), decrypts it by adding the bytes of the KERNAL ROM at $FE00 and jumps into it. The key sector code installs its own IRQ and STOP handlers and then decrypts the BASIC starter of the program at $0801 (see below) and runs it.

If the check fails

Warning: a failed check damages the disk. If the key sector bytes do not match, the loader sends N: to the drive (a short NEW without ID) and resets. This rewrites the BAM and the directory on track 18: the disk name is empty and all blocks are free. The file data on the other tracks stays, but the disk no longer shows any files.

In an emulator this happens to the attached image file. Never test scheme A software on an original disk or on the only copy of an image. Always work on a copy.

The pre-check (step 1) does not send N:; it only crashes the computer.

Key sector contents

The key sectors of all releases are identical except for one byte at offset 245. That byte is not encrypted. The key sector code uses it as the start offset of a key stream taken from KERNAL ROM page $F7xx and decrypts the program block from $0801 to the end of the loaded file with it. The result is the BASIC starter of the program (e.g. 10 SYS2304).

Release Byte 245 Decrypted block Starts with
Multitrack 2.1 $A0 $0801-$08EE 10 IF F=1 THEN 200
Korg 8-Track Sequencer $21 $0801-$09D0 10 SYS2304
CASIO Cosmo Synthesizer Editor $94 $0801-$0F80 10 SYS2304
WAVE DW6000 Editor $45 $0801-$0F80 10 SYS2304
Pro16 PLUS V2.0 $67 $0801-$0B30 10 SYS2304
SES DX7 Editor source 1 $D4 $0801-$4028 1 SYS2064
SES DX7 Editor source 2 $24 $0801-$4028 1 SYS2064

So every mastering got its own key. The two sources of SES DX7 Editor contain the same program version: after decryption the programs are identical and all other files are identical. They come from two different duplication runs with different keys.

The rest of the key sector is the same in all releases and ends with the plain text " B.JUROW ".

KERNAL ROM requirement

Because the KERNAL ROM is used as the key, the software only starts with a KERNAL whose bytes at $F700-$F7FF and $FE00-$FEF3 match. This is the case for KERNAL 901227-02 and 901227-03 (and the SX-64 KERNAL), but not for the first C64 KERNAL 901227-01. In VICE with KERNAL 901227-01, Multitrack does not start and ends on an empty screen with READY.

Emulation

G64 images that contain track 37 work in VICE (tested with VICE 3.10 on all scheme A images). A D64, or a G64 without track 37, fails and its directory is wiped (see above).

Scheme B: read errors on tracks 33-35

Disk

  • Track 33: a single header (sector 0) and no valid data block.
  • Track 34: 17 sector headers (sectors 0-16), but no data blocks.
  • Track 35: 19 sectors (sectors 0-18, data filled with $30), written at the speed zone 2 bit rate (as on tracks 18-24). The 1541 DOS always reads track 35 at the slower zone 0 rate.

Check

The loader is loaded over the stack page, $0200 and the KERNAL vectors. It decrypts the rest of its code and installs a CBM80 cartridge signature at $8000, so that a RESET wipes the loader.

The check is executed once per program start, without retry. The jiffy clock ($A2) selects one of three variants:

Variant Command Expected DOS error Reason on the original disk
0 U1 2 0 33 00 21 READ ERROR (no sync) Track 33 has only one header in a whole revolution
1 U1 2 0 34 00 22 READ ERROR (data block not found) Track 34 has headers but no data blocks
2 U1 2 0 35 00 27 READ ERROR (header checksum) The zone 2 data on track 35 is misread at the zone 0 clock

If the error code does not match, the loader wipes its own code and does not start the program. The disk is not changed.

The tables with the track number and the expected error code are self-modifying (they are incremented after the check). When reading them from memory after a check, subtract 1.

Behaviour on a real 1541

Variants 0 and 1 are deterministic. Variant 2 is not: error 27 is not written onto the disk. The headers on track 35 are fine, and the error comes from the drive reading them at the wrong bit rate.

How often variant 2 fails on a real drive could not be determined. It was simulated with a model of the 1541 read electronics and DOS, applied to the KryoFlux streams of all scheme B releases. The model includes the job code, sync timeouts and the full retry chain with head offsets, and returns exactly 21, 22 and 00 for tracks 33, 34 and the normal track 18. For track 35 the results contradict each other:

  • With the exact digital circuit of the 1541 (as emulated by VICE for P64 images, without analog noise), the dumps of Hohner Midi Sequencer and Korg Poly 800 II Editor give error 27 in 72-99% of the reads at nominal drive speed. The dumps of Track Star, Pro16 2.4 and Pro16 PLUS V2.4 read track 35 too well: the DOS reports 23 (data block checksum) or no error at all, so variant 2 would never pass, as in VICE with the P64.
  • An earlier model with more timing noise gave error 27 in 83-98% of the reads for all disks.
  • A drive speed difference of only 1% changes the result a lot (e.g. Korg Poly 800 II Editor side 0: error 27 in 0% of the reads at 1% slower disk rotation, 93% at nominal speed, 100% at 1% faster rotation).

Since the original disks were sold and used, a check that never passes on some of them is unlikely; the analog noise of a real drive is probably what makes the misread produce error 27. A test on real hardware is needed. Until then, the failure rate of variant 2 on a real drive is unknown.

Note: the KryoFlux streams of these disks were captured at 360 rpm. Normalise the timing to 300 rpm (200 ms per revolution) before analysing them.

Emulation

In VICE 3.10, variants 0 and 1 work with G64 and P64, but variant 2 fails with both:

  • G64: VICE ignores the speed zone of the track and reads track 35 without error (00).
  • P64: VICE mostly returns error 23.

So in VICE about one program start in three fails, whether the G64 or the P64 is used. In that case simply reset and load again.

Patching the G64

Note that the following change only makes the check work reliably in an emulator.

On track 35, invert the checksum byte of the header of sector 0 (header layout: $08, checksum, sector, track, ID2, ID1; new checksum = old checksum XOR $FF). Track length and all other data stay unchanged. The DOS then reports error 27 for 35/0 every time, and all three variants pass.

Patched G64s (file names ending in _patched_s0 / _patched_s1) are available on the pages of Track Star, Hohner Midi Sequencer, Korg Poly 800 II Editor, Pro16 and Pro16 PLUS V2.4. Each differs from the original dump in exactly two bytes. All three variants of the check were forced in VICE 3.10 on every patched image and all passed.

Pages that refer to this protection