-----Computer Drill and Instruction---- --------------Decimals C-2------------- A 4am crack 2017-10-16 --------------------------------------- Name: Computer Drill and Instruction: Decimals C-2 Genre: educational Year: 1981 Publisher: Science Research Associates Platform: Apple ][+ or later Media: single-sided 5.25-inch floppy OS: DOS 3.2 Previous cracks: none ~ Chapter 0 If You Give a Cracker a Disk This disk was automatically cracked by the development version of Passport (dated 2017-10-01). Here is the transcript: --v-- READING FROM S6,D1 T00,S00 FOUND DOS 3.2 BOOTLOADER USING DISK'S OWN RWTS WRITING TO S5,D2 T00,S02 WRITING BUILT-IN RWTS T00,S01,$38: 20 -> 2C T00,S00 WRITING STANDARD DELIVERY BOOTLOADER CRACK COMPLETE. --^-- [Narrator] But the crack was not complete. Passport successfully converts the original disk from DOS 3.2 to DOS 3.3. But when I boot the copy, it gets as far as displaying part of the title screen before displaying this message: --v-- YOU HAVE ENCOUNTERED ERROR NO. CDIM-592 PLEASE CONTACT SRA IN CHICAGO FOR ASSISTANCE. --^-- Pro-tip: do not do that. ~ Chapter 1 If You Give a Pirate a Prompt After displaying the cryptic error message, my non-working copy drops me to a BASIC prompt where any attempt to LIST the current program in memory RUNs it instead. This is what it looks like when you set the RUN flag, zero page $D6. However, you can just as easily clear the flag by re-initializing BASIC with the "FP" command. ]FP It appears that DOS is still in memory. Let's see if I can use that to my advantage. ]CATALOG DISK VOLUME 254 A 003 HELLO B 040 MPG CODE A 016 MINI LOADER A 021 MINI P1 A 023 MINI P12 A 021 MINI P3 A 012 STUDENT A 008 SIGNON A 017 HOME B 005 FONT2 B 012 FONT1 B 002 C-DECC B 005 DECC37 B 006 DECC24 B 011 HDECC24 B 008 DECC25 B 009 HDECC25 B 005 DECC30 B 006 DECC33 B 007 DECC51 B 011 HDECC51 B 003 DECC27 B 007 HDECC27 B 003 DECC28 B 007 HDECC28 B 005 DECC34 B 005 DECC71 B 009 HDECC71 B 002 PL-DECC B 010 HDECC30 B 006 HDECC37 B 002 RNDM B 005 DECC38 B 005 DECC39 B 010 HDECC34 B 009 HDECC54 B 010 DECC54 B 004 DECC43 B 006 HDECC43 B 002 Q-DECC ]LOAD HELLO ]LIST 1 REM HELLO VER:1.1/RPT 2 REM COPYRIGHT 1981 SRA. ALL RIGHTS RESERVED. LICENSED MA TERIAL. PROGRAM PROPERTY OF SRA. 5 D$ = CHR$ (4) 10 GOSUB 100 12 POKE 1010,0: POKE 1011,0 15 PRINT D$ 20 POKE 103,1 25 POKE 104,67 30 POKE 17152,0 40 POKE 214,227 45 POKE 215,55 50 PRINT D$;"RUN STUDENT" 100 IF PEEK (116) = 150 THEN RETURN 110 HOME : PRINT : PRINT "THE C OMPUTER MUST HAVE 48K OF MEM ORY TO OPERATE CDIM.": NEW The subroutine at line 100 checks that DOS relocated properly to higher memory during boot. Line 12 munges the reset vector. Lines 20 and 25 set a custom start address in memory for the next BASIC program. Line 40 sets the RUN flag I noted earlier. Nothing extraordinary yet. Then it runs another program, STUDENT. ~ Chapter 2 If You Give a STUDENT a CALL ]LOAD STUDENT ]LIST 1 REM STUDENT VER:1.1/FRAC-2/L L 2 REM COPYRIGHT 1981 SRA. ALL RIGHTS RESERVED. LICENSED MA TERIAL. PROGRAM PROPERTY OF SRA. 3 ONERR GOTO 60000 10 POKE 30840,0: POKE 30841,141 : REM TRAIL STACK 15 GOSUB 8000 16 Q = RND ( - 1) 18 HCOLOR= 3 20 HOME 21 PRINT "COPYRIGHT SRA 1981.": PRINT "ALL RIGHTS RESERVED. ": PRINT "LICENSED MATERIAL. ": PRINT "PROGRAM PROPERTY O F SRA.": PRINT "PRODUCED IN USA." 22 PRINT : PRINT : PRINT : PRINT 23 PRINT "THE COPYRIGHTED COMPU TER PROGRAMS AND": PRINT "TE XT MATERIAL CONTAINED HEREIN ARE": PRINT "FURNISHED UNDE R LICENSE FROM SRA." 24 PRINT "THE RIGHTS TO THIS MA TERIAL ARE": PRINT "OWNED OR CONTROLLED BY SRA AND MAY": PRINT "BE USED ONLY IN ACCO RDANCE WITH THE" 25 PRINT "PROVISIONS DETAILED I N THE LICENSE": PRINT "BETWE EN THE CUSTOMER AND SRA." 30 POKE - 16368,0 OK, I saw all of that printed on my non-working copy. 40 PRINT CHR$ (4);"BLOAD MPG C ODE" 41 PRINT CHR$ (4);"BLOAD FONT1 " 42 PRINT CHR$ (4);"BLOAD FONT2 " Looks like we're loading several binary files. Some sort of hi-res character generator? 43 POKE 49289 + PEEK (47081),2 55 45 GOSUB 9300: GOSUB 100: GOSUB 200 ]LIST 9300 9300 HOME : HGR :X% = 0:Y% = 15 : POKE - 16302,0:X% = 0:Y% = 15:FY% = 0: RETURN OK, that just initializes the hi-res screen and sets some global variables. ]LIST 100, 100 FOR X = 8 TO 28 STEP 5: HPLOT X,90 TO X - 3,90 TO X - 3,12 0 TO X,120 TO X,90:: NEXT X 102 HPLOT 30,90 TO 30,120 TO 60 ,120 TO 60,90 TO 30,90 110 FOR Y = 8 TO 88 STEP 5: HPLOT 64,Y TO 94,Y TO 94,Y - 3 TO 64,Y - 3 TO 64,Y: NEXT Y 111 HPLOT 64,90 TO 94,90 TO 94, 120 TO 64,120 TO 64,90 120 FOR X = 273 TO 133 STEP - 5: HPLOT X,90 TO X,120 TO X - 3,120 TO X - 3,90 TO X,90: NEXT X 121 HPLOT 98,90 TO 128,90 TO 12 8,120 TO 98,120 TO 98,90 130 HCOLOR= 3 131 HPLOT 53,97 TO 50,95 TO 37, 95 TO 35,97 TO 35,103 TO 37, 105 TO 50,105 132 HPLOT 50,105 TO 53,107 TO 5 3,113 TO 50,115 TO 37,115 TO 35,112 139 FOR I = 1 TO 500: NEXT I 141 HPLOT 71,115 TO 71,95 TO 87 ,95 TO 89,97 TO 89,103 TO 87 ,105 TO 71,105 142 HPLOT 81,105 TO 85,109 TO 8 8,115 149 FOR I = 1 TO 500: NEXT I 151 HPLOT 104,115 TO 113,95 TO 123,115 152 HPLOT 106,109 TO 120,109 153 X% = 121:Y% = 87: REM X AND Y COOR FOR * 154 GOSUB 180: REM PRINT ASTER ISK We're drawing a bunch of stuff on the screen. I saw all of this on my non- working copy. ]LIST 180, 180 HPLOT X%,Y% TO X% + 4,Y% 181 HPLOT X% + 1,Y% + 2 TO X% + 3,Y% - 2 182 HPLOT X% + 1,Y% - 2 TO X% + 3,Y% + 2 183 RETURN More manual drawing. Continuing after line 154... ]LIST 155, 160 X% = 16:Y% = 30:A$ = "]COMPU TER": GOSUB 9900 ]LIST 9900, 9900 REM --DISPLAY HI-RES TEXT 9901 OX% = X%: GOSUB 9950:X% = O X%:Y% = Y% + 15:NX% = FRE ( 0): RETURN 9950 FOR II = 1 TO LEN (A$): POKE 30800 + II - 1, ASC ( MID$ ( A$,II,1)): NEXT : POKE 31340 , LEN (A$) 9952 POKE 31355,X%: POKE 30894, Y%: POKE 30897,S% 9953 POKE 30964,69 9954 CALL 23601 9956 RETURN Ah, I was right. Those binary files we loaded earlier are some sort of hi-res character generator. We're POKE-ing the strings into memory, one byte at a time, then CALL-ing the print routine on line 9954. But here's the really interesting part: this is where my non-working copy stopped working. It never prints the string "COMPUTER" in any hi-res font. The original disk does. So I think we are never returning from that CALL on line 9954. 23601 is $5C31 in hex, so let's BLOAD those files and see what's going on. ~ Chapter 3 If You Give an Apple a Byte ]BLOAD MPG CODE ]BLOAD FONT1 ]BLOAD FONT2 *5C31L 5C31- A9 00 LDA #$00 5C33- 20 00 7B JSR $7B00 5C36- 8D 6C 7A STA $7A6C *7B00L 7B00- 20 0F 5A JSR $5A0F *5A0FL 5A0F- AC 6C 7A LDY $7A6C 5A12- 99 50 78 STA $7850,Y 5A15- C8 INY 5A16- 8C 6C 7A STY $7A6C 5A19- 60 RTS Continuing from $7B03... 7B03- 20 1F 7C JSR $7C1F *7C1FL 7C1F- A2 FF LDX #$FF 7C21- 18 CLC 7C22- 3E 0F 7B ROL $7B0F,X 7C25- CA DEX 7C26- D0 FA BNE $7C22 7C28- 60 RTS Ah, decrypting the code in the caller! *7C1FG Continuing from $7B06... ; Overwrite the code that called this ; routine in the first place. The next ; time something CALLs this program, ; it will simply do its thing instead ; of redirecting to this protection ; check! 7B06- A9 0F LDA #$0F 7B08- 8D 34 5C STA $5C34 7B0B- A9 5A LDA #$5A 7B0D- 8D 35 5C STA $5C35 Everything after this was previously encrypted, but the subroutine at $7C1F decrypted it. *7B10L ; turn on drive motor manually 7B10- AE E9 B7 LDX $B7E9 7B13- BD 89 C0 LDA $C089,X ; wait for the drive to spin up 7B16- A9 FF LDA #$FF 7B18- 20 A8 FC JSR $FCA8 7B1B- A9 FF LDA #$FF 7B1D- 20 A8 FC JSR $FCA8 7B20- A9 FF LDA #$FF 7B22- 20 A8 FC JSR $FCA8 7B25- A9 FF LDA #$FF 7B27- 20 A8 FC JSR $FCA8 ; clear all status flags 7B2A- A9 00 LDA #$00 7B2C- 48 PHA 7B2D- 28 PLP 7B2E- D0 01 BNE $7B31 7B30- 4C 20 E3 JMP $E320 7B33- 03 ??? Fake. Since we just forcibly cleared all the status flags, including the Z flag, the "BNE" at $7B2E will always branch... into the middle of the next instruction! *7B31L 7B31- 20 E3 03 JSR $03E3 7B34- 85 01 STA $01 7B36- 84 00 STY $00 7B38- A0 01 LDY #$01 7B3A- D0 01 BNE $7B3D 7B3C- D0 B1 BNE $7AEF 7B3E- 00 BRK Fake. The "BNE" at $7B3A will always branch, because we just set Y=1. Execution continues at $7B3D, which is in the middle of an instruction again. I'll spare you the blow-by-blow, but there are a number of these. 14. There are 14 of these. *7B30:EA *7B3C:EA *7B42:EA *7B4C:EA *7B52:EA *7B5B:EA *7B63:EA *7B6A:EA *7B6D:EA *7B77:EA *7B7F:EA *7B86:EA *7B8E:EA *7B95:EA Whew. ~ Chapter 4 If You Give a Nibble a Bit And here is the entire copy protection routine, as unobfuscated as it can get: *7B10L ; turn on drive motor manually 7B10- AE E9 B7 LDX $B7E9 7B13- BD 89 C0 LDA $C089,X ; wait for the drive to spin up 7B16- A9 FF LDA #$FF 7B18- 20 A8 FC JSR $FCA8 7B1B- A9 FF LDA #$FF 7B1D- 20 A8 FC JSR $FCA8 7B20- A9 FF LDA #$FF 7B22- 20 A8 FC JSR $FCA8 7B25- A9 FF LDA #$FF 7B27- 20 A8 FC JSR $FCA8 ; clear all status flags 7B2A- A9 00 LDA #$00 7B2C- 48 PHA 7B2D- 28 PLP 7B2E- D0 01 BNE $7B31 7B30- EA NOP ; get address of RWTS parameter table 7B31- 20 E3 03 JSR $03E3 7B34- 85 01 STA $01 7B36- 84 00 STY $00 7B38- A0 01 LDY #$01 7B3A- D0 01 BNE $7B3D 7B3C- EA NOP ; get current slot from RWTS table 7B3D- B1 00 LDA ($00),Y 7B3F- AA TAX 7B40- D0 01 BNE $7B43 7B42- EA NOP ; turn on drive motor manually (again) 7B43- BD 89 C0 LDA $C089,X ; set up Death Counter 7B46- A9 56 LDA #$56 7B48- 85 00 STA $00 7B4A- D0 01 BNE $7B4D 7B4C- EA NOP 7B4D- 88 DEY 7B4E- D0 0C BNE $7B5C 7B50- F0 01 BEQ $7B53 7B52- EA NOP 7B53- C6 00 DEC $00 7B55- D0 05 BNE $7B5C All roads lead to $7B5C until the Death Counter in zp$00 hits 0. ; failure path branches to $7B96 7B57- A9 00 LDA #$00 7B59- F0 3B BEQ $7B96 7B5B- EA NOP ; execution continues here -- ; find a $BF nibble 7B5C- BD 8C C0 LDA $C08C,X 7B5F- 10 FB BPL $7B5C 7B61- D0 01 BNE $7B64 7B63- EA NOP 7B64- C9 BF CMP #$BF 7B66- F0 03 BEQ $7B6B 7B68- D0 E3 BNE $7B4D 7B6A- EA NOP 7B6B- F0 01 BEQ $7B6E 7B6D- EA NOP ; Read data latch exactly once (no BPL ; loop here!) and check its value. ; We're out of sync here because of all ; the branching, so the exact value of ; the data latch depends on timing bit ; after the $BF nibble. 7B6E- BD 8C C0 LDA $C08C,X 7B71- C9 08 CMP #$08 7B73- B0 D8 BCS $7B4D 7B75- D0 01 BNE $7B78 7B77- EA NOP ; find a $D5 nibble 7B78- BD 8C C0 LDA $C08C,X 7B7B- 10 FB BPL $7B78 7B7D- D0 01 BNE $7B80 7B7F- EA NOP 7B80- C9 D5 CMP #$D5 7B82- F0 03 BEQ $7B87 7B84- D0 C7 BNE $7B4D 7B86- EA NOP ; find an $AA nibble 7B87- BD 8C C0 LDA $C08C,X 7B8A- 10 FB BPL $7B87 7B8C- D0 01 BNE $7B8F 7B8E- EA NOP 7B8F- C9 AA CMP #$AA 7B91- F0 03 BEQ $7B96 7B93- D0 B8 BNE $7B4D 7B95- EA NOP ; both success and failure paths lead ; here -- ; turn off drive motor 7B96- DD 88 C0 CMP $C088,X ; check current nibble under the drive ; head (will only be $AA if we got here ; through the success path) 7B99- C9 AA CMP #$AA ; branch on success 7B9B- F0 13 BEQ $7BB0 ; failure path falls through to here -- ; switch to text page and display error ; message 7B9D- AD 51 C0 LDA $C051 7BA0- AD 54 C0 LDA $C054 7BA3- A2 00 LDX #$00 7BA5- BD B3 7B LDA $7BB3,X 7BA8- F0 66 BEQ $7C10 7BAA- 20 ED FD JSR $FDED 7BAD- E8 INX 7BAE- D0 F5 BNE $7BA5 7BB0- A9 00 LDA #$00 7BB2- 60 RTS 7BB3- "YOU HAVE ENCOUNTERED ERROR..." ; execution continues here (from $7BA8) ; after it finishes displaying the ; error message 7C10- 20 16 7C JSR $7C16 *7C16L ; re-encrypt protection check in memory 7C16- A2 00 LDX #$00 7C18- 7E 10 7B ROR $7B10,X 7C1B- E8 INX 7C1C- D0 FA BNE $7C18 7C1E- 60 RTS Continuing from $7C13... ; exit via DOS warm start 7C13- 4C D0 03 JMP $03D0 ...which is the behavior I saw on my non-working copy. ~ Chapter 5 If You Give a Caller a Bypass To sum up: This hi-res character generator has a built-in protection check that looks for the nibble sequence BF+ D5 AA where "+" is a timing bit. Nowhere in this routine does it seek to any specific track. Inspecting the original disk with a nibble editor, I see this nibble sequence at the start of every track! Just before the address prologue of sector 0, there is a $BF nibble with a timing bit. The protection check is only run once. As soon as it runs, it overwrites the calling code at $5C33 so future calls will bypass the protection check. That points to an obvious solution: bypass the protection check in exactly that way, but permanently. Turning to my trusty Disk Fixer sector editor, I search the disk for the JSR that called $7B00 ("20 00 7B") and find it on track $1A, sector $05 -- part of the "MPG CODE" file. T1A,S05,$3B: 007B -> 0F5A ]PR#6 ...works... ~ Chapter 6 ...He's Going to Want to Automate It I'm not sure if this was intentional, but the magic nibble sequence can be integrated into either DOS 3.2 or 3.3 disks. After the $BF+bit, the next two nibbles are the start of the address prologue ($D5 $AA), which are unchanged between DOS 3.2 and 3.3. I have six other SRA disks that use an identical protection scheme -- some DOS 3.2, others DOS 3.3. It seems that SRA reused this protection scheme across their product line for several years. And you know what that means... Automation! The next version of Passport will detect and defeat this protection. Re- running the updated Passport on this disk, the crack log looks like this: --v-- READING FROM S6,D1 T00,S00 FOUND DOS 3.2 BOOTLOADER USING DISK'S OWN RWTS WRITING TO S5,D2 T1A,S05 FOUND SRA PROTECTION CHECK T1A,S05,$3B: 007B -> 0F5A T00,S02 WRITING BUILT-IN RWTS T00,S01,$38: 20 -> 2C T00,S00 WRITING STANDARD DELIVERY BOOTLOADER CRACK COMPLETE. --^-- Quod erat liberandum. --------------------------------------- A 4am crack No. 1477 ------------------EOF------------------