def paint_function(self, color, new_address): """ Paint function with the given color :param color: the color :param new_address: address within the function where apply the color """ # # paint all instructions within the function with default background # this has to be done because painting function paint all nodes in it # self.paint_function_instructions(new_address) new_func = ida_funcs.get_func(new_address) # get the previous user position user_position = self.users_positions.get(color) if user_position: address = user_position['address'] func = ida_funcs.get_func(address) # paint it only if previous function and new function are different if not new_func or (func and new_func and func == new_func): return if new_func: # add the color to the new function color stack self._painted_functions[new_func.startEA].append(new_func.color) # finaly paint the function self.set_paint_function(new_func, color)
def __process_names(self): names = list() for i in range(0, ida_name.get_nlist_size()): ea = ida_name.get_nlist_ea(i) if ida_funcs.get_func(ea) is not None: continue name = { 'rva': ea - self._base, 'name': ida_name.get_nlist_name(i), 'name_demangled': ida_name.get_demangled_name(ea, 0xFFFF, 0, 0), 'is_public': ida_name.is_public_name(ea), 'is_func': ida_funcs.get_func(ea) is not None } # PE32/PE32+ only support binaries up to 2GB if name['rva'] >= 2**32: print('RVA out of range for name: ' + name['name'], file=sys.stderr) names.append(name) return names
def clear_function(self, name, new_address): """Clear paint from the specified user and function.""" user_position = self._users_positions.get(name) new_func = ida_funcs.get_func(new_address) # If the stack is empty, this is the first time we meet this function, # so we must save the original color to restore it. if new_func and not self._painted_functions[new_func.start_ea]: func_color = self._get_paint_function(new_func) self._painted_functions[new_func.start_ea].append(func_color) if user_position: address = user_position["address"] self.clear_function_instructions(address) func = ida_funcs.get_func(address) # Clear it only if previous func and new func are different if (func and not new_func) or (func and new_func and func != new_func): color = self._painted_functions[func.start_ea].pop() # If the stack is not empty, repaint all the instructions with # the color popped from the stack. if self._painted_functions[func.start_ea]: self.paint_function_instructions(address) self._set_paint_function(func, color)
def clear_function(self, color, new_address): """ Clear paint from the given functions :param color: the color :param new_address: an address within the function where the color needs to be cleared """ user_position = self.users_positions.get(color) new_func = ida_funcs.get_func(new_address) # # if the deqeue is empty, this is the first time we meet this function # we must save the original color to restore it # TODO: broadcast the original color to others users # if new_func and not self._painted_functions[new_func.startEA]: self._painted_functions[new_func.startEA].append(new_func.color) if user_position: address = user_position['address'] self.clear_function_instructions(address) func = ida_funcs.get_func(address) # clear it only if previous func and new func are different if (func and not new_func) or \ (func and new_func and func != new_func): color = self._painted_functions[func.startEA].pop() # if the queue is not empty, repaint all the instructions with # the background color if self._painted_functions[func.startEA]: self.paint_function_instructions(address) self.set_paint_function(func, color)
def main(): is_selected, sel_start, sel_end = ida_kernwin.read_selection() if not is_selected: logger.error('range must be selected') return -1 sel_end = ida_bytes.next_head(sel_end) buf = ida_bytes.get_bytes(sel_start, sel_end - sel_start) if buf is None: logger.error('failed to fetch instruction bytes') return -1 f = ida_funcs.get_func(sel_start) if f != ida_funcs.get_func(sel_end): logger.error('range must be within a single function') return -1 # find mappings from "$localN" to "custom_name" regvars = {} for i in range(0x1000): regvar = ida_frame.find_regvar(f, sel_start, '$local%d' % i) if regvar is None: continue regvars[regvar.canon] = regvar.user if len(regvars) >= f.regvarqty: break globals_ = {} for i, offset in netnode.Netnode('$ wasm.offsets').get('globals', {}).items(): globals_['$global' + i] = ida_name.get_name(offset) frame = {} if f.frame != ida_idaapi.BADADDR: names = set([]) for i in range(ida_struct.get_struc_size(f.frame)): s = ida_struct.get_struc(f.frame) if not s: continue m = ida_struct.get_member(s, i) if not m: continue name = ida_struct.get_member_name(m.id) if name in names: continue frame[i] = name names.add(name) emu = Emulator(buf) emu.run() print( emu.render(ctx={ 'regvars': regvars, 'frame': frame, 'globals': globals_, }))
def ti_changed(self, ea, typeinf, fnames): res = ida_struct.get_member_by_id(ea) if res is not None: m, name, sptr = res if sptr.is_frame(): func = ida_funcs.get_func(ida_frame.get_func_by_frame(sptr.id)) if func is not None: return self.func_updated(func) elif utils.is_func(ea): return self.func_updated(ida_funcs.get_func(ea)) return 0
def find_img4decodeinit(base_ea): ea_list = ida_search.find_imm(base_ea, ida_search.SEARCH_DOWN, 0x494D0000) if ea_list[0] != ida_idaapi.BADADDR: func_ea = ida_funcs.get_func(ea_list[0]).start_ea ea_func_list = list(idautils.XrefsTo(func_ea)) if ea_func_list[0].frm != ida_idaapi.BADADDR: i4d_ea = ida_funcs.get_func(ea_func_list[0].frm).start_ea print "\t[+] _Img4DecodeInit = 0x%x" % (i4d_ea) idc.set_name(i4d_ea, "_Img4DecodeInit", idc.SN_CHECK) return i4d_ea return ida_idaapi.BADADDR
def _hxe_callback(self, event, *args): if not self._installed: return 0 # this event gets triggered each time that a user changes the view to # a different decompilation view. It will also get triggered when staying on the # same view but having it refreshed if event == ida_hexrays.hxe_func_printed: ida_cfunc = args[0] func_addr = ida_cfunc.entry_ea func = ida_funcs.get_func(func_addr) # sanity check if func is None: return 0 # run update tasks needed for this function since we are looking at it if not self.updating_states.locked(): with self.updating_states: self.controller.update_states[func_addr].do_updates() # create a new cache for unseen funcs if func.start_ea not in self._cached_funcs.keys(): self._cached_funcs[func.start_ea] = { "cmts": [], "header": None } # push changes viewable only in decompilation self._push_new_comments(func.start_ea) self._push_new_func_header(ida_cfunc) return 0
def activate(self, ctx): """ :param ctx: idaapi.action_activation_ctx_t :return: None """ ea = get_screen_ea() if get_func(ea) is None: print("address = " + hex(ea)) data = get_bytes(ea, 16) guid = str(UUID(bytes_le=data)) else: name, data = extract_guid(ea) guid = str(UUID(bytes_le=data)) print("Local variable EFI_GUID extraction for " + name) print("data = " + " ".join("%02x" % x for x in bytes(data))) print("guid = " + guid) try: import clipboard clipboard.copy(guid) except ImportError: print("clipboard module is not available.")
def propagate_function_type(ea: int, func_type: FUNCTION_TYPE): print(f"propagate func {hex(ea)}, type {func_type}") if visited.get(ea) is not None: return if func_type == FUNCTION_TYPE.NULLSUB: ida_name.set_name(ea, f"nullsub_{hex(ea)[2:]}") elif func_type == FUNCTION_TYPE.IDENTITY: ida_name.set_name(ea, f"identity_{hex(ea)[2:]}") elif func_type == FUNCTION_TYPE.GETVALUE: ida_name.set_name(ea, f"getvalue_{hex(ea)[2:]}") visited[ea] = True cref = ida_xref.get_first_cref_to(ea) while cref != idaapi.BADADDR: cref_func = ida_funcs.get_func(cref) #function is not defined or function has been visited if cref_func is None or visited.get(cref_func.start_ea) is not None: cref = ida_xref.get_next_cref_to(ea, cref) continue cref_func_type = infer_function_type(cref_func.start_ea, func_type) if cref_func_type == FUNCTION_TYPE.OTHER: cref = ida_xref.get_next_cref_to(ea, cref) visited[cref_func.start_ea] = True continue propagate_function_type(cref_func.start_ea, cref_func_type) cref = ida_xref.get_next_cref_to(ea, cref)
def _erase_reg_in_range(s_ea, e_ea, reg): pfn = ida_funcs.get_func(s_ea) ea = s_ea prev_ranges = [] #if there was a rename range with this reg containing the start of the range (s_ea) - remember it prev_range_s = ida_frame.find_regvar(pfn, s_ea, reg) if (prev_range_s is not None) and (prev_range_s.start_ea < s_ea): prev_ranges += [(prev_range_s.start_ea, s_ea, prev_range_s.user)] #if there was a rename range with this reg containing the end of the range (e_ea) - remember it prev_range_s = ida_frame.find_regvar(pfn, e_ea, reg) if (prev_range_s is not None) and (prev_range_s.start_ea < e_ea) and (prev_range_s.end_ea > e_ea): prev_ranges += [(e_ea, prev_range_s.end_ea, prev_range_s.user)] debug('Delete range %x : %x - %s' % (s_ea, e_ea, reg)) #deletion seems to require actual existing range - so we'll change the name to orig, and then delete it idc.MakeLocal(s_ea, e_ea, reg, reg) idc.Refresh() ida_frame.del_regvar(pfn, s_ea, e_ea, reg) idc.Refresh() #restore ranges for s_ea, e_ea, reg_new_name in prev_ranges: debug('Restore range %x : %x - %s->%s' % (s_ea, e_ea, reg, reg_new_name)) idc.MakeLocal(s_ea, e_ea, reg, reg_new_name) idc.Refresh()
def find_load_kernelcache_object(base, ea): if ea != ida_idaapi.BADADDR: ea_list = list(idautils.XrefsTo(ea)) if ea_list[0].frm != ida_idaapi.BADADDR: func_ea = ida_funcs.get_func(ea_list[0].frm).start_ea print("\t[+] _load_kernelcache_object = 0x%x" % (func_ea)) idc.set_name(func_ea, "_load_kernelcache_object", idc.SN_CHECK) return func_ea print("\t[-] _load_kernelcache_object = not found") return ida_idaapi.BADADDR else: str_ea = ida_search.find_text(base, 1, 1, "Kernelcache too large", ida_search.SEARCH_DOWN) if str_ea != ida_idaapi.BADADDR: for xref in idautils.XrefsTo(str_ea): func = idaapi.get_func(xref.frm) print("\t[+] _load_kernelcache_object = 0x%x" % (func.start_ea)) idc.set_name(func.start_ea, "_load_kernelcache_object", idc.SN_CHECK) return func.start_ea print("\t[-] _load_kernelcache_object = not found") return ida_idaapi.BADADDR
def function(addr): ida_func = ida_funcs.get_func(addr) if ida_func is None: l.warning(f"IDA function does not exist for {hex(addr)}.") return None func_addr = ida_func.start_ea try: ida_cfunc = idaapi.decompile(func_addr) except Exception: ida_cfunc = None if not ida_cfunc: l.warning(f"IDA function {hex(func_addr)} is not decompilable") return Function(func_addr, get_func_size(func_addr), last_change=int(time())) func = Function(func_addr, get_func_size(func_addr), last_change=int(time())) func_header: FunctionHeader = function_header(ida_cfunc) stack_vars = { offset: var for offset, var in get_func_stack_var_info(ida_func.start_ea).items() } func.header = func_header func.stack_vars = stack_vars return func
def find_target_early_init(base_ea): ea_list = ida_search.find_imm(base_ea, ida_search.SEARCH_DOWN, 0x4A41) if ea_list[0] != ida_idaapi.BADADDR: func_ea = ida_funcs.get_func(ea_list[0]).start_ea print("\t[+] _target_early_init = 0x%x" % (func_ea)) idc.set_name(func_ea, "_target_early_init", idc.SN_CHECK) tei_ea = func_ea str_ea = ida_search.find_text(tei_ea, 1, 1, "All pre", ida_search.SEARCH_DOWN) if str_ea != ida_idaapi.BADADDR: f_ea = idaapi.get_func(str_ea).start_ea if tei_ea != f_ea: print("\t[-] _platform_not_supported = not found") return tei_ea bl_ea = str_ea + 8 dst = idc.print_operand(bl_ea, 0) pns_ea = idc.get_name_ea_simple(dst) print("\t[+] _platform_not_supported = 0x%x" % (pns_ea)) idc.set_name(pns_ea, "_platform_not_supported", idc.SN_CHECK) return tei_ea print("\t[-] _target_early_init = not found") return ida_idaapi.BADADDR
def set_repeated_comment(address, repeated_comment): assert type(repeated_comment) == str if is_function_start(address): pfn = ida_funcs.get_func(address) ida_funcs.set_func_cmt(pfn, repeated_comment, 1) else: ida_bytes.set_cmt(address, repeated_comment, 1)
def change_user_color(self, name, old_color, new_color): """Notifies the painter that an user has changed color.""" # Replace the color for the given user self._users_positions[name]["color"] = new_color # Replace the color in painted instructions for the given user user_address = self._users_positions[name]["address"] for n, e in enumerate(self._painted_instructions[user_address]): if e == old_color: self._painted_instructions[user_address][n] = new_color # If the color is the current color instruction (not in the stack yet), # repaint the given instruction with the new color if new_color not in self._painted_instructions[user_address]: self._set_paint_instruction(user_address, new_color) # Replace the color in painted functions for the given user func = ida_funcs.get_func(user_address) if func: for n, e in enumerate(self._painted_functions[func.start_ea]): if e == old_color: self._painted_functions[func.start_ea][n] = new_color # If the color is the current color function (not in the stack # yet, repaint the given function with the new color if new_color not in self._painted_functions[user_address]: self._set_paint_function(func, new_color)
def init_contexts(): logger.debug("Iterating contexts for call level: %d", depth) if not depth: yield init_context return func = utils.Function(ea) yielded = False for call_ea in func.calls_to: if call_ea in func: logger.warning( "Ignoring recursive function call at 0x%08X", call_ea) continue if not ida_funcs.get_func(call_ea): logger.warning( "Ignoring call at 0x%08X. Not in a function", call_ea) continue for context in self.iter_context_at(call_ea, depth=depth - 1, exhaustive=exhaustive, follow_loops=follow_loops, init_context=init_context, _first_call=False): if issubclass(self._context_class, x86_64ProcessorContext): # increase the sp to account for the return address that gets pushed # onto the stack so that we are aligned correctly. context.sp -= context.byteness # yield a context containing the caller executed first. yield context yielded = True # If we didn't yield, then we hit a function that has no callers or valid contexts. if not yielded: yield init_context
def __init__(self, callsite, call): self.callsite = callsite self.func_name = call self.ctx = ida_funcs.get_func(self.callsite).startEA self.target = None self.ret = None # this is a NSObject self.success = False
def is_func_ptr(offset: int) -> bool: """Returns true if the given offset is a function pointer.""" # As a first check, simply see if the offset is the start of a function. func = ida_funcs.get_func(offset) if func and func.start_ea == offset: return True # Sometimes we will get a really strange issue where the IDA disassember has set a type for an # address that should not have been set during our course of emulation. # Therefore, before attempting to use get_function_data() to test if it's a function pointer, # first see if guess_type() will return None while is_loaded() is true. # If it doesn't, we know that it shouldn't be a function pointer. # (plus it saves on time) # TODO: Determine if we could have false negatives. # - this caused a false negatives, so I added the check if offset is the start of a function. try: if idc.is_loaded(offset) and not idc.guess_type(offset): return False except TypeError: return False try: get_function_data(offset) return True except RuntimeError: return False except Exception as e: # If we get any other type of exception raise a more friendly error message. raise FunctionTracingError( "Failed to retrieve function data from {!r}: {}".format(offset, e))
def __get_xref_sigs(self, addr: int, is_func: bool) -> Iterator[str]: """ Create a signature from a function address XRef sigs are preferred, however if none are available the func itself will be used :param addr: Function address :param is_func: Indicates that this address is a func, and can be signatured directly :return: A series of Dalamud compatible signatures """ xref_addrs = [xref.frm for xref in idautils.XrefsTo(addr)] if is_func and not ida_funcs.get_func(addr): Log.warn( f'Address at {addr:X} is identified as a func, but is not in IDA, attempting to make a subroutine' ) ida_funcs.add_func(addr) # This should prune xrefs in places like .pdata by only keeping xrefs in a function xref_addrs = list(filter(ida_funcs.get_func_name, xref_addrs)) # Grab the first N xrefs xref_addrs = xref_addrs[:self.XREFS_TO_SEARCH] if is_func: # Try to sig the func itself as well xref_addrs.insert(0, addr) for xref_addr in xref_addrs: yield from SigGen(xref_addr)
def render_img(self, buffers, addr, mouse_offs): colors = [] head = ida_idaapi.BADADDR tail = ida_idaapi.BADADDR goffs = 0 for mapped, buf in buffers: if mapped: if mouse_offs is not None: if self.switch == 0: # data head = get_item_head(addr + mouse_offs) tail = get_item_end(addr + mouse_offs) else: # code f = get_func(addr + mouse_offs) if f: head = f.startEA tail = f.endEA for pos in xrange(len(buf)): c = ord(buf[pos]) & 0xFF highlight = False if mouse_offs is not None: if addr + pos + goffs >= head and addr + pos + goffs < tail: highlight = True if highlight: colors.append((True, qRgb(c, 0xFF, self.hl_color))) else: colors.append((True, qRgb(c, 0, 0))) else: for pos in xrange(len(buf)): colors.append((False, 0)) goffs += len(buf) return colors
def infer_function_type(ea: int, callee_type: FUNCTION_TYPE) -> FUNCTION_TYPE: func = ida_funcs.get_func(ea) if func == None: return FUNCTION_TYPE.OTHER func_size = func.end_ea - func.start_ea # function larger than 0x30 bytes is type other if func_size > 0x30: return FUNCTION_TYPE.OTHER try: code = str(idaapi.decompile(ea)) except: print(f"decompile failed for func {hex(ea)}") return FUNCTION_TYPE.OTHER code_lines = code.split("\n") # function more than five lines is type other if len(code_lines) > 5: return FUNCTION_TYPE.OTHER # nullsub function only have a single ';' if code_lines[2] == " ;": return FUNCTION_TYPE.NULLSUB # if there is only a return subXXX() statement, then it's type depends on its callee if code_lines[2].find("return") > 0 and callee_type != FUNCTION_TYPE.OTHER: return callee_type # if there is only a return a1 statement, then it's type is identity if code_lines[2].find("return a1;") > 0: return FUNCTION_TYPE.IDENTITY # if there is only a return *a1 statement, then it's type is getvalue # todo: dealing with more getvalue type rather than QWORD if code_lines[2].find("return *(_QWORD *)a1;") > 0: return FUNCTION_TYPE.GETVALUE return FUNCTION_TYPE.OTHER
def acquire_pseudocode_vdui(addr): """ Acquires a IDA HexRays vdui pointer, which is a pointer to a pseudocode view that contains the cfunc which describes the code on the screen. Using this function optimizes the switching of code views by using in-place switching if a view is already present. @param addr: @return: """ func = ida_funcs.get_func(addr) if not func: return None names = ["Pseudocode-%c" % chr(ord("A") + i) for i in range(5)] for name in names: widget = ida_kernwin.find_widget(name) if not widget: continue vu = ida_hexrays.get_widget_vdui(widget) break else: vu = ida_hexrays.open_pseudocode(func.start_ea, False) if func.start_ea != vu.cfunc.entry_ea: target_cfunc = idaapi.decompile(func.start_ea) vu.switch_to(target_cfunc, False) return vu
def _read_taint_info(self): semantic_labels = self._read_semantic_labels() input_file = open(self._taint_file, "r") reader = csv.reader(input_file) self._ea_to_labels.clear() self._tainted_funcs.clear() self._skip_csv_header(reader, False) for row in reader: pid = int(row[1]) pc = int(row[2], 16) label = int(row[3]) try: label = semantic_labels[label] except KeyError: pass if pid != self._tainted_process['process_id']: continue fn = ida_funcs.get_func(pc) if not fn: continue fn_start = fn.start_ea self._tainted_funcs.add(fn_start) if pc not in self._ea_to_labels: self._ea_to_labels[pc] = set() self._ea_to_labels[pc].add(label) input_file.close()
def main(): # Get current ea ea = ida_kernwin.get_screen_ea() # Get segment class seg = ida_segment.getseg(ea) # Loop from segment start to end func_ea = seg.start_ea # Get a function at the start of the segment (if any) func = ida_funcs.get_func(func_ea) if func is None: # No function there, try to get the next one func = ida_funcs.get_next_func(func_ea) seg_end = seg.end_ea while func is not None and func.start_ea < seg_end: funcea = func.start_ea print("Function %s at 0x%x" % (ida_funcs.get_func_name(funcea), funcea)) ref = ida_xref.get_first_cref_to(funcea) while ref != ida_idaapi.BADADDR: print(" called from %s(0x%x)" % (ida_funcs.get_func_name(ref), ref)) ref = ida_xref.get_next_cref_to(funcea, ref) func = ida_funcs.get_next_func(funcea)
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 _hxe_callback(self, event, *_): if not self._installed: return 0 if event == ida_hexrays.hxe_func_printed: ea = ida_kernwin.get_screen_ea() func = ida_funcs.get_func(ea) if func is None: return if self._func_ea != func.start_ea: self._func_ea = func.start_ea self._labels = HexRaysHooks._get_user_labels(self._func_ea) self._cmts = HexRaysHooks._get_user_cmts(self._func_ea) self._iflags = HexRaysHooks._get_user_iflags(self._func_ea) self._lvar_settings = HexRaysHooks._get_user_lvar_settings( self._func_ea ) self._numforms = HexRaysHooks._get_user_numforms(self._func_ea) self._send_user_labels(func.start_ea) self._send_user_cmts(func.start_ea) self._send_user_iflags(func.start_ea) self._send_user_lvar_settings(func.start_ea) self._send_user_numforms(func.start_ea) return 0
def _recurse(self, ea, path, depth): if depth + 1 >= self.mr: self.paths[path] = [("[...]", BADADDR)] return # for all callers of ea... i = 0 for ref in idautils.CodeRefsTo(ea, False): if i + 1 >= self.mf: self.paths[path].append(("...", BADADDR)) break cea = ref func = ida_funcs.get_func(cea) if func: cea = func.start_ea loc_name = ida_name.get_short_name(cea) if not len(loc_name): loc_name = "unkn_%x" % cea elem = (loc_name, cea) # if path doesn't exist yet if path not in self.paths: self.paths[path] = [elem] # if caller doesn't exist yet if elem not in self.paths[path]: self.paths[path].append(elem) i += 1 newpath = "%s/%s" % (path, loc_name) self._recurse(cea, newpath, depth + 1) return
def find_item(ea, q, parents=False, flags=0): """find item within AST of decompiled function arguments: ea: address belonging to a function q: lambda/function: f(cfunc_t, citem_t) returning a bool parents: False -> discard cexpr_t parent nodes True -> maintain citem_t parent nodes returns list of query_result_t objects """ f = ida_funcs.get_func(ea) if f: cfunc = None hf = hx.hexrays_failure_t() try: cfunc = hx.decompile(f, hf, flags) except Exception as e: print("%s %x: unable to decompile: '%s'" % (SCRIPT_NAME, ea, hf)) print("\t (%s)" % e) return list() if cfunc: return find_child_item(cfunc, cfunc.body, q, parents) return list()
def get_dispatcher(handler): """Retrieves the dispatcher of the TL/DR API calls :param handler: Handler of the TL/DR API calls :type handler: int :return: Dispatcher for the TL/DR API calls :rtype: int """ func = ida_funcs.get_func(handler) insn = ida_ua.insn_t() ea = 0 branch_addr = -1 ea = func.start_ea while ea < func.end_ea: insn = ida_ua.insn_t() insn_len = max(1, ida_ua.decode_insn(insn, ea)) if insn.itype == ida_allins.ARM_bl and \ insn.ops[0].type == ida_ua.o_near: branch_addr = insn.ops[0].addr break ea += insn_len return branch_addr
def __init__(self, caller, sp): self.caller = caller self.sp = sp f = ida_funcs.get_func(caller) self.displ = "%08x: " % caller if f: self.displ += ida_funcs.get_func_name(caller) t = caller - f.start_ea if t > 0: self.displ += "+" + hex(t) else: self.displ += hex(caller) self.displ += " [" + hex(sp) + "]"
def Chunks(start): """ Get a list of function chunks @param start: address of the function @return: list of funcion chunks (tuples of the form (start_ea, end_ea)) belonging to the function """ func_iter = ida_funcs.func_tail_iterator_t( ida_funcs.get_func( start ) ) status = func_iter.main() while status: chunk = func_iter.chunk() yield (chunk.start_ea, chunk.end_ea) status = next(func_iter)
def FuncItems(start): """ Get a list of function items @param start: address of the function @return: ea of each item in the function """ func = ida_funcs.get_func(start) if not func: return fii = ida_funcs.func_item_iterator_t() ok = fii.set(func) while ok: yield fii.current() ok = fii.next_code()
def decompile(ea, hf=None): if isinstance(ea, (int, long)): func = ida_funcs.get_func(ea) if not func: return elif type(ea) == ida_funcs.func_t: func = ea else: raise RuntimeError('arg 1 of decompile expects either ea_t or cfunc_t argument') if hf is None: hf = hexrays_failure_t() ptr = _decompile(func, hf) if ptr.__deref__() is None: raise DecompilationFailure(hf) return ptr
def function_graph_ir(): # Get settings settings = GraphIRForm() ret = settings.Execute() if not ret: return func = ida_funcs.get_func(idc.ScreenEA()) func_addr = func.startEA build_graph( func_addr, settings.cScope.value, simplify=settings.cOptions.value & OPTION_GRAPH_CODESIMPLIFY, dontmodstack=settings.cOptions.value & OPTION_GRAPH_DONTMODSTACK, loadint=settings.cOptions.value & OPTION_GRAPH_LOADMEMINT, verbose=False ) return
def find_import_ref(dllname): imports = find_imported_funcs(dllname) R = dict() for i, (ea, name,_) in enumerate(imports): #print "%x -> %s" % (ea, name) for xref in idautils.XrefsTo(ea): # check if referrer is a thunk ea = xref.frm f = ida_funcs.get_func(ea) if f and (f.flags & ida_funcs.FUNC_THUNK) != 0: imports.append([f.start_ea, ida_funcs.get_func_name(f.start_ea), 0]) #print "\t%x %s: from a thunk, parent added %x" % (ea, name, f.start_ea) continue # save results if i not in R: R[i] = [] R[i].append(ea) return (imports, R)
def __init__(self, ira): self.ira = ira default_types_info = r"""ExprId("RDX", 64): char *""" archs = ["AMD64_unk", "X86_32_unk", "msp430_unk"] func = ida_funcs.get_func(idc.ScreenEA()) func_addr = func.startEA start_addr = idc.SelStart() if start_addr == idc.BADADDR: start_addr = idc.ScreenEA() end_addr = idc.SelEnd() ida_kernwin.Form.__init__(self, r"""BUTTON YES* Launch BUTTON CANCEL NONE Type Propagation Settings {FormChangeCb} Analysis scope: <Whole function:{rFunction}> <From an address to the end of function:{rAddr}> <Between two addresses:{r2Addr}>{cScope}> <Target function:{functionAddr}> <Start address :{startAddr}> <End address :{endAddr}> <Architecture/compilator :{arch}> <##Header file :{headerFile}> <Use a file for type informations:{rTypeFile}>{cTypeFile}> <##Types informations :{typeFile}> <Types informations :{strTypesInfo}> <Unalias stack:{rUnaliasStack}>{cUnalias}> """, { 'FormChangeCb': ida_kernwin.Form.FormChangeCb(self.OnFormChange), 'cScope': ida_kernwin.Form.RadGroupControl( ("rFunction", "rAddr", "r2Addr")), 'functionAddr': ida_kernwin.Form.NumericInput( tp=ida_kernwin.Form.FT_RAWHEX, value=func_addr), 'startAddr': ida_kernwin.Form.NumericInput( tp=ida_kernwin.Form.FT_RAWHEX, value=start_addr), 'endAddr': ida_kernwin.Form.NumericInput( tp=ida_kernwin.Form.FT_RAWHEX, value=end_addr), 'arch': ida_kernwin.Form.DropdownListControl( items=archs, readonly=False, selval=archs[0]), 'headerFile': ida_kernwin.Form.FileInput(swidth=20, open=True), 'cTypeFile': ida_kernwin.Form.ChkGroupControl(("rTypeFile",)), 'typeFile': ida_kernwin.Form.FileInput(swidth=20, open=True), 'strTypesInfo': ida_kernwin.Form.MultiLineTextControl(text=default_types_info, flags=ida_kernwin.Form.MultiLineTextControl.TXTF_FIXEDFONT), 'cUnalias': ida_kernwin.Form.ChkGroupControl(("rUnaliasStack",)), }) form, args = self.Compile() form.rUnaliasStack.checked = True form.rTypeFile.checked = True
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 = ida_funcs.get_func(caller) self.displ = "%08x: " % caller if f: self.displ += ida_funcs.get_func_name(caller) t = caller - f.start_ea 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 = idautils.cpu.Esp seg = ida_segment.getseg(sp) if not seg: return (False, "Could not locate stack segment!") stack_seg = Seg(seg) word_size = 2 ** (seg.bitness + 1) callers = [] sp = idautils.cpu.Esp - word_size while sp < stack_seg.end_ea: sp += word_size ptr = next(idautils.GetDataList(sp, 1, word_size)) seg = ida_segment.getseg(ptr) # only accept executable segments if (not seg) or ((seg.perm & ida_segment.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 = ida_funcs.get_func(ea) if not f: # create function ida_funcs.add_func(ea) # get the flags f = ida_bytes.get_flags(caller) # no code there? if not ida_bytes.is_code(f): ida_ua.create_insn(caller) callers.append(Result(caller, sp)) # return (True, callers)
def launch_depgraph(): global graphs, comments, sol_nb, settings, addr, ir_arch, ircfg # Get the current function addr = idc.ScreenEA() func = ida_funcs.get_func(addr) # Init machine = guess_machine(addr=func.startEA) mn, dis_engine, ira = machine.mn, machine.dis_engine, machine.ira bs = bin_stream_ida() mdis = dis_engine(bs, dont_dis_nulstart_bloc=True) ir_arch = ira(mdis.loc_db) # Populate symbols with ida names for ad, name in idautils.Names(): if name is None: continue mdis.loc_db.add_location(name, ad) asmcfg = mdis.dis_multiblock(func.startEA) # Generate IR ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg) # Get settings settings = depGraphSettingsForm(ir_arch, ircfg) settings.Execute() loc_key, elements, line_nb = settings.loc_key, settings.elements, settings.line_nb # Simplify affectations for irb in ircfg.blocks.values(): irs = [] offset = ir_arch.loc_db.get_location_offset(irb.loc_key) fix_stack = offset is not None and settings.unalias_stack for assignblk in irb: if fix_stack: stk_high = m2_expr.ExprInt(idc.GetSpd(assignblk.instr.offset), ir_arch.sp.size) fix_dct = {ir_arch.sp: mn.regs.regs_init[ir_arch.sp] + stk_high} new_assignblk = {} for dst, src in assignblk.iteritems(): if fix_stack: src = src.replace_expr(fix_dct) if dst != ir_arch.sp: dst = dst.replace_expr(fix_dct) dst, src = expr_simp(dst), expr_simp(src) new_assignblk[dst] = src irs.append(AssignBlock(new_assignblk, instr=assignblk.instr)) ircfg.blocks[irb.loc_key] = IRBlock(irb.loc_key, irs) # Get dependency graphs dg = settings.depgraph graphs = dg.get(loc_key, elements, line_nb, set([ir_arch.loc_db.get_offset_location(func.startEA)])) # Display the result comments = {} sol_nb = 0 # Register and launch ida_kernwin.add_hotkey("Shift-N", next_element) treat_element()