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
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)
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)
) 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.
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()