Module refinery.units.formats.archive.xtmacho

Expand source code Browse git
from __future__ import annotations

from enum import IntFlag

from refinery.lib.structures import StreamDetour, Struct, StructReader
from refinery.units.formats.archive import ArchiveUnit


class CPUType(IntFlag):
    any         = 0xFFFFFFFF  # noqa
    vax         = 0x00000001  # noqa
    mc680x0     = 0x00000006  # noqa
    x32         = 0x00000007  # noqa
    x64         = 0x01000007  # noqa
    mips        = 0x00000008  # noqa
    mc98000     = 0x0000000A  # noqa
    hppa        = 0x0000000B  # noqa
    arm32       = 0x0000000C  # noqa
    arm64       = 0x0100000C  # noqa
    mc880000    = 0x0000000D  # noqa
    sparc       = 0x0000000E  # noqa
    i860        = 0x0000000F  # noqa
    alpha       = 0x00000010  # noqa
    ppc32       = 0x00000012  # noqa
    ppc64       = 0x01000012  # noqa


class FatArch(Struct):
    def __init__(self, reader: StructReader):
        self.cputype = CPUType(reader.u32())
        self.machine = reader.u32()
        offset = reader.u32()
        size = reader.u32()
        self.is64bit = (self.cputype >> 24) & 1
        with StreamDetour(reader, offset):
            self.data = reader.read(size)
        self.align = reader.u32()


class xtmacho(ArchiveUnit):
    """
    Extract the individual executables from a MachO universal binary (sometimes called a MachO fat file)."
    """
    _SIGNATURE_BE = B'\xCA\xFE\xBA\xBE'
    _SIGNATURE_LE = B'\xBE\xBA\xFE\xCA'

    def unpack(self, data: bytearray):
        view = memoryview(data)
        signature = bytes(view[:4])
        try:
            reader = StructReader(view, bigendian={
                self._SIGNATURE_BE: True,
                self._SIGNATURE_LE: False,
            }[signature])
        except KeyError as KE:
            raise ValueError('Not a MachO universal binary; invalid magic header bytes.') from KE
        else:
            reader.seekset(4)
        count = reader.u32()
        self.log_info(F'reading {count} embedded executables')
        while count > 0:
            fa = FatArch(reader)
            self.log_info(F'reading item of size 0x{len(fa.data):08X}, arch {fa.cputype.name}')
            yield self._pack(fa.cputype.name, None, fa.data)
            count -= 1

    @classmethod
    def handles(cls, data):
        return data[:4] in (
            cls._SIGNATURE_BE,
            cls._SIGNATURE_LE,
        )

Classes

class CPUType (*args, **kwds)

Support for integer-based Flags

Expand source code Browse git
class CPUType(IntFlag):
    any         = 0xFFFFFFFF  # noqa
    vax         = 0x00000001  # noqa
    mc680x0     = 0x00000006  # noqa
    x32         = 0x00000007  # noqa
    x64         = 0x01000007  # noqa
    mips        = 0x00000008  # noqa
    mc98000     = 0x0000000A  # noqa
    hppa        = 0x0000000B  # noqa
    arm32       = 0x0000000C  # noqa
    arm64       = 0x0100000C  # noqa
    mc880000    = 0x0000000D  # noqa
    sparc       = 0x0000000E  # noqa
    i860        = 0x0000000F  # noqa
    alpha       = 0x00000010  # noqa
    ppc32       = 0x00000012  # noqa
    ppc64       = 0x01000012  # noqa

Ancestors

  • enum.IntFlag
  • builtins.int
  • enum.ReprEnum
  • enum.Flag
  • enum.Enum

Class variables

var any

The type of the None singleton.

var vax

The type of the None singleton.

var mc680x0

The type of the None singleton.

var x32

The type of the None singleton.

var x64

The type of the None singleton.

var mips

The type of the None singleton.

var mc98000

The type of the None singleton.

var hppa

The type of the None singleton.

var arm32

The type of the None singleton.

var arm64

The type of the None singleton.

var mc880000

The type of the None singleton.

var sparc

The type of the None singleton.

var i860

The type of the None singleton.

var alpha

The type of the None singleton.

var ppc32

The type of the None singleton.

var ppc64

The type of the None singleton.

class FatArch (reader)

A class to parse structured data. A Struct class can be instantiated as follows:

foo = Struct(data, bar=29)

The initialization routine of the structure will be called with a single argument reader. If the object data is already a StructReader, then it will be passed as reader. Otherwise, the argument will be wrapped in a StructReader. Additional arguments to the struct are passed through.

Expand source code Browse git
class FatArch(Struct):
    def __init__(self, reader: StructReader):
        self.cputype = CPUType(reader.u32())
        self.machine = reader.u32()
        offset = reader.u32()
        size = reader.u32()
        self.is64bit = (self.cputype >> 24) & 1
        with StreamDetour(reader, offset):
            self.data = reader.read(size)
        self.align = reader.u32()

Ancestors

  • Struct
  • typing.Generic
  • collections.abc.Buffer

Static methods

def Parse(reader, *args, **kwargs)
class xtmacho (*paths, list=False, join_path=False, drop_path=False, fuzzy=0, exact=False, regex=False, path=b'path', date=b'date', pwd=b'')

Extract the individual executables from a MachO universal binary (sometimes called a MachO fat file)."

Expand source code Browse git
class xtmacho(ArchiveUnit):
    """
    Extract the individual executables from a MachO universal binary (sometimes called a MachO fat file)."
    """
    _SIGNATURE_BE = B'\xCA\xFE\xBA\xBE'
    _SIGNATURE_LE = B'\xBE\xBA\xFE\xCA'

    def unpack(self, data: bytearray):
        view = memoryview(data)
        signature = bytes(view[:4])
        try:
            reader = StructReader(view, bigendian={
                self._SIGNATURE_BE: True,
                self._SIGNATURE_LE: False,
            }[signature])
        except KeyError as KE:
            raise ValueError('Not a MachO universal binary; invalid magic header bytes.') from KE
        else:
            reader.seekset(4)
        count = reader.u32()
        self.log_info(F'reading {count} embedded executables')
        while count > 0:
            fa = FatArch(reader)
            self.log_info(F'reading item of size 0x{len(fa.data):08X}, arch {fa.cputype.name}')
            yield self._pack(fa.cputype.name, None, fa.data)
            count -= 1

    @classmethod
    def handles(cls, data):
        return data[:4] in (
            cls._SIGNATURE_BE,
            cls._SIGNATURE_LE,
        )

Ancestors

Subclasses

Methods

def unpack(self, data)
Expand source code Browse git
def unpack(self, data: bytearray):
    view = memoryview(data)
    signature = bytes(view[:4])
    try:
        reader = StructReader(view, bigendian={
            self._SIGNATURE_BE: True,
            self._SIGNATURE_LE: False,
        }[signature])
    except KeyError as KE:
        raise ValueError('Not a MachO universal binary; invalid magic header bytes.') from KE
    else:
        reader.seekset(4)
    count = reader.u32()
    self.log_info(F'reading {count} embedded executables')
    while count > 0:
        fa = FatArch(reader)
        self.log_info(F'reading item of size 0x{len(fa.data):08X}, arch {fa.cputype.name}')
        yield self._pack(fa.cputype.name, None, fa.data)
        count -= 1

Inherited members