-----------Car Builder rev. 2---------- A 4am crack 2016-03-08 --------------------------------------- Name: Car Builder Version: (*) see below Genre: educational Year: 1985 Publisher: Optimum Resource, Inc. Media: single-sided 5.25-inch floppy OS: custom Previous cracks: me, but a different version (*) Similar cracks: #616 Stickybear Typing rev. 2 #615 Stickybear Math 2 rev. 2 #614 Stickybear Spellgrabber rev. 2 #613 Stickybear Reading Comprehension #611 Stickybear Reading #610 Stickybear Word Problems #609 Stickybear Math 2 rev. 1 #586 Stickybear Parts of Speech #585 Map Skills #336 Car Builder (*) With modern tools (xxd and diff), I compared this disk image against all the other copies I can find, online and in my private collection. This copy has significant differences on multiple tracks, and the boot trace routines I wrote for the other version don't work on this one. I'm pretty sure this one came later, because it has some IIgs- specific initialization code that the other one lacked. Both disks simply say "1985" on the label. ~ Chapter 0 In Which Various Automated Tools Fail In Interesting Ways COPYA read error on first pass Locksmith Fast Disk Backup fails to read T01,S0F; copy hangs during boot EDD 4 bit copy (no sync, no count) no read errors, but copy still hangs during boot Disk Fixer unable to read T01,S0F by any obvious combination of parameters Why didn't COPYA work? intentionally bad sector on track $01 Why didn't Locksmith FDB work? probably a nibble check during boot that centers around the bad sector Why didn't my EDD copy work? ditto Next steps: 1. Trace the boot 2. Find the nibble check and skip it 3. There is no step 3 (I hope) ~ Chapter 1 In Which We Abuse The Stack For Fun And Profit (Mostly Fun) [S6,D1=original disk] [S5,D1=my work disk] ]PR#5 ... CAPTURING BOOT0 ...reboots slot 6... ...reboots slot 5... SAVING BOOT0 CAPTURING BOOT1 ...reboots slot 6... ...reboots slot 5... SAVING BOOT1 SAVING RWTS ]BLOAD BOOT1,A$2600 ]CALL -151 *B600<2600.2EFFM ; move RWTS into place ; (but don't overwrite ; Diversi-DOS @ $BF00) *B700L ; clear hi-res graphics screen 1 B700- A9 00 LDA #$00 B702- A8 TAY B703- 85 10 STA $10 B705- A2 20 LDX #$20 B707- 86 11 STX $11 B709- 91 10 STA ($10),Y B70B- C8 INY B70C- D0 FB BNE $B709 B70E- E6 11 INC $11 B710- CA DEX B711- D0 F6 BNE $B709 ; hmm, a JSR followed by garbage code B713- 20 5D B6 JSR $B65D B716- 01 0E ORA ($0E,X) B718- 00 BRK B719- 08 PHP B71A- 18 CLC ; and another (maybe) B71B- 20 5D B6 JSR $B65D B71E- 03 ??? B71F- 0F ??? B720- 00 BRK *B65DL ; Ah! This subroutine uses the stack to ; pass in multiple arguments and store ; them in zero page B65D- 68 PLA B65E- 85 F0 STA $F0 B660- 68 PLA B661- 85 F1 STA $F1 B663- A0 01 LDY #$01 B665- B1 F0 LDA ($F0),Y B667- 85 54 STA $54 B669- C8 INY B66A- B1 F0 LDA ($F0),Y B66C- 85 55 STA $55 B66E- C8 INY B66F- B1 F0 LDA ($F0),Y B671- 85 58 STA $58 B673- C8 INY B674- B1 F0 LDA ($F0),Y B676- 85 59 STA $59 B678- C8 INY B679- B1 F0 LDA ($F0),Y B67B- 85 67 STA $67 B67D- 18 CLC B67E- A5 F0 LDA $F0 B680- 69 05 ADC #$05 B682- A8 TAY B683- A5 F1 LDA $F1 B685- 69 00 ADC #$00 ; then munges the stack pointer to ; "return" to the next real instruction ; after the parameters B687- 48 PHA B688- 98 TYA B689- 48 PHA B68A- A9 00 LDA #$00 B68C- 85 5A STA $5A B68E- 85 5B STA $5B B690- 85 5E STA $5E B692- 85 53 STA $53 B694- A9 01 LDA #$01 B696- 85 50 STA $50 B698- 85 52 STA $52 B69A- 85 60 STA $60 B69C- 85 62 STA $62 B69E- A9 60 LDA #$60 B6A0- 85 51 STA $51 B6A2- 85 5F STA $5F B6A4- A9 00 LDA #$00 B6A6- 85 57 STA $57 B6A8- A9 61 LDA #$61 B6AA- 85 56 STA $56 B6AC- A9 EF LDA #$EF B6AE- 85 63 STA $63 B6B0- A9 D8 LDA #$D8 B6B2- 85 64 STA $64 B6B4- A5 67 LDA $67 B6B6- D0 01 BNE $B6B9 B6B8- 60 RTS B6B9- A9 01 LDA #$01 B6BB- 85 5C STA $5C B6BD- A9 00 LDA #$00 B6BF- A0 50 LDY #$50 B6C1- 20 B5 B7 JSR $B7B5 B6C4- E6 59 INC $59 B6C6- C6 67 DEC $67 B6C8- C6 55 DEC $55 B6CA- 10 E8 BPL $B6B4 B6CC- A9 0F LDA #$0F B6CE- 85 55 STA $55 B6D0- E6 54 INC $54 B6D2- D0 E0 BNE $B6B4 This is a multi-sector read loop. It calls the regular $B7B5 entry point to read sectors (at $B6C1). Interestingly, the RWTS parameter table is actually on zero page, starting at $50. That would mean that the parameters passed in (on the stack, after the JSR $B65D) are 1. start track ($54) 2. start sector ($55) 3. start address - low ($58) 4. start address - high ($59) 5. sector count ($67) It uses logical sectors (via the RWTS). Sectors count down from $0F to $00, and tracks are decremented once the sector wraps around to $0F. The target address is incremented monotonically, and the sector count is decremented until it hits 0. Revisiting the caller with this new understanding... ; read $18 sectors into $0800 starting ; from T01,S0E B713- 20 5D B6 JSR $B65D B716- [01 0E 00 08 18] ; read $08 sectors into $6000 starting ; from T03,S0F B71B- 20 5D B6 JSR $B65D B71E- [03 0F 00 60 08] ; read $13 sectors into $6790 starting ; from T10,S0F B723- 20 5D B6 JSR $B65D B726- [10 0F 90 67 13] ; continue in the code we just read B72B- 4C 00 08 JMP $0800 That's where I'll interrupt the boot. ~ Chapter 2 Hello, I'd Like To Have An Argument On The Stack, Please *9600 *800L 0800- 4C 79 08 JMP $0879 Woohoo! It worked. *2000<800.1FFFM *C500G ... ]CALL -151 *800<2000.37FFM *BSAVE BOOT2 0800-1FFF,A$800,L$1800 *BSAVE BOOT2 6000-7AFF,A$6000,L$1B00 *800L 0800- 4C 79 08 JMP $0879 *879L ; A quick investigation reveals that ; this is also a multi-sector read loop ; that takes parameters on the stack, ; just like the one at $B65D. So this ; reads $0C sectors into $7A90 starting ; from T19,S0F. 0879- 20 DD 65 JSR $65DD 087C- [19 0F 90 7A 0C] ; and call it 0881- 20 90 7A JSR $7A90 Once again, time to interrupt the boot. ~ Chapter 3 In Which We Grow Suspicious *9600 $1E00 7CC4- A9 00 LDA #$00 7CC6- 85 50 STA $50 7CC8- A9 1E LDA #$1E 7CCA- 85 51 STA $51 ; wipe $46 bytes of memory at $1E00 7CCC- A0 46 LDY #$46 7CCE- A9 00 LDA #$00 7CD0- 91 50 STA ($50),Y 7CD2- 88 DEY 7CD3- D0 FB BNE $7CD0 ; call the next instruction, then fall ; through to do it again 7CD5- 20 D8 7C JSR $7CD8 ; read $02 sectors into $42D8 starting ; from T02,S06 7CD8- 20 E8 65 JSR $65E8 7CDB- [02 06 D8 42 02] ; copy these pages (well, most of them) ; to very low memory 7CE0- A0 00 LDY #$00 7CE2- B9 D8 42 LDA $42D8,Y 7CE5- 99 D8 02 STA $02D8,Y 7CE8- C8 INY 7CE9- D0 F7 BNE $7CE2 7CEB- A0 90 LDY #$90 7CED- B9 D6 43 LDA $43D6,Y 7CF0- 99 D6 03 STA $03D6,Y 7CF3- 88 DEY 7CF4- D0 F7 BNE $7CED ; and... crash? 7CF6- 20 FA 7C JSR $7CFA 7CF9- 60 RTS 7CFA- 00 BRK 7CFB- 00 BRK 7CFC- 00 BRK 7CFD- 00 BRK Ah, but we just modified $7CFA..$7CFD (at $7CB0). This is the code that ends up there: *7CFA:20 D8 02 60 *7CFAL 7CFA- 20 D8 02 JSR $02D8 7CFD- 60 RTS Highly suspect. Let's interrupt at $7CF6 and see what sneaky code ends up in the input buffer ($02D8), the page 3 vectors ($03D6), and overflowing onto the text page. ~ Chapter 4 Why Build One When You Can Have Two At Twice The Price? *9600