Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 186 additions & 10 deletions filebytes/mach_o.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,30 +183,57 @@ 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
_fields_ = [('cmd', c_uint),
('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),
('cmdsize', c_uint),
('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),
Expand All @@ -215,20 +242,42 @@ 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),
('cmdsize', c_uint),
('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),
('cmdsize', c_uint),
('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):
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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 ###########################

Expand All @@ -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
Expand All @@ -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
Expand All @@ -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 ###########################

Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)

Expand All @@ -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)

Expand All @@ -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)
Expand Down