Beispiel #1
0
 def activate(self, ctx):
     cur_ea = ida_kernwin.get_screen_ea()
     pfn = ida_funcs.get_func(cur_ea)
     if pfn:
         v = ida_kernwin.get_current_viewer()
         result = ida_kernwin.get_highlight(v)
         if result:
             stkvar_name, _ = result
             frame = ida_frame.get_frame(cur_ea)
             sptr = ida_struct.get_struc(frame.id)
             mptr = ida_struct.get_member_by_name(sptr, stkvar_name)
             if mptr:
                 fii = ida_funcs.func_item_iterator_t()
                 ok = fii.set(pfn)
                 while ok:
                     ea = fii.current()
                     F = ida_bytes.get_flags(ea)
                     for n in range(ida_ida.UA_MAXOP):
                         if not ida_bytes.is_stkvar(F, n):
                             continue
                         insn = ida_ua.insn_t()
                         if not ida_ua.decode_insn(insn, ea):
                             continue
                         v = ida_frame.calc_stkvar_struc_offset(
                             pfn, insn, n)
                         if v >= mptr.soff and v < mptr.eoff:
                             print("Found xref at 0x%08x, operand #%d" %
                                   (ea, n))
                     ok = fii.next_code()
             else:
                 print("No stack variable named \"%s\"" % stkvar_name)
     else:
         print("Please position the cursor within a function")
def get_local_var_value_64(loc_var_name):
    frame = ida_frame.get_frame(idc.here())
    loc_var = ida_struct.get_member_by_name(frame, loc_var_name)
    loc_var_start = loc_var.soff
    loc_var_ea = loc_var_start + idc.get_reg_value("RSP")
    loc_var_value = idc.read_dbg_qword(loc_var_ea)  # in case the variable is 32bit, just use get_wide_dword() instead
    return loc_var_value
Beispiel #3
0
    def _get_frame(self):
        result = False
        sp = get_sp_val()
        ip = get_ip_val()

        if ip and sp:
            f = get_func(ip)
            if f:
                frame = get_frame(f)
                if frame:
                    self.framesize = get_struc_size(frame)
                    n = frame.memqty
                    frame_offs = f.frregs + f.frsize
                    self.ea = sp - get_spd(f, ip) - frame_offs
                    for i in xrange(n):
                        m = frame.get_member(i)
                        if m:
                            lvar_name = get_member_name(m.id)
                            lvar_ea = self.ea + m.soff
                            lvar_size = m.eoff - m.soff
                            self.members[lvar_ea] = (lvar_name, m.soff, lvar_size, frame_offs)
                    result = True
        return result
    def _record_func_args(self):
        """
        Reset stack pointer reference and
        record function argument variables if we are executing the beginning of a function.
        """
        func_obj = ida_funcs.get_func(self.ip)
        if not func_obj or func_obj.start_ea != self.ip:
            return

        # Reset the sp_start
        self._cpu_context._sp_start = self._cpu_context.sp

        # Add the passed in arguments to the variables map.
        # (This also helps to standardize the argument names to "a*" instead of "arg_*")
        for arg in self._cpu_context.passed_in_args:
            addr = arg.addr
            # TODO: Support variables from registers?
            if addr is not None:
                if arg.is_stack:
                    try:
                        frame = ida_frame.get_frame(func_obj)
                        if not frame:
                            logger.warning(f"Failed to get frame for function argument: {repr(arg)}")
                            continue

                        # Getting member stack offset from name is more reliable then calculating
                        # it from the address.
                        member = ida_struct.get_member_by_name(frame, arg.name)
                        if not member:
                            logger.warning(f"Failed to get member for function argument: {repr(arg)}")
                            continue

                        self._cpu_context.variables.add(addr, frame_id=frame.id, stack_offset=member.soff)
                    except ValueError:
                        logger.warning(f"Failed to get stack information for function argument: {repr(arg)}")
                else:
                    self._cpu_context.variables.add(addr)
Beispiel #5
0
    def execute(self, start=None, end=None, max_instructions=10000):
        """
        "Execute" the instruction at IP and store results in the context.
        The RIP/EIP register will be set to the value supplied in IP so that it is
        correct.

        :param start: instruction address to start execution (defaults to currently set ip)
        :param end: instruction to stop execution (not including)
            (defaults to only run start)
        :param max_instructions: Maximum number of instructions to execute before
            raising an RuntimeError

        :raises RuntimeError: If maximum number of instructions get hit.
        """
        if not start:
            start = self.ip

        # Set instruction pointer to where we are currently executing.
        self.ip = start

        # Extra processing if we are at the start of a function.
        func_obj = ida_funcs.get_func(self.ip)
        if func_obj.start_ea == self.ip:
            # Reset the sp_start
            self._sp_start = self.sp

            # Add the passed in arguments to the variables map.
            # (This also helps to standardize the argument names to "a*" instead of "arg_*")
            for arg in self.passed_in_args:
                addr = arg.addr
                # TODO: Support variables from registers?
                if addr is not None:
                    if arg.is_stack:
                        try:
                            frame = ida_frame.get_frame(func_obj)
                            if not frame:
                                logger.warning(
                                    f"Failed to get frame for function argument: {repr(arg)}"
                                )
                                continue

                            # Getting member stack offset from name is more reliable then calculating
                            # it from the address.
                            member = ida_struct.get_member_by_name(
                                frame, arg.name)
                            if not member:
                                logger.warning(
                                    f"Failed to get member for function argument: {repr(arg)}"
                                )
                                continue

                            self.variables.add(addr,
                                               frame_id=frame.id,
                                               stack_offset=member.soff)
                        except ValueError:
                            logger.warning(
                                f"Failed to get stack information for function argument: {repr(arg)}"
                            )
                    else:
                        self.variables.add(addr)

        # If end is provided, recursively run execute() until ip is end.
        if end is not None:
            count = max_instructions
            prev_ecx = self.registers.ecx
            prev_ecx_count = count
            while self.ip != end:
                if ida_ua.print_insn_mnem(self.ip) == 'retn':
                    return
                self.execute()
                # TODO: Re-enable this feature after rigorous testing.
                # # Dynamically allow more instructions to be executed if we detect we are in a loop
                # # and it is making progress.
                # # Ie. this will allow most while statements not to ding our max instruction quota.
                # if self.registers.ecx and (self.registers.ecx < prev_ecx or prev_ecx == 0):
                #     if prev_ecx:
                #         count += min(prev_ecx_count - count, 1000)
                #     prev_ecx = self.registers.ecx
                #     prev_ecx_count = count
                count -= 1
                if not count:
                    raise RuntimeError('Hit maximum number of instructions.')
            return

        # Determine if a rep* instruction and add termination condition.
        term_condition = None
        if idc.get_wide_byte(start) in (0xF2, 0xF3):
            insn = idc.GetDisasm(
                start)  # IDA pro never has operands for rep opcodes.
            if insn.startswith("rep "):
                term_condition = lambda: self.registers.ecx == 0
                term_condition.unconditional = True
            elif insn.startswith(("repe ", "repz ")):
                term_condition = lambda: self.registers.ecx == 0 or self.registers.zf == 0
                term_condition.unconditional = False
            elif insn.startswith(("repne ", "repnz ")):
                term_condition = lambda: self.registers.ecx == 0 or self.registers.zf == 1
                term_condition.unconditional = False

        # Emulate instruction.
        mnem = ida_ua.print_insn_mnem(start)

        # Log a header line for debug messages of this instruction.
        # This is simpler and faster then trying to include the information at each log line
        logger.debug("[0x%X %03X] :: %s", start, self.sp_diff, mnem)

        # Run any pre-hooks first.
        self.execute_instruction_hooks(start, mnem, pre=True)

        instruction = self.OPCODES.get(mnem)
        if instruction:
            operands = self.operands

            try:
                if term_condition:
                    if self.emulator.disabled_rep:
                        logger.debug("Ignoring rep instructions: DISABLED.")

                    # As a safety measure, don't allow rep instructions to surpass
                    # our max memory read limit.
                    # Only do this check if the terminating condition is unconditional, otherwise
                    # this number usually big because it expects zf to be toggled.
                    elif term_condition.unconditional and self.registers.ecx > self.memory.MAX_MEM_READ:
                        logger.warning(
                            "Emulation attempted to read %s instruction %d times. "
                            "Ignoring instruction.", mnem, self.registers.ecx)
                    else:
                        logger.debug("Emulating %s instruction %d times.",
                                     mnem, self.registers.ecx)
                        count = 0
                        while not term_condition():
                            instruction(self, start, mnem, operands)
                            self.registers.ecx -= 1
                            # Stop if we are iterating too much.
                            count += 1
                            if count > self.memory.MAX_MEM_READ:
                                logger.warning(
                                    "Looped too many times, exiting prematurely."
                                )
                                break
                else:
                    instruction(self, start, mnem, operands)
            except Exception:
                logger.exception("Failed to execute address 0x%X: %s", start,
                                 idc.GetDisasm(start))
        else:
            logger.debug("%s instruction not implemented.", mnem)

        # Record executed instruction.
        self.executed_instructions.append(start)

        # Run any post-hooks
        self.execute_instruction_hooks(start, mnem, pre=False)

        # Add a blank space to help visually separate logs for each instruction.
        logger.debug(" ")

        # After execution, set instruction pointer to next instruction assuming
        # standard code flow and if no jump was made.
        if self.ip == start:
            self.ip = idc.next_head(start)
Beispiel #6
0
        )
    return members, base


# func_frames maps from function address to a record of the function's stack
# frame size and local variables.
func_frames = {}
func_addrs = []
for seg in idautils.Segments():
    # Skip extern segment; as used by IDA for external functions.
    if idc.get_segm_attr(seg, SEGATTR_TYPE) == idc.SEG_XTRN:
        #print("skipping segment ", idc.get_segm_name(seg))
        continue
    for fn in idautils.Functions(seg, idc.get_segm_end(seg)):
        func_addr = fn
        frame = ida_frame.get_frame(func_addr)
        frame_size = ida_frame.get_frame_size(func_addr)
        var_names = []
        for i in range(frame_size):
            var_name = idc.GetMemberName(frame, i)
            # TODO: check if ' r' and ' s' (return address and saved registers) may have
            # duplicates.
            if var_name is None:
                continue
            var_names.append(var_name)
        print(var_names)
        func_frame = {"func_name": func_name, "func_type": func_type}
        func_frames[func_addr] = func_frame
        func_addrs.append(func_addr)

# TODO: check diff between ESP at function entry and each instruction.
Beispiel #7
0
def update_form(update):
    """ Processes an incoming update by adding it to the form.

    Args:
        update (IdbUpdate) - The message received from the ZMQ server, as a class that inherits IdbUpdate
    """
    try:
        g_item_list_mutex.lock()
        message_type = update.update_type
        address = update.address
        current_data = None

        if message_type == idb_push_ops.UpdateTypes.Name:
            current_data = psida_common.get_non_default_name(address, update.is_local)
            if current_data == update.data:
                return

        elif message_type == idb_push_ops.UpdateTypes.Comment:
            current_data = psida_common.get_comment(address)
            if current_data == update.data:
                return

        elif message_type == idb_push_ops.UpdateTypes.RepeatableComment:
            current_data = psida_common.get_repeated_comment(address)
            if current_data == update.data:
                return

        elif message_type in [idb_push_ops.UpdateTypes.AnteriorLine, idb_push_ops.UpdateTypes.PosteriorLine]:
            current_data = idc.get_extra_cmt(address, update.line_index)
            if current_data == update.data:
                return

        elif message_type == idb_push_ops.UpdateTypes.LookHere:
            current_data = psida_common.get_non_default_name(address)

        elif message_type == idb_push_ops.UpdateTypes.StackVariableRenamed:
            func_frame = ida_frame.get_frame(address)
            update.func_frame_pointer = func_frame
            member = ida_struct.get_member(func_frame, update.offset)
            current_data = None
            if member is not None:
                current_data = ida_struct.get_member_name(member.id)

            if current_data == update.data:
                return

            if current_data is not None:
                update.new = False
            else:
                update.new = True

        elif message_type in [idb_push_ops.UpdateTypes.MakeData, idb_push_ops.UpdateTypes.MakeCode,
                              idb_push_ops.UpdateTypes.MakeFunc]:
            current_data = update.get_conflict()
            if current_data == '':
                return

        else:
            if CONFIGURATION[DEBUG]:
                print 'DEBUG - UI - Unrecognized/Unimplemented type %d: in message %s' % (message_type, update.to_dict())
            return

        update.data_at_address = current_data
        add_item(update)
    except:
        if CONFIGURATION['debug']:
            traceback.print_exc()
        print 'ERROR - UI - General error while updating form'

    finally:
        g_item_list_mutex.unlock()