# -------------------------------------------------------------------------- import os import sys import idaapi import _idaapi from sys import getrefcount import gc try: import pywraps pywraps_there = True _idaapi.pyw_register_idc_func = pywraps.pyw_register_idc_func _idaapi.pyw_unregister_idc_func = pywraps.pyw_unregister_idc_func _idaapi.py_get_call_idc_func = pywraps.py_get_call_idc_func _idaapi.py_set_idc_func_ex = pywraps.py_set_idc_func_ex except Exception as e: pywraps_there = False print("exception: %s" % str(e)) print("Using PyWraps: %s" % pywraps_there) # -------------------------------------------------------------------------- # try: import types import ctypes # Callback for IDC func callback (On Windows, we use stdcall) # typedef error_t idaapi idc_func_t(idc_value_t *argv,idc_value_t *r); _IDCFUNC_CB_T = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p) # A trampoline function that is called from idcfunc_t that will # call the Python callback with the argv and r properly serialized to python call_idc_func__ = ctypes.CFUNCTYPE(ctypes.c_long)(_idaapi.py_get_call_idc_func()) except: def call_idc_func__(*args): warning("IDC extensions need ctypes library in order to work") return 0 try: _IDCFUNC_CB_T = CFUNCTYPE(c_int, c_void_p, c_void_p) except: _IDCFUNC_CB_T = None # -------------------------------------------------------------------------- EXTFUN_BASE = 0x0001 """requires open database""" EXTFUN_NORET = 0x0002 """does not return. the interpreter may clean up its state before calling it.""" EXTFUN_SAFE = 0x0004 """thread safe function. may be called""" # -------------------------------------------------------------------------- class _IdcFunction(object): """ Internal class that calls pyw_call_idc_func() with a context """ def __init__(self, ctxptr): self.ctxptr = ctxptr # Take a reference to the ctypes callback # (note: this will create a circular reference) self.cb = _IDCFUNC_CB_T(self) fp_ptr = property(lambda self: ctypes.cast(self.cb, ctypes.c_void_p).value) def __call__(self, args, res): return call_idc_func__(self.ctxptr, args, res) # -------------------------------------------------------------------------- # Dictionary to remember IDC function names along with the context pointer # retrieved by using the internal pyw_register_idc_func() __IDC_FUNC_CTXS = {} # -------------------------------------------------------------------------- def set_idc_func_ex(name, fp=None, args=(), flags=0): """ Extends the IDC language by exposing a new IDC function that is backed up by a Python function This function also unregisters the IDC function if 'fp' was passed as None @param name: IDC function name to expose @param fp: Python callable that will receive the arguments and return a tuple. If this argument is None then the IDC function is unregistered @param args: Arguments. A tuple of idaapi.VT_XXX constants @param flags: IDC function flags. A combination of EXTFUN_XXX constants @return: Boolean. """ global __IDC_FUNC_CTXS # Get the context f = __IDC_FUNC_CTXS.get(name, None) # Unregistering? if fp is None: # Not registered? if f is None: return False # Break circular reference del f.cb # Delete the name from the dictionary del __IDC_FUNC_CTXS[name] # Delete the context and unregister the function return _idaapi.pyw_unregister_idc_func(f.ctxptr) # Registering a function that is already registered? if f is not None: # Unregister it first set_idc_func_ex(name, None) # Convert the tupple argument info to a string args = "".join([chr(x) for x in args]) # Create a context ctxptr = _idaapi.pyw_register_idc_func(name, args, fp) if ctxptr == 0: return False # Bind the context with the IdcFunc object f = _IdcFunction(ctxptr) # Remember the Python context __IDC_FUNC_CTXS[name] = f # Register IDC function with a callback return _idaapi.py_set_idc_func_ex( name, f.fp_ptr, args, flags) # # -------------------------------------------------------------------------- def test1(): global MY_IDC_FUNC try: # Already registered? MY_IDC_FUNC # Unregister print("Unregistering function") set_idc_func_ex(MY_IDC_FUNC) except: MY_IDC_FUNC = "pysum" ok = set_idc_func_ex(MY_IDC_FUNC, my_idc_sum, (idaapi.VT_LONG, idaapi.VT_LONG), 0) if not ok: del MY_IDC_FUNC # # -------------------------------------------------------------------------- # def py_power(n, e): return n ** e ok = set_idc_func_ex("pow", py_power, (idaapi.VT_LONG, idaapi.VT_LONG), 0) if ok: print("Now the pow() will be present IDC!") else: print("Failed to register pow() IDC function") #