------------Picture Perfect------------ A 4am crack 2017-11-19 --------------------------------------- Name: Picture Perfect Genre: graphics Year: 1989 Publisher: Mindplay, Inc. Platform: Apple ][+ or later Media: single-sided 5.25-inch floppy OS: DOS 3.3 Previous cracks: none ~ Chapter 0 In Which Various Automated Tools Fail In Interesting Ways COPYA read error Locksmith Fast Disk Backup unable to read track $0F copy boots DOS, shows a title screen, then hangs with the drive motor on EDD 4 bit copy (no sync, no count) no errors, but copy boots DOS, shows a title screen, then displays "DISK ERROR 35W" and hangs Copy ][+ nibble editor track $0F is almost entirely sync bytes, with the occasional $D5 nibble (almost certainly a protection track) Disk Fixer entire disk is standard except T0F T00,S00 -> DOS 3.3 bootloader T01,S09 -> startup program is "HELLO" standard DOS 3.3 disk catalog on T11 Why didn't any of my copies work? specially formatted nibble sequence on track $0F, designed to fool even the best bit copiers Next steps: 1. Find the protection check that is reading track $0F 2. Disable it 3. Declare victory (*) (*) go to the gym ~ Chapter 1 In Which We Get Lucky One thing that all protection checks have in common is they need to access the disk drive. Since most protection checks exploit edge cases of how bits are stored on disk, they need to use the lowest level access methods to manipulate those bits manually. The lowest level way to "read" a disk is the data latch softswitch address in the $C0xx range. For slot 6, it's $C0EC, but to allow disks to boot from any slot, developers usually use code like this: LDX LDA $C08C,X There's nothing that says you have to use the X-register as the index or the accumulator as the load register. But most disks do, out of convention I suppose (or fear of messing up such low-level code in subtle ways). Also, since developers don't actually want people finding their protection- related code, they may try to encrypt it or obfuscate it on disk, in memory, or both. But eventually, the code must exist and the code must run, and it must run on my machine, and I have the final say on what my machine does or does not do. But sometimes you get lucky. Turning to my trusty Disk Fixer sector editor, I search the non-working copy for "BD 8C C0", which is the opcode sequence for "LDA $C08C,X". [Disk Fixer] ["F"ind] ["H"ex] ["BD 8C C0"] --v-- ------------- DISK SEARCH ------------- $00/$02-$75 $00/$02-$8B $00/$02-$B4 $00/$02-$E1 $00/$02-$EB $00/$02-$F6 $00/$03-$2F $00/$03-$39 $00/$03-$4F $00/$03-$59 $00/$03-$64 $00/$03-$71 $00/$03-$79 $00/$03-$8B $00/$03-$95 $00/$06-$A4 $00/$06-$C0 $00/$07-$27 $00/$07-$37 $00/$07-$3C $06/$01-$D5 $08/$08-$3A $08/$08-$4A $08/$08-$65 $08/$08-$76 $08/$08-$80 $08/$08-$8F --^-- The matches on track $00 are part of DOS 3.3, i.e. not suspicious. The one on track $06 seems harmless. But the cluster of matches on track $08 are highly suspect. ~ Chapter 2 In Which We Find Ourselves In Enemy Territory The protection routine appears to start at offset $04. --v-- T08,S08 ----------- DISASSEMBLY MODE ---------- ; save some things on the stack and get ; the boot slot (x16) from zero page 0004:08 PHP 0005:A6 2B LDX $2B 0007:A5 FD LDA $FD 0009:48 PHA 000A:A5 FE LDA $FE 000C:48 PHA ; get RWTS parameter table address 000D:20 E3 03 JSR $03E3 0010:84 FD STY $FD 0012:85 FE STA $FE ; track $0F -- the mystery track! 0014:A0 04 LDY #$04 0016:A9 0F LDA #$0F 0018:91 FD STA ($FD),Y ; RWTS command = seek 001A:A0 0C LDY #$0C 001C:A9 00 LDA #$00 001E:91 FD STA ($FD),Y ; slow down IIgs (has no effect on ; other machines) 0020:AD 36 C0 LDA $C036 0023:29 7F AND #$7F 0025:8D 36 C0 STA $C036 ; disable last line of RWTS that turns ; off the drive motor 0028:A9 60 LDA #$60 002A:8D 4D BE STA $BE4D ; call the RWTS to execute the seek to ; track $15 002D:20 E3 03 JSR $03E3 0030:20 D9 03 JSR $03D9 ; restore the RWTS code (but the drive ; motor is still on) 0033:A9 BD LDA #$BD 0035:8D 4D BE STA $BE4D ; if the seek failed for some reason, ; exit 0038:B0 65 BCS $009F ; find $D5 nibble 003A:BD 8C C0 LDA $C08C,X 003D:10 FB BPL $003A 003F:48 PHA 0040:68 PLA 0041:C9 D5 CMP #$D5 0043:D0 F5 BNE $003A ; initialize a checksum 0045:A0 00 LDY #$00 0047:8C CF 93 STY $93CF ; count number of $F7 nibbles before ; another $D5 nibble 004A:BD 8C C0 LDA $C08C,X 004D:10 FB BPL $004A 004F:C9 D5 CMP #$D5 0051:F0 0F BEQ $0062 0053:C9 F7 CMP #$F7 0055:D0 01 BNE $0058 0057:C8 INY ; the sum of the nibbles themselves ; constitutes the checksum 0058:18 CLC 0059:6D CF 93 ADC $93CF 005C:8D CF 93 STA $93CF 005F:4C 46 93 JMP $9346 0062:98 TYA 0063:F0 E0 BEQ $0045 ; skip $FF nibbles 0065:BD 8C C0 LDA $C08C,X 0068:10 FB BPL $0065 006A:48 PHA 006B:68 PLA 006C:C9 FF CMP #$FF 006E:F0 F5 BEQ $0065 ; if next nibble is $D5, fail 0070:C9 D5 CMP #$D5 0072:F0 36 BEQ $00AA ; skip several more nibbles 0074:A0 05 LDY #$05 0076:BD 8C C0 LDA $C08C,X 0079:10 FB BPL $0076 007B:48 PHA 007C:68 PLA 007D:88 DEY 007E:D0 F6 BNE $0076 ; skip $FF nibbles 0080:BD 8C C0 LDA $C08C,X 0083:10 FB BPL $0080 0085:48 PHA 0086:68 PLA 0087:C9 FF CMP #$FF 0089:F0 F5 BEQ $0080 ; if next nibble is not $D5, fail 008B:C9 D5 CMP #$D5 008D:D0 1B BNE $00AA ; skip $FF nibbles 008F:BD 8C C0 LDA $C08C,X 0092:10 FB BPL $008F 0094:C9 FF CMP #$FF 0096:D0 12 BNE $00AA ; verify checksum, branch on failure 0098:AD CF 93 LDA $93CF 009B:C9 10 CMP #$10 009D:D0 0B BNE $00AA ; success path falls through to here -- ; turn off drive motor and restore the ; state of things before returning to ; the caller 009F:BD 88 C0 LDA $C088,X 00A2:68 PLA 00A3:85 FE STA $FE 00A5:68 PLA 00A6:85 FD STA $FD 00A8:28 PLP 00A9:60 RTS ; all failures lead here -- ; wipe memory 00AA:A2 80 LDX #$80 00AC:A9 A0 LDA #$A0 00AE:99 FF 08 STA $08FF,Y 00B1:C8 INY 00B2:D0 FA BNE $00AE 00B4:EE AC 93 INC $93AC 00B7:CA DEX 00B8:D0 F4 BNE $00AE 00BA:AD 8A C0 LDA $C08A ; display encrypted error message ; "DISK ERROR 35W" 00BD:20 2F FB JSR $FB2F 00C0:20 58 FC JSR $FC58 00C3:A0 0E LDY #$0E 00C5:B9 D0 93 LDA $93D0,Y 00C8:49 BB EOR #$BB 00CA:99 B4 05 STA $05B4,Y 00CD:88 DEY 00CE:10 F5 BPL $00C5 00D0:78 SEI ; hang forever 00D1:30 FE BMI $00D1 (This is the behavior I saw on my non- working EDD bit copy.) There are no side effects. Replacing the first byte with an "RTS" will bypass the entire thing. T08,S08,$04: 08 -> 60 ]PR#6 ...works... Quod erat liberandum. --------------------------------------- A 4am crack No. 1529 ------------------EOF------------------