Bank Street Writer III (Scholastic, 1986), by qkumba (14th December 2015) from http://www.hackzapple.com/phpBB2/viewtopic.php?t=980 This title is a fantastic word processor which was never cracked before. We start with a standard boot sector. 0800 .BYTE 1 0801 LDA #$60 0803 STA $0801 0806 LDA #$FF 0808 STA $04FB 080B STA $03F3 080E STA $03F4 0811 STA $C000 0814 STA $C002 0817 STA $C004 081A STA $C00C 081D STA $C00E 0820 STA $C081 0823 JSR $FB2F 0826 JSR $FC58 0829 JSR $FE84 082C JSR $FE93 082F JSR $FE89 0832 LDA $FBB3 0835 CMP #$06 0837 BNE $865 0839 LDA $FBC0 083C CMP #$E0 083E BNE $0865 0840 LDA $FBBF 0843 BNE $0865 0845 SEC 0846 JSR $FE1F 0849 BCS $0865 084B LDA $C034 084E AND #$F0 0850 STA $C034 0853 LDA #$F0 0855 STA $C022 0858 LDA #$80 085A STA $C021 085D LDA $C029 0860 ORA #$20 0862 STA $C029 0865 LDX $2B 0867 TXA 0868 LSR 0869 LSR 086A LSR 086B LSR 086C ORA #$C0 086E STA $0885 0871 LDA #$0F 0873 STA $50 0875 LDY $50 0877 LDA $88F,Y 087A STA $3D 087C LDA $089F,Y 087F BEQ $0886 0881 STA $27 0883 JSR $005C 0886 DEC $50 0888 BNE $0875 088A LDX $2B 088C JMP $1300 088F .BYTE 0, $D, $B, 9, 7, 5, 3, 1, $E, $C, $A, 8, 6, 4, 2, $F 089F .BYTE 0, $20, $21, $22, $23, $24, $10, $11, $12, $13, $14, 0, 0, 0, 0, 0 ... 08F5 .BYTE 'BANK STREET' It loads some sectors to $1000-14FF and $2000-24FF. Nothing special here. Here is the first protection check, just like in Prince of Persia. It was really very popular. 1300 LDA #$00 1302 LDX #$F0 1304 TXS 1305 STA $00,X 1307 INX 1308 BNE $1305 130A LDA #$0A 130C STA $FC 130E LDX $2B 1310 LDA $C089,X 1313 LDA $C08E,X 1316 LDA #$80 1318 STA $FD 131A DEC $FD 131C BEQ $138C Find sector #$0A address. 131E JSR $1396 1321 BCS $138C 1323 LDA $F9 1325 CMP #$0A 1327 BNE $131A Find the data prologue, and then check the E7 E7 E7 sequence. 1329 LDY #$00 132B LDA $C08C,X 132E BPL $132B 1330 DEY 1331 BEQ $138C 1333 CMP #$D5 1335 BNE $132B 1337 LDY #$00 1339 LDA $C08C,X 133C BPL $1339 133E DEY 133F BEQ $138C 1341 CMP #$E7 1343 BNE $1339 1345 LDA $C08C,X 1348 BPL $1345 134A CMP #$E7 134C BNE $138C 134E LDA $C08C,X 1351 BPL $134E 1353 CMP #$E7 1355 BNE $138C Desynch the read. 1357 LDA $C08D,X 135A LDY #$10 135C BIT $80 Then fetch some nibbles after that, which will look different because of the desynch. 135E LDA $C08C,X 1361 BPL $135E 1363 DEY 1364 BEQ $138C 1366 CMP #$EE 1368 BNE $135E 136A NOP 136B NOP 136C LDY #$07 136E LDA $C08C,X 1371 BPL $136E 1373 STA $F0,Y 1376 NOP 1377 DEY 1378 BPL $136E Use one of those nibbles as the decryption key. 137A LDY #$00 137C LDA $F4 137E EOR $1000,Y 1381 STA $1000,Y 1384 DEY 1385 BNE $137C Then jump to the decoded code. 1387 LDX $2B 1389 JMP $1000 The original sequence looks like E7 E7 E7 E7 E7 E7 E7 ... It is read as E7 E7 E7 ... EE E7 FC EE E7 FC EE EE FC. Normally, deprotection of this technique is done by patching the code so that it does not run at all. However, I decided to try a different approach, to make as few changes as possible to the code. For this protection, I made no changes to the code at all! Instead, I constructed a sector containing just the right data, so that it is interpreted properly despite the bit-slip. Specifically, I used this sequence: EE FF F3 FC E7 E7 EA 96 ... In binary, that looks like this: 11101110 11111111 11110011 11111100 11100111 11100111 11101010 10010110 ... After the bit-slip, it is read like this: EE FF FF E7 E7 EA 96 ... In binary, that looks like this: 11101111 11111111 00 11111111 00 11100111 11100111 11101010 10010110 ... This is the shortest sequence that I found, that re-synchs itself after the bit-slip, and which contains the decryption key ($E7) at the proper spot (5th position). It is also compatible with emulators that don't support bit-slip at all. Shortly after reaching $1000, we find this sequence: 1187 JSR sub_2000 118A .BYTE 2, 0, 1 Yes, it's RW18, seek to track 1, but first: 118D LDX $FD 118F TXA 1190 LSR 1191 LSR 1192 LSR 1193 LSR 1194 ORA #$C0 1196 STA $11B2 1199 LDA #$0F 119B STA $50 119D LDA #01 119F STA $0800 11A2 STA $41 11A4 LDY $50 11A6 LDA $11C7,Y 11A9 STA $3D 11AB LDA $11D7,Y 11AE STA $27 11B0 JSR $005C 11B3 DEC $50 11B5 BPL $11A4 11B7 STA $C005 11BA LDA #$B7 11BC LDY #$75 11BE LDX #3 11C0 JSR $1276 11C3 STA $C004 11C6 RTS 11C7 .BYTE $F, $D, $B, 9, 7, 5, 3, 1, $E, $C, $A, 8, 6, 4, 2, 0 11D7 .BYTE $BA, $B9, $B8, $B7, $B6, $B5, $B4, $B3, $B2, $B1, $B0, $AF, $AE, $AD, $AC, $AB Regular sectors are loaded to $AB00-BAFF. So track 1 is completely full. These two points are important for later. Now is the real RW18: 11F9 JSR $2000 11FC .BYTE $C3, $B, $40 11FF JSR $2000 1202 .BYTE $C3, $B, $52 1205 JSR $2000 1208 .BYTE $C3, $B, $64 120B JSR $2000 120E .BYTE $84, $B, $76, $77, $78, $79, $7A, $7B, $7C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 and so on. We end up with a map that looks like this, showing how it's read (as whole track or individual sectors), and where it's loaded (main or aux): 00 sec main 00 00 08 01 0d 20 02 0b 21 03 09 22 04 07 23 05 05 24 06 03 10 07 01 11 08 0e 12 09 0c 13 0a 0a 14 0b 08 protected 0c 06 unused 0d 04 unused 0e 02 unused 0f 0f unused 01 sec main 00 00 ab 01 0d b9 02 0b b8 03 09 b7 04 07 b6 05 05 b5 06 03 b4 07 01 b3 08 0e b2 09 0c b1 0a 0a b0 0b 08 af 0c 06 ae 0d 04 ad 0e 02 ac 0f 0f ba 02 trk main 00 40 01 41 02 42 03 43 04 44 05 45 06 46 07 47 08 48 09 49 0a 4a 0b 4b 0c 4c 0d 4d 0e 4e 0f 4f 10 50 11 51 03 trk main 00 52 01 53 02 54 03 55 04 56 05 57 06 58 07 59 08 5a 09 5b 0a 5c 0b 5d 0c 5e 0d 5f 0e 60 0f 61 10 62 11 63 04 trk main 00 64 01 65 02 66 03 67 04 68 05 69 06 6a 07 6b 08 6c 09 6d 0a 6e 0b 6f 0c 70 0d 71 0e 72 0f 73 10 74 11 75 05 sec main 00 76 01 77 02 78 03 79 04 7a 05 7b 06 7c 07 unused 08 unused 09 unused 0a unused 0b unused 0c unused 0d unused 0e unused 0f unused 10 unused 11 unused 06 trk aux 00 40 01 41 02 42 03 43 04 44 05 45 06 46 07 47 08 48 09 49 0a 4a 0b 4b 0c 4c 0d 4d 0e 4e 0f 4f 10 50 11 51 07 sec main 00 0b 01 0c 02 0d 03 11 04 12 05 13 06 14 07 15 08 16 09 17 0a 18 0b 19 0c 1a 0d 1b 0e 1c 0f 1d 10 1e 11 1f 08 sec main 00 40 01 41 02 42 03 43 04 44 05 45 06 46 07 47 08 48 09 49 0a 4a 0b 4b 0c 4c 0d 4d 0e 70 0f 71 10 72 11 73 09 trk main 00 74 01 75 02 76 03 77 04 78 05 79 06 7a 07 7b 08 7c 09 7d 0a 7e 0b 7f 0c 80 0d 81 0e 82 0f 83 10 84 11 85 0a trk main 00 86 01 87 02 88 03 89 04 8a 05 8b 06 8c 07 8d 08 8e 09 8f 0a 90 0b 91 0c 92 0d 93 0e 94 0f 95 10 96 11 97 0b trk main 00 98 01 99 02 9a 03 9b 04 9c 05 9d 06 9e 07 9f 08 a0 09 a1 0a a2 0b a3 0c a4 0d a5 0e a6 0f a7 10 a8 11 a9 0c trk main 00 aa 01 ab 02 ac 03 ad 04 ae 05 af 06 b0 07 b1 08 b2 09 b3 0a b4 0b b5 0c b6 0d b7 0e b8 0f b9 10 ba 11 bb 0d sec main 00 bc 01 bd 02 be aux 03 08 04 09 05 0a 06 0b 07 0c 08 0d 09 0e 0a 0f 0b 10 0c 11 0d 12 0e 13 0f 14 10 15 11 16 0e sec aux 00 17 01 18 02 19 03 1a 04 1b 05 1c 06 1d 07 1e 08 1f 09 42 0a 43 0b 44 0c 45 0d 46 0e 47 0f 48 10 49 11 4a 0f trk aux 00 4b 01 4c 02 4d 03 4e 04 4f 05 50 06 51 07 52 08 53 09 54 0a 55 0b 56 0c 57 0d 58 0e 59 0f 5a 10 5b 11 5c 10 trk aux 00 5d 01 5e 02 5f 03 60 04 61 05 62 06 63 07 64 08 65 09 66 0a 67 0b 68 0c 69 0d 6a 0e 6b 0f 6c 10 6d 11 6e 11 sec aux 00 6f 01 70 02 71 03 72 04 73 05 74 aux bank 2 06 d0 07 d1 08 d2 09 d3 0a d4 0b d5 0c d6 0d d7 0e d8 0f d9 10 da 11 db 12 sec aux bank 2 00 dc 01 dd 02 de 03 df aux bank 1 04 d0 05 d1 06 d2 07 d3 08 d4 09 d5 0a d6 0b d7 0c d8 0d d9 0e da 0f db 10 dc 11 dd 13 trk aux bank 1 00 de 01 df 02 e0 03 e1 04 e2 05 e3 06 e4 07 e5 08 e6 09 e7 0a e8 0b e9 0c ea 0d eb 0e ec 0f ed 10 ee 11 ef 14 sec aux bank 1 00 f0 01 f1 02 f2 03 f3 04 f4 05 f5 06 f6 07 f7 08 f8 09 f9 0a fa 0b fb 0c fc 0d fd 0e fe 0f ff 10 unused 11 unused 80 cols 15 sec main 00 0e 01 0f 02 10 03 4e 04 4f 05 50 06 51 07 52 08 53 09 54 0a 55 0b 56 0c 57 0d 58 0e 59 0f 5a 10 5b 11 5c 16 trk main 00 5d 01 5e 02 5f 03 60 04 61 05 62 06 63 07 64 08 65 09 66 0a 67 0b 68 0c 69 0d 6a 0e 6b 0f 6c 10 6d 11 6e 17 sec main 00 6f aux 01 40 02 41 40 cols main 03 0e 04 0f 05 10 06 4e 07 4f 08 50 09 51 0a 52 0b 53 0c 54 0d 55 0e 56 0f 57 10 58 11 59 18 trk main 00 5a 01 5b 02 5c 03 5d 04 5e 05 5f 06 60 07 61 08 62 09 63 0a 64 0b 65 0c 66 0d 67 0e 68 0f 69 10 6a 11 6b 19 sec main 00 6c 01 6d 02 6e 03 6f aux 04 40 05 41 06 unused 07 unused 08 unused 09 unused 0a unused 0b unused 0c unused 0d unused 0e unused 0f unused 10 unused 11 unused tools 1a sec(!) main 00 08 01 09 02 0a 03 0b 04 0c 05 0d 06 0e 07 0f 08 10 09 11 0a 12 0b 13 0c 14 0d 15 0e 16 0f 17 10 18 11 19 1b sec main 00 1a 01 1b 02 1c 03 1d 04 1e 05 1f 06 60 07 61 08 62 09 63 0a 64 0b 65 0c 66 0d 67 0e 68 0f 69 10 6a 11 6b 1c trk main 00 6c 01 6d 02 6e 03 6f 04 70 05 71 06 72 07 73 08 74 09 75 0a 76 0b 77 0c 78 0d 79 0e 7a 0f 7b 10 7c 11 7d 1d trk main 00 7e 01 7f 02 80 03 81 04 82 05 83 06 84 07 85 08 86 09 87 0a 88 0b 89 0c 8a 0d 8b 0e 8c 0f 8d 10 8e 11 8f 1e trk main 00 90 01 91 02 92 03 93 04 94 05 95 06 96 07 97 08 98 09 99 0a 9a 0b 9b 0c 9c 0d 9d 0e 9e 0f 9f 10 a0 11 a1 1f sec main 00 a2 01 a3 02 a4 03 a5 04 a6 05 a7 06 a8 07 a9 08 aa 09 ab 0a ac 0b ad 0c ae 0d unused 0e unused 0f unused 10 unused 11 unused 20 trk aux bank 2 00 e0 01 e1 02 e2 03 e3 04 e4 05 e5 06 e6 07 e7 08 e8 09 e9 0a ea 0b eb 0c ec 0d ed 0e ee 0f ef 10 f0 11 f1 21 unused 22 unused Yes, it's really using all of the main and auxilliary memory, including both banks of ROM on both sides. It's a wonder that there's any room left for typing actual text. :-) More importantly, tracks 02-$20 are RW18 format, meaning that the disk is really really full. We have another constraint besides the data size - the code size. We don't want to rewrite large portions of the loader, of we can avoid it. That's 558 sectors that we'd like to fit into 528 sectors... My first thought was to simply compress the title screen, which worked perfectly for Airheart, but alas the screen is already compressed here. Mostly, I wanted to avoid compressing everything because of the trouble to find enough memory for the decompression buffer. The Toy Shop and Prince of Persia conversions were really difficult. I didn't want to do it again, if I didn't have to. Let's try to lay it out in 16-sector format, showing the 16 sector position alongside the original RW18 sector position. 00 sec main 00 00 08 01 0d 20 02 0b 21 03 09 22 04 07 23 05 05 24 06 03 10 07 01 11 08 0e 12 09 0c 13 0a 0a 14 0b 08 protected 0c 06 unused 0d 04 unused 0e 02 unused 0f 0f unused 01 sec main 00 00 ab 01 0d b9 02 0b b8 03 09 b7 04 07 b6 05 05 b5 06 03 b4 07 01 b3 08 0e b2 09 0c b1 0a 0a b0 0b 08 af 0c 06 ae 0d 04 ad 0e 02 ac 0f 0f ba 02 trk main 00 00 40 01 01 41 02 02 42 03 03 43 04 04 44 05 05 45 06 06 46 07 07 47 08 08 48 09 09 49 0a 0a 4a 0b 0b 4b 0c 0c 4c 0d 0d 4d 0e 0e 4e 0f 0f 4f 03 trk main T02 00 10 50 01 11 51 T03 02 00 52 03 01 53 04 02 54 05 03 55 06 04 56 07 05 57 08 06 58 09 07 59 0a 08 5a 0b 09 5b 0c 0a 5c 0d 0b 5d 0e 0c 5e 0f 0d 5f 04 trk main T03 00 0e 60 01 0f 61 02 10 62 03 11 63 T04 04 00 64 05 01 65 06 02 66 07 03 67 08 04 68 09 05 69 0a 06 6a 0b 07 6b 0c 08 6c 0d 09 6d 0e 0a 6e 0f 0b 6f 05 sec main T04 00 0c 70 01 0d 71 02 0e 72 03 0f 73 04 10 74 05 11 75 T05 06 00 76 07 01 77 08 02 78 09 03 79 0a 04 7a 0b 05 7b 0c 06 7c 0d 07 unused 0e 08 unused 0f 09 unused Unused portion of T05 is discarded, allowing track 06 to be aligned naturally 06 trk aux T06 00 00 40 01 01 41 02 02 42 03 03 43 04 04 44 05 05 45 06 06 46 07 07 47 08 08 48 09 09 49 0a 0a 4a 0b 0b 4b 0c 0c 4c 0d 0d 4d 0e 0e 4e 0f 0f 4f A lucky break here: the next two sectors are duplicates of others, and can be discarded. 10 50 11 51 07 sec main T07 00 00 0b 01 01 0c 02 02 0d 03 03 11 04 04 12 05 05 13 06 06 14 07 07 15 08 08 16 09 09 17 0a 0a 18 0b 0b 19 0c 0c 1a 0d 0d 1b 0e 0e 1c 0f 0f 1d 08 sec main T07 00 10 1e 01 11 1f T08 02 00 40 03 01 41 04 02 42 05 03 43 06 04 44 07 05 45 08 06 46 09 07 47 0a 08 48 0b 09 49 0c 0a 4a 0d 0b 4b 0e 0c 4c 0f 0d 4d 09 trk main T08 00 0e 70 01 0f 71 02 10 72 03 11 73 T09 04 00 74 05 01 75 06 02 76 07 03 77 08 04 78 09 05 79 0a 06 7a 0b 07 7b 0c 08 7c 0d 09 7d 0e 0a 7e 0f 0b 7f 0a trk main T09 00 0c 80 01 0d 81 02 0e 82 03 0f 83 04 10 84 05 11 85 T0A 06 00 86 07 01 87 08 02 88 09 03 89 0a 04 8a 0b 05 8b 0c 06 8c 0d 07 8d 0e 08 8e 0f 09 8f 0b trk main T0A 00 0a 90 01 0b 91 02 0c 92 03 0d 93 04 0e 94 05 0f 95 06 10 96 07 11 97 T0B 08 00 98 09 01 99 0a 02 9a 0b 03 9b 0c 04 9c 0d 05 9d 0e 06 9e 0f 07 9f 0c trk main T0B 00 08 a0 01 09 a1 02 0a a2 03 0b a3 04 0c a4 05 0d a5 06 0e a6 07 0f a7 08 10 a8 09 11 a9 T0C 0a 00 aa 0b 01 ab 0c 02 ac 0d 03 ad 0e 04 ae 0f 05 af We only have room to perform a track read here, but with only 15 sectors, that doesn't work. Instead, we duplicate one sector, bringing us to 16 sectors, and then we're okay. 0d trk main T0C 00 05 af duped 01 06 b0 02 07 b1 03 08 b2 04 09 b3 05 0a b4 06 0b b5 07 0c b6 08 0d b7 09 0e b8 0a 0f b9 0b 10 ba 0c 11 bb T0D 0d 00 bc 0e 01 bd 0f 02 be Running out of code room, we have to convert this one from a sector read to a track read. 0e sec->trk aux T0D 00 03 08 01 04 09 02 05 0a 03 06 0b 04 07 0c 05 08 0d 06 09 0e 07 0a 0f 08 0b 10 09 0c 11 0a 0d 12 0b 0e 13 0c 0f 14 0d 10 15 0e 11 16 T0E 0f 00 17 0f sec aux T0E 00 01 18 01 02 19 02 03 1a 03 04 1b 04 05 1c 05 06 1d 06 07 1e 07 08 1f 08 09 42 09 0a 43 0a 0b 44 0b 0c 45 0c 0d 46 0d 0e 47 0e 0f 48 0f 10 49 10 trk aux T0E 00 11 4a Here is where we start to worry - we are behind by an entire track at this point, with only two tracks spare at the end, and not even halfway through the disk. T0F 01 00 4b 02 01 4c 03 02 4d 04 03 4e 05 04 4f 06 05 50 07 06 51 08 07 52 09 08 53 0a 09 54 0b 0a 55 0c 0b 56 0d 0c 57 0e 0d 58 0f 0e 59 11 trk aux 00 0f 5a 01 10 5b 02 11 5c T10 03 00 5d 04 01 5e 05 02 5f 06 03 60 07 04 61 08 05 62 09 06 63 0a 07 64 0b 08 65 0c 09 66 0d 0a 67 0e 0b 68 0f 0c 69 12 sec aux T10 00 0d 6a 01 0e 6b 02 0f 6c 03 10 6d 04 11 6e T11 05 00 6f 06 01 70 07 02 71 08 03 72 09 04 73 0a 05 74 aux bank 2 0b 06 d0 0c 07 d1 0d 08 d2 0e 09 d3 0f 0a d4 13 sec aux bank 2 T11 00 0b d5 01 0c d6 02 0d d7 03 0e d8 04 0f d9 05 10 da 06 11 db T12 07 00 dc 08 01 dd 09 02 de 0a 03 df aux bank 1 0b 04 d0 0c 05 d1 0d 06 d2 0e 07 d3 0f 08 d4 14 trk aux bank 1 T12 00 09 d5 01 0a d6 02 0b d7 03 0c d8 04 0d d9 05 0e da 06 0f db 07 10 dc 08 11 dd T13 09 00 de 0a 01 df 0b 02 e0 0c 03 e1 0d 04 e2 0e 05 e3 0f 06 e4 15 sec->trk aux bank 1 T13 00 07 e5 01 08 e6 02 09 e7 03 0a e8 04 0b e9 05 0c ea 06 0d eb 07 0e ec 08 0f ed 09 10 ee 0a 11 ef T14 0b 00 f0 0c 01 f1 0d 02 f2 0e 03 f3 0f 04 f4 Now we have to insert a sector read. The code room is getting really tight here. 16 sec aux bank 1 T14 00 05 f5 01 06 f6 02 07 f7 03 08 f8 04 09 f9 05 0a fa 06 0b fb 07 0c fc 08 0d fd 09 0e fe 0a 0f ff main T15 0b 00 0e 0c 01 0f 0d 02 10 0e 03 4e 0f 04 4f 80 cols 17 trk main T15 00 05 50 01 06 51 02 07 52 03 08 53 04 09 54 05 0a 55 06 0b 56 07 0c 57 08 0d 58 09 0e 59 0a 0f 5a 0b 10 5b 0c 11 5c T16 0d 00 5d 0e 01 5e 0f 02 5f 18 trk main T16 00 03 60 01 04 61 02 05 62 03 06 63 04 07 64 05 08 65 06 09 66 07 0a 67 08 0b 68 09 0c 69 0a 0d 6a 0b 0e 6b 0c 0f 6c 0d 10 6d 0e 11 6e T17 0f 00 6f Here is where we really start to worry (in case we weren't already) - we are behind by two entire tracks at this point, about to use both of the spare tracks. 19 sec aux T17 00 01 40 01 02 41 40 cols main 02 03 0e 03 04 0f 04 05 10 05 06 4e 06 07 4f 07 08 50 08 09 51 09 0a 52 0a 0b 53 0b 0c 54 0c 0d 55 0d 0e 56 0e 0f 57 0f 10 58 1a trk main T17 00 11 59 T18 01 00 5a 02 01 5b 03 02 5c 04 03 5d 05 04 5e 06 05 5f 07 06 60 08 07 61 09 08 62 0a 09 63 0b 0a 64 0c 0b 65 0d 0c 66 0e 0d 67 0f 0e 68 1b sec main T18 00 0f 69 01 10 6a 02 11 6b T19 03 00 6c 04 01 6d 05 02 6e 06 03 6f aux 07 04 40 08 05 41 tools There's a lucky break here - T19 is mostly unused, so we gain some sectors here, but not many, and not nearly enough. There's another lucky break - the track was read as sectors, so we have some code room available. main T1A 09 00 08 0a 01 09 0b 02 0a 0c 03 0b 0d 04 0c 0e 05 0d 0f 06 0e Again, running out of code room, we have to convert this one from a sector read to a track read. We're also back to being two tracks behind. 1c sec->trk main T1A 00 07 0f 01 08 10 02 09 11 03 0a 12 04 0b 13 05 0c 14 06 0d 15 07 0e 16 08 0f 17 09 10 18 0a 11 19 T1B 0b 00 1a 0c 01 1b 0d 02 1c 0e 03 1d 0f 04 1e 1d sec main T1B 00 05 1f 01 06 60 02 07 61 03 08 62 04 09 63 05 0a 64 06 0b 65 07 0c 66 08 0d 67 09 0e 68 0a 0f 69 0b 10 6a 0c 11 6b T1C 0d 00 6c 0e 01 6d 0f 02 6e 1e trk main T1C 00 03 6f 01 04 70 02 05 71 03 06 72 04 07 73 05 08 74 06 09 75 07 0a 76 08 0b 77 09 0c 78 0a 0d 79 0b 0e 7a 0c 0f 7b 0d 10 7c 0e 11 7d T1D 0f 00 7e 1f trk main T1D 00 01 7f 01 02 80 02 03 81 03 04 82 04 05 83 05 06 84 06 07 85 07 08 86 08 09 87 09 0a 88 0a 0b 89 0b 0c 8a 0c 0d 8b 0d 0e 8c 0e 0f 8d 0f 10 8e 20 trk main T1D 00 11 8f T1E 01 00 90 02 01 91 03 02 92 04 03 93 05 04 94 06 05 95 07 06 96 08 07 97 09 08 98 0a 09 99 0b 0a 9a 0c 0b 9b 0d 0c 9c 0e 0d 9d 0f 0e 9e 21 sec main T1E 00 11 9f T1F 01 00 a0 02 01 a1 03 02 a2 04 03 a3 05 04 a4 06 05 a5 07 06 a6 08 07 a7 09 08 a8 0a 09 a9 0b 0a aa 0c 0b ab 0d 0c ac T20 0e 00 ad 0f 01 ae 22 trk aux bank 2 T20 00 02 e0 01 03 e1 02 04 e2 03 05 e3 04 06 e4 05 07 e5 06 08 e6 07 09 e7 08 0a e8 09 0b e9 0a 0c ea 0b 0d eb 0c 0e ec 0d 0f ed 0e 10 ee 0f 11 ef F0 and F1? Two sectors short?! Oh so close. But wait - we have three sectors free in track 5, so we can just use those, right? No, we have no code room for another sector read. What else can we do? At this point, we have to get creative. Really creative. We need to find a way to make use of the sectors in track 5. For that, we need to piggyback on that read, using the same context (main vs auxilliary memory), because we can't spare any room to seek later. We can preload some sectors, but only use a memory location that won't be overwritten by something else that's read later. What does our memory map look like? Track 5 is a main memory read, but we can't preload the program code, because there aren't enough sectors already (we already had to duplicate one to fulfill a track read). That leaves the tool code. At the point where the tools request is checked, we have $0B00-1FFF, $4000-7CFF, $AB00-B9FF. There's also ProDOS which overwrites $0800-0AFF, and $BA00-BFFF. In the end, I grabbed the first two sectors of track $21 ($9E and $9F), moved them to track 5, so now track $21 looks like this: 21 sec main T1E 00 11 a1 T1F 01 00 a2 02 01 a3 03 02 a4 04 03 a5 05 04 a6 06 05 a7 07 06 a8 08 07 a9 09 08 aa 0a 09 ab 0b 0a ac 0c 0b ad 0d 0c ae aux bank 2 T20 0e 00 e0 0f 01 e1 22 trk aux bank 2 T20 00 02 e2 01 03 e3 02 04 e4 03 05 e5 04 06 e6 05 07 e7 06 08 e8 07 09 e9 08 0a ea 09 0b eb 0a 0c ec 0b 0d ed 0c 0e ee 0d 0f ef 0e 10 f0 0f 11 f1 It fits, with a whole sector to spare. :-) As far as the code goes, we change this: 11FF JSR $2000 1202 .BYTE $C3, $B, $52 1205 JSR $2000 1208 .BYTE $C3, $B, $64 120B JSR $2000 120E .BYTE $84, $B, $76, $77, $78, $79, $7A, $7B, $7C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 to this: 11FF JSR $2000 1202 .BYTE $C3, $B, $50 1205 JSR $2000 1208 .BYTE $C3, $B, $60 120B JSR $2000 120E .BYTE $84, $B, $70, $71, $72, $73, $74, $75, $76, $77, $78, $79, $7A, $7B, $7C, 0, $9F 120E .BYTE $A0, 0, 0 This one carries the two pre-loaded sectors. From this (running from auxilliary memory, hence the >64kb address): 12577 JSR $2000 1257A .BYTE $C4, 3, $B, $C, $D, $11, $12, $13, $14, $15, $16, $17, $18, $19, $1A, $1B, $1C 1257A .BYTE $1D, $1E, $1F to this: 12577 JSR $2000 1257A .BYTE $C4, 3, $B, $C, $D, $11, $12, $13, $14, $15, $16, $17, $18, $19, $1A, $1B, $1C 1257A .BYTE $1D, 0, 0 From this: 1258E JSR $2000 12591 .BYTE $C4, 3, $40, $41, $42, $43, $44, $45, $46, $47, $48, $49, $4A, $4B, $4C, $4D, $70 12591 .BYTE $71, $72, $73 125A5 JSR $2000 125A8 .BYTE $C3, 3, $74 125AB JSR $2000 125AE .BYTE $C3, 3, $86 to this: 1258E JSR $2000 12591 .BYTE $C4, 3, $1E, $1F, $40, $41, $42, $43, $44, $45, $46, $47, $48, $49, $4A, $4B, $4C 12591 .BYTE $4D, 0, 0 125A5 JSR $2000 125A8 .BYTE $C3, 3, $70 125AB JSR $2000 125AE .BYTE $C3, 3, $80 From this: 125BB JSR $2000 125BE .BYTE $C3, 3, $98 125C1 JSR $2000 125C4 .BYTE $C3, 3, $AA 125C7 JSR $2000 125CA .BYTE $84, 3, $BC, $BD, $BE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 to this: 125BB JSR $2000 125BE .BYTE $C3, 3, $90 125C1 JSR $2000 125C4 .BYTE $C3, 3, $A0 125C7 JSR $2000 125CA .BYTE $C3, 3, $AF 125CD BRA $125E9 This introduces some code room which we will use later. From this: 125DE JSR $2000 125E1 .BYTE $C4, $83, 0, 0, 0, 8, 9, $A, $B, $C, $D, $E, $F, $10, $11, $12, $13, $14, $15 125E1 .BYTE $16 125F5 JSR $2000 125F8 .BYTE $C4, $83, $17, $18, $19, $1A, $1B, $1C, $1D, $1E, $1F, $42, $43, $44, $45, $46 125F8 .BYTE $47, $48, $49, $4A 1260C JSR $2000 1260F .BYTE $C3, $83, $4B 12612 JSR $2000 12615 .BYTE $C3, $83, $5D 12618 JSR $2000 1261B .BYTE $C4, $83, $6F, $70, $71, $72, $73, $74, $D0, $D1, $D2, $D3, $D4, $D5, $D6, $D7 1261B .BYTE $D8, $D9, $DA, $DB 1262F JSR $2000 12632 .BYTE $84, $83, $DC, $DD, $DE, $DF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 12646 JSR $2000 12649 .BYTE $C4, $8B, 0, 0, 0, 0, $D0, $D1, $D2, $D3, $D4, $D5, $D6, $D7, $D8, $D9, $DA, $DB 12649 .BYTE $DC, $DD 1265D JSR $2000 12660 .BYTE $C3, $8B, $DE 12663 JSR $2000 12666 .BYTE $C4, $8B, $F0, $F1, $F2, $F3, $F4, $F5, $F6, $F7, $F8, $F9, $FA, $FB, $FC, $FD 12666 .BYTE $FE, $FF, 0, 0 to this: 125E9 JSR $2000 125EC .BYTE $C3, $83, 8 125EF JSR $2000 125F2 .BYTE $C4, $83, $18, $19, $1A, $1B, $1C, $1D, $1E, $1F, $42, $43, $44, $45, $46, $47 125F2 .BYTE $48, $49, 0, 0 12606 JSR $2000 12609 .BYTE $C3, $83, $4A 1260C JSR $2000 1260F .BYTE $C3, $83, $5A 12612 JSR $2000 12615 .BYTE $C4, $83, $6A, $6B, $6C, $6D, $6E, $6F, $70, $71, $72, $73, $74, $D0, $D1, $D2 12615 .BYTE $D3, $D4, 0, 0 12629 JSR $2000 1262C .BYTE $84, $83, $D5, $D6, $D7, $D8, $D9, $DA, $DB, $DC, $DD, $DE, $DF, 0, 0, 0, 0, 0 1262C .BYTE 0, 0 12640 JSR $2000 12643 .BYTE $C4, $8B, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, $D0, $D1, $D2, $D3, $D4, 0, 0 12657 JSR $2000 1265A .BYTE $C3, $8B, $D5 1265D JSR $2000 12660 .BYTE $C3, $8B, $E5 12663 JSR $2000 12666 .BYTE $84, $8B, $F5, $F6, $F7, $F8, $F9, $FA, $FB, $FC, $FD, $FE, $FF, 0, 0, 0, 0, 0 12666 .BYTE 0, 0 The changes are relatively minor there, despite the large block that contains them. From this: 12683 JSR $2000 12686 .BYTE $C4, 3, $E, $F, $10, $4E, $4F, $50, $51, $52, $53, $54, $55, $56, $57, $58, $59 12686 .BYTE $5A, $5B, $5C 1269A JSR $2000 1269D .BYTE $C3, 3, $5D 126A0 JSR $2000 126A3 .BYTE $84, 3, $6F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 to this: 12683 JSR $2000 12686 .BYTE $C4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, $E, $F, $10, $4E, $4F, 0, 0 1269A JSR $2000 1269D .BYTE $C3, 3, $50 126A0 JSR $2000 126A3 .BYTE $C3, 3, $60 126A6 BRA $126B7 This introduces more code room that we will use later. From this: 126D3 JSR $2000 126D6 .BYTE $C4, 3, 0, 0, 0, $E, $F, $10, $4E, $4F, $50, $51, $52, $53, $54, $55, $56, $57 126D6 .BYTE $58, $59 126EA JSR $2000 126ED .BYTE $C3, 3, $5A 126F0 JSR $2000 126F3 .BYTE $84, 3, $6C, $6D, $6E, $6F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 12707 JSR $2000 1270A .BYTE $84, $83, 0, 0, 0, 0, $40, $41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 to this: 126D3 JSR $2000 126D6 .BYTE $C4, 3, 0, 0, $E, $F, $10, $4E, $4F, $50, $51, $52, $53, $54, $55, $56, $57, $58 126D6 .BYTE 0, 0 126EA JSR $2000 126ED .BYTE $C3, 3, $59 126F0 JSR $2000 126F3 .BYTE $84, 3, $69, $6A, $6B, $6C, $6D, $6E, $6F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 12707 JSR $2000 1270A .BYTE $84, $83, 0, 0, 0, 0, 0, 0, 0, $40, $41, 0, 0, 0, 0, 0, 0, 0, 0, 0 This one is just a slight shift in the position of the sectors in the array. From this: 12722 LDA #$1A 12724 STA $FE 12726 JSR $2000 12729 .BYTE $C4, 3, 8, 9, $A, $B, $C, $D, $E, $F, $10, $11, $12, $13, $14, $15, $16, $17, $18 12729 .BYTE $19 1273D JSR $2000 12740 .BYTE $C4, 3, $1A, $1B, $1C, $1D, $1E, $1F, $60, $61, $62, $63, $64, $65, $66, $67, $68 12740 .BYTE $69, $6A, $6B 12754 JSR $2000 12757 .BYTE $C3, 3, $6C 1275A JSR $2000 1275D .BYTE $C3, 3, $7E 12760 JSR $2000 12763 .BYTE $C3, 3, $90 12766 JSR $2000 12769 .BYTE $C4, 3, $A2, $A3, $A4, $A5, $A6, $A7, $A8, $A9, $AA, $AB, $AC, $AD, $AE, 0, 0 12769 .BYTE 0, 0, 0 1277D JSR $2000 12780 .BYTE $83, $83, $E0 to this: 12726 JSR $2000 12729 .BYTE $C4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, $A, $B, $C, $D, $E, 0, 0 1273D JSR $2000 12740 .BYTE $C3, 3, $F 12743 JSR $2000 12746 .BYTE $C4, 3, $1F, $60, $61, $62, $63, $64, $65, $66, $67, $68, $69, $6A, $6B, $6C, $6D 12746 .BYTE $6E, 0, 0 1275A JSR $2000 1275D .BYTE $C3, 3, $6F 12760 JSR $26A8 12763 JSR $2000 12766 .BYTE $C4, 3, $A1, $A2, $A3, $A4, $A5, $A6, $A7, $A8, $A9, $AA, $AB, $AC, $AD, $AE, 0 12766 .BYTE 0, 0, 0 1277A JSR $25CF 1277D JSR $2000 12780 .BYTE $83, $83, $E2 Here we see the two code rooms being used. 126A8 JSR $2000 126AB .BYTE $C3, 3, $7F 126AE JSR $2000 126B1 .BYTE $C3, 3, $8F 126B4 RTS and 125CF JSR $2000 125D2 .BYTE $C4, $83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, $E0, $E1, 0, 0 125E6 RTS It fits, with four whole bytes to spare. :-) Specifically, I used this sequence: EE FF F3 FC E7 E7 EA 96 ... ... After the bit-slip, it is read like this: EE FF FF E7 E7 EA 96 ... ... This is the shortest sequence that I found, that re-synchs itself after the bit-slip, and which contains the decryption key ($E7) at the proper spot (5th position). In fact, all I needed was for the sequence to begin with: FF F3 FC (11111111 11110011 11111100) It would be read as FF FF (11111111 00 11111111 00) Thereafter, it would be synchronised, and the EE xx xx xx E7 pattern would be the same for both cases. It would also work around the current bug in MAME that skips one extra bit and can't find the EE.