' +JJJJ ?\>m0M='+l> /+l  H d@hLҦ L~ L  ﵪ*i BB䵊嵰`72µ- i ư&( Rp s P  LLʬLoō 鷎귭෍ᷩ췩緈JJJJx Lȿ L8ᷭ緍췩 緍i 8 `巬 췌`x (`(8`I`B` ``>J>J>VU)?`8'x0|&HhHh VY)'&Y)xꪽ)' `Hh`V0^*^*>&` aI꽌ɪVɭ&Y&&Y& 꽌ɪ\8`&&꽌ɪɖ'*&%&,E'зЮ꽌ɪФ`+*xS&x'8*3Ixix&& 8  '  & x)*++`NG8`0($ p,&" ۿ ۿڿL흍ٿ vLQ  !"#$%&'()*+,-./0123456789:;<=>?  ( 9 +"  "*  (9"1 ( ,.(0# 2  /#0/#0 *?'#07#00/0/'#07#0:"4<*55/**5/*%5/)1/)1/)1/)'#0/#0*5/*75/**5/*:5//#0/#0'#07#0:::*::'#07#0).).*#!.*'!.8)(#/-)(#/-,,eb)++$ h( ,!!"@h !D)"E` @ $ C ` DQ &J80^݌Hh ü ü݌ ռ ռ ռA ļD ļ? ļAEDE?HJ>h Լ ռ ռ ռ`HJ>݌h Hh݌`HH ᥠ L\HIHHHHhHH݌hHhHh݌H6 VDP (FD Z $0x8x D- ܸDD# H8`?F Vk *f???0xF Hh D#-FFF8` D ܸx D - ܸx8`-0ݩ?ʥD FFF`   LDcpq` [` ~  L IH  /JJJJ"L뷩 ᷩ췩 ɛ LDLSAVBPILOCUNLOCIBPIBPIBPPRBPIBLISCALBPIBUZZOFӜsqu`".Q`pNФbptťܥm2<(-Py0\|e<6e< ~ vL~ JJJJj귍hI  aUL@ kU8  L  ^R(jQ0l^l\  OÌȌ`W ԧ H h@ [_ /QSIRb_L`LLLL`ª`LQL߼YLeLXLeLee ўQ0 L&RE;BY; Ꝥ$`( R \ZLl8 ўR HH\`\Z[YS6`LxQɿu3'RͲʎRʎ]]]ɍuL͟ɍ}RLRɍg^H8 ^hZLɍR LͲɊRR% QLܤͲ Z@ -^ ş\[Z QY\[Z8`l6Lş_Ȍb_Ͳ] )Y h( ֭ͲLɍ [LLĦ__ ^ 9 LҦ3 9 a   0LjLY u< (_9 ˭ɠuɠK_9 ?LˆʎõĵL õ ĵµ aµ`` L̦µ_bJLuLz`  ȟ QlXJ̥KlV  ȟ QlV eօ3L׭Lܫ &RL &QL d L4 We)n `@-eff L f`L . tQLѤ LҦL` OPu d L Ne)noon 8ɍ` ^f\õL ^NR  RΩLҦ\L \ şL_ NLjHv 3h`0h8` [L NС õ`A@` ŵL]Lõ`  \ 濭0 ş  Q ^\lZl^\8  ş Lȟ`fhjõĵ@OAP`u@`@&`QR`F Ls  @DAF@u`8` %@ @A@`@`@A`Mµ ) LЦ`8@AWc@8@-@HAȑ@hHȑ@ȑ@hHȑ@Ȋ@ch8&ȑ@Hȑ@Ah@LHȑ@ȑ@ htphso`hMhL`9V8U897T6S67`INILOASAVRUCHAIDELETLOCUNLOCCLOSREAEXEWRITPOSITIOOPEAPPENRENAMCATALOMONOMOPRINMAXFILEFINBSAVBLOABRUVERIF!pppp p p p p`" t""#x"p0p@p@@@p@!y q q p@ ,\Z[PRR3\ɄSɊ"RQJ(0Fw6. ^-%p 㩠RP.Q I* P\L˵B̵C8pB߮Z\ @ յյ\BIR Z-^ Jp\IZLLӜv  Ϡ@跻~!Wo*9~~~~ɬƬ~_ j ʪHɪH`Lc (L ܫ㵮赎 ɱ^_ J LsL Q(`贩紎 DǴҵԵƴѵӵµȴ 7 ַ :ŵƴѵǴҵȴµ納贍﵎ٵ്ᵭⳍڵL^ѵ-I `  4 ò-յ!  8صٵ紭ﵝ 7L (0+BC  7L HH`LgL{0 HH` õL H hBL BH [ h`Lo õ ڬL B ڬ LH hB@ յյ [L (ȴ) ȴ 7L L ( L (ȴL{ƴѵ洩ƴǴҵ 7 ^* B0 HȱBh ӵԵ 8 L8 ݲ` ܫ  / / şFD B / / ]ƴS0Jȴ ȴ)  紅D贅F B ƴ  / 0L Ν `ND8HFFhDh N ş`, ŵBѵ`, ѵB8`  XI볩쳢8 DH E𳈈췍Ȍ X0 · JLǵBȵC`,յp` 䯩 R-յյ`յ0` K R-յյ`ɵʵӵԵ` 4 K ( ѵҵLBȱBL8` DBHBH : ַ޵BȭߵBhhӵԵ RBܵmڵ޵ȱBݵm۵ߵ` 䯩LR˵̵ֵ׵`LzĪLR E( 8` R` ELRŪƪ`췌 յյI뷭鷭귭ⵍ㵍跬ª 뷰` Lf ݵܵߵ޵ ^`8ܵ i B8` 4L ֵȱB׵ ܯ䵍൭嵍 ` DȑB׵Bֵ  ַ յյ`` ᥠ hh`ĵµ`ڿ8.ڿ.ۿ`êL`õĵBCõĵ`µµ`L õBĵCصص Qƴ0"Bƴ 󮜳` 0۰ϬBƴ8`i#`ЗLw!0>ﵭ` m ﳐ 7i볍 8 ЉLw`H h ݲL~ `浍국䵍뵩嵠Jm赍嵊mjnnn浈ۭm浍浭m䵍䵩m嵍`"L ŵ8ŵH x(`F d£àĠz# u` @@A` @A@  B C BBCLCLfBL ީLhh`LLN7ɿLݍҭ -A@@i@@@i@AAݣ@ݢΩDDLeA@@lL /?@Hɷ@#@h@!ɵ@ɥͰi+hɝi@@/8e@@DAA͈@̈DDL܇@BA݅C@BAC濽տ`xxlt]iVȿQkKRE;BY;LꍁlL<ԍL WLHr7s8 LH HLݍ ,,(`l8 LH e UL׉ LH LH,, sL,,, t鍁` H `Le HL H LL H QL H Llש B\ȹ'ȹ' (LRANGWRITE PROEND DATFILE NOT FOUNVOLUMI/O ERDISK FULLOCKESYNTANO BUFFETYPE MISMATCTOO LARGNOT DIREC q`QrU`)`\N|Lي80ʭ) $% B橠 B  ` L߭ɍ_LةحW`8& 9ʩ8`WL () ~ۭ N N L,H whLZ؍^؍_`$,,L`hhhL٭0 ,0L,Ƀɛɍ8ɠnɻɺ: n(8l mnحuIn Lw8n {۠u  {ۥgh,,0۬ۍ،؍La8 L߭ u ب H بh,8m l بNۘHج,8۰h Z wةͼH h بLZ8Ѕυ Z0 Z LڭٍَٺHץ9ɾIn0 hH )? @(I7n׽Nשn I-- h+( ,,0 ,Hّ(ho Lލ ׭,0 )?( Ɉoɀ@MםH Ihh0 Lڊʰڍ,עLڍhhیڬ<۠x )ڠ8۬ڰ(HH `ȹ0,Ȍ ɍ  ɠ )?, @, LB LƠ LLւ&LݩLL#B B!P`L FORMAT TARGET DISK ...grind grind grind... --> CONVERT DISK This disk is 16 sectors, and I want to copy from track 03 sector 00 to track 21 sector 0F. (Track $22 it. It's time to use Advanced Demuffin to make a standard DOS 3.3-readable disk. ]BLOAD TLR A000-BFFF,A$2000 ]BSAVE TLR RWTS,A$2800,L$800 Put work disk in S6D1 and reboot ]PR#6 ]BRUN ADVANCED DEMUFFIN 1.1 --> LOAD NEW RWTS MODULE At $B8, load "TLR to have no ill effects. Now I think I have everything I need. A bit of spot checking confirms that the code that was loaded into $A000..$BFFF is indeed a full DOS 3.3. Not just an RWTS, but a full DOS. I know where the nibble check is and how to disable F 9702- 4C 01 08 JMP $0801 ; disable nibble check 9705- A9 60 LDA #$60 9707- 8D 00 05 STA $0500 ; continue boot, no more interruptions 970A- 4C 73 04 JMP $0473 The game still boots; skipping the nibble check entirely appearses that if execution returns, everything is OK. So I can most likely just skip the check and continue. ; interrupt boot after T0S0 96F8- A9 97 LDA #$97 96FA- 8D 18 08 STA $0818 96FD- A9 04 LDA #$04 96FF- 8D 3F 08 STA $083 RTS 0578- C6 2A DEC $2A 057A- D0 99 BNE $0515 Yep, that's a nibble check. If the check fails, execution falls through to $057C, a.k.a. The Badlands, which wipes all memory and reboots. There is no return code; the caller just assumF4 BNE $055D 0569- A0 07 LDY #$07 056B- BD 8C C0 LDA $C08C,X 056E- 10 FB BPL $056B 0570- D1 48 CMP ($48),Y 0572- D0 04 BNE $0578 0574- 88 DEY 0575- 10 F4 BPL $056B 0577- 60 6- BD 8D C0 LDA $C08D,X 0559- A0 10 LDY #$10 055B- 24 06 BIT $06 055D- BD 8C C0 LDA $C08C,X 0560- 10 FB BPL $055D 0562- 88 DEY 0563- F0 13 BEQ $0578 0565- C9 EE CMP #$EE 0567- D0 BD 8C C0 LDA $C08C,X 0547- 10 FB BPL $0544 0549- C9 E7 CMP #$E7 054B- D0 2B BNE $0578 054D- BD 8C C0 LDA $C08C,X 0550- 10 FB BPL $054D 0552- C9 E7 CMP #$E7 0554- D0 22 BNE $0578 055D5 0534- D0 F4 BNE $052A 0536- A0 00 LDY #$00 0538- BD 8C C0 LDA $C08C,X 053B- 10 FB BPL $0538 053D- 88 DEY 053E- F0 38 BEQ $0578 0540- C9 E7 CMP #$E7 0542- D0 F4 BNE $0538 0544- LDA $2D 0524- C9 0D CMP #$0D 0526- D0 F1 BNE $0519 0528- A0 00 LDY #$00 052A- BD 8C C0 LDA $C08C,X 052D- 10 FB BPL $052A 052F- 88 DEY 0530- F0 46 BEQ $0578 0532- C9 D5 CMP #$ 02 LDA #$02 0513- 85 49 STA $49 0515- A9 80 LDA #$80 0517- 85 2B STA $2B 0519- C6 2B DEC $2B 051B- F0 5B BEQ $0578 051D- 20 44 B9 JSR $B944 0520- B0 56 BCS $0578 0522- A5 2D 00) is a nibble check. 0500- A9 0A LDA #$0A 0502- 85 2A STA $2A 0504- AE E9 B7 LDX $B7E9 0507- BD 89 C0 LDA $C089,X 050A- BD 8E C0 LDA $C08E,X 050D- A9 AC LDA #$AC 050F- 85 48 STA $48 0511- A9finally pushes an address to the stack and "returns" to it. 049E- A9 B7 LDA #$B7 04A0- 48 PHA 04A1- A9 01 LDA #$01 04A3- 48 PHA 04A4- 60 RTS I'd bet good money that the routine at $0200 (previously $05 BNE $048B It reads a single sector using the standard DOS 3.3 RWTS entry point... 0494- A9 B7 LDA #$B7 0496- A0 E8 LDY #$E8 0498- 20 B5 B7 JSR $B7B5 Calls the relocated subroutine... 049B- 20 00 02 JSR $0200 And - A5 FC LDA $FC 0482- 99 78 04 STA $0478,Y 0485- 4A LSR 0486- 8D 78 04 STA $0478 0489- A0 00 LDY #$00 048B- B9 00 05 LDA $0500,Y 048E- 99 00 02 STA $0200,Y 0491- 88 DEY 0492- D0 F7 00.BFFFM *C500G ... ]BSAVE TLR A000-BFFF,A$2000,L$2000 Returning where I left off in the $0400 range, the bootloader continues with some more RWTS-related initialization, then moves an entire page from $0500 to $0200. 047D- 20 8E BE JSR $BE8E 0480cks 1 and 2 into $A000..$BFFF. Combined with the three sectors from track 0 in $9D00..$9FFF, that would be enough to make... an entire copy of DOS 3.3 (or some semblance thereof). Hmm. Anyway, I'll save it to the work disk and sort it out later. *2000J>J>VU)?`8'x0|&HhHh VY)'&Y)xꪽ)' `Hh`V0^*^*>&` aI꽌ɪVD# H8`?E Vk *f???0xE Hh D#-EEE8` D ܸx D - ܸx8`-0ݩ?ʥD EEE`   d@ŵLҦL [` ~ hh@(LH9LHH/Hh/ H-З( ܸ(& ¸$8 H` *HVDP (ED Z $0x8x D- ܸDHIHHHHhHH݌hHhHh݌H6 h Լ ռ ռ ռ`HJ>݌h Hh݌`<=>?xH  hx`X<-2  4  2 2 #<* `FG8`0($ p,&" 0ʎ `/  !"#$%&'()*+,-./0123456789:;&Y&&Y&ސ 꽌ɪ\8`&&꽌ɪɖ'*&%&,E'зސ꽌ɪ`+*xS&x'8*3Ixix&& 8  '  & x)*++8>J>J>VU)?`8'x0|&HhHh VY)'&Y)xꪽ)' `Hh`V0^*^*>&` aI꽌ɪV     an later JSR ($3E) (OK, that's not a real instruction, but you can fake it by calling a local subroutine that ends with an indirect jump) to read other sectors from track 0. $083E..$0840: push $72 to stack (suspicious) $0841..$0844: put $00 in zero page to reboot $0817..$0819: push $04 to stack (suspicious) $081A..$0834: initialize text screen, JSR to $08A0 which zaps hi-res page 1, show hi-res page 1 $0835..$083D: put $5C in zero page $3E, put RTS into $0801. This sets up a situation where the code c boot tracing... S6D1 = Ten Little Robots original disk S5D1 = my work disk ]CALL -151 *9600VDP (ED Z $0x8x D- DLHIHHHHhHH݌hHhHh݌H6 h    `HJ>݌h Hh݌` ﶵBD <=>?>>!`FG8`0($ p,&"h8 흠 BȱBȭۿHۿ ȿL߼  !"#$%&'()*+,-./0123456789:;&Y&&Y& 꽌ɪ\8`&&꽌ɪɖ'*&%&,E'зЮ꽌ɪФ`+*xS&x'8*3Ixix&& 8  '  & x)*++>J>J>VU)?`8'x0|&HhHh    VY)'&Y)xꪽ)'     `Hh`V0^*^*>&` aI꽌ɪVJ"#' *LΠ٠ŠˠԠDZàϠƠ٠Ϡ֠Ӡ٠٠ϠŽԠŠĠӠԠԠĠӠΠŠġӠӢϠԠҬâϠJi# c NO SUCH BINARY FILE EXISTS! L08"'&"#* &` c PLEASE INSERT CORRECT DISK CORRECTLY IN THE CORRECT DRIVE AND PRESS Q ɍLYI`ĠΠԠL X c LOAD IOB MODULE- 0'   ;L c PLEASE TYPE THE NAME OF THE FILE TO LOAD FILE: c _ Q Ɉɍ'ɠ  c  c PL c ,D_ Q ɱɲ ) K 4 +. JJ)ȱJ!JHȱJh9! *!B c UNABLE TO FORMAT! PRESS RETURN TO GO BACK TO MENU Q ɍL X c LOAD RWTS MODULE- PAGE TO LOAD AT (MUST BE A 2-DIGIT HEX NUMBER):   L  Ɉ L LL c 0L''J ;''ɿJh`K H Kh`) ɺi``/`،#'J" * *+E8@' c  Q hh L 0'` X c FORMAT DISK IN DRIVE: _ Q ɱɲ )  c INSERT DISK AND PRESS RETURN Q ɍ* `KJ ɮAJ   Ɉ3 LHJ JhJJ$ c P  ɈJJJJJIJJ*JJ  (KJJJJJJ JJ J`JJ J`JJJJ JJ J` c _ Q ɍɮɈɰǰɺ)H h(`H Q ɸLɱIp76 c 80NJ J G&J (J c Lɛ`,ɛ`hhLh&h'&'&H h'H&H`i G'&)?&`'& )&`LHJh``i GJi&&` GJi& 婮 LG 0к m(  L K Q ɍ  I K 3 06. m( KKL P c  c TRK: +.5: 0123456789ABCDEF0123456789ABCDEF0123SC0: SC1: SC2: SC3: SC4: SC5: SC6: SC7: SC8: SC9: SCA: SCB: SCC:  c SCD: SCE: SCFKn Q ɍ  I K  KK ND SECTOR: $  2* c BACKWARDS COPYING NOT SUPPORTEDL c INCREMENT:  c P c MAX # OF RETRIES: _   c COPY FROM DRIVE 1 TO DRIVE: Q ɱɲ) X) c INSERT DISKS AND PRESS RETURN Q ɍ XLLUȌȌD c CHANGE DEFAULT VALUES Q L X c INPUT ALL VALUES IN HEX SECTORS PER TRACK? (13/16) 1_ Q ɳɶ  c START TRACK:   c START SECTOR: $  c END TRACK:   c Exة67  / X'(P"# X c MAIN MENU: CONVERT DISK LOAD NEW RWTS MODULE LOAD NEW IOB MODULE FORMAT TARGET DISK EXIT TO MONITOR Q ɍɈɕ  ޢ X / XX LYL         z#??    ҠӠ ΠŠӠ͠˩\ ŲųҠƠ"ĠΠ ĠΠӠE ĠΠŠ ĠΠȠӠBϠŰҠ԰ӰűҠƠҠƠ ҠİƠ0456- A8 TAY 0457- B9 80 C0 LDA $C080,Y 045A- A9 30 LDA #$30 045C- 20 A8 FC JSR $FCA8 045F- 68 PLA 0460- A8 TAY 0461- 68 PLA 0462- 60 RTS $0400..$0404: load X with the current 2B ORA $2B 0446- A8 TAY 0447- B9 81 C0 LDA $C081,Y 044A- A9 30 LDA #$30 044C- 20 A8 FC JSR $FCA8 044F- A5 FD LDA $FD 0451- 29 03 AND #$03 0453- 0A ASL 0454- 05 2B ORA $2B 436- 48 PHA 0437- 98 TYA 0438- 48 PHA 0439- A5 FC LDA $FC 043B- 85 FD STA $FD 043D- E6 FC INC $FC 043F- A5 FC LDA $FC 0441- 29 03 AND #$03 0443- 0A ASL 0444- 055 3D STA $3D 0426- 20 00 04 JSR $0400 0429- A4 F9 LDY $F9 042B- C8 INY 042C- C4 49 CPY $49 042E- 90 EA BCC $041A 0430- A5 27 LDA $27 0432- 60 RTS 0433- 20 36 04 JSR $0436 0 LDY #$00 0415- 85 27 STA $27 0417- E8 INX 0418- 86 49 STX $49 041A- 84 F9 STY $F9 041C- 98 TYA 041D- 24 4A BIT $4A 041F- 30 03 BMI $0424 0421- B9 63 04 LDA $0463,Y 0424- 8its entirety: 0400- A6 2B LDX $2B 0402- 6C 3E 00 JMP ($003E) 0405- 20 0E 04 JSR $040E 0408- 20 0E 04 JSR $040E 040B- 20 0E 04 JSR $040E 040E- 20 33 04 JSR $0433 0411- A2 0F LDX #$0F 0413- A0 00 routine do its thing and regain control after it returned. I got lucky, and that guess turned out to be correct. But I want to delve into that subroutine a bit now, because it's interesting and it's something I haven't seen before. This is the routine in gotten. . . . Lastly, a postscript about a very interesting disk read routine used to read the rest of DOS from tracks $01 and $02... At $0473, the bootloader called a subroutne at $040B. When I first traced the boot, I guessed that I could let this sub00..$12FF? As far as I can tell, they were never used. Were they the remnants of another game that used a similar protection scheme? That was common practice in the 1980s. Perhaps I'm just stumbling over the ghosts of dead code, hastily reused and long forat work, all that boot0 weirdness, code in the text pages, a custom RWTS, a nibble check, and for what? A lightly patched version of DOS 3.3 that runs a program written in Applesoft BASIC. And what about those sectors that were loaded from track 0 into $09on tracks $03-$21). I used Copy ][+ for this because it has a convenient "Copy DOS" option, but Disk Muncher or Fast Copy or any other copier would also work. Mirabile visu! The game loads and runs without a hitch. In a way, it seems anticlimactic. All thle instead of auto-running an Applesoft BASIC program. - boot the DOS 3.3 master disk - remove it and insert a blank disk ]POKE 40514,20 ]INIT EXEC I copied tracks $00-$02 from this scratch disk to the disk that I made with ADVANCED DEMUFFIN (with data ll need to patch it to auto-exec the "EXEC" file instead of a HELLO program. Can DOS 3.3 do that? Beagle Bros. to the rescue! As listed on their inimitable "Peeks, Pokes & Pointers" chart, there is a magic POKE that will make DOS 3.3 auto-execute a text fi wait. If the game has a regular disk catalog and runs after booting from an entirely different disk, why do I need to recreate the obfuscated bootloader at all? I can just put a copy of DOS 3.3 on the unprotected disk and call it a day. Well, I would sti rom track B to track A, first step to (half-)track B-0.5, then to B-1, and so on until you arrive at track A. An individual step (which must from the original half-track to one if its immediately neighboring half-tracks) is accomplished by turning on the f stepping one track at a time from the original track to the destination track. Thus, to step inward from track A to track B, first step to (half-)track A+0.5, then to (half-)track A+1, and so on, until you arrive at track B. Likewise, to step outward f 2 1.5 3 2 0 2.5 1 3 2 3.5 3 etc. To figure the phase for a given (half-)track, multiply the track number by 2, and keep only the two low-order bits. Stepping from one track to another is simply a matter oually work. macgui.com/usenet/?group=1&id=31160 [begin quote] Basically, each track (and half-track) may be considered to be "under" one of the four phases of the stepper motor. Track Phase ---- ----- 0 0 0.5 1 1 cations is critical, making this a non-trivial exercise. [end quote] Unsatisfied, I scoured the internet for some additional information to make sense of this. I found an archive of a single Usenet post from 1990 that explained how the stepper motors actep motor phase 3 on Basically, each of the four [stepper motor] phases (0-3) must be turned on and then off again. Done in ascending order, this moves the arm inward. In descending order, this moves the arm outward. The timing between accesses to these lo 0 off $C081 PHASEON Step motor phase 0 on $C082 PHASE1OFF Step motor phase 1 off $C083 PHASE1ON Step motor phase 1 on $C084 PHASE2OFF Step motor phase 2 off $C085 PHASE2ON Step motor phase 2 on $C086 PHASE3OFF Step motor phase 3 off $C087 PHASE3ON Structure. So I went back to my dog-eared copy of "Beneath Apple DOS" and read through chapter 6 again ("Using DOS from Assembly Language"): [begin quote] ADDR LABEL DESCRIPTION --------------------------------------- $C080 PHASEOFF Step motor phase9..$0446: load zero page $FC and manipulate it to... do what exactly? ORA with $2B? That's the current slot number (x16). $0447..$045E: I'm afraid I'm not as familiar with the low-level disk motor control bits as I am with the higher level RWTS and DOS stnd then come back. $0433..$0435: JSR $0436. Again, this "falls through" to $0436, so whatever $0436 is doing, this code will do it twice. I quite like this pattern, and apparently the original author did too. $0436..$0438: push A and Y to the stack $043calling $0408 would do it three times; calling $0405 would do it 4 times. Nice. And it doesn't require an index register or any branching logic. The caller at $0473 called $040B, so this code will do it twice. $040E..$0410: JSR $0433. Let's skip to that acalls to $040E, which appears to a main entry point of some sort. Note that the last one "falls through" to $040E (no RTS). So this is a cheap way of doing something multiple times. Calling $040E directly would do it once; calling $040B would do it twice; slot number (x16) and jump to ($3E), which was set to point to $Cx5C way back in T0S0 ($0835..$083D). Furthermore, $0801 was set to an RTS, so you could JSR $0400 and it would end up returning control to you after reading a sector. $0405..$040D: multiple Y < $<`rHȩ p꩝ p  'I= I'`+l>   X ,W,P,R`@@@@@@ ------------EOF------------------ moving the drive head, the original disk can re-use that naive routine in ROM to blindly read data from these intentionally malformed tracks. That's wickedly delicious. --------------------------------------- A 4am crack 2014-03-05 ------der to fulfill its primary purpose (reading track $00). It has already slammed the drive head far enough that it can safely assume it's reading track $00, so it just blindly reads and never double-checks the track numbers in the address field. By manually e head if it's not. But... these tracks aren't ever read by a sane RWTS. They're read by a very naive, very minimalist routine embedded in the disk controller card ROM. This routine doesn't do any checking of track numbers because it doesn't need to in orn these tracks, because the track number listed in the address field doesn't match the track number it was trying to read. That's the entire purpose of the address field, so the RWTS can ensure it's reading data off the correct track and re-adjust the drivstrange: the address field is exactly the same as track $00 (AA AA AA AA AA AA AA AA). Track $01 is claiming to be track $00. And track $02 is, too! These tracks are lying to me. No sane RWTS would be able to read these tracks. Any sane RWTS would barf othat, it says that this is track 0, sector 0 (true), and that this disk has volume number 0 (which is illegal). But the disk controller card doesn't actually check the volume number, so the disk still boots. Looking at track $01, I noticed something VERY ?L$%LY < $<    3'I$J0c= I'` 6HH) +0 ) +0 hh`  FJ + xJx HH`L BBBBBBBBBB@@@@@@ *鷽HI++[ DV- F8+"$H`*Й"LONNO OЅO뭁lBBBBBBBB@@@@@@$+l>    3'I$J0c= I'` 6HH) +0 ) +0 hh`  FJ + xJx HH`L BBBBBBBBBB@@@@@@  OICE"@~p?@|`x@@("DU*A` ( `@@~?p?`x~p?p?`@x@~p?@|?x@ :E,RCLOSE NO CHOICE SELECTEDA) NO CHQP(/T`Az~p?@|`x@@D"$m6A0h:l~{A~~?p?`x~p?p?`@x@~p?@x@ 3,QT((`E   (Q\(*@ Q  D&QHP(*TP(*t@0A ~p?@|`x@@r` E"_P6(*t@ 0C~?p?`x~p?p?`~x@~p?@x@`8q\8|~F `@8""`D u(QT(*@ Q  D" @`?p{(*|~}_G~~p?@|`x@P}(*4xwmGz~?p?`~x~?p?`~x~p?@`x@ 0AP   @""%" ])QT(*}?@ Qocq8"`E @~p?@|x@D/dq8"g`PX(*T5@E ~p?p?`~x@@#DpQ`qD"_~?p?`x~p?@`x@`Ap`px| @>b" M+QT(*`@ `8@x~~p?@|x@J "D"bPPph+TG~~p?p?`@x@@$$!$Q E"A~?p?`x~p?@`x@ t8""$" w.QT(*}A  (`  @@ `\(*X6`~p?@||?x@Q`"D20PP((T@ ~p?p?`@x@@h"D E"A~?p?`x~p?@`x@ ""D" -QT(*0C } h1h?:~@~#@o8.p~|F@~~p?@|`x@@("D` E"G@8p~|?@~?p?`x~p?@`x@~p?@|?x@ BE" ];QT(*uG  (Q6( *@"0 (` "#P "     u`".Q`pNФbptťܥm2<(-Py0\|e<6e<ԍ L}JJJJj귍hI  aUL@ kU8  L  Q^R(jQ0l^l\8õ浍õĵB3'RͲʎRʎ]]]ɍuL͟ɍ}RLRɍg^H8 ^hZLɍR LͲɊRR% QLܤͲ Z@ -^ ş\[Z QY\[Z8`l6Lş_Ȍb_Ͳ] )Y h( D` L[W ԧ H h@ [_ /QIb_L`LLLL`ª`LQLYLeLXLeLee ўQH\(h0L& $`( R \ZLl8 ўR HH\`\Z[YS6`LxQɿu=Ӝu`".Q`pNФbptťܥm2<(-Py0\|e<6e<ԍ L}JJJJj귍hI  aUL@ kU8  L  Q^R(jQ0l^l\8õ浍õĵB   ?L`Ls%LY  < $<L[dmx-Sà@跻~!Wo*9~~ɬƬ~~~ABRUVERIF!pppp p p p p`" t""#x"p0p@p@@@p@!y q q p@  LANGUAGE NOT AVAILABLRANGE ERROWRITE PROTECTEEND OF DATFILE NOT FOUNVOLUME MISMATCI/O ERRODISK FULFILE LOCKESYNTAX ERRONO BUFFhHȑ@ȑ@hHȑ@Ȋ@ch8&ȑ@Hȑ@Ah@LHȑ@ȑ@ htphso`hMhL`9 V8U897T6S67`INILOASAVRUCHAIDELETLOCUNLOCCLOSREAEXEWRITPOSITIOOPEAPPENRENAMCATALOMONOMOPRINMAXFILEFINBSAVBLOlZl^?cqH şch`fhjõĵ@OAP`u@`@&`QR`E Ls  @DAE@u`8` %@ @A@`@`@A`Mµ ) LЦ`8@AWc@8@-@HAȑ@on 8ɍ` ^f\õL ^NR  RΩLҦ)\Z ʽ LHv 3h`0h8` [L NС õ`A@` ŵLȿõ` F`  \ 濭0 \  ȟ Q ^\ eօ3L׮ʊHLQ &RL &QL d L4 Ne)n `@-eff L f`L . tQLѤ LҦL` OPu d L Ne)noLõĵLx LLЦ  #-µµ( egehtpjigh q Ql` z8L`MaEK@>ˆʎõĵL õ ĵµ aµ`` L̦µ_bJLLz L^ ۰L^  ȟ QlXJ̥KlV  ȟ QlV @ NL   L` -e L գsr ࣭ml ࣭srL -µLЦ ze)rs zrsLq ] Qlr L̦ գ8gh ࣥhgL գ8LʨM ࣥˤLµH hLħõµ µõ8`D&E`( 80 0 DDLDLDL^ t^`,tP ȟpMt-^^`DH hWLԧ d@` Lꢩ  c ȢL LLգcl mllm ꢥELȦAD@ C N cLuɠ% d: Lz @ĽJ0U eeʎd d E DUEX БDWJEgDfL䠬õĵ h RĵLH eeh) tt L [ _HH`]ɍ]ɬ` ɠ``DE ɤ<(LΡ DE`80!  eDeE eDDeEE ͲLɍ [LLĦ__ ^ 9 LҦ3 9 a   0LjLY u< (_9 ˭ɠuɠK_9 ?LVDP (ED Z $0x8x D- ܸDHIHHHHhHH݌hHhHh݌H6 h Լ ռ ռ ռ`HJ>݌h Hh݌`<=>?xH  hx`X<-2  4  2 2 #<* `FG8`0($ p,&" 0ʎ `/  !"#$%&'()*+,-./0123456789:;&Y&&Y&ސ 꽌ɪ\8`&&꽌ɪɖ'*&%&,E'зސ꽌ɪ`+*xS&x'8*3Ixix&& 8  '  & x)*++>J>J>VU)?`8'x0|&HhHh VY)'&Y)xꪽ)' `Hh`V0^*^*>&` aI꽌ɪV H  Xh L;緈JJJJx i L8ᷭ緍췩 i 8 `巬 췌`x (`(8`I`B` ``Hhgz./hLz֭Ƀ ,,Rl9`/+l  P˵B̵CõDĵEµµBD ĵ ⵭µ ۰ µL``ޠ`5?`ϳŠƠӠӠ Ġà Ӡ T zzU`??Ϡϲ`浍국䵍뵩嵠Jm赍嵊mjnnn浈m浍浭m䵍䵐`"L ŵ8ŵH ~(` d֠z #ƴ 󮜳` 0۰ϬBƴ8`i#`ЗLw!0>ﵭ` m ﳐ 7i볍 8 ЉLw`H h ݲL~  B8` 9L%ֵȱB׵ ܯ䵍൭嵍 ` DȑB׵BֵO G굎뵎쵬 뵎쵌`` ַ յյ`@ +õm浍õĵL õBĵCصص Qƴ0"BêĪLR E( 8` R` ELRŪƪ`췌 յյI뷭鷭  ˤLª 뷰` Lk ݵܵߵ޵ ^`8ܵ i · JLǵBȵC`,յp` 䯩 R-յյ`յ0` K R-յյ`ɵʵӵԵ` 4 K ( ѵҵLBȱBL8` DBHBH : ַ޵BȭߵBhhӵԵ RBܵmڵ޵ȱBݵm۵ߵ` 䯩LR˵̵ֵ׵` LͲLɍ [LLĦ__ ^ 9 LҦ3 9 a   0LjLY u< (_9 ˭ɠuɠK_9 ?L