Created
January 21, 2022 20:19
-
-
Save CookiePLMonster/9847b4427741b538c8a9ae67f2634667 to your computer and use it in GitHub Desktop.
Unpacker for NES ROMs included in Memorial Series games
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import os | |
if len(sys.argv) < 2: | |
exit() | |
# Dump all files specified in the command line | |
for arg in sys.argv[1:]: | |
decrypted = [] | |
GAME_HEADER_SIZE = 0x18 # Header specific to the Memorial Series | |
with open(arg, 'rb') as f: | |
f.seek(0x800) | |
def toSigned16(n): | |
n = n & 0xffff | |
return (n ^ 0x8000) - 0x8000 | |
def readByte(file): | |
return int.from_bytes(file.read(1), 'little') | |
try: | |
while True: # Read until EOF, or until control termination | |
control = readByte(f) | |
typeMaybe = control >> 6 | |
if typeMaybe == 1: | |
count = (control & 0x3F) + 1 | |
byte = readByte(f) | |
while count != -1: | |
decrypted.append(byte) | |
count -= 1 | |
elif typeMaybe == 2: | |
count = (control & 0x3F) + 2 | |
offsetHigh = readByte(f) | |
offsetLow = readByte(f) | |
offset = toSigned16((offsetHigh << 8) | offsetLow) | |
index = count + offset + 1 | |
while count != -1: | |
decrypted.append(decrypted[-index]) | |
count -= 1 | |
elif typeMaybe == 3: | |
break # Control termination | |
elif typeMaybe == 0: | |
count = control & 0x3F | |
while count != -1: | |
decrypted.append(readByte(f)) | |
count -= 1 | |
except EOFError: | |
pass | |
# Verify header, then strip it | |
if ''.join([chr(i) for i in decrypted[:4]]) == 'CODE': | |
decrypted = decrypted[GAME_HEADER_SIZE:] | |
filename = os.path.splitext(os.path.basename(arg))[0] | |
with open(filename + '.bin', 'wb') as f: | |
f.write(bytes(decrypted)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment