modemwars/extracted/decryptDisk.py
2026-08-23 02:09:40 -05:00

49 lines
1.6 KiB
Python

#!/usr/bin/env python3
# decryptDisk.py - undo the Electronic Arts sector cipher used by the Modem Wars 1541 loader
# (drive code at $0531): every sector except track 18 is XORed with a rolling key.
import os, sys, glob
SECTORS_PER_TRACK = [21]*17 + [19]*7 + [18]*6 + [17]*5
def decryptSector(track, sector, data):
if track == 18:
return bytes(data)
# lda track ; ora #$C0 ; asl a (carry = 1 since bit 7 is set) ; adc sector
a = (track | 0xC0) << 1
carry = (a >> 8) & 1
a &= 0xFF
a = a + sector + carry
carry = (a >> 8) & 1
a &= 0xFF
out = bytearray(256)
key = 0
for y in range(256):
if y != 0:
a = y ^ key # tya ; eor key
# rol a (carry from the previous rol / adc)
newCarry = (a >> 7) & 1
a = ((a << 1) | carry) & 0xFF
carry = newCarry
key = a # sta key
out[y] = data[y] ^ key
return bytes(out)
def main():
src = sys.argv[1]
dst = sys.argv[2]
os.makedirs(dst, exist_ok=True)
img = bytearray()
for track in range(1, 36):
n = SECTORS_PER_TRACK[track-1]
trackBytes = bytearray()
for s in range(n):
raw = open(f"{src}/t{track:02d}s{s:02d}.bin", "rb").read()
dec = decryptSector(track, s, raw)
open(f"{dst}/t{track:02d}s{s:02d}.bin", "wb").write(dec)
trackBytes += dec
open(f"{dst}/track{track:02d}.bin", "wb").write(trackBytes)
img += trackBytes
open(f"{dst}/decrypted.d64", "wb").write(img)
print(f"wrote {len(img)} bytes")
main()