Repository URL to install this package:
Version:
9.1~250226-5.fc43 ▾
|
"""
summary: dynamically provide a custom call type
description:
This plugin can greatly improve decompilation of indirect calls:
call [eax+4]
For them, the decompiler has to guess the prototype of the called function.
This has to be done at a very early phase of decompilation because
the function prototype influences the data flow analysis. On the other
hand, we do not have global data flow analysis results yet because
we haven't analyzed all calls in the function. It is a chicked-and-egg
problem.
The decompiler uses various techniques to guess the called function
prototype. While it works very well, it may fail in some cases.
To fix, the user can specify the call prototype manually, using
"Edit, Operand types, Set operand type" at the call instruction.
This plugin illustrates another approach to the problem:
if you happen to be able to calculate the call prototypes dynamically,
this is how to inform the decompiler about them.
level: intermediate
"""
import ida_idaapi
import ida_nalt
import ida_kernwin
import ida_typeinf
import ida_hexrays
testing = False # only for testing purposes
class callinfo_provider_t(ida_hexrays.Hexrays_Hooks):
# this callback will be called for all call instructions
# our plugin may provide the function prototype or even a complete new callinfo
# object. The callinfo object may be useful if the prototype is not enough
# to express all details of the call.
def build_callinfo(self, blk, type):
# it is a good idea to skip direct calls.
# note that some indirect calls may be resolved and become direct calls,
# and will be filtered out here:
ida_kernwin.msg("%x: got called for: %s\n" % (blk.tail.ea, blk.tail.dstr()))
tail = blk.tail
if tail.opcode == ida_hexrays.m_call:
return
# also, if the type was specified by the user, do not interfere
call_ea = tail.ea
tif = ida_typeinf.tinfo_t()
if ida_nalt.get_op_tinfo(tif, call_ea, 0):
return
global testing
if not testing:
# ok, the decompiler really has to guess the type.
# just for the sake of an example, return a predefined prototype.
# in real life you will provide the prototype you discovered yourself,
# using your magic of yours :)
my_proto = "int f();"
ida_kernwin.msg("%x: providing prototype %s\n" % (call_ea, my_proto))
ida_typeinf.parse_decl(type, None, my_proto, 0)
else:
# as an alternative to filling 'type', you can
# choose to return a mcallinfo_t instance.
mi = ida_hexrays.mcallinfo_t()
mi.cc = ida_typeinf.CM_CC_STDCALL | ida_typeinf.CM_N32_F48 # let's use stdcall to differentiate from the tinfo_t-filling version
mi.return_type = ida_typeinf.tinfo_t(ida_typeinf.BT_INT)
mi.return_argloc.set_reg1(0) # eax
return mi
# a plugin interface, boilerplate code
class my_plugin_t(ida_idaapi.plugin_t):
flags = ida_idaapi.PLUGIN_HIDE
wanted_name = "Hex-Rays custom prototype provider (IDAPython)"
wanted_hotkey = ""
comment = "Sample plugin21 for Hex-Rays decompiler"
help = ""
def init(self):
if ida_hexrays.init_hexrays_plugin():
self.hooks = callinfo_provider_t()
self.hooks.hook()
ida_kernwin.warning(
"Installed callinfo provider sample (vds21.py)\n" +\
"Please note that it is just an example\n" +\
"and will spoil your decompilations!")
return ida_idaapi.PLUGIN_KEEP # keep us in the memory
def term(self):
self.hooks.unhook()
def run(self, arg):
pass
def PLUGIN_ENTRY():
return my_plugin_t()