diff --git a/filebytes/mach_o.py b/filebytes/mach_o.py index 828b536..52fda9b 100644 --- a/filebytes/mach_o.py +++ b/filebytes/mach_o.py @@ -183,11 +183,19 @@ class LcStr(Union): _pack_ = 4 _fields_ = [('offset', c_uint)] +class BE_LcStr(BigEndianUnion): + _pack_ = 4 + _fields_ = [('offset', c_uint)] + class LoadCommand(LittleEndianStructure): _pack_ = 4 _fields_ = [('cmd', c_uint), ('cmdsize', c_uint)] +class BE_LoadCommand(BigEndianStructure): + _pack_ = 4 + _fields_ = [('cmd', c_uint), + ('cmdsize', c_uint)] class UuidCommand(LittleEndianStructure): _pack_ = 4 @@ -195,6 +203,12 @@ class UuidCommand(LittleEndianStructure): ('cmdsize', c_uint), ('uuid', c_ubyte * 16)] +class BE_UuidCommand(BigEndianStructure): + _pack_ = 4 + _fields_ = [('cmd', c_uint), + ('cmdsize', c_uint), + ('uuid', c_ubyte * 16)] + class TwoLevelHintsCommand(LittleEndianStructure): _pack_ = 4 _fields_ = [('cmd', c_uint), @@ -202,11 +216,24 @@ class TwoLevelHintsCommand(LittleEndianStructure): ('offset', c_uint), ('nhints', c_uint)] +class BE_TwoLevelHintsCommand(BigEndianStructure): + _pack_ = 4 + _fields_ = [('cmd', c_uint), + ('cmdsize', c_uint), + ('offset', c_uint), + ('nhints', c_uint)] + class TwoLevelHint(LittleEndianStructure): _pack_ = 4 _fields_ = [('isub_image', c_uint), ('itoc', c_uint)] +class BE_TwoLevelHint(BigEndianStructure): + _pack_ = 4 + _fields_ = [('isub_image', c_uint), + ('itoc', c_uint)] + + class Dylib(LittleEndianStructure): _pack_ = 4 _fields_ = [('name', LcStr), @@ -215,6 +242,14 @@ class Dylib(LittleEndianStructure): ('compatibility_version', c_uint), ] +class BE_Dylib(BigEndianStructure): + _pack_ = 4 + _fields_ = [('name', LcStr), + ('timestamp', c_uint), + ('current_version', c_uint), + ('compatibility_version', c_uint), + ] + class DylibCommand(LittleEndianStructure): _pack_ = 4 _fields_ = [('cmd', c_uint), @@ -222,6 +257,13 @@ class DylibCommand(LittleEndianStructure): ('dylib', Dylib), ] +class BE_DylibCommand(BigEndianStructure): + _pack_ = 4 + _fields_ = [('cmd', c_uint), + ('cmdsize', c_uint), + ('dylib', BE_Dylib), + ] + class DylinkerCommand(LittleEndianStructure): _pack_ = 4 _fields_ = [('cmd', c_uint), @@ -229,6 +271,13 @@ class DylinkerCommand(LittleEndianStructure): ('name', LcStr) ] +class BE_DylinkerCommand(BigEndianStructure): + _pack_ = 4 + _fields_ = [('cmd', c_uint), + ('cmdsize', c_uint), + ('name', LcStr) + ] + ########################### 32 BIT Structures ########################### class LSB_32_MachHeader(LittleEndianStructure): @@ -242,6 +291,17 @@ class LSB_32_MachHeader(LittleEndianStructure): ('flags', c_uint) ] +class LSB_BE32_MachHeader(BigEndianStructure): + _pack_ = 4 + _fields_ = [('magic', c_uint), + ('cputype', c_uint), + ('cpusubtype', c_uint), + ('filetype', c_uint), + ('ncmds', c_uint), + ('sizeofcmds', c_uint), + ('flags', c_uint) + ] + class LSB_32_SegmentCommand(LittleEndianStructure): _pack_ = 4 @@ -257,6 +317,20 @@ class LSB_32_SegmentCommand(LittleEndianStructure): ('nsects', c_uint), ('flags', c_uint)] +class LSB_BE32_SegmentCommand(BigEndianStructure): + _pack_ = 4 + _fields_ = [('cmd', c_uint), + ('cmdsize', c_uint), + ('segname', c_char * 16), + ('vmaddr', c_uint), + ('vmsize', c_uint), + ('fileoff', c_uint), + ('filesize', c_uint), + ('maxprot', c_uint), + ('initprot', c_uint), + ('nsects', c_uint), + ('flags', c_uint)] + class LSB_32_Section(LittleEndianStructure): _pack_ = 4 @@ -273,10 +347,46 @@ class LSB_32_Section(LittleEndianStructure): ('reserved2', c_uint) ] +class LSB_BE32_Section(BigEndianStructure): + _pack_ = 4 + _fields_ = [('sectname', c_char * 16), + ('segname', c_char * 16), + ('addr', c_uint), + ('size', c_uint), + ('offset', c_uint), + ('align', c_uint), + ('reloff', c_uint), + ('nreloc', c_uint), + ('flags', c_uint), + ('reserved1', c_uint), + ('reserved2', c_uint) + ] + class LSB_32(object): Section = LSB_32_Section SegmentCommand = LSB_32_SegmentCommand MachHeader = LSB_32_MachHeader + LcStr = LcStr + LoadCommand = LoadCommand + UuidCommand = UuidCommand + TwoLevelHintsCommand = TwoLevelHintsCommand + TwoLevelHint = TwoLevelHint + Dylib = Dylib + DylibCommand = DylibCommand + DylinkerCommand = DylinkerCommand + +class LSB_BE32(object): + Section = LSB_BE32_Section + SegmentCommand = LSB_BE32_SegmentCommand + MachHeader = LSB_BE32_MachHeader + LcStr = BE_LcStr + LoadCommand = BE_LoadCommand + UuidCommand = BE_UuidCommand + TwoLevelHintsCommand = BE_TwoLevelHintsCommand + TwoLevelHint = BE_TwoLevelHint + Dylib = BE_Dylib + DylibCommand = BE_DylibCommand + DylinkerCommand = BE_DylinkerCommand ########################### 64 BIT Structures ########################### @@ -292,6 +402,17 @@ class LSB_64_MachHeader(LittleEndianStructure): ('reserved', c_uint), ] +class LSB_BE64_MachHeader(BigEndianStructure): + _pack_ = 8 + _fields_ = [('magic', c_uint), + ('cputype', c_uint), + ('cpusubtype', c_uint), + ('filetype', c_uint), + ('ncmds', c_uint), + ('sizeofcmds', c_uint), + ('flags', c_uint), + ('reserved', c_uint), + ] class LSB_64_SegmentCommand(LittleEndianStructure): _pack_ = 8 @@ -307,6 +428,19 @@ class LSB_64_SegmentCommand(LittleEndianStructure): ('nsects', c_uint), ('flags', c_uint)] +class LSB_BE64_SegmentCommand(BigEndianStructure): + _pack_ = 8 + _fields_ = [('cmd', c_uint), + ('cmdsize', c_uint), + ('segname', c_char * 16), + ('vmaddr', c_ulonglong), + ('vmsize', c_ulonglong), + ('fileoff', c_ulonglong), + ('filesize', c_ulonglong), + ('maxprot', c_uint), + ('initprot', c_uint), + ('nsects', c_uint), + ('flags', c_uint)] class LSB_64_Section(LittleEndianStructure): _pack_ = 8 @@ -323,11 +457,46 @@ class LSB_64_Section(LittleEndianStructure): ('reserved2', c_uint) ] +class LSB_BE64_Section(BigEndianStructure): + _pack_ = 8 + _fields_ = [('sectname', c_char * 16), + ('segname', c_char * 16), + ('addr', c_ulonglong), + ('size', c_ulonglong), + ('offset', c_uint), + ('align', c_uint), + ('reloff', c_uint), + ('nreloc', c_uint), + ('flags', c_uint), + ('reserved1', c_uint), + ('reserved2', c_uint) + ] + class LSB_64(object): Section = LSB_64_Section SegmentCommand = LSB_64_SegmentCommand MachHeader = LSB_64_MachHeader - + LcStr = LcStr + LoadCommand = LoadCommand + UuidCommand = UuidCommand + TwoLevelHintsCommand = TwoLevelHintsCommand + TwoLevelHint = TwoLevelHint + Dylib = Dylib + DylibCommand = DylibCommand + DylinkerCommand = DylinkerCommand + +class LSB_BE64(object): + Section = LSB_BE64_Section + SegmentCommand = LSB_BE64_SegmentCommand + MachHeader = LSB_BE64_MachHeader + LcStr = BE_LcStr + LoadCommand = BE_LoadCommand + UuidCommand = BE_UuidCommand + TwoLevelHintsCommand = BE_TwoLevelHintsCommand + TwoLevelHint = BE_TwoLevelHint + Dylib = BE_Dylib + DylibCommand = BE_DylibCommand + DylinkerCommand = BE_DylinkerCommand ############################# Fat/Universal ########################### @@ -442,14 +611,21 @@ def imageBase(self): @property def type(self): return 'MachO' + + @property + def isBigEndian(self): + return self.__classes in (LSB_BE32, LSB_BE64) def _getSuitableClasses(self, data): classes = None - if data[7] == 0: + if data[0] == 0xCE: classes = LSB_32 - elif data[7] == 1: + elif data[0] == 0xCF: classes = LSB_64 - + elif data[3] == 0xCE: + classes = LSB_BE32 + elif data[3] == 0xCF: + classes = LSB_BE64 return classes def _tryParseFat(self, data): @@ -484,7 +660,7 @@ def _parseLoadCommands(self, data, machHeader): offset = sizeof(self._classes.MachHeader) load_commands = [] for i in range(machHeader.header.ncmds): - command = LoadCommand.from_buffer(data, offset) + command = self._classes.LoadCommand.from_buffer(data, offset) raw = (c_ubyte * command.cmdsize).from_buffer(data, offset) if command.cmd == LC.SEGMENT or command.cmd == LC.SEGMENT_64: @@ -512,11 +688,11 @@ def __parseSegmentCommand(self, data, offset, raw): return LoadCommandData(header=sc, name=sc.segname.decode('ASCII'), sections=sections, bytes=bytearray(raw), raw=raw) def __parseUuidCommand(self, data, offset, raw): - uc = UuidCommand.from_buffer(data, offset) + uc = self._classes.UuidCommand.from_buffer(data, offset) return LoadCommandData(header=uc, uuid=hexlify(uc.uuid), bytes=bytearray(raw), raw=raw) def __parseTwoLevelHintCommand(self, data, offset, raw): - tlhc = TwoLevelHintsCommand.from_buffer(data, offset) + tlhc = self._classes.TwoLevelHintsCommand.from_buffer(data, offset) hints = self.__parseTwoLevelHints(data, tlhc) return LoadCommandData(header=tlhc, twoLevelHints=hints, bytes=bytearray(raw), raw=raw) @@ -530,12 +706,12 @@ def __parseTwoLevelHints(self, data, twoLevelHintCommand): return hints def __parseDylibCommand(self, data, offset, raw): - dc = DylibCommand.from_buffer(data, offset) + dc = self._classes.DylibCommand.from_buffer(data, offset) name = get_str(raw, dc.dylib.name.offset) return LoadCommandData(header=dc, bytes=bytearray(raw), raw=raw, name=name) def __parseDylinkerCommand(self, data, offset, raw): - dc = DylinkerCommand.from_buffer(data, offset) + dc = self._classes.DylinkerCommand.from_buffer(data, offset) name = get_str(raw, dc.name.offset) return LoadCommandData(header=dc, bytes=bytearray(raw), raw=raw, name=name) @@ -544,7 +720,7 @@ def __parseSections(self, data, segment, offset): sections = [] for i in range(segment.nsects): sec = self._classes.Section.from_buffer(data, offset) - if self._classes.Section == LSB_64_Section: + if self._classes.Section in (LSB_64_Section, LSB_BE64_Section): offset += 80 else: offset += sizeof(self._classes.Section)