def write(self, fileobj): fileobj = fileview(fileobj, self.offset, self.size) fileobj.seek(0) # serialize all the mach-o commands self.synchronize_size() self.header.to_fileobj(fileobj) for lc, cmd, data in self.commands: lc.to_fileobj(fileobj) cmd.to_fileobj(fileobj) if isinstance(data, unicode): fileobj.write(data.encode(sys.getfilesystemencoding())) elif isinstance(data, (bytes, str)): fileobj.write(data) else: # segments.. for obj in data: obj.to_fileobj(fileobj) # zero out the unused space, doubt this is strictly necessary # and is generally probably already the case fileobj.write(B('\x00') * (self.low_offset - fileobj.tell()))
def readMachoFile(path): rout = {} logger.info("It is getting the header of the MachoFile") header = getHeader(path) descripe = dict(header.header._describe()) cupType = descripe.get("cputype_string") rout["MachHeader"] = descripe commands = [] logger.info("It is getting the contents of the MachoFile") for (index,(lc, cmd, data)) in enumerate(header.commands): lc_name = lc.get_cmd_name() if lc_name==44: if cupType.find("64")!=-1: lc_name = "LC_ENCRYPTION_INFO_64" else: lc_name = "LC_ENCRYPTION_INFO" desc = cmd.describe() if lc_name=="LC_SEGMENT_64" or lc_name == "LC_SEGMENT": sec_num = cmd.nsects if sec_num > 0: for sec in data: secDesc = sec.describe() strs = '' with open(path, 'rb') as fp: fh = fileview(fp, sec.addr, sec.size) fh.seek(0) with open("temp","wb") as f: f.write(fh.read()) for s in strings("temp"): if isinstance(s, str): strs = strs + s + ',' secDesc["strings"] = strs desc[str(sec.sectname.rstrip('\x00'))] = secDesc os.remove("temp") else: desc["data"] = data.rstrip('\x00') commands.append(desc) rout["loadcommand"] = commands return rout
def write(self, fileobj): fileobj = fileview(fileobj, self.offset, self.size) fileobj.seek(0) # serialize all the mach-o commands self.synchronize_size() # self.header.to_fileobj(fileobj) for lc, cmd, data in self.commands: if lc not in self.mod_dict: continue changed_arr = self.mod_dict[lc] for changed in changed_arr: if changed is lc: lc.to_fileobj(fileobj) elif changed is cmd: cmd.to_fileobj(fileobj) elif changed is data: if lc.cmd == LC_SYMTAB: c = fileobj.tell() fileobj.seek(cmd.stroff) fileobj.write(data) fileobj.seek(c) elif isinstance(data, str): fileobj.write(data.encode(sys.getfilesystemencoding())) elif isinstance(data, bytes): fileobj.write(data) elif changed in data: not_zerofill = ((changed.flags & S_ZEROFILL) != S_ZEROFILL) if not_zerofill: c = fileobj.tell() fileobj.seek(changed.offset) fileobj.write(changed.section_data) fileobj.seek(c)
def write(self, fileobj): fileobj = fileview(fileobj, self.offset, self.size) fileobj.seek(0) # serialize all the mach-o commands self.synchronize_size() self.header.to_fileobj(fileobj) for lc, cmd, data in self.commands: lc.to_fileobj(fileobj) cmd.to_fileobj(fileobj) if sys.version_info[0] == 2: if isinstance(data, unicode): fileobj.write(data.encode(sys.getfilesystemencoding())) elif isinstance(data, (bytes, str)): fileobj.write(data) else: # segments.. for obj in data: obj.to_fileobj(fileobj) else: if isinstance(data, str): fileobj.write(data.encode(sys.getfilesystemencoding())) elif isinstance(data, bytes): fileobj.write(data) else: # segments.. for obj in data: obj.to_fileobj(fileobj) # zero out the unused space, doubt this is strictly necessary # and is generally probably already the case fileobj.write(b'\x00' * (self.low_offset - fileobj.tell()))
def load(self, fh): fh = fileview(fh, self.offset, self.size) fh.seek(0) self.sizediff = 0 kw = {'_endian_': self.endian} header = self.mach_header.from_fileobj(fh, **kw) self.header = header if header.magic != self.MH_MAGIC: raise ValueError("header has magic %08x, expecting %08x" % (header.magic, self.MH_MAGIC)) cmd = self.commands = [] self.filetype = MH_FILETYPE_SHORTNAMES[header.filetype] read_bytes = 0 low_offset = sys.maxsize for i in range(header.ncmds): # read the load command cmd_load = load_command.from_fileobj(fh, **kw) # read the specific command klass = LC_REGISTRY.get(cmd_load.cmd, None) if klass is None: raise ValueError("Unknown load command: %d" % (cmd_load.cmd, )) cmd_cmd = klass.from_fileobj(fh, **kw) if cmd_load.cmd == LC_ID_DYLIB: # remember where this command was if self.id_cmd is not None: raise ValueError("This dylib already has an id") self.id_cmd = i if cmd_load.cmd in (LC_SEGMENT, LC_SEGMENT_64): # for segment commands, read the list of segments segs = [] # assert that the size makes sense if cmd_load.cmd == LC_SEGMENT: section_cls = section else: # LC_SEGMENT_64 section_cls = section_64 expected_size = (sizeof(klass) + sizeof(load_command) + (sizeof(section_cls) * cmd_cmd.nsects)) if cmd_load.cmdsize != expected_size: raise ValueError("Segment size mismatch") # this is a zero block or something # so the beginning is wherever the fileoff of this command is if cmd_cmd.nsects == 0: if cmd_cmd.filesize != 0: low_offset = min(low_offset, cmd_cmd.fileoff) else: # this one has multiple segments for j in range(cmd_cmd.nsects): # read the segment seg = section_cls.from_fileobj(fh, **kw) # if the segment has a size and is not zero filled # then its beginning is the offset of this segment not_zerofill = ((seg.flags & S_ZEROFILL) != S_ZEROFILL) if seg.offset > 0 and seg.size > 0 and not_zerofill: low_offset = min(low_offset, seg.offset) segs.append(seg) # data is a list of segments cmd_data = segs else: # data is a raw str data_size = (cmd_load.cmdsize - sizeof(klass) - sizeof(load_command)) cmd_data = fh.read(data_size) cmd.append((cmd_load, cmd_cmd, cmd_data)) read_bytes += cmd_load.cmdsize # make sure the header made sense if read_bytes != header.sizeofcmds: raise ValueError("Read %d bytes, header reports %d bytes" % (read_bytes, header.sizeofcmds)) self.total_size = sizeof(self.mach_header) + read_bytes self.low_offset = low_offset # this header overwrites a segment, what the heck? if self.total_size > low_offset: raise ValueError("total_size > low_offset (%d > %d)" % (self.total_size, low_offset))
def getPartOfFile(path, start, size): with open(path, 'rb') as fp: fh = fileview(fp, start, size) fh.seek(0) with open("temp", "wb") as f: f.write(fh.read())
def load(self, fh): fh = fileview(fh, self.offset, self.size) fh.seek(0) self.sizediff = 0 kw = {'_endian_': self.endian} header = self.mach_header.from_fileobj(fh, **kw) self.header = header if header.magic != self.MH_MAGIC: raise ValueError("header has magic %08x, expecting %08x" % ( header.magic, self.MH_MAGIC)) cmd = self.commands = [] self.filetype = MH_FILETYPE_SHORTNAMES[header.filetype] read_bytes = 0 low_offset = sys.maxsize for i in range(header.ncmds): # read the load command cmd_load = load_command.from_fileobj(fh, **kw) # read the specific command klass = LC_REGISTRY.get(cmd_load.cmd, None) if klass is None: raise ValueError("Unknown load command: %d" % (cmd_load.cmd)) cmd_cmd = klass.from_fileobj(fh, **kw) if cmd_load.cmd == LC_ID_DYLIB: # remember where this command was if self.id_cmd is not None: raise ValueError("This dylib already has an id") self.id_cmd = i if cmd_load.cmd in (LC_SEGMENT, LC_SEGMENT_64): # for segment commands, read the list of segments segs = [] # assert that the size makes sense if cmd_load.cmd == LC_SEGMENT: section_cls = section else: # LC_SEGMENT_64 section_cls = section_64 expected_size = ( sizeof(klass) + sizeof(load_command) + (sizeof(section_cls) * cmd_cmd.nsects) ) if cmd_load.cmdsize != expected_size: raise ValueError("Segment size mismatch") # this is a zero block or something # so the beginning is wherever the fileoff of this command is if cmd_cmd.nsects == 0: if cmd_cmd.filesize != 0: low_offset = min(low_offset, cmd_cmd.fileoff) else: # this one has multiple segments for j in range(cmd_cmd.nsects): # read the segment seg = section_cls.from_fileobj(fh, **kw) # if the segment has a size and is not zero filled # then its beginning is the offset of this segment not_zerofill = ((seg.flags & S_ZEROFILL) != S_ZEROFILL) if seg.offset > 0 and seg.size > 0 and not_zerofill: low_offset = min(low_offset, seg.offset) segs.append(seg) # data is a list of segments cmd_data = segs else: # data is a raw str data_size = ( cmd_load.cmdsize - sizeof(klass) - sizeof(load_command) ) cmd_data = fh.read(data_size) cmd.append((cmd_load, cmd_cmd, cmd_data)) read_bytes += cmd_load.cmdsize # make sure the header made sense if read_bytes != header.sizeofcmds: raise ValueError("Read %d bytes, header reports %d bytes" % ( read_bytes, header.sizeofcmds)) self.total_size = sizeof(self.mach_header) + read_bytes self.low_offset = low_offset # this header overwrites a segment, what the heck? if self.total_size > low_offset: raise ValueError("total_size > low_offset (%d > %d)" % ( self.total_size, low_offset))
def load(self, fh): fh = fileview(fh, self.offset, self.size) fh.seek(0) self.sizediff = 0 kw = {"_endian_": self.endian} header = self.mach_header.from_fileobj(fh, **kw) self.header = header # if header.magic != self.MH_MAGIC: # raise ValueError("header has magic %08x, expecting %08x" % ( # header.magic, self.MH_MAGIC)) cmd = self.commands = [] self.filetype = self.get_filetype_shortname(header.filetype) read_bytes = 0 low_offset = sys.maxsize for i in range(header.ncmds): # read the load command cmd_load = load_command.from_fileobj(fh, **kw) # read the specific command klass = LC_REGISTRY.get(cmd_load.cmd, None) if klass is None: if not self.allow_unknown_load_commands: raise ValueError("Unknown load command: %d" % (cmd_load.cmd, )) # No load command in the registry, so append the load command itself # instead of trying to deserialize the data after the header. data_size = cmd_load.cmdsize - sizeof(load_command) cmd_data = fh.read(data_size) cmd.append((cmd_load, cmd_load, cmd_data)) read_bytes += cmd_load.cmdsize continue cmd_cmd = klass.from_fileobj(fh, **kw) if cmd_load.cmd == LC_ID_DYLIB: # remember where this command was if self.id_cmd is not None: raise ValueError("This dylib already has an id") self.id_cmd = i if cmd_load.cmd in (LC_SEGMENT, LC_SEGMENT_64): # for segment commands, read the list of segments segs = [] # assert that the size makes sense if cmd_load.cmd == LC_SEGMENT: section_cls = section else: # LC_SEGMENT_64 section_cls = section_64 expected_size = (sizeof(klass) + sizeof(load_command) + (sizeof(section_cls) * cmd_cmd.nsects)) if cmd_load.cmdsize != expected_size: raise ValueError("Segment size mismatch") # this is a zero block or something # so the beginning is wherever the fileoff of this command is if cmd_cmd.nsects == 0: if cmd_cmd.filesize != 0: low_offset = min(low_offset, cmd_cmd.fileoff) else: # this one has multiple segments for _j in range(cmd_cmd.nsects): # read the segment seg = section_cls.from_fileobj(fh, **kw) # if the segment has a size and is not zero filled # then its beginning is the offset of this segment not_zerofill = (seg.flags & S_ZEROFILL) != S_ZEROFILL if seg.offset > 0 and seg.size > 0 and not_zerofill: low_offset = min(low_offset, seg.offset) if not_zerofill: c = fh.tell() fh.seek(seg.offset) sd = fh.read(seg.size) seg.add_section_data(sd) fh.seek(c) segs.append(seg) # data is a list of segments cmd_data = segs # These are disabled for now because writing back doesn't work # elif cmd_load.cmd == LC_CODE_SIGNATURE: # c = fh.tell() # fh.seek(cmd_cmd.dataoff) # cmd_data = fh.read(cmd_cmd.datasize) # fh.seek(c) # elif cmd_load.cmd == LC_SYMTAB: # c = fh.tell() # fh.seek(cmd_cmd.stroff) # cmd_data = fh.read(cmd_cmd.strsize) # fh.seek(c) else: # data is a raw str data_size = cmd_load.cmdsize - sizeof(klass) - sizeof( load_command) cmd_data = fh.read(data_size) cmd.append((cmd_load, cmd_cmd, cmd_data)) read_bytes += cmd_load.cmdsize # make sure the header made sense if read_bytes != header.sizeofcmds: raise ValueError("Read %d bytes, header reports %d bytes" % (read_bytes, header.sizeofcmds)) self.total_size = sizeof(self.mach_header) + read_bytes self.low_offset = low_offset