def symbol(self, matched_idx): assert 0 <= matched_idx < self.num_matched table_idx = 0 section_desc = '' for mapping in self._filter_mappings: mapping_size = len(mapping) if matched_idx >= mapping_size: matched_idx -= mapping_size table_idx += 1 continue (index, n_strx, n_type, n_sect, n_desc, n_value, symbol_name) = \ self._symbol_tables[table_idx].symbols[mapping[matched_idx]] nlist = Nlist64(index=index, n_strx=n_strx, n_type=n_type, n_sect=n_sect, n_desc=n_desc, n_value=n_value) if nlist.n_sect != 0: this_section = self._sections[nlist.n_sect] section_desc = '%s, %s' % \ (NullTerminatedStringField.get_string(this_section.segname), NullTerminatedStringField.get_string(this_section.sectname)) return nlist, symbol_name, section_desc assert False # should never get here
def __init__(self, seg_name, sect_name, bytes_): self.seg_name = None self.sect_name = None seg_name = NullTerminatedStringField.get_string(seg_name) sect_name = NullTerminatedStringField.get_string(sect_name) super(SectionBlock, self).__init__('Section: %s %s' % (seg_name, sect_name), seg_name=seg_name, sect_name=sect_name) self.parse_bytes(bytes_)
def parse(self, section_desc): section = section_desc.section self.initialize(section.offset, section.size) # Get the segment and section names seg_name = NullTerminatedStringField.get_string(section.segname) sect_name = NullTerminatedStringField.get_string(section.sectname) bytes_ = self.get_bytes() if seg_name == '__TEXT': data_section = TextSection(sect_name, bytes_) elif seg_name == '__DATA': data_section = DataSection(sect_name, bytes_) else: data_section = SectionBlock(seg_name, sect_name, bytes_) # If the section is inside a encrypted region (specificed by LC_ENCRYPTION_INFO), # we cannot parse it because we don't have the decryption key. So, we just # create a block without trying to parse its content. if self.mach_o.is_section_encrypted(section): data_section.name += ' [ENCRYPTED]' self.add_subrange(data_section, section.size) return if section.offset == 0: # .bss and .common sections only exist in VM but not in the file. So, they have an offset of 0 # which aliases with the mach header. We do not add any subrange for these sections since # there is no data to parse / display. # TODO - in some iOS binraries, offset is set to 0 for many sections that should have data # Need to study them more to determine if offset is just not set proerly and we can # compute the offset from the first data section and the VM address. return elif section_desc.is_cstring(): data_section = CstringSection(bytes_) cstring_br = self.add_subrange(data_section, section.size) for (offset, string) in data_section.items(): unescaped_string = Unescape.convert(string) cstring_br.add_subrange(offset, len(string) + 1, data=Cstring(unescaped_string)) elif section_desc.is_objc_methname(): data_section = ObjCMethodNameSection(bytes_) obj_methname_br = self.add_subrange(data_section, section.size) for (offset, string) in data_section.items(): unescaped_string = Unescape.convert(string) obj_methname_br.add_subrange( offset, len(string) + 1, data=ObjCMethodName(unescaped_string)) else: self.add_subrange(data_section, section.size)
def __init__(self, sect_name, bytes_): sect_name = NullTerminatedStringField.get_string(sect_name) super(TextSection, self).__init__('__TEXT', sect_name, bytes_) self.name = 'TextSection: %s' % sect_name
def __init__(self, sect_name, bytes_): sect_name = NullTerminatedStringField.get_string(sect_name) super(DataSection, self).__init__('__DATA', sect_name, bytes_) self.name = 'DataSection: %s' % sect_name
def __init__(self, seg_name): self.seg_name = None seg_name = NullTerminatedStringField.get_string(seg_name) super(SegmentBlock, self).__init__('Segment: %s' % seg_name, color='cyan', bold=True, seg_name=seg_name)