Beispiel #1
0
def get_params(ea):
    data_addr = None
    length = None
    inst = idautils.DecodePreviousInstruction(ea)
    if (inst != None) and (inst.get_canon_mnem() == "mov"):
        length = inst.Op2.value
        inst2 = idautils.DecodePreviousInstruction(inst.ea)
        if (inst2 != None) and (inst2.get_canon_mnem() == "mov"):
            inst3 = idautils.DecodePreviousInstruction(inst2.ea)
            if (inst3 != None) and (inst3.get_canon_mnem() == "lea"):
                length = inst.Op2.value
                data_addr = inst3.Op2.addr

    return data_addr, length
Beispiel #2
0
def get_first_function(ea):
    """ see above, but returns the first pushed value """
    maybe_start = idc.get_func_attr(ea, idc.FUNCATTR_START)
    limit = 0
    if maybe_start == idc.BADADDR:
        limit = 10

    cur_ea = ea
    limit_count = 0
    while cur_ea != idc.BADADDR:
        # are we over limit or up to the func start?
        limit_count += 1
        limit_exceeded = (limit > 0 and limit_count > limit)
        too_far = (maybe_start != idc.BADADDR and cur_ea < maybe_start)
        if limit_exceeded or too_far:
            LOG.error(
                "Failed to find string walking backwards from {:08X}".format(
                    ea))
            return None

        prev_ins = idautils.DecodePreviousInstruction(cur_ea)
        prev_ea = prev_ins.ea

        # did we find it?
        if idc.GetMnem(prev_ea) == 'push':
            if idc.get_operand_type(prev_ea, 0) in [idc.o_mem, idc.o_imm]:
                # push offset found!
                pushed_addr = idc.GetOperandValue(prev_ea, 0)
                # it's not data, then probably good
                if idc.isCode(idc.GetFlags(pushed_addr)):
                    return pushed_addr

        cur_ea = prev_ea
Beispiel #3
0
def ret_addr(ea):

    #we can't assume Thumb only, so we also keep ARM cases, just adjust addr in Thumb cases
    if (ea % 2) != 0:
        ea -= 1
    '''
	#calculating code segment ranges every time is wasteful
	code_segs = []
	for s in idautils.Segments():
		if idaapi.segtype(s) == idaapi.SEG_CODE:
			s_end = idc.GetSegmentAttr(s, SEGATTR_END)
			code_segs.append({"start" : s, "end" : s_end})

	if not reduce(lambda x, y: x or y, map(lambda x: (x["start"] <= ea) and (x["end"] > ea), code_segs)):
		return False
	'''

    #this is-in-function check is enough (segment check redundant) if we trust function ID'ing anyway.

    f_ea = idaapi.get_func(ea)
    if not f_ea:
        return False

    #Preceding or Previous?
    #	Not necessarily all preceding will be a call to a ret instruction,
    #	but "the" prev should be always the one.
    i = idautils.DecodePreviousInstruction(ea)
    if i and "BL" in idc.GetMnem(i.ea):
        return True

    return False
def parse_xrefs(xrefs):
	rsas = set()
	
	for xref in xrefs:
		name = None
		rsa = None
		
		ea = xref
		
		for i in range(0, 7):
			decoded_instruction = idautils.DecodePreviousInstruction(ea)
			xrefs_from = idautils.XrefsFrom(decoded_instruction.ea)
			
			for ref in xrefs_from:
				if ref.type == 1:
					s = idc.GetString(ref.to)
					
					if s:
						rsa = s
				elif ref.type == 21 and idc.GetDisasm(ref.to).find("cfstr") != -1:
					cfstr_xrefs = idautils.XrefsFrom(ref.to)
					
					for cfstr_xref in cfstr_xrefs:
						if cfstr_xref.type == 1:
							for cfstr_xref2 in idautils.XrefsFrom(cfstr_xref.to):
								s = idc.GetString(cfstr_xref2.to)
								if s and s.strip() != "":
									name = s
									
									if name and rsa:
										rsas.add((name, rsa))
			ea = decoded_instruction.ea
	
	return [{"name": x[0].strip(), "rsa": x[1].strip()} for x in rsas]
def get_prev_push_addr(base_addr):
    global INSTR_DISTANCE_LIMITER
    prev_op = idautils.DecodePreviousInstruction(base_addr)
    retVal = idaapi.BADADDR  # static value

    for idx in range(INSTR_DISTANCE_LIMITER):

        # some calls get rekt by asm segments
        if prev_op is None:
            break

        if is_push_mnem(prev_op.ea):
            retVal = prev_op.ea
            break

        prev_op = idautils.DecodePreviousInstruction(prev_op.ea)

    return retVal
Beispiel #6
0
def ret_addr(ea):

    #we can't assume Thumb only, so we also keep ARM cases, just adjust addr in Thumb cases
    if (ea % 2) != 0:
        ea -= 1

    f_ea = idaapi.get_func(ea)
    if not f_ea:
        return False

    #Preceding or Previous?
    #	Not necessarily all preceding will be a call to a ret instruction,
    #	but "the" prev should be always the one.
    i = idautils.DecodePreviousInstruction(ea)
    if i and "BL" in idc.GetMnem(i.ea):
        return True

    return False
Beispiel #7
0
def get_first_string(ea):
    """ walk up and grab a string like this
    push    offset aGamegetpotionc ; "GameGetPotionColorUint"
    lea     ecx, [ebp+var_244] ; int
    call    makestr
    push    offset sub_435ADA
    lea     eax, [ebp+var_244]
    mov     ecx, esi
    push    eax
    call    register_global ; <---- ea
    """
    maybe_start = idc.get_func_attr(ea, idc.FUNCATTR_START)
    limit = 0
    if maybe_start == idc.BADADDR:
        limit = 10

    cur_ea = ea
    limit_count = 0
    while cur_ea != idc.BADADDR:
        # are we over limit or up to the func start?
        limit_count += 1
        limit_exceeded = (limit > 0 and limit_count > limit)
        too_far = (maybe_start != idc.BADADDR and cur_ea < maybe_start)
        if limit_exceeded or too_far:
            LOG.error(
                "Failed to find string walking backwards from {:08X}".format(
                    ea))
            return None

        prev_ins = idautils.DecodePreviousInstruction(cur_ea)
        prev_ea = prev_ins.ea

        # did we find it?
        if idc.GetMnem(prev_ea) == 'push':
            if idc.get_operand_type(prev_ea, 0) in [idc.o_mem, idc.o_imm]:
                # push offset found!
                pushed_addr = idc.GetOperandValue(prev_ea, 0)
                if idc.isASCII(idc.GetFlags(pushed_addr)):
                    s = idc.GetString(pushed_addr, -1, idc.ASCSTR_C)
                    #LOG.debug("Read string {} from {:08X} from instruction at {:08X}".format(repr(s), pushed_addr, prev_ea))
                    return s

        cur_ea = prev_ea
Beispiel #8
0
def get_interface_param_addr(xref):
    """
    Find the interface address looking for this instruction :
    lea     r8, Interface
    """
    # Check up to 3 instructions before
    next_addr = xref
    for i in range(3):
        inst = idautils.DecodePreviousInstruction(next_addr)
        if inst.get_canon_mnem() == 'call':
            break
        elif is_lea_r8_mem_inst(inst):
            return inst.Op2.addr
        next_addr = inst.ea

    # Check up to 3 instructions forward
    for addr in get_func_items_from_xref(xref)[:3]:
        inst = idautils.DecodeInstruction(addr)
        if inst.get_canon_mnem() == 'call':
            break
        elif is_lea_r8_mem_inst(inst):
            return inst.Op2.addr

    return None
Beispiel #9
0
 def preceeding_call(ea):
     p = idautils.DecodePreviousInstruction(ea)
     if p and "BL" in idc.GetMnem(p.ea):
         return str(idc.GetOpnd(p.ea, 0))
     else:
         return ""
Beispiel #10
0
    def notify_ana(self, insn):
        ea = insn.ea
        bytes_left = chunk_start(ea) + chunk_size(ea) - ea
        bytecode = ida_bytes.get_bytes(
            insn.ea, bytes_left)  # get remaining bytes in chunk
        try:
            instruction = EVMAsm.disassemble_one(bytecode)
        except Exception as e:
            print e
            return

        insn.size = instruction.size

        #initialize operands to voids
        operands = [insn[i] for i in xrange(1, 6)]
        for o in operands:
            o.type = o_void

        # set the instruction
        insn.itype = self.instruction_index.get(instruction._opcode, 0)

        #detect "CALLI"
        if instruction.name == "JUMPI":
            # TODO: check for 4 prev instructions where there is a DUP2 in the middle
            #decode 3 previous instructions
            prev_insns = [insn]
            for i in range(3):
                prev_insns.append(
                    idautils.DecodePreviousInstruction(prev_insns[-1].ea))
            prev_insns.pop(0)  # remove orig

            # sanity check previous instructions
            for i in prev_insns:
                #print i.get_canon_mnem(),
                if i.ea == ida_idaapi.BADADDR:
                    print 'ERROR'

            if (prev_insns[0].get_canon_mnem().startswith("PUSH2")
                    and prev_insns[1].get_canon_mnem().startswith("EQ")
                    and prev_insns[2].get_canon_mnem().startswith("PUSH4")):
                # switch it to a "CALLI"
                insn.itype = 1  # CALLI instruction index

                jump_target = self.get_operand(
                    prev_insns[0][0])  # operand on the push2
                insn[0].type = o_near
                insn[0].addr = jump_target

                function_hash = self.get_operand(
                    prev_insns[2][0])  # operand on the push4
                insn[1].type = o_imm
                insn[1].value = function_hash

                # set the target to be a function
                AutoMark(jump_target, AU_PROC)

        if instruction.has_operand:
            insn[0].type = o_idpspec0  # custom type
            insn[0].dtype = dt_byte32
            insn[0].addr = ea + 1  # operand is located after opcode
            insn[0].specval = instruction.operand_size
            #o.specval = str(instruction.operand)

        # return the instruction size here
        return insn.size
Beispiel #11
0
    def notify_emu(self, insn):
        feature = insn.get_canon_feature()
        #print "emulating", insn.get_canon_mnem(), hex(feature)

        mnemonic = insn.get_canon_mnem()
        if mnemonic == "CALLI":
            # operand 0 is the address
            # operand 1 is the function hash
            add_cref(insn.ea, insn.ea + insn.size,
                     fl_JN)  # false branch is following instruction
            addr = insn[0].addr
            add_cref(insn.ea, addr,
                     fl_CN)  # true branch is stored in operand index 0
            ida_bytes.set_cmt(insn.ea, "JUMPI", True)

            hash_str = '0x%08x' % (insn[1].value)
            function_prototype = known_hashes.knownHashes.get(hash_str, '')
            label = '%s (%s)' % (function_prototype, hash_str)
            if not ida_lines.get_extra_cmt(addr,
                                           ida_lines.E_PREV + 0):  # don't dup
                ida_lines.add_extra_cmt(addr, True, label)
                if function_prototype == '':
                    function_prototype = 'func_%s' % (hash_str)
                set_name(addr, function_prototype, SN_NOCHECK)

        elif mnemonic == "JUMPI":
            # add ref to next instruction for false branch
            add_cref(insn.ea, insn.ea + insn.size, fl_JN)

            # maybe we have a simple puch
            prev_insn = idautils.DecodePreviousInstruction(insn.ea)
            if prev_insn:
                if prev_insn.get_canon_mnem().startswith("PUSH"):
                    jump_addr = self.get_operand(prev_insn[0])
                    add_cref(insn.ea, jump_addr, fl_JN)

        elif mnemonic == "JUMP":
            prev_insn = idautils.DecodePreviousInstruction(insn.ea)
            if prev_insn:
                # TODO: implement stack modeling to resolve actual top value of stack
                if prev_insn.get_canon_mnem().startswith("PUSH"):
                    jump_addr = self.get_operand(prev_insn[0])
                    #print "found jump to", hex(jump_addr)
                    add_cref(insn.ea, jump_addr, fl_JN)
                    # TODO: adjust function boundary to include all code
                    #func = get_func(insn.ea)
                    #if func:
                    #    print "appending new tail"
                    #    append_func_tail(func, jump_addr, BADADDR)

        flows = (feature & CF_STOP) == 0
        if flows:
            add_cref(insn.ea, insn.ea + insn.size, fl_F)

        if may_trace_sp():
            if flows:
                self.trace_sp(insn)
            else:
                idc.recalc_spd(insn.ea)

        return True
Beispiel #12
0
def trace_arg_bwd(ea, arg_num):

    ARCH = "ARM32"
    CALL_ARGS = {"ARM32": ["R0", "R1", "R2", "R3"]}

    args = CALL_ARGS[ARCH]

    if (len(args) <= arg_num):
        arg_into = "SP"
        arg_offs = ((arg_num - len(args))) * 4
    else:
        arg_into = CALL_ARGS[ARCH][arg_num]
        arg_offs = 0

    func = idaapi.get_func(ea)
    fc = idaapi.FlowChart(func)

    for block in fc:
        if block.startEA <= ea and block.endEA > ea:
            break

    #original sink
    arg_in = set([arg_into])

    while (ea >= block.startEA):

        #print "0x%08x %s" % (ea, idc.GetDisasm(ea))

        ############ BEGINNING OF TRACING ############

        mnem = idc.GetMnem(ea)

        if mnem == "MOV":
            arg_to = idc.GetOpnd(ea, 0)
            arg_from = idc.GetOpnd(ea, 1)

            #propagate to new register
            if arg_to in arg_in:
                arg_in.add(arg_from)
            #note: if arg_from is in arg_in, but arg_to isn't, we don't add arg_to to the sinks, because we are going backwards,
            #so we know that's not the one that ended up being used.

        elif mnem == "LDR":

            arg_to = idc.GetOpnd(ea, 0)
            arg_from = idc.GetOpnd(ea, 1)

            if ARCH == "ARM32":

                if arg_to in arg_in:
                    #now there should be a a DataRef here to a string.
                    #we want the data reference that is of type 1 (Data_Offset), as oppossed to 1 (Data_Read)
                    refs = [r for r in idautils.XrefsFrom(ea) if r.type == 1]
                    if len(refs) == 1:
                        #print "There is only one data offset reference from here, if it is a string we are done."
                        for s in IDAStrings:
                            if s.ea == refs[0].to:
                                return str(s)

        elif mnem == "ADR" or mnem == "ADR.W":
            #print "ADR instruction!"

            arg_to = idc.GetOpnd(ea, 0)
            arg_from = idc.GetOpnd(ea, 1)

            if ARCH == "ARM32":

                if arg_to in arg_in:
                    #now there should be a a DataRef here to a string.
                    #we want the data reference that is of type 1 (Data_Offset), as oppossed to 1 (Data_Read)
                    refs = [r for r in idautils.XrefsFrom(ea) if r.type == 1]
                    if len(refs) == 1:
                        #print "There is only one data offset reference from here, if it is a string we are done."
                        for s in IDAStrings:
                            if s.ea == refs[0].to:
                                return str(s)

        elif mnem == "ADD":

            arg_to = idc.GetOpnd(ea, 0)
            arg_from = idc.GetOpnd(ea, 1)

            if ARCH == "ARM32":

                if arg_from == "PC" and arg_to in arg_in:

                    #now there should be a a DataRef here to a string.
                    if sum(1 for _ in idautils.DataRefsFrom(ea)) == 1:
                        for ref in idautils.DataRefsFrom(ea):
                            #get string at ref
                            for s in IDAStrings:
                                if s.ea == ref:
                                    return str(s)

        ############ END OF TRACING ############

        if ea == block.startEA:

            #For some reason, block.preds() seems to be broken. I get 0 predecessors to every block. So for now, we limit to same block.
            #Also idaapi.decode_preceding_instruction is annoying, because if there are more than 1 preceding, it just shows the first one only.
            #So this is getting around the preds() not working.

            preds = []
            for b in fc:
                for s in b.succs():
                    if s.startEA == block.startEA:
                        #this is a predecessor block to us
                        preds.append(b)

            if len(preds) == 1:
                #print "1 predecessor, continuing there"
                block = preds[0]
                i = idautils.DecodePreviousInstruction(block.endEA)
                ea = block.endEA - i.size

            else:
                #print "0 or multiple predecessor blocks, givin up."
                return ""

        else:
            i = idautils.DecodePreviousInstruction(ea)
            ea -= i.size

    return ""