예제 #1
0
    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()
예제 #2
0
    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()
예제 #3
0
    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()
예제 #4
0
파일: mach_o.py 프로젝트: hkkwok/MachOTool
    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')
예제 #5
0
파일: mach_o.py 프로젝트: uvbs/MachOTool
    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')