def parse_section(self): name = strip(self.f.read(16)) segname = strip(self.f.read(16)) addr = get_int(self.f) if self.macho.is_32_bit() else get_ll(self.f) size = get_int(self.f) if self.macho.is_32_bit() else get_ll(self.f) offset = get_int(self.f) align = get_int(self.f) reloff = get_int(self.f) nreloc = get_int(self.f) flags = get_int(self.f) self.f.read(8) if self.macho.is_32_bit() else self.f.read(12) if self.macho.is_little(): addr = little(addr, 'I') if self.macho.is_32_bit() \ else little(addr, 'Q') size = little(size, 'I') if self.macho.is_32_bit() \ else little(size, 'Q') offset = little(offset, 'I') align = little(align, 'I') reloff = little(reloff, 'I') nreloc = little(nreloc, 'I') flags = little(flags, 'I') section = Section(name=name, segname=segname, addr=addr, offset=offset, align=align, reloff=reloff, nreloc=nreloc, size=size) self.parse_section_flags(section, flags) return section
def parse_segment(self, lc): name = strip(self.f.read(16)) vmaddr = get_int(self.f) if self.macho.is_32_bit() else get_ll(self.f) vmsize = get_int(self.f) if self.macho.is_32_bit() else get_ll(self.f) offset = get_int(self.f) if self.macho.is_32_bit() else get_ll(self.f) segsize = get_int(self.f) if self.macho.is_32_bit() else get_ll(self.f) maxprot = get_int(self.f) initprot = get_int(self.f) nsects = get_int(self.f) flags = get_int(self.f) if self.macho.is_little(): vmaddr = little(vmaddr, 'I') if self.macho.is_32_bit() \ else little(vmaddr, 'Q') vmsize = little(vmsize, 'I') if self.macho.is_32_bit() \ else little(vmsize, 'Q') offset = little(offset, 'I') if self.macho.is_32_bit() \ else little(offset, 'Q') segsize = little(segsize, 'I') if self.macho.is_32_bit() \ else little(segsize, 'Q') maxprot = little(maxprot, 'I') initprot = little(initprot, 'I') nsects = little(nsects, 'I') flags = little(flags, 'I') maxprot = dictionary.protections[maxprot & 0b111] initprot = dictionary.protections[initprot & 0b111] entropy = self.get_segment_entropy(offset, segsize) segment = Segment(cmd=lc.cmd, size=lc.size, name=name, vmaddr=vmaddr, vmsize=vmsize, offset=offset, segsize=segsize, maxprot=maxprot, initprot=initprot, nsects=nsects, entropy=entropy) if self.macho.is_32_bit(): sect_size = 68 else: sect_size = 80 for i in range(segment.nsects): if self.f.tell() + sect_size > self.file_size: data = {'offset': self.f.tell(), 'file_size': self.file_size} a = Abnormality(title='SECTION OUT OF BOUNDS', data=data) break sect = self.parse_section() segment.add_sect(sect) self.parse_segment_flags(segment, flags) self.macho.add_lc(segment)
def parse_main(self, lc): offset = get_ll(self.f) size = get_ll(self.f) if self.macho.is_little(): offset = little(offset, 'Q') size = little(size, 'Q') lc.add_data('offset', offset) lc.add_data('size', size) self.macho.add_lc(lc)
def parse_segment(self, lc): name = strip(self.f.read(16)) vmaddr = get_int(self.f) if self.macho.is_32_bit() else get_ll(self.f) vmsize = get_int(self.f) if self.macho.is_32_bit() else get_ll(self.f) offset = get_int(self.f) if self.macho.is_32_bit() else get_ll(self.f) segsize = get_int(self.f) if self.macho.is_32_bit() else get_ll(self.f) maxprot = get_int(self.f) initprot = get_int(self.f) nsects = get_int(self.f) flags = get_int(self.f) if self.macho.is_little(): vmaddr = little(vmaddr, 'I') if self.macho.is_32_bit() \ else little(vmaddr, 'Q') vmsize = little(vmsize, 'I') if self.macho.is_32_bit() \ else little(vmsize, 'Q') offset = little(offset, 'I') if self.macho.is_32_bit() \ else little(offset, 'Q') segsize = little(segsize, 'I') if self.macho.is_32_bit() \ else little(segsize, 'Q') maxprot = little(maxprot, 'I') initprot = little(initprot, 'I') nsects = little(nsects, 'I') flags = little(flags, 'I') maxprot = dictionary.protections[maxprot & 0b111] initprot = dictionary.protections[initprot & 0b111] entropy = self.get_segment_entropy(offset, segsize) segment = Segment(cmd=lc.cmd, size=lc.size, name=name, vmaddr=vmaddr, vmsize=vmsize, offset=offset, segsize=segsize, maxprot=maxprot, initprot=initprot, nsects=nsects, entropy=entropy) if self.macho.is_32_bit(): sect_size = 68 else: sect_size = 80 for i in range(segment.nsects): if self.f.tell() + sect_size > self.file_size: data = { 'offset': self.f.tell(), 'file_size': self.file_size } a = Abnormality(title='SECTION OUT OF BOUNDS', data=data) break sect = self.parse_section() segment.add_sect(sect) self.parse_segment_flags(segment, flags) self.macho.add_lc(segment)
def parse_routines(self, lc): if lc.cmd == 'ROUTINES': init_address = get_int(self.f) init_module = get_int(self.f) if self.macho.is_little(): init_address = little(init_address, 'I') init_module = little(init_module, 'I') self.f.read(24) else: init_address = get_ll(self.f) init_module = get_ll(self.f) if self.macho.is_little(): init_address = little(init_address, 'Q') init_module = little(init_module, 'Q') self.f.read(48) lc.add_data('init_address', init_address) lc.add_data('init_module', init_module) self.macho.add_lc(lc)
def parse_source_version(self, lc): version = get_ll(self.f) if self.macho.is_little(): version = little(version, 'Q') a = str((version >> 40) & 0xffffff) b = str((version >> 30) & 0x3ff) c = str((version >> 20) & 0x3ff) d = str((version >> 10) & 0x3ff) e = str(version & 0x3ff) # TODO: fix source version. version = a + '.' + b + '.' + c + '.' + d + '.' + e lc.add_data('version', version) self.macho.add_lc(lc)
def parse_syms(self, macho): prev = self.f.tell() true_offset = macho.offset + macho.symtab.offset if macho.is_64_bit(): symbol_size = 60 else: symbol_size = 56 if (true_offset < macho.offset + macho.size and true_offset < self.file.size): self.f.seek(true_offset) for i in range(macho.symtab.nsyms): if ((self.f.tell() + symbol_size > macho.offset + macho.size) or (self.f.tell() + symbol_size > self.file.size)): data = { 'offset': self.f.tell(), 'mach-o_size': macho.size, 'mach-o_offset': macho.offset, 'file_size': self.file.size } a = Abnormality(title='REMAINING SYMBOLS OUT OF BOUNDS', data=data) self.add_abnormality(a) self.f.seek(prev) return else: index = get_int(self.f) sym_type = int(self.f.read(1).encode('hex'), 16) sect = int(self.f.read(1).encode('hex'), 16) desc = int(self.f.read(2).encode('hex'), 16) value = None if macho.is_64_bit(): if macho.is_little(): value = little(get_ll(self.f), 'Q') else: value = get_ll(self.f) else: if macho.is_little(): value = little(get_int(self.f), 'I') else: value = get_int(self.f) if macho.is_little(): index = little(index, 'I') if sym_type >= 32: if sym_type in dictionary.stabs: stab = dictionary.stabs[sym_type] else: offset = self.f.tell() - symbol_size data = { 'offset': offset, 'index': index, 'sym_type': sym_type, 'sect': sect, 'desc': desc, 'value': value } a = Abnormality(title='UNKNOWN STAB', data=data) self.add_abnormality(a) continue sym = Symbol(index=index, stab=stab, sect=sect, value=value) macho.symtab.add_sym(sym) else: pext = sym_type & 0x10 if sym_type & 0x0e in dictionary.n_types: n_type = dictionary.n_types[sym_type & 0x0e] else: offset = self.f.tell() - symbol_size data = { 'offset': offset, 'index': index, 'pext': pext, 'n_type': sym_type & 0x0e, 'sect': sect, 'desc': desc, 'value': value } a = Abnormality(title='UNKNOWN N_TYPE', data=data) self.add_abnormality(a) ext = sym_type & 0x01 if macho.is_little(): dylib = desc & 0x0f ref = (desc >> 8) & 0xff else: dylib = (desc >> 8) & 0xff ref = desc & 0x0f sym = Symbol(index=index, pext=pext, sym_type=n_type, ext=ext, sect=sect, dylib=dylib, ref=ref, value=value) macho.symtab.add_sym(sym) else: data = { 'offset': true_offset, 'mach-o_size': macho.size, 'mach-o_offset': macho.offset, 'file_size': self.file.size } a = Abnormality(title='SYMBOL TABLE OUT OF BOUNDS', data=data) self.add_abnormality(a) self.f.seek(prev)