def _add_subtree(self, parent_id, br): def get_values(sr): if hasattr(sr.data, 'name'): desc = sr.data.name else: desc = str(sr.data) (start, stop) = sr.abs_range() return desc, format(start, ','), format(stop, ',') pi = ProgressIndicator('show byte ranges...', 1) for idx in xrange(len(br.subranges)): subrange = br.subranges[idx] child_id = parent_id + '.%d' % idx if not self.byte_range_tree.tree.exists(child_id): child_id = self.byte_range_tree.add( parent_id, idx, values=get_values(subrange)) if len(subrange.subranges) > 0: # if there are subsubranges, just insert 1st row so that the open icon is shown if not self.byte_range_tree.tree.exists(child_id + '.0'): subsubrange = subrange.subranges[0] self.byte_range_tree.add(child_id, 0, values=get_values(subsubrange)) pi.click() pi.done()
def _add_subtree(self, parent_id, br): def get_values(sr): if hasattr(sr.data, 'name'): desc = sr.data.name else: desc = str(sr.data) (start, stop) = sr.abs_range() return desc, format(start, ','), format(stop, ',') pi = ProgressIndicator('show byte ranges...', 1) for idx in xrange(len(br.subranges)): subrange = br.subranges[idx] child_id = parent_id + '.%d' % idx if not self.byte_range_tree.tree.exists(child_id): child_id = self.byte_range_tree.add(parent_id, idx, values=get_values(subrange)) if len(subrange.subranges) > 0: # if there are subsubranges, just insert 1st row so that the open icon is shown if not self.byte_range_tree.tree.exists(child_id + '.0'): subsubrange = subrange.subranges[0] self.byte_range_tree.add(child_id, 0, values=get_values(subsubrange)) pi.click() pi.done()
def parse(self, symtab_command): if symtab_command is None: return self.initialize(0, len(self.byte_range)) if ProgressIndicator.ENABLED: progress = ProgressIndicator('parsing symbol table...', 4096) else: progress = None # Add nlist entries and string table section. sym_tab = SymbolTable(symtab_command.nsyms) sym_str_tab = SymbolStringTable() sym_br = self.add_section(symtab_command.symoff, symtab_command.nsyms * self.nlist_size, data=sym_tab) self.add_section(symtab_command.stroff, symtab_command.strsize, data=sym_str_tab) str_bytes_ = self.byte_range.bytes( symtab_command.stroff, symtab_command.stroff + symtab_command.strsize) # Parse all nlist entries for idx in xrange(symtab_command.nsyms): if progress is not None: progress.click() start = idx * self.nlist_size stop = start + self.nlist_size bytes_ = sym_br.bytes(start, stop) nlist = self.nlist_class(bytes_) # The original code was: # # sym_br.add_subrange(start, self.nlist_size, data=nlist) # # The problem is that for a real iOS app, there can be hundreds of thousands if not # millions of symbols and these Nlist and BytesRange objects consume a lot of memory. # (Each python object with attribute seems to consume at least 300B.) # # The solution is to deviate the framework and save the values of these nlist headers # into a big list. sym_tab.add(nlist) if nlist.n_strx == 0: # From nlist.h: # # Symbols with a index into the string table of zero (n_un.n_strx == 0) are # defined to have a null, "", name. Therefore all string indexes to non null # names must not have a zero string index. This is bit historical information # that has never been well documented. pass else: (sym_name, total_len) = self._find_string(str_bytes_, nlist.n_strx) # Original code is: # # str_br.add_subrange(nlist.n_strx, total_len, data=SymtabString(nlist.n_strx, sym_name)) # # Again, we avoid creating the byte range in order to reduce memory consumption. sym_str_tab.add(nlist.n_strx, sym_name) sym_tab.correlate_string_table(sym_str_tab) if progress is not None: progress.done()
def __init__(self, mach_o_br): self.arch_width = None self.mach_header = None self.load_commands = list() self.segments = dict() self.linkedit_br = None self.encryption_info_commands = list() # Try to parse it as mach_header start = 0 hdr_size = None try: hdr_size = MachHeader.get_size() self.mach_header = MachHeader(mach_o_br.bytes(start, hdr_size)) self.arch_width = 32 except HeaderInvalidValueError: pass # If fail, try mach_header_64 if self.mach_header is None: try: hdr_size = MachHeader64.get_size() self.mach_header = MachHeader64(mach_o_br.bytes(start, hdr_size)) self.arch_width = 64 except ValueError: raise ValueError('mach_o: no valid mach header found') self.name = 'Mach-O: %s' % self.mach_header.FIELDS[1].display(self.mach_header) # Create a subrange for the parsed mach_header mach_header_br = mach_o_br.add_subrange(start, hdr_size) mach_header_br.data = self.mach_header # Parse each load commands lc_parser = LoadCommandParser(mach_o_br, self) start += hdr_size lc_size = LoadCommand.get_size() for idx in xrange(self.mach_header.ncmds): ProgressIndicator.display('parsing load command %d\n', idx) generic_lc = LoadCommand(mach_o_br.bytes(start, start + lc_size)) lc_parser.parse(generic_lc, start) start += generic_lc.cmdsize # Add all data sections for (seg_name, segment_desc) in self.segments.items(): for (sect_name, section_desc) in segment_desc.sections.items(): ProgressIndicator.display('parsing section %s, %s\n', seg_name, sect_name) SectionParser(mach_o_br, self).parse(section_desc) # Add all encryption blocks for lc in self.encryption_info_commands: assert isinstance(lc, (EncryptionInfoCommand, EncryptionInfoCommand64)) mach_o_br.insert_subrange(lc.cryptoff, lc.cryptsize, data=EncryptedBlock(lc.cryptid)) # Add all segments for (seg_name, segment_desc) in self.segments.items(): ProgressIndicator.display('parsing segment %s\n', seg_name) br = SegmentParser(mach_o_br).parse(segment_desc) if seg_name.startswith('__LINKEDIT'): self.linkedit_br = br ProgressIndicator.display('mach-o parsed\n')
def __init__(self, mach_o_br): self.arch_width = None self.mach_header = None self.load_commands = list() self.segments = dict() self.linkedit_br = None self.encryption_info_commands = list() # Try to parse it as mach_header start = 0 hdr_size = None try: hdr_size = MachHeader.get_size() self.mach_header = MachHeader(mach_o_br.bytes(start, hdr_size)) self.arch_width = 32 except HeaderInvalidValueError: pass # If fail, try mach_header_64 if self.mach_header is None: try: hdr_size = MachHeader64.get_size() self.mach_header = MachHeader64( mach_o_br.bytes(start, hdr_size)) self.arch_width = 64 except ValueError: raise ValueError('mach_o: no valid mach header found') self.name = 'Mach-O: %s' % self.mach_header.FIELDS[1].display( self.mach_header) # Create a subrange for the parsed mach_header mach_header_br = mach_o_br.add_subrange(start, hdr_size) mach_header_br.data = self.mach_header # Parse each load commands lc_parser = LoadCommandParser(mach_o_br, self) start += hdr_size lc_size = LoadCommand.get_size() for idx in xrange(self.mach_header.ncmds): ProgressIndicator.display('parsing load command %d\n', idx) generic_lc = LoadCommand(mach_o_br.bytes(start, start + lc_size)) lc_parser.parse(generic_lc, start) start += generic_lc.cmdsize # Add all data sections for (seg_name, segment_desc) in self.segments.items(): for (sect_name, section_desc) in segment_desc.sections.items(): ProgressIndicator.display('parsing section %s, %s\n', seg_name, sect_name) SectionParser(mach_o_br, self).parse(section_desc) # Add all encryption blocks for lc in self.encryption_info_commands: assert isinstance(lc, (EncryptionInfoCommand, EncryptionInfoCommand64)) mach_o_br.insert_subrange(lc.cryptoff, lc.cryptsize, data=EncryptedBlock(lc.cryptid)) # Add all segments for (seg_name, segment_desc) in self.segments.items(): ProgressIndicator.display('parsing segment %s\n', seg_name) br = SegmentParser(mach_o_br).parse(segment_desc) if seg_name.startswith('__LINKEDIT'): self.linkedit_br = br ProgressIndicator.display('mach-o parsed\n')