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

437 lines
15 KiB
Python

#<pycode(py_idp)>
#----------------------------------------------------------------------------
# P R O C E S S O R M O D U L E S C O N S T A N T S
#----------------------------------------------------------------------------
# ----------------------------------------------------------------------
# processor_t related constants
REAL_ERROR_FORMAT = -1 # not supported format for current .idp
REAL_ERROR_RANGE = -2 # number too big (small) for store (mem NOT modifyed)
REAL_ERROR_BADDATA = -3 # illegal real data for load (IEEE data not filled)
#
# Set IDP options constants
#
IDPOPT_STR = 1 # string constant
IDPOPT_NUM = 2 # number
IDPOPT_BIT = 3 # bit, yes/no
IDPOPT_FLT = 4 # float
IDPOPT_I64 = 5 # 64bit number
IDPOPT_OK = 0 # ok
IDPOPT_BADKEY = 1 # illegal keyword
IDPOPT_BADTYPE = 2 # illegal type of value
IDPOPT_BADVALUE = 3 # illegal value (bad range, for example)
# ----------------------------------------------------------------------
import ida_pro
import ida_funcs
import ida_segment
import ida_ua
class processor_t(IDP_Hooks):
__idc_cvt_id__ = ida_idaapi.PY_ICID_OPAQUE
"""
Base class for all processor module scripts
A processor_t instance is both an ida_idp.IDP_Hooks, and an
ida_idp.IDB_Hooks at the same time: any method of those two classes
can be overridden in your processor_t subclass (with the exception of
'ida_idp.IDP_Hooks.ev_init' (replaced with processor_t.__init__),
and 'ida_idp.IDP_Hooks.ev_term' (replaced with processor_t.__del__)).
"""
def __init__(self):
IDP_Hooks.__init__(self, ida_idaapi.HBF_CALL_WITH_NEW_EXEC)
self.idb_hooks = _processor_t_Trampoline_IDB_Hooks(self)
def get_idpdesc(self):
"""
This function must be present and should return the list of
short processor names similar to the one in ph.psnames.
This method can be overridden to return to the kernel a different IDP description.
"""
return '\x01'.join(map(lambda t: '\x01'.join(t), zip(self.plnames, self.psnames)))
def get_auxpref(self, insn):
"""This function returns insn.auxpref value"""
return insn.auxpref
def _get_idp_notifier_addr(self):
return _ida_idp.get_idp_notifier_addr(self)
def _get_idp_notifier_ud_addr(self):
return _ida_idp.get_idp_notifier_ud_addr(self)
def _get_idb_notifier_addr(self):
return _ida_idp.get_idb_notifier_addr(self)
def _get_idb_notifier_ud_addr(self):
return _ida_idp.get_idb_notifier_ud_addr(self.idb_hooks)
def _make_forced_value_wrapper(self, val, meth=None):
def f(*args):
if meth:
meth(*args)
return val
return f
def _make_int_returning_wrapper(self, meth, intval=0):
def f(*args):
val = meth(*args)
if val is None:
val = intval
return val
return f
def _get_notify(self, what, unimp_val=0, imp_forced_val=None, add_prefix=True, mandatory_impl=None):
"""
This helper is used to implement backward-compatibility
of pre IDA 7.3 processor_t interfaces.
"""
if add_prefix:
what = "notify_%s" % what
meth = getattr(self, what, None)
if meth is None:
if mandatory_impl:
raise Exception("processor_t.%s() must be implemented" % mandatory_impl)
meth = self._make_forced_value_wrapper(unimp_val)
else:
if imp_forced_val is not None:
meth = self._make_forced_value_wrapper(imp_forced_val, meth)
else:
meth = self._make_int_returning_wrapper(meth)
return meth
# The default implementations below are what guarantees that
# pre IDA 7.3 processor_t subclasses, will continue working
def ev_newprc(self, *args):
return self._get_notify("newprc")(*args)
def ev_newfile(self, *args):
return self._get_notify("newfile")(*args)
def ev_oldfile(self, *args):
return self._get_notify("oldfile")(*args)
def ev_newbinary(self, *args):
return self._get_notify("newbinary")(*args)
def ev_endbinary(self, *args):
return self._get_notify("endbinary")(*args)
def ev_set_idp_options(self, keyword, value_type, value, idb_loaded):
res = self._get_notify("set_idp_options", unimp_val=None)(keyword, value_type, value)
if res is None:
return 0
return 1 if res == IDPOPT_OK else -1
def ev_set_proc_options(self, *args):
return self._get_notify("set_proc_options")(*args)
def ev_ana_insn(self, *args):
rc = self._get_notify("ana", mandatory_impl="ev_ana_insn")(*args)
return rc > 0
def ev_emu_insn(self, *args):
rc = self._get_notify("emu", mandatory_impl="ev_emu_insn")(*args)
return rc > 0
def ev_out_header(self, *args):
return self._get_notify("out_header", imp_forced_val=1)(*args)
def ev_out_footer(self, *args):
return self._get_notify("out_footer", imp_forced_val=1)(*args)
def ev_out_segstart(self, ctx, s):
return self._get_notify("out_segstart", imp_forced_val=1)(ctx, s.start_ea)
def ev_out_segend(self, ctx, s):
return self._get_notify("out_segend", imp_forced_val=1)(ctx, s.end_ea)
def ev_out_assumes(self, *args):
return self._get_notify("out_assumes", imp_forced_val=1)(*args)
def ev_out_insn(self, *args):
return self._get_notify("out_insn", mandatory_impl="ev_out_insn", imp_forced_val=True)(*args)
def ev_out_mnem(self, *args):
return self._get_notify("out_mnem", add_prefix=False, imp_forced_val=1)(*args)
def ev_out_operand(self, *args):
rc = self._get_notify("out_operand", mandatory_impl="ev_out_operand", imp_forced_val=1)(*args)
return rc > 0
def ev_out_data(self, *args):
return self._get_notify("out_data", imp_forced_val=1)(*args)
def ev_out_label(self, *args):
return self._get_notify("out_label")(*args)
def ev_out_special_item(self, *args):
return self._get_notify("out_special_item")(*args)
def ev_gen_regvar_def(self, ctx, v):
return self._get_notify("gen_regvar_def")(ctx, v.canon, v.user, v.cmt)
def ev_gen_src_file_lnnum(self, *args):
return self._get_notify("gen_src_file_lnnum")(*args)
def ev_creating_segm(self, s):
sname = ida_segment.get_visible_segm_name(s)
sclass = ida_segment.get_segm_class(s)
return self._get_notify("creating_segm")(s.start_ea, sname, sclass)
def ev_moving_segm(self, s, to_ea, flags):
sname = ida_segment.get_visible_segm_name(s)
sclass = ida_segment.get_segm_class(s)
return self._get_notify("moving_segm")(s.start_ea, sname, sclass, to_ea, flags)
def ev_coagulate(self, *args):
return self._get_notify("coagulate")(*args)
def ev_undefine(self, *args):
return self._get_notify("undefine")(*args)
def ev_treat_hindering_item(self, *args):
return self._get_notify("treat_hindering_item")(*args)
def ev_rename(self, *args):
return self._get_notify("rename")(*args)
def ev_is_far_jump(self, *args):
rc = self._get_notify("is_far_jump", unimp_val=False)(*args)
return 1 if rc else -1
def ev_is_sane_insn(self, *args):
return self._get_notify("is_sane_insn")(*args)
def ev_is_call_insn(self, *args):
return self._get_notify("is_call_insn")(*args)
def ev_is_ret_insn(self, *args):
return self._get_notify("is_ret_insn")(*args)
def ev_may_be_func(self, *args):
return self._get_notify("may_be_func")(*args)
def ev_is_basic_block_end(self, *args):
return self._get_notify("is_basic_block_end")(*args)
def ev_is_indirect_jump(self, *args):
return self._get_notify("is_indirect_jump")(*args)
def ev_is_insn_table_jump(self, *args):
return self._get_notify("is_insn_table_jump")(*args)
def ev_is_switch(self, *args):
rc = self._get_notify("is_switch")(*args)
return 1 if rc else 0
def ev_create_switch_xrefs(self, *args):
return self._get_notify("create_switch_xrefs", imp_forced_val=1)(*args)
def ev_is_align_insn(self, *args):
return self._get_notify("is_align_insn")(*args)
def ev_is_alloca_probe(self, *args):
return self._get_notify("is_alloca_probe")(*args)
def ev_is_sp_based(self, mode, insn, op):
rc = self._get_notify("is_sp_based", unimp_val=None)(insn, op)
if type(rc) == int:
ida_pro.int_pointer.frompointer(mode).assign(rc)
return 1
return 0
def ev_can_have_type(self, *args):
rc = self._get_notify("can_have_type")(*args)
if rc is True:
return 1
elif rc is False:
return -1
else:
return 0
def ev_cmp_operands(self, *args):
rc = self._get_notify("cmp_operands")(*args)
if rc is True:
return 1
elif rc is False:
return -1
else:
return 0
def ev_get_operand_string(self, buf, insn, opnum):
rc = self._get_notify("get_operand_string")(insn, opnum)
if rc:
return 1
return 0
def ev_str2reg(self, *args):
rc = self._get_notify("notify_str2reg", unimp_val=-1)(*args)
return 0 if rc < 0 else rc + 1
def ev_get_autocmt(self, *args):
return self._get_notify("get_autocmt")(*args)
def ev_func_bounds(self, _possible_return_code, pfn, max_func_end_ea):
possible_return_code = ida_pro.int_pointer.frompointer(_possible_return_code)
rc = self._get_notify("func_bounds", unimp_val=None)(
possible_return_code.value(),
pfn.start_ea,
max_func_end_ea)
if type(rc) == int:
possible_return_code.assign(rc)
return 0
def ev_verify_sp(self, pfn):
return self._get_notify("verify_sp")(pfn.start_ea)
def ev_verify_noreturn(self, pfn):
return self._get_notify("verify_noreturn")(pfn.start_ea)
def ev_create_func_frame(self, pfn):
rc = self._get_notify("create_func_frame", imp_forced_val=1)(pfn.start_ea)
if rc is True:
return 1
elif rc is False:
return -1
else:
return rc
def ev_get_frame_retsize(self, frsize, pfn):
rc = self._get_notify("get_frame_retsize", unimp_val=None)(pfn.start_ea)
if type(rc) == int:
ida_pro.int_pointer.frompointer(frsize).assign(rc)
return 1
return 0
def ev_coagulate_dref(self, from_ea, to_ea, may_define, _code_ea):
code_ea = ida_pro.ea_pointer.frompointer(_code_ea)
rc = self._get_notify("coagulate_dref")(from_ea, to_ea, may_define, code_ea.value())
if rc == -1:
return -1
if rc != 0:
code_ea.assign(rc)
return 0
def ev_may_show_sreg(self, *args):
return self._get_notify("may_show_sreg")(*args)
def ev_auto_queue_empty(self, *args):
return self._get_notify("auto_queue_empty")(*args)
def ev_validate_flirt_func(self, *args):
return self._get_notify("validate_flirt_func")(*args)
def ev_assemble(self, *args):
return self._get_notify("assemble")(*args)
def ev_gen_map_file(self, nlines, fp):
import ida_fpro
qfile = ida_fpro.qfile_t_from_fp(fp)
rc = self._get_notify("gen_map_file")(qfile)
if rc > 0:
ida_pro.int_pointer.frompointer(nlines).assign(rc)
return 1
else:
return 0
def ev_calc_step_over(self, target, ip):
rc = self._get_notify("calc_step_over", unimp_val=None)(ip)
if rc is not None and rc != ida_idaapi.BADADDR:
ida_pro.ea_pointer.frompointer(target).assign(rc)
return 1
return 0
# IDB hooks handling
def closebase(self, *args):
self._get_notify("closebase")(*args)
def savebase(self, *args):
self._get_notify("savebase")(*args)
def auto_empty(self, *args):
self._get_notify("auto_empty")(*args)
def auto_empty_finally(self, *args):
self._get_notify("auto_empty_finally")(*args)
def determined_main(self, *args):
self._get_notify("determined_main")(*args)
def idasgn_loaded(self, *args):
self._get_notify("load_idasgn")(*args)
def kernel_config_loaded(self, *args):
self._get_notify("kernel_config_loaded")(*args)
def compiler_changed(self, *args):
self._get_notify("set_compiler")(*args)
def segm_moved(self, from_ea, to_ea, size, changed_netmap):
s = ida_segment.getseg(to_ea)
sname = ida_segment.get_visible_segm_name(s)
sclass = ida_segment.get_segm_class(s)
self._get_notify("move_segm")(from_ea, to_ea, sname, sclass, changed_netmap)
def func_added(self, pfn):
self._get_notify("add_func")(pfn.start_ea)
def set_func_start(self, *args):
self._get_notify("set_func_start")(*args)
def set_func_end(self, *args):
self._get_notify("set_func_end")(*args)
def deleting_func(self, pfn):
self._get_notify("del_func")(pfn.start_ea)
def sgr_changed(self, *args):
self._get_notify("setsgr")(*args)
def make_code(self, *args):
self._get_notify("make_code")(*args)
def make_data(self, *args):
self._get_notify("make_data")(*args)
def renamed(self, *args):
self._get_notify("renamed")(*args)
# ----------------------------------------------------------------------
class __ph(object):
id = property(lambda self: ph_get_id())
cnbits = property(lambda self: ph_get_cnbits())
dnbits = property(lambda self: ph_get_dnbits())
flag = property(lambda self: ph_get_flag())
icode_return = property(lambda self: ph_get_icode_return())
instruc = property(lambda self: ph_get_instruc())
instruc_end = property(lambda self: ph_get_instruc_end())
instruc_start = property(lambda self: ph_get_instruc_start())
reg_code_sreg = property(lambda self: ph_get_reg_code_sreg())
reg_data_sreg = property(lambda self: ph_get_reg_data_sreg())
reg_first_sreg = property(lambda self: ph_get_reg_first_sreg())
reg_last_sreg = property(lambda self: ph_get_reg_last_sreg())
regnames = property(lambda self: ph_get_regnames())
segreg_size = property(lambda self: ph_get_segreg_size())
tbyte_size = property(lambda self: ph_get_tbyte_size())
version = property(lambda self: ph_get_version())
def str2sreg(name: str):
"""get segment register number from its name or -1"""
rn = ph_get_regnames()
for i in range(ph_get_reg_first_sreg(), ph_get_reg_last_sreg()+1):
if name.lower()==rn[i].lower():
return i
return -1
ph = __ph()
#</pycode(py_idp)>