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 _decompile(offset: int) -> tuple: """ Attempt to decompile the function at the provided offset using the Hex-Rays plugin. Returns a tuple containing the decompiled text (which will be None if an error occurred) and the populated hexrays_failure_t object. :param offset: an offset in the function to decompile :return: (decompiled text, failure object) """ func = ida_funcs.get_func(offset) hf = ida_hexrays.hexrays_failure_t() decompiled = ida_hexrays.decompile_func(func, hf, 0) return decompiled, hf
def get_microcode(func, maturity): """ Return the mba_t of the given function at the specified maturity. """ mbr = ida_hexrays.mba_ranges_t(func) hf = ida_hexrays.hexrays_failure_t() ml = ida_hexrays.mlist_t() ida_hexrays.mark_cfunc_dirty(func.start_ea) mba = ida_hexrays.gen_microcode(mbr, hf, ml, ida_hexrays.DECOMP_NO_WAIT, maturity) if not mba: print("0x%08X: %s" % (hf.errea, hf.desc())) return None return mba
def decompiled_code(address: int, _visited=None) -> Optional[ida_hexrays.cfuncptr_t]: """ Generates IDA object representing the decompiled code for the given address. :param address: Start address of the function. :returns: cfuncptr_t object or None on failure. """ if _visited is None: _visited = set() attempted_before = address in _visited _visited.add(address) # This requires Hexrays decompiler, load it and make sure it's available before continuing. if not ida_hexrays.init_hexrays_plugin(): idc.load_and_run_plugin("hexrays", 0) or idc.load_and_run_plugin("hexx64", 0) if not ida_hexrays.init_hexrays_plugin(): logger.debug("Unable to load Hexrays decompiler.") return None fail_obj = ida_hexrays.hexrays_failure_t() code = ida_hexrays.decompile(address, fail_obj) if code and not fail_obj.code: return code if not fail_obj: logger.warning(f"Unable to decompile function at {hex(address)}") return None # Cannot possibly recover from call analysis failure. if fail_obj.code == -12: logger.warning(f"Unable to decompile function at {hex(address)}: call analysis failed") return None # We may be able to still recover from this by first trying to decompile # the called function that caused the failure. # If we've attempted this before, ensure we don't try a third time # and cause an infinite loop. if not attempted_before: failed_address = fail_obj.errea if ida_ua.ua_mnem(failed_address) == "call": call_address = idc.get_operand_value(failed_address, 0) if decompiled_code(_visited=_visited) is not None: return decompiled_code(address, visited=_visited) # TODO: Observed this message pops up with fail_obj.code == 0... unsure if that is actually an error. logger.debug(f"Unable to decompile function at {hex(address)}: {fail_obj.code}") return None
def show_microcode(): """Generates and displays microcode for an address range. An address range can be a selection of code or that of the current function.""" sel, sea, eea = kw.read_range_selection(None) pfn = ida_funcs.get_func(kw.get_screen_ea()) if not sel and not pfn: return (False, "Position cursor within a function or select range") if not sel and pfn: sea = pfn.start_ea eea = pfn.end_ea addr_fmt = "%016x" if ida_ida.inf_is_64bit() else "%08x" fn_name = (ida_funcs.get_func_name(pfn.start_ea) if pfn else "0x%s-0x%s" % (addr_fmt % sea, addr_fmt % eea)) F = ida_bytes.get_flags(sea) if not ida_bytes.is_code(F): return (False, "The selected range must start with an instruction") text, mmat, mba_flags = ask_desired_maturity() if text is None and mmat is None: return (True, "Cancelled") if not sel and pfn: mbr = hr.mba_ranges_t(pfn) else: mbr = hr.mba_ranges_t() mbr.ranges.push_back(ida_range.range_t(sea, eea)) hf = hr.hexrays_failure_t() ml = hr.mlist_t() mba = hr.gen_microcode(mbr, hf, ml, hr.DECOMP_WARNINGS, mmat) if not mba: return (False, "0x%s: %s" % (addr_fmt % hf.errea, hf.desc())) vp = printer_t() mba.set_mba_flags(mba_flags) mba._print(vp) mcv = microcode_viewer_t() if not mcv.Create( mba, "0x%s-0x%s (%s)" % (addr_fmt % sea, addr_fmt % eea, text), text, fn_name, vp.get_mc()): return (False, "Error creating viewer") mcv.Show() return (True, "Successfully generated microcode for 0x%s..0x%s" % (addr_fmt % sea, addr_fmt % eea))
def run(self, _): fn = ida_funcs.get_func(ida_kernwin.get_screen_ea()) if fn is None: ida_kernwin.warning("Please position the cursor within a function") return True mmat = MCExplorer.ask_desired_maturity() if mmat == 0: return True hf = ida_hexrays.hexrays_failure_t() mba = Native.gen_microcode(fn, hf, None, 0, mmat) if not mba: return True fn_name = ida_funcs.get_func_name(fn.start_ea) mmat_name = LEVELS[mmat - 1] MCTextView(mba, fn_name, mmat_name).Show() return True
def scrape_unsupported_instructions(): """ Scrape all 'external' (unsupported) decompiler instructions from this IDB. Returns a tuple of two maps: ext2func = { opcode: set([func_ea, func2_ea, ...]) } func2ext = { func_ea: set([opcode1, opcode2, opcode3]) } """ miv = MinsnVisitor() ext2func = collections.defaultdict(set) func2ext = {} for address in idautils.Functions(): #address = 0x1800017E0 print("0x%08X: DECOMPILING" % address) func = ida_funcs.get_func(address) func_mbr = ida_hexrays.mba_ranges_t(func) hf = ida_hexrays.hexrays_failure_t() flags = ida_hexrays.DECOMP_NO_XREFS | ida_hexrays.DECOMP_NO_WAIT | ida_hexrays.DECOMP_WARNINGS mba = ida_hexrays.gen_microcode(func_mbr, hf, None, flags, ida_hexrays.MMAT_GENERATED) if not mba: print(" - 0x%08x: FAILED %s" % (hf.errea, hf.str)) continue miv.found = set() mba.for_all_insns(miv) # opcode --> [func_ea, func2_ea, ..] for ins_op in miv.found: ext2func[ins_op].add(address) # func_ea --> [ins_op, ins_op2, ..] func2ext[address] = miv.found print("\nDone scraping...\n") return (ext2func, func2ext)
i = xc.Show(True) if i >= 0: ida_kernwin.jumpto(xrefs[i]) if ida_hexrays.init_hexrays_plugin(): ea = ida_kernwin.get_screen_ea() pfn = ida_funcs.get_func(ea) w = ida_kernwin.warning if pfn: F = ida_bytes.get_flags(ea) if ida_bytes.is_code(F): gco = ida_hexrays.gco_info_t() if ida_hexrays.get_current_operand(gco): # generate microcode hf = ida_hexrays.hexrays_failure_t() mbr = ida_hexrays.mba_ranges_t(pfn) mba = ida_hexrays.gen_microcode(mbr, hf, None, ida_hexrays.DECOMP_WARNINGS, ida_hexrays.MMAT_PREOPTIMIZED) if mba: merr = mba.build_graph() if merr == ida_hexrays.MERR_OK: ncalls = mba.analyze_calls(ida_hexrays.ACFL_GUESS) if ncalls < 0: print( "%08x: failed to determine some calling conventions", pfn.start_ea) mlist = ida_hexrays.mlist_t() if gco.append_to_list(mlist, mba): ctx = ida_hexrays.op_parent_info_t()
if table is not None: os.write(table, "# Function infomation in " + idaapi.get_root_filename() + "\n") os.write(table, "\n|Address|Name|Declaration|Comment|\n") os.write(table, "|----|----|----|----|\n") for func_ea in idautils.Functions(): name = idaapi.get_func_name(func_ea) if idaapi.is_uname(name): func = idaapi.get_func(func_ea) comment = idaapi.get_func_cmt(func, 1) if comment is None: comment = "" # new line in comment comment = comment.replace("\n", "<br>") # pf = ida_hexrays._decompile(func, None) try: pf = ida_hexrays.decompile(func_ea, ida_hexrays.hexrays_failure_t(0, func_ea, name)) except ida_hexrays.DecompilationFailure, e: print e, name decl = "" else: decl = pf.print_dcl() # delete SOH decl = decl.replace("\x01", "") # delete STX decl = decl.replace("\x02", "") # delete ETB decl = decl.replace("\x17", "") decl = decl.replace("!", "") # delete call standard decl = decl.replace("__fastcall ", "") decl = decl.replace("__stdcall ", "")