def get_func_details(func_ea): xfunc = ida_hexrays.decompile(func_ea) if xfunc is None: return None func_details = idaapi.func_type_data_t() xfunc.type.get_func_details(func_details) return func_details
def process_sscanf_callers(instr, sscanf): func = ida_hexrays.decompile(instr) # Error prone, better would be to filter func.body.treeitems node = func.body.find_closest_addr(instr) if node is None: return if node.op != ida_hexrays.cot_call: return node = node.to_specific_type if node.x.op != ida_hexrays.cot_obj: return if node.x.obj_ea != sscanf: return num_args = len(list(node.a)) - 2 parent = func.body.find_parent_of(node) if parent is None: # Should never happen ? return grandparent = func.body.find_parent_of(parent) comparand = None if parent.op == ida_hexrays.cit_expr and grandparent.op == ida_hexrays.cit_block: pass else: if parent.op == ida_hexrays.cot_asg: parent.to_specific_type.x if parent.op == ida_hexrays.cot_eq: parent = parent.to_specific_type if parent.y.op != ida_hexrays.cot_num: print( 'Not supporting comparisons against anything but an num node' ) return else: comparand = parent.y.n._value elif parent.op == ida_hexrays.cit_if: comparand = 'nonzero' if comparand is None: print( "The sscanf call at 0x%08x is worth looking at, no comparisons were found despite %d arguments" % (instr, num_args)) elif comparand == 'nonzero': print( "The sscanf call at 0x%08x is worth looking at, there is only a comparison against being non-zero and there are %d arguments" % (instr, num_args)) else: if comparand < num_args: print( "The sscanf call at 0x%08x is worth looking at, there is a comparison against %d but there are %d arguments" % (instr, comparand, num_args))
def parse_table(ea): table = u64(idc.get_bytes(ea, 8)) addr = table func_table = [] while True: pm4type, opcode, handler = read_entry(addr) if handler == 0: break # get gnm name and packet count gnm_name, packet_count = parse_function(handler) # decompile the handler func = ida_hexrays.decompile(handler) lines = func.get_pseudocode() code_lines = [] for sline in lines: line = ida_lines.tag_remove(sline.line) code_lines.append(line) print('{}\t{} {} {:X} {:08X}'.format(gnm_name, packet_count, pm4type, opcode, handler)) if not gnm_name: gnm_name = 'sub_{:X}'.format(handler) func_table.append( (gnm_name, packet_count, pm4type, opcode, handler, code_lines)) addr += 16 return func_table
def from_addr(cls, ea=None): """ Class method which return a :class:`HxCFunc` object corresponding to the function at a particular address. This may raise a :class:`~bip.base.BipDecompileError` if the decompilation failed or if the address provided is not in a function. :param int ea: An address inside the function for which we want an :class:`HxCFunc`. If ``None`` the screen address will be used. :return: A :class:`HxCFunc` object. """ if ea is None: ea = ida_kernwin.get_screen_ea() try: idaobj = ida_hexrays.decompile(ea) except ida_hexrays.DecompilationFailure: # IDA could not decompile the function raise bbase.BipDecompileError( "Hexrays failed to decompile function at 0x{:X}".format(ea)) if idaobj is None: raise bbase.BipDecompileError( "Decompilation failed for {}: address was probably not in a function ?" .format(ea)) return cls(idaobj)
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 apply_jni_func_sig(): """ Apply the standard JNIEnv* and jobject signature to a function. """ print("Function: {}".format(idc.get_func_name(here()))) func = ida_hexrays.decompile(here()) func_type = func.type funcdata = ida_typeinf.func_type_data_t() func_type.get_func_details(funcdata) jnienv = ida_typeinf.tinfo_t() jnienv.get_named_type(ida_typeinf.get_idati(), "JNIEnv") jnienv_ptr = ida_typeinf.tinfo_t() jnienv_ptr.create_ptr(jnienv) jobject = ida_typeinf.tinfo_t() jobject.get_named_type(ida_typeinf.get_idati(), "jobject") funcdata[0].type = jnienv_ptr funcdata[0].name = "env" funcdata[1].type = jobject funcdata[1].name = "thiz" new_tinfo = ida_typeinf.tinfo_t() new_tinfo.create_func(funcdata) ida_typeinf.apply_tinfo(here(), new_tinfo, ida_typeinf.TINFO_DEFINITE)
def run(self, arg): for function in idautils.Functions(): values = {} #function = ida_kernwin.get_screen_ea() function_start = idc.get_func_attr(function, idc.FUNCATTR_START) function_end = idc.get_func_attr(function, idc.FUNCATTR_END) function_name = idc.get_func_name(function) if "func" in function_name: try: values[function_name] = [] for z in re.findall("= (0[xX][0-9a-fA-F]+)",str(ida_hexrays.decompile(function))): values[function_name].append(binascii.hexlify(struct.pack('<Q', int(int(z.replace("0x", ""), base=16)))).decode("windows-1252").replace("00","")) except idaapi.DecompilationFailure: pass lenght = int(len(values[function_name]) / 2) string = self.to_decimal(values[function_name][0:lenght]) key = self.to_decimal(values[function_name][lenght::]) str_decrypted = "" for i in range(0, len(string)): str_decrypted += chr(string[i] ^ key[i % len(key)]) #idaapi.msg(f"{string[i]} ^ {key[i % len(key)]}\n") if str_decrypted != "": #idaapi.msg(str_decrypted+"\n") idc.set_func_cmt(function_start, str_decrypted, 0) rowPosition = self.plg.table.rowCount() self.plg.table.insertRow(rowPosition) self.plg.table.setItem(rowPosition, 0, QtWidgets.QTableWidgetItem(function_name)) self.plg.table.setItem(rowPosition, 1, QtWidgets.QTableWidgetItem(str_decrypted))
def get_func_stack_var_info(func_addr) -> typing.Dict[int, StackVariable]: try: decompilation = ida_hexrays.decompile(func_addr) except ida_hexrays.DecompilationFailure: l.debug( "Decompiling too many functions too fast! Slow down and try that operation again." ) return {} stack_var_info = {} for var in decompilation.lvars: if not var.is_stk_var(): continue size = var.width name = var.name ida_offset = var.location.stkoff() - decompilation.get_stkoff_delta() bs_offset = ida_to_angr_stack_offset(func_addr, ida_offset) type_str = str(var.type()) stack_var_info[bs_offset] = StackVariable(ida_offset, StackOffsetType.IDA, name, type_str, size, func_addr) return stack_var_info
def alive_copy_unimplemented(check_active, ctx): if check_active == 1: return 0; decompiled = ida_hexrays.decompile(here()) result = "EXPORT " + str(decompiled.type) + " { NOT_IMPLEMENTED; }" result = fix_type_string(result) copy_to_clip(result) print "Alive Function copied to clipboard!"
def refresh_pseudocode(self, vu): if self.another_decompile_ea: logging.debug("decompile again") ea = self.another_decompile_ea ida_hexrays.mark_cfunc_dirty(ea, False) cfunc = ida_hexrays.decompile(ea) self.another_decompile_ea = None vu.switch_to(cfunc, True) return 0
def auto_rename_single(ca, addr, force=False): cfunc = ida_hexrays.decompile(addr, flags=ida_hexrays.DECOMP_NO_CACHE if force else 0) if not cfunc: return ca.reset() ca.apply_to(cfunc.body, None) if ca.results: ida_name.set_name(addr, ca.results[-1], ida_name.SN_AUTO | ida_name.SN_NOCHECK | ida_name.SN_NOWARN)
def decompile_func(ea, outfile): ida_kernwin.msg("Decompiling at: %X..." % ea) cf = ida_hexrays.decompile(ea) if cf: ida_kernwin.msg("OK\n") outfile.write(str(cf) + "\n") else: ida_kernwin.msg("failed!\n") outfile.write("decompilation failure at %X!\n" % ea)
def _on_refresh_pseudocode(vu): global _ANOTHER_DECOMPILER_EA if not _ANOTHER_DECOMPILER_EA: return log.debug("decompile again") ea = _ANOTHER_DECOMPILER_EA ida_hexrays.mark_cfunc_dirty(ea, False) cfunc = ida_hexrays.decompile(ea) _ANOTHER_DECOMPILER_EA = None vu.switch_to(cfunc, True)
def apply_everywhere(): hr_remove() for segea in idautils.Segments(): for funcea in idautils.Functions(segea, idc.SegEnd(segea)): print("Handling %s" % idc.GetFunctionName(funcea)) try: cfunc = ida_hexrays.decompile(funcea) apply_on_fn(cfunc) except ida_hexrays.DecompilationFailure as e: print("Failed to decompile!") hr_install()
def ast_a_function(address): try: vfun = hexray.decompile(address) #without this print the vfun has an empty ctree associated. b = str(vfun) itemstruct = {} #itemstruct['src']=b body = vfun.body str(body) treenodes = [x for x in vfun.treeitems] for x in treenodes: index = int(x.index) treeitem = {} treeitem['op_name'] = hexray.get_ctype_name(x.op) x = x.to_specific_type op = x.op if op == hexray.cot_call: #se e' una chiamata a funzione ci mettiamo il nome della funzione #treeitem['opcall']=idaapi.get_func_name(x.obj_ea) pass elif op == hexray.cot_ptr: pass elif op == hexray.cot_memptr: pass elif op == hexray.cot_memref: pass elif op == hexray.cot_obj: treeitem['name'] = idaapi.get_func_name(x.obj_ea) elif op == hexray.cot_var: treeitem['size'] = x.refwidth #treeitem['varname'] = str(dir(x)) pass elif op == hexray.cot_num: #typeInfo = idaapi.tinfo_t() treeitem['value'] = str(x.numval()) #treeitem['size'] = x.refwidth #treeitem['formatname'] = str(x.n.nf.type_name) pass elif op == hexray.cot_helper: pass elif op == hexray.cot_str: pass try: treeitem['parent_index'] = int( vfun.body.find_parent_of(x).index) except: treeitem['parent_index'] = None itemstruct[index] = treeitem return itemstruct except Exception as e: return None
def auto_rename_single(ca, addr): cfunc = ida_hexrays.decompile(addr) if not cfunc: return ca.reset() ca.apply_to(cfunc.body, None) if ca.results: ida_name.set_name( addr, ca.results[-1], ida_name.SN_AUTO | ida_name.SN_NOCHECK | ida_name.SN_NOWARN)
def find_item(ea, item, findall=True, parents=False): """find item within AST of decompiled function arguments: ea: address belonging to a function item: lambda/function: f(cfunc_t, citem_t) returning a bool findall: False -> find cexpr_t only (faster but doesn't find cinsn_t items) True -> find citem_t elements, which includes cexpr_t and cinsn_t parents: False -> discard cexpr_t parent nodes True -> maintain citem_t parent nodes returns list of citem_t items """ class citem_finder_t(hr.ctree_visitor_t): def __init__(self, cfunc, i, parents): hr.ctree_visitor_t.__init__(self, hr.CV_PARENTS if parents else hr.CV_FAST) self.findall = findall self.cfunc = cfunc self.item = i self.found = list() return def process(self, i): """process cinsn_t and cexpr_t elements alike""" cfunc = self.cfunc if self.item(cfunc, i): self.found.append(i) if not self.findall: return 1 return 0 def visit_insn(self, i): return self.process(i) def visit_expr(self, e): return self.process(e) try: cfunc = hr.decompile(ea) except: print("%x: unable to decompile." % ea) return list() if cfunc: itfinder = citem_finder_t(cfunc, item, parents) itfinder.apply_to(cfunc.body, None) return itfinder.found return list()
def decompile(self): ida_hexrays.init_hexrays_plugin() cfuncs = [] for function in idautils.Functions(): try: cfunc = ida_hexrays.decompile(function) log_file.write("CFUNC: %s\n" % (cfunc)) cfuncs.append(cfunc) except Exception as e: log_file.write("ERROR: %s - %s\n" % (e, idc.get_func_name(function))) #traceback.print_exc(file=log_file) return cfuncs
def get_hexrays_vars(ea, stack_size): # can be used to get member size, type, etc. hexrays_types[idc.get_func_name(ea)] = {} for var in ida_hexrays.decompile(ea).get_lvars(): if not var.name: continue if var.width>=8: ownertype = "pointer" else: ownertype = "scalar" # print(dir(var.tif)) offset = -stack_size + var.get_stkoff() hexrays_types[idc.get_func_name(ea)][offset] = var.width, ownertype
def alive_copy_decompiled(check_active, ctx): if check_active == 1: return 0; addr = here() for i in xrange(len(ctx.chooser_selection)): idx = ctx.chooser_selection.at(i) addr = ida_name.get_nlist_ea(idx) result = "EXPORT " + str(ida_hexrays.decompile(addr)) result = fix_type_string(result) copy_to_clip(result) print "Alive Function copied to clipboard!"
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 find_item(ea, q, parents=False): """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 tb_result_t objects """ class citem_finder_t(hr.ctree_visitor_t): def __init__(self, cfunc, q, parents): hr.ctree_visitor_t.__init__( self, hr.CV_PARENTS if parents else hr.CV_FAST) self.cfunc = cfunc self.query = q self.found = list() return def process(self, i): """process cinsn_t and cexpr_t elements alike""" if self.query(self.cfunc, i): self.found.append(tb_result_t(i)) return 0 def visit_insn(self, i): return self.process(i) def visit_expr(self, e): return self.process(e) try: f = ida_funcs.get_func(ea) if f: cfunc = hr.decompile(f) except: print("%x: unable to decompile." % ea) return list() if cfunc: itfinder = citem_finder_t(cfunc, q, parents) itfinder.apply_to(cfunc.body, None) return itfinder.found return list()
def __call__(self): # FIXME: Hey-Rays bindings are broken # iflags = ida_hexrays.user_iflags_new() # for (cl_ea, cl_op), f in self.iflags: # cl = ida_hexrays.citem_locator_t(cl_ea, cl_op) # iflags.insert(cl, f) # ida_hexrays.save_user_iflags(self.ea, iflags) ida_hexrays.save_user_iflags(self.ea, ida_hexrays.user_iflags_new()) HexRaysEvent.refresh_pseudocode_view() cfunc = ida_hexrays.decompile(self.ea) for (cl_ea, cl_op), f in self.iflags: cl = ida_hexrays.citem_locator_t(cl_ea, cl_op) cfunc.set_user_iflags(cl, f) cfunc.save_user_iflags() HexRaysEvent.refresh_pseudocode_view()
def get_items_for_ea(self, ea): frm = [x.frm for x in idautils.XrefsTo(self.__ea)] items = [] for ea in frm: try: cfunc = ida_hexrays.decompile(ea) self.functions.append(cfunc.entry_ea) self.items.append((ea, ida_funcs.get_func_name(cfunc.entry_ea) or "", self.get_decompiled_line(cfunc, ea))) except Exception as e: print('could not decompile: %s' % (str(e), )) raise return
def find_expr(ea, expr, findall=True, parents=False): """find expression within AST of decompiled function arguments: ea: address belonging to a function expr: lambda/function: f(cfunc_t, citem_t) returning a bool findall: False -> find cexpr_t only (faster but doesn't find cinsn_t items) True -> find citem_t elements, which includes cexpr_t and cinsn_t parents: False -> discard cexpr_t parent nodes True -> maintain citem_t parent nodes returns list of cexpr_t items """ class expr_finder_t(hr.ctree_visitor_t): def __init__(self, cfunc, expr, parents): hr.ctree_visitor_t.__init__( self, hr.CV_PARENTS if parents else hr.CV_FAST) self.findall = findall self.cfunc = cfunc self.expr = expr self.found = list() return def visit_expr(self, e): """process cexpr_t elements""" if self.expr(self.cfunc, e): self.found.append(e) #print("dbg %x" % e.ea) if not self.findall: return 1 return 0 try: cfunc = hr.decompile(ea) except: print("%x: unable to decompile." % ea) return list() if cfunc: expfinder = expr_finder_t(cfunc, expr, parents) expfinder.apply_to_exprs(cfunc.body, None) return expfinder.found return list()
def get_decompiled_func(): f = ida_funcs.get_func(ida_kernwin.get_screen_ea()) if f is None: Util.clear_output_window() print("[SPIRIT] Please position the cursor within a function") return True cfunc = ida_hexrays.decompile(f) if cfunc is None: Util.clear_output_window() print("[SPIRIT] Failed to decompile!") return True sb = cfunc.get_pseudocode() function_arr = [] for line in sb: function_arr.append(ida_lines.tag_remove(line.line)) return function_arr
def analyzeSingleFunction(startAddr, endAddr, searchString, paramIndex): #print"Analyzing Function Name: {}".format(GetFunctionName(startAddr)) curAddr = startAddr # If some trace statements within this function don't match others, name the function with the # name used most often, which this dict will keep track of possibleNameList = dict() try: c = ida_hexrays.decompile(startAddr) except ida_hexrays.DecompilationFailure: print("Decompilation failure trying to decompile function at addr {}". format(hex(startAddr))) return "" for singleLine in findFuncCalls(str(c), searchString): leftJustifiedLine = singleLine.lstrip() if (leftJustifiedLine.startswith(searchString + "(")): #print leftJustifiedLine possibleName = analyzeSingleCall(leftJustifiedLine, paramIndex) if possibleName in possibleNameList: possibleNameList[ possibleName] = possibleNameList[possibleName] + 1 else: possibleNameList[possibleName] = 1 if (len(possibleNameList) == 0): print "No function names discovered for {}".format( GetFunctionName(startAddr)) return "" print "All possible function names discovered for {}:\n\t{}".format( GetFunctionName(startAddr), "\n\t".join(possibleNameList)) numUses = 0 for fName in possibleNameList: if (possibleNameList[fName] > numUses): numUses = possibleNameList[fName] retVal = fName return fName
def get_func_type(funcea): """ Try to get decompiled func type. If can't decompile func, try to get tinfo from funcea, And if funcaa doesn't have associated tinfo, try to guess type at funcea @return: tuple(type, fnames) """ if not is_func(funcea): log.warn("%08X is not a func", funcea) return None funcea = get_func_start(funcea) try: xfunc = ida_hexrays.decompile(funcea) return xfunc.type.serialize()[:-1] except ida_hexrays.DecompilationFailure as ex: log.warn( "Couldn't decompile func at %08X: %s, getting or guessing func type from ea", funcea, ex ) return get_or_guess_tinfo(funcea)
def post_func_type_change(pfn): ea = pfn.start_ea xrefs = idautils.XrefsTo(ea, ida_xref.XREF_USER) xrefs = list(filter(lambda x: x.type == ida_xref.dr_I and x.user == 1, xrefs)) args_list = [] if len(xrefs) == 0: return None, [] try: xfunc = ida_hexrays.decompile(ea) func_ptr_typeinf = utils.get_typeinf_ptr(xfunc.type) for xref in xrefs: member, old_name, struct = ida_struct.get_member_by_id(xref.frm) if member is not None and struct is not None: args_list.append( [struct, member, 0, func_ptr_typeinf, idaapi.TINFO_DEFINITE] ) except Exception: pass return ida_struct.set_member_tinfo, args_list
def decompile_func(ea): if not init_hexrays_plugin(): #print 'no here' return '' f = get_func(ea) if f is None: return '' cfunc = ida_hexrays.decompile(f) if cfunc is None: # Failed to decompile return '' lines = [] sv = cfunc.get_pseudocode() for sline in sv: line = tag_remove(sline.line) lines.append(line) return lines
import ida_loader import ida_hexrays import ida_idp import ida_entry ida_auto.auto_wait() ALL_DECOMPILERS = { ida_idp.PLFM_386 : ("hexrays", "hexx64"), ida_idp.PLFM_ARM : ("hexarm", "hexarm64"), ida_idp.PLFM_PPC : ("hexppc", "hexppc64"), } pair = ALL_DECOMPILERS.get(ida_idp.ph.id, None) if pair: decompiler = pair[1 if ida_ida.cvar.inf.is_64bit() else 0] if ida_loader.load_plugin(decompiler) and ida_hexrays.init_hexrays_plugin(): eqty = ida_entry.get_entry_qty() if eqty: ea = ida_entry.get_entry(ida_entry.get_entry_ordinal(0)) print("Decompiling at: %X" % ea) cf = ida_hexrays.decompile(ea) if cf: print(cf) else: print("Decompilation failed") else: print("No known entrypoint. Cannot decompile.") else: print("Couldn't load or initialize decompiler: \"%s\"" % decompiler) else: print("No known decompilers for architecture with ID: %d" % ida_idp.ph.id)