💾 Archived View for mirrors.apple2.org.za › active › 4am › images › games › misc › Video%20Vegas%20(… captured on 2023-05-24 at 23:11:05.
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
--------------Video Vegas-------------- A 4am crack 2014-06-12 --------------------------------------- "Video Vegas" is a 1984 casino simulation game by Baudville, Inc. [The copy protection is identical to "Take 1," also by Baudville. This write-up is therefore quite similar to that one, with updated listings and a few corrections.] COPYA gives no read errors, but the copy does not work. (EDD 4 bit copy fares no better.) It displays "12501" (a version number, I think), then grinds the disk in a most unusual fashion (hopping back and forth between two tracks? trying to read a quarter track? I've never heard anything like it) until I frantically power off in an attempt to save my 30 year old floppy drive from frog-stepping off my desk. Time for boot tracing, I suppose. [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 *801L ; starts off looking like DOS 3.3 boot0 0801- A5 27 LDA $27 0803- C9 09 CMP #$09 0805- D0 34 BNE $083B 0807- A5 2B LDA $2B 0809- 4A LSR 080A- 4A LSR 080B- 4A LSR 080C- 4A LSR 080D- 09 C0 ORA #$C0 080F- 85 3F STA $3F 0811- A9 5C LDA #$5C 0813- 85 3E STA $3E 0815- 18 CLC ; slightly unusual -- it appears to ; keep the target address and sector ; count in $0866/7 instead of $08FE/F 0816- AD 66 08 LDA $0866 0819- 6D 67 08 ADC $0867 081C- 8D 66 08 STA $0866 ; enable read/write on RAM bank 2 (at ; $D000..$FFFF) 081F- AD 83 C0 LDA $C083 0822- AD 83 C0 LDA $C083 ; set low-level reset vector 0825- A9 EF LDA #$EF 0827- 8D FC FF STA $FFFC 082A- 8D FE FF STA $FFFE 082D- 8D FA FF STA $FFFA 0830- A9 08 LDA #$08 0832- 8D FD FF STA $FFFD 0835- 8D FF FF STA $FFFF 0838- 8D FB FF STA $FFFB ; looks like a sector read loop 083B- AE 67 08 LDX $0867 ; jump out of the read loop here 083E- 30 28 BMI $0868 0840- BD 55 08 LDA $0855,X 0843- 85 3D STA $3D 0845- CE 67 08 DEC $0867 0848- AD 66 08 LDA $0866 084B- 85 27 STA $27 084D- CE 66 08 DEC $0866 0850- A6 2B LDX $2B ; jump to disk controller ROM routine ; to read sectors 0852- 6C 3E 00 JMP ($003E) . . . ; looks like the loop above will read ; 7 sectors into $DA00..$E0FF 0866- DA 0867- 07 ; out of the sector read loop -- ; switch back to ROM, initialize ; keyboard/video/text mode/screen 0868- AD 82 C0 LDA $C082 086B- 20 93 FE JSR $FE93 086E- 20 89 FE JSR $FE89 0871- 20 2F FB JSR $FB2F 0874- 20 58 FC JSR $FC58 ; display the version number 0877- A0 00 LDY #$00 0879- 20 A5 08 JSR $08A5 ; check for Applesoft in ROM, display ; error message if not found 087C- AD 00 E0 LDA $E000 087F- C9 4C CMP #$4C 0881- D0 13 BNE $0896 ; switch back to RAM bank 2 0883- AD 83 C0 LDA $C083 0886- AD 83 C0 LDA $C083 ; push ($E000) to the stack, then ; "return" to that address (+1) 0889- AD 00 E0 LDA $E000 088C- C9 E0 CMP #$E0 088E- D0 06 BNE $0896 0890- 48 PHA 0891- AD 01 E0 LDA $E001 0894- 48 PHA 0895- 60 RTS 0896- AD 82 C0 LDA $C082 Since this boot0 code bears little resemblance to DOS 3.3, I'll need a custom trace routine to capture the code it loads into $DA00..$E0FF. *9600<C600.C6FFM ; Interrupt boot at $086B, immediately ; after the sector read loop. Set up a ; callback to a routine under my ; control so I can capture the code in ; RAM bank 2. 96F8- A9 4C LDA #$4C 96FA- 8D 68 08 STA $0868 96FD- A9 0A LDA #$0A 96FF- 8D 69 08 STA $0869 9702- A9 97 LDA #$97 9704- 8D 6A 08 STA $086A ; start the boot 9707- 4C 01 08 JMP $0801 ; callback is here -- copy $DA00..$E0FF ; to main memory so it will survive a ; reboot (RAM bank 2 is read/write at ; this point) 970A- A2 07 LDX #$07 970C- A0 00 LDY #$00 970E- B9 00 DA LDA $DA00,Y 9711- 99 00 2A STA $2A00,Y 9714- C8 INY 9715- D0 F7 BNE $970E 9717- EE 10 97 INC $9710 971A- EE 13 97 INC $9713 971D- CA DEX 971E- D0 EE BNE $970E ; switch back from RAM bank 2 to ROM 9720- AD 82 C0 LDA $C082 ; turn off slot 6 drive motor 9723- AD E8 C0 LDA $C0E8 ; reboot to my work disk 9726- 4C 00 C5 JMP $C500 *BSAVE TRACE1,A$9600,L$129 *9600G ...reboots slot 6... ...reboots slot 5... ]BSAVE BOOT1 DA00-E0FF,A$2A00,L$700 ]CALL -151 (The code at $DA00..$E0FF is loaded in $2A00..$30FF, so everything is off by $B000. Relative branches will look correct, but absolute addresses will be off by $B000.) First, let's see what would be at $E000 and $E001, which the boot0 code pushes to the stack. *3000.3001 3000- E0 02 OK, so execution continues at $E003 (the address pushed to the stack, +1). *3003L ; seek to track 0 3003- A6 2B LDX $2B 3005- A9 00 LDA #$00 3007- 20 A0 DC JSR $DCA0 ; read the next available address field 300A- 20 44 DC JSR $DC44 ; Zero page $2D is part of the scratch ; space used by the RWTS to verify the ; address field checksum. (The routine ; is at $B962..$B98A, in a regular DOS ; 3.3 RWTS. Zero page $2F holds the ; disk volume number; $2E holds the ; track number; $2D holds the sector ; number; $2C holds the checksum.) 300D- A5 2D LDA $2D 300F- C9 00 CMP #$00 ; keep reading address fields until we ; find sector 0 3011- D0 F7 BNE $300A ; this subroutine is just a wait loop 3013- 20 BF E0 JSR $E0BF ; now seek to track 1 3016- A0 01 LDY #$01 3018- 8C CD E0 STY $E0CD 301B- 98 TYA 301C- 0A ASL 301D- 20 A0 DC JSR $DCA0 ; and read the address field of the ; next available sector (without any ; regard for which sector it is) 3020- 20 44 DC JSR $DC44 ; and wait again 3023- 20 BF E0 JSR $E0BF ; now compare the sector number we ; actually found to a predetermined ; list of expected sector numbers) 3026- A5 2D LDA $2D 3028- AC CD E0 LDY $E0CD 302B- D9 CE E0 CMP $E0CE,Y ; if we didn't find the "right" sector, ; jump back to the beginning and start ; again (which explains why my copy ; makes that unique grinding sound ; forever) 302E- D0 D5 BNE $3005 3030- C8 INY 3031- C0 08 CPY #$08 3033- 90 E3 BCC $3018 ; seek back to track 0 3035- A9 00 LDA #$00 3037- 20 A0 DC JSR $DCA0 ; the rest of this looks like normal ; initialization of the RWTS parameter ; table (albeit shifted) 303A- A5 2B LDA $2B 303C- 8D D0 DF STA $DFD0 303F- 8D DE DF STA $DFDE 3042- 8D F2 DF STA $DFF2 3045- 4A LSR 3046- 4A LSR 3047- 4A LSR 3048- 4A LSR 3049- AA TAX 304A- A9 00 LDA #$00 304C- 8D 79 DD STA $DD79 304F- 0A ASL 3050- 9D 79 DD STA $DD79,X 3053- A9 01 LDA #$01 3055- 8D DF DF STA $DFDF 3058- 8D D1 DF STA $DFD1 . . . ; array of expected sectors 30CF- 05 0A 0F 04 09 0E 03 08 30D7- 0D 02 07 0C 01 06 0B 00 That is a fascinating form of copy protection. It relies on tracks 0 and 1 being synchronized on the physical disk in such a way that blindly jumping between the tracks finds sectors in a specific order as the disk is rotating in the drive. It's theoretically possible to defeat this copy protection with a bit copy that maintains that synchronization (the so-called "sync tracks" option in most copiers), but even then it probably wouldn't work in an emulator. For example, the AppleWin emulator offers an "enhanced speed" option which ignores sector skew to get standard DOS 3.3 disks to load faster. So even if I did manage to create a perfectly synchronized copy of this disk, emulators would just ignore it. Emulating copy protection is A Hard Problem(tm). Anyway, this copy protection routine doesn't seem to have any side effects. If it succeeds, execution continues at $E03A. If it fails, it keeps trying until it succeeds (or until it destroys your disk drive). Thus, I can change the jump address at $E000 to point to the first instruction after the copy protection (minus 1, due to how pushing addresses to the stack works). T00,S06,$01 change "02" to "39" Quod erat liberandum. --------------------------------------- A 4am crack No. 70 ------------------EOF------------------