Files
2025-03-13 16:17:53 +01:00

449 lines
16 KiB
Python

# -----------------------------------------------------------------------
#<pycode(py_hexrays)>
import ida_funcs
import ida_idaapi
hexrays_failure_t.__repr__ = lambda self: str("%x: %s" % (self.errea, self.desc()))
# ---------------------------------------------------------------------
# Renamings
is_allowed_on_small_struni = accepts_small_udts
is_small_struni = is_small_udt
mbl_array_t = mba_t
# NOTE: Strictly for backward-compatibily reasons (i.e., not
# to break existing scripts), and will never be thrown.
class DecompilationFailure(Exception):
pass
# NOTE: We need to keep this `decompile` prototype because some
# scripts might be passing arguments by keyword
def decompile(ea, hf=None, flags=0):
"""
Decompile a function.
@param ea an address belonging to the function, or an ida_funcs.func_t object
@param hf extended error information (if failed)
@param flags decomp_flags bitwise combination of `DECOMP_...` bits
@return the decompilation result (a `ida_hexrays.cfunc_t` wrapper), or None
"""
return decompile_func(ea, hf, flags)
# ---------------------------------------------------------------------
# listify all list types
import ida_idaapi
ida_idaapi._listify_types(
cinsnptrvec_t,
ctree_items_t,
qvector_lvar_t,
qvector_carg_t,
qvector_ccase_t,
hexwarns_t,
history_t,
lvar_saved_infos_t,
ui_stroff_ops_t)
def citem_to_specific_type(self):
""" cast the citem_t object to its more specific type, either cexpr_t or cinsn_t. """
if self.op >= cot_empty and self.op <= cot_last:
return self.cexpr
elif self.op >= cit_empty and self.op < cit_end:
return self.cinsn
raise RuntimeError('unknown op type %s' % (repr(self.op), ))
citem_t.to_specific_type = property(citem_to_specific_type)
""" array used for translating cinsn_t->op type to their names. """
cinsn_t.op_to_typename = {}
for k in dir(_ida_hexrays):
if k.startswith('cit_'):
cinsn_t.op_to_typename[getattr(_ida_hexrays, k)] = k[4:]
""" array used for translating cexpr_t->op type to their names. """
cexpr_t.op_to_typename = {}
for k in dir(_ida_hexrays):
if k.startswith('cot_'):
cexpr_t.op_to_typename[getattr(_ida_hexrays, k)] = k[4:]
def property_op_to_typename(self):
return self.op_to_typename[self.op]
cinsn_t.opname = property(property_op_to_typename)
cexpr_t.opname = property(property_op_to_typename)
def cexpr_operands(self):
""" return a dictionary with the operands of a cexpr_t. """
if self.op >= cot_comma and self.op <= cot_asgumod or \
self.op >= cot_lor and self.op <= cot_fdiv or \
self.op == cot_idx:
return {'x': self.x, 'y': self.y}
elif self.op == cot_tern:
return {'x': self.x, 'y': self.y, 'z': self.z}
elif self.op in [cot_fneg, cot_neg, cot_sizeof] or \
self.op >= cot_lnot and self.op <= cot_predec:
return {'x': self.x}
elif self.op == cot_cast:
return {'type': self.type, 'x': self.x}
elif self.op == cot_call:
return {'x': self.x, 'a': self.a}
elif self.op in [cot_memref, cot_memptr]:
return {'x': self.x, 'm': self.m}
elif self.op == cot_num:
return {'n': self.n}
elif self.op == cot_fnum:
return {'fpc': self.fpc}
elif self.op == cot_str:
return {'string': self.string}
elif self.op == cot_obj:
return {'obj_ea': self.obj_ea}
elif self.op == cot_var:
return {'v': self.v}
elif self.op == cot_helper:
return {'helper': self.helper}
raise RuntimeError('unknown op type %s' % self.opname)
cexpr_t.operands = property(cexpr_operands)
def cinsn_details(self):
"""
return the details pointer for the cinsn_t object depending on the value of its op member. \
this is one of the cblock_t, cif_t, etc. objects.
"""
if self.op not in self.op_to_typename:
raise RuntimeError('unknown item->op type')
opname = self.opname
if opname == 'empty':
return self
if opname in ['break', 'continue']:
return None
return getattr(self, 'c' + opname)
cinsn_t.details = property(cinsn_details)
cfuncptr_t.__str__ = lambda self: str(self.__deref__())
cfuncptr_t.__repr__ = lambda self: repr(self.__deref__())
cfuncptr_t.__eq__ = lambda self, other: self.__ptrval__() == other.__ptrval__() if isinstance(other, cfuncptr_t) else False
import ida_typeinf
def cfunc_type(self):
""" Get the function's return type tinfo_t object. """
tif = ida_typeinf.tinfo_t()
result = self.get_func_type(tif)
if not result:
return
return tif
cfunc_t.type = property(cfunc_type)
cfuncptr_t.type = property(lambda self: self.__deref__().type)
cfunc_t.arguments = property(lambda self: [self.lvars[i] for i in self.argidx])
cfuncptr_t.arguments = property(lambda self: self.__deref__().arguments)
cfunc_t.lvars = property(cfunc_t.get_lvars)
cfuncptr_t.lvars = property(lambda self: self.__deref__().lvars)
cfunc_t.warnings = property(cfunc_t.get_warnings)
cfuncptr_t.warnings = property(lambda self: self.__deref__().warnings)
cfunc_t.pseudocode = property(cfunc_t.get_pseudocode)
cfuncptr_t.pseudocode = property(lambda self: self.__deref__().get_pseudocode())
cfunc_t.eamap = property(cfunc_t.get_eamap)
cfuncptr_t.eamap = property(lambda self: self.__deref__().get_eamap())
cfunc_t.boundaries = property(cfunc_t.get_boundaries)
cfuncptr_t.boundaries = property(lambda self: self.__deref__().get_boundaries())
#pragma SWIG nowarn=+503
lvar_t.used = property(lvar_t.used)
lvar_t.typed = property(lvar_t.typed)
lvar_t.mreg_done = property(lvar_t.mreg_done)
lvar_t.has_nice_name = property(lvar_t.has_nice_name)
lvar_t.is_unknown_width = property(lvar_t.is_unknown_width)
lvar_t.has_user_info = property(lvar_t.has_user_info)
lvar_t.has_user_name = property(lvar_t.has_user_name)
lvar_t.has_user_type = property(lvar_t.has_user_type)
lvar_t.is_result_var = property(lvar_t.is_result_var)
lvar_t.is_arg_var = property(lvar_t.is_arg_var)
lvar_t.is_fake_var = property(lvar_t.is_fake_var)
lvar_t.is_overlapped_var = property(lvar_t.is_overlapped_var)
lvar_t.is_floating_var = property(lvar_t.is_floating_var)
lvar_t.is_spoiled_var = property(lvar_t.is_spoiled_var)
lvar_t.is_mapdst_var = property(lvar_t.is_mapdst_var)
# dictify all dict-like types
def _map_as_dict(maptype, name, keytype, valuetype):
maptype.keytype = keytype
maptype.valuetype = valuetype
for fctname in ['begin', 'end', 'first', 'second', 'next', \
'find', 'insert', 'erase', 'clear', 'size']:
fct = getattr(_ida_hexrays, name + '_' + fctname)
setattr(maptype, '__' + fctname, fct)
maptype.__len__ = maptype.size
maptype.__getitem__ = maptype.at
maptype.begin = lambda self, *args: self.__begin(self, *args)
maptype.end = lambda self, *args: self.__end(self, *args)
maptype.first = lambda self, *args: self.__first(*args)
maptype.second = lambda self, *args: self.__second(*args)
maptype.next = lambda self, *args: self.__next(*args)
maptype.find = lambda self, *args: self.__find(self, *args)
maptype.insert = lambda self, *args: self.__insert(self, *args)
maptype.erase = lambda self, *args: self.__erase(self, *args)
maptype.clear = lambda self, *args: self.__clear(self, *args)
maptype.size = lambda self, *args: self.__size(self, *args)
def _map___iter__(self):
""" Iterate over dictionary keys. """
return self.iterkeys()
maptype.__iter__ = _map___iter__
def _map___getitem__(self, key):
""" Returns the value associated with the provided key. """
if not isinstance(key, self.keytype):
raise KeyError('type of key should be ' + repr(self.keytype) + ' but got ' + repr(type(key)))
if key not in self:
raise KeyError('key not found')
return self.second(self.find(key))
maptype.__getitem__ = _map___getitem__
def _map___setitem__(self, key, value):
""" Returns the value associated with the provided key. """
if not isinstance(key, self.keytype):
raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key)))
if not isinstance(value, self.valuetype):
raise KeyError('type of `value` should be ' + repr(self.valuetype) + ' but got ' + type(value))
self.insert(key, value)
return
maptype.__setitem__ = _map___setitem__
def _map___delitem__(self, key):
""" Removes the value associated with the provided key. """
if not isinstance(key, self.keytype):
raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key)))
if key not in self:
raise KeyError('key not found')
self.erase(self.find(key))
return
maptype.__delitem__ = _map___delitem__
def _map___contains__(self, key):
""" Returns true if the specified key exists in the . """
if not isinstance(key, self.keytype):
raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key)))
if self.find(key) != self.end():
return True
return False
maptype.__contains__ = _map___contains__
def _map_clear(self):
self.clear()
return
maptype.clear = _map_clear
def _map_copy(self):
ret = {}
for k in self.iterkeys():
ret[k] = self[k]
return ret
maptype.copy = _map_copy
def _map_get(self, key, default=None):
if key in self:
return self[key]
return default
maptype.get = _map_get
def _map_iterkeys(self):
iter = self.begin()
while iter != self.end():
yield self.first(iter)
iter = self.next(iter)
return
maptype.iterkeys = _map_iterkeys
def _map_itervalues(self):
iter = self.begin()
while iter != self.end():
yield self.second(iter)
iter = self.next(iter)
return
maptype.itervalues = _map_itervalues
def _map_iteritems(self):
iter = self.begin()
while iter != self.end():
yield (self.first(iter), self.second(iter))
iter = self.next(iter)
return
maptype.iteritems = _map_iteritems
def _map_keys(self):
return list(self.iterkeys())
maptype.keys = _map_keys
def _map_values(self):
return list(self.itervalues())
maptype.values = _map_values
def _map_items(self):
return list(self.iteritems())
maptype.items = _map_items
def _map_has_key(self, key):
return key in self
maptype.has_key = _map_has_key
def _map_pop(self, key):
""" Sets the value associated with the provided key. """
if not isinstance(key, self.keytype):
raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key)))
if key not in self:
raise KeyError('key not found')
ret = self[key]
del self[key]
return ret
maptype.pop = _map_pop
def _map_popitem(self):
""" Sets the value associated with the provided key. """
if len(self) == 0:
raise KeyError('key not found')
key = self.keys()[0]
return (key, self.pop(key))
maptype.popitem = _map_popitem
def _map_setdefault(self, key, default=None):
""" Sets the value associated with the provided key. """
if not isinstance(key, self.keytype):
raise KeyError('type of `key` should be ' + repr(self.keytype) + ' but got ' + repr(type(key)))
if key in self:
return self[key]
self[key] = default
return default
maptype.setdefault = _map_setdefault
_map_as_dict(user_cmts_t, 'user_cmts', treeloc_t, citem_cmt_t)
_map_as_dict(user_numforms_t, 'user_numforms', operand_locator_t, number_format_t)
_map_as_dict(user_iflags_t, 'user_iflags', citem_locator_t, int)
import ida_pro
_map_as_dict(user_unions_t, 'user_unions', ida_idaapi.integer_types, ida_pro.intvec_t)
_map_as_dict(eamap_t, 'eamap', ida_idaapi.long_type, cinsnptrvec_t)
import ida_range
_map_as_dict(boundaries_t, 'boundaries', cinsn_t, ida_range.rangeset_t)
#
# Object ownership
#
def _call_with_transferrable_ownership(fun, *args):
e = args[0]
was_owned = e.thisown
res = fun(e, *args[1:])
# ATM, 'res' doesn't own the resulting cexpr_t.
# In case 'fun'
# - created a new object: we want to own that one in case 'e' was owned
# - didn't create a new object: we will remove & re-gain ownership on
# the same underlying cexpr_t. No biggie.
if was_owned:
if res:
e._maybe_disown_and_deregister()
res._own_and_register()
else:
debug_hexrays_ctree("NOTE: call_with_transferrable_ownership() called with non-IDAPython-owned object. Is this intentional?")
return res
def lnot(e):
return _call_with_transferrable_ownership(_ll_lnot, e)
def make_ref(e):
return _call_with_transferrable_ownership(_ll_make_ref, e)
def dereference(e, ptrsize, is_float=False):
return _call_with_transferrable_ownership(_ll_dereference, e, ptrsize, is_float)
def call_helper(rettype, args, *rest):
res = _ll_call_helper(rettype, args, *rest)
if res:
res._own_and_register()
if type(args) == carglist_t:
args.thisown = False
return res
def new_block():
res = _ll_new_block()
if res:
res._own_and_register()
return res
def make_num(*args):
res = _ll_make_num(*args)
if res:
res._own_and_register()
return res
def create_helper(*args):
res = _ll_create_helper(*args)
if res:
res._own_and_register()
return res
# ----------------
class __cbhooks_t(Hexrays_Hooks):
instances = []
def __init__(self, callback):
self.callback = callback
self.instances.append(self)
Hexrays_Hooks.__init__(self)
def maturity(self, *args): return self.callback(hxe_maturity, *args)
def interr(self, *args): return self.callback(hxe_interr, *args)
def print_func(self, *args): return self.callback(hxe_print_func, *args)
def func_printed(self, *args): return self.callback(hxe_func_printed, *args)
def open_pseudocode(self, *args): return self.callback(hxe_open_pseudocode, *args)
def switch_pseudocode(self, *args): return self.callback(hxe_switch_pseudocode, *args)
def refresh_pseudocode(self, *args): return self.callback(hxe_refresh_pseudocode, *args)
def close_pseudocode(self, *args): return self.callback(hxe_close_pseudocode, *args)
def keyboard(self, *args): return self.callback(hxe_keyboard, *args)
def right_click(self, *args): return self.callback(hxe_right_click, *args)
def double_click(self, *args): return self.callback(hxe_double_click, *args)
def curpos(self, *args): return self.callback(hxe_curpos, *args)
def create_hint(self, *args): return self.callback(hxe_create_hint, *args)
def text_ready(self, *args): return self.callback(hxe_text_ready, *args)
def populating_popup(self, *args): return self.callback(hxe_populating_popup, *args)
# NOTE: Do not add support for new notifications here;
# non-Hexrays_Hooks callbacks are deprecated.
def install_hexrays_callback(callback):
"Deprecated. Please use Hexrays_Hooks instead"
h = __cbhooks_t(callback)
h.hook()
return True
def remove_hexrays_callback(callback):
"Deprecated. Please use Hexrays_Hooks instead"
for inst in __cbhooks_t.instances:
if inst.callback == callback:
inst.unhook()
__cbhooks_t.instances.remove(inst)
return 1
return 0
#</pycode(py_hexrays)>