Loading ropperapp/loaders/loader.py +1 −1 Original line number Diff line number Diff line Loading @@ -26,7 +26,7 @@ from ropperapp.common.error import * class Type(Enum): _enum_ = 'ELF PE' _enum_ = 'ELF PE MACH_O' class DataContainer(object): Loading ropperapp/loaders/mach_intern/mach32.py +3 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ from ctypes import * class MachHeader(LittleEndianStructure): _fields_ = [('magic', c_uint), ('cputype', c_uint), Loading Loading @@ -48,7 +49,7 @@ class SegmentCommand(LittleEndianStructure): class Section(LittleEndianStructure): _fields_ = [('sectname', c_char * 16), ('segname', c_uint * 16), ('segname', c_char * 16), ('addr', c_uint), ('size', c_uint), ('offset', c_uint), Loading @@ -70,5 +71,5 @@ class TwoLevelHint(LittleEndianStructure): _fields_ = [('isub_image', c_uint), ('itoc', c_uint)] class LcStr(LittleEndianUnion): class LcStr(Union): _fields_ = [('offset', c_uint)] ropperapp/loaders/mach_intern/mach64.py 0 → 100644 +76 −0 Original line number Diff line number Diff line #!/usr/bin/env python2 # coding=utf-8 # # Copyright 2014 Sascha Schirra # # This file is part of Ropper. # # Ropper is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ropper is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. from ctypes import * class MachHeader(LittleEndianStructure): _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 SegmentCommand(LittleEndianStructure): _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 Section(LittleEndianStructure): _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 TwoLevelHintsCommand(LittleEndianStructure): _fields_ = [('cmd', c_uint), ('cmdsize', c_uint), ('offset', c_uint), ('nhints', c_uint)] class TwoLevelHint(LittleEndianStructure): _fields_ = [('isub_image', c_uint), ('itoc', c_uint)] class LcStr(Union): _fields_ = [('offset', c_uint)] ropperapp/loaders/mach_intern/mach_gen.py +11 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. from ropperapp.common.enum import Enum from ctypes import * from ropperapp.disasm.arch import * class TypeFlags(Enum): Loading Loading @@ -49,6 +51,7 @@ class SubTypeFlags(Enum): class CPU_SUBTYPE_X86(Enum): X86 = 3 X86_64 = X86 | SubTypeFlags.LIB64 X86_64_H = 8 I486 = 4 I486SX = 0x84 Loading Loading @@ -118,6 +121,10 @@ class LC(Enum): LINKER_OPTIMIZATION_HINT = 0x0000002E class S_ATTR(Enum): SOME_INSTRUCTIONS = 0x00000400 PURE_INSTRUCTIONS = 0x80000000 class LoadCommand(LittleEndianStructure): _fields_ = [('cmd', c_uint), ('cmdsize', c_uint)] Loading @@ -126,3 +133,7 @@ class UuidCommand(LittleEndianStructure): _fields_ = [('cmd', c_uint), ('cmdsize', c_uint), ('uuid', c_ubyte * 16)] ARCH = {int(CpuType.I386): x86, int(CpuType.X86_64): x86_64} ropperapp/loaders/mach_o.py +128 −1 Original line number Diff line number Diff line Loading @@ -17,5 +17,132 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. from loader import * from mach_intern.mach_gen import * from struct import pack as p import importlib class SegmentData(DataContainer): """ struct = SectionHeader name = string (section name) bytes = c_byte_array (section bytes) """ class LoaderData(DataContainer): """ struct = SectionHeader """ class MachO(Loader): def __init__(self, filename): self.loaderCommands = [] self.header = None self.segments = [] self.__module = None self.__imageBase = None super(MachO, self).__init__(filename) @property def entryPoint(self): return 0x0 @property def imageBase(self): if self.__imageBase == None: es = self.executableSections[0] if es != None: self.__imageBase = es.virtualAddress - es.offset else: self.__imageBase = 0x0 return self.__imageBase @property def arch(self): try: return ARCH[self.header.cputype] except: raise LoaderError('Architecture not supported') @property def type(self): return Type.MACH_O @property def executableSections(self): toReturn = [] for loaderCommand in self.loaderCommands: if loaderCommand.struct.cmd == LC.SEGMENT or loaderCommand.struct.cmd == LC.SEGMENT_64: for section in loaderCommand.sections: if section.flags & S_ATTR.SOME_INSTRUCTIONS > 0 or section.flags & S_ATTR.PURE_INSTRUCTIONS: sectbytes_p = c_void_p(self._bytes_p.value + section.offset) sectbytes = cast(sectbytes_p, POINTER(c_ubyte * section.size)).contents toReturn.append(Section(section.sectname, sectbytes, section.addr, section.offset)) return toReturn def __loadModule(self): modName = None if self._bytes[7] == 0: modName = 'ropperapp.loaders.mach_intern.mach32' elif self._bytes[7] == 1: modName = 'ropperapp.loaders.mach_intern.mach64' else: raise LoaderError('Bad architecture') self.__module = importlib.import_module(modName) def __parseSections(self, segment, segment_p): p_tmp = c_void_p(segment_p.value + sizeof(self.__module.SegmentCommand)) sections = [] for i in range(segment.nsects): sec = cast(p_tmp, POINTER(self.__module.Section)).contents p_tmp.value += sizeof(self.__module.Section) sections.append(sec) return sections def __parseSegmentCommand(self, segment_p): sc = cast(segment_p, POINTER(self.__module.SegmentCommand)).contents sections = self.__parseSections(sc, segment_p) return SegmentData(struct=sc, name=sc.segname, sections=sections) def __parseCommands(self): p_tmp = c_void_p(self._bytes_p.value + sizeof(self.__module.MachHeader)) for i in range(self.header.ncmds): command = cast(p_tmp, POINTER(LoadCommand)).contents if command.cmd == LC.SEGMENT or command.cmd == LC.SEGMENT_64: self.loaderCommands.append(self.__parseSegmentCommand(p_tmp)) else: self.loaderCommands.append(LoaderData(struct=command)) p_tmp.value += command.cmdsize def __parseHeader(self): self.header = cast(self._bytes_p, POINTER(self.__module.MachHeader)).contents def _parseFile(self): self.__loadModule() self.__parseHeader() self.__parseCommands() def setNX(self, enable): pass def setASLR(self, enable): pass @classmethod def isSupportedFile(cls, fileName): try: with open(fileName, 'rb') as f: magic = f.read(4) return magic == p('>I', 0xfeedface) or magic == p('>I', 0xfeedfacf) or magic == p('<I', 0xfeedface) or magic == p('<I', 0xfeedfacf) except BaseException as e: raise LoaderError(e) Loading
ropperapp/loaders/loader.py +1 −1 Original line number Diff line number Diff line Loading @@ -26,7 +26,7 @@ from ropperapp.common.error import * class Type(Enum): _enum_ = 'ELF PE' _enum_ = 'ELF PE MACH_O' class DataContainer(object): Loading
ropperapp/loaders/mach_intern/mach32.py +3 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ from ctypes import * class MachHeader(LittleEndianStructure): _fields_ = [('magic', c_uint), ('cputype', c_uint), Loading Loading @@ -48,7 +49,7 @@ class SegmentCommand(LittleEndianStructure): class Section(LittleEndianStructure): _fields_ = [('sectname', c_char * 16), ('segname', c_uint * 16), ('segname', c_char * 16), ('addr', c_uint), ('size', c_uint), ('offset', c_uint), Loading @@ -70,5 +71,5 @@ class TwoLevelHint(LittleEndianStructure): _fields_ = [('isub_image', c_uint), ('itoc', c_uint)] class LcStr(LittleEndianUnion): class LcStr(Union): _fields_ = [('offset', c_uint)]
ropperapp/loaders/mach_intern/mach64.py 0 → 100644 +76 −0 Original line number Diff line number Diff line #!/usr/bin/env python2 # coding=utf-8 # # Copyright 2014 Sascha Schirra # # This file is part of Ropper. # # Ropper is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ropper is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. from ctypes import * class MachHeader(LittleEndianStructure): _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 SegmentCommand(LittleEndianStructure): _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 Section(LittleEndianStructure): _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 TwoLevelHintsCommand(LittleEndianStructure): _fields_ = [('cmd', c_uint), ('cmdsize', c_uint), ('offset', c_uint), ('nhints', c_uint)] class TwoLevelHint(LittleEndianStructure): _fields_ = [('isub_image', c_uint), ('itoc', c_uint)] class LcStr(Union): _fields_ = [('offset', c_uint)]
ropperapp/loaders/mach_intern/mach_gen.py +11 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. from ropperapp.common.enum import Enum from ctypes import * from ropperapp.disasm.arch import * class TypeFlags(Enum): Loading Loading @@ -49,6 +51,7 @@ class SubTypeFlags(Enum): class CPU_SUBTYPE_X86(Enum): X86 = 3 X86_64 = X86 | SubTypeFlags.LIB64 X86_64_H = 8 I486 = 4 I486SX = 0x84 Loading Loading @@ -118,6 +121,10 @@ class LC(Enum): LINKER_OPTIMIZATION_HINT = 0x0000002E class S_ATTR(Enum): SOME_INSTRUCTIONS = 0x00000400 PURE_INSTRUCTIONS = 0x80000000 class LoadCommand(LittleEndianStructure): _fields_ = [('cmd', c_uint), ('cmdsize', c_uint)] Loading @@ -126,3 +133,7 @@ class UuidCommand(LittleEndianStructure): _fields_ = [('cmd', c_uint), ('cmdsize', c_uint), ('uuid', c_ubyte * 16)] ARCH = {int(CpuType.I386): x86, int(CpuType.X86_64): x86_64}
ropperapp/loaders/mach_o.py +128 −1 Original line number Diff line number Diff line Loading @@ -17,5 +17,132 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. from loader import * from mach_intern.mach_gen import * from struct import pack as p import importlib class SegmentData(DataContainer): """ struct = SectionHeader name = string (section name) bytes = c_byte_array (section bytes) """ class LoaderData(DataContainer): """ struct = SectionHeader """ class MachO(Loader): def __init__(self, filename): self.loaderCommands = [] self.header = None self.segments = [] self.__module = None self.__imageBase = None super(MachO, self).__init__(filename) @property def entryPoint(self): return 0x0 @property def imageBase(self): if self.__imageBase == None: es = self.executableSections[0] if es != None: self.__imageBase = es.virtualAddress - es.offset else: self.__imageBase = 0x0 return self.__imageBase @property def arch(self): try: return ARCH[self.header.cputype] except: raise LoaderError('Architecture not supported') @property def type(self): return Type.MACH_O @property def executableSections(self): toReturn = [] for loaderCommand in self.loaderCommands: if loaderCommand.struct.cmd == LC.SEGMENT or loaderCommand.struct.cmd == LC.SEGMENT_64: for section in loaderCommand.sections: if section.flags & S_ATTR.SOME_INSTRUCTIONS > 0 or section.flags & S_ATTR.PURE_INSTRUCTIONS: sectbytes_p = c_void_p(self._bytes_p.value + section.offset) sectbytes = cast(sectbytes_p, POINTER(c_ubyte * section.size)).contents toReturn.append(Section(section.sectname, sectbytes, section.addr, section.offset)) return toReturn def __loadModule(self): modName = None if self._bytes[7] == 0: modName = 'ropperapp.loaders.mach_intern.mach32' elif self._bytes[7] == 1: modName = 'ropperapp.loaders.mach_intern.mach64' else: raise LoaderError('Bad architecture') self.__module = importlib.import_module(modName) def __parseSections(self, segment, segment_p): p_tmp = c_void_p(segment_p.value + sizeof(self.__module.SegmentCommand)) sections = [] for i in range(segment.nsects): sec = cast(p_tmp, POINTER(self.__module.Section)).contents p_tmp.value += sizeof(self.__module.Section) sections.append(sec) return sections def __parseSegmentCommand(self, segment_p): sc = cast(segment_p, POINTER(self.__module.SegmentCommand)).contents sections = self.__parseSections(sc, segment_p) return SegmentData(struct=sc, name=sc.segname, sections=sections) def __parseCommands(self): p_tmp = c_void_p(self._bytes_p.value + sizeof(self.__module.MachHeader)) for i in range(self.header.ncmds): command = cast(p_tmp, POINTER(LoadCommand)).contents if command.cmd == LC.SEGMENT or command.cmd == LC.SEGMENT_64: self.loaderCommands.append(self.__parseSegmentCommand(p_tmp)) else: self.loaderCommands.append(LoaderData(struct=command)) p_tmp.value += command.cmdsize def __parseHeader(self): self.header = cast(self._bytes_p, POINTER(self.__module.MachHeader)).contents def _parseFile(self): self.__loadModule() self.__parseHeader() self.__parseCommands() def setNX(self, enable): pass def setASLR(self, enable): pass @classmethod def isSupportedFile(cls, fileName): try: with open(fileName, 'rb') as f: magic = f.read(4) return magic == p('>I', 0xfeedface) or magic == p('>I', 0xfeedfacf) or magic == p('<I', 0xfeedface) or magic == p('<I', 0xfeedfacf) except BaseException as e: raise LoaderError(e)