Example #1
0
    def __init__(self, ea=UseCurrentAddress, name=None, index=None):
        """Wrapper around IDA segments.

        There are 3 ways to get a segment - by name, ea or index. Only use one.

        Args:
            ea - address in the segment
            name - name of the segment
            index - index of the segment
        """
        if sum((ea not in (self.UseCurrentAddress, None), name is not None, index is not None,)) > 1:
            raise ValueError(
                "Expected only one (ea, name or index). Got (ea={!r}, name={!r}, index={!r})".format(ea, name, index))

        elif name is not None:
            seg = idaapi.get_segm_by_name(name)

        elif index is not None:
            seg = idaapi.getnseg(index)

        elif ea == self.UseCurrentAddress:
            seg = idaapi.getseg(idc.here())

        elif ea is None:
            raise ValueError("`None` is not a valid address. To use the current screen ea, "
                             "use `Function(ea=Function.UseCurrentAddress)` or supply no `ea`.")

        else:
            seg = idaapi.getseg(ea)

        self._segment = seg
Example #2
0
 def get_cur_offset(self):
     ea = idc.ScreenEA()
     seg = idaapi.getseg(ea)
     SigmName = idc.SegName(ea)
     startA = idc.SegStart(ea)
     self.off_edit.setText(hex(ea - startA).upper())
     self.search_edit.setText(SigmName)
Example #3
0
    def update_content_viewers(self):
        n = self.GetLineNo()
        item = self.get_item(n)
        self.dav.clear()
        self.hv.clear()
        self.iv.clear()


        if item != None and item.type == Item.TYPE_CODE:

            # get disassembly and hex stream
            dis = self.payload.da.get_disasm(item.ea)
            for line in dis:
                self.dav.add_line(line[0])
                self.hv.add_line(line[1])

            # get various info
            seg = idaapi.getseg(item.ea)
            if seg:
                name      = idaapi.get_true_segm_name(seg)
                perm      = seg.perm
                ltype     = "ld" if seg.is_loader_segm() else "dbg"
                ea_start  = seg.startEA
                ea_end    = seg.endEA

                perms = ""
                perms += "R" if perm & idaapi.SEGPERM_READ != 0 else "."
                perms += "W" if perm & idaapi.SEGPERM_WRITE != 0 else "."
                perms += "X" if perm & idaapi.SEGPERM_EXEC != 0 else "."                
                self.iv.add_line("<%s> [%X - %X], %s, [%s]" % (name, ea_start, ea_end, ltype, perms))


        self.dav.update()
        self.hv.update()
        self.iv.update()
Example #4
0
def create(offset, size, name, **kwds):
    '''Create a segment at /offset/ and /size/ and name it /name/

    /bits/ can be used to specify the bit size of the segment
    /comb/ can be used to specify any flags (idaapi.sc*)
    /align/ can be used to specify paragraph alignment (idaapi.sa*)
    /org/ specifies the origin of the segment (must be paragraph aligned due to ida)
    '''
    s = idaapi.get_segm_by_name(name)
    if s is not None:
        logging.fatal("segment.create(%x, %x, %r, %r) : a segment with the specified name already exists : %s", offset, size, name, kwds, name)
        return None

    bits = kwds.get( 'bits', 32 if idaapi.getseg(offset) is None else idaapi.getseg(offset).abits()) # FIXME: use disassembler default bit length instead of 32

    if bits == 16:
        ## create a selector with the requested origin
        org = kwds.get('org',0)
        if org&0xf > 0:
            logging.fatal("segment.create(%x, %x, %r, %r) : origin (.org) is not aligned to the size of a paragraph (0x10):%x", offset, size, name, kwds, org)
            return None

        para = offset/16
        sel = idaapi.allocate_selector(para)
        idaapi.set_selector(sel, (para-kwds.get('org',0)/16)&0xffffffff)
    else:
        ## auto-create a selector for everything else
        sel = idaapi.setup_selector(kwds['selector']) if 'selector' in kwds else idaapi.find_free_selector()

    # create segment. ripped from idc
    s = idaapi.segment_t()
    s.startEA = offset
    s.endEA = offset+size
    s.sel = sel
    s.bitness = {16:0,32:1,64:2}[bits]
    s.comb = kwds.get('comb', idaapi.scPub)       # public
    s.align = kwds.get('align', idaapi.saRelByte)  # paragraphs

    res = idaapi.add_segm_ex(s, name, "", idaapi.ADDSEG_NOSREG|idaapi.ADDSEG_SPARSE)
    if res == 0:
        logging.warn("segment.create(%x, %x, %r, %r) : unable to add a new segment", offset, size, name, kwds)
        res = idaapi.del_selector(sel)
        #assert res != 0
        return None
    return s
Example #5
0
def output_segments(out):
    """Dump binary segmentation."""
    info = idaapi.get_inf_structure()
    size = "r32" if info.is_32bit else "r64"
    out.writelines(('(', info.get_proc_name()[1], ' ', size, ' ('))
    for seg in idautils.Segments():
        out.write("\n({} {} {:d} ({:#x} {:d}))".format(
            idaapi.get_segm_name(seg),
            "code" if idaapi.segtype(seg) == idaapi.SEG_CODE else "data",
            idaapi.get_fileregion_offset(seg),
            seg, idaapi.getseg(seg).size()))
    out.write("))\n")
Example #6
0
def get_import_module_name(address):
    
    global module_names
    global idata_seg_start
    global idata_seg_end
    
    segment_eas = list( idautils.Segments() )
    
    # This hasn't been initialized yet...
    #
    if module_names is None:
        
        module_names = list()
        for idata_seg_start in segment_eas:
            print "Going through segment %08X" % idata_seg_start
            segment = idaapi.getseg(idata_seg_start)
            if segment.type != idaapi.SEG_XTRN:
                continue
            print "Found idata segment"
        
            idata_seg_end = idc.SegEnd(idata_seg_start)
            
            parse = re.compile('.*Imports\s+from\s+([\w\d]+\.[\w\d]+).*', re.IGNORECASE)
            
            # save the address/module name combinations we discover
            #
            modules = list()
            
            # Scan the .idata segment looking for the imports from
            # string and get the address ranges where it applies
            #
            for head in idautils.Heads(idata_seg_start, idata_seg_end):
                for line_id in range(100):
                    line = idc.LineA(head, line_id)
                    if line and 'imports from' in line.lower():
                        res = parse.match(line)
                        if res:
                            print 'Found import line [%s][%s]' % (line, res.group(1))
                            modules.append( (head, res.group(1).lower()) )
                
            modules.append( (idata_seg_end, None) )
            for idx in range(len(modules)-1):
                mod = modules[idx]
                module_names.append( ( (mod[0], modules[idx+1][0]), mod[1] ) )
                
    
    for addr_range, module_name in module_names:
        if addr_range[0] <= address < addr_range[1]:
            return module_name
            
    return None
Example #7
0
    def update_content_viewers(self, n=None):
        if n is None:
            n = self.GetLineNo()

        item = self.get_item(n)

        self.dav.clear()
        self.hv.clear()
        self.iv.clear()

        if item is not None:
            if item.type == Item.TYPE_CODE:
                # get disassembly and hex stream
                dis = self.payload.da.get_disasm(item.ea)
                for line in dis:
                    self.dav.add_line(line[0])
                    self.hv.add_line(line[1])

                # get various info
                seg = idaapi.getseg(item.ea)
                if seg:
                    name = idaapi.get_true_segm_name(seg)
                    perm = seg.perm
                    ltype = "ld" if seg.is_loader_segm() else "dbg"
                    ea_start = seg.startEA
                    ea_end = seg.endEA

                    perms = ""
                    perms += "R" if perm & idaapi.SEGPERM_READ != 0 else "."
                    perms += "W" if perm & idaapi.SEGPERM_WRITE != 0 else "."
                    perms += "X" if perm & idaapi.SEGPERM_EXEC != 0 else "."
                    self.iv.add_line("<%s> [%X - %X], %s, [%s]" % (name, ea_start, ea_end, ltype, perms))
            else:
                stype = GetStringType(item.ea)
                if stype is not None:
                    scontent = GetString(item.ea, -1, stype)
                    if scontent != None and len(scontent):
                        self.dav.add_line(idaapi.COLSTR("\"%s\"" % scontent, idaapi.SCOLOR_DSTR))
                        # length = idaapi.get_max_ascii_length(item.ea, stype, idaapi.ALOPT_IGNHEADS)
                        # self.hv.add_line()
                else:
                    scontent = GetString(item.ea, -1, ASCSTR_C)
                    if scontent != None and len(scontent):
                        self.dav.add_line("\"%s\"" % scontent)

        self.dav.update()
        self.hv.update()
        self.iv.update()
Example #8
0
 def enum_segm(self):
     i = 0
     for ea in idautils.Segments():
         seg = idaapi.getseg(ea)
         SigmName = idc.SegName(ea)
         startA = idc.SegStart(ea)
         endA = idc.SegEnd(ea)
         className = idaapi.get_segm_class(seg)
         seg_radio = SegmRadio(SigmName, startA, endA, className)
         self.segm.append((SigmName, startA, endA, className))
         self.segm_vbox.addWidget(seg_radio)
         self.segm_vbox.addStretch(1)
         if i == 0:
             i = 1
             seg_radio.toggle()
     return self.segm_vbox
Example #9
0
    def _fix_data_offsets(self):
        ea = 0
        count = 0

        print "Fixing unresolved offset xrefs...",

        while ea != idaapi.BADADDR:
            (ea, n) = idaapi.find_notype(ea, idaapi.SEARCH_DOWN)
            if idaapi.decode_insn(ea):
                for i in range(0, len(idaapi.cmd.Operands)):
                    op = idaapi.cmd.Operands[i]
                    if op.type == idaapi.o_imm and idaapi.getseg(op.value):
                        idaapi.add_dref(ea, op.value, (idaapi.dr_O | idaapi.XREF_USER))
                        count += 1

        print "created %d new data xrefs" % count
Example #10
0
def dump_loader_info(output_filename):
    """Dump information for BAP's loader into output_filename."""
    from idautils import Segments
    import idc

    idaapi.autoWait()

    with open(output_filename, 'w+') as out:
        info = idaapi.get_inf_structure()
        size = "r32" if info.is_32bit else "r64"
        out.write("(%s %s (" % (info.get_proc_name()[1], size))
        for seg in Segments():
            out.write("\n(%s %s %d (0x%X %d))" % (
                idaapi.get_segm_name(seg),
                "code" if idaapi.segtype(seg) == idaapi.SEG_CODE else "data",
                idaapi.get_fileregion_offset(seg),
                seg, idaapi.getseg(seg).size()))
        out.write("))\n")
Example #11
0
def find(s=None, x=False, asm_where=None):
    b, ret = FindInstructions(s, asm_where)
    if b:
        # executable segs only?
        if x:
            results = []
            for ea in ret:
                seg = idaapi.getseg(ea)
                if (not seg) or (seg.perm & idaapi.SEGPERM_EXEC) == 0:
                    continue
                results.append(SearchResult(ea))
        else:
            results = [SearchResult(ea) for ea in ret]
        title = "Search result for: [%s]" % s
        idaapi.close_chooser(title)
        c = SearchResultChoose(results, title)
        c.choose()
    else:
        print ret
Example #12
0
    def read(self, n=-1):
        if not self.__idb__:
            return super(IDBFileIO, self).read(n)
        else:
            data = ''
            read_count = 0
            filler_count = 0

            # Loop to read n bytes of data across IDB segments, filling
            # segment gaps with NULL bytes.
            while n and self.idb_pos <= self.idb_end:
                segment = idaapi.getseg(self.idb_pos)

                if not segment:
                    filler_count += 1
                    self.idb_pos += 1
                    n -= 1
                else:
                    if filler_count:
                        data += "\x00" * filler_count
                        filler_count = 0

                    if (self.idb_pos + n) > segment.endEA:
                        read_count = segment.endEA - self.idb_pos
                    else:
                        read_count = n

                    try:
                        data += idc.GetManyBytes(self.idb_pos, read_count)
                    except TypeError as e:
                        # This happens when trying to read from uninitialized
                        # segments (e.g., .bss)
                        data += "\x00" * read_count

                    n -= read_count
                    self.idb_pos += read_count

            if filler_count:
                data += "\x00" * filler_count
                filler_count = 0

            return data
Example #13
0
def addDataSegment(M, start, end, new_eas):
    if end < start:
        raise Exception("Start must be before end")

    seg = idaapi.getseg(start)

    if not seg:
        raise Exception("Data must be in a valid segment")

    # if this is in an executalbe region,
    # move it to a data section
    seg_offset = 0
    need_move = (seg.perm & idaapi.SEGPERM_EXEC) != 0
    if need_move:
        free_data = findFreeData()
        seg_offset = free_data - start
        DEBUG("Data Segment {0:x} moved to: {1:x}\n".format(start, start+seg_offset))

    D = M.internal_data.add()
    D.base_address = start+seg_offset

    SEGPERM_WRITE = 2
    
    if (seg.perm & SEGPERM_WRITE) == 0:
        D.read_only = True
    else:
        D.read_only = False

    #D.data = idaapi.get_many_bytes(start, end-start)
    D.data = readBytesSlowly(start, end)

    DATA_SEGMENTS.append( (start+seg_offset,end+seg_offset) )

    processRelocationsInData(M, D, start, end, new_eas, seg_offset)

    DEBUG("Adding data seg: {0}: {1}-{2}\n".format( 
        idc.SegName(start),
        hex(start+seg_offset),
        hex(end+seg_offset)))

    return seg_offset
Example #14
0
    def setupUI(self):
        ea = idc.ScreenEA()
        seg = idaapi.getseg(ea)
        SigmName = idc.SegName(ea)
        startA = idc.SegStart(ea)
        endA = idc.SegEnd(ea)
        className = idaapi.get_segm_class(seg)
        self.setWindowTitle("Jumper--%s %s %s" % (hex(ea - startA).upper(), SigmName, className))

        self.groupBox.setLayout(self.enum_segm())

        search_hbox = QHBoxLayout()
        search_hbox.addWidget(QLabel("search"))
        search_hbox.addWidget(self.search_edit)

        offset_hbox = QHBoxLayout()
        offset_hbox.addWidget(QLabel("offset"))
        offset_hbox.addWidget(self.off_edit)

        self.scroll = QScrollArea()
        self.scroll.setWidgetResizable(True)  # Set to make the inner widget resize with scroll area
        self.scroll.setWidget(self.groupBox)

        globle_vbox = QVBoxLayout(self)
        globle_vbox.addWidget(self.scroll)
        globle_vbox.addLayout(search_hbox)
        globle_vbox.addLayout(offset_hbox)

        btn_layout =  QHBoxLayout()
        jump = QPushButton("jump")
        jump.clicked.connect(self.jump_click)
        get_offset = QPushButton("offset")
        get_offset.clicked.connect(self.get_cur_offset)
        btn_layout.addWidget(jump)
        btn_layout.addWidget(get_offset)
        globle_vbox.addLayout(btn_layout)

        self.search_edit.textChanged.connect(self.search_changed)
Example #15
0
def _Assemble(ea, line):
    """
    Please refer to Assemble() - INTERNAL USE ONLY
    """
    if type(line) == types.StringType:
        lines = [line]
    else:
        lines = line
    ret = []
    for line in lines:
        seg = idaapi.getseg(ea)
        if not seg:
            return (False, "No segment at ea")
        ip  = ea - (idaapi.ask_selector(seg.sel) << 4)
        buf = idaapi.AssembleLine(ea, seg.sel, ip, seg.bitness, line)
        if not buf:
            return (False, "Assembler failed: " + line)
        ea += len(buf)
        ret.append(buf)

    if len(ret) == 1:
        ret = ret[0]
    return (True, ret)
Example #16
0
def get_offset_name(ea):
    # Try and get the function name
    try:
        func = get_func(ea)
        name = idc.GetTrueName(func.startEA)
        name = demangle(name, 0x60) # MNG_NOTYPE | MNG_NORETTYPE
        if name:
            offset = ea - func.startEA
            if offset:
                return '{}+{:X}'.format(name, offset)
            return name
    except exceptions.SarkNoFunction:
        pass

    # If that failed, use the segment name instead.
    segment = idaapi.getseg(ea)
    name = idaapi.get_true_segm_name(segment)
    offset_format = '{{:0{}X}}'.format(get_native_size() * 2)
    ea_text = offset_format.format(ea)
    if name:
        return '{}:{}'.format(name, ea_text)

    # Nothing found, simply return the address
    return ea_text
    def single_operand_parser(self, address, op, idx):
        """Parse a metapc operand."""
        
        # Convenience functions
        #
        def has_sib_byte(op):
            # Does the instruction use the SIB byte?
            return self.as_byte_value(op.specflag1)==1
        
        def get_sib_scale(op):
            return (None, 2, 4, 8)[self.as_byte_value(op.specflag2)>>6]
        
        def get_sib_scaled_index_reg(op):
            return self.SIB_INDEX_REGISTERS[(self.as_byte_value(op.specflag2)>>3)&0x7]
        
        def get_sib_base_reg(op):
            #
            #       [       [7-6]            [5-3]            [2-0] ]
            # MOD/RM = ( (mod_2 << 6) | (reg_opcode_3 << 3) | rm_3 )
            # There's not MOD/RM made available by IDA!?
            #
            #       [     [7-6]             [5-3]       [2-0] ]
            # SIB = ( (scale_2 << 6) | (index_3 << 3) | base )
            # op.specflag2
            #
            # instruction = op + modrm + sib + disp + imm
            #
            
            # If MOD is zero there's no base register, otherwise it's EBP
            # But IDA exposes no MOD/RM.
            # Following a discussion in IDA's forums:
            # http://www.hex-rays.com/forum/viewtopic.php?f=8&t=1424&p=8479&hilit=mod+rm#p8479
            # checking for it can be done in the following manner:
            #
            
            SIB_byte = self.as_byte_value(op.specflag2)
            
            return  self.SIB_BASE_REGISTERS[ SIB_byte & 0x7]
        
        def get_segment_prefix(op):
        
            seg_idx = (op.specval>>16)
            if seg_idx == 0:
                return None
                
            if (op.specval>>16) < len(self.REGISTERS[0]) :
                seg_prefix = self.REGISTERS[0][op.specval>>16] + ':'
            else:
                seg_prefix = op.specval&0xffff
                
            # This must return a string in case a segment register selector is used
            # or and int/long of a descriptor itself.
            #
            return seg_prefix
            
        
        def parse_phrase(op, has_displacement=False):
            """Parse the expression used for indexed memory access.
            
            Returns its AST as a nested list of lists.
            """
            
            # Check the addressing mode using in this segment
            segment = idaapi.getseg(address)
            if segment.bitness != 1:
                raise Exception(
                    'Not yet handling addressing modes other than 32bit!')
            
            
            base_reg = get_sib_base_reg(op)
            scaled_index_reg = get_sib_scaled_index_reg(op)
            scale = get_sib_scale(op)
            
            if scale:
                
                # return nested list for reg+reg*scale
                if base_reg != '':
                    # The last values in each tuple indicate the
                    # preferred display position of each element.
                    # base_reg + (scale_reg * scale)
                    #
                    
                    if scaled_index_reg == '':
                        return [
                            self.NODE_TYPE_OPERATOR_PLUS, 
                                [self.NODE_TYPE_REGISTER, base_reg, 0] ]
                        
                    return [
                        self.NODE_TYPE_OPERATOR_PLUS, 
                            [self.NODE_TYPE_REGISTER, base_reg, 0],
                            [self.NODE_TYPE_OPERATOR_TIMES,
                                [self.NODE_TYPE_REGISTER, scaled_index_reg, 0],
                                [self.NODE_TYPE_VALUE, scale, 1], 1 ] ]
                else:
                    # If there's no base register and
                    # mod == 01 or mod == 10 (=> operand has displacement)
                    # then we need to add EBP
                    if has_displacement:
                        return [
                            self.NODE_TYPE_OPERATOR_PLUS,
                                [ self.NODE_TYPE_REGISTER, 'ebp', 0],
                                [ self.NODE_TYPE_OPERATOR_TIMES,
                                    [self.NODE_TYPE_REGISTER, scaled_index_reg, 0],
                                    [self.NODE_TYPE_VALUE, scale, 1], 1 ] ]
                    return [
                        self.NODE_TYPE_OPERATOR_PLUS,
                            [ self.NODE_TYPE_OPERATOR_TIMES,
                                [self.NODE_TYPE_REGISTER, scaled_index_reg, 0],
                                [self.NODE_TYPE_VALUE, scale, 1], 0 ] ]
            
            else:
                # return nested list for reg+reg
                if base_reg == '':
                    if scaled_index_reg != '':
                        if has_displacement:
                            return [
                                self.NODE_TYPE_OPERATOR_PLUS,
                                    [ self.NODE_TYPE_REGISTER, 'ebp', 0],
                                    [ self.NODE_TYPE_REGISTER, scaled_index_reg, 1 ] ]
                        return [
                            self.NODE_TYPE_OPERATOR_PLUS,
                                [self.NODE_TYPE_REGISTER, scaled_index_reg, 0 ] ]
                    else:
                        if has_displacement:
                            return [self.NODE_TYPE_OPERATOR_PLUS, [self.NODE_TYPE_REGISTER, 'ebp', 0] ]
                        return [ ]
                        
                else:
                    if scaled_index_reg != '':
                        return [
                            self.NODE_TYPE_OPERATOR_PLUS,
                                [self.NODE_TYPE_REGISTER, base_reg, 0],
                                [self.NODE_TYPE_REGISTER, scaled_index_reg, 1 ] ]
                    else:
                        return [
                            self.NODE_TYPE_OPERATOR_PLUS,
                                [self.NODE_TYPE_REGISTER, base_reg, 0] ]
        
        
        # Operand parsing
        #
        
        if op.type == OPERAND_TYPE_NO_OPERAND:
            return None
        
        segment = idaapi.getseg(address)
        addressing_mode = segment.bitness
        
        # Start creating the AST, the root entry is always the width of the
        # operand
        operand = [self.OPERAND_WIDTH[ self.as_byte_value( op.dtyp ) ]]
        
        
        # If the operand indicates a displacement and it does
        # the indexing through the SIB the it might be referring
        # a variable on the stack and an attempt to retrieve it
        # is made.
        #
        
        
        # Compose the rest of the AST
        #
        
        if op.type == OPERAND_TYPE_DISPLACEMENT:
            
            # A displacement operatior might refer to a variable...
            #
            var_name = None
            
            # Try to get any stack name that might have been assigned
            # to the variable. 
            #
            flags = idc.GetFlags(address)
            if (idx==0 and idc.isStkvar0(flags)) or (
                idx==1 and idc.isStkvar1(flags)):
                
                var_name = self.get_operand_stack_variable_name(address, op, idx)
            
            if has_sib_byte(op) is True:
                # when SIB byte set, process the SIB indexing
                phrase = parse_phrase(op, has_displacement=True)
            else:
                phrase = [
                    self.NODE_TYPE_OPERATOR_PLUS, 
                        [self.NODE_TYPE_REGISTER,
                            self.REGISTERS[addressing_mode+1][op.reg], 0] ]
            
            if var_name:
                value = arch.ExpressionNamedValue(long(op.addr), var_name)
            else:
                value = op.addr
                
            # Calculate the index of the value depending on how many components
            # we have in the phrase
            #
            idx_of_value = len( phrase ) - 1
            operand.extend([
                [ get_segment_prefix(op),
                    [self.NODE_TYPE_DEREFERENCE,
                        phrase+[ [self.NODE_TYPE_VALUE, value, idx_of_value] ] ] ] ])
            
        
        elif op.type == OPERAND_TYPE_REGISTER:
            
            operand.extend([
                [self.NODE_TYPE_REGISTER, self.REGISTERS[self.as_byte_value(op.dtyp)][op.reg], 0]])
        
        elif op.type == OPERAND_TYPE_MEMORY:
            
            addr_name = self.get_address_name(op.addr)
            
            if addr_name:
                value = arch.ExpressionNamedValue(long(op.addr), addr_name)
            else:
                value = op.addr
            
            if has_sib_byte(op) is True:
                # when SIB byte set, process the SIB indexing
                phrase = parse_phrase(op)
                
                idx_of_value = len( phrase ) - 1
                operand.extend([
                    [ get_segment_prefix(op),
                        [self.NODE_TYPE_DEREFERENCE,
                            phrase+[[self.NODE_TYPE_VALUE, value, idx_of_value]] ] ] ])
            else:                
                operand.extend([
                    [ get_segment_prefix(op),
                        [self.NODE_TYPE_DEREFERENCE,
                            [self.NODE_TYPE_VALUE, value, 0] ] ] ])
            
            
        
        elif op.type == OPERAND_TYPE_IMMEDIATE:
            
            width = self.OPERAND_WIDTH[self.as_byte_value(op.dtyp)]
            
            if width == arch.Arch.NODE_TYPE_OPERATOR_WIDTH_BYTE_1:
                value = op.value&0xff
            elif width == arch.Arch.NODE_TYPE_OPERATOR_WIDTH_BYTE_2:
                value = op.value&0xffff
            elif width == arch.Arch.NODE_TYPE_OPERATOR_WIDTH_BYTE_4:
                value = op.value&0xffffffff
            else:
                value = op.value
            
            operand.extend([[self.NODE_TYPE_VALUE, value, 0]])
            
        
        elif op.type in (OPERAND_TYPE_NEAR, OPERAND_TYPE_FAR):
            
            addr_name = self.get_address_name(op.addr)
            
            if addr_name:
                value = arch.ExpressionNamedValue(long(op.addr), addr_name)
            else:
                value = op.addr
            
            seg_prefix = get_segment_prefix(op)
            if isinstance(seg_prefix, str):
                operand.extend([
                    [ seg_prefix, [self.NODE_TYPE_VALUE, value, 0] ]])
            elif isinstance(seg_prefix, (int, long)):
                operand.extend([
                    [ self.NODE_TYPE_OPERATOR_SEGMENT_GEN, 
                        [self.NODE_TYPE_VALUE, seg_prefix, 0],
                        [self.NODE_TYPE_VALUE, value, 1] ]] )
            
        
        elif op.type == OPERAND_TYPE_PHRASE:
            if has_sib_byte(op) is True:
                phrase = parse_phrase(op)
                
                # Detect observed cases (in GCC compiled sshd) where GCC's instruction
                # encoding would be parsed into a phrase with an addition of a single
                # register, without any other summands. 
                # In those cases, if there's a name associated to the zero such as
                # a stack variable, we will add a zero to the sum. We do that to have
                # an expression to which alias an expression substitution (in the past
                # we were removing the addition altogether)
                # If there's no name we will remove the redundant 0
                # 
                #
                # This case has been observed for the encoding of [esp] where the tree
                # would be "[" -> "+" -> "esp".
                #
                #
                if phrase[0] == self.NODE_TYPE_OPERATOR_PLUS and len(phrase) == 2:
                    
                    var_name = self.get_operand_stack_variable_name(address, op, idx)
                    if var_name:
                        value = arch.ExpressionNamedValue(0, var_name)
                        phrase.append( [self.NODE_TYPE_VALUE, value, 1] )
                    else:
                        phrase = phrase[1]
                    
                
                operand.extend([
                    [get_segment_prefix(op),
                        [self.NODE_TYPE_DEREFERENCE, phrase] ]] )
                
            else:
                operand.extend([
                    [get_segment_prefix(op),
                        [self.NODE_TYPE_DEREFERENCE,
                            [self.NODE_TYPE_REGISTER,
                                self.REGISTERS[addressing_mode+1][op.phrase], 0] ] ]])
        
        elif op.type == OPERAND_TYPE_IDPSPEC0:
            # The operand refers to the TR* registers
            operand.extend([
                [self.NODE_TYPE_REGISTER, 'tr%d' % op.reg, 0]])
        
        elif op.type == OPERAND_TYPE_IDPSPEC1:
            # The operand refers to the DR* registers
            operand.extend([
                [self.NODE_TYPE_REGISTER, 'dr%d' % op.reg, 0]])
        
        elif op.type == OPERAND_TYPE_IDPSPEC2:
            # The operand refers to the CR* registers
            operand.extend([
                [self.NODE_TYPE_REGISTER, 'cr%d' % op.reg, 0]])
        
        elif op.type == OPERAND_TYPE_IDPSPEC3:
            # The operand refers to the FPU register stack
            operand.extend([
                [self.NODE_TYPE_REGISTER, 'st(%d)' % op.reg, 0]])
        
        elif op.type == OPERAND_TYPE_IDPSPEC4:
            # The operand is a MMX register
            operand.extend([
                [self.NODE_TYPE_REGISTER, 'mm%d' % op.reg, 0]])
        
        elif op.type == OPERAND_TYPE_IDPSPEC5:
            # The operand is a MMX register
            operand.extend([
                [self.NODE_TYPE_REGISTER, 'xmm%d' % op.reg, 0]])
        
        # If no other thing that a width, i.e. ['b2'] is retrieved
        # we assume there was no operand... this is a hack but I've seen
        # IDA pretend there's a first operand like this:
        #
        # fld ['b2'], ['b4', ['ds', ['[', ['+', ['$', 'edx'], [...]]]]]
        #
        # So, in these cases I want no first operand...
        #if len(operand)==1:
        #    return None

        return operand
Example #18
0
 def segment(cls):
     '''Return the current segment.'''
     ea = cls.address()
     return idaapi.getseg(ea)
Example #19
0
def find_function_ends(location, end_mnem_bytes=None):
    """
    Description:
        Identifies all possible function ends before the next function or Align.

    Input:
        location - The EA to search after
        end_mnem_bytes - Try to end functions on a particular instruction
                         Instructions are entered as space separated bytes (i.e. 'C2' for 'retn')
                         The specified pattern will be used first, then the defaults will be used
                         If no pattern is specified, the defaults will be used, which prefers 'retn'

    Output:
        ends - A list of function end EAs sorted: end_mnem_bytes, retn, jmp
    """
    # foreach target bytes:
    #  step instructions down
    #  if instruction matches the target bytes, add to the corresponding output list
    #  if we hit a function or an align, quit
    # return ends in the order:
    #  end_nmem_bytes
    #  retn
    #  jmp
    #  others, sorted ascending

    max_location = None
    ea = location
    while max_location is None:
        ea = idc.next_head(ea)
        if idaapi.get_func(ea) or idc.is_align(idc.get_full_flags(ea)):
            max_location = ea
        elif ea == idc.BADADDR:
            max_location = idaapi.getseg(location).end_ea
    max_location = min(max_location, idaapi.getseg(location).end_ea)

    targets = ['C3', 'C2', 'E9', 'EA', 'EB']
    if end_mnem_bytes:
        targets.insert(0, end_mnem_bytes)

    ends = {}
    for target in targets:
        function_ends = []
        ea = find_binary_instruction_start(location,
                                           idc.SEARCH_DOWN,
                                           target,
                                           max_location=max_location)
        while ea != idc.BADADDR:
            if ea > max_location:
                break
            else:
                function_ends.append(ea)
            ea = find_binary_instruction_start(ea + 11,
                                               idc.SEARCH_DOWN,
                                               target,
                                               max_location=max_location)
        ends[target] = function_ends

    return [
        end + idc.get_item_size(end) for end in (
            (ends[end_mnem_bytes] if end_mnem_bytes else []) +
            sorted(ends['C3'] + ends['C2']) + sorted(
                itertools.chain.from_iterable(ends[target]
                                              for target in targets[-3:])))
    ]
Example #20
0
File: ui.py Project: mmg1/ida-minsc
 def segment(cls):
     '''Return the current segment.'''
     ea = cls.address()
     return idaapi.getseg(ea)
Example #21
0
    def check_fmt_function(name, addr):
        """
        Check if the format string argument is not valid
        """
        function_head = idc.get_func_attr(addr, idc.FUNCATTR_START)

        while True:
            addr = idc.prev_head(addr)
            op = idc.print_insn_mnem(addr).lower()
            dst = idc.print_operand(addr, 0)

            if op in ("ret", "retn", "jmp", "b") or addr < function_head:
                return

            c = idc.get_cmt(addr, 0)
            if c and c.lower() == "format":
                break
            elif name.endswith(("snprintf_chk", )):
                if op in ("mov", "lea") and dst.endswith(
                    ("r8", "r8d", "[esp+10h]")):
                    break
            elif name.endswith(("sprintf_chk", )):
                if op in ("mov", "lea") and (dst.endswith(
                    ("rcx", "[esp+0Ch]", "R3")) or dst.endswith("ecx")
                                             and BITS == 64):
                    break
            elif name.endswith(("snprintf", "fnprintf")):
                if op in ("mov", "lea") and (dst.endswith(
                    ("rdx", "[esp+8]", "R2")) or dst.endswith("edx")
                                             and BITS == 64):
                    break
            elif name.endswith(
                ("sprintf", "fprintf", "dprintf", "printf_chk")):
                if op in ("mov", "lea") and (dst.endswith(
                    ("rsi", "[esp+4]", "R1")) or dst.endswith("esi")
                                             and BITS == 64):
                    break
            elif name.endswith("printf"):
                if op in ("mov", "lea") and (dst.endswith(
                    ("rdi", "[esp]", "R0")) or dst.endswith("edi")
                                             and BITS == 64):
                    break

        # format arg found, check its type and value
        # get last oprend
        op_index = idc.generate_disasm_line(addr, 0).count(",")
        op_type = idc.get_operand_type(addr, op_index)
        opnd = idc.print_operand(addr, op_index)

        if op_type == idc.o_reg:
            # format is in register, try to track back and get the source
            _addr = addr
            while True:
                _addr = idc.prev_head(_addr)
                _op = idc.print_insn_mnem(_addr).lower()
                if _op in ("ret", "retn", "jmp", "b") or _addr < function_head:
                    break
                elif _op in ("mov", "lea", "ldr") and idc.print_operand(
                        _addr, 0) == opnd:
                    op_type = idc.get_operand_type(_addr, 1)
                    opnd = idc.print_operand(_addr, 1)
                    addr = _addr
                    break

        if op_type == idc.o_imm or op_type == idc.o_mem:
            # format is a memory address, check if it's in writable segment
            op_addr = idc.get_operand_value(addr, op_index)
            seg = idaapi.getseg(op_addr)
            if seg:
                if not seg.perm & idaapi.SEGPERM_WRITE:
                    # format is in read-only segment
                    return

        print("0x%X: Possible Vulnerability: %s, format = %s" %
              (addr, name, opnd))
        return ["0x%X" % addr, name, opnd]
Example #22
0
 def get_addressing(self):
     seg = idaapi.getseg(self.start)
     return seg.bitness
Example #23
0
def CallStackWalk(nn):
    class Result:
        """
        Class holding the result of one call stack item
        Each call stack item instance has the following attributes:
            caller = ea of caller
            displ  = display string
            sp     = stack pointer
        """
        def __init__(self, caller, sp):
            self.caller = caller
            self.sp     = sp
            f = idaapi.get_func(caller)
            self.displ = "%08x: " % caller
            if f:
                self.displ += idc.GetFunctionName(caller)
                t = caller - f.startEA
                if t > 0: self.displ += "+" + hex(t)
            else:
                self.displ += hex(caller)
            self.displ += " [" + hex(sp) + "]"

        def __str__(self):
            return self.displ

    # get stack pointer
    sp = GetRegValue("RSP")
    seg = idaapi.getseg(sp)
    if not seg:
        return (False, "Could not locate stack segment!")

    stack_seg = Seg(seg)
    word_size = 2 ** (seg.bitness + 1)
    callers = []
    sp = cpu.Esp - word_size
    while sp < stack_seg.endEA:
        sp += word_size
        ptr = idautils.GetDataList(sp, 1, word_size).next()
        seg = idaapi.getseg(ptr)
        # only accept executable segments
        if (not seg) or ((seg.perm & idaapi.SEGPERM_EXEC) == 0):
            continue
        # try to find caller
        caller = IsPrevInsnCall(ptr)
        # we have no recognized caller, skip!
        if caller is None:
            continue

        # do we have a debug name that is near?
        if nn:
            ret = nn.find(caller)
            if ret:
                ea = ret[0]
                # function exists?
                f = idaapi.get_func(ea)
                if not f:
                    # create function
                    idc.MakeFunction(ea, idaapi.BADADDR)

        # get the flags
        f = idc.GetFlags(caller)
        # no code there?
        if not isCode(f):
            MakeCode(caller)

        callers.append(Result(caller, sp))
    #
    return (True, callers)
Example #24
0
 def get_class(self):
     seg = idaapi.getseg(self.addr)
     if not seg:
         return None
     return idaapi.get_segm_class()
Example #25
0
 def get_type(self):
     seg = idaapi.getseg(self.addr)
     if not seg:
         return None
     return seg.type
Example #26
0
def run_yara_on_segments(rule_text,
                         names=None,
                         excluded_names=None,
                         start_eas=None,
                         excluded_eas=None,
                         callback_func=_yara_callback):
    """
    Description:
        Applies yara rule to the bytes in the specified segments and returns raw results.
        Segments may be specified by name or start EA, but one or the other is required.
        Alternatively, names or start EAs may be provided to exclude. In this case all other segments will be scanned.
        Clears the matches each time to prevent duplicates.

    Input:
        names - The names of the target segments
        excluded_names - The names of the excluded segments
        start_eas - The start EAs of the target segments
        excluded_eas - The start EAs of the excluded segments
        callback_func - A pointer to the callback function for YARA's matching to use

    Output:
        Returns a list of YARA's match results with items (location, description)
    """
    global _YARA_MATCHES, FROM_FILE
    _YARA_MATCHES = []
    FROM_FILE = False

    if names is None and excluded_names is None and start_eas is None and excluded_eas is None:
        raise Exception(
            "Either segment names, start EAs, excluded names, or excluded EAs are required to YARA scan by segment."
        )

    if (names and excluded_names) or (start_eas and excluded_eas):
        raise Exception(
            "Do not specify names and excluded names or start eas and excluded eas."
        )

    results = []
    if names:
        for name in names:
            results.extend(
                run_yara_on_segment(rule_text,
                                    name=name,
                                    callback_func=callback_func))
    elif start_eas:
        for start_ea in start_eas:
            results.extend(
                run_yara_on_segment(rule_text,
                                    start_ea=start_ea,
                                    callback_func=callback_func))
    else:
        segs_eas = list(idautils.Segments())
        if excluded_names:
            for seg_ea in segs_eas:
                seg_name = idaapi.get_segm_name(idaapi.getseg(seg_ea))
                if seg_name not in excluded_names:
                    results.extend(
                        run_yara_on_segment(rule_text,
                                            name=seg_name,
                                            callback_func=callback_func))
        elif excluded_eas:
            for seg_ea in segs_eas:
                if seg_ea not in excluded_eas:
                    results.extend(
                        run_yara_on_segment(rule_text,
                                            start_ea=seg_ea,
                                            callback_func=callback_func))

    _YARA_MATCHES = results  # For conformity sake, make sure _YARA_MATCHES is set with all results
    return _YARA_MATCHES
Example #27
0
 def get_bitness(ea):
     seg = idaapi.getseg(ea)
     if not seg:
         seg = idaapi.getseg(idautils.Segments().next())
     bitness = seg.bitness
     return {0: 16, 1: 32, 2: 64}[bitness]
Example #28
0
    def _initialize_page(self, n, new_page):
        if n in self._initialized:
            return False
        self._initialized.add(n)

        new_page_addr = n * self._page_size
        initialized = False

        if self.state is not None:
            self.state.scratch.push_priv(True)

        #return True

        if self._memory_backer is None:
            pass

        elif isinstance(self._memory_backer, cle.Clemory):
            # first, find the right clemory backer
            for addr, backer in self._memory_backer.cbackers if self.byte_width == 8 else (
                (x, y) for x, _, y in self._memory_backer.stride_repr):
                start_backer = new_page_addr - addr
                if isinstance(start_backer, BV):
                    continue
                if start_backer < 0 and abs(start_backer) >= self._page_size:
                    continue
                if start_backer >= len(backer):
                    continue

                # find permission backer associated with the address
                # fall back to read-write if we can't find any...
                flags = IdaPage.PROT_READ | IdaPage.PROT_WRITE
                for start, end in self._permission_map:
                    if start <= new_page_addr < end:
                        flags = self._permission_map[(start, end)]
                        break

                snip_start = max(0, start_backer)
                write_start = max(new_page_addr, addr + snip_start)
                write_size = self._page_size - write_start % self._page_size

                if self.byte_width == 8:
                    snip = _ffi.buffer(backer)[snip_start:snip_start +
                                               write_size]
                    mo = SimMemoryObject(claripy.BVV(snip),
                                         write_start,
                                         byte_width=self.byte_width)
                    self._apply_object_to_page(n * self._page_size,
                                               mo,
                                               page=new_page)
                else:
                    for i, byte in enumerate(backer):
                        mo = SimMemoryObject(claripy.BVV(
                            byte, self.byte_width),
                                             write_start + i,
                                             byte_width=self.byte_width)
                        self._apply_object_to_page(n * self._page_size,
                                                   mo,
                                                   page=new_page)

                new_page.permissions = claripy.BVV(flags, 3)
                initialized = True

        elif len(self._memory_backer) <= self._page_size:
            for i in self._memory_backer:
                if new_page_addr <= i and i <= new_page_addr + self._page_size:
                    if isinstance(self._memory_backer[i], claripy.ast.Base):
                        backer = self._memory_backer[i]
                    elif isinstance(self._memory_backer[i], bytes):
                        backer = claripy.BVV(self._memory_backer[i])
                    else:
                        backer = claripy.BVV(self._memory_backer[i],
                                             self.byte_width)
                    mo = SimMemoryObject(backer, i, byte_width=self.byte_width)
                    self._apply_object_to_page(n * self._page_size,
                                               mo,
                                               page=new_page)
                    initialized = True
        elif len(self._memory_backer) > self._page_size:
            for i in range(self._page_size):
                try:
                    if isinstance(self._memory_backer[i], claripy.ast.Base):
                        backer = self._memory_backer[i]
                    elif isinstance(self._memory_backer[i], bytes):
                        backer = claripy.BVV(self._memory_backer[i])
                    else:
                        backer = claripy.BVV(self._memory_backer[i],
                                             self.byte_width)
                    mo = SimMemoryObject(backer,
                                         new_page_addr + i,
                                         byte_width=self.byte_width)
                    self._apply_object_to_page(n * self._page_size,
                                               mo,
                                               page=new_page)
                    initialized = True
                except KeyError:
                    pass

        # page from debugger
        try:
            seg = idaapi.getseg(
                new_page_addr)  ### CHANGE TO SUPPORT OTHER DEBUGGERS
            if seg is not None:
                perms = 0
                if seg.perm & idaapi.SEGPERM_EXEC:
                    perms += IdaPage.PROT_EXEC
                if seg.perm & idaapi.SEGPERM_WRITE:
                    perms += IdaPage.PROT_WRITE
                if seg.perm & idaapi.SEGPERM_READ:
                    perms += IdaPage.PROT_READ
                new_page.permissions = claripy.BVV(perms, 3)
                #print "permissions setted %x  %d" % (new_page_addr, perms)
                initialized = True
                setattr(new_page, "from_ida_dbg", True)
        except:
            pass

        if self.state is not None:
            self.state.scratch.pop_priv()
        return initialized
Example #29
0
def byAddress(ea):
    '''Return the segment_t that holds the specified /ea/'''
    s = idaapi.getseg(ea)
    if s is None:
        raise Exception, "segment.byAddress(%x):unable to locate segment"% ea
    return s
Example #30
0
 def get_bitness(ea):
     bitness = idaapi.getseg(ea).bitness
     return {0: 16, 1: 32, 2: 64}[bitness]
Example #31
0
def InsNotInTextSection(i):
    seg_name = idaapi.get_segm_name(idaapi.getseg(i))
    return seg_name != ".text", seg_name
Example #32
0
File: ifl.py Project: wbaby/ida_ifl
 def _set_segment_color(self, ea, color) -> None:
     seg = idaapi.getseg(ea)
     seg.color = COLOR_NORMAL
     seg.update()
Example #33
0
 def segment(cls):
     """Current segment"""
     ea = cls.address()
     return idaapi.getseg(ea)
Example #34
0
    def single_operand_parser(self, address, op, idx):
        """Parse a ARM operand."""
        
        def constraint_value(value):
            if value>2**16:
                return -(2**32-value)
            return value
        
        
        def parse_register_list(bitfield, bit_field_width=32):
            """Parse operand representing a list of registers."""
            operand = [self.NODE_TYPE_OPERATOR_LIST]
            i = 0
            for idx in range(32):
                if bitfield&(2**idx):
                    operand.extend([[self.NODE_TYPE_REGISTER, self.REGISTERS[idx], i]])
                    i=i+1
                        
            return operand
        
        
        def parse_register_list_floating_point(register, count):
            """Parse operand representing a list of registers."""
            
            operand = [self.NODE_TYPE_OPERATOR_LIST]
            for idx in range(register, register+count):
                operand.extend([[self.NODE_TYPE_REGISTER, 'D%d' % idx , 0]])
            
            return operand
        
        ### Operand parsing ###
        
        if op.type == OPERAND_TYPE_NO_OPERAND:
            return None
        
        segment = idaapi.getseg(address)
        addressing_mode = segment.bitness
        
        # Start creating the AST, the root entry is always the width of the operand
        
        operand = [self.OPERAND_WIDTH[self.as_byte_value(op.dtyp)]]
        
        
        # Compose the rest of the AST
        
        if op.type == OPERAND_TYPE_DISPLACEMENT:
        
            # At this point we have to parse specific bits of the instruction
            # ourselves because IDA does not provide all the required data.
        
            val = idc.Dword(address)
            p = (val >> 24) & 1
            w = (val >> 21) & 1
            value = constraint_value(op.addr)
            
            phrase = [self.NODE_TYPE_OPERATOR_COMMA, [ self.NODE_TYPE_REGISTER, self.REGISTERS[op.reg], 0]]
                            
            if idc.GetMnem(address) in ["LDR", "STR"] and idc.ItemSize(address) > 2:
                if p == 0 and w == 0: # Situation: [ ... ], VALUE
                    operand.extend( [ [ 
                        self.NODE_TYPE_OPERATOR_COMMA, 
                            [ self.NODE_TYPE_DEREFERENCE, [ 
                                self.NODE_TYPE_REGISTER, self.REGISTERS[op.reg], 0] , ], 
                            [ self.NODE_TYPE_VALUE, value, 1 ] ] ])
                            
                else: # Situation: [ ... ] or [ ... ]!
                    
                    # We want to avoid [R1 + 0]! situations, so we explicitly
                    # remove the +0 phrase if it exists.
                    
                    if value != 0:
                        inner = [self.NODE_TYPE_DEREFERENCE,phrase+[ [self.NODE_TYPE_VALUE, value, 1]] ]
                    else:
                        inner = [self.NODE_TYPE_DEREFERENCE,[self.NODE_TYPE_REGISTER, self.REGISTERS[op.reg], 0]]
                    if p == 1 and w == 1:
                        operand.extend([[self.NODE_TYPE_OPERATOR_EXCMARK, inner]])
                    else:
                        operand.extend([inner])
            else:
                
                if value != 0:
                    operand.extend([[self.NODE_TYPE_DEREFERENCE,phrase+[ [self.NODE_TYPE_VALUE, value, 1]]]])
                else:
                    operand.extend([[self.NODE_TYPE_DEREFERENCE,[self.NODE_TYPE_REGISTER, self.REGISTERS[op.reg], 0]]])

        elif op.type == OPERAND_TYPE_REGISTER:
        
            if idc.GetMnem(address) in ["STM", "LDM"]:
            
                val = idc.Dword(address)
                w = (val >> 21) & 1
            
                if w == 1:
                    operand.extend([[self.NODE_TYPE_OPERATOR_EXCMARK,[self.NODE_TYPE_REGISTER, self.REGISTERS[op.reg], 0]]])
                else:
                    operand.extend([[self.NODE_TYPE_REGISTER, self.REGISTERS[op.reg], 0]])
            
            else:
                try:
                    operand.extend([[self.NODE_TYPE_REGISTER, self.REGISTERS[op.reg], 0]])
                except Exception, excp:
                    print '%08x: UNSUPPORTED OPERAND REGISTER at %08x: idx: %d' % (address, address, op.reg)
Example #35
0
def new(offset, size, name, **kwds):
    """Create a segment at `offset` with `size` and name it according to `name`.

    The keyword `bits` can be used to specify the bit size of the segment
    The keyword `comb` can be used to specify any flags (idaapi.sc*)
    The keyword `align` can be used to specify paragraph alignment (idaapi.sa*)
    The keyword `org` specifies the origin of the segment (must be paragraph aligned due to ida)
    """
    res = utils.string.to(name)

    # find the segment according to the name specified by the user
    seg = idaapi.get_segm_by_name(res)
    if seg is not None:
        raise E.DuplicateItemError(u"{:s}.new({:#x}, {:+#x}, \"{:s}\"{:s}) : A segment with the specified name (\"{:s}\") already exists.".format(__name__, offset, size, utils.string.escape(name, '"'), u", {:s}".format(utils.string.kwargs(kwds)) if kwds else '', utils.string.escape(name, '"')))

    # FIXME: use disassembler default bit length instead of 32
    bits = kwds.get( 'bits', 32 if idaapi.getseg(offset) is None else idaapi.getseg(offset).abits())

    ## create a selector with the requested origin
    if bits == 16:
        org = kwds.get('org',0)
        if org & 0xf > 0:
            raise E.InvalidTypeOrValueError(u"{:s}.new({:#x}, {:+#x}, {!r}{:s}) : The specified origin ({:#x}) is not aligned to the size of a paragraph (0x10).".format(__name__, offset, size, name, u", {:s}".format(utils.string.kwargs(kwds)) if kwds else '', org))

        para = offset/16
        sel = idaapi.allocate_selector(para)
        idaapi.set_selector(sel, (para-kwds.get('org',0)/16)&0xffffffff)

    ## if the user specified a selector, then use it
    elif 'sel' in kwds or 'selector' in kwds:
        sel = kwds.get('sel', kwds.get('selector', idaapi.find_free_selector()))

    ## choose the paragraph size defined by the user
    elif 'para' in kwds or 'paragraphs' in kwds:
        para = kwds.get('paragraph', kwds.get('para', 1))
        sel = idaapi.setup_selector(para)

    ## find a selector that is 1 paragraph size,
    elif idaapi.get_selector_qty():
        sel = idaapi.find_selector(1)

    # otherwise find a free one and set it.
    else:
        sel = idaapi.find_free_selector()
        idaapi.set_selector(sel, 1)

    # populate the segment_t using code ripped from the idc module
    seg = idaapi.segment_t()
    seg.startEA = offset
    seg.endEA = offset+size
    seg.sel = sel
    seg.bitness = {16:0,32:1,64:2}[bits]
    seg.comb = kwds.get('comb', idaapi.scPub)       # public
    seg.align = kwds.get('align', idaapi.saRelByte)  # paragraphs

    # now we can add our segment_t to the database
    res = utils.string.to(name)
    ok = idaapi.add_segm_ex(seg, res, "", idaapi.ADDSEG_NOSREG|idaapi.ADDSEG_SPARSE)
    if not ok:
        ok = idaapi.del_selector(sel)
        if not ok:
            logging.warn(u"{:s}.new({:#x}, {:+#x}, {!r}{:s}) : Unable to delete the created selector ({:#x}) for the new segment.".format(__name__, offset, size, name, u", {:s}".format(utils.string.kwargs(kwds)) if kwds else '', sel))
        raise E.DisassemblerError(u"{:s}.new({:#x}, {:+#x}, {!r}{:s}) : Unable to add a new segment.".format(__name__, offset, size, name, u", {:s}".format(utils.string.kwargs(kwds)) if kwds else ''))
    return seg
    'func_ptr', 'call_code', 'is_rep_call', 'input_size_1', 'input_size_2',
    'output_size_1', 'output_size_2', 'unkw'
])

HypercallDefine = namedtuple('HypercallDefine',
                             ['define', 'hypercall_name', 'call_code'])

# Hypercall table alway seems to appear in segment "CONST"
hypercall_dispatch_table = idaapi.get_segm_by_name("CONST").startEA
print '[+] Hypercall Dispatch Table: ' + hex(hypercall_dispatch_table)

# Find +X segment
segX_start = 0
segX_end = 0
for ea in idautils.Segments():
    seg = idaapi.getseg(ea)
    if seg and (seg.perm & idaapi.SEGPERM_EXEC):
        SigmName = idc.SegName(ea)
        print '[+] Segments with +X permission: ' + SigmName
        segX_start = seg.startEA
        segX_end = seg.endEA

# Loop through hypercall table
hypercalls = []
valid_hypercall = True
addr = hypercall_dispatch_table
while valid_hypercall:
    func_ptr = idaapi.get_qword(addr)
    # Set struct field sizes in IDA in the HypercallDispatchFormat format
    if APPLY_TO_IDB:
        MakeQword(addr)
Example #37
0
def load_file(li, neflags, format):

    # Read in the bFLT header fields
    li.seek(0)
    (magic, version, entry, data_start, data_end, bss_end, stack_size,
     reloc_start, reloc_count, flags) = struct.unpack(">IIIIIIIIII",
                                                      li.read(4 * 10))

    # Check for the GZIP flag.
    # The loader doesn't de-compress GZIP'd files, as these can be easily decompressed with external tools prior to loading the file into IDA
    if (flags & FLAGS_GZIP) == FLAGS_GZIP:
        Warning(
            "Code/data is GZIP compressed. You probably want to decompress the bFLT file with the flthdr or gunzip_bflt utilities before loading it into IDA."
        )

    # Load the file data into IDA
    li.file2base(BFLT_HEADER_SIZE, BFLT_HEADER_SIZE, data_end, True)

    # Set default processor
    idaapi.set_processor_type(DEFAULT_CPU, SETPROC_ALL)

    # Add the .text .data and .bss segments
    idaapi.add_segm(0, BFLT_HEADER_SIZE, data_start, ".text", "CODE")
    idaapi.add_segm(0, data_start, data_end, ".data", "DATA")
    idaapi.add_segm(0, data_end, bss_end, ".bss", "BSS")

    if DEBUG:
        print "Created File Segments: "
        print "\t.text   0x%.8X - 0x%.8X" % (BFLT_HEADER_SIZE, data_start)
        print "\t.data   0x%.8X - 0x%.8X" % (data_start, data_end)
        print "\t.bss    0x%.8X - 0x%.8X" % (data_end, bss_end)

    # Entry point is at the beginning of the .text section
    idaapi.add_entry(entry, entry, "_start", 1)

    # Explicitly set 32 bit addressing on .text segment
    idaapi.set_segm_addressing(idaapi.getseg(entry), 1)

    # prepare structure for set_fixup()
    fd = idaapi.fixup_data_t()
    fd.type = idaapi.FIXUP_OFF32

    # Is there a global offset table?
    if (flags & FLAGS_GOTPIC) == FLAGS_GOTPIC:

        # Add a reptable comment and name the offset so that all references to GOT are obvious
        MakeRptCmt(data_start, "GLOBAL_OFFSET_TABLE")
        MakeName(data_start, "GOT")

        if DEBUG:
            print "Global Offset Table detected, patching..."

        # GOT starts at the beginning of the data section; loop through the data section, patching up valid GOT entries.
        i = data_start
        while i < data_end:

            # Get the next GOT entry
            li.seek(i)
            got_entry = struct.unpack("<I", li.read(4))[0]

            # The last GOT entry is -1
            if got_entry == 0xFFFFFFFF:
                if DEBUG:
                    print "Finished processing Global Offset Table."
                break

            # All other non-zero entries are valid GOT entries
            elif got_entry > 0:

                # The actual data is located at <original GOT entry> + <BFLT_HEADER_SIZE>
                new_entry = got_entry + BFLT_HEADER_SIZE

                if DEBUG:
                    print "Replacing GOT entry value 0x%.8X with 0x%.8X at offset 0x%.8X" % (
                        got_entry, new_entry, i)

                # Replace the GOT entry with the correct pointer
                idaapi.put_long(i, new_entry)
                # add info about relocation to help analyzer
                fd.off = new_entry
                idaapi.set_fixup(i, fd)

            # Make each GOT entry a DWORD
            MakeDword(i)

            # Point i at the next GOT entry address
            i = i + 4

    # Patch relocation addresses
    for i in range(0, reloc_count):
        try:
            # Get the next relocation entry.
            # Relocation entry = <address of bytes to be patched> - <BFLT_HEADER_SIZE>
            li.seek(reloc_start + (i * 4))
            reloc_offset = struct.unpack(">I",
                                         li.read(4))[0] + BFLT_HEADER_SIZE

            # Sanity check, make sure the relocation offset is in a defined segment
            if reloc_offset < bss_end:
                try:
                    # reloc_offset + base_offset == <pointer to actual data> - <BFLT_HEADER_SIZE>
                    li.seek(reloc_offset)
                    reloc_val = struct.unpack(">I", li.read(4))[0]
                    if reloc_val == 0:
                        # skip zero relocs
                        # see fs/binfmt_flat.c
                        if DEBUG:
                            print "Skipping zero reloc at (0x%.8X)" % reloc_offset
                        continue

                    reloc_data_offset = reloc_val + BFLT_HEADER_SIZE

                    if DEBUG:
                        print "Patching reloc: (0x%.8X) == 0x%.8X" % (
                            reloc_offset, reloc_data_offset)

                    # Replace pointer at reloc_offset with the address of the actual data
                    idaapi.put_long(reloc_offset, reloc_data_offset)
                    # add info about relocation to help analyzer
                    fd.off = reloc_data_offset
                    idaapi.set_fixup(reloc_offset, fd)
                except Exception, e:
                    print "Error patching relocation entry #%d: %s" % (i,
                                                                       str(e))
            elif DEBUG:
                print "Relocation entry #%d outside of defined file sections, skipping..." % i
Example #38
0
    def check_fmt_function(name, addr):
        """
        Check if the format string argument is not valid
        """
        function_head = GetFunctionAttr(addr, idc.FUNCATTR_START)

        while True:
            addr = idc.PrevHead(addr)
            op = GetMnem(addr).lower()
            dst = GetOpnd(addr, 0)

            if op in ("ret", "retn", "jmp", "b") or addr < function_head:
                return

            c = GetCommentEx(addr, 0)
            if c and c.lower() == "format":
                break
            elif name.endswith(("snprintf_chk",)):
                if op in ("mov", "lea") and dst.endswith(("r8", "r8d", "[esp+10h]")):
                    break
            elif name.endswith(("sprintf_chk",)):
                if op in ("mov", "lea") and (dst.endswith(("rcx", "[esp+0Ch]", "R3")) or
                                             dst.endswith("ecx") and BITS == 64):
                    break
            elif name.endswith(("snprintf", "fnprintf")):
                if op in ("mov", "lea") and (dst.endswith(("rdx", "[esp+8]", "R2")) or
                                             dst.endswith("edx") and BITS== 64):
                    break
            elif name.endswith(("sprintf", "fprintf", "dprintf", "printf_chk")):
                if op in ("mov", "lea") and (dst.endswith(("rsi", "[esp+4]", "R1")) or
                                             dst.endswith("esi") and BITS == 64):
                    break
            elif name.endswith("printf"):
                if op in ("mov", "lea") and (dst.endswith(("rdi", "[esp]", "R0")) or
                                             dst.endswith("edi") and BITS == 64):
                    break

        # format arg found, check its type and value
        # get last oprend
        op_index = GetDisasm(addr).count(",")
        op_type = GetOpType(addr, op_index)
        opnd = GetOpnd(addr, op_index)

        if op_type == o_reg:
            # format is in register, try to track back and get the source
            _addr = addr
            while True:
                _addr = idc.PrevHead(_addr)
                _op = GetMnem(_addr).lower()
                if _op in ("ret", "retn", "jmp", "b") or _addr < function_head:
                    break
                elif _op in ("mov", "lea", "ldr") and GetOpnd(_addr, 0) == opnd:
                    op_type = GetOpType(_addr, 1)
                    opnd = GetOpnd(_addr, 1)
                    addr = _addr
                    break

        if op_type == o_imm or op_type == o_mem:
            # format is a memory address, check if it's in writable segment
            op_addr = GetOperandValue(addr, op_index)
            seg = idaapi.getseg(op_addr)
            if seg:
                if not seg.perm & idaapi.SEGPERM_WRITE:
                    # format is in read-only segment
                    return

        print "0x%X: Possible Vulnerability: %s, format = %s" % (addr, name, opnd)
        return ["0x%X" % addr, name, opnd]
def analyze (payload):
    for n in xrange (payload.get_number_of_items()):
        ea = payload.get_item(n).ea
        seg = idaapi.getseg(ea)
        if seg and ((seg.perm & idaapi.SEGPERM_EXEC) != 0):
            payload.get_item(n).type = Item.TYPE_CODE
Example #40
0
 def __call__(self):
     s = idaapi.getseg(self.ea)
     idaapi.set_segm_class(s, self.sclass)
 def parse_phrase(op, has_displacement=False):
     """Parse the expression used for indexed memory access.
     
     Returns its AST as a nested list of lists.
     """
     
     # Check the addressing mode using in this segment
     segment = idaapi.getseg(address)
     if segment.bitness != 1:
         raise Exception(
             'Not yet handling addressing modes other than 32bit!')
     
     
     base_reg = get_sib_base_reg(op)
     scaled_index_reg = get_sib_scaled_index_reg(op)
     scale = get_sib_scale(op)
     
     if scale:
         
         # return nested list for reg+reg*scale
         if base_reg != '':
             # The last values in each tuple indicate the
             # preferred display position of each element.
             # base_reg + (scale_reg * scale)
             #
             
             if scaled_index_reg == '':
                 return [
                     self.NODE_TYPE_OPERATOR_PLUS, 
                         [self.NODE_TYPE_REGISTER, base_reg, 0] ]
                 
             return [
                 self.NODE_TYPE_OPERATOR_PLUS, 
                     [self.NODE_TYPE_REGISTER, base_reg, 0],
                     [self.NODE_TYPE_OPERATOR_TIMES,
                         [self.NODE_TYPE_REGISTER, scaled_index_reg, 0],
                         [self.NODE_TYPE_VALUE, scale, 1], 1 ] ]
         else:
             # If there's no base register and
             # mod == 01 or mod == 10 (=> operand has displacement)
             # then we need to add EBP
             if has_displacement:
                 return [
                     self.NODE_TYPE_OPERATOR_PLUS,
                         [ self.NODE_TYPE_REGISTER, 'ebp', 0],
                         [ self.NODE_TYPE_OPERATOR_TIMES,
                             [self.NODE_TYPE_REGISTER, scaled_index_reg, 0],
                             [self.NODE_TYPE_VALUE, scale, 1], 1 ] ]
             return [
                 self.NODE_TYPE_OPERATOR_PLUS,
                     [ self.NODE_TYPE_OPERATOR_TIMES,
                         [self.NODE_TYPE_REGISTER, scaled_index_reg, 0],
                         [self.NODE_TYPE_VALUE, scale, 1], 0 ] ]
     
     else:
         # return nested list for reg+reg
         if base_reg == '':
             if scaled_index_reg != '':
                 if has_displacement:
                     return [
                         self.NODE_TYPE_OPERATOR_PLUS,
                             [ self.NODE_TYPE_REGISTER, 'ebp', 0],
                             [ self.NODE_TYPE_REGISTER, scaled_index_reg, 1 ] ]
                 return [
                     self.NODE_TYPE_OPERATOR_PLUS,
                         [self.NODE_TYPE_REGISTER, scaled_index_reg, 0 ] ]
             else:
                 if has_displacement:
                     return [self.NODE_TYPE_OPERATOR_PLUS, [self.NODE_TYPE_REGISTER, 'ebp', 0] ]
                 return [ ]
                 
         else:
             if scaled_index_reg != '':
                 return [
                     self.NODE_TYPE_OPERATOR_PLUS,
                         [self.NODE_TYPE_REGISTER, base_reg, 0],
                         [self.NODE_TYPE_REGISTER, scaled_index_reg, 1 ] ]
             else:
                 return [
                     self.NODE_TYPE_OPERATOR_PLUS,
                         [self.NODE_TYPE_REGISTER, base_reg, 0] ]
Example #42
0
 def is_writable(self, offset):
     """Determine if memory address is writable"""
     self.ret = bool(idaapi.getseg(offset).perm & idaapi.SEGPERM_WRITE)
     return self.ret
Example #43
0
 def __call__(self):
     s = idaapi.getseg(self.ea)
     idaapi.set_segm_name(s, self.name.encode('utf-8'))
Example #44
0
def is_rw_ea(ea):
    seg = idaapi.getseg(ea)
    return seg.perm & idaapi.SEGPERM_WRITE and seg.perm & idaapi.SEGPERM_READ
Example #45
0
def section_end(i):
    sec = idaapi.getseg(i)
    assert sec, "no section for 0x%x" % i

    return sec.endEA
Example #46
0
 def __call__(self):
     s = idaapi.getseg(self.ea)
     idaapi.set_segm_name(s, self.name)
Example #47
0
    def single_operand_parser(self, address, op, idx):
        """Parse a PPC operand."""
        
        def constraint_value(value):
            if value>2**16:
                return -(2**32-value)
            return value

        
        # Operand parsing
        #
        
        if op.type == OPERAND_TYPE_NO_OPERAND:
            return None
        
        #print '>>>', hex(address), idx, op.type
        
        segment = idaapi.getseg(address)
        addressing_mode = segment.bitness
        
        # Start creating the AST, the root entry is always the width of the
        # operand
        operand = [self.OPERAND_WIDTH[self.as_byte_value(op.dtyp)]]
        
        
        # Compose the rest of the AST
        #
        
        if op.type == OPERAND_TYPE_DISPLACEMENT:
            
            # A displacement operatior might refer to a variable...
            #
            var_name = None
            
            # Try to get any name that might have been assigned to the
            # variable. It's only done if the register is:
            # sp/esp (4) os bp/ebp (5)
            #
            flags = idc.GetFlags(address)
            if (idx==0 and idc.isStkvar0(flags)) or (
                idx==1 and idc.isStkvar1(flags)):
                
                var_name = self.get_operand_stack_variable_name(address, op, idx)
            
            #if has_sib_byte(op) is True:
                # when SIB byte set, process the SIB indexing
            #    phrase = parse_phrase(op)
            #else:
            phrase = [
                self.NODE_TYPE_OPERATOR_PLUS,
                    [self.NODE_TYPE_REGISTER,
                        self.REGISTERS[self.as_byte_value(op.reg)], 0]]
            
            if var_name:
                value = arch.ExpressionNamedValue(long(op.addr), var_name)
            else:
                value = constraint_value(op.addr)
            
            operand.extend([
                [self.NODE_TYPE_DEREFERENCE,
                    phrase+[ [self.NODE_TYPE_VALUE, value, 1]] ] ])
        
        elif op.type == OPERAND_TYPE_REGISTER:
            operand.extend([
                [self.NODE_TYPE_REGISTER, self.REGISTERS[self.as_byte_value(op.reg)], 1]])
                
        
        elif op.type == OPERAND_TYPE_MEMORY:
            
            addr_name = self.get_address_name(op.addr)
            
            if addr_name:
                value = arch.ExpressionNamedValue(long(op.addr), addr_name)
            else:
                value = op.addr
            
            operand.extend([
                [self.NODE_TYPE_DEREFERENCE,
                    [self.NODE_TYPE_VALUE, value, 0]] ])
             
        
        elif op.type == OPERAND_TYPE_IMMEDIATE:
            
            # Keep the value's size
            #
            if self.as_byte_value(op.dtyp) == 0:
                mask = 0xff
            elif self.as_byte_value(op.dtyp) == 1:
                mask = 0xffff
            else:
                mask = 0xffffffff
            
            operand.extend([[self.NODE_TYPE_VALUE, op.value&mask, 0]])
            
        
        elif op.type in (OPERAND_TYPE_NEAR, OPERAND_TYPE_FAR):
            
            addr_name = self.get_address_name(op.addr)
            
            if addr_name:
                value = arch.ExpressionNamedValue(long(op.addr), addr_name)
            else:
                value = op.addr
            
            operand.extend([[self.NODE_TYPE_VALUE, value, 0]])
            
        
        elif op.type == OPERAND_TYPE_PHRASE:
            print '***Dunno how to parse PHRASE'
            operand.extend([[self.NODE_TYPE_SYMBOL,
                'UNK_PHRASE(val:%d, reg:%d, type:%d)' % (
                    op.value, self.as_byte_value(op.reg), op.type), 0]])
        
        elif op.type == OPERAND_TYPE_IDPSPEC0:
            
            # Handle Special Purpose Registers
            #
            register = self.SPR_REGISTERS.get(
                op.value, 'UNKNOWN_REGISTER(val:%x)' % op.value)
            
            operand.extend([
                [self.NODE_TYPE_REGISTER, register, 0]])
        
        elif op.type == OPERAND_TYPE_IDPSPEC1:
            #print '***Dunno how to parse OPERAND_TYPE_IDPSPEC1'
            #operand.extend([[self.NODE_TYPE_SYMBOL,
            #    'UNK_IDPSPEC1(val:%d, reg:%d, type:%d)' % (
            #        op.value, op.reg, op.type), 0]])
            operand.extend([
                [self.NODE_TYPE_REGISTER, self.REGISTERS[self.as_byte_value(op.reg)], 1]])
            operand.extend([
                [self.NODE_TYPE_REGISTER, self.REGISTERS[self.as_byte_value(op.specflag1)], 2]])
        
        elif op.type == OPERAND_TYPE_IDPSPEC2:
            # IDSPEC2 is operand type for all rlwinm and rlwnm
            # instructions which are in general op reg, reg, byte, byte, byte
            # or eqivalent. simplified mnemonics sometimes take less than
            # five arguments.
            #
            # Keep the value's size
            #
            if self.as_byte_value(op.dtyp) == 0:
                mask = 0xff
            elif self.as_byte_value(op.dtyp) == 1:
                mask = 0xffff
            else:
                mask = 0xffffffff

            operand_1 = []
            operand_2 = []
            operand_3 = []

            # Get the object representing the instruction's data.
            # It varies between IDA pre-5.7 and 5.7 onwards, the following check
            # will take care of it (for more detail look into the similar 
            # construct in arch.py)
            #
            if hasattr(idaapi, 'cmd' ):
                idaapi.decode_insn(address)
                ida_instruction = idaapi.cmd
            else:
                idaapi.ua_code(address)
                ida_instruction = idaapi.cvar.cmd
            
            if (ida_instruction.auxpref & 0x0020):
                #print "SH"		    
                operand_1 = [self.OPERAND_WIDTH[self.as_byte_value(op.dtyp)]]
                operand_1.extend([[self.NODE_TYPE_VALUE, self.as_byte_value(op.reg)&mask, 0]])
            else:
                operand_1 = [self.OPERAND_WIDTH[self.as_byte_value(op.dtyp)]]
                operand_1.extend([[self.NODE_TYPE_REGISTER, self.REGISTERS[self.as_byte_value(op.reg)], 0]])
            #print operand_1

            if (ida_instruction.auxpref & 0x0040):
                #print "MB"
                operand_2 = [self.OPERAND_WIDTH[self.as_byte_value(op.dtyp)]]
                operand_2.extend([[self.NODE_TYPE_VALUE, self.as_byte_value(op.specflag1)&mask, 0]])
            #print operand_2

            if (ida_instruction.auxpref & 0x0080):
                #print "ME"
                operand_3 = [self.OPERAND_WIDTH[self.as_byte_value(op.dtyp)]]
                operand_3.extend([[self.NODE_TYPE_VALUE, self.as_byte_value(op.specflag2)&mask, 0]])
            #print operand_3

            operand = [operand_1]
            #operand = operand_1

            if (ida_instruction.auxpref & 0x0040): 
                #print "MB2"
                operand.append(operand_2)
            if (ida_instruction.auxpref & 0x0080):
                #print "ME2"
                operand.append(operand_3)	    

            #print operand 
            # operand = operand_1
            #print operand
            #print '>>>', hex(address), idx, op.type, op.reg
            #operand.extend([[self.NODE_TYPE_OPERATOR_COMMA, [self.NODE_TYPE_VALUE, op.reg&mask, 0], [self.NODE_TYPE_VALUE, self.as_byte_value(op.specflag1)&mask, 1], [self.NODE_TYPE_VALUE, self.as_byte_value(op.specflag2)&mask, 2]]])

        elif op.type == OPERAND_TYPE_IDPSPEC3:
            # CR registers
            #
            operand.extend([
                [self.NODE_TYPE_REGISTER, self.CR_REGISTERS[self.as_byte_value(op.reg)], 0]])
        
        elif op.type == OPERAND_TYPE_IDPSPEC4:
            # The bit in the CR to check for
            #
            operand.extend([[self.NODE_TYPE_REGISTER, self.as_byte_value(op.reg), 0]])
            
        
        elif op.type == OPERAND_TYPE_IDPSPEC5:
            # Device Control Register, implementation specific
            operand.extend([[self.NODE_TYPE_REGISTER, 'DCR(%x)' % op.value, 0]])
            
        
        return operand
 def get_segm_name(ea, align=10):
     seg = idaapi.get_segm_name(idaapi.getseg(ea))
     line = idaapi.add_spaces(seg, align)
     return idaapi.COLSTR(line, idaapi.SCOLOR_SEGNAME)
Example #49
0
    def search_pointers(self):

        # HACK: A separate flag is used to track user canceling the search,
        #       because multiple calls to idaapi.wasBreak() do not properly
        #       detect cancellations.
        breakFlag = False

        # Show wait dialog
        idaapi.show_wait_box("Searching writable function pointers...")

        for m in self.modules:

            ###################################################################
            # Locate all of the CALL and JMP instructions in the current module
            # which use an immediate operand.

            # List of call/jmp pointer calls in a given module
            ptr_calls = list()

            # Iterate over segments in the module
            # BUG: Iterating over all loaded segments is more stable than looking up by address
            for n in xrange(idaapi.get_segm_qty()):
                seg = idaapi.getnseg(n)

                # Segment in a selected modules
                if seg and seg.startEA >= m.addr and seg.endEA <= (m.addr + m.size):

                    # Locate executable segments
                    # NOTE: Each module may have multiple executable segments
                    # TODO: Search for "MOV REG, PTR # CALL REG"
                    if seg.perm & idaapi.SEGPERM_EXEC:

                        # Search all instances of CALL /2 imm32/64 - FF 15
                        # TODO: Alternative pointer calls using SIB: FF 14 E5 11 22 33 44 - call dword/qword ptr [0x44332211]
                        #                                            FF 14 65 11 22 33 44
                        #                                            FF 14 25 11 22 33 44
                        call_ea = seg.startEA
                        while True:
                            call_ea = idaapi.find_binary(call_ea + 1, seg.endEA, "FF 15", 16, idaapi.SEARCH_DOWN)
                            if call_ea == idaapi.BADADDR: break
                            ptr_calls.append(call_ea)

                        # Search all instances of JMP /2 imm32/64 - FF 25
                        # TODO: Alternative pointer calls using SIB: FF 24 E5 11 22 33 44 - jmp dword/qword ptr [0x44332211]
                        #                                            FF 24 65 11 22 33 44
                        #                                            FF 24 25 11 22 33 44
                        call_ea = seg.startEA
                        while True:
                            call_ea = idaapi.find_binary(call_ea + 1, seg.endEA, "FF 25", 16, idaapi.SEARCH_DOWN)
                            if call_ea == idaapi.BADADDR: break
                            ptr_calls.append(call_ea)

            ###################################################################
            # Extract all of the function pointers and make sure they are
            # are writable.

            # List of writable function pointer objects in a given module
            ptrs = list()

            for call_ea in ptr_calls:

                # Decode CALL/JMP instruction
                # NOTE: May result in invalid disassembly of split instructions
                insn_size = idaapi.decode_insn(call_ea)

                if insn_size:

                    insn = idaapi.cmd
                    insn_op1 = insn.Operands[0].type

                    # Verify first operand is a direct memory reference
                    if insn.Operands[0].type == idaapi.o_mem:

                        # Get operand address
                        ptr_ea = insn.Operands[0].addr

                        # Apply pointer offset
                        ptr_ea -= self.ptrOffset

                        # Locate segment where the pointer is located
                        ptr_seg = idaapi.getseg(ptr_ea)

                        # Make sure a valid segment writeable segment was found
                        if ptr_seg and ptr_seg.perm & idaapi.SEGPERM_WRITE:

                            # Get pointer charset
                            ptr_charset = self.sploiter.get_ptr_charset(ptr_ea)

                            # Filter the pointer
                            if not self.filterP2P:
                                if ptr_charset == None:                                    continue
                                if self.ptrNonull and not "nonull" in ptr_charset: continue
                                if self.ptrUnicode and not "unicode" in ptr_charset: continue
                                if self.ptrAscii and not "ascii" in ptr_charset: continue
                                if self.ptrAsciiPrint and not "asciiprint" in ptr_charset: continue
                                if self.ptrAlphaNum and not "alphanum" in ptr_charset: continue
                                if self.ptrNum and not "numeric" in ptr_charset: continue
                                if self.ptrAlpha and not "alpha" in ptr_charset: continue

                            # Increment the fptr counter

                            # Get pointer disassembly
                            insn_disas = idc.GetDisasmEx(call_ea, idaapi.GENDSM_FORCE_CODE)

                            # Add pointer to the list
                            ptr = Ptr(m.file, ptr_ea, self.ptrOffset, ptr_charset, call_ea, insn_disas)
                            ptrs.append(ptr)

            ###################################################################
            # Cache Pointers to Pointers

            ptr_ea_prefix_cache = dict()

            if self.searchP2P:

                # CACHE: Running repeated searches over the entire memory space is
                #        very expensive. Let's cache all of the addresses containing
                #        bytes corresponding to discovered function pointers in a
                #        single search and simply reference this cache for each
                #        function pointer. Specifically running idaapi.find_binary()
                #        is much more expensive than idaapi.dbg_read_memory().
                #
                # NOTE:  For performance considerations, the cache works on a per
                #        module basis, but could be expanded for the entire memory
                #        space.
                #
                # prefix_offset - how many bytes of discovered function
                #        pointers to cache.
                #
                #        Example: For function pointers 0x00401234, 0x00404321, 0x000405678
                #        we are going to use prefix_offset 2, so we will cache all of the
                #        values located at addresses 0x0040XXXX

                if self.sploiter.addr64:
                    pack_format = "<Q"
                    addr_bytes = 8
                    prefix_offset = 6
                else:
                    pack_format = "<I"
                    addr_bytes = 4
                    prefix_offset = 2

                # Set of unique N-byte address prefixes to search in memory
                ea_prefix_set = set()

                for ptr in ptrs:
                    ptr_ea = ptr.ptr_ea

                    ptr_bytes = struct.pack(pack_format, ptr_ea)
                    ptr_bytes = ptr_bytes[-prefix_offset:]

                    ea_prefix_set.add(ptr_bytes)

                # Search the module for all bytes corresponding to the prefix
                # and use them as candidates for pointers-to-pointers

                for ea_prefix in ea_prefix_set:

                    # NOTE: Make sure you search using 44 33 22 11 format and not 11223344
                    ea_prefix_str = " ".join(["%02x" % ord(b) for b in ea_prefix])

                    # Initialize search parameters for a given module
                    ea = m.addr
                    maxea = m.addr + m.size

                    while True:
                        ea = idaapi.find_binary(ea + 1, maxea, ea_prefix_str, 16, idaapi.SEARCH_DOWN)
                        if ea == idaapi.BADADDR: break

                        p2p_ea = ea - (addr_bytes - prefix_offset)

                        dbg_mem = read_module_memory(p2p_ea, addr_bytes)
                        ptr_ea_prefix = unpack(pack_format, dbg_mem)[0]

                        if ptr_ea_prefix in ptr_ea_prefix_cache:
                            ptr_ea_prefix_cache[ptr_ea_prefix].add(p2p_ea)
                        else:
                            ptr_ea_prefix_cache[ptr_ea_prefix] = set([p2p_ea, ])

                        # Detect search cancellation, but allow the loop below
                        # to run to create already cached/found function pointers

                        # Canceled
                        if breakFlag or idaapi.wasBreak():
                            breakFlag = True
                            break

                    # Canceled
                    if breakFlag or idaapi.wasBreak():
                        breakFlag = True
                        break

            ###################################################################
            # Locate Pointer to Pointers

            for ptr in ptrs:

                ptr_ea = ptr.ptr_ea

                # Locate pointers-to-pointers for a given function pointer in the cache
                if self.searchP2P and ptr_ea in ptr_ea_prefix_cache:

                    for p2p_ea in ptr_ea_prefix_cache[ptr_ea]:

                        # Apply pointer-to-pointer offset
                        p2p_ea -= self.p2pOffset

                        p2p_charset = self.sploiter.get_ptr_charset(p2p_ea)

                        # Filter the pointer
                        if self.filterP2P:
                            if p2p_charset == None:                                    continue
                            if self.ptrNonull and not "nonull" in p2p_charset: continue
                            if self.ptrUnicode and not "unicode" in p2p_charset: continue
                            if self.ptrAscii and not "ascii" in p2p_charset: continue
                            if self.ptrAsciiPrint and not "asciiprint" in p2p_charset: continue
                            if self.ptrAlphaNum and not "alphanum" in p2p_charset: continue
                            if self.ptrNum and not "numeric" in p2p_charset: continue
                            if self.ptrAlpha and not "alpha" in p2p_charset: continue

                        # Copy existing pointer object to modify it for the particular p
                        p2p = copy.copy(ptr)
                        p2p.p2p_ea = p2p_ea
                        p2p.p2p_offset = self.p2pOffset
                        p2p.p2p_charset = p2p_charset

                        # Apppend p2p specific pointer object to the global list
                        self.ptrs.append(p2p)

                        # Exceeded maximum number of pointers
                        if self.maxPtrs and len(self.ptrs) >= self.maxPtrs:
                            breakFlag = True
                            print "[idasploiter] Maximum number of pointers exceeded."
                            break

                # Simply append pointer object to the global list
                else:
                    self.ptrs.append(ptr)

                    # Exceeded maximum number of pointers
                    if self.maxPtrs and len(self.ptrs) >= self.maxPtrs:
                        breakFlag = True
                        print "[idasploiter] Maximum number of pointers exceeded."
                        break

                if breakFlag or idaapi.wasBreak():
                    breakFlag = True
                    break

            # Canceled
            # NOTE: Only works when started from GUI not script.
            if breakFlag or idaapi.wasBreak():
                breakFlag = True
                print "[idasploiter] Canceled."
                break

        print "[idasploiter] Found %d total pointers." % len(self.ptrs)
        idaapi.hide_wait_box()
 def is_seg_init(ea):
     return idaapi.get_segm_name(idaapi.getseg(ea)).startswith('.init')
Example #51
0
def new(offset, size, name, **kwds):
    """Create a segment at `offset` with `size` and name it according to `name`.

    The keyword `bits` can be used to specify the bit size of the segment
    The keyword `comb` can be used to specify any flags (idaapi.sc*)
    The keyword `align` can be used to specify paragraph alignment (idaapi.sa*)
    The keyword `org` specifies the origin of the segment (must be paragraph aligned due to ida)
    """
    res = utils.string.to(name)

    # find the segment according to the name specified by the user
    seg = idaapi.get_segm_by_name(res)
    if seg is not None:
        raise E.DuplicateItemError(
            u"{:s}.new({:#x}, {:+#x}, \"{:s}\"{:s}) : A segment with the specified name (\"{:s}\") already exists."
            .format(
                __name__, offset, size, utils.string.escape(name, '"'),
                u", {:s}".format(utils.string.kwargs(kwds)) if kwds else '',
                utils.string.escape(name, '"')))

    # FIXME: use disassembler default bit length instead of 32
    bits = kwds.get(
        'bits',
        32 if idaapi.getseg(offset) is None else idaapi.getseg(offset).abits())

    ## create a selector with the requested origin
    if bits == 16:
        org = kwds.get('org', 0)
        if org & 0xf > 0:
            raise E.InvalidTypeOrValueError(
                u"{:s}.new({:#x}, {:+#x}, {!r}{:s}) : The specified origin ({:#x}) is not aligned to the size of a paragraph (0x10)."
                .format(
                    __name__, offset, size, name, u", {:s}".format(
                        utils.string.kwargs(kwds)) if kwds else '', org))

        para = offset // 16
        sel = idaapi.allocate_selector(para)
        idaapi.set_selector(sel,
                            (para - kwds.get('org', 0) // 16) & 0xffffffff)

    ## if the user specified a selector, then use it
    elif 'sel' in kwds or 'selector' in kwds:
        sel = kwds.get('sel', kwds.get('selector',
                                       idaapi.find_free_selector()))

    ## choose the paragraph size defined by the user
    elif 'para' in kwds or 'paragraphs' in kwds:
        para = kwds.get('paragraph', kwds.get('para', 1))
        sel = idaapi.setup_selector(para)

    ## find a selector that is 1 paragraph size,
    elif idaapi.get_selector_qty():
        sel = idaapi.find_selector(1)

    # otherwise find a free one and set it.
    else:
        sel = idaapi.find_free_selector()
        idaapi.set_selector(sel, 1)

    # populate the segment_t for versions of IDA prior to 7.0
    if idaapi.__version__ < 7.0:
        seg = idaapi.segment_t()
        seg.startEA, seg.endEA = offset, offset + size

    # now for versions of IDA 7.0 and newer
    else:
        seg = idaapi.segment_t()
        seg.start_ea, seg.end_ea = offset, offset + size

    # assign the rest of the necessary attributes
    seg.sel = sel
    seg.bitness = {16: 0, 32: 1, 64: 2}[bits]
    seg.comb = kwds.get('comb', idaapi.scPub)  # public
    seg.align = kwds.get('align', idaapi.saRelByte)  # paragraphs

    # now we can add our segment_t to the database
    res = utils.string.to(name)
    ok = idaapi.add_segm_ex(seg, res, "",
                            idaapi.ADDSEG_NOSREG | idaapi.ADDSEG_SPARSE)
    if not ok:
        ok = idaapi.del_selector(sel)
        if not ok:
            logging.warning(
                u"{:s}.new({:#x}, {:+#x}, {!r}{:s}) : Unable to delete the created selector ({:#x}) for the new segment."
                .format(
                    __name__, offset, size, name, u", {:s}".format(
                        utils.string.kwargs(kwds)) if kwds else '', sel))
        raise E.DisassemblerError(
            u"{:s}.new({:#x}, {:+#x}, {!r}{:s}) : Unable to add a new segment."
            .format(
                __name__, offset, size, name,
                u", {:s}".format(utils.string.kwargs(kwds)) if kwds else ''))
    return seg
Example #52
0
def by_address(ea):
    '''Return the segment that contains the specified `ea`.'''
    seg = idaapi.getseg(interface.address.within(ea))
    if seg is None:
        raise E.SegmentNotFoundError(u"{:s}.by_address({:#x}) : Unable to locate segment containing the specified address.".format(__name__, ea))
    return seg
Example #53
0
def by_address(ea):
    '''Return the segment that contains the specified ``ea``.'''
    s = idaapi.getseg(interface.address.within(ea))
    if s is None:
        raise LookupError("{:s}.by_address({:x}) : Unable to locate segment".format(__name__, ea))
    return s
Example #54
0
# Triple recursion limit.
sys.setrecursionlimit(3 * sys.getrecursionlimit())

plt_seg = None
plt_start = 0
plt_end = 0
segments = list(idautils.Segments())
exec_segments = list()
for segment in segments:
    if idc.SegName(segment) == ".plt":
        plt_seg = segment
        plt_start = idc.SegStart(plt_seg)
        plt_end = idc.SegEnd(plt_seg)

    permissions = idaapi.getseg(segment).perm
    if permissions & idaapi.SEGPERM_EXEC:
        exec_segments.append(segment)

allowed_xref_types = [
    IDA_XrefTypes.Code_Far_Call, IDA_XrefTypes.Code_Near_Call,
    IDA_XrefTypes.Code_Far_Jump, IDA_XrefTypes.Code_Near_Jump,
    IDA_XrefTypes.Data_Offset
]

start_time = time.time()

# Import existing ssa file if exists in order to be able to process idb
# in multiple steps.
export_ssa_file = idc.GetInputFile() + "_ssa.pb2"
export_ssa_dict = dict()
Example #55
0
 def create_got_fix(cls):
     idaapi.add_segm(0, 0x90000000, 0x90000001, '.got', 'DATA')
     seg = idaapi.getseg(0x90000000)
     idaapi.set_visible_segm(seg, False)
Example #56
0
def print_section_list():
    for s in idautils.Segments():
        seg = idaapi.getseg(s)
        print("    {name:\"%s\", begin:0x%x, end:0x%x}," % (idc.SegName(s), idc.SegStart(s), idc.SegEnd(s)))
Example #57
0
 def segment(cls):
     """Current segment"""
     ea = cls.address()
     return idaapi.getseg(ea)
Example #58
0
def byAddress(ea):
    '''Return the segment_t that holds the specified /ea/'''
    s = idaapi.getseg(ea)
    if s is None:
        raise Exception, "segment.byAddress(%x):unable to locate segment" % ea
    return s