#!/usr/bin/env python3 # A very very POC .DIR extractor # I probably won't continue using python # this is just a test because I hate quickbms dearly import ctypes import sys import os from pathlib import Path, PurePath class CoolStructure(ctypes.Structure): def __repr__(self) -> str: values = ", ".join(f"{name}={value}" for name, value in self._asdict().items()) return f"<{self.__class__.__name__}: {values}>" def _asdict(self) -> dict: return {field[0]: getattr(self, field[0]) for field in self._fields_} # DIR structures. Note that I'm not using the Python `struct` module for brevity. class DirHeader(CoolStructure): _fields_ = [ ('magic', ctypes.c_char * 4), # "DIRF" ('pad', ctypes.c_uint32), ('version', ctypes.c_char * 4), # version (2.2d) ('fileCount', ctypes.c_uint32), # count of files ('pad_2', ctypes.c_char * 0x30), ] def valid(self) -> bool: return self.magic == b'DIRF' def version(self) -> str: return self.version.decode('ascii') class DirTocEntry(CoolStructure): _fields_ = [ ('blockOffset', ctypes.c_uint32), # offset in 0x800 "blocks" ('size', ctypes.c_uint32), # size in bytes ('_fileName', ctypes.c_char * 0x38) # filename ] def fileName(self) -> str: return self._fileName.decode('ascii') def byteOffset(self) -> int: return self.blockOffset * 0x800 def getData(self, file) -> bytes: ret = bytearray(self.size) lastOffset = file.tell() file.seek(self.byteOffset(), os.SEEK_SET) file.readinto(ret) file.seek(lastOffset, os.SEEK_SET) return ret # """""main loop""""" def makePath(filename): return Path(os.getcwd()) / Path(sys.argv[1]).stem / filename def makeFolderPath(): (Path(os.getcwd()) / Path(sys.argv[1]).stem).mkdir(exist_ok=True) with open(sys.argv[1], "rb") as file: header = DirHeader() file.readinto(header) if header.valid(): makeFolderPath() toc = [] for i in range(0, header.fileCount): # hacky and slow probably but whatever entry = DirTocEntry() file.readinto(entry) toc.append(entry) # read the TOC out print(f'going to extract {header.fileCount} files') for item in toc: name = item.fileName() data = item.getData(file) path = makePath(name) with open(str(path), "wb") as outFile: outFile.write(data) print(f' wrote \'{str(path)}\' size {item.size} bytes')