diff --git a/BootScriptExtractor.sh b/BootScriptExtractor.sh new file mode 100755 index 0000000..4eb9bdc --- /dev/null +++ b/BootScriptExtractor.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +# USAGE: BootScriptExtractor BOOTSCRIPT + +head -c $((0x4000)) | LC_CTYPE=C tr -d '\0' | LC_CTYPE=C tr '\r' '\n' | awk 'f && /BOOT-SCRIPT/{exit} f{print} /BOOT-SCRIPT/{f=1}' | sed 's/# ...... const/# xxxxxx const/' diff --git a/Every68kInstAssembler.py b/Every68kInstAssembler.py new file mode 100755 index 0000000..ac28c77 --- /dev/null +++ b/Every68kInstAssembler.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 + +import struct +from sys import argv + +class MPWObject: + def __init__(self): + self._list = [] + self._dict = [] + self._backdict = {} + self._dict_idx = 200 + + def __bytes__(self): + dest = bytearray() + + for chunk in self._list: + dest.extend(chunk) + if len(dest) & 1: dest.append(0) + + return bytes(dest) + + def _ensurename(self, name): + # get the ID of this name from the dict + # If nonexistent, then add it + # i.e. idempotent + + try: + return self._backdict[name] + except KeyError: + self.putdict([name]) + return self._backdict[name] + + def _quickappend(self, *bytelist): + self._list.append(bytes(bytelist)) + + def putfirst(self): + self._quickappend(1, 1, 0, 2) + + def putlast(self): + self._quickappend(2, 0) + + def putdict(self, items): + dest = bytearray() + + dest.extend([4, 0, 99, 99]) + dest.extend(struct.pack('>H', self._dict_idx)) + + flag = False + + for item in items: + flag = True + dest.append(len(item)) + dest.extend(item.encode('ascii')) + + self._backdict[item] = self._dict_idx + + self._dict_idx += 1 # ID of the *next* thing + + if not flag: return + + struct.pack_into('>H', dest, 2, len(dest)) + + self._list.append(dest) + + def putmod(self, name='#0001', segname='Main', flags=(1<<7)+(1<<3)): + modid = self._ensurename(name) + segid = self._ensurename(segname) + self._last_mod_id = modid + + self._list.append(struct.pack('>BBHH', 5, flags, modid, segid)) + + def putentry(self, offset, name): + entid = self._ensurename(name) + + self._list.append(struct.pack('>BBHL', 6, 1<<3, entid, offset)) + + def putsize(self, size): + self._list.append(struct.pack('>BBL', 7, 0, size)) + + def putcontents(self, data): # in multiple chunks please! + done = 0 + + while done < len(data): + this_time = data[done:done+30000] + + header = struct.pack('>BBHL', 8, 1<<3, 8 + len(this_time), done) + + self._list.append(header + this_time) + + done += len(this_time) + + def putcomment(self, cmt): + cmt = cmt.replace('\n','\r').encode('mac_roman') + if len(cmt) & 1: cmt += b' ' + + dest = bytearray() + dest.extend([3, 0]) + dest.extend(struct.pack('>H', len(cmt) + 4)) + dest.extend(cmt) + + self._list.append(dest) + + def putsimpleref(self, targname, width, *offsets): + offsets = list(offsets) + + if width == 2: # of the operand field, in bytes + flags = 1 << 4 + elif width == 4: + flags = 0 + + flags |= 1<<3 # longwords in the offset list! + + targid = self._ensurename(targname) + + dest = struct.pack('>BBHH', 9, flags, 6 + 4 * len(offsets), targid) + dest += b''.join(struct.pack('>L', o) for o in offsets) + + self._list.append(dest) + + def putweirdref(self, targname, width, *offsets): + # Assumes that you've already put -offset at offset + offsets = list(offsets) + + if width == 1: + flags = 2 << 4 + elif width == 2: # of the operand field, in bytes + flags = 1 << 4 + elif width == 4: + flags = 0 << 4 + + flags |= 1<<7 # difference calculation + # flags |= 1<<3 # longwords in the offset list! + + targid = self._ensurename(targname) + + dest = struct.pack('>BBHHH', 10, flags, 8 + 2 * len(offsets), targid, self._last_mod_id) + dest += b''.join(struct.pack('>H', o) for o in offsets) + + self._list.append(dest) + + + + +# included my own copy of mpwobj! + +o = MPWObject() + +o.putfirst() + +for i in range(65536): + b = struct.pack('>H16b', i, *range(1,17)) + + o.putmod(name='#xxxx') + o.putcontents(b) + +o.putlast() + +if argv[1:]: + with open(argv[1], 'wb') as f: + f.write(bytes(o)) + diff --git a/KernelExtractor.py b/KernelExtractor.py new file mode 100755 index 0000000..119c99a --- /dev/null +++ b/KernelExtractor.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 + +from sys import argv + +# USAGE: KernelExtractor.py DESTDIR ROM1 [ROM2 ...] + +kerns = {} + +for fname in argv[2:]: + print(fname) + with open(fname, 'rb') as f: + b = f.read() + if len(b) != 0x400000: print('--- bad size') + b = b[0x310000:] + l = b.index(bytes(1024)) + l += 3 + l -= l % 4 + b = b[:l] + if not b: + print('--- no kernel') + continue + vers = '%02x%02x' % tuple(b[4:6]) + if not vers.startswith('02'): continue + print('---', vers) + if vers in kerns: + if kerns[vers] != b: + print('--- bad motivator') + kerns[vers] = None + else: + kerns[vers] = b + +for v, k in kerns.items(): + if k is None: continue + with open(argv[1] + v, 'wb') as f: + f.write(k) diff --git a/MovePEFsToResources.py b/MovePEFsToResources.py new file mode 100755 index 0000000..33a73de --- /dev/null +++ b/MovePEFsToResources.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 + +# MacOS apps, extensions etc often keep their PEF (Portable Executable +# Format) binaries (also called Code Fragments) in the data fork, with +# offsets in a 'cfrg' resource in the resource fork. This scheme allows +# the Code Fragment Manager to map that file directly into memory (when VM +# is on) instead of using the Resource Manager to load it into a Memory +# Manager heap. But when multiple PEFs are concatenated into the DF, +# patchpef (https://github.com/elliotnunn/patchpef) cannot be used to +# mangle them. This script moves the PEFs to 'ndrv' resources (type +# doesn't really matter) and updates the 'cfrg' accordingly. The original +# PEFs are zeroed out in the data fork, so if everything has gone +# correctly, the data fork should be all zeroes. + +# USAGE: MovePEFsToResources.py SRCFILE DESTFILE + +from sys import argv +from subprocess import run + +oln, fn = argv[1:] + +run(['rm', '-f', fn]) +run(['cp', oln, fn]) + +with open(fn, 'rb') as f: + df = bytearray(f.read()) + +run(['zcp', fn+'//cfrg/0', '/tmp/mycfrg']) + +with open('/tmp/mycfrg', 'rb') as f: + cfrg = bytearray(f.read()) + +pwpc_locs = [] +start = 0 +while True: + found = cfrg.find(b'pwpc', start) + if found == -1: break + pwpc_locs.append(found) + start = found + 4 + +for i, p in enumerate(pwpc_locs): + where = cfrg[p+0x14+3] + if where != 1: continue + + rsrcnum = i+13000 + + start = int.from_bytes(cfrg[p+0x18:p+0x1c], 'big') + size = int.from_bytes(cfrg[p+0x1c:p+0x20], 'big') + nlen = cfrg[p+0x2a] + name = cfrg[p+0x2b:p+0x2b+nlen].decode('ascii') + + pef = df[start:start+size] + + with open('/tmp/thispef', 'wb') as f: + f.write(pef) + + run(['zcp', '/tmp/thispef', '%s//ndrv/%d/%s/sysheap/locked' % (fn, rsrcnum, name)]) + + df[start:start+size] = bytes(size) + + cfrg[p+0x14+3] = 2 + cfrg[p+0x18:p+0x1c] = b'ndrv' + cfrg[p+0x1c:p+0x20] = rsrcnum.to_bytes(4, 'big', signed=True) + +with open(fn, 'wb') as f: + f.write(df) + +with open('/tmp/mycfrg', 'wb') as f: + f.write(cfrg) + +run(['zcp', '/tmp/mycfrg', fn+'//cfrg/0'])