--------------Microzine 8-------------- A 4am crack 2014-09-29 -------------------. updated 2015-09-06 |___________________ "Microzine" was an educational disk- based magazine published by Scholastic between 1983 and 1992. Issue no. 8 is a double-sided disk that features "Zazoo Come Home" and "Secret Journal." Side 1 is bootable; side 2 just says "put in side 1." COPYA copies both sides, but the copy does not work. It loads DOS, displays a prompt, runs a boot program, then reboots. Attempts to break (Ctrl-C, Ctrl-Reset) with the program in memory also reboot. In my experience, computers do not spontaneously reboot unless someone tells them to. Copy ][+ can't find the boot program, but my trusty Disk Fixer sector editor finds it on T01,S07. (This DOS must be a derivative of Pronto-DOS. Derivatives of DOS 3.3 are arranged differently on tracks 0-2, and the boot program is listed in T01,S09.) --v-- -------------- DISK EDIT -------------- TRACK $01/SECTOR $07/VOLUME $FE/BYTE$00 --------------------------------------- $00:>41<56 41 49 4C 41 42 4C AVAILABL $08: C5 46 49 4C 45 20 54 59 EFILE TY $10: 50 45 20 4D 49 53 4D 41 PE MISMA $18: 54 43 C8 50 52 4F 47 52 TCHPROGR $20: 41 4D 20 54 4F 4F 20 4C AM TOO L $28: 41 52 47 C5 4E 4F 54 20 ARGENOT $30: 44 49 52 45 43 54 20 43 DIRECT C $38: 4F 4D 4D 41 4E C4 8D 00 OMMAND.@ $40: 03 19 19 24 33 3E 4C 5B CYY$3>L[ $48: 64 6D 78 84 98 AA BB 2D $-8..*;- $50: 98 00 00 F0 FD 1B FD 03 .@@p}[}C $58: 03 D4 0D 28 8D 0D 00 00 CTM(.M@@ $60: 32 09 00 0B 01 20 FE 00 2I@KA ~@ $68: 01 00 06 00 01 00 00 00 A@F@A@@@ $70: 00 00 00 00 00 C8 C5 CC @@@@@HEL ^^^^^^^^ $78: CC CF A0 A0 A0 A0 A0 A0 LO ^^^^^ --------------------------------------- BUFFER 0/SLOT 6/DRIVE 1/MASK OFF/NORMAL --------------------------------------- COMMAND : --^-- [S6,D1=DOS 3.3 master disk] [S6,D2=non-working copy] ]PR#6 ... ]CATALOG,S6,D2 DISK VOLUME 254 B 012 A.SPC B 005 A1.SPC B 010 B.SPC B 015 C.SPC B 002 CLEAR.OBJ A 010 CREDITS B 014 D.SPC B 010 E.SPC B 006 ENHANCED.SF B 010 F.SPC B 011 G.SPC B 011 H.SPC A 005 HELLO B 008 I.SPC B 004 INIT.OBJ B 011 J.SPC B 010 K.SPC B 008 L.SPC B 012 LITTLE APEX A 007 LOAD PIC B 013 M.SPC A 003 MICROZINE SIDE 1 T 002 MZ.PARAMETER FILE B 011 MZINE1.PAK B 011 MZINE2.PAK B 011 N.SPC B 007 O.SPC B 014 PICDRAWH B 002 RUNPACK T 002 SIDE B 002 SOUND.OBJ B 002 ST.NOTES B 002 ST.TIME A 024 TABLE OF CONTENTS A 056 TWISTAPLOT T 126 TWISTAPLOT FILE T 000 TWISTAPLOT FILE INDEX A 021 UTILITIES B 014 UTILITIES.SPC B 002 W.SPC ]LOAD HELLO ]LIST 0 REM ]LIST (nothing) Annoying BASIC tricks are annoying. ]LOAD HELLO ]LIST 1, 1 ONERR GOTO 62000 2 REM COPYRIGHT 1984 SCHOLASTI C INC 3 PRINT CHR$ (4);"BLOAD W.SPC" 4 CALL 36864 10 IF PEEK (238) = 69 AND PEEK (239) = 88 THEN POKE 238,0: POKE 239,0: HGR : POKE - 1 6302,0: GOTO 47 11 HGR2 : HGR : TEXT : HOME :D$ = CHR$ (4) 15 POKE - 16301,0 20 PRINT D$"BLOAD RUNPACK,A3825 0" 21 PRINT D$"BLOADMZINE1.PAK" 22 CALL 38250 25 POKE - 16368,0 28 X$ = "4000<2000.3FFFM D823G" 29 FOR X = 1 TO 21: POKE 511 + X, ASC ( MID$ (X$,X,1)) + 12 8: NEXT : POKE 72,0: CALL - 144 31 PRINT D$"BLOAD MZINE2.PAK": CALL 38250 32 POKE - 16304,0: POKE - 163 02,0: POKE - 16299,0: POKE - 16297,0 34 IF PEEK ( - 16384) > 127 THEN POKE - 16300,0: GOTO 40 35 GOSUB 100: POKE - 16299,0: IF PEEK ( - 16384) > 127 THEN 40 36 GOSUB 100: POKE - 16300,0: IF PEEK ( - 16384) > 127 THEN 40 37 GOTO 35 40 POKE - 16300,0 45 HCOLOR= 0: FOR V = 165 TO 17 2: HPLOT 64,V TO 218,V: NEXT : HCOLOR= 3 47 POKE 103,1: POKE 104,64: POKE 16384,0 50 PRINT CHR$ (4)"RUNMICROZINE SIDE 1": END 100 FOR X = 1 TO 75 110 NEXT X 120 RETURN 62000 SL = PEEK (47081) / 16: POKE - 16368,0: IF SL < 1 OR SL > 7 THEN SL = 6 62010 PRINT CHR$ (12): PRINT CHR$ (4)"CLOSE": PRINT CHR$ (4)" PR#0": PRINT CHR$ (4)"IN#0" : PRINT CHR$ (4): TEXT : HOME 62020 VTAB 11: HTAB 4: PRINT "T HERE IS A PROBLEM WITH YOUR DISK": PRINT : HTAB 9: PRINT "PRESS ANY KEY TO RESTART": WAIT - 16384,128:A = 49152 + (25 6 * SL): CALL A 62021 GOTO 62021 OK, a couple of things jump out at me. There are several binary files loaded: - W.SPC (line 3) - RUNPACK (line 20) - MZINE1.PAK (line 21) - MZINE2.PAK (line 31) And several calls: - CALL 36864 (line 4) - CALL 38250 (line 22) - CALL -144 (line 29) - CALL 38250 (line 31) I have a hunch that the .PAK files are some sort of compressed data (possibly graphics), RUNPACK is the unpacker, and CALL 38250 is its entry point. Also, my non-working copy never got as far as clearing the hi-res graphics screen (lines 10, 11), I'm going to focus on the first binary file and the first CALL. ]BLOAD W.SPC ]CALL -151 *AA72.AA73 AA72- 00 90 *9000L ; get address of RWTS parameter table 9000- 20 E3 03 JSR $03E3 9003- 85 FB STA $FB 9005- 84 FA STY $FA ; hmm 9007- A9 C5 LDA #$C5 9009- 48 PHA ; copy RWTS parameters 900A- A9 00 LDA #$00 900C- 85 FC STA $FC 900E- A2 03 LDX #$03 9010- BC 35 90 LDY $9035,X 9013- 91 FA STA ($FA),Y 9015- CA DEX 9016- 10 F8 BPL $9010 9018- 8A TXA ; hmm 9019- 48 PHA The X register will be $FF after the loop, so this means we've pushed $C5FF to the stack. At this point, a bare RTS will "return" to $C5FF+1, i.e. reboot. 901A- 20 28 90 JSR $9028 *9028L ; call the RWTS (most likely just to ; move the drive head to the proper ; position for an impending nibble ; check) 9028- 20 E3 03 JSR $03E3 902B- 20 D9 03 JSR $03D9 902E- A9 00 LDA #$00 9030- 85 48 STA $48 ; if that fails, off to The Badlands 9032- B0 52 BCS $9086 9034- 60 RTS 9035- 08 04 0C 03 Caller was $901A, so resuming at $901D: *901DL 901D- A0 01 LDY #$01 901F- B1 FA LDA ($FA),Y 9021- AA TAX 9022- 20 39 90 JSR $9039 *9039L ; turning on the drive motor manually ; is always suspicious 9039- BD 89 C0 LDA $C089,X ; set up a Death Counter 903C- A9 56 LDA #$56 903E- 85 FD STA $FD 9040- A9 08 LDA #$08 9042- C6 FC DEC $FC 9044- D0 04 BNE $904A ; If the Death Counter hits zero, that ; would be bad. Which part of "Death ; Counter" sounded good to you, anyway? 9046- C6 FD DEC $FD 9048- F0 3C BEQ $9086 ; look for a specific nibble ($FB) 904A- BC 8C C0 LDY $C08C,X 904D- 10 FB BPL $904A 904F- C0 FB CPY #$FB 9051- D0 ED BNE $9040 9053- F0 00 BEQ $9055 ; kill a few cycles (not pointless, ; because the disk spins independently ; of the CPU, so all of these low-level ; disk reads are highly time-sensitive) 9055- EA NOP 9056- EA NOP ; read data latch (note: no BPL loop ; here, we're just reading it once) 9057- BC 8C C0 LDY $C08C,X ; do a compare to set or clear the ; carry bit (among other things, but ; it's the carry bit we care about) 905A- C0 08 CPY #$08 ; rotate the carry into the low bit of ; the accumulator 905C- 2A ROL ; if we just rolled a "1" bit out of ; the high bit of the accumulator, take ; this branch 905D- B0 0B BCS $906A ; next nibble needs to be $FF 905F- BC 8C C0 LDY $C08C,X 9062- 10 FB BPL $905F ; ...otherwise we start over 9064- C0 FF CPY #$FF 9066- D0 D8 BNE $9040 ; loop back to get next nibble 9068- F0 EB BEQ $9055 ; execution continues here (from $905D) ; get another nibble 906A- BC 8C C0 LDY $C08C,X 906D- 10 FB BPL $906A ; stash it in zero page 906F- 84 FC STY $FC ; if the accumulator is anything but ; %00001010, start over 9071- C9 0A CMP #$0A 9073- D0 CB BNE $9040 I got lost several times trying to follow this routine. I think the easiest way to explain it is to show the difference between the original disk and my non-working copy. Here is the original disk, as seen by the Copy II+ nibble editor. Nibbles with extra "0" bits (timing bits) after them are displayed in inverse on an original machine, marked here with a "+" after the nibble. --v-- COPY ][ PLUS BIT COPY PROGRAM 8.4 (C) 1982-9 CENTRAL POINT SOFTWARE, INC. --------------------------------------- TRACK: START: 1B1E LENGTH: 17C1 1C70: 9F EB E5 FC D7 D7 D7 EE VIEW 1C78: FA E6 E6 FF FE F2 ED FD 1C80: FF EF ED BA BB DD AF E6 1C88: B7 A7 CB B7 DE AA EB FF 1C90: FF FF FF FB+FF FF+FF FF+ 1C98: FD FF+FF+FF+FF+FF+FF+FF+ 1CA0: FF+FF+D5 AA 96 AA AB AA 1CA8: AA AA AB AA AA DE AA EB+ 1CB0: FF+FF+FF+FF+FF+FF D5 AA --------------------------------------- A TO ANALYZE DATA ESC TO QUIT ? FOR HELP SCREEN / CHANGE PARMS Q FOR NEXT TRACK SPACE TO RE-READ --^-- It's easy to understand why a simple sector copy failed. The sequence that this code is looking for starts at offset $1C93, which is between the end of one sector and the beginning of the next. (The data epilogue is at $1C8C; the next address prologue is at $1CA2.) Sector copiers discard everything between those delimiters and rebuild the track with a default pattern of sync bytes. That pattern doesn't include an $FB nibble, so the nibble check fails. But the EDD bit copy also failed. Here is the original disk's pattern at offset $1C93: - $FB + timing bit - $FF - $FF + timing bit - $FF - $FF + timing bit And here is what the same part of the track looks like on my failed EDD copy: --v-- COPY ][ PLUS BIT COPY PROGRAM 8.4 (C) 1982-9 CENTRAL POINT SOFTWARE, INC. --------------------------------------- TRACK: START: 1B1E LENGTH: 17C1 1C70: 9F EB E5 FC D7 D7 D7 EE VIEW 1C78: FA E6 E6 FF FE F2 ED FD 1C80: FF EF ED BA BB DD AF E6 1C88: B7 A7 CB B7 DE AA EB FF 1C90: FF FF FF FB+FF FF FF+FF+ 1C98: FD FF+FF+FF+FF+FF+FF+FF+ 1CA0: FF+FF+D5 AA 96 AA AB AA 1CA8: AA AA AB AA AA DE AA EB+ 1CB0: FF+FF+FF+FF+FF+FF D5 AA --------------------------------------- A TO ANALYZE DATA ESC TO QUIT ? FOR HELP SCREEN / CHANGE PARMS Q FOR NEXT TRACK SPACE TO RE-READ --^-- A subtle difference! The sequence at offset $1C93 now looks like this: - $FB + timing bit - $FF - $FF - $FF + timing bit - $FF + timing bit This code is looking for $FF bytes with an alternating pattern of timing bit, no timing bit, timing bit, no timing bit. It doesn't find that on the bit copy, so it knows it's not running on an original disk. Continuing the code listing... ; get a nibble 9075- BD 8C C0 LDA $C08C,X 9078- 10 FB BPL $9075 ; more bit twiddling 907A- 38 SEC 907B- 2A ROL ; AND it with the previously stashed ; nibble 907C- 25 FC AND $FC 907E- 49 FF EOR #$FF ; branch to failure path 9080- D0 04 BNE $9086 ; success path falls through to here -- ; turn off the drive motor and return ; to the caller 9082- DD 88 C0 CMP $C088,X 9085- 60 RTS ; failure path (a.k.a. "The Badlands", ; from which there is no return) 9086- A8 TAY 9087- DD 88 C0 CMP $C088,X ; manually pop the return address of ; the immediate caller (which leaves ; the manually pushed $C5FF address on ; the top of the stack to "return" to) 908A- 68 PLA 908B- 68 PLA ; destroy all trace of this program in ; memory 908C- 99 00 90 STA $9000,Y 908F- C8 INY 9090- C0 8B CPY #$8B 9092- D0 F8 BNE $908C ; "return" to $C5FF+1, i.e. reboot 9094- 60 RTS That explains the behavior that I saw on my non-working copy (endlessly rebooting). This was called from $9022, so let's continue from $9025. *9025L ; remove the dummy address that we ; manually pushed to the stack earlier ; (which would reboot if "returned" to) 9025- 68 PLA 9026- 68 PLA 9027- 60 RTS This program literally does nothing I want. I could probably just delete the line in HELLO that CALLs it, but I'm wary of disturbing a BASIC program by modifying it and re-saving it. (I've seen other disks where the HELLO program fakes its own size and hides some critical assembly language routine in the free space that follows. I'm not saying that that's happening here, but life is short and re-saving a BASIC program can be surprisingly invasive.) Instead, I turn to my trusty Disk Fixer sector editor. I press "D" for the directory listing, select "W.SPC", and I find the first sector on T02,S02. The first four bytes are the address and length (as with any DOS 3.3 binary file), so the fifth byte is where I need to put an "RTS". T02,S02,$04 change "20" to "60" Success! The disk boots and loads with no complaint. There doesn't appear to be any further protection. Quod erat liberandum. ~ Changelog 2015-09-06 - Vastly improved explanation of the actual protection routine. Thanks to qkumba for pointing out that my original explanation was inaccurate. 2014-09-29 - initial release --------------------------------------- A 4am crack No. 149 ------------------EOF------------------