Microzine14

From DaphneWiki

Revision as of 07:10, 11 February 2011 by Matt (Talk | contribs)
Jump to: navigation, search

Contents

Microzine #14 (Funhouse Caper)

This floppy disk sat in my garage for probably years and before that it sat in my mom's basement. It survived several winters amazingly enough and I just recently re-assembled the family Apple //gs and tried booting it up. To my amazement, it still worked!

The Goals

  1. To be able to enjoy this software in a modern emulator instead of needing to have a real Apple ][ to play it.
  2. To preserve the copy protection so that it can be studied in the future if anyone is curious.

The second goal has not been fully reached (yet).

Recovering the data

Most of the hard work was done by Phil Pattengale in Computist magazine, issue 27, pages 12 and 13. (see http://victa.jamtronix.com/display/page/958 )

The disk has non-standard formatting but can still be read properly as long as a copy program ignores non-fatal errors. To copy the disk,

  1. Boot a DOS 3.3 system master disk
  2. type the following at the BASIC prompt:
    1. "call -151"
    2. "b942: 18 60"
    3. "q"
    4. "run copya"
  3. copy the microzine disk to a duplicate

We now have a standard DOS 3.3 disk with all the sectors recovered from the copy protected disk. But during the boot sequence of the disk, it will do a check against the raw nibbles on one of the tracks (I believe track 1) and if it doesn't find what it is looking for, it will know it's a copy. How does it know? Because the nibbles it checks for are not part of the sector data, and only the sector data is copied by programs like COPYA.

Transferring the image to an emulator

This is mostly beyond the scope of this article, but what I usually do is use shrinkit to compress the 5.25" disk image to an .SHK file. I then use ProTERM to upload the file (using zmodem) to a modern PC using a null modem cable and a term program such as hyperterminal (for windows) or minicom (for linux). Once the .SHK file is on the modern PC, you can use nulib or ciderpress to extract it to a disk image and then run it inside KEGS or AppleWin or whatever.

The Copy Protection Routine

A really handy way to examine the copy protection routine is to use KEGS' debugger. This is a much more powerful technique for seeing what's really going on than trying to do it on a real Apple // where you can't set breakpoints easily.

  • The copy protection routine starts with a JSR to $BB00, so boot up KEGS, hit Shift-F6 to break into the debugger, and type "bb00B", then "G" to resume exeuction. Then boot the disk image ("PR#6" or whatever). Your breakpoint will get a few false positive "hits" but you know that you're in the right place when the program counter (PC) is near BB00 (bb02 for me).
  • type "bb00L" in the KEGS debugger and check out what's going on.
00/bb00: a0 00          LDY     #$00
00/bb02: b9 00 bb       LDA     $bb00,Y
00/bb05: 99 00 02       STA     $0200,Y
00/bb08: 88             DEY
00/bb09: d0 f7          BNE     $bb02
00/bb0b: 60             RTS

This routine copies the code from $BB00-BBFF to $200 and then returns. So the actual copy protection routine is at $bb0c-$bbff (or so) but is designed to run at $20C-$2FF.

Since we have the luxury of being able to set breakpoints, we know that $20C must eventually get called in order to run the copy protection routine, so set a breakpoint.

  • First, get rid of the BB00 breakpoint because it will waste your time if you don't. Type "bb00D" to get rid of it.
  • Then type "20cB", then "g" to resume execution.

You will break at 2CF due to KEGS breaking you after the instruction you wanted has executed (I'd love to change that).

  • Type "20CL" to check out the copy protection routine. You can hit L a few times to see all of it.
  • The copy protection routine will branch to $293 if the copy protection check has failed. You will see a lot of those branches here.
00/020c: 20 cf 02       JSR     $02cf
00/020f: a9 0a          LDA     #$0a
00/0211: 85 2a          STA     $2a

$2a contains how many failures the copy protection routine will tolerate before assuming that the disk is indeed a copy. In this case, it will try 10 times to look for the special signature on the disk that will not be on the copy.

00/0213: ae e9 b7       LDX     $b7e9
00/0216: bd 89 c0       LDA     $c089,X
00/0219: bd 8e c0       LDA     $c08e,X

Reading from $c089,X turns on the drive motor. Reading from $c08e,X puts us in input mode.

00/021c: a9 c7          LDA     #$c7
00/021e: 85 48          STA     $48
00/0220: a9 02          LDA     #$02
00/0222: 85 49          STA     $49
00/0224: a9 80          LDA     #$80
00/0226: 85 29          STA     $29
00/0228: c6 29          DEC     $29
00/022a: f0 67          BEQ     $0293
00/022c: 20 44 b9       JSR     $b944
00/022f: b0 62          BCS     $0293
00/0231: a5 2d          LDA     $2d
00/0233: c9 0d          CMP     #$0d
00/0235: d0 f1          BNE     $0228

I haven't dug into what the above routine does. It probably calls some RWTS routine to get the disk positioned on the right track.

00/0237: a0 00          LDY     #$00
00/0239: bd 8c c0       LDA     $c08c,X
00/023c: 10 fb          BPL     $0239
00/023e: 88             DEY
00/023f: f0 52          BEQ     $0293
00/0241: c9 d5          CMP     #$d5
00/0243: d0 f4          BNE     $0239

This routine reads 256 bytes off the disk (to get it in sync probably) and then starts looking for #$D5 which is a standard sector header.

00/0245: a0 00          LDY     #$00
00/0247: bd 8c c0       LDA     $c08c,X
00/024a: 10 fb          BPL     $0247
00/024c: 88             DEY
00/024d: f0 44          BEQ     $0293
00/024f: c9 e7          CMP     #$e7
00/0251: d0 f4          BNE     $0247
00/0253: bd 8c c0       LDA     $c08c,X
00/0256: 10 fb          BPL     $0253
00/0258: c9 e7          CMP     #$e7
00/025a: d0 37          BNE     $0293
00/025c: bd 8c c0       LDA     $c08c,X
00/025f: 10 fb          BPL     $025c
00/0261: c9 e7          CMP     #$e7
00/0263: d0 2e          BNE     $0293

This section seems to look for three consecutive nibbles all with a value of #$E7. This presumably has one of the signatures on the copy protected disk that will not be present on a copied disk. It probably will be found right before a bunch of sync bytes, which is legitimate because it's valid for arbitrary bytes (garbage) to show up before sync bytes (see "Beneath Apple DOS", page 3-7 for more info). I intend to check the original disk and find out exactly where it is stored.

00/0265: bd 8d c0       LDA     $c08d,X
00/0268: a0 10          LDY     #$10
00/026a: 24 06          BIT     $06
00/026c: bd 8c c0       LDA     $c08c,X
00/026f: 10 fb          BPL     $026c
00/0271: 88             DEY
00/0272: f0 1f          BEQ     $0293
00/0274: c9 ee          CMP     #$ee
00/0276: d0 f4          BNE     $026c

A specific amount of time after the consecutive #$E7's, there will be an #$EE on the copy protected disk that it expects to find.

00/0278: a0 07          LDY     #$07
00/027a: bd 8c c0       LDA     $c08c,X
00/027d: 10 fb          BPL     $027a
00/027f: d1 48          CMP     ($48),Y
00/0281: d0 10          BNE     $0293
00/0283: 88             DEY
00/0284: 10 f4          BPL     $027a

Now it looks for specific nibble pattern, 7 bytes long, matching what we see at $2C7.

00/0286: a9 80          LDA     #$80
00/0288: 8d 4e 9e       STA     $9e4e
00/028b: a9 a1          LDA     #$a1
00/028d: 8d 4f 9e       STA     $9e4f
00/0290: 4c 4d 9e       JMP     $9e4d

If we get to $286, it means the copy protection routine has passed.

00/0293: c6 2a          DEC     $2a
00/0295: d0 8d          BNE     $0224
00/0297: a2 22          LDX     #$22
00/0299: bd a4 02       LDA     $02a4,X
00/029c: 95 00          STA     $00,X
00/029e: ca             DEX
00/029f: 10 f8          BPL     $0299
00/02a1: 4c 00 00       JMP     $0000

$293 is where the program goes if the copy protection has failed. The copy protection routine will try again a number of times to succeed ($293 and $295). Memory location $2a contains how many attempts we have left before failing. If we do fail, it will zero out $2a4-$2c6, and then jump to $0000 which causes a random crash. I really can't see how $2a4-$2c6 is used but the copy protection engineer obviously thought it contained some serious clues that he didn't want anyone to know about. :)

02a4: a0 01 84 4f 88 84 4e 98 91 4e 88 d0    ..O..N..N.P
02b0: fb e6 4f f0 0c a5 4f c9 c0 d0 f1 a9 d0 85 4f d0   {fOp.%OI@Pq)P.OP
02c0: eb ad 81 c0 6c fc ff   k-.@l|.

Not sure what $2a4-$2c6 is for but it doesn't seem to get executed. It does, however, seem to be important because it gets cleared right before the copy protection routine causes a crash. Interesting.

02c7: fc ee ee fc e7 ee fc e7   |nn|gn|g

$2c7-$2ce is a nibble pattern on the copy protected disk that will not show up on a copied disk. (see $21C and $27F)

00/02cf: ad e9 b7       LDA     $b7e9
00/02d2: 4a             LSR
00/02d3: 4a             LSR
00/02d4: 4a             LSR
00/02d5: 4a             LSR
00/02d6: 09 c0          ORA     #$c0
00/02d8: 8d f3 03       STA     $03f3
00/02db: 49 a5          EOR     #$a5
00/02dd: 8d f4 03       STA     $03f4
00/02e0: a9 00          LDA     #$00
00/02e2: 8d f2 03       STA     $03f2
00/02e5: 8d f4 b7       STA     $b7f4
00/02e8: a9 11          LDA     #$11
00/02ea: 8d ec b7       STA     $b7ec
00/02ed: a9 b7          LDA     #$b7
00/02ef: a0 e8          LDY     #$e8
00/02f1: 4c b5 b7       JMP     $b7b5

$2cf sets up an IOB and calls RWTS. The IOB is stored at $b7e8 (standard place). To learn about IOB and RWTS, see the book "Beneath Apple DOS" which is how I learned about it.

The IOB looks like this:

b7e8: 01 60 01 ff 11 09 fb b7   .`....{7
b7f0: 00 9c 00 01 00 00 fe 60 01   ......~`.

b7e8: table type (must be 1) b7e9: slot * 16 (0x60) b7ea: drive number (1 in this case) b7eb: volume number expected (0xFF in this case) b7ec: track number (0x11 in this case) b7ed: sector number (9 in this case) b7ee: pointer to device characteristics table (DCT), $b7fb in this case b7f0: pointer to buffer to read/write ($9c00 in this case) b7f2: unused b7f3: byte count for partial sector ($1 in this case) b7f4: command code (0 in this case, which means SEEK) b7f5-b7f8 are return codes (from what I can tell)

So in other words, this function performs a seek to track $11, sector $9. (unless I've read it wrong)

The Crack

The crack is to make this copy protection routine end up at $286 instead of $293. There are a few ways this can be done:

  • Change all branches that go to $293 so they go to $286 instead.
  • Change location $293 to branch to $286 which feels cleaner.
  • Change location $293 to jump to $286.

Phil Pattengale decided to go with the third option and code in a jump. Just to show that I can actually contribute something beyond what Phil has done (ok let's face it, he did 90% of the work hehe), I'm going to present the second option instead.

Change 293 from c6 2a d0 8d to a9 00 10 ef which changes the "DEC $2A, BNE $224" to "LDA #$0, BPL $286" which is a long-winded way of saying ALWAYS branch to $286, but the BRA instruction isn't available on the 6502 last I recall so I gotta use something that I know is there (BPL).

With a sector editor

Search for "c6 2a d0". I found mine on track $0, sector $5, byte $93 which is the same place Phil found it on his disk (although he was not doing Microzine #14).

Personal tools