Exemplo n.º 1
0
def get_op(ea, op, stkvars=None):
    '''ea_t -> int -> opt:{int : tinfo_t} -> op_ret'''
    cmd = idautils.DecodeInstruction(ea)
    cmd.Operands = get_operands(cmd)  # for mips_op_hack
    op = mips_op_hack(cmd, op)
    opd = cmd[op]

    if opd.type == idaapi.o_reg:  # gpr, XXX sorta MIPS-specific
        return op_ret(op_ty.reg, regs.gpr(opd.reg), 0)
    elif opd.type == idaapi.o_idpspec1:  # fpr, XXX sorta MIPS-specific
        return op_ret(op_ty.reg, regs.fpr(opd.reg), 0)
    elif opd.type in [idaapi.o_near, idaapi.o_mem]:
        return op_ret(op_ty.name, idc.Name(opd.addr), 0)
    elif idc.isStkvar1(idc.GetFlags(ea)):
        # IDA seems to set this flag even for operands beyond the second,
        # i.e. both of these are true for isStkvar1:
        # .text:10003A84                 sd      $a1, 0x2E0+var_58($sp)
        # .text:10003A68                 addiu   $a1, $sp, 0x2E0+var_2D8
        try:
            func = idaapi.get_func(ea)
            off = idaapi.calc_stkvar_struc_offset(func, ea, op)
            (name, ti) = stkvars[off]

            return op_ret_for_ti(ti, name, off, off)
        except KeyError:
            raise OperandUnresolvableError('unable to get operand %u at %s' % (op, idc.atoa(ea)))
    elif opd.type in [idaapi.o_imm, idaapi.o_displ]:
        return cpu_ida.ida_current_cpu().data.get_op_addrmode(ea, op, cmd)
    else:
        raise OperandUnresolvableError('unable to get operand %u at %s' % (op, idc.atoa(ea)))
Exemplo n.º 2
0
def get_op(ea, op, stkvars=None):
    '''ea_t -> int -> opt:{int : tinfo_t} -> op_ret'''
    cmd = idautils.DecodeInstruction(ea)
    cmd.Operands = get_operands(cmd)  # for mips_op_hack
    op = mips_op_hack(cmd, op)
    opd = cmd[op]

    if opd.type == idaapi.o_reg:  # gpr, XXX sorta MIPS-specific
        return op_ret(op_ty.reg, regs.gpr(opd.reg), 0)
    elif opd.type == idaapi.o_idpspec1:  # fpr, XXX sorta MIPS-specific
        return op_ret(op_ty.reg, regs.fpr(opd.reg), 0)
    elif opd.type in [idaapi.o_near, idaapi.o_mem]:
        return op_ret(op_ty.name, idc.Name(opd.addr), 0)
    elif idc.isStkvar1(idc.GetFlags(ea)):
        # IDA seems to set this flag even for operands beyond the second,
        # i.e. both of these are true for isStkvar1:
        # .text:10003A84                 sd      $a1, 0x2E0+var_58($sp)
        # .text:10003A68                 addiu   $a1, $sp, 0x2E0+var_2D8
        try:
            func = idaapi.get_func(ea)
            off = idaapi.calc_stkvar_struc_offset(func, ea, op)
            (name, ti) = stkvars[off]

            return op_ret_for_ti(ti, name, off, off)
        except KeyError:
            raise OperandUnresolvableError('unable to get operand %u at %s' %
                                           (op, idc.atoa(ea)))
    elif opd.type in [idaapi.o_imm, idaapi.o_displ]:
        return cpu_ida.ida_current_cpu().data.get_op_addrmode(ea, op, cmd)
    else:
        raise OperandUnresolvableError('unable to get operand %u at %s' %
                                       (op, idc.atoa(ea)))
Exemplo n.º 3
0
def type_to_reg_and_slot(node, chooser, i):
    '''c_ast -> fn -> int -> (reg_type, slot_type) | None'''

    def yield_void():
        # return an empty list for (void) arglists
        raise StopIteration

    def maybe_fail(node):
        if type(node) is c_ast.Struct:
            raise StructByValueError('structs by value not yet supported')
        return type_to_reg_and_slot(node.type, chooser, i)

    def get(names):
        '''[str] -> (gpr|fpr, slot_ty)'''
        if 'void' in names:
            return yield_void()

        ti = ida.parse_decl(' '.join(names))
        (ty, base, slot) = chooser(ti)
        return (ty(base + i), slot)

    sw = {
        c_ast.Decl: lambda x: type_to_reg_and_slot(x.type, chooser, i),
        c_ast.TypeDecl: lambda x: type_to_reg_and_slot(x.type, chooser, i),
        c_ast.Typename: lambda x: type_to_reg_and_slot(x.type, chooser, i),
        c_ast.IdentifierType: lambda x: get(x.names)
    }

    if i > 7:
        raise RegSpillError('spilling registers to stack not yet supported')

    # in order to use chooser we need a tinfo_t--make one suitable for an
    # an int (which is also suitable for a pointer on N32)
    dummy_ti = ida.parse_decl('int')

    (_, base, _) = chooser(dummy_ti)
    node_ty = type(node)

    if node_ty in [c_ast.ArrayDecl, c_ast.PtrDecl]:
        return (regs.gpr(base + i), ep_ct.slot_types.u64)
    elif node_ty is c_ast.Enum:
        return (regs.gpr(base + i), ep_ct.slot_types.i64)
    else:
        return utils.dictswitch(node_ty, sw, node, maybe_fail, node)
Exemplo n.º 4
0
def type_to_reg_and_slot(node, chooser, i):
    '''c_ast -> fn -> int -> (reg_type, slot_type) | None'''
    def yield_void():
        # return an empty list for (void) arglists
        raise StopIteration

    def maybe_fail(node):
        if type(node) is c_ast.Struct:
            raise StructByValueError('structs by value not yet supported')
        return type_to_reg_and_slot(node.type, chooser, i)

    def get(names):
        '''[str] -> (gpr|fpr, slot_ty)'''
        if 'void' in names:
            return yield_void()

        ti = ida.parse_decl(' '.join(names))
        (ty, base, slot) = chooser(ti)
        return (ty(base + i), slot)

    sw = {
        c_ast.Decl : lambda x: type_to_reg_and_slot(x.type, chooser, i),
        c_ast.TypeDecl : lambda x: type_to_reg_and_slot(x.type, chooser, i),
        c_ast.Typename : lambda x: type_to_reg_and_slot(x.type, chooser, i),
        c_ast.IdentifierType : lambda x: get(x.names)
    }

    if i > 7:
        raise RegSpillError('spilling registers to stack not yet supported')

    # in order to use chooser we need a tinfo_t--make one suitable for an
    # an int (which is also suitable for a pointer on N32)
    dummy_ti = ida.parse_decl('int')

    (_, base, _) = chooser(dummy_ti)
    node_ty = type(node)

    if node_ty in [c_ast.ArrayDecl, c_ast.PtrDecl]:
        return (regs.gpr(base + i), ep_ct.slot_types.u64)
    elif node_ty is c_ast.Enum:
        return (regs.gpr(base + i), ep_ct.slot_types.i64)
    else:
        return utils.dictswitch(node_ty, sw, node, maybe_fail, node)
Exemplo n.º 5
0
def get_arg_for_va_function(callee, start_ea):
    '''str -> ea_t -> str'''
    # XXX hacky; not a very general function
    # XXX imperative
    # get a relevant item needed for processing a variadic function
    sw = {
        'printf' : regs.gpr(abi.arg_regs[0]),
        'scanf' : regs.gpr(abi.arg_regs[0]),
        'sscanf' : regs.gpr(abi.arg_regs[1])
    }
    try:
        wanted_reg = sw[callee]
    except KeyError:
        raise utils.BugError('unrecognized callee %s' % callee)

    distance = 0
    fn = ida.get_func(start_ea)
    # first, look at the delay slot
    ea = ida.next_head(start_ea, fn.endEA)

    while True:
        if distance > 10:
            raise VarargsError(
                'gave up looking for needed varargs argument for %s between ' +
                '%s..%s' % (ida.atoa(ea), ida.atoa(start_ea)))

        if ea == start_ea:
            ea = ida.prev_head(ea)
            continue # skip the call insn
        elif list(ida.code_refs_from(ea, 0)) != []:
            raise VarargsError(
                'encountered branch/jump while looking for varargs argument ' +
                'between %s..%s' % (ida.atoa(ea), ida.atoa(start_ea)))

        rd = ida.get_op(ea, 0)
        if rd.val == wanted_reg:
            opvals = ida.get_opvals(ea) # XXX should try to track stkvar values
            s = ida.get_string(opvals[-1].target)
            if s is not None:
                return s

        ea = ida.prev_head(ea)
        distance += 1
Exemplo n.º 6
0
def get_arg_for_va_function(callee, start_ea):
    """str -> ea_t -> str"""
    # XXX hacky; not a very general function
    # XXX imperative
    # get a relevant item needed for processing a variadic function
    sw = {"printf": regs.gpr(abi.arg_regs[0]), "scanf": regs.gpr(abi.arg_regs[0]), "sscanf": regs.gpr(abi.arg_regs[1])}
    try:
        wanted_reg = sw[callee]
    except KeyError:
        raise utils.BugError("unrecognized callee %s" % callee)

    distance = 0
    fn = ida.get_func(start_ea)
    # first, look at the delay slot
    ea = ida.next_head(start_ea, fn.endEA)

    while True:
        if distance > 10:
            raise VarargsError(
                "gave up looking for needed varargs argument for %s between "
                + "%s..%s" % (ida.atoa(ea), ida.atoa(start_ea))
            )

        if ea == start_ea:
            ea = ida.prev_head(ea)
            continue  # skip the call insn
        elif list(ida.code_refs_from(ea, 0)) != []:
            raise VarargsError(
                "encountered branch/jump while looking for varargs argument "
                + "between %s..%s" % (ida.atoa(ea), ida.atoa(start_ea))
            )

        rd = ida.get_op(ea, 0)
        if rd.val == wanted_reg:
            opvals = ida.get_opvals(ea)  # XXX should try to track stkvar values
            s = ida.get_string(opvals[-1].target)
            if s is not None:
                return s

        ea = ida.prev_head(ea)
        distance += 1
Exemplo n.º 7
0
def get_op_addrmode(ea, op, cmd):
    '''ea_t -> int -> insn_t -> op_ret'''
    # the ida module calls back into this module to deal with some MIPS-specific
    # operand handling here
    mnem = ida.get_mnem(ea)
    op = ida.mips_op_hack(cmd, op)

    if cmd[op].type == ida.o_imm:
        val = cmd[op].value
    elif cmd[op].type == ida.o_displ:
        val = cmd[op].addr
    else:
        raise utils.BugError('neither imm nor displ passed to get_op_addrmode')

    if mnem in insns.has_special_opnd:
        target = val
        return ida.resolve_opnd(target, val)
    # addiu is often used for address calculation, which IDA will resolve to a
    # name, so handle addiu's immval only if we fail to resolve it later
    elif mnem != 'addiu' and mnem in insns.has_imm:
        return ida.op_ret(ida.op_ty.value, immval(val), 0)
    else:
        target = ida.calc_target(ea, ea, op, immval(val))
        if target == ida.BADADDR and cmd[op].type == ida.o_displ:
            reg = cmd[op].reg
            if reg >= 0 and reg <= 31:
                reg = regs.gpr(reg)
            elif reg >= 32 and reg <= 63:
                reg = regs.fpr(reg)
            else:
                raise utils.BugError('bogus register %u' % reg)
            return ida.op_ret(ida.op_ty.displ,
                              ida.displ(reg=reg,
                                        displ=immval(val)),
                              0)
        else:
            opnd = ida.resolve_opnd(target, val)
            if mnem == 'addiu' and opnd.ty == ida.op_ty.value:
                # addiu is being used for regular addition; handle its third
                # operand as an immediate value
                return ida.op_ret(ida.op_ty.value, immval(opnd.val), 0)
            else:
                return opnd
Exemplo n.º 8
0
def fmt_reg(mnem, arg, slot=None):
    '''str -> int -> reg -> opt:slot_types -> str'''
    if arg == regs.gpr(0):
        return c_ast.Constant('int', '0')
    else:
        insn = insns.insns[mnem]
        stripped = reg_strip(arg)
        # XXX FIXME: we store the register gpr/fpr register number, but
        # regs_by_reference is offsets into IDA's register list
        regnum = arg.reg + (abi.fpr_off if type(arg) is regs.fpr else 0)
        if regnum in abi.regs_by_reference:
            # refer to argument via ARGS->
            r = c_ast.StructRef(c_ast.ID(utils.args_tag), '->', c_ast.ID(stripped))
        else:
            r = c_ast.ID(stripped)

        if slot is not None and slot != ep_ct.slot_types._:
            # use a union slot
            return c_ast.StructRef(r, '.', c_ast.ID(slot.name))
        else:
            return r
Exemplo n.º 9
0
def get_op_addrmode(ea, op, cmd):
    """ea_t -> int -> insn_t -> op_ret"""
    # the ida module calls back into this module to deal with some MIPS-specific
    # operand handling here
    mnem = ida.get_mnem(ea)
    op = ida.mips_op_hack(cmd, op)

    if cmd[op].type == ida.o_imm:
        val = cmd[op].value
    elif cmd[op].type == ida.o_displ:
        val = cmd[op].addr
    else:
        raise utils.BugError("neither imm nor displ passed to get_op_addrmode")

    if mnem in insns.has_special_opnd:
        target = val
        return ida.resolve_opnd(target, val)
    # addiu is often used for address calculation, which IDA will resolve to a
    # name, so handle addiu's immval only if we fail to resolve it later
    elif mnem != "addiu" and mnem in insns.has_imm:
        return ida.op_ret(ida.op_ty.value, immval(val), 0)
    else:
        target = ida.calc_target(ea, ea, op, immval(val))
        if target == ida.BADADDR and cmd[op].type == ida.o_displ:
            reg = cmd[op].reg
            if reg >= 0 and reg <= 31:
                reg = regs.gpr(reg)
            elif reg >= 32 and reg <= 63:
                reg = regs.fpr(reg)
            else:
                raise utils.BugError("bogus register %u" % reg)
            return ida.op_ret(ida.op_ty.displ, ida.displ(reg=reg, displ=immval(val)), 0)
        else:
            opnd = ida.resolve_opnd(target, val)
            if mnem == "addiu" and opnd.ty == ida.op_ty.value:
                # addiu is being used for regular addition; handle its third
                # operand as an immediate value
                return ida.op_ret(ida.op_ty.value, immval(opnd.val), 0)
            else:
                return opnd