--------------Heavy Barrel------------- A 4am crack 2017-08-12 -------------------. updated 2017-08-21 |___________________ Name: Heavy Barrel Genre: arcade Year: 1989 Credits: Artwork by S. Chastain, S. Tanaka, C. Robinson, Ironwind Software; programming by L. Feddersen Publisher: Data East USA, Inc. Platform: Apple //e or later (128K) Media: single-sided 5.25-inch floppy OS: Quick-DOS ~ Chapter 0 In Which Various Automated Tools Fail In Interesting Ways COPYA no errors, but copy reboots endlessly Locksmith Fast Disk Backup ditto EDD 4 bit copy (no sync, no count) ditto Copy ][+ nibble editor nothing immediately suspicious Disk Fixer T00 -> looks like ProDOS bootloader and ProDOS disk catalog Why didn't any of my copies work? Probably a nibble check in the startup program Next steps: 1. Search for the error condition (maybe we'll get lucky!) 2. Disable protection check that leads to the error condition 3. Declare victory (*) go to the gym ~ Chapter 1 Jump, Jump For My Love As with many protection checks, this disk reboots as soon as it fails. There are many ways to reboot an Apple II, but the simplest is a direct jump to $C600, the slot 6 firmware. (The more "correct" way is to jump to $FAA6, which does a "cold" restart and scans your slots from 7 down to 1 looking for card firmware to run. Since I have a hard drive device in slot 7, I can tell this protection check is not doing that, because it reboots slot 6 when it fails.) Anyway... [Disk Fixer] ["F"ind] ["H"ex] "4C 00 C6" One match on track $00, sector $0E. Turning to my trusty Disk Fixer sector editor, I notice an oddity right out of the gate: the boot sector has a #$03 in byte 0, which tells the drive firmware to load 3 sectors from track 0 before transferring control to $0801. --v-- -------------- DISK EDIT -------------- TRACK $00/SECTOR $00/VOLUME $FE/BYTE$00 --------------------------------------- $00:>03<4C 00 0A EA D0 27 78 CL@JjP'8 $08: AD 83 C0 AD 83 C0 A5 2B -.@-.@%+ $10: 4A 4A 4A 4A 09 C0 85 3F JJJJI@.? $18: 8D FD FF A9 5C 85 3E A9 .}.)\.>) $20: 00 8D FC FF 18 AD BF 08 @.|.X-?H ... --------------------------------------- BUFFER 0/SLOT 6/DRIVE 1/MASK OFF/NORMAL --^-- The boot sector (T00,S00) is loaded at $0800. If byte 0 is more than 1, the drive firmware will load additional sectors at $0900, $0A00, and so on. Theoretically it could load all 16 sectors on track 0, but very few disks do this because it's generally faster to write a little loop to load only the sectors you need into the memory pages you need them. Also, the bytes at $0801 are "4C 00 0A" a.k.a. "JMP $0A00". So we're loading 3 sectors and jumping to the last one. Due to sector skewing, the last one is actually T00,S0E. (The second one is T00,S07. I know, right? There's a table in "Beneath Apple DOS" on p. 3-23 that explains sector skewing.) Which is exactly where I found the "JMP $C600". Thus... --v-- T00,S0E (loaded at $0A00) ----------- DISASSEMBLY MODE ---------- 0000:EA NOP 0001:EA NOP 0002:A2 60 LDX #$60 ; initialize Death Counter (2 bytes) 0004:A9 56 LDA #$56 0006:85 FD STA $FD 0008:A9 08 LDA #$08 000A:C6 FC DEC $FC 000C:D0 04 BNE $0012 000E:C6 FD DEC $FD ; If the Death Counter hits zero, that ; would be bad. Which part of "Death ; Counter" sounded good to you, anyway? ; (Specifically, this jumps to the ; immediate reboot we saw earlier.) 0010:F0 38 BEQ $004A ; look for an #$FB nibble 0012:BC 8C C0 LDY $C08C,X 0015:10 FB BPL $0012 0017:C0 FB CPY #$FB 0019:D0 ED BNE $0008 ; 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) 001B:F0 00 BEQ $001D 001D:EA NOP 001E:EA NOP ; read data latch (note: no BPL loop ; here, we're just reading it once) 001F: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) 0022:C0 08 CPY #$08 ; rotate the carry into the low bit of ; the accumulator 0024:2A ROL ; if we just rolled a "1" bit out of ; the high bit of the accumulator, take ; this branch 0025:B0 0B BCS $0032 ; next nibble needs to be #$FF 0027:BC 8C C0 LDY $C08C,X 002A:10 FB BPL $0027 002C:C0 FF CPY #$FF ; ...otherwise we start over 002E:D0 D8 BNE $0008 ; loop back to get next nibble 0030:F0 EB BEQ $001D ; execution continues here (from $0A25) ; and we get another (full) nibble 0032:BC 8C C0 LDY $C08C,X 0035:10 FB BPL $0032 ; stash it in zero page 0037:84 FC STY $FC ; if the accumulator is anything but ; %00001010, start over 0039:C9 0A CMP #$0A 003B:D0 CB BNE $0008 ; get one more nibble 003D:BD 8C C0 LDA $C08C,X 0040:10 FB BPL $003D ; AND it with the previously stashed ; nibble, to get a single 4-and-4 ; encoded byte value 0042:38 SEC 0043:2A ROL 0044:25 FC AND $FC 0046:49 FF EOR #$FF ; branch on success 0048:F0 03 BEQ $004D ; otherwise reboot 004A:4C 00 C6 JMP $C600 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. ~ Chapter 2 It's Time To Get Visual 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: 00 START: 1A8E LENGTH: 1813 1BE0: FE AB DE BD 96 96 96 96 VIEW 1BE8: 96 96 96 96 96 96 96 96 1BF0: 96 96 96 96 96 96 96 96 1BF8: 96 EA B6 FF DE AA EB FB 1C00: BF FD+BB+FB+FF FF+FF FF+ <-1C03 1C08: FF+FF+FF+D5 AA 96 FF FE 1C10: AA AA AA AB FF FF DE AA 1C18: EB FF+FF+FF+FF+FF+FF+D5 FIND: 1C20: AA AD A7 E9 DD 96 B6 F4 FB FF --^-- It's easy to understand why a simple sector copy failed. The sequence that this code is looking for starts at offset $1C03, which is between the end of one sector and the beginning of the next. (The data epilogue is at $1BFC; the next address prologue is at $1C0B.) 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 $1C03: - #$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-- 1C00: BF FD+BB+FB+FF FF FF+FF+ 1C08: FF+FF+FF+D5 AA 96 FF FE 1C10: AA AA AA AB FF FF DE AA 1C18: EB FF+FF+FF+FF+FF+FF+D5 1C20: AA AD A7 E9 DD 96 B6 F4 --^-- A subtle difference! The sequence at offset $1C03 now looks like this: - #$FB + timing bit - #$FF - #$FF - #$FF + timing bit - #$FF + timing bit This code is looking for #$FF nibbles 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. ~ Chapter 3 One Byte To Rule Them All Continuing with the disassembly of track $00 sector $0E (loaded at $0A00): --v-- ; success path is here -- reset zero ; page addresses to their normal values 004D:A9 60 LDA #$60 004F:85 2B STA $2B 0051:A9 09 LDA #$09 0053:85 27 STA $27 ; restore the boot sector code to its ; normal values 0055:A9 01 LDA #$01 0057:8D 00 08 STA $0800 005A:A9 A5 LDA #$A5 005C:8D 01 08 STA $0801 005F:A9 27 LDA #$27 0061:8D 02 08 STA $0802 0064:A9 C9 LDA #$C9 0066:8D 03 08 STA $0803 0069:A9 09 LDA #$09 006B:8D 04 08 STA $0804 ; and continue with the normal boot 006E:4C 01 08 JMP $0801 --^-- This entire routine is a kludge. The bootloader was supposed to load only one sector into $0800, then go right into disk-specific code that loads the RWTS in higher memory. Then they go and plop this copy protection routine on top, jump to it, do the nasty, and restore the real bootloader one byte at a time on the way out. Anyway, the easiest patch is to jump directly to the success path at $0A4D. T00,S00,$02: 00 -> 4D Quod erat liberandum. ~ Acknowledgments Thanks to Ian Baronofsky for lending me the original disk at Kansasfest 2017. ~ Changelog 2015-08-21 - typos (thanks LoGo) 2017-08-12 - initial release --------------------------------------- A 4am crack No. 1359 ------------------EOF------------------