From 8ce6297ad1dbc25c3b20ea9bb9ffea4ed7fcb150 Mon Sep 17 00:00:00 2001 From: 4am Date: Sat, 9 Feb 2019 23:51:41 -0500 Subject: [PATCH] prelimary support for decrypting and patching Holle bootloader --- src/apicode.a | 4 + src/apidefs.a | 4 +- src/id/holle.a | 29 ++++++ src/id/inspect0.a | 10 ++ src/passport.a | 2 + src/patchers/holle.a | 194 ++++++++++++++++++++++++++++++++++++ src/patchers/protecteddos.a | 2 +- src/strings/en.a | 7 +- src/strings/enid.a | 5 +- 9 files changed, 251 insertions(+), 6 deletions(-) create mode 100644 src/id/holle.a create mode 100644 src/patchers/holle.a diff --git a/src/apicode.a b/src/apicode.a index d19af65..5f9cd93 100644 --- a/src/apicode.a +++ b/src/apicode.a @@ -64,6 +64,10 @@ ; set in IDBootloader() after reading T00,S00 FIRSTFILTER +;gIsHolle + !byte FALSE ; 0=true, 1=false + ; reset before each operation + ; set in IDBootloader() after reading T00,S00 ;gIsMUSERWTS !byte FALSE ; 0=true, 1=false ; reset before each operation diff --git a/src/apidefs.a b/src/apidefs.a index 7b54614..a3327a3 100644 --- a/src/apidefs.a +++ b/src/apidefs.a @@ -99,9 +99,10 @@ gIsPanglosDOS = gIsAdvent-$01 ; byte gIsDavidson = gIsPanglosDOS-$01 ; byte gIsRDOS13 = gIsDavidson-$01 ; byte gIsMUSERWTS = gIsRDOS13-$01 ; byte +gIsHolle = gIsMUSERWTS-$01 ; byte ;LASTFILTER ; add new gIs* above this line ;gIsInfocom18 is a special case whose ID is not in the regular inspection path -gIsInfocom18 = gIsMUSERWTS-$01 ; byte +gIsInfocom18 = gIsHolle-$01 ; byte ;gIs13Sector is a special case whose ID is not in the regular inspection path gIs13Sector = gIsInfocom18-$01 ; byte ;gMECCFastloadType is a special case integer whose default value cannot be #FALSE @@ -173,6 +174,7 @@ ConstructStandardDelivery = jConstructStandardDelivery !warn "gIsPanglosDOS=",gIsPanglosDOS !warn "gIsDavidson=",gIsDavidson !warn "gIsMUSERWTS=",gIsMUSERWTS +!warn "gIsHolle=",gIsHolle !warn "gIsRDOS13=",gIsRDOS13 !warn "gIsInfocom18=",gIsInfocom18 !warn "gIs13Sector=",gIs13Sector diff --git a/src/id/holle.a b/src/id/holle.a new file mode 100644 index 0000000..22c1560 --- /dev/null +++ b/src/id/holle.a @@ -0,0 +1,29 @@ +;------------------------------- +; IDHolle +; identify Dav Holle's encrypted bootloader +; +; in: $0800..$08FF contains T00,S00 +; first page of track buffer also contains T00,S00 +; out: C clear if Holle bootloader found +; C set otherwise +; all registers clobbered +; all other flags clobbered +;------------------------------- +!zone { +IDHolle + lda #$00 + tax + ldy #(@searchend-@searchstart) + jsr compare ; if T00,S00,$00 == +@searchstart + !byte $01 + CLD + BIT $C081 + LDA #$60 + EOR $FF58 +@hang BNE @hang + STA $03F3 + SEI +@searchend + rts +} diff --git a/src/id/inspect0.a b/src/id/inspect0.a index bf53af1..0997a45 100755 --- a/src/id/inspect0.a +++ b/src/id/inspect0.a @@ -286,6 +286,16 @@ IDBootloader lda #s_rdos jsr PrintByID +; +; Dav Holle encrypted bootloader +; ++ jsr IDHolle + bcs + + lda #s_holle + jsr PrintByID + lda #TRUE + sta gIsHolle + + .useuniv jmp UseUniversal diff --git a/src/passport.a b/src/passport.a index 0441d34..0618c50 100755 --- a/src/passport.a +++ b/src/passport.a @@ -150,6 +150,7 @@ FirstMover !source "id/advent.a" !source "id/panglosdos.a" !source "id/davidson.a" + !source "id/holle.a" !source "print.a" !source "compare.a" !source "modify.a" @@ -842,6 +843,7 @@ _applyToAll !source "patchers/rdosfmt.a" ; gIsRDOS13 only !source "patchers/aacount.a" !source "patchers/hallabs.a" ; T01 only + !source "patchers/holle.a" ; gIsHolle only lda gPatchCount beq .nopatches diff --git a/src/patchers/holle.a b/src/patchers/holle.a new file mode 100644 index 0000000..6e35350 --- /dev/null +++ b/src/patchers/holle.a @@ -0,0 +1,194 @@ +;------------------------------- +; #HOLLE +; encrypted bootloader hides an evil RWTS +; +; tested on +; - Sherwood Forest (Phoenix Software) +; - Mad Rat (Phoenix Software) +; - Masquerade (Phoenix Software) +; - Bats in the Belfry (Phoenix Software) +; - Bouncing Kamungas (Penguin Software) +; - Crime Wave (Penguin Software) +; - Thunder Bombs (Penguin Software) +; - The Spy Strikes Back (Penguin Software) +;------------------------------- +!zone { + bit gMode ; nothing to do here in verify-only mode + bmi + +- jmp .exit ++ bvc - ; nothing to do here in demuffin mode + lda gIsHolle + beq + + jmp .exit ++ lda gTrack + beq @DecryptBootloader + + ; TODO search for secondary RWTS here + ; TODO search for secondary volume checks here + jmp .exit + +@DecryptBootloader ; we've read the entire disk, now we're on track 0 + jsr ReorderBuffer + ldy #(@decrypt1End-@decrypt1Start) + jsr SearchTrack; find decryption loop #1 +@decrypt1Start + LDX #WILDCARD +- EOR $082D,X + STA $0110,X + DEX + BPL - +@decrypt1End + bcs @PatchBootloader + clc ; set up a decryption loop to simulate this one + adc #BASEPAGE + sta @decrypt1+2 + sta @decrypt1_eor+2 + inx + stx @decrypt1+1 + inx + stx @decrypt1_eor+1 + + ldy #(@decrypt2End-@decrypt2Start) + jsr SearchTrack; find decryption loop #2 +@decrypt2Start + LDX $082B +- EOR $0900,X + STA $0500,X + INX + BNE - +@decrypt2End + bcs @PatchBootloader + clc ; set up a decryption loop to simulate this one + adc #BASEPAGE + sta @decrypt2_load+2 + sta @decrypt2_store+2 + sta @decrypt2_eor+2 + inx + inx + inx + stx @decrypt2_eor+1 + + lda #BASEPAGE + sta @decrypt1_load+2 + sta @decrypt1_store+2 + sta @decrypt2+2 + + lda #s_decryptrwts + jsr PrintByID + inc gPatchCount + lda #$4C +@decrypt1 + ldx $FDFD ; simulate the decryption within the track buffer +@decrypt1_load +- eor $FD2D,x +@decrypt1_store + sta $FD2D,x + dex + bpl - + ldy #$03 +@decrypt2 + ldx $FD2B +@decrypt2_load +- eor $FD00,x +@decrypt2_store + sta $FD00,x + inx + bne - + inc @decrypt2_load+2 + inc @decrypt2_store+2 + dey + bne - + lda #$BD ; LDA abs,X opcode +@decrypt1_eor + sta $FDFD ; EOR -> LDA so now decryption loop #1 is just a copy loop +@decrypt2_eor + sta $FDFD ; EOR -> LDA so now decryption loop #2 is just a copy loop + +@PatchBootloader + jsr ReorderBuffer + + ldy #(@addressEpilogueEnd-@addressEpilogueStart) + jsr SearchTrack +@addressEpilogueStart + !byte $C9,WILDCARD + BNE + + CLC + RTS ++ SEC + RTS +@addressEpilogueEnd + bcs + + inx + ldy #$01 + jsr modify ; normalize address epilogue 1st nibble + !byte $DE ++ + ldy #(@dataPrologue3End-@dataPrologue3Start) + jsr SearchTrack +@dataPrologue3Start + EOR #$AD + !byte $D0,$E7 + PHP + !byte $20 +@dataPrologue3End + bcs + + inx + inx + inx + inx + ldy #$02 + jsr modify ; disable CPU-burning JSR after data prologue + !byte $F0,$03 ++ + ldy #(@dataEpilogue1End-@dataEpilogue1Start) + jsr SearchTrack +@dataEpilogue1Start + !byte $C9,WILDCARD + !byte $D0,$9B + NOP +@dataEpilogue1End + bcs + + inx + ldy #$01 + jsr modify ; normalize data epilogue 1st nibble + !byte $DE ++ + ldy #(@dataEpilogue3End-@dataEpilogue3Start) + jsr SearchTrack +@dataEpilogue3Start + !byte $EB + !byte $D0,$86 +@dataEpilogue3End + bcs + + inx + inx + ldy #$01 + jsr modify ; ignore data epilogue 3rd nibble + !byte $00 ++ + ldy #(@diskVolumeEnd-@diskVolumeStart) + jsr SearchTrack +@diskVolumeStart + LDY $2F +@diskVolumeEnd + bcs + + ldy #$02 + jsr modify ; don't use disk volume number to initialize data field checksum + LDY #$00 ++ + ldy #(@alternatingTrackEnd-@alternatingTrackStart) + jsr SearchTrack +@alternatingTrackStart + EOR $01 + AND #$01 +@alternatingTrackEnd + bcs + + ldy #$01 + jsr modify + !byte $A9 ; EOR -> LDA so alternating track check always passes ++ + jmp .exit +.reorderAndExit + jsr ReorderBuffer +.exit +} diff --git a/src/patchers/protecteddos.a b/src/patchers/protecteddos.a index 740c425..7b9fa0c 100755 --- a/src/patchers/protecteddos.a +++ b/src/patchers/protecteddos.a @@ -126,7 +126,7 @@ ; bit gMode bpl + - lda #s_protdosw + lda #s_decryptrwts jsr PrintByID + ldx #BASEPAGE inx diff --git a/src/strings/en.a b/src/strings/en.a index 8e8cba6..7ee1356 100755 --- a/src/strings/en.a +++ b/src/strings/en.a @@ -76,7 +76,7 @@ StringTable !word .bcs08 !word .jmpb660 !word .protdos - !word .protdosw + !word .decryptrwts !word .protserial !word .fbff !word .encoded44 @@ -129,6 +129,7 @@ StringTable !word .dakin5 !word .springboard !word .hallabs + !word .holle ; ; Text can contain substitution strings, which ; are replaced by current values at runtime. Each @@ -354,7 +355,7 @@ StringTable !text "the data prologue by jumping to $B660.",$8D,$00 .protdos !text "T00,S01 Found encrypted RWTS, key=$%0",$8D,$00 -.protdosw +.decryptrwts !text "T00 Decrypting RWTS before writing",$8D,$00 .protserial !text "T%t,S%3 Erasing serial number %0%1%2",$8D,$00 @@ -475,4 +476,6 @@ StringTable !text "the address epilogue",$8D,$00 .hallabs !text "T%t,S%0 Found HAL Labs protection check",$8D,$00 +.holle + !text "T00,S00 Found Holle bootloader",$8D,$00 } diff --git a/src/strings/enid.a b/src/strings/enid.a index 5f38b82..23e488b 100644 --- a/src/strings/enid.a +++ b/src/strings/enid.a @@ -62,7 +62,7 @@ s_lsr6a = $38 s_bcs08 = $39 s_jmpb660 = $3A s_protdos = $3B -s_protdosw = $3C +s_decryptrwts =$3C s_protserial = $3D s_fbff = $3E s_encoded44 = $3F @@ -115,4 +115,5 @@ s_13sector = $6D s_dakin5 = $6E s_springboard =$6F s_hallabs = $70 -STRINGCOUNT = $71 +s_holle = $71 +STRINGCOUNT = $72