Module refinery.units.formats.archive.xtmacho

Expand source code Browse git
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from enum import IntFlag

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


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: bytearray):
        return data[:4] in (
            cls._SIGNATURE_BE,
            cls._SIGNATURE_LE,
        )

Classes

class CPUType (value, names=None, *, module=None, qualname=None, type=None, start=1)

An enumeration.

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.Flag
  • enum.Enum

Class variables

var any
var vax
var mc680x0
var x32
var x64
var mips
var mc98000
var hppa
var arm32
var arm64
var mc880000
var sparc
var i860
var alpha
var ppc32
var ppc64
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

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: bytearray):
        return data[:4] in (
            cls._SIGNATURE_BE,
            cls._SIGNATURE_LE,
        )

Ancestors

Class variables

var required_dependencies
var optional_dependencies

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