------------The Observatory------------ a san inc crack 2015-10-22 -------------------. updated 2015-10-24 |___________________ Name: The Observatory Genre: educational Year: 1984 Authors: Gary J. Lassiter Publisher: Lightspeed Software Media: single-sided 5.25-inch floppy OS: custom Previous cracks: none ___________________________ { } { "If you're going through } { hell, keep going." } { } { -variously misattributed } {___________________________} ~ Prologue From Each According To His Ability This crack was a joint venture between me (4am) and qkumba of san inc, in the sense that he burned through the copy protection like flash paper, and I muttered "But that's insane!" over and over while I wrote these docs. Everyone seemed OK with this division of labor. ~ Chapter 0 In Which Various Automated Tools Fail In Interesting Ways COPYA immediate disk read error Locksmith Fast Disk Backup unable to read any track EDD 4 bit copy (no sync, no count) copy loads several tracks, then hangs with the drive motor running Copy ][+ nibble editor T00 -> custom epilogues T01-T10 -> weird, 4-and-4 encoded? T12-T20 -> custom prologues ("AA D5 96" / "AA D5 AD") Disk Fixer ["O" -> "Input/Output Control"] set CHECKSUM ENABLED to "NO" T00 readable, looks entirely custom (not DOS 3.3, not ProDOS, not Pascal) no sign of a disk catalog or OS Why didn't COPYA work? so many reasons Why didn't Locksmith FDB work? ditto Why didn't my EDD copy work? I don't know. Maybe a nibble check during boot? Could also be reading from half or quarter tracks at some point. (The original disk has that "rapid fire" sound during the second half of the boot.) Next steps: 1. Trace the boot 2. ??? ~ Chapter 1 Look At This Stuff, It's All An Exact Replica [S6,D1=original disk] [S5,D1=my work disk] ]PR#5 CAPTURING BOOT0 ...reboots slot 6... ...reboots slot 5... SAVING BOOT0 ]BLOAD BOOT0,A$800 ]CALL-151 *800 ; the disk controller PROM reads two ; sectors from disk, at $0800 and $0900 ; (most disks have a $01 here) 0800- 02 *801L ; jump over denibbilisation table 0801- 78 SEI 0802- 4C 6F 08 JMP $086F *86FL ; enable RAM bank 1 in languard card ; this has the (unpleasant) side-effect ; of making the machine hang if anyone ; attempts to use the ROM (like an evil ; hacker breaking to monitor) 086F- AD 8B C0 LDA $C08B 0872- AD 8B C0 LDA $C08B ; prepare to write to $B400+ 0875- A9 00 LDA #$00 0877- 85 00 STA $00 0879- A9 B4 LDA #$B4 087B- 85 01 STA $01 ; sector 3 087D- A9 03 LDA #$03 087F- 85 04 STA $04 After reusing the PROM to load the two boot sectors, the program proceeds to reproduce the behaviour of said PROM to load additional sectors. I have to assume the author knew about the $Cx5C entrypoint, so why duplicate work? Anyway, this is an exact replica of the built-in PROM: standard address and data prologues, but no epilogue check. (Track $00 uses non-standard epilogue bytes.) 0881- 18 CLC 0882- 08 PHP 0883- BD 8C C0 LDA $C08C,X 0886- 10 FB BPL $0883 0888- 49 D5 EOR #$D5 088A- D0 F7 BNE $0883 088C- BD 8C C0 LDA $C08C,X 088F- 10 FB BPL $088C 0891- C9 AA CMP #$AA 0893- D0 F3 BNE $0888 0895- 78 SEI 0896- BD 8C C0 LDA $C08C,X 0899- 10 FB BPL $0896 089B- C9 96 CMP #$96 089D- F0 09 BEQ $08A8 089F- 28 PLP 08A0- 90 DF BCC $0881 08A2- 49 AD EOR #$AD 08A4- F0 1D BEQ $08C3 08A6- D0 D9 BNE $0881 . . &c. . ; load every second sector because ; denibbilisation is slow and we miss ; sectors while we're doing it 0906- E6 01 INC $01 0908- E6 04 INC $04 090A- E6 04 INC $04 090C- A6 2B LDX $2B ; read until end of track 090E- A5 04 LDA $04 0910- C9 11 CMP #$11 0912- D0 DC BNE $08F0 ; erase hi-res screen 2 0914- A9 40 LDA #$40 0916- 85 03 STA $03 0918- A9 00 LDA #$00 091A- 85 02 STA $02 091C- A8 TAY 091D- 91 02 STA ($02),Y 091F- C8 INY 0920- D0 FB BNE $091D 0922- E6 03 INC $03 0924- A6 03 LDX $03 0926- E0 60 CPX #$60 0928- D0 F3 BNE $091D ; show hi-res screen 2 (now blank) 092A- AD 50 C0 LDA $C050 092D- AD 52 C0 LDA $C052 0930- AD 55 C0 LDA $C055 0933- AD 57 C0 LDA $C057 ; continue to boot1 0936- 4C 00 B4 JMP $B400 And that's where I need to interrupt the boot to capture the next phase. ~ Chapter 2 Another Day, Another RWTS *1600 At $B8, load "RWTS 0" [press "6" to switch to slot 6] [press "C" to convert disk] --> CHANGE DEFAULT VALUES? Y ADVANCED DEMUFFIN 1.5 (C) 1983, 2014 ORIGINAL BY THE STACK UPDATES BY 4AM ======================================= INPUT ALL VALUES IN HEX SECTORS PER TRACK? (13/16) 16 START TRACK: $00 START SECTOR: $00 END TRACK: $00 <-- change this END SECTOR: $0F INCREMENT: 1 MAX # OF RETRIES: 0 COPY FROM DRIVE 1 TO DRIVE: 2 ======================================= 16SC $00,$00-$00,$0F BY1.0 S6,D1->S6,D2 Now press RETURN to start the copy... --v-- ADVANCED DEMUFFIN 1.5 (C) 1983, 2014 ORIGINAL BY THE STACK UPDATES BY 4AM =======PRESS ANY KEY TO CONTINUE======= TRK:. +.5: 0123456789ABCDEF0123456789ABCDEF012 SC0:. SC1:. SC2:. SC3:. SC4:. SC5:. SC6:. SC7:. SC8:. SC9:. SCA:. SCB:. SCC:. SCD:. SCE:. SCF:. ======================================= 16SC $00,$00-$00,$0F BY1.0 S6,D1->S6,D2 --^-- One track down, 34 to go! ]PR#5 ... ]CALL -151 *3800 At $B8, load "RWTS 12+" [press "6" to switch to slot 6] [press "C" to convert disk] --> CHANGE DEFAULT VALUES? Y ADVANCED DEMUFFIN 1.5 (C) 1983, 2014 ORIGINAL BY THE STACK UPDATES BY 4AM ======================================= INPUT ALL VALUES IN HEX SECTORS PER TRACK? (13/16) 16 START TRACK: $12 <-- change this START SECTOR: $00 END TRACK: $20 <-- change this END SECTOR: $0F INCREMENT: 1 MAX # OF RETRIES: 0 COPY FROM DRIVE 1 TO DRIVE: 2 ======================================= 16SC $12,$00-$20,$0F BY1.0 S6,D1->S6,D2 Now press RETURN to start the copy... --v-- ADVANCED DEMUFFIN 1.5 (C) 1983, 2014 ORIGINAL BY THE STACK UPDATES BY 4AM =======PRESS ANY KEY TO CONTINUE======= TRK: ............... +.5: 0123456789ABCDEF0123456789ABCDEF012 SC0: ............... SC1: ............... SC2: ............... SC3: ............... SC4: ............... SC5: ............... SC6: ............... SC7: ............... SC8: ............... SC9: ............... SCA: ............... SCB: ............... SCC: ............... SCD: ............... SCE: ............... SCF: ............... ======================================= 16SC $12,$00-$20,$0F BY1.0 S6,D1->S6,D2 --^-- The RWTS that reads tracks $12-$20 is on track $00, so let's patch that now. Both the address and data prologue swap the order of the first two nibbles: T00,S02,$41 change "AA" to "D5" T00,S02,$4B change "D5" to "AA" T00,S02,$7E change "AA" to "D5" T00,S02,$88 change "D5" to "AA" For T11,S00, I just used my Disk Fixer sector editor to copy the sector. The RWTS that reads it is liberal enough to read a standard format (since it just ignores the epilogues), so no patches are required. Fun(*) fact: T11,S00 is the only sector on the disk that is read/write. The program prompts you for coordinates (latitude and longitude) and writes them back to disk on T11,S00. The write routine uses standard prologue and epilogue bytes, so no patches are required. (*) not guaranteed, actual fun may vary Next up: the weird 4-and-4 encoded data on tracks $01-$10. The code that reads the data and moves the drive arm is on T00,S04, starting at offset $3B. (It's loaded into $B63B in memory; I listed it earlier at $263B.) Instead of 4-and-4 encoding, I'll use a standard (6-and-2) encoding; instead of one sector per consecutive half-track, I'll read two sectors from each whole track. Which is still weird, but it'll be minimally invasive, given the code we already have. So this is the new disk layout: T01,S01 -> $0200 T01,S00 -> $0300 T02,S01 -> $0400 T02,S00 -> $0500 . . &c. . And this is the new code (on T00,S04): ; start on sector $01 263B- A9 01 LDA #$01 263D- 85 04 STA $04 263F- 20 00 B8 JSR $B800 ; seek to track $01 and prepare to read ; into $0200+ (like the original) 2642- A9 02 LDA #$02 2644- 85 03 STA $03 2646- A9 02 LDA #$02 2648- 85 15 STA $15 264A- 20 B6 B6 JSR $B6B6 ; read sector using 6-and-2 encoding, ; using one of the many RWTS routines ; available in memory (I'm not bitter!) 264D- 20 39 B8 JSR $B839 ; decrement sector (we'll read two ; sectors per whole track, then skip to ; the next whole track) 2650- C6 04 DEC $04 2652- 10 09 BPL $265D ; sector $01 again 2654- A9 01 LDA #$01 2656- 85 04 STA $04 ; increment phase twice to advance to ; the next whole track 2658- E6 03 INC $03 265A- E6 03 INC $03 ; a spare byte (!) 265C- EA NOP ; increment address until $2000 265D- E6 15 INC $15 265F- A5 15 LDA $15 ; loop until we've filled $0200..$1FFF ; in main memory 2661- C9 20 CMP #$20 2663- D0 E5 BNE $264A ; prevent seek from wandering away 2665- A5 02 LDA $02 2667- 4A LSR 2668- 90 09 BCC $2673 (I could lie and say that I automated writing out this data in the right pattern across tracks $01-$10, but I didn't. I just used a sector editor to write each page where this code would look for it. It's not that much data.) That's covers all the disk reading. For the "magic byte" verification, I can change the comparison loop into a copy loop. (This is now on T06,S00.) ; copy the magic byte array into the ; proper place on zero page (instead of ; verifying) 1F05- A0 00 LDY #$00 1F07- A2 07 LDX #$07 1F09- BD EC 15 LDA $15EC,X <-- 1F0C- 99 6F 00 STA $006F,Y <-- 1F0F- D0 00 BNE $1F11 Finally, I made a one-byte patch on T0C,S00 to disable the drive stepping. Now it'll actually read $1C bytes from disk, but all from the same track (and then ignore them and copy the correct bytes from memory). Which would make no sense if we were building this program from scratch, but we're not; we're patching a hostile codebase in a minimally invasive way. Anyway, this code (to check whether we need to move the drive arm): 18FE- A5 5F LDA $5F 1900- C5 60 CMP $60 1902- D0 01 BNE $1905 <-- 1904- 60 RTS becomes this: 18FE- A5 5F LDA $5F 1900- C5 60 CMP $60 1902- D0 00 BNE $1904 <-- 1904- 60 RTS ]PR#6 ...works... Infernum post nos. ~ Changelog 2015-10-24 - corrected bug in original software that could write to the wrong track when saving state 2015-10-22 - initial release --------------------------------------- a san inc crack docs by 4am ------------------EOF------------------