-------------Math Leap Frog------------ A 4am crack 2016-09-12 --------------------------------------- Name: Math Leap Frog Version: 3.1.6 Genre: educational Year: 1987 Publisher: Gamco Industries, Inc. Platform: Apple ][+ or later Media: double-sided 5.25-inch floppy OS: ProDOS 1.1.1 Previous cracks: none Similar cracks: #826 Math Football #795 Treasure Dive #794 Grammar Baseball #686 The Word Problem Game Show #685 Eureka: Following Directions ~ Chapter 0 In Which Various Automated Tools Fail In Interesting Ways COPYA fails on last pass (both sides) Locksmith Fast Disk Backup unable to read track $22 -- copy boots ProDOS, prints "BEAGLE COMPILER 3.2", then prints "NOT AN EXECUTABLE DISK." and hangs EDD 4 bit copy (no sync, no count) works Copy ][+ nibble editor track $22 is entirely unformatted Disk Fixer T00 -> looks like standard ProDOS no way to read T22 Why didn't COPYA work? intentionally unformatted track Why didn't Locksmith FDB work? Probably a runtime protection check to ensure track $22 is unreadable EDD works. What does that tell us? The protection check is probably very simple, just checking that track $22 is unreadable. Next steps: 1. Search for protection check 2. Disable it 3. Declare victory(*) (*) Go to the gym ~ Chapter 1 How Do I Read Thee? Let Me Count The Ways On the theory that some code on disk is trying to access track $22, and thus noticing if it's unexpectedly readable, let's enumerate some of the ways that could happen: - Reading a file that is mapped to the unreadable track $22. Copy II+ disk map shows there are no files mapped to track $22, so let's rule that out. - Manually seeking to the track and looking for a nibble sequence. Given that this disk is ProDOS-based, there is no explicit support for "seeking to a particular track" unless you're calling ProDOS internals. (But that's always possible, of course!) Without calling into ProDOS, this technique would require low-level disk access (turning on the drive and hitting the right stepper motors and whatnot). A sector search with Disk Fixer didn't find any suspicious instances of "BD 89 C0" (LDA $C089,X) ; drive on "AD E9 C0" (LDA $C0E9) ; drive on "BD 80 C0" (LDA $C080,X) ; stepper or any similar variations that would point to low-level disk access. - Issuing a ProDOS MLI "raw block read" and checking the return code. This is a popular technique under ProDOS, partly because it can be adapted to work on 3.5-inch and 5.25-inch disks. Combined with the knowledge that EDD bit copy produced a working copy, I suspect this is what I'm looking for. Unfortunately, a sector search for "20 00 BF 80" (JSR $BF00 / [80]) -- the standard opcode sequence for calling the ProDOS MLI with command $80 (block read) -- turned up nothing at all. Which means, perhaps, that this entire chapter was just mental gymnastics. Or is it? Dun dun DUN... ~ Chapter 2 Lies, Damned Lies, And Error Messages After striking out looking for the protection check, let's change tactics and look for the error string instead. My non-working copy prints the message "NOT AN EXECUTABLE DISK" after booting ProDOS, launching the Beagle Compiler, and executing the startup program -- a delightfully bald-faced lie only a copy protection developer could love. Searching for the string "EXECUTABLE" finds nothing, but wait! Disk Fixer also supports finding strings with the low bit clear. Pressing "T" twice to change from "NORMAL" to "INVERSE" to "FLASH" mode, then "F"ind "A"SCII and search for "EXECUTABLE" again. Lo and behold, it finds a match on track $0D. --v-- -------------- DISK EDIT --------------- TRACK $0D/SECTOR $01/VOLUME $FE/BYTE $A9 ---------------------------------------- $80: 1F 7C 96 30 BF 6E 96 F0 .|.0?n.p $88: 1F 4A A4 7C 96 EF 1F 94 .J$|.o.. $90: 27 09 97 00 0A 98 00 0E '....... $98: 28 66 94 0A 64 94 09 1C (f..d... $A0: 9A 17 4E 4F 54 20 41 4E ..NOT AN ^^^^^^^^^^^^^^^^^ lies! all lies! $A8: 20>45<58 45 43 55 54 41 EXECUTA ^^^^^^^^^^^^^^^^^^^^^^^ $B0: 42 4C 45 20 44 49 53 4B BLE DISK ^^^^^^^^^^^^^^^^^^^^^^^ $B8: 2E 24 0A BA 00 12 02 33 .$.:...3 $C0: 32 01 30 03 31 39 31 03 2.0.191. $C8: 31 32 38 03 32 35 30 02 128.250. $D0: 33 31 03 31 34 31 03 32 31.141.2 $D8: 33 39 02 33 31 02 39 36 39.31.96 $E0: 01 33 02 39 36 01 30 01 .3.96.0. $E8: 32 02 31 37 01 31 FF 12 2.17.1.. $F0: 00 00 00 00 00 00 00 00 ........ $F8: 00 00 00 00 00 00 00 00 ........ ---------------------------------------- BUFFER 0/SLOT 6/DRIVE 1/MASK OFF/FLASH ---------------------------------------- COMMAND : _ --^-- Starting at byte $BF, I spy with my little eye a sequence of numbers written out as strings: 32 0 191 128 250 31 141 239 31 96 ...and so on. Each is preceded by a hex byte #$01, #$02, or #$03, which appears to be the length in character of the number as a string. "32" is always preceded by #$02 because it's a 2-digit number -- er, string -- while "191" is preceded by #$03 because it's a 3-digit number string. So what is this sequence? They seem to be base 10 numbers between 0 and 255. Converted to base 16, they turn out to be quite interesting indeed: 32 -> $20 0 -> $00 191 -> $BF 128 -> $80 250 -> $FA 31 -> $1F 141 -> $8D 239 -> $EF 31 -> $1F 96 -> $60 3 -> $03 96 -> $60 0 -> $00 2 -> $02 17 -> $11 1 -> $01 "20 00 BF" looks suspiciously like 6502 assembly code. (It's a call to the ProDOS MLI subroutine at $BF00.) The rest of it fits my theory that this ends up as executable code. I like data that fits my theory. That's so much easier than changing my theory to fit the data. Boring! Dropping into the monitor, I can see it in its native form: *1FF0:20 00 BF 80 FA 1F 8D EF 1F 60 03 60 00 02 11 01 *1FF0L 1FF0- 20 00 BF JSR $BF00 1FF3- [80] ; MLI block read 1FF4- [FA 1F] ; MLI param address 1FF6- 8D EF 1F STA $1FEF 1FF9- 60 RTS 1FFA- [03] ; MLI param count 1FFB- [60] ; unit number 1FFC- [00 02] ; buffer address 1FFE- [11 01] ; block number Note: block $0111 is on the unreadable track $22! I think I know what I'm looking at here. This (compiled) BASIC program is taking a sequence of numbers and POKE-ing them into memory, then calling that assembly language routine to accomplish what would otherwise impossible from pure BASIC -- calling the ProDOS MLI with a raw block read, and storing the result. According to "Beneath Apple ProDOS" (p. 6-19), the return codes from a raw block read (MLI code $80) are $00 - no errors $04 - incorrect parameter count $27 - I/O error or bad block number $28 - drive not found $56 - buffer already in use Since the original disk's track $22 is unformatted and thus unreadable, I'm guessing the "correct" answer is $27 ("I/O error"). I can change this routine so it simply puts the expected value in memory address $1FEF. *1FF0:2C *1FF3:EA A9 27 *1FF0L 1FF0- 2C 00 BF BIT $BF00 1FF3- EA NOP 1FF4- A9 27 LDA #$27 1FF6- 8D EF 1F STA $1FEF 1FF9- 60 RTS Converting this hacked routine back to decimal would yield the sequence 44 0 191 234 169 39 [...] ...which happens to be exactly as long as the original number-string sequence: 32 0 191 128 250 31 [...] T0D,S01,$BF: 33 32 -> 34 34 T0D,S01,$C8: 31 32 38 -> 32 33 34 T0D,S01,$CC: 32 35 30 -> 31 36 39 T0D,S01,$D1: 31 -> 39 ]PR#6 ...works, and it is glorious... Side B is unprotected. Quod erat liberandum. --------------------------------------- A 4am crack No. 839 ------------------EOF------------------