mirror of
https://github.com/cemu-project/idapython.git
synced 2025-01-15 19:39:13 +01:00
IDAPython 1.3.0 / IDA Pro 5.6
(For older versions please use the 1.2.90 branch)
This commit is contained in:
parent
ab7a03431e
commit
277facf240
28
BUILDING.txt
28
BUILDING.txt
@ -9,8 +9,8 @@ REQUIREMENTS
|
|||||||
|
|
||||||
[Tested versions are in brackets]
|
[Tested versions are in brackets]
|
||||||
|
|
||||||
- IDA and IDA SDK [5.4]
|
- IDA and IDA SDK [5.6]
|
||||||
http://www.datarescue.com/idabase/
|
http://www.hex-rays.com/idapro/
|
||||||
|
|
||||||
- Python [2.5.1, 2.6.1]
|
- Python [2.5.1, 2.6.1]
|
||||||
http://www.python.org/
|
http://www.python.org/
|
||||||
@ -38,26 +38,26 @@ Make sure all the needed tools (compiler, swig) are on the PATH.
|
|||||||
1, Unpack the IDAPython source and IDA Pro SDK into the following
|
1, Unpack the IDAPython source and IDA Pro SDK into the following
|
||||||
directory structure:
|
directory structure:
|
||||||
|
|
||||||
swigsdk-versions/5.4/ - version 5.4 of the IDA Pro SDK
|
swigsdk-versions/5.6/ - version 5.4 of the IDA Pro SDK
|
||||||
idapython/ - IDAPython source code
|
idapython/ - IDAPython source code
|
||||||
|
|
||||||
2, Patch the SDK using GNU Patch with one of patches from patches/ directory.
|
2, On Mac OS X copy libida.dylib from the IDA install directory to
|
||||||
You will have to use the -P option depending on which directory you
|
swigsdk-versions/5.6/lib/gcc32.mac/
|
||||||
patch from. This step is not required if there is no SDK patch.
|
|
||||||
|
|
||||||
3, On Mac OS X copy libida.dylib from the IDA install directory to
|
|
||||||
swigsdk-versions/5.4/libgcc32.mac/
|
|
||||||
and libida64.dylib to
|
and libida64.dylib to
|
||||||
swigsdk-versions/5.4/libgcc64.mac/
|
swigsdk-versions/5.6/lib/gcc64.mac/
|
||||||
|
|
||||||
4, Build the plugin
|
3, Build the plugin
|
||||||
|
|
||||||
python build.py
|
python build.py
|
||||||
|
|
||||||
It is possible to build the plugin for different Python versions by
|
It is possible to build the plugin for different Python versions by
|
||||||
running build.py with the corresponding Python binary. The option
|
running build.py with the corresponding Python binary.
|
||||||
--ea64 builds the 64-bit version as well.
|
|
||||||
|
Some build options:
|
||||||
|
--ea64: builds the 64-bit version
|
||||||
|
--no-early-load: builds the IDAPython plugin w/o PLUGIN_FIX plugin flag
|
||||||
|
(This flag disables the ability to write file loaders in IDAPython)
|
||||||
|
|
||||||
5, Install the components as described in README.txt
|
4, Install the components as described in README.txt
|
||||||
|
|
||||||
See build.py for build details and possible tweaks.
|
See build.py for build details and possible tweaks.
|
||||||
|
11
README.txt
11
README.txt
@ -61,6 +61,15 @@ Start IDA with the following command line options:
|
|||||||
If you want fully unattended execution mode, make sure your script
|
If you want fully unattended execution mode, make sure your script
|
||||||
exits with a qexit() call.
|
exits with a qexit() call.
|
||||||
|
|
||||||
|
By default scripts run after the database is opened. Extended option
|
||||||
|
format is:
|
||||||
|
|
||||||
|
-OIDAPython:[N;]script.py
|
||||||
|
|
||||||
|
Where N can be:
|
||||||
|
0: run script after opening database (default)
|
||||||
|
1: run script when UI is ready
|
||||||
|
2: run script immediately on plugin load (shortly after IDA starts and before processor modules and loaders)
|
||||||
|
|
||||||
User init file:
|
User init file:
|
||||||
|
|
||||||
@ -71,7 +80,7 @@ ${HOME}/.idapro/
|
|||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
C:\Documents and Settings\%USER%\Application Data\Hex-Rays\IDA Pro
|
%AppData%\Hex-Rays\IDA Pro
|
||||||
|
|
||||||
The user init file is read and executed at the end of the init process.
|
The user init file is read and executed at the end of the init process.
|
||||||
|
|
||||||
|
16
build.py
16
build.py
@ -22,7 +22,7 @@ from distutils import sysconfig
|
|||||||
# Start of user configurable options
|
# Start of user configurable options
|
||||||
VERBOSE = True
|
VERBOSE = True
|
||||||
IDA_MAJOR_VERSION = 5
|
IDA_MAJOR_VERSION = 5
|
||||||
IDA_MINOR_VERSION = 5
|
IDA_MINOR_VERSION = 6
|
||||||
if 'IDA' in os.environ:
|
if 'IDA' in os.environ:
|
||||||
IDA_SDK = os.environ['IDA']
|
IDA_SDK = os.environ['IDA']
|
||||||
else:
|
else:
|
||||||
@ -32,8 +32,8 @@ else:
|
|||||||
|
|
||||||
# IDAPython version
|
# IDAPython version
|
||||||
VERSION_MAJOR = 1
|
VERSION_MAJOR = 1
|
||||||
VERSION_MINOR = 2
|
VERSION_MINOR = 3
|
||||||
VERSION_PATCH = 90
|
VERSION_PATCH = 0
|
||||||
|
|
||||||
# Determine Python version
|
# Determine Python version
|
||||||
PYTHON_MAJOR_VERSION = int(platform.python_version()[0])
|
PYTHON_MAJOR_VERSION = int(platform.python_version()[0])
|
||||||
@ -296,7 +296,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
|
|||||||
platform_macros = [ "__LINUX__" ]
|
platform_macros = [ "__LINUX__" ]
|
||||||
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "lib"
|
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "lib"
|
||||||
python_library = "-lpython%d.%d" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
|
python_library = "-lpython%d.%d" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
|
||||||
ida_libpath = os.path.join(idasdkdir, ea64 and "libgcc64.lnx" or "libgcc32.lnx")
|
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "gcc64.lnx" or "gcc32.lnx")
|
||||||
ida_lib = ""
|
ida_lib = ""
|
||||||
extra_link_parameters = ""
|
extra_link_parameters = ""
|
||||||
# Platform-specific settings for the Windows build
|
# Platform-specific settings for the Windows build
|
||||||
@ -305,7 +305,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
|
|||||||
platform_macros = [ "__NT__" ]
|
platform_macros = [ "__NT__" ]
|
||||||
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "libs"
|
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "libs"
|
||||||
python_library = "python%d%d.lib" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
|
python_library = "python%d%d.lib" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
|
||||||
ida_libpath = os.path.join(idasdkdir, ea64 and "libvc.w64" or "libvc.w32")
|
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "vc.w64" or "vc.w32")
|
||||||
ida_lib = "ida.lib"
|
ida_lib = "ida.lib"
|
||||||
SWIG_OPTIONS += " -D__NT__ "
|
SWIG_OPTIONS += " -D__NT__ "
|
||||||
extra_link_parameters = ""
|
extra_link_parameters = ""
|
||||||
@ -316,7 +316,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
|
|||||||
platform_macros = [ "__MAC__" ]
|
platform_macros = [ "__MAC__" ]
|
||||||
python_libpath = "."
|
python_libpath = "."
|
||||||
python_library = "-framework Python"
|
python_library = "-framework Python"
|
||||||
ida_libpath = os.path.join(idasdkdir, ea64 and "libgcc64.mac" or "libgcc32.mac")
|
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "gcc64.mac64" or "gcc32.mac")
|
||||||
ida_lib = ea64 and "-lida64" or "-lida"
|
ida_lib = ea64 and "-lida64" or "-lida"
|
||||||
extra_link_parameters = ""
|
extra_link_parameters = ""
|
||||||
|
|
||||||
@ -326,7 +326,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
|
|||||||
if ea64:
|
if ea64:
|
||||||
platform_macros.append("__EA64__")
|
platform_macros.append("__EA64__")
|
||||||
|
|
||||||
if '--early-load' in sys.argv:
|
if not '--no-early-load' in sys.argv:
|
||||||
platform_macros.append("PLUGINFIX")
|
platform_macros.append("PLUGINFIX")
|
||||||
|
|
||||||
# Build the wrapper from the interface files
|
# Build the wrapper from the interface files
|
||||||
@ -394,7 +394,7 @@ def build_binary_package(ea64, nukeold):
|
|||||||
binmanifest = []
|
binmanifest = []
|
||||||
if nukeold:
|
if nukeold:
|
||||||
binmanifest.extend(BINDIST_MANIFEST)
|
binmanifest.extend(BINDIST_MANIFEST)
|
||||||
binmanifest.extend([(x, ea64 and "python64" or "python") for x in "python/init.py", "python/idc.py", "python/idautils.py", "idaapi.py"])
|
binmanifest.extend([(x, "python") for x in "python/init.py", "python/idc.py", "python/idautils.py", "idaapi.py"])
|
||||||
binmanifest.append((plugin_name, "plugins"))
|
binmanifest.append((plugin_name, "plugins"))
|
||||||
build_distribution(binmanifest, BINDISTDIR, ea64, nukeold)
|
build_distribution(binmanifest, BINDISTDIR, ea64, nukeold)
|
||||||
|
|
||||||
|
595
python.cpp
595
python.cpp
@ -48,15 +48,20 @@ extern "C"
|
|||||||
|
|
||||||
#define IDAPYTHON_DATA_STATEMENT 0
|
#define IDAPYTHON_DATA_STATEMENT 0
|
||||||
|
|
||||||
#ifdef __EA64__
|
|
||||||
#define PYTHON_DIR_NAME "python64"
|
|
||||||
#else
|
|
||||||
#define PYTHON_DIR_NAME "python"
|
#define PYTHON_DIR_NAME "python"
|
||||||
#endif
|
|
||||||
|
|
||||||
void init_idaapi(void);
|
void init_idaapi(void);
|
||||||
void idaapi run(int arg);
|
void idaapi run(int arg);
|
||||||
static int initialized = 0;
|
static int initialized = 0;
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Some utility functions from pywraps / idaapi
|
||||||
|
int idcvar_to_pyvar(const idc_value_t &idc_var, PyObject **py_var);
|
||||||
|
int pyvar_to_idcvar(PyObject *py_var, idc_value_t *idc_var, int *gvar_sn = NULL);
|
||||||
|
PyObject *PyObject_TryGetAttrString(PyObject *py_var, const char *attr);
|
||||||
|
bool PyGetError(qstring *out = NULL);
|
||||||
|
bool init_pywraps();
|
||||||
|
void deinit_pywraps();
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
/* This is a simple tracing code for debugging purposes. */
|
/* This is a simple tracing code for debugging purposes. */
|
||||||
/* It might evolve into a tracing facility for user scripts. */
|
/* It might evolve into a tracing facility for user scripts. */
|
||||||
@ -141,34 +146,99 @@ void end_execution()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return a formatted error or just print it to the console */
|
||||||
|
static void handle_python_error(char *errbuf, size_t errbufsize)
|
||||||
|
{
|
||||||
|
PyObject *result;
|
||||||
|
PyObject *ptype, *pvalue, *ptraceback;
|
||||||
|
|
||||||
|
if ( errbufsize > 0 )
|
||||||
|
errbuf[0] = '\0';
|
||||||
|
|
||||||
|
if (PyErr_Occurred())
|
||||||
|
{
|
||||||
|
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
|
||||||
|
result = PyObject_Repr(pvalue);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
qsnprintf(errbuf, errbufsize, "ERROR: %s", PyString_AsString(result));
|
||||||
|
PyErr_Clear();
|
||||||
|
Py_XDECREF(ptype);
|
||||||
|
Py_XDECREF(pvalue);
|
||||||
|
Py_XDECREF(ptraceback);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PyErr_Print();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* helper function to get globals for the __main__ module */
|
||||||
|
PyObject *GetMainGlobals()
|
||||||
|
{
|
||||||
|
PyObject *module = PyImport_AddModule("__main__");
|
||||||
|
if (module == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return PyModule_GetDict(module);
|
||||||
|
}
|
||||||
|
|
||||||
/* Simple Python statement runner function for IDC */
|
/* Simple Python statement runner function for IDC */
|
||||||
static const char idc_runpythonstatement_args[] = { VT_STR, 0 };
|
static const char idc_runpythonstatement_args[] = { VT_STR2, 0 };
|
||||||
static error_t idaapi idc_runpythonstatement(idc_value_t *argv, idc_value_t *res)
|
static error_t idaapi idc_runpythonstatement(idc_value_t *argv, idc_value_t *res)
|
||||||
{
|
{
|
||||||
begin_execution();
|
PyObject *globals = GetMainGlobals();
|
||||||
res->num = PyRun_SimpleString(argv[0].str);
|
if (globals == NULL)
|
||||||
end_execution();
|
{
|
||||||
|
res->set_string("internal error");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PyErr_Clear();
|
||||||
|
begin_execution();
|
||||||
|
PyObject *result = PyRun_String(argv[0].c_str(), Py_file_input, globals, globals );
|
||||||
|
end_execution();
|
||||||
|
Py_XDECREF(result);
|
||||||
|
if ( result == NULL || PyErr_Occurred() )
|
||||||
|
{
|
||||||
|
char errbuf[MAXSTR];
|
||||||
|
handle_python_error(errbuf, sizeof(errbuf));
|
||||||
|
*res = idc_value_t(errbuf);
|
||||||
|
if ( errbuf[0] == '\0' )
|
||||||
|
res->set_string("internal error");
|
||||||
|
else
|
||||||
|
res->set_string(errbuf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// success
|
||||||
|
res->set_long(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
return eOk;
|
return eOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* QuickFix for the FILE* incompatibility problem */
|
/* QuickFix for the FILE* incompatibility problem */
|
||||||
int ExecFile(const char *FileName)
|
int ExecFile(const char *FileName)
|
||||||
{
|
{
|
||||||
PyObject* PyFileObject = PyFile_FromString((char*)FileName, "r");
|
PyObject *PyFileObject = PyFile_FromString((char*)FileName, "r");
|
||||||
|
|
||||||
if (!PyFileObject)
|
PyObject *globals = GetMainGlobals();
|
||||||
|
if (globals == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (PyRun_SimpleFile(PyFile_AsFile(PyFileObject), FileName) == 0)
|
PyErr_Clear();
|
||||||
|
PyObject *result = PyRun_File(PyFile_AsFile(PyFileObject), FileName, Py_file_input, globals, globals);
|
||||||
|
|
||||||
|
Py_XDECREF(PyFileObject);
|
||||||
|
Py_XDECREF(result);
|
||||||
|
if ( result == NULL || PyErr_Occurred() )
|
||||||
{
|
{
|
||||||
Py_DECREF(PyFileObject);
|
if ( !PyErr_Occurred() )
|
||||||
return 1;
|
PyErr_Print();
|
||||||
}
|
return 0;
|
||||||
else
|
|
||||||
{
|
|
||||||
Py_DECREF(PyFileObject);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for the presence of a file in IDADIR/python */
|
/* Check for the presence of a file in IDADIR/python */
|
||||||
@ -188,11 +258,11 @@ bool CheckFile(char *filename)
|
|||||||
|
|
||||||
/* Execute the Python script from the plugin */
|
/* Execute the Python script from the plugin */
|
||||||
/* Default hotkey: Alt-9 */
|
/* Default hotkey: Alt-9 */
|
||||||
void IDAPython_RunScript(char *script)
|
void IDAPython_RunScript(const char *script)
|
||||||
{
|
{
|
||||||
char statement[MAXSTR+32];
|
char statement[MAXSTR+32];
|
||||||
char slashpath[MAXSTR+1];
|
char slashpath[MAXSTR+1];
|
||||||
char *scriptpath;
|
const char *scriptpath;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -255,15 +325,13 @@ void IDAPython_RunStatement(void)
|
|||||||
/* Default hotkey: Alt-7 */
|
/* Default hotkey: Alt-7 */
|
||||||
void IDAPython_ScriptBox(void)
|
void IDAPython_ScriptBox(void)
|
||||||
{
|
{
|
||||||
PyObject *module;
|
|
||||||
PyObject *dict;
|
PyObject *dict;
|
||||||
PyObject *scriptbox;
|
PyObject *scriptbox;
|
||||||
PyObject *pystr;
|
PyObject *pystr;
|
||||||
|
|
||||||
/* Get globals() */
|
/* Get globals() */
|
||||||
/* These two should never fail */
|
/* This should never fail */
|
||||||
module = PyImport_AddModule("__main__");
|
dict = GetMainGlobals();
|
||||||
dict = PyModule_GetDict(module);
|
|
||||||
|
|
||||||
scriptbox = PyDict_GetItemString(dict, "scriptbox");
|
scriptbox = PyDict_GetItemString(dict, "scriptbox");
|
||||||
|
|
||||||
@ -296,37 +364,52 @@ void IDAPython_ScriptBox(void)
|
|||||||
|
|
||||||
bool idaapi IDAPython_Menu_Callback(void *ud)
|
bool idaapi IDAPython_Menu_Callback(void *ud)
|
||||||
{
|
{
|
||||||
run((int)ud);
|
run((size_t)ud);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return a formatted error or just print it to the console */
|
|
||||||
static void handle_python_error(char *errbuf, size_t errbufsize)
|
//--------------------------------------------------------------------------
|
||||||
|
// This function parses a name into two different components (if it applies).
|
||||||
|
// The first mode of operation:
|
||||||
|
// split_mod_attr_name("modname.attrname", mod_buf, attr_buf)
|
||||||
|
// It splits the full name into two parts.
|
||||||
|
//
|
||||||
|
// The second mode of operation:
|
||||||
|
// split_mod_attr_name("c:\libs\x.py", file_name_buf, NULL)
|
||||||
|
//
|
||||||
|
static bool parse_py_modname(
|
||||||
|
const char *full_name,
|
||||||
|
char *modname,
|
||||||
|
char *attrname, size_t sz)
|
||||||
{
|
{
|
||||||
PyObject *result;
|
if (attrname == NULL)
|
||||||
PyObject *ptype, *pvalue, *ptraceback;
|
{
|
||||||
|
// take the filename.ext part
|
||||||
if ( errbufsize > 0 )
|
qstrncpy(modname, qbasename(full_name), sz);
|
||||||
errbuf[0] = '\0';
|
// take the filename part only
|
||||||
|
qsplitfile(modname, NULL, NULL);
|
||||||
if (PyErr_Occurred())
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const char *p = strchr(full_name, '.');
|
||||||
|
if (p == NULL)
|
||||||
{
|
{
|
||||||
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
|
qstrncpy(modname, "idaapi", sz);
|
||||||
result = PyObject_Repr(pvalue);
|
qstrncpy(attrname, full_name, sz);
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
qsnprintf(errbuf, errbufsize, "ERROR: %s", PyString_AsString(result));
|
|
||||||
PyErr_Clear();
|
|
||||||
Py_XDECREF(ptype);
|
|
||||||
Py_XDECREF(pvalue);
|
|
||||||
Py_XDECREF(ptraceback);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
PyErr_Print();
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qstrncpy(modname, full_name, p - full_name + 1);
|
||||||
|
qstrncpy(attrname, p + 1, sz);
|
||||||
|
}
|
||||||
|
return p != NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert return value from Python to IDC or report about an error */
|
/* Convert return value from Python to IDC or report about an error. */
|
||||||
|
/* This function also decrements the reference "result" (python variable) */
|
||||||
static bool return_python_result(idc_value_t *rv,
|
static bool return_python_result(idc_value_t *rv,
|
||||||
PyObject *result,
|
PyObject *result,
|
||||||
char *errbuf,
|
char *errbuf,
|
||||||
@ -340,48 +423,24 @@ static bool return_python_result(idc_value_t *rv,
|
|||||||
handle_python_error(errbuf, errbufsize);
|
handle_python_error(errbuf, errbufsize);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
bool ok = true;
|
||||||
if (PyInt_Check(result))
|
if (pyvar_to_idcvar(result, rv) <= 0)
|
||||||
{
|
{
|
||||||
rv->num = PyInt_AsLong(result);
|
qsnprintf(errbuf, errbufsize, "ERROR: bad return value");
|
||||||
rv->vtype = VT_LONG;
|
ok = false;
|
||||||
Py_XDECREF(result);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
Py_XDECREF(result);
|
||||||
if (PyString_Check(result))
|
return ok;
|
||||||
{
|
|
||||||
rv->str = (char *)qalloc(PyString_Size(result)+1);
|
|
||||||
if (!rv->str)
|
|
||||||
return false;
|
|
||||||
qstrncpy(rv->str, PyString_AsString(result), MAXSTR);
|
|
||||||
rv->vtype = VT_STR;
|
|
||||||
Py_XDECREF(result);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PyFloat_Check(result))
|
|
||||||
{
|
|
||||||
double dresult = PyFloat_AsDouble(result);
|
|
||||||
ieee_realcvt((void *)&dresult, rv->e, 3);
|
|
||||||
rv->vtype = VT_FLOAT;
|
|
||||||
Py_XDECREF(result);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
qsnprintf(errbuf, errbufsize, "ERROR: bad return value");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compile callback for Python external language evaluator */
|
/* Compile callback for Python external language evaluator */
|
||||||
bool idaapi IDAPython_extlang_compile(const char *name,
|
bool idaapi IDAPython_extlang_compile(const char *name,
|
||||||
ea_t /*current_ea*/,
|
ea_t /*current_ea*/,
|
||||||
const char *expr,
|
const char *expr,
|
||||||
char *errbuf,
|
char *errbuf,
|
||||||
size_t errbufsize)
|
size_t errbufsize)
|
||||||
{
|
{
|
||||||
PyObject *main = PyImport_AddModule("__main__"); QASSERT(main != NULL);
|
PyObject *globals = GetMainGlobals(); QASSERT(globals != NULL);
|
||||||
PyObject *globals = PyModule_GetDict(main); QASSERT(globals != NULL);
|
|
||||||
|
|
||||||
PyCodeObject *code = (PyCodeObject *)Py_CompileString(expr, "<string>", Py_eval_input);
|
PyCodeObject *code = (PyCodeObject *)Py_CompileString(expr, "<string>", Py_eval_input);
|
||||||
if (code == NULL)
|
if (code == NULL)
|
||||||
@ -413,77 +472,211 @@ bool idaapi IDAPython_extlang_compile(const char *name,
|
|||||||
|
|
||||||
/* Run callback for Python external language evaluator */
|
/* Run callback for Python external language evaluator */
|
||||||
bool idaapi IDAPython_extlang_run(const char *name,
|
bool idaapi IDAPython_extlang_run(const char *name,
|
||||||
int nargs,
|
int nargs,
|
||||||
const idc_value_t args[],
|
const idc_value_t args[],
|
||||||
idc_value_t *result,
|
idc_value_t *result,
|
||||||
char *errbuf,
|
char *errbuf,
|
||||||
size_t errbufsize)
|
size_t errbufsize)
|
||||||
{
|
{
|
||||||
// convert arguments to python
|
// convert arguments to python
|
||||||
qvector<PyObject *> pargs;
|
qvector<PyObject *> pargs;
|
||||||
|
qvector<bool> do_decref;
|
||||||
|
|
||||||
for (int i=0; i<nargs; i++)
|
bool ok = true;
|
||||||
|
|
||||||
|
PyObject *module(NULL);
|
||||||
|
char modname[MAXSTR] = {0};
|
||||||
|
char funcname[MAXSTR] = {0};
|
||||||
|
bool imported_module = parse_py_modname(name, modname, funcname, MAXSTR);
|
||||||
|
do
|
||||||
{
|
{
|
||||||
double dresult;
|
for (int i=0; i<nargs; i++)
|
||||||
PyObject *pa;
|
|
||||||
switch (args[i].vtype)
|
|
||||||
{
|
{
|
||||||
case VT_LONG:
|
PyObject *py_obj(NULL);
|
||||||
pa = PyInt_FromLong(args[i].num);
|
int cvt = idcvar_to_pyvar(args[i], &py_obj);
|
||||||
break;
|
if (cvt <= 0)
|
||||||
case VT_STR:
|
{
|
||||||
pa = PyString_FromString(args[i].str);
|
qsnprintf(errbuf, errbufsize, "arg#%d has wrong type %d", i, args[i].vtype);
|
||||||
break;
|
ok = false;
|
||||||
case VT_FLOAT:
|
break;
|
||||||
ieee_realcvt(&dresult, (ushort *)args[i].e, 013);
|
}
|
||||||
pa = PyFloat_FromDouble(dresult);
|
pargs.push_back(py_obj);
|
||||||
break;
|
// do not decrement reference of opaque objects
|
||||||
default:
|
do_decref.push_back(cvt == 1);
|
||||||
qsnprintf(errbuf, errbufsize, "arg#%d has wrong type %d", i, args[i].vtype);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
pargs.push_back(pa);
|
if (!ok)
|
||||||
}
|
break;
|
||||||
|
|
||||||
PyObject *main = PyImport_AddModule("__main__"); QASSERT(main != NULL);
|
if (imported_module)
|
||||||
PyObject *globals = PyModule_GetDict(main); QASSERT(globals != NULL);
|
{
|
||||||
PyObject *func = PyDict_GetItemString(globals, name);
|
module = PyImport_ImportModule(modname);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
module = PyImport_AddModule("__main__"); QASSERT(module != NULL);
|
||||||
|
}
|
||||||
|
PyObject *globals = PyModule_GetDict(module); QASSERT(globals != NULL);
|
||||||
|
PyObject *func = PyDict_GetItemString(globals, funcname);
|
||||||
|
|
||||||
if (func == NULL)
|
if (func == NULL)
|
||||||
{
|
{
|
||||||
qsnprintf(errbuf, errbufsize, "undefined function %s", name);
|
qsnprintf(errbuf, errbufsize, "undefined function %s", name);
|
||||||
return false;
|
ok = false;
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
PyCodeObject *code = (PyCodeObject *)PyFunction_GetCode(func);
|
PyCodeObject *code = (PyCodeObject *)PyFunction_GetCode(func);
|
||||||
PyObject *pres = PyEval_EvalCodeEx(code, globals, NULL, &pargs[0], nargs,
|
PyObject *pres = PyEval_EvalCodeEx(code, globals, NULL, &pargs[0], nargs,
|
||||||
NULL, 0, NULL, 0, NULL);
|
NULL, 0, NULL, 0, NULL);
|
||||||
|
|
||||||
|
ok = return_python_result(result, pres, errbuf, errbufsize);
|
||||||
|
} while (false);
|
||||||
|
|
||||||
// free argument objects
|
// free argument objects
|
||||||
for (int i=0; i<nargs; i++)
|
for (int i=0; i<nargs; i++)
|
||||||
Py_XDECREF(pargs[i]);
|
{
|
||||||
|
if (do_decref[i])
|
||||||
|
Py_DECREF(pargs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
return return_python_result(result, pres, errbuf, errbufsize);
|
if (imported_module)
|
||||||
|
Py_XDECREF(module);
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Compile callback for Python external language evaluator */
|
/* Compile callback for Python external language evaluator */
|
||||||
bool idaapi IDAPython_extlang_compile_file(const char *name,
|
bool idaapi IDAPython_extlang_compile_file(const char *script_path,
|
||||||
char *errbuf,
|
char *errbuf,
|
||||||
size_t errbufsize)
|
size_t errbufsize)
|
||||||
{
|
{
|
||||||
PyObject *main = PyImport_AddModule("__main__"); QASSERT(main != NULL);
|
PyObject *globals = GetMainGlobals(); QASSERT(globals != NULL);
|
||||||
PyObject *globals = PyModule_GetDict(main); QASSERT(globals != NULL);
|
|
||||||
|
|
||||||
if (!ExecFile(name))
|
if (!ExecFile(script_path))
|
||||||
{
|
{
|
||||||
handle_python_error(errbuf, errbufsize);
|
handle_python_error(errbuf, errbufsize);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char modname[MAXSTR] = {0};
|
||||||
|
parse_py_modname(script_path, modname, NULL, sizeof(modname));
|
||||||
|
// import the module using its absolute path
|
||||||
|
qstring s;
|
||||||
|
s.sprnt(
|
||||||
|
"import imp\n"
|
||||||
|
"imp.load_source('%s', r'%s')", modname, script_path);
|
||||||
|
PyRun_SimpleString(s.c_str());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Create an object instance */
|
||||||
|
bool idaapi IDAPython_extlang_create_object(
|
||||||
|
const char *name, // in: object class name
|
||||||
|
int nargs, // in: number of input arguments
|
||||||
|
const idc_value_t args[], // in: input arguments
|
||||||
|
idc_value_t *result, // out: created object or exception
|
||||||
|
char *errbuf, // out: error message if evaluation fails
|
||||||
|
size_t errbufsize) // in: size of the error buffer
|
||||||
|
{
|
||||||
|
PyObject *py_mod(NULL), *py_cls(NULL), *py_args(NULL);
|
||||||
|
bool ok = false;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Parse the object name (to get the module and class name)
|
||||||
|
char modname[MAXSTR] = {0};
|
||||||
|
char clsname[MAXSTR] = {0};
|
||||||
|
parse_py_modname(name, modname, clsname, MAXSTR);
|
||||||
|
|
||||||
|
// Get a reference to the module
|
||||||
|
py_mod = PyImport_ImportModule(modname);
|
||||||
|
if (py_mod == NULL)
|
||||||
|
{
|
||||||
|
qsnprintf(errbuf, errbufsize, "Could not import module %s!", modname);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Get the class reference
|
||||||
|
py_cls = PyObject_GetAttrString(py_mod, clsname);
|
||||||
|
if (py_cls == NULL)
|
||||||
|
{
|
||||||
|
qsnprintf(errbuf, errbufsize, "Could not find class %s!", clsname);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a tupple
|
||||||
|
py_args = PyTuple_New(nargs);
|
||||||
|
if (py_args == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Store all the converted arguments in the tupple
|
||||||
|
ok = true;
|
||||||
|
for (int i=0;i<nargs;i++)
|
||||||
|
{
|
||||||
|
PyObject *arg(NULL);
|
||||||
|
// Convert the argument
|
||||||
|
int cvt = idcvar_to_pyvar(args[i], &arg);
|
||||||
|
if (cvt <= 0)
|
||||||
|
{
|
||||||
|
qsnprintf(errbuf, errbufsize, "Failed while converting argument #%d", i);
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Opaque object?
|
||||||
|
if (cvt == 2)
|
||||||
|
{
|
||||||
|
// Increment reference for opaque objects.
|
||||||
|
// A tupple will steal references of its set items,
|
||||||
|
// and for an opaque object we want it to still exist
|
||||||
|
// even if the tuple is gone.
|
||||||
|
Py_INCREF(arg);
|
||||||
|
}
|
||||||
|
// Save it
|
||||||
|
// Steals the reference and that means we are no longer responsible
|
||||||
|
// for reference management of the items.
|
||||||
|
PyTuple_SetItem(py_args, i, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error during conversion?
|
||||||
|
if (!ok)
|
||||||
|
break;
|
||||||
|
ok = false;
|
||||||
|
|
||||||
|
// Call the constructor
|
||||||
|
PyObject *py_res = PyObject_Call(py_cls, py_args, NULL);
|
||||||
|
|
||||||
|
// Call failed?
|
||||||
|
if (py_res == NULL)
|
||||||
|
{
|
||||||
|
// Try to get a meaningful error string
|
||||||
|
qstring s;
|
||||||
|
if (!PyGetError(&s))
|
||||||
|
{
|
||||||
|
qsnprintf(errbuf, errbufsize, "Calling the constructor failed!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qstrncpy(errbuf, s.c_str(), errbufsize);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int r = pyvar_to_idcvar(py_res, result);
|
||||||
|
ok = r > 0;
|
||||||
|
// decrement reference only if not an opaque object
|
||||||
|
if (r == 1)
|
||||||
|
Py_DECREF(py_res);
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
Py_XDECREF(py_mod);
|
||||||
|
Py_XDECREF(py_cls);
|
||||||
|
|
||||||
|
// Free the arguments tuple
|
||||||
|
if (py_args != NULL)
|
||||||
|
Py_DECREF(py_args);
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns: success
|
||||||
|
|
||||||
/* Calculator callback for Python external language evaluator */
|
/* Calculator callback for Python external language evaluator */
|
||||||
bool idaapi IDAPython_extlang_calcexpr(ea_t /*current_ea*/,
|
bool idaapi IDAPython_extlang_calcexpr(ea_t /*current_ea*/,
|
||||||
const char *expr,
|
const char *expr,
|
||||||
@ -492,18 +685,16 @@ bool idaapi IDAPython_extlang_calcexpr(ea_t /*current_ea*/,
|
|||||||
size_t errbufsize)
|
size_t errbufsize)
|
||||||
{
|
{
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
PyObject *module = PyImport_AddModule("__main__");
|
|
||||||
|
|
||||||
if (module == NULL)
|
PyObject *globals = GetMainGlobals();
|
||||||
|
if (globals == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
PyObject *globals = PyModule_GetDict(module);
|
begin_execution();
|
||||||
|
|
||||||
begin_execution();
|
|
||||||
result = PyRun_String(expr, Py_eval_input, globals, globals);
|
result = PyRun_String(expr, Py_eval_input, globals, globals);
|
||||||
end_execution();
|
end_execution();
|
||||||
|
|
||||||
VarFree(rv);
|
rv->clear();
|
||||||
|
|
||||||
return return_python_result(rv, result, errbuf, errbufsize);
|
return return_python_result(rv, result, errbuf, errbufsize);
|
||||||
}
|
}
|
||||||
@ -517,25 +708,52 @@ extlang_t extlang_python =
|
|||||||
IDAPython_extlang_run,
|
IDAPython_extlang_run,
|
||||||
IDAPython_extlang_calcexpr,
|
IDAPython_extlang_calcexpr,
|
||||||
IDAPython_extlang_compile_file,
|
IDAPython_extlang_compile_file,
|
||||||
"py"
|
"py",
|
||||||
|
IDAPython_extlang_create_object
|
||||||
};
|
};
|
||||||
|
|
||||||
void enable_extlang_python(bool enable)
|
void enable_extlang_python(bool enable)
|
||||||
{
|
{
|
||||||
|
#if IDA_SDK_VERSION < 560
|
||||||
|
#define SELECT_EXTLANG register_extlang
|
||||||
|
#else
|
||||||
|
#define SELECT_EXTLANG select_extlang
|
||||||
|
#endif
|
||||||
if (enable)
|
if (enable)
|
||||||
register_extlang(&extlang_python);
|
SELECT_EXTLANG(&extlang_python);
|
||||||
else
|
else
|
||||||
register_extlang(NULL);
|
SELECT_EXTLANG(NULL);
|
||||||
|
#undef SELECT_EXTLANG
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IDA_SDK_VERSION >= 540
|
#if IDA_SDK_VERSION >= 540
|
||||||
/* Execute a line in the Python CLI */
|
/* Execute a line in the Python CLI */
|
||||||
bool idaapi IDAPython_cli_execute_line(const char *line)
|
bool idaapi IDAPython_cli_execute_line(const char *line)
|
||||||
{
|
{
|
||||||
begin_execution();
|
const char *first_line = strrchr(line, '\n');
|
||||||
PyRun_SimpleString(line);
|
if (first_line == NULL)
|
||||||
end_execution();
|
first_line = line;
|
||||||
return true;
|
else
|
||||||
|
first_line += 1;
|
||||||
|
|
||||||
|
// skip empty lines
|
||||||
|
if (first_line[0] != '\0')
|
||||||
|
{
|
||||||
|
// take a copy of the line so we r-trim it
|
||||||
|
char *tline = qstrdup(first_line);
|
||||||
|
trim(tline);
|
||||||
|
// line ends with ":" or begins with a space character?
|
||||||
|
bool more = tline[qstrlen(tline)-1] == ':' || isspace(first_line[0]);
|
||||||
|
qfree(tline);
|
||||||
|
|
||||||
|
if ( more )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
begin_execution();
|
||||||
|
PyRun_SimpleString(line);
|
||||||
|
end_execution();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cli_t cli_python =
|
cli_t cli_python =
|
||||||
@ -560,6 +778,12 @@ void enable_python_cli(bool enable)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Prints the IDAPython copyright banner */
|
||||||
|
void print_banner()
|
||||||
|
{
|
||||||
|
PyRun_SimpleString("print_banner()");
|
||||||
|
}
|
||||||
|
|
||||||
/* Install python menu items */
|
/* Install python menu items */
|
||||||
static void install_python_menus()
|
static void install_python_menus()
|
||||||
{
|
{
|
||||||
@ -593,22 +817,65 @@ static void install_python_menus()
|
|||||||
(void *)IDAPYTHON_SCRIPTBOX);
|
(void *)IDAPYTHON_SCRIPTBOX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum script_run_when {
|
||||||
|
run_on_db_open = 0, // run script after opening database (default)
|
||||||
|
run_on_ui_ready = 1, // run script when UI is ready
|
||||||
|
run_on_init = 2, // run script immediately on plugin load (shortly after IDA starts)
|
||||||
|
};
|
||||||
|
|
||||||
|
static int g_run_when = -1;
|
||||||
|
static char g_run_script[QMAXPATH];
|
||||||
|
|
||||||
|
/* Parse plugin options */
|
||||||
|
void parse_options()
|
||||||
|
{
|
||||||
|
const char *options = get_plugin_options("IDAPython");
|
||||||
|
if ( options == NULL )
|
||||||
|
return;
|
||||||
|
const char *p = strchr(options, ';');
|
||||||
|
if ( p == NULL )
|
||||||
|
{
|
||||||
|
g_run_when = run_on_db_open;
|
||||||
|
qstrncpy(g_run_script, options, sizeof(g_run_script));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_run_when = atoi(options);
|
||||||
|
qstrncpy(g_run_script, p+1, sizeof(g_run_script));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* we install the menu later because the text version crashes if
|
/* we install the menu later because the text version crashes if
|
||||||
add_menu_item is called too early */
|
add_menu_item is called too early */
|
||||||
static int idaapi menu_installer_cb(void *, int code, va_list)
|
static int idaapi menu_installer_cb(void *, int code, va_list)
|
||||||
{
|
{
|
||||||
if ( code != ui_ready_to_run )
|
const char *script;
|
||||||
return 0;
|
int when;
|
||||||
|
|
||||||
install_python_menus();
|
switch ( code )
|
||||||
unhook_from_notification_point(HT_UI, menu_installer_cb, NULL);
|
{
|
||||||
|
case ui_ready_to_run:
|
||||||
|
print_banner();
|
||||||
|
install_python_menus();
|
||||||
|
|
||||||
|
if ( g_run_when == run_on_ui_ready )
|
||||||
|
IDAPython_RunScript(g_run_script);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ui_database_inited:
|
||||||
|
if ( g_run_when == run_on_db_open )
|
||||||
|
IDAPython_RunScript(g_run_script);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the Python environment */
|
/* Initialize the Python environment */
|
||||||
bool IDAPython_Init(void)
|
bool IDAPython_Init(void)
|
||||||
{
|
{
|
||||||
char *options;
|
|
||||||
char tmp[MAXSTR+64];
|
char tmp[MAXSTR+64];
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
@ -631,9 +898,9 @@ bool IDAPython_Init(void)
|
|||||||
qsnprintf(tmp, sizeof(tmp), "libpython%d.%d.so",
|
qsnprintf(tmp, sizeof(tmp), "libpython%d.%d.so",
|
||||||
PY_MAJOR_VERSION,
|
PY_MAJOR_VERSION,
|
||||||
PY_MINOR_VERSION);
|
PY_MINOR_VERSION);
|
||||||
if (!dlopen(tmp, RTLD_NOLOAD | RTLD_GLOBAL))
|
if (!dlopen(tmp, RTLD_NOLOAD | RTLD_GLOBAL | RTLD_LAZY))
|
||||||
{
|
{
|
||||||
warning("IDAPython: dlopen(%s) failed", tmp);
|
warning("IDAPython: %s", dlerror());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -648,7 +915,6 @@ bool IDAPython_Init(void)
|
|||||||
|
|
||||||
/* Init the SWIG wrapper */
|
/* Init the SWIG wrapper */
|
||||||
init_idaapi();
|
init_idaapi();
|
||||||
|
|
||||||
/* Set IDAPYTHON_VERSION in Python */
|
/* Set IDAPYTHON_VERSION in Python */
|
||||||
qsnprintf(tmp, sizeof(tmp), "IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)", \
|
qsnprintf(tmp, sizeof(tmp), "IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)", \
|
||||||
VER_MAJOR,
|
VER_MAJOR,
|
||||||
@ -656,32 +922,41 @@ bool IDAPython_Init(void)
|
|||||||
VER_PATCH,
|
VER_PATCH,
|
||||||
VER_STATUS,
|
VER_STATUS,
|
||||||
VER_SERIAL);
|
VER_SERIAL);
|
||||||
begin_execution();
|
begin_execution();
|
||||||
PyRun_SimpleString(tmp);
|
PyRun_SimpleString(tmp);
|
||||||
end_execution();
|
end_execution();
|
||||||
|
|
||||||
/* Pull in the Python side of init */
|
/* Pull in the Python side of init */
|
||||||
qmakepath(tmp, MAXSTR, idadir(PYTHON_DIR_NAME), "init.py", NULL);
|
qmakepath(tmp, MAXSTR, idadir(PYTHON_DIR_NAME), "init.py", NULL);
|
||||||
if (!ExecFile(tmp))
|
if (!ExecFile(tmp))
|
||||||
{
|
{
|
||||||
warning("IDAPython: error executing init.py");
|
handle_python_error(tmp, sizeof(tmp));
|
||||||
|
warning("IDAPython: error executing init.py:\n%s", tmp);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Init pywraps (hand made/custom wrapper) */
|
||||||
|
if (!init_pywraps())
|
||||||
|
{
|
||||||
|
warning("IDAPython: init_pywraps() failed!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_PYTHON_PROFILING
|
#ifdef ENABLE_PYTHON_PROFILING
|
||||||
PyEval_SetTrace(tracefunc, NULL);
|
PyEval_SetTrace(tracefunc, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Batch-mode operation: */
|
/* Batch-mode operation: */
|
||||||
/* A script specified on the command line is run */
|
/* A script specified on the command line is run */
|
||||||
options = (char *)get_plugin_options("IDAPython");
|
parse_options();
|
||||||
if (options)
|
if ( g_run_when == run_on_init )
|
||||||
IDAPython_RunScript(options);
|
IDAPython_RunScript(g_run_script);
|
||||||
|
|
||||||
#ifdef PLUGINFIX
|
#ifdef PLUGINFIX
|
||||||
hook_to_notification_point(HT_UI, menu_installer_cb, NULL);
|
hook_to_notification_point(HT_UI, menu_installer_cb, NULL);
|
||||||
#else
|
#else
|
||||||
install_python_menus();
|
install_python_menus();
|
||||||
|
print_banner();
|
||||||
#endif
|
#endif
|
||||||
/* Register a RunPythonStatement() function for IDC */
|
/* Register a RunPythonStatement() function for IDC */
|
||||||
set_idc_func("RunPythonStatement", idc_runpythonstatement, idc_runpythonstatement_args);
|
set_idc_func("RunPythonStatement", idc_runpythonstatement, idc_runpythonstatement_args);
|
||||||
@ -691,6 +966,10 @@ bool IDAPython_Init(void)
|
|||||||
enable_python_cli(true);
|
enable_python_cli(true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if IDA_SDK_VERSION >= 560
|
||||||
|
install_extlang(&extlang_python);
|
||||||
|
#endif
|
||||||
|
|
||||||
initialized = 1;
|
initialized = 1;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -714,8 +993,14 @@ void IDAPython_Term(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Remove the extlang */
|
/* Remove the extlang */
|
||||||
|
#if IDA_SDK_VERSION >= 560
|
||||||
|
remove_extlang(&extlang_python);
|
||||||
|
#else
|
||||||
register_extlang(NULL);
|
register_extlang(NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* De-init pywraps */
|
||||||
|
deinit_pywraps();
|
||||||
/* Shut the interpreter down */
|
/* Shut the interpreter down */
|
||||||
Py_Finalize();
|
Py_Finalize();
|
||||||
|
|
||||||
|
@ -438,10 +438,12 @@ def Eval(expr):
|
|||||||
if err:
|
if err:
|
||||||
return "IDC_FAILURE: "+err
|
return "IDC_FAILURE: "+err
|
||||||
else:
|
else:
|
||||||
if rv.vtype == '\x01': # string
|
if rv.vtype == '\x01': # VT_STR
|
||||||
return rv.str
|
return rv.str
|
||||||
elif rv.vtype == '\x02': # long
|
elif rv.vtype == '\x02': # long
|
||||||
return rv.num
|
return rv.num
|
||||||
|
elif rv.vtype == '\x07': # VT_STR2
|
||||||
|
return rv.c_str()
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError, "Eval() supports only expressions returning strings or longs"
|
raise NotImplementedError, "Eval() supports only expressions returning strings or longs"
|
||||||
|
|
||||||
@ -6165,6 +6167,13 @@ def GetType(ea):
|
|||||||
"""
|
"""
|
||||||
return idaapi.idc_get_type(ea)
|
return idaapi.idc_get_type(ea)
|
||||||
|
|
||||||
|
def SizeOf(typestr):
|
||||||
|
"""
|
||||||
|
Returns the size of the type. It is equivalent to IDC's sizeof().
|
||||||
|
Use name, tp, fld = idc.ParseType() ; Sizeof(fld) to retrieve the size
|
||||||
|
@return: -1 if typestring is not valid otherwise the size of the type
|
||||||
|
"""
|
||||||
|
return idaapi.get_type_size0(idaapi.cvar.idati, typestr)
|
||||||
|
|
||||||
def GuessType(ea):
|
def GuessType(ea):
|
||||||
"""
|
"""
|
||||||
@ -6191,6 +6200,16 @@ def SetType(ea, newtype):
|
|||||||
"""
|
"""
|
||||||
return idaapi.apply_cdecl(ea, newtype)
|
return idaapi.apply_cdecl(ea, newtype)
|
||||||
|
|
||||||
|
def ParseType(inputtype, flags):
|
||||||
|
"""
|
||||||
|
Parse type declaration
|
||||||
|
|
||||||
|
@param inputtype: file name or C declarations (depending on the flags)
|
||||||
|
@param flags: combination of PT_... constants or 0
|
||||||
|
|
||||||
|
@return: None on failure or (name, type, fields) tuple
|
||||||
|
"""
|
||||||
|
return idaapi.idc_parse_decl(idaapi.cvar.idati, inputtype, flags)
|
||||||
|
|
||||||
def ParseTypes(inputtype, flags):
|
def ParseTypes(inputtype, flags):
|
||||||
"""
|
"""
|
||||||
|
@ -113,18 +113,12 @@ sys.stdout = sys.stderr = MyStdOut()
|
|||||||
sys.argv = [ "" ]
|
sys.argv = [ "" ]
|
||||||
|
|
||||||
# Have to make sure Python finds our modules
|
# Have to make sure Python finds our modules
|
||||||
if _idaapi.idainfo_is_64bit(_idaapi.cvar.inf):
|
sys.path.append(_idaapi.idadir("python"))
|
||||||
pythonDir = "python64"
|
|
||||||
else:
|
|
||||||
pythonDir = "python"
|
|
||||||
sys.path.append(_idaapi.idadir(pythonDir))
|
|
||||||
|
|
||||||
print_banner()
|
|
||||||
|
|
||||||
#-----------------------------------------------------------
|
#-----------------------------------------------------------
|
||||||
# Import all the required modules
|
# Import all the required modules
|
||||||
#-----------------------------------------------------------
|
#-----------------------------------------------------------
|
||||||
from idaapi import Choose, get_user_idadir, cvar, Choose2
|
from idaapi import Choose, get_user_idadir, cvar, Choose2, Appcall
|
||||||
from idc import *
|
from idc import *
|
||||||
from idautils import *
|
from idautils import *
|
||||||
import idaapi
|
import idaapi
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
%ignore clrFlbits;
|
%ignore clrFlbits;
|
||||||
%ignore get_8bit;
|
%ignore get_8bit;
|
||||||
%ignore get_ascii_char;
|
%ignore get_ascii_char;
|
||||||
%ignore del_typeinfo;
|
%ignore del_opinfo;
|
||||||
%ignore del_operand_typeinfo;
|
%ignore del_one_opinfo;
|
||||||
%ignore doCode;
|
%ignore doCode;
|
||||||
%ignore get_repeatable_cmt;
|
%ignore get_repeatable_cmt;
|
||||||
%ignore get_any_indented_cmt;
|
%ignore get_any_indented_cmt;
|
||||||
@ -72,11 +72,11 @@
|
|||||||
|
|
||||||
%clear(const void *buf, size_t size);
|
%clear(const void *buf, size_t size);
|
||||||
%clear(void *buf, ssize_t size);
|
%clear(void *buf, ssize_t size);
|
||||||
%clear(typeinfo_t *);
|
%clear(opinfo_t *);
|
||||||
|
|
||||||
%rename (nextthat) py_nextthat;
|
%rename (nextthat) py_nextthat;
|
||||||
%rename (prevthat) py_prevthat;
|
%rename (prevthat) py_prevthat;
|
||||||
|
|
||||||
%{
|
%{
|
||||||
//<code(py_bytes)>
|
//<code(py_bytes)>
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
|
@ -10,7 +10,7 @@ typedef struct
|
|||||||
%rename (get_manual_regions) py_get_manual_regions;
|
%rename (get_manual_regions) py_get_manual_regions;
|
||||||
%ignore set_manual_regions;
|
%ignore set_manual_regions;
|
||||||
%include "dbg.hpp"
|
%include "dbg.hpp"
|
||||||
|
%ignore DBG_Callback;
|
||||||
%feature("director") DBG_Hooks;
|
%feature("director") DBG_Hooks;
|
||||||
|
|
||||||
%{
|
%{
|
||||||
@ -250,7 +250,7 @@ int idaapi DBG_Callback(void *ud, int notification_code, va_list va)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Swig::DirectorException &e)
|
catch (Swig::DirectorException &)
|
||||||
{
|
{
|
||||||
msg("Exception in IDP Hook function:\n");
|
msg("Exception in IDP Hook function:\n");
|
||||||
if (PyErr_Occurred())
|
if (PyErr_Occurred())
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
%ignore qlfile;
|
%ignore qlfile;
|
||||||
%ignore make_linput;
|
%ignore make_linput;
|
||||||
%ignore unmake_linput;
|
%ignore unmake_linput;
|
||||||
|
%ignore create_remote_linput;
|
||||||
|
|
||||||
// FIXME: These should be wrapped for completeness
|
// FIXME: These should be wrapped for completeness
|
||||||
%ignore eread;
|
%ignore eread;
|
||||||
@ -44,6 +45,7 @@
|
|||||||
|
|
||||||
%{
|
%{
|
||||||
//<code(py_diskio)>
|
//<code(py_diskio)>
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
int idaapi py_enumerate_files_cb(const char *file, void *ud)
|
int idaapi py_enumerate_files_cb(const char *file, void *ud)
|
||||||
{
|
{
|
||||||
PyObject *py_file = PyString_FromString(file);
|
PyObject *py_file = PyString_FromString(file);
|
||||||
@ -72,6 +74,12 @@ private:
|
|||||||
OWN_FROM_FP = 3, // We got an li instance from an fp instance, we have to unmake_linput() on Close
|
OWN_FROM_FP = 3, // We got an li instance from an fp instance, we have to unmake_linput() on Close
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
void _from_cobject(PyObject *pycobject)
|
||||||
|
{
|
||||||
|
this->set_linput((linput_t *)PyCObject_AsVoidPtr(pycobject));
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
void assign(const loader_input_t &rhs)
|
void assign(const loader_input_t &rhs)
|
||||||
{
|
{
|
||||||
@ -79,19 +87,30 @@ private:
|
|||||||
li = rhs.li;
|
li = rhs.li;
|
||||||
own = OWN_FROM_LI;
|
own = OWN_FROM_LI;
|
||||||
}
|
}
|
||||||
public:
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
loader_input_t(const loader_input_t &rhs)
|
loader_input_t(const loader_input_t &rhs)
|
||||||
{
|
{
|
||||||
assign(rhs);
|
assign(rhs);
|
||||||
}
|
}
|
||||||
|
public:
|
||||||
|
// Special attribute that tells the pyvar_to_idcvar how to convert this
|
||||||
|
// class from and to IDC. The value of this variable must be set to two
|
||||||
|
int __idc_cvt_id__;
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
loader_input_t()
|
loader_input_t(PyObject *pycobject = NULL)
|
||||||
{
|
{
|
||||||
li = NULL;
|
__idc_cvt_id__ = 2; // Opaque object
|
||||||
own = OWN_NONE;
|
if (pycobject != NULL && PyCObject_Check(pycobject))
|
||||||
fn.qclear();
|
{
|
||||||
|
_from_cobject(pycobject);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
li = NULL;
|
||||||
|
own = OWN_NONE;
|
||||||
|
fn.qclear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
@ -152,7 +171,7 @@ public:
|
|||||||
if (!PyCObject_Check(pycobject))
|
if (!PyCObject_Check(pycobject))
|
||||||
return NULL;
|
return NULL;
|
||||||
loader_input_t *l = new loader_input_t();
|
loader_input_t *l = new loader_input_t();
|
||||||
l->set_linput((linput_t *)PyCObject_AsVoidPtr(pycobject));
|
l->_from_cobject(pycobject);
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,6 +304,12 @@ public:
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
int file2base(int32 pos, ea_t ea1, ea_t ea2, int patchable)
|
||||||
|
{
|
||||||
|
return ::file2base(li, pos, ea1, ea2, patchable);
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
int32 size()
|
int32 size()
|
||||||
{
|
{
|
||||||
@ -308,6 +333,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
PyObject *py_enumerate_files(PyObject *path, PyObject *fname, PyObject *callback)
|
PyObject *py_enumerate_files(PyObject *path, PyObject *fname, PyObject *callback)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
%ignore funcset_t;
|
%ignore funcset_t;
|
||||||
%ignore extlang_t;
|
%ignore extlang_t;
|
||||||
%ignore extlang;
|
%ignore extlang;
|
||||||
|
%ignore extlangs_t;
|
||||||
|
%ignore extlangs;
|
||||||
%ignore register_extlang;
|
%ignore register_extlang;
|
||||||
%ignore IDCFuncs;
|
%ignore IDCFuncs;
|
||||||
%ignore set_idc_func;
|
%ignore set_idc_func;
|
||||||
@ -28,6 +30,8 @@
|
|||||||
%ignore find_builtin_idc_func;
|
%ignore find_builtin_idc_func;
|
||||||
%ignore idc_lx;
|
%ignore idc_lx;
|
||||||
%ignore idc_vars;
|
%ignore idc_vars;
|
||||||
|
%ignore idc_resolve_label;
|
||||||
|
%ignore idc_resolver_ea;
|
||||||
|
|
||||||
%cstring_output_maxstr_none(char *errbuf, size_t errbufsize);
|
%cstring_output_maxstr_none(char *errbuf, size_t errbufsize);
|
||||||
|
|
||||||
@ -65,7 +69,7 @@ bool calc_idc_expr_wrap(ea_t where,const char *line, idc_value_t *rv, char *errb
|
|||||||
return !calc_idc_expr(where, line, rv, errbuf, errbufsize);
|
return !calc_idc_expr(where, line, rv, errbuf, errbufsize);
|
||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%ignore CompileLine(const char *line, char *errbuf, size_t errbufsize, uval_t (idaapi*_getname)(const char *name)=NULL);
|
%ignore CompileLine(const char *line, char *errbuf, size_t errbufsize, uval_t (idaapi*_getname)(const char *name)=NULL);
|
||||||
|
|
||||||
%rename (CompileLine) CompileLine_wrap;
|
%rename (CompileLine) CompileLine_wrap;
|
||||||
|
21
swig/fpro.i
21
swig/fpro.i
@ -7,13 +7,29 @@ private:
|
|||||||
bool own;
|
bool own;
|
||||||
qstring fn;
|
qstring fn;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
void assign(const qfile_t &rhs)
|
void assign(const qfile_t &rhs)
|
||||||
{
|
{
|
||||||
fn = rhs.fn;
|
fn = rhs.fn;
|
||||||
fp = rhs.fp;
|
fp = rhs.fp;
|
||||||
own = false;
|
own = false;
|
||||||
}
|
}
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
bool _from_fp(FILE *fp)
|
||||||
|
{
|
||||||
|
if (fp == NULL)
|
||||||
|
return false;
|
||||||
|
own = false;
|
||||||
|
fn.sprnt("<FILE * %p>", fp);
|
||||||
|
fp = fp;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
inline void _from_cobject(PyObject *pycobject)
|
||||||
|
{
|
||||||
|
_from_fp((FILE *)PyCObject_AsVoidPtr(pycobject));
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
|
int __idc_cvt_id__;
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
qfile_t(const qfile_t &rhs)
|
qfile_t(const qfile_t &rhs)
|
||||||
{
|
{
|
||||||
@ -21,11 +37,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
qfile_t()
|
qfile_t(PyObject *pycobject = NULL)
|
||||||
{
|
{
|
||||||
fp = NULL;
|
fp = NULL;
|
||||||
own = true;
|
own = true;
|
||||||
fn.qclear();
|
fn.qclear();
|
||||||
|
__idc_cvt_id__ = 2; // Opaque object
|
||||||
|
if (pycobject != NULL && PyCObject_Check(pycobject))
|
||||||
|
_from_cobject(pycobject);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
%pythoncode %{
|
%pythoncode %{
|
||||||
|
#<pycode(py_gdl)>
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
class BasicBlock:
|
class BasicBlock:
|
||||||
def __init__(self, id, bb, f):
|
def __init__(self, id, bb, f):
|
||||||
@ -96,5 +97,5 @@ class FlowChart:
|
|||||||
if index >= self.size:
|
if index >= self.size:
|
||||||
raise StopIteration
|
raise StopIteration
|
||||||
return BasicBlock(index, self._q[index], self)
|
return BasicBlock(index, self._q[index], self)
|
||||||
|
#</pycode(py_gdl)>
|
||||||
%}
|
%}
|
||||||
|
19
swig/graph.i
19
swig/graph.i
@ -481,12 +481,6 @@ private:
|
|||||||
//grcode_user_draw, // render node of a user-defined graph
|
//grcode_user_draw, // render node of a user-defined graph
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
static PyObject *PyObject_TryGetAttrString(PyObject *object, const char *attr)
|
|
||||||
{
|
|
||||||
if (!PyObject_HasAttrString(object, attr))
|
|
||||||
return NULL;
|
|
||||||
return PyObject_GetAttrString(object, attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void unbind()
|
void unbind()
|
||||||
{
|
{
|
||||||
@ -494,7 +488,9 @@ private:
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Unbind this object from the python object
|
// Unbind this object from the python object
|
||||||
PyObject_SetAttrString(self, S_M_THIS, PyCObject_FromVoidPtr(NULL, NULL));
|
PyObject *py_cobj = PyCObject_FromVoidPtr(NULL, NULL);
|
||||||
|
PyObject_SetAttrString(self, S_M_THIS, py_cobj);
|
||||||
|
Py_DECREF(py_cobj);
|
||||||
Py_XDECREF(self);
|
Py_XDECREF(self);
|
||||||
self = NULL;
|
self = NULL;
|
||||||
}
|
}
|
||||||
@ -600,10 +596,15 @@ private:
|
|||||||
Py_XDECREF(attr);
|
Py_XDECREF(attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind py_graph_t to python object
|
|
||||||
|
// Keep a reference
|
||||||
this->self = self;
|
this->self = self;
|
||||||
Py_INCREF(self);
|
Py_INCREF(self);
|
||||||
PyObject_SetAttrString(self, S_M_THIS, PyCObject_FromVoidPtr(this, NULL));
|
|
||||||
|
// Bind py_graph_t to python object
|
||||||
|
PyObject *py_cobj = PyCObject_FromVoidPtr(this, NULL);
|
||||||
|
PyObject_SetAttrString(self, S_M_THIS, py_cobj);
|
||||||
|
Py_DECREF(py_cobj);
|
||||||
|
|
||||||
// Create form
|
// Create form
|
||||||
HWND hwnd = NULL;
|
HWND hwnd = NULL;
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
%ignore idainfo::retrieve;
|
%ignore idainfo::retrieve;
|
||||||
%ignore idainfo::read;
|
%ignore idainfo::read;
|
||||||
%ignore idainfo::write;
|
%ignore idainfo::write;
|
||||||
|
%ignore idainfo::align_short_demnames;
|
||||||
|
%ignore idainfo::align_strtype;
|
||||||
|
%ignore idainfo::align_long_demnames;
|
||||||
|
|
||||||
%ignore setflag(uchar &where,uchar bit,int value);
|
%ignore setflag(uchar &where,uchar bit,int value);
|
||||||
%ignore setflag(ushort &where,ushort bit,int value);
|
%ignore setflag(ushort &where,ushort bit,int value);
|
||||||
|
806
swig/idaapi.i
806
swig/idaapi.i
@ -45,24 +45,697 @@
|
|||||||
#include "typeinf.hpp"
|
#include "typeinf.hpp"
|
||||||
#include "ua.hpp"
|
#include "ua.hpp"
|
||||||
#include "xref.hpp"
|
#include "xref.hpp"
|
||||||
|
#include "ieee.h"
|
||||||
|
#include "err.h"
|
||||||
#include "fpro.h"
|
#include "fpro.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#ifdef __NT__
|
#ifdef __NT__
|
||||||
#include "graph.hpp"
|
#include "graph.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//<code(py_idaapi)>
|
||||||
|
|
||||||
|
#ifndef PYUL_DEFINED
|
||||||
|
#define PYUL_DEFINED
|
||||||
|
typedef unsigned PY_LONG_LONG pyul_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
static const char PY_IDC_CLASS_NAME[] = "py_idc_object_class";
|
||||||
|
static const char PY_IDC_GLOBAL_VAR_FMT[] = "__py_cvt_gvar_%d";
|
||||||
|
static const char PY_IDCCVT_ID_ATTR[] = "__idc_cvt_id__";
|
||||||
|
static const char PY_IDCCVT_VALUE_ATTR[] = "__idc_cvt_value__";
|
||||||
|
static const char S_PY_IDC_OPAQUE_T[] = "py_idc_cvt_helper_t";
|
||||||
|
|
||||||
|
#ifndef __PYWRAPS__
|
||||||
|
static const char S_PY_IDAAPI_MODNAME[] = "idaapi";
|
||||||
|
#else
|
||||||
|
static const char S_PY_IDAAPI_MODNAME[] = "__main__";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PY_CLSID_CVT_INT64 0
|
||||||
|
#define PY_CLSID_APPCALL_SKEL_OBJ 1
|
||||||
|
#define PY_CLSID_CVT_BYREF 2
|
||||||
|
#define PY_CLSID_LAST 3
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// PyIdc conversion object ids
|
||||||
|
#define PY_ICID_INT64 0
|
||||||
|
#define PY_ICID_BYREF 1
|
||||||
|
#define PY_ICID_OPAQUE 2
|
||||||
|
|
||||||
|
static PyObject *py_cvt_helper_module = NULL;
|
||||||
|
static bool pywraps_initialized = false;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
idc_class_t *py_idc_cvt_opaque_t = NULL;
|
||||||
|
static const char py_idc_cvt_helper_dtor_args[] = { VT_OBJ, 0 };
|
||||||
|
static error_t idaapi py_idc_opaque_dtor(
|
||||||
|
idc_value_t *argv,
|
||||||
|
idc_value_t *res)
|
||||||
|
{
|
||||||
|
// Get the value from the object
|
||||||
|
idc_value_t idc_val;
|
||||||
|
VarGetAttr(&argv[0], PY_IDCCVT_VALUE_ATTR, &idc_val);
|
||||||
|
|
||||||
|
// Extract the Python object reference
|
||||||
|
PyObject *py_obj = (PyObject *)idc_val.pvoid;
|
||||||
|
// Decrease its reference (and eventually destroy it)
|
||||||
|
Py_DECREF(py_obj);
|
||||||
|
return eOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// This function must be called on initialization
|
||||||
|
bool init_pywraps()
|
||||||
|
{
|
||||||
|
if (pywraps_initialized)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Take a reference to the idaapi python module
|
||||||
|
// (We need it to create instances of certain classes)
|
||||||
|
if (py_cvt_helper_module == NULL)
|
||||||
|
{
|
||||||
|
// Take a reference to the module so we can create the needed class instances
|
||||||
|
py_cvt_helper_module = PyImport_ImportModule(S_PY_IDAAPI_MODNAME);
|
||||||
|
if (py_cvt_helper_module == NULL)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (py_idc_cvt_opaque_t == NULL)
|
||||||
|
{
|
||||||
|
// Add the class
|
||||||
|
py_idc_cvt_opaque_t = add_idc_class(S_PY_IDC_OPAQUE_T);
|
||||||
|
if (py_idc_cvt_opaque_t == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Form the dtor name
|
||||||
|
char dtor_name[MAXSTR];
|
||||||
|
qstrncpy(dtor_name, S_PY_IDC_OPAQUE_T, sizeof(dtor_name));
|
||||||
|
qstrncat(dtor_name, ".dtor", sizeof(dtor_name));
|
||||||
|
|
||||||
|
// register the dtor function
|
||||||
|
if (!set_idc_func(dtor_name, py_idc_opaque_dtor, py_idc_cvt_helper_dtor_args))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Link the dtor function to the class
|
||||||
|
set_idc_dtor(py_idc_cvt_opaque_t, dtor_name);
|
||||||
|
}
|
||||||
|
pywraps_initialized = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// This function must be called on de-initialization
|
||||||
|
void deinit_pywraps()
|
||||||
|
{
|
||||||
|
if (!pywraps_initialized)
|
||||||
|
return;
|
||||||
|
pywraps_initialized = false;
|
||||||
|
Py_XDECREF(py_cvt_helper_module);
|
||||||
|
py_cvt_helper_module = NULL;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Gets a class type reference in idaapi
|
||||||
|
// With the class type reference we can create a new instance of that type
|
||||||
|
// This function takes a reference to the idaapi module and keeps the reference
|
||||||
|
static PyObject *get_idaapi_class_reference(const int class_id)
|
||||||
|
{
|
||||||
|
if (class_id >= PY_CLSID_LAST)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Some class names. The array is parallel with the PY_CLSID_xxx consts
|
||||||
|
static const char *class_names[]=
|
||||||
|
{
|
||||||
|
"PyIdc_cvt_int64__",
|
||||||
|
"Appcall_object__",
|
||||||
|
"PyIdc_cvt_refclass__"
|
||||||
|
};
|
||||||
|
|
||||||
|
return PyObject_GetAttrString(py_cvt_helper_module, class_names[class_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Returns an attribute or NULL
|
||||||
|
// No errors will be set if the attribute did not exist
|
||||||
|
PyObject *PyObject_TryGetAttrString(PyObject *py_var, const char *attr)
|
||||||
|
{
|
||||||
|
if (!PyObject_HasAttrString(py_var, attr))
|
||||||
|
return NULL;
|
||||||
|
return PyObject_GetAttrString(py_var, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Converts a Python number into an IDC value (32 or 64bits)
|
||||||
|
// The function will first try to convert the number into a 32bit value
|
||||||
|
// If the number does not fit then VT_INT64 will be used
|
||||||
|
// NB: This function cannot properly detect if the Python value should be
|
||||||
|
// converted to a VT_INT64 or not. For example: 2**32-1 = 0xffffffff which
|
||||||
|
// can fit in a C long but Python creates a PyLong object for it.
|
||||||
|
// And because of that we are confused as to whether to convert to 32 or 64
|
||||||
|
bool PyGetNumber(PyObject *py_var, idc_value_t *idc_var)
|
||||||
|
{
|
||||||
|
if (!(PyInt_CheckExact(py_var) || PyLong_CheckExact(py_var)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Can we convert to C long?
|
||||||
|
long l = PyInt_AsLong(py_var);
|
||||||
|
if (!PyErr_Occurred())
|
||||||
|
{
|
||||||
|
idc_var->set_long(l);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Clear last error
|
||||||
|
PyErr_Clear();
|
||||||
|
// Can be fit into a C unsigned long?
|
||||||
|
l = (long) PyLong_AsUnsignedLong(py_var);
|
||||||
|
if (!PyErr_Occurred())
|
||||||
|
{
|
||||||
|
idc_var->set_long(l);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
PyErr_Clear();
|
||||||
|
idc_var->set_int64(PyLong_AsLongLong(py_var));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Checks if a given object is of sequence type
|
||||||
|
bool PyIsSequenceType(PyObject *obj)
|
||||||
|
{
|
||||||
|
if (!PySequence_Check(obj))
|
||||||
|
return false;
|
||||||
|
Py_ssize_t sz = PySequence_Size(obj);
|
||||||
|
if (sz == -1 || PyErr_Occurred() != NULL)
|
||||||
|
{
|
||||||
|
PyErr_Clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Returns the string representation of an object
|
||||||
|
bool PyObjectToString(PyObject *obj, qstring *out)
|
||||||
|
{
|
||||||
|
PyObject *py_str = PyObject_Str(obj);
|
||||||
|
if (py_str != NULL)
|
||||||
|
{
|
||||||
|
*out = PyString_AsString(py_str);
|
||||||
|
Py_DECREF(py_str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out->qclear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Checks if a Python error occured and fills the out parameter with the
|
||||||
|
// exception string
|
||||||
|
bool PyGetError(qstring *out = NULL)
|
||||||
|
{
|
||||||
|
PyObject *py_err;
|
||||||
|
if ( (py_err = PyErr_Occurred()) == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
PyObject *err_type, *err_value, *err_traceback;
|
||||||
|
PyErr_Fetch(&err_type, &err_value, &err_traceback);
|
||||||
|
if ( out != NULL )
|
||||||
|
PyObjectToString(err_value, out);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Checks if the given py_var is a special PyIdc_cvt_helper object.
|
||||||
|
// It does that by examining the magic attribute and returns its numeric value.
|
||||||
|
// It returns -1 if the object is not a recognized helper object.
|
||||||
|
// Any Python object can be treated as an cvt object if this attribute is created.
|
||||||
|
static int get_pyidc_cvt_type(PyObject *py_var)
|
||||||
|
{
|
||||||
|
// Check if this our special by reference object
|
||||||
|
PyObject *attr = PyObject_TryGetAttrString(py_var, PY_IDCCVT_ID_ATTR);
|
||||||
|
if (attr == NULL)
|
||||||
|
return -1;
|
||||||
|
if (!(PyInt_Check(attr) || PyLong_Check(attr)))
|
||||||
|
{
|
||||||
|
Py_DECREF(attr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int r = (int)PyInt_AsLong(attr);
|
||||||
|
Py_DECREF(attr);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Utility function to create opaque / convertible Python <-> IDC variables
|
||||||
|
// The referred Python variable will have its reference increased
|
||||||
|
static bool create_py_idc_opaque_obj(PyObject *py_var, idc_value_t *idc_var)
|
||||||
|
{
|
||||||
|
// Create an IDC object of this special helper class
|
||||||
|
if (VarObject(idc_var, py_idc_cvt_opaque_t) != eOk)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Store the CVT id
|
||||||
|
idc_value_t idc_val;
|
||||||
|
idc_val.set_long(PY_ICID_OPAQUE);
|
||||||
|
VarSetAttr(idc_var, PY_IDCCVT_ID_ATTR, &idc_val);
|
||||||
|
|
||||||
|
// Store the value as a PVOID referencing the given Python object
|
||||||
|
idc_val.set_pvoid(py_var);
|
||||||
|
VarSetAttr(idc_var, PY_IDCCVT_VALUE_ATTR, &idc_val);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Converts a Python variable into an IDC variable
|
||||||
|
// This function returns:
|
||||||
|
// 0 - failure
|
||||||
|
// 1 - success
|
||||||
|
// 2 - success but do not decrement the reference of the py_var (used by opaque values)
|
||||||
|
int pyvar_to_idcvar(
|
||||||
|
PyObject *py_var,
|
||||||
|
idc_value_t *idc_var,
|
||||||
|
int *gvar_sn = NULL)
|
||||||
|
{
|
||||||
|
PyObject *attr;
|
||||||
|
// None / NULL
|
||||||
|
if (py_var == NULL || py_var == Py_None)
|
||||||
|
idc_var->set_long(0);
|
||||||
|
// Numbers?
|
||||||
|
else if (PyGetNumber(py_var, idc_var))
|
||||||
|
return 1;
|
||||||
|
// String
|
||||||
|
else if (PyString_Check(py_var))
|
||||||
|
idc_var->_set_string(PyString_AsString(py_var), PyString_Size(py_var)+1);
|
||||||
|
// Float
|
||||||
|
else if (PyBool_Check(py_var))
|
||||||
|
idc_var->set_long(py_var == Py_True ? 1 : 0);
|
||||||
|
// Boolean
|
||||||
|
else if (PyFloat_Check(py_var))
|
||||||
|
{
|
||||||
|
double dresult = PyFloat_AsDouble(py_var);
|
||||||
|
ieee_realcvt((void *)&dresult, idc_var->e, 3);
|
||||||
|
idc_var->vtype = VT_FLOAT;
|
||||||
|
}
|
||||||
|
// void*
|
||||||
|
else if (PyCObject_Check(py_var))
|
||||||
|
idc_var->set_pvoid(PyCObject_AsVoidPtr(py_var));
|
||||||
|
else if (PyList_CheckExact(py_var) || PyIsSequenceType(py_var))
|
||||||
|
{
|
||||||
|
// Create the object
|
||||||
|
VarObject(idc_var);
|
||||||
|
|
||||||
|
// Determine list size and type
|
||||||
|
bool is_seq = !PyList_CheckExact(py_var);
|
||||||
|
Py_ssize_t size = is_seq ? PySequence_Size(py_var) : PyList_Size(py_var);
|
||||||
|
bool ok = true;
|
||||||
|
qstring attr_name;
|
||||||
|
|
||||||
|
// Convert each item
|
||||||
|
for (Py_ssize_t i=0;i<size;i++)
|
||||||
|
{
|
||||||
|
// Get the item
|
||||||
|
PyObject *py_item = is_seq ? PySequence_GetItem(py_var, i) : PyList_GetItem(py_var, i);
|
||||||
|
|
||||||
|
// Convert the item into an IDC variable
|
||||||
|
idc_value_t v;
|
||||||
|
ok = pyvar_to_idcvar(py_item, &v, gvar_sn) > 0;
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
// Form the attribute name
|
||||||
|
PyObject *py_int = PyInt_FromSsize_t(i);
|
||||||
|
ok = PyObjectToString(py_int, &attr_name);
|
||||||
|
if (!ok)
|
||||||
|
break;
|
||||||
|
Py_DECREF(py_int);
|
||||||
|
// Store the attribute
|
||||||
|
VarSetAttr(idc_var, attr_name.c_str(), &v);
|
||||||
|
}
|
||||||
|
// Sequences return a new reference for GetItem()
|
||||||
|
if (is_seq)
|
||||||
|
Py_DECREF(py_var);
|
||||||
|
if (!ok)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ok ? 1 : 0;
|
||||||
|
}
|
||||||
|
// Dictionary: we convert to an IDC object
|
||||||
|
else if (PyDict_Check(py_var))
|
||||||
|
{
|
||||||
|
// Create an empty IDC object
|
||||||
|
VarObject(idc_var);
|
||||||
|
|
||||||
|
// Get the dict.items() list
|
||||||
|
PyObject *py_items = PyDict_Items(py_var);
|
||||||
|
|
||||||
|
// Get the size of the list
|
||||||
|
qstring key_name;
|
||||||
|
bool ok = true;
|
||||||
|
Py_ssize_t size = PySequence_Size(py_items);
|
||||||
|
for (Py_ssize_t i=0;i<size;i++)
|
||||||
|
{
|
||||||
|
// Get item[i] -> (key, value)
|
||||||
|
PyObject *py_item = PyList_GetItem(py_items, i);
|
||||||
|
|
||||||
|
// Extract key/value
|
||||||
|
PyObject *key = PySequence_GetItem(py_item, 0);
|
||||||
|
PyObject *val = PySequence_GetItem(py_item, 1);
|
||||||
|
|
||||||
|
// Get key's string representation
|
||||||
|
PyObjectToString(key, &key_name);
|
||||||
|
|
||||||
|
// Convert the attribute into an IDC value
|
||||||
|
idc_value_t v;
|
||||||
|
ok = pyvar_to_idcvar(val, &v, gvar_sn) > 0;
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
// Store the attribute
|
||||||
|
VarSetAttr(idc_var, key_name.c_str(), &v);
|
||||||
|
}
|
||||||
|
Py_XDECREF(key);
|
||||||
|
Py_XDECREF(val);
|
||||||
|
if (!ok)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Decrement attribute reference
|
||||||
|
Py_DECREF(py_items);
|
||||||
|
return ok ? 1 : 0;
|
||||||
|
}
|
||||||
|
// Objects:
|
||||||
|
// - pyidc_cvt objects: int64, byref, opaque
|
||||||
|
// - other python objects
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Get the type
|
||||||
|
int cvt_id = get_pyidc_cvt_type(py_var);
|
||||||
|
switch (cvt_id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// INT64
|
||||||
|
//
|
||||||
|
case PY_ICID_INT64:
|
||||||
|
// Get the value attribute
|
||||||
|
attr = PyObject_TryGetAttrString(py_var, PY_IDCCVT_VALUE_ATTR);
|
||||||
|
if (attr == NULL)
|
||||||
|
return false;
|
||||||
|
idc_var->set_int64(PyLong_AsLongLong(attr));
|
||||||
|
Py_DECREF(attr);
|
||||||
|
return 1;
|
||||||
|
//
|
||||||
|
// BYREF
|
||||||
|
//
|
||||||
|
case PY_ICID_BYREF:
|
||||||
|
{
|
||||||
|
// BYREF always require this parameter
|
||||||
|
if (gvar_sn == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Get the value attribute
|
||||||
|
attr = PyObject_TryGetAttrString(py_var, PY_IDCCVT_VALUE_ATTR);
|
||||||
|
if (attr == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Create a global variable
|
||||||
|
char buf[MAXSTR];
|
||||||
|
qsnprintf(buf, sizeof(buf), PY_IDC_GLOBAL_VAR_FMT, *gvar_sn);
|
||||||
|
idc_value_t *gvar = add_idc_gvar(buf);
|
||||||
|
// Convert the python value into the IDC global variable
|
||||||
|
bool ok = pyvar_to_idcvar(attr, gvar, gvar_sn) > 0;
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
(*gvar_sn)++;
|
||||||
|
// Create a reference to this global variable
|
||||||
|
VarRef(idc_var, gvar);
|
||||||
|
}
|
||||||
|
Py_DECREF(attr);
|
||||||
|
return ok ? 1 : 0;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// OPAQUE
|
||||||
|
//
|
||||||
|
case PY_ICID_OPAQUE:
|
||||||
|
{
|
||||||
|
if (!create_py_idc_opaque_obj(py_var, idc_var))
|
||||||
|
return 0;
|
||||||
|
return 2; // do not decrement the reference
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Other objects
|
||||||
|
//
|
||||||
|
default:
|
||||||
|
// A normal object?
|
||||||
|
PyObject *py_dir = PyObject_Dir(py_var);
|
||||||
|
Py_ssize_t size = PyList_Size(py_dir);
|
||||||
|
if (py_dir == NULL || !PyList_Check(py_dir) || size == 0)
|
||||||
|
{
|
||||||
|
Py_XDECREF(py_dir);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Create the IDC object
|
||||||
|
VarObject(idc_var);
|
||||||
|
for (Py_ssize_t i=0;i<size;i++)
|
||||||
|
{
|
||||||
|
PyObject *item = PyList_GetItem(py_dir, i);
|
||||||
|
const char *field_name = PyString_AsString(item);
|
||||||
|
if (field_name == NULL)
|
||||||
|
continue;
|
||||||
|
size_t len = strlen(field_name);
|
||||||
|
// skip private attributes
|
||||||
|
if ( (len > 2 )
|
||||||
|
&& (strncmp(field_name, "__", 2) == 0 )
|
||||||
|
&& (strncmp(field_name+len-2, "__", 2) == 0) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
idc_value_t v;
|
||||||
|
// Get the non-private attribute from the object
|
||||||
|
attr = PyObject_GetAttrString(py_var, field_name);
|
||||||
|
if (attr == NULL
|
||||||
|
// Convert the attribute into an IDC value
|
||||||
|
|| pyvar_to_idcvar(attr, &v, gvar_sn) <= 0)
|
||||||
|
{
|
||||||
|
Py_XDECREF(attr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Store the attribute
|
||||||
|
VarSetAttr(idc_var, field_name, &v);
|
||||||
|
// Decrement attribute reference
|
||||||
|
Py_DECREF(attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Converts an IDC variable to a Python variable
|
||||||
|
// If py_var points to an existing object then the object will be updated
|
||||||
|
// If py_var points to an existing immutable object then ZERO is returned
|
||||||
|
// Return codes:
|
||||||
|
#define CIP_FAILED -1 // Conversion error
|
||||||
|
#define CIP_IMMUTABLE 0 // Immutable object passed. Will not update the object but no error occured
|
||||||
|
#define CIP_OK 1 // Success
|
||||||
|
#define CIP_OK_NODECREF 2 // Success but do not decrement its reference
|
||||||
|
int idcvar_to_pyvar(
|
||||||
|
const idc_value_t &idc_var,
|
||||||
|
PyObject **py_var)
|
||||||
|
{
|
||||||
|
switch (idc_var.vtype)
|
||||||
|
{
|
||||||
|
case VT_PVOID:
|
||||||
|
if (*py_var == NULL)
|
||||||
|
*py_var = PyCObject_FromVoidPtr(idc_var.pvoid, NULL);
|
||||||
|
else
|
||||||
|
return CIP_IMMUTABLE;
|
||||||
|
break;
|
||||||
|
case VT_INT64:
|
||||||
|
{
|
||||||
|
// Recycle?
|
||||||
|
if (*py_var != NULL)
|
||||||
|
{
|
||||||
|
// Recycling an int64 object?
|
||||||
|
int t = get_pyidc_cvt_type(*py_var);
|
||||||
|
if (t != PY_ICID_INT64)
|
||||||
|
return CIP_IMMUTABLE; // Cannot recycle immutable object
|
||||||
|
// Update the attribute
|
||||||
|
PyObject_SetAttrString(*py_var, PY_IDCCVT_VALUE_ATTR, PyLong_FromLongLong(idc_var.i64));
|
||||||
|
return CIP_OK;
|
||||||
|
}
|
||||||
|
PyObject *py_cls = get_idaapi_class_reference(PY_CLSID_CVT_INT64);
|
||||||
|
if (py_cls == NULL)
|
||||||
|
return CIP_FAILED;
|
||||||
|
*py_var = PyObject_CallFunctionObjArgs(py_cls, PyLong_FromLongLong(idc_var.i64), NULL);
|
||||||
|
Py_DECREF(py_cls);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VT_STR:
|
||||||
|
*py_var = PyString_FromString(idc_var.str);
|
||||||
|
break;
|
||||||
|
case VT_STR2:
|
||||||
|
if (*py_var == NULL)
|
||||||
|
{
|
||||||
|
const qstring &s = idc_var.qstr();
|
||||||
|
*py_var = PyString_FromStringAndSize(s.begin(), s.length());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return CIP_IMMUTABLE; // Cannot recycle immutable object
|
||||||
|
case VT_LONG:
|
||||||
|
// Cannot recycle immutable objects
|
||||||
|
if (*py_var != NULL)
|
||||||
|
return CIP_IMMUTABLE;
|
||||||
|
#ifdef __EA64__
|
||||||
|
*py_var = PyLong_FromLongLong(idc_var.num);
|
||||||
|
#else
|
||||||
|
*py_var = PyLong_FromLong(idc_var.num);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case VT_FLOAT:
|
||||||
|
if (*py_var == NULL)
|
||||||
|
{
|
||||||
|
double x;
|
||||||
|
if ( ph.realcvt(&x, (uint16 *)idc_var.e, (sizeof(x)/2-1)|010) != 0 )
|
||||||
|
INTERR();
|
||||||
|
*py_var = PyFloat_FromDouble(x);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return CIP_IMMUTABLE;
|
||||||
|
case VT_REF:
|
||||||
|
{
|
||||||
|
if (*py_var == NULL)
|
||||||
|
{
|
||||||
|
PyObject *py_cls = get_idaapi_class_reference(PY_CLSID_CVT_BYREF);
|
||||||
|
if (py_cls == NULL)
|
||||||
|
return CIP_FAILED;
|
||||||
|
// Create a byref object with None value. We populate it later
|
||||||
|
*py_var = PyObject_CallFunctionObjArgs(py_cls, Py_None, NULL);
|
||||||
|
Py_DECREF(py_cls);
|
||||||
|
}
|
||||||
|
int t = *py_var == NULL ? -1 : get_pyidc_cvt_type(*py_var);
|
||||||
|
if (t != PY_ICID_BYREF)
|
||||||
|
return CIP_FAILED;
|
||||||
|
|
||||||
|
// Dereference
|
||||||
|
// (Since we are not using VREF_COPY flag, we can safely const_cast)
|
||||||
|
idc_value_t *dref_v = VarDeref(const_cast<idc_value_t *>(&idc_var), VREF_LOOP);
|
||||||
|
if (dref_v == NULL)
|
||||||
|
return CIP_FAILED;
|
||||||
|
|
||||||
|
// Can we recycle the object?
|
||||||
|
PyObject *new_py_val = PyObject_TryGetAttrString(*py_var, PY_IDCCVT_VALUE_ATTR);
|
||||||
|
if (new_py_val != NULL)
|
||||||
|
{
|
||||||
|
// Recycle
|
||||||
|
t = idcvar_to_pyvar(*dref_v, &new_py_val);
|
||||||
|
Py_XDECREF(new_py_val); // DECREF because of GetAttrStr
|
||||||
|
// Success? Nothing more to be done
|
||||||
|
if (t == CIP_OK)
|
||||||
|
return CIP_OK;
|
||||||
|
// Clear it so we don't recycle it
|
||||||
|
new_py_val = NULL;
|
||||||
|
}
|
||||||
|
// Try to convert (not recycle)
|
||||||
|
if (idcvar_to_pyvar(*dref_v, &new_py_val) != CIP_OK)
|
||||||
|
return CIP_FAILED;
|
||||||
|
// Update the attribute
|
||||||
|
PyObject_SetAttrString(*py_var, PY_IDCCVT_VALUE_ATTR, new_py_val);
|
||||||
|
Py_DECREF(new_py_val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Can convert back into a Python object or Python dictionary
|
||||||
|
// (Depending if py_var will be recycled and it was a dictionary)
|
||||||
|
case VT_OBJ:
|
||||||
|
{
|
||||||
|
// Check if this IDC object has __cvt_id__ and the __idc_cvt_value__ fields
|
||||||
|
idc_value_t idc_val;
|
||||||
|
if ( VarGetAttr(&idc_var, PY_IDCCVT_ID_ATTR, &idc_val) == eOk
|
||||||
|
&& VarGetAttr(&idc_var, PY_IDCCVT_VALUE_ATTR, &idc_val) == eOk )
|
||||||
|
{
|
||||||
|
// Extract the object
|
||||||
|
*py_var = (PyObject *) idc_val.pvoid;
|
||||||
|
return CIP_OK_NODECREF;
|
||||||
|
}
|
||||||
|
PyObject *obj;
|
||||||
|
bool is_dict = false;
|
||||||
|
// Need to create a new object?
|
||||||
|
if (*py_var == NULL)
|
||||||
|
{
|
||||||
|
PyObject *py_cls = get_idaapi_class_reference(PY_CLSID_APPCALL_SKEL_OBJ);
|
||||||
|
if (py_cls == NULL)
|
||||||
|
return CIP_FAILED;
|
||||||
|
obj = PyObject_CallFunctionObjArgs(py_cls, NULL);
|
||||||
|
Py_DECREF(py_cls);
|
||||||
|
if (obj == NULL)
|
||||||
|
return CIP_FAILED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Recycle existing variable
|
||||||
|
obj = *py_var;
|
||||||
|
if (PyDict_Check(obj))
|
||||||
|
is_dict = true;
|
||||||
|
}
|
||||||
|
// Walk the IDC attributes and store into python
|
||||||
|
for (const char *attr_name = VarFirstAttr(&idc_var);
|
||||||
|
attr_name != NULL;
|
||||||
|
attr_name=VarNextAttr(&idc_var, attr_name))
|
||||||
|
{
|
||||||
|
// Get the attribute
|
||||||
|
idc_value_t v;
|
||||||
|
VarGetAttr(&idc_var, attr_name, &v, true);
|
||||||
|
// Convert attribute to a python value
|
||||||
|
PyObject *py_attr(NULL);
|
||||||
|
int cvt = idcvar_to_pyvar(v, &py_attr);
|
||||||
|
if (cvt <= CIP_IMMUTABLE)
|
||||||
|
{
|
||||||
|
// Delete the object (if we created it)
|
||||||
|
if (*py_var == NULL)
|
||||||
|
Py_DECREF(obj);
|
||||||
|
return CIP_FAILED;
|
||||||
|
}
|
||||||
|
if (is_dict)
|
||||||
|
PyDict_SetItemString(obj, attr_name, py_attr);
|
||||||
|
else
|
||||||
|
PyObject_SetAttrString(obj, attr_name, py_attr);
|
||||||
|
if (cvt == CIP_OK)
|
||||||
|
Py_DECREF(py_attr);
|
||||||
|
}
|
||||||
|
*py_var = obj;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Unhandled type
|
||||||
|
default:
|
||||||
|
*py_var = NULL;
|
||||||
|
return CIP_FAILED;
|
||||||
|
}
|
||||||
|
return CIP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
//</code(py_idaapi)>
|
||||||
%}
|
%}
|
||||||
|
|
||||||
// Do not create separate wrappers for default arguments
|
// Do not create separate wrappers for default arguments
|
||||||
%feature("compactdefaultargs");
|
%feature("compactdefaultargs");
|
||||||
|
|
||||||
#ifdef __EA64__
|
#ifdef __EA64__
|
||||||
%constant ea_t BADADDR = 0xFFFFFFFFFFFFFFFF;
|
#ifdef __GNUC__
|
||||||
%constant sel_t BADSEL = 0xFFFFFFFFFFFFFFFF;
|
%constant ea_t BADADDR = 0xFFFFFFFFFFFFFFFFll;
|
||||||
%constant nodeidx_t BADNODE = 0xFFFFFFFFFFFFFFFF;
|
%constant sel_t BADSEL = 0xFFFFFFFFFFFFFFFFll;
|
||||||
#else
|
%constant nodeidx_t BADNODE = 0xFFFFFFFFFFFFFFFFll;
|
||||||
%constant ea_t BADADDR = 0xFFFFFFFF;
|
#else // __GNUC__
|
||||||
%constant sel_t BADSEL = 0xFFFFFFFF;
|
%constant ea_t BADADDR = 0xFFFFFFFFFFFFFFFFui64;
|
||||||
%constant nodeidx_t BADNODE = 0xFFFFFFFF;
|
%constant sel_t BADSEL = 0xFFFFFFFFFFFFFFFFui64;
|
||||||
|
%constant nodeidx_t BADNODE = 0xFFFFFFFFFFFFFFFFui64;
|
||||||
|
#endif // __GNUC__
|
||||||
|
#else //__EA64__
|
||||||
|
%constant ea_t BADADDR = 0xFFFFFFFFL;
|
||||||
|
%constant sel_t BADSEL = 0xFFFFFFFFL;
|
||||||
|
%constant nodeidx_t BADNODE = 0xFFFFFFFFL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Help SWIG to figure out the ulonglong type
|
// Help SWIG to figure out the ulonglong type
|
||||||
@ -166,3 +839,122 @@ idainfo *get_inf_structure(void)
|
|||||||
void enable_extlang_python(bool enable);
|
void enable_extlang_python(bool enable);
|
||||||
void enable_python_cli(bool enable);
|
void enable_python_cli(bool enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
%pythoncode %{
|
||||||
|
#<pycode(py_idaapi)>
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Seek constants
|
||||||
|
SEEK_SET = 0 # from the file start
|
||||||
|
SEEK_CUR = 1 # from the current position
|
||||||
|
SEEK_END = 2 # from the file end
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# This is a special helper object that helps detect which kind
|
||||||
|
# of object is this python object wrapping and how to convert it
|
||||||
|
# back and from IDC.
|
||||||
|
# This object is characterized by its special attribute and its value
|
||||||
|
class PyIdc_cvt_helper__(object):
|
||||||
|
def __init__(self, cvt_id, value):
|
||||||
|
# 0 = int64 object
|
||||||
|
# 1 = byref object
|
||||||
|
# 2 = opaque object
|
||||||
|
self.__idc_cvt_id__ = cvt_id
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def __set_value(self, v):
|
||||||
|
self.__idc_cvt_value__ = v
|
||||||
|
def __get_value(self):
|
||||||
|
return self.__idc_cvt_value__
|
||||||
|
value = property(__get_value, __set_value)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
class PyIdc_cvt_int64__(PyIdc_cvt_helper__):
|
||||||
|
"""Helper class for explicitly representing VT_INT64 values"""
|
||||||
|
def __init__(self, v):
|
||||||
|
# id = 0 = int64 object
|
||||||
|
super(self.__class__, self).__init__(0, v)
|
||||||
|
|
||||||
|
# operation table
|
||||||
|
op_table = \
|
||||||
|
{
|
||||||
|
0: lambda a, b: a + b,
|
||||||
|
1: lambda a, b: a - b,
|
||||||
|
2: lambda a, b: a * b,
|
||||||
|
3: lambda a, b: a / b
|
||||||
|
}
|
||||||
|
# carries the operation given its number
|
||||||
|
def op(self, op_n, other, rev=False):
|
||||||
|
a = self.value
|
||||||
|
# other operand of same type? then take its value field
|
||||||
|
if type(other) == type(self):
|
||||||
|
b = other.value
|
||||||
|
else:
|
||||||
|
b = other
|
||||||
|
if rev:
|
||||||
|
t = a
|
||||||
|
a = b
|
||||||
|
b = t
|
||||||
|
# construct a new object and return as the result
|
||||||
|
return self.__class__(self.op_table[op_n](a, b))
|
||||||
|
|
||||||
|
# overloaded operators
|
||||||
|
def __add__(self, other): return self.op(0, other)
|
||||||
|
def __sub__(self, other): return self.op(1, other)
|
||||||
|
def __mul__(self, other): return self.op(2, other)
|
||||||
|
def __div__(self, other): return self.op(3, other)
|
||||||
|
def __radd__(self, other): return self.op(0, other, True)
|
||||||
|
def __rsub__(self, other): return self.op(1, other, True)
|
||||||
|
def __rmul__(self, other): return self.op(2, other, True)
|
||||||
|
def __rdiv__(self, other): return self.op(3, other, True)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
class PyIdc_cvt_refclass__(PyIdc_cvt_helper__):
|
||||||
|
"""Helper class for representing references to immutable objects"""
|
||||||
|
def __init__(self, v):
|
||||||
|
# id = one = byref object
|
||||||
|
super(self.__class__, self).__init__(1, v)
|
||||||
|
|
||||||
|
def cstr(self):
|
||||||
|
return as_cstr(self.value)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# This object can be passed to IDC and back to Python transparently
|
||||||
|
# The attribute "__idc_cvt_value__" is used
|
||||||
|
class PyIdc_cvt_opaque__(PyIdc_cvt_helper__):
|
||||||
|
def __init__(self, v):
|
||||||
|
# id = two = opaque object
|
||||||
|
super(self.__class__, self).__init__(2, v)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def as_cstr(val):
|
||||||
|
"""
|
||||||
|
Returns a C str from the passed value. The passed value can be of type refclass (returned by a call to buffer() or byref())
|
||||||
|
It scans for the first \x00 and returns the string value up to that point.
|
||||||
|
"""
|
||||||
|
if isinstance(val, PyIdc_cvt_refclass__):
|
||||||
|
val = val.value
|
||||||
|
n = 0
|
||||||
|
for x in val:
|
||||||
|
if ord(x) == 0:
|
||||||
|
break
|
||||||
|
n = n + 1
|
||||||
|
return val[:n]
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def as_unicode(s):
|
||||||
|
"""Convenience function to convert a string into appropriate unicode format"""
|
||||||
|
# use UTF16 big/little endian, depending on the environment?
|
||||||
|
return unicode(s).encode("UTF-16" + ("BE" if _idaapi.cvar.inf.mf else "LE"))
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def as_uint32(v):
|
||||||
|
return v & 0xffffffff
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def as_int32(v):
|
||||||
|
return -((~v & 0xffffffff)+1)
|
||||||
|
|
||||||
|
#</pycode(py_idaapi)>
|
||||||
|
|
||||||
|
%}
|
523
swig/idd.i
523
swig/idd.i
@ -1,7 +1,7 @@
|
|||||||
%ignore debugger_t;
|
%ignore debugger_t;
|
||||||
%ignore memory_info_t;
|
%ignore memory_info_t;
|
||||||
%ignore register_info_t;
|
%ignore register_info_t;
|
||||||
|
%ignore appcall;
|
||||||
%apply unsigned char { char dtyp };
|
%apply unsigned char { char dtyp };
|
||||||
|
|
||||||
%include "idd.hpp"
|
%include "idd.hpp"
|
||||||
@ -11,11 +11,7 @@
|
|||||||
%{
|
%{
|
||||||
//<code(py_idd)>
|
//<code(py_idd)>
|
||||||
|
|
||||||
#ifndef PYUL_DEFINED
|
//-------------------------------------------------------------------------
|
||||||
#define PYUL_DEFINED
|
|
||||||
typedef unsigned PY_LONG_LONG pyul_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool dbg_can_query()
|
bool dbg_can_query()
|
||||||
{
|
{
|
||||||
// Reject the request only if no debugger is set
|
// Reject the request only if no debugger is set
|
||||||
@ -23,6 +19,7 @@ bool dbg_can_query()
|
|||||||
return !(dbg == NULL || (!dbg->may_disturb() && get_process_state() != DSTATE_SUSP));
|
return !(dbg == NULL || (!dbg->may_disturb() && get_process_state() != DSTATE_SUSP));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
PyObject *meminfo_vec_t_to_py(meminfo_vec_t &areas)
|
PyObject *meminfo_vec_t_to_py(meminfo_vec_t &areas)
|
||||||
{
|
{
|
||||||
PyObject *py_list = PyList_New(areas.size());
|
PyObject *py_list = PyList_New(areas.size());
|
||||||
@ -32,19 +29,20 @@ PyObject *meminfo_vec_t_to_py(meminfo_vec_t &areas)
|
|||||||
{
|
{
|
||||||
const memory_info_t &mi = *it;
|
const memory_info_t &mi = *it;
|
||||||
// startEA endEA name sclass sbase bitness perm
|
// startEA endEA name sclass sbase bitness perm
|
||||||
PyList_SetItem(py_list, i,
|
PyList_SetItem(py_list, i,
|
||||||
Py_BuildValue("(KKssKii)",
|
Py_BuildValue("(KKssKii)",
|
||||||
pyul_t(mi.startEA),
|
pyul_t(mi.startEA),
|
||||||
pyul_t(mi.endEA),
|
pyul_t(mi.endEA),
|
||||||
mi.name.c_str(),
|
mi.name.c_str(),
|
||||||
mi.sclass.c_str(),
|
mi.sclass.c_str(),
|
||||||
pyul_t(mi.sbase),
|
pyul_t(mi.sbase),
|
||||||
(unsigned int)(mi.bitness),
|
(unsigned int)(mi.bitness),
|
||||||
(unsigned int)mi.perm));
|
(unsigned int)mi.perm));
|
||||||
}
|
}
|
||||||
return py_list;
|
return py_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
PyObject *dbg_get_memory_info()
|
PyObject *dbg_get_memory_info()
|
||||||
{
|
{
|
||||||
if (!dbg_can_query())
|
if (!dbg_can_query())
|
||||||
@ -59,11 +57,12 @@ PyObject *dbg_get_memory_info()
|
|||||||
return meminfo_vec_t_to_py(areas);
|
return meminfo_vec_t_to_py(areas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
PyObject *dbg_get_registers()
|
PyObject *dbg_get_registers()
|
||||||
{
|
{
|
||||||
if (dbg == NULL)
|
if (dbg == NULL)
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
PyObject *py_list = PyList_New(dbg->registers_size);
|
PyObject *py_list = PyList_New(dbg->registers_size);
|
||||||
|
|
||||||
for (int i=0;i<dbg->registers_size;i++)
|
for (int i=0;i<dbg->registers_size;i++)
|
||||||
@ -89,11 +88,11 @@ PyObject *dbg_get_registers()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// name flags class dtyp bit_strings bit_strings_default_mask
|
// name flags class dtyp bit_strings bit_strings_default_mask
|
||||||
PyList_SetItem(py_list, i,
|
PyList_SetItem(py_list, i,
|
||||||
Py_BuildValue("(sIIINI)",
|
Py_BuildValue("(sIIINI)",
|
||||||
ri.name,
|
ri.name,
|
||||||
ri.flags,
|
ri.flags,
|
||||||
(unsigned int)ri.register_class,
|
(unsigned int)ri.register_class,
|
||||||
(unsigned int)ri.dtyp,
|
(unsigned int)ri.dtyp,
|
||||||
py_bits,
|
py_bits,
|
||||||
(unsigned int)ri.bit_strings_default));
|
(unsigned int)ri.bit_strings_default));
|
||||||
@ -101,6 +100,7 @@ PyObject *dbg_get_registers()
|
|||||||
return py_list;
|
return py_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
PyObject *dbg_get_thread_sreg_base(PyObject *py_tid, PyObject *py_sreg_value)
|
PyObject *dbg_get_thread_sreg_base(PyObject *py_tid, PyObject *py_sreg_value)
|
||||||
{
|
{
|
||||||
if (!dbg_can_query() || !PyInt_Check(py_tid) || !PyInt_Check(py_sreg_value))
|
if (!dbg_can_query() || !PyInt_Check(py_tid) || !PyInt_Check(py_sreg_value))
|
||||||
@ -113,6 +113,7 @@ PyObject *dbg_get_thread_sreg_base(PyObject *py_tid, PyObject *py_sreg_value)
|
|||||||
return Py_BuildValue("K", pyul_t(answer));
|
return Py_BuildValue("K", pyul_t(answer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
PyObject *dbg_read_memory(PyObject *py_ea, PyObject *py_sz)
|
PyObject *dbg_read_memory(PyObject *py_ea, PyObject *py_sz)
|
||||||
{
|
{
|
||||||
if (!dbg_can_query() || !PyNumber_Check(py_ea) || !PyNumber_Check(py_sz))
|
if (!dbg_can_query() || !PyNumber_Check(py_ea) || !PyNumber_Check(py_sz))
|
||||||
@ -139,6 +140,7 @@ PyObject *dbg_read_memory(PyObject *py_ea, PyObject *py_sz)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
PyObject *dbg_write_memory(PyObject *py_ea, PyObject *py_buf)
|
PyObject *dbg_write_memory(PyObject *py_ea, PyObject *py_buf)
|
||||||
{
|
{
|
||||||
if (!dbg_can_query() || !PyString_Check(py_buf) || !PyNumber_Check(py_ea))
|
if (!dbg_can_query() || !PyString_Check(py_buf) || !PyNumber_Check(py_ea))
|
||||||
@ -151,9 +153,145 @@ PyObject *dbg_write_memory(PyObject *py_ea, PyObject *py_buf)
|
|||||||
Py_RETURN_FALSE;
|
Py_RETURN_FALSE;
|
||||||
Py_RETURN_TRUE;
|
Py_RETURN_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
PyObject *py_appcall(
|
||||||
|
ea_t func_ea,
|
||||||
|
thid_t tid,
|
||||||
|
PyObject *py_type,
|
||||||
|
PyObject *py_fields,
|
||||||
|
PyObject *arg_list)
|
||||||
|
{
|
||||||
|
if (!PyList_Check(arg_list))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
const char *type = py_type == Py_None ? NULL : PyString_AS_STRING(py_type);
|
||||||
|
const char *fields = py_fields == Py_None ? NULL : PyString_AS_STRING(py_fields);
|
||||||
|
|
||||||
|
// Convert Python arguments into IDC values
|
||||||
|
qvector<idc_value_t> idc_args;
|
||||||
|
int sn = 0;
|
||||||
|
Py_ssize_t nargs = PyList_Size(arg_list);
|
||||||
|
idc_args.resize(nargs);
|
||||||
|
bool ok = true;
|
||||||
|
for (Py_ssize_t i=0;i<nargs;i++)
|
||||||
|
{
|
||||||
|
// Get argument
|
||||||
|
PyObject *py_item = PyList_GetItem(arg_list, i);
|
||||||
|
if ( (debug & IDA_DEBUG_APPCALL) != 0 )
|
||||||
|
{
|
||||||
|
qstring s;
|
||||||
|
PyObjectToString(py_item, &s);
|
||||||
|
msg("obj[%d]->%s\n", int(i), s.c_str());
|
||||||
|
}
|
||||||
|
// Convert it
|
||||||
|
if (pyvar_to_idcvar(py_item, &idc_args[i], &sn) <= 0)
|
||||||
|
{
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set exception message
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_ValueError, "PyAppCall: Failed to convert Python values to IDC values");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (debug & IDA_DEBUG_APPCALL) != 0 )
|
||||||
|
{
|
||||||
|
msg("input variables:\n"
|
||||||
|
"----------------\n");
|
||||||
|
qstring s;
|
||||||
|
for (Py_ssize_t i=0;i<nargs;i++)
|
||||||
|
{
|
||||||
|
VarPrint(&s, &idc_args[i]);
|
||||||
|
msg("%d]\n%s\n-----------\n", int(i), s.c_str());
|
||||||
|
s.qclear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Do Appcall
|
||||||
|
idc_value_t idc_result;
|
||||||
|
error_t ret = appcall(
|
||||||
|
func_ea,
|
||||||
|
tid,
|
||||||
|
(type_t *)type,
|
||||||
|
(p_list *)fields,
|
||||||
|
idc_args.size(),
|
||||||
|
idc_args.begin(),
|
||||||
|
&idc_result);
|
||||||
|
|
||||||
|
if (ret != eOk)
|
||||||
|
{
|
||||||
|
// An exception was thrown?
|
||||||
|
if (ret == eExecThrow)
|
||||||
|
{
|
||||||
|
// Convert the result (which is a debug_event) into a Python object
|
||||||
|
PyObject *py_appcall_exc(NULL);
|
||||||
|
idcvar_to_pyvar(idc_result, &py_appcall_exc);
|
||||||
|
PyErr_SetObject(PyExc_OSError, py_appcall_exc);
|
||||||
|
Py_DECREF(py_appcall_exc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
// An error in the Appcall? (or an exception but AppCallOptions/DEBEV is not set)
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char err_str[MAXSTR];
|
||||||
|
qstrerror(ret, err_str, sizeof(err_str));
|
||||||
|
PyErr_SetString(PyExc_Exception, err_str);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (debug & IDA_DEBUG_APPCALL) != 0 )
|
||||||
|
{
|
||||||
|
msg("return variables:\n"
|
||||||
|
"-----------------\n");
|
||||||
|
qstring s;
|
||||||
|
for (Py_ssize_t i=0;i<nargs;i++)
|
||||||
|
{
|
||||||
|
VarPrint(&s, &idc_args[i]);
|
||||||
|
msg("%d]\n%s\n-----------\n", int(i), s.c_str());
|
||||||
|
s.qclear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Convert IDC values back to Python values
|
||||||
|
for (Py_ssize_t i=0;i<nargs;i++)
|
||||||
|
{
|
||||||
|
// Get argument
|
||||||
|
PyObject *py_item = PyList_GetItem(arg_list, i);
|
||||||
|
// We convert arguments but fail only on fatal errors
|
||||||
|
// (we ignore failure because of immutable objects)
|
||||||
|
if (idcvar_to_pyvar(idc_args[i], &py_item) == CIP_FAILED)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_ValueError, "PyAppCall: Failed while converting IDC values to Python values");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Convert the result from IDC back to Python
|
||||||
|
PyObject *py_result(NULL);
|
||||||
|
if (idcvar_to_pyvar(idc_result, &py_result) <= CIP_IMMUTABLE)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_ValueError, "PyAppCall: Failed while converting IDC return value to Python return value");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (debug & IDA_DEBUG_APPCALL) != 0 )
|
||||||
|
{
|
||||||
|
msg("return var:\n"
|
||||||
|
"-----------\n");
|
||||||
|
qstring s;
|
||||||
|
VarPrint(&s, &idc_result);
|
||||||
|
msg("%s\n-----------\n", s.c_str());
|
||||||
|
}
|
||||||
|
return py_result;
|
||||||
|
}
|
||||||
//</code(py_idd)>
|
//</code(py_idd)>
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
%rename (appcall) py_appcall;
|
||||||
|
|
||||||
%inline %{
|
%inline %{
|
||||||
|
|
||||||
//<inline(py_idd)>
|
//<inline(py_idd)>
|
||||||
@ -163,6 +301,12 @@ PyObject *dbg_get_thread_sreg_base(PyObject *py_tid, PyObject *py_sreg_value);
|
|||||||
PyObject *dbg_get_registers();
|
PyObject *dbg_get_registers();
|
||||||
PyObject *dbg_get_memory_info();
|
PyObject *dbg_get_memory_info();
|
||||||
bool dbg_can_query();
|
bool dbg_can_query();
|
||||||
|
PyObject *py_appcall(
|
||||||
|
ea_t func_ea,
|
||||||
|
thid_t tid,
|
||||||
|
PyObject *py_type,
|
||||||
|
PyObject *py_fields,
|
||||||
|
PyObject *arg_list);
|
||||||
//</inline(py_idd)>
|
//</inline(py_idd)>
|
||||||
|
|
||||||
char get_event_module_name(const debug_event_t* ev, char *buf, size_t bufsize)
|
char get_event_module_name(const debug_event_t* ev, char *buf, size_t bufsize)
|
||||||
@ -213,3 +357,352 @@ bool can_exc_continue(const debug_event_t* ev)
|
|||||||
return ev->exc.can_cont;
|
return ev->exc.can_cont;
|
||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
%pythoncode %{
|
||||||
|
#<pycode(py_idd)>
|
||||||
|
import types
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# This class is used with |Appcall.array() method
|
||||||
|
class Appcall_array__(object):
|
||||||
|
def __init__(self, tp):
|
||||||
|
self.__type = tp
|
||||||
|
|
||||||
|
def pack(self, L):
|
||||||
|
t = type(L)
|
||||||
|
if not (t == types.ListType or t == types.TupleType):
|
||||||
|
raise ValueError, "Either a list or a type must be passed"
|
||||||
|
self.__size = len(L)
|
||||||
|
if self.__size == 1:
|
||||||
|
self.__typedobj = Appcall__.typedobj(self.__type + ";")
|
||||||
|
else:
|
||||||
|
self.__typedobj = Appcall__.typedobj("%s x[%d];" % (self.__type, self.__size))
|
||||||
|
# Now store the object in a string buffer
|
||||||
|
ok, buf = self.__typedobj.store(L)
|
||||||
|
if ok:
|
||||||
|
return Appcall__.byref(buf)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def try_to_convert_to_list(self, obj):
|
||||||
|
if not (hasattr(obj, "0") and hasattr(obj, str(self.__size-1))):
|
||||||
|
return obj
|
||||||
|
# at this point, we are sure we have an "idc list"
|
||||||
|
# let us convert to a Python list
|
||||||
|
return [getattr(obj, str(x)) for x in xrange(0, self.__size)]
|
||||||
|
|
||||||
|
def unpack(self, buf, as_list=True):
|
||||||
|
# take the value from the special ref object
|
||||||
|
if isinstance(buf, PyIdc_cvt_refclass__):
|
||||||
|
buf = buf.value
|
||||||
|
|
||||||
|
# we can only unpack from strings
|
||||||
|
if type(buf) != types.StringType:
|
||||||
|
raise ValueError, "Cannot unpack this type!"
|
||||||
|
# now unpack
|
||||||
|
ok, obj = self.__typedobj.retrieve(buf)
|
||||||
|
if not ok:
|
||||||
|
raise ValueError, "Failed while unpacking!"
|
||||||
|
if not as_list:
|
||||||
|
return obj
|
||||||
|
return self.try_to_convert_to_list(obj)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# This class is used with the obj() method
|
||||||
|
class Appcall_object__(object):
|
||||||
|
"""Helper class used to initialize empty objects"""
|
||||||
|
def __init__(self, **kwds):
|
||||||
|
self.__dict__ = kwds
|
||||||
|
|
||||||
|
def __getitem__(self, idx):
|
||||||
|
return getattr(self, idx)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Wrapper class for the appcall()
|
||||||
|
class Appcall_callable__(object):
|
||||||
|
"""
|
||||||
|
Helper class to issue appcalls using a natural syntax:
|
||||||
|
appcall.FunctionNameInTheDatabase(arguments, ....)
|
||||||
|
or
|
||||||
|
appcall["Function@8"](arguments, ...)
|
||||||
|
or
|
||||||
|
f8 = appcall["Function@8"]
|
||||||
|
f8(arg1, arg2, ...)
|
||||||
|
or
|
||||||
|
o = appcall.obj()
|
||||||
|
i = byref(5)
|
||||||
|
appcall.funcname(arg1, i, "hello", o)
|
||||||
|
"""
|
||||||
|
def __init__(self, ea, tp = None, fld = None):
|
||||||
|
"""Initializes an appcall with a given function ea"""
|
||||||
|
self.__ea = ea
|
||||||
|
self.__type = tp
|
||||||
|
self.__fields = fld
|
||||||
|
self.__options = None # Appcall options
|
||||||
|
|
||||||
|
def __get_options(self):
|
||||||
|
return self.__options if self.__options != None else Appcall__.get_appcall_options()
|
||||||
|
def __set_options(self, v):
|
||||||
|
self.__options = v
|
||||||
|
"""Sets the Appcall options locally to this Appcall instance"""
|
||||||
|
options = property(__get_options, __set_options)
|
||||||
|
|
||||||
|
def __call__(self, *args):
|
||||||
|
"""Make object callable. We redirect execution to idaapi.appcall()"""
|
||||||
|
if self.ea == None:
|
||||||
|
raise ValueError, "Object not callable!"
|
||||||
|
|
||||||
|
# unpack arguments and convert to a list
|
||||||
|
arg_list = [x for x in args]
|
||||||
|
|
||||||
|
# Save appcall options and set new global options
|
||||||
|
old_opt = Appcall__.get_appcall_options()
|
||||||
|
Appcall__.set_appcall_options(self.options)
|
||||||
|
|
||||||
|
# Do the Appcall (use the wrapped version)
|
||||||
|
e_obj = None
|
||||||
|
try:
|
||||||
|
r = _idaapi.appcall(
|
||||||
|
self.ea,
|
||||||
|
_idaapi.get_current_thread(),
|
||||||
|
self.type,
|
||||||
|
self.fields,
|
||||||
|
arg_list)
|
||||||
|
except Exception, e:
|
||||||
|
e_obj = e
|
||||||
|
|
||||||
|
# Restore appcall options
|
||||||
|
Appcall__.set_appcall_options(old_opt)
|
||||||
|
|
||||||
|
# Return or re-raise exception
|
||||||
|
if e_obj:
|
||||||
|
raise Exception, e_obj
|
||||||
|
return r
|
||||||
|
|
||||||
|
def __get_ea(self):
|
||||||
|
return self.__ea
|
||||||
|
def __set_ea(self, val):
|
||||||
|
self.__ea = val
|
||||||
|
"""Returns or sets the EA associated with this object"""
|
||||||
|
ea = property(__get_ea, __set_ea)
|
||||||
|
|
||||||
|
def __get_size(self):
|
||||||
|
if self.__type == None:
|
||||||
|
return -1
|
||||||
|
r = _idaapi.get_type_size0(_idaapi.cvar.idati, self.__type)
|
||||||
|
if not r:
|
||||||
|
return -1
|
||||||
|
return r
|
||||||
|
"""Returns the size of the type"""
|
||||||
|
size = property(__get_size)
|
||||||
|
|
||||||
|
def __get_type(self):
|
||||||
|
return self.__type
|
||||||
|
"""Returns the typestring"""
|
||||||
|
type = property(__get_type)
|
||||||
|
|
||||||
|
def __get_fields(self):
|
||||||
|
return self.__fields
|
||||||
|
"""Returns the typestring"""
|
||||||
|
fields = property(__get_fields)
|
||||||
|
|
||||||
|
def retrieve(self, src=None, flags=0):
|
||||||
|
"""
|
||||||
|
Unpacks a typed object from the database if an ea is given or from a string if a string was passed
|
||||||
|
@param src: the address of the object or a string
|
||||||
|
@return: Returns a tuple of boolean and object or error number (Bool, Error | Object).
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Nothing passed? Take the address and unpack from the database
|
||||||
|
if not src:
|
||||||
|
src = self.ea
|
||||||
|
|
||||||
|
if type(src) == types.StringType:
|
||||||
|
return _idaapi.unpack_object_from_bv(_idaapi.cvar.idati, self.type, self.fields, src, flags)
|
||||||
|
else:
|
||||||
|
return _idaapi.unpack_object_from_idb(_idaapi.cvar.idati, self.type, self.fields, src, flags)
|
||||||
|
|
||||||
|
def store(self, obj, dest_ea=None, base_ea=0, flags=0):
|
||||||
|
"""
|
||||||
|
Packs an object into a given ea if provided or into a string if no address was passed.
|
||||||
|
|
||||||
|
@return: - If packing to a string then a Tuple(Boolean, packed_string or error code)
|
||||||
|
- If packing to the database then a return code is returned (0 is success)
|
||||||
|
"""
|
||||||
|
|
||||||
|
# no ea passed? thus pack to a string
|
||||||
|
if not dest_ea:
|
||||||
|
return _idaapi.pack_object_to_bv(obj, _idaapi.cvar.idati, self.type, self.fields, base_ea, flags)
|
||||||
|
else:
|
||||||
|
return _idaapi.pack_object_to_idb(obj, _idaapi.cvar.idati, self.type, self.fields, dest_ea, flags)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
class Appcall_consts__(object):
|
||||||
|
def __init__(self, default=0):
|
||||||
|
self.__default = default
|
||||||
|
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
return Appcall__.valueof(attr, self.__default)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
class Appcall__(object):
|
||||||
|
"""
|
||||||
|
Only set up the appcall, do not run it.
|
||||||
|
you should call CleanupAppcall() when finished
|
||||||
|
"""
|
||||||
|
APPCALL_MANUAL = 0x1
|
||||||
|
"""
|
||||||
|
Return debug event information
|
||||||
|
If this bit is set, exceptions during appcall
|
||||||
|
will generate idc exceptions with full
|
||||||
|
information about the exception
|
||||||
|
"""
|
||||||
|
APPCALL_DEBEV = 0x2
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.__consts = Appcall_consts__()
|
||||||
|
|
||||||
|
def __get_consts(self):
|
||||||
|
return self.__consts
|
||||||
|
"""Use Appcall.Consts.CONST_NAME to access constants"""
|
||||||
|
Consts = property(__get_consts)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __name_or_ea(name_or_ea):
|
||||||
|
"""Function that accepts a name or an ea and checks if the address is enabled.
|
||||||
|
If a name is passed then idaapi.get_name_ea() is applied to retrieve the name
|
||||||
|
@return: Returns the resolved EA or raises an exception if the address is not enabled
|
||||||
|
"""
|
||||||
|
|
||||||
|
# a string? try to resolve it
|
||||||
|
if type(name_or_ea) == types.StringType:
|
||||||
|
ea = _idaapi.get_name_ea(_idaapi.BADADDR, name_or_ea)
|
||||||
|
else:
|
||||||
|
ea = name_or_ea
|
||||||
|
# could not resolve name or invalid address?
|
||||||
|
if ea == _idaapi.BADADDR or not _idaapi.isEnabled(ea):
|
||||||
|
raise ValueError, "Undefined function " + name_or_ea
|
||||||
|
return ea
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def proto(name_or_ea, prototype, flags = None):
|
||||||
|
"""Allows you to instantiate an appcall with the desired prototype"""
|
||||||
|
|
||||||
|
# resolve and raise exception on error
|
||||||
|
ea = Appcall__.__name_or_ea(name_or_ea)
|
||||||
|
# parse the type
|
||||||
|
if not flags:
|
||||||
|
flags = 1 | 2 | 4 # PT_SIL | PT_NDC | PT_TYP
|
||||||
|
result = _idaapi.idc_parse_decl(_idaapi.cvar.idati, prototype, flags)
|
||||||
|
if not result:
|
||||||
|
raise ValueError, "Could not parse type: " + prototype
|
||||||
|
# Return the callable method with type info
|
||||||
|
return Appcall_callable__(ea, result[1], result[2])
|
||||||
|
|
||||||
|
def __getattr__(self, name_or_ea):
|
||||||
|
"""Allows you to call functions as if they were member functions"""
|
||||||
|
# resolve and raise exception on error
|
||||||
|
ea = self.__name_or_ea(name_or_ea)
|
||||||
|
if ea == _idaapi.BADADDR:
|
||||||
|
raise ValueError, "Undefined function " + name
|
||||||
|
# Return the callable method
|
||||||
|
return Appcall_callable__(ea)
|
||||||
|
|
||||||
|
def __getitem__(self, idx):
|
||||||
|
"""
|
||||||
|
Use self[func_name] syntax if the function name contains invalid characters for an attribute name
|
||||||
|
See __getattr___
|
||||||
|
"""
|
||||||
|
return self.__getattr__(idx)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def valueof(name, default=0):
|
||||||
|
"""
|
||||||
|
Returns the numeric value of a given name string.
|
||||||
|
If the name could not be resolved then the default value will be returned
|
||||||
|
"""
|
||||||
|
t, v = _idaapi.get_name_value(_idaapi.BADADDR, name)
|
||||||
|
if t == 0: # NT_NONE
|
||||||
|
v = default
|
||||||
|
return v
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def int64(v):
|
||||||
|
"""Whenever a 64bit number is needed use this method to construct an object"""
|
||||||
|
return PyIdc_cvt_int64__(v)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def byref(val):
|
||||||
|
"""
|
||||||
|
Method to create references to immutable objects
|
||||||
|
Currently we support references to int/strings
|
||||||
|
Objects need not be passed by reference (this will be done automatically)
|
||||||
|
"""
|
||||||
|
return PyIdc_cvt_refclass__(val)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def buffer(str = None, size = 0, fill="\x00"):
|
||||||
|
"""
|
||||||
|
Creates a string buffer. The returned value (r) will be a byref object.
|
||||||
|
Use r.value to get the contents and r.size to get the buffer's size
|
||||||
|
"""
|
||||||
|
if not str:
|
||||||
|
str = ""
|
||||||
|
left = size - len(str)
|
||||||
|
if left > 0:
|
||||||
|
str = str + (fill * left)
|
||||||
|
r = Appcall__.byref(str)
|
||||||
|
r.size = size
|
||||||
|
return r
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def obj(**kwds):
|
||||||
|
"""Returns an empty object or objects with attributes as passed via its keywords arguments"""
|
||||||
|
return Appcall_object__(**kwds)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def cstr(val):
|
||||||
|
return as_cstr(val)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def unicode(s):
|
||||||
|
return as_unicode(s)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def array(type_name):
|
||||||
|
"""Defines an array type. Later you need to pack() / unpack()"""
|
||||||
|
return Appcall_array__(type_name)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def typedobj(typestr, ea=None):
|
||||||
|
"""
|
||||||
|
Parses a type string and returns an appcall object.
|
||||||
|
One can then use retrieve() member method
|
||||||
|
@param ea: Optional parameter that later can be used to retrieve the type
|
||||||
|
@return: Appcall object
|
||||||
|
"""
|
||||||
|
# parse the type
|
||||||
|
result = _idaapi.idc_parse_decl(_idaapi.cvar.idati, typestr, 1 | 2 | 4) # PT_SIL | PT_NDC | PT_TYP
|
||||||
|
if not result:
|
||||||
|
raise ValueError, "Could not parse type: " + typestr
|
||||||
|
# Return the callable method with type info
|
||||||
|
return Appcall_callable__(ea, result[1], result[2])
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def set_appcall_options(opt):
|
||||||
|
old_opt = Appcall__.get_appcall_options()
|
||||||
|
_idaapi.cvar.inf.appcall_options = opt
|
||||||
|
return old_opt
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_appcall_options():
|
||||||
|
return _idaapi.cvar.inf.appcall_options
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def cleanup_appcall(tid = 0):
|
||||||
|
"""Equivalent to IDC's CleanupAppcall()"""
|
||||||
|
return _idaapi.cleanup_appcall(tid)
|
||||||
|
|
||||||
|
Appcall = Appcall__()
|
||||||
|
#</pycode(py_idd)>
|
||||||
|
%}
|
@ -50,7 +50,7 @@
|
|||||||
%ignore processor_t::gen_stkvar_def;
|
%ignore processor_t::gen_stkvar_def;
|
||||||
%ignore processor_t::u_outspec;
|
%ignore processor_t::u_outspec;
|
||||||
%ignore processor_t::is_align_insn;
|
%ignore processor_t::is_align_insn;
|
||||||
|
%ignore IDB_Callback;
|
||||||
%ignore processor_t::idp_notify;
|
%ignore processor_t::idp_notify;
|
||||||
%ignore processor_t::notify;
|
%ignore processor_t::notify;
|
||||||
%ignore processor_t::set_idp_options;
|
%ignore processor_t::set_idp_options;
|
||||||
@ -113,7 +113,7 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
|
|||||||
class IDB_Hooks *proxy = (class IDB_Hooks *)ud;
|
class IDB_Hooks *proxy = (class IDB_Hooks *)ud;
|
||||||
ea_t ea, ea2;
|
ea_t ea, ea2;
|
||||||
bool repeatable_cmt;
|
bool repeatable_cmt;
|
||||||
type_t *type;
|
/*type_t *type;*/
|
||||||
/* p_list *fnames; */
|
/* p_list *fnames; */
|
||||||
int n;
|
int n;
|
||||||
enum_t id;
|
enum_t id;
|
||||||
@ -269,7 +269,7 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
|
|||||||
return proxy->segm_moved(ea, ea2, size);
|
return proxy->segm_moved(ea, ea2, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Swig::DirectorException &e)
|
catch (Swig::DirectorException &)
|
||||||
{
|
{
|
||||||
msg("Exception in IDP Hook function:\n");
|
msg("Exception in IDP Hook function:\n");
|
||||||
if (PyErr_Occurred())
|
if (PyErr_Occurred())
|
||||||
|
@ -156,14 +156,6 @@ uint32 choose_choose(PyObject *self,
|
|||||||
|
|
||||||
//<code(py_choose2)>
|
//<code(py_choose2)>
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
|
||||||
static PyObject *PyObject_TryGetAttrString(PyObject *object, const char *attr)
|
|
||||||
{
|
|
||||||
if (!PyObject_HasAttrString(object, attr))
|
|
||||||
return NULL;
|
|
||||||
return PyObject_GetAttrString(object, attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Some defines
|
// Some defines
|
||||||
#define POPUP_NAMES_COUNT 4
|
#define POPUP_NAMES_COUNT 4
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
// TODO: These could be wrapped if needed
|
// TODO: These could be wrapped if needed
|
||||||
%ignore load_info_t;
|
%ignore load_info_t;
|
||||||
|
%ignore add_plugin_option;
|
||||||
%ignore build_loaders_list;
|
%ignore build_loaders_list;
|
||||||
%ignore free_loaders_list;
|
%ignore free_loaders_list;
|
||||||
%ignore get_loader_name_from_dll;
|
%ignore get_loader_name_from_dll;
|
||||||
|
228
swig/typeinf.i
228
swig/typeinf.i
@ -10,6 +10,10 @@
|
|||||||
%ignore get_de;
|
%ignore get_de;
|
||||||
%ignore skip_ptr_type_header;
|
%ignore skip_ptr_type_header;
|
||||||
%ignore skip_array_type_header;
|
%ignore skip_array_type_header;
|
||||||
|
%ignore unpack_object_from_idb;
|
||||||
|
%ignore unpack_object_from_bv;
|
||||||
|
%ignore pack_object_to_idb;
|
||||||
|
%ignore pack_object_to_bv;
|
||||||
%ignore typend;
|
%ignore typend;
|
||||||
%ignore typlen;
|
%ignore typlen;
|
||||||
%ignore typncpy;
|
%ignore typncpy;
|
||||||
@ -133,22 +137,230 @@
|
|||||||
%ignore build_anon_type_name;
|
%ignore build_anon_type_name;
|
||||||
%ignore type_names;
|
%ignore type_names;
|
||||||
%ignore get_compiler_id;
|
%ignore get_compiler_id;
|
||||||
|
%ignore reloc_info_t;
|
||||||
|
%ignore relobj_t;
|
||||||
|
%ignore regobj_t;
|
||||||
%ignore build_func_type;
|
%ignore build_func_type;
|
||||||
|
|
||||||
%include "typeinf.hpp"
|
%include "typeinf.hpp"
|
||||||
|
|
||||||
|
%{
|
||||||
|
//<code(py_typeinf)>
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Utility function to convert a python object to an IDC object
|
||||||
|
// and sets a python exception on failure.
|
||||||
|
static bool convert_pyobj_to_idc_exc(PyObject *py_obj, idc_value_t *idc_obj)
|
||||||
|
{
|
||||||
|
int sn = 0;
|
||||||
|
if (pyvar_to_idcvar(py_obj, idc_obj, &sn) <= 0)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_ValueError, "Could not convert Python object to IDC object!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//</code(py_typeinf)>
|
||||||
|
%}
|
||||||
// Custom wrappers
|
// Custom wrappers
|
||||||
|
|
||||||
%rename (load_til) load_til_wrap;
|
%rename (load_til) load_til_wrap;
|
||||||
|
%rename (get_type_size0) py_get_type_size0;
|
||||||
|
%rename (unpack_object_from_idb) py_unpack_object_from_idb;
|
||||||
|
%rename (unpack_object_from_bv) py_unpack_object_from_bv;
|
||||||
|
%rename (pack_object_to_idb) py_pack_object_to_idb;
|
||||||
|
%rename (pack_object_to_bv) py_pack_object_to_bv;
|
||||||
%inline %{
|
%inline %{
|
||||||
|
//<inline(py_typeinf)>
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
PyObject *idc_parse_decl(til_t *ti, const char *decl, int flags)
|
||||||
|
{
|
||||||
|
qtype fields, type;
|
||||||
|
qstring name;
|
||||||
|
bool ok = parse_decl(ti, decl, &name, &type, &fields, flags);
|
||||||
|
if (!ok)
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
return Py_BuildValue("(sss)",
|
||||||
|
name.c_str(),
|
||||||
|
(char *)type.c_str(),
|
||||||
|
(char *)fields.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
PyObject *py_get_type_size0(const til_t *ti, PyObject *tp)
|
||||||
|
{
|
||||||
|
if (!PyString_Check(tp))
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_ValueError, "String expected!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
size_t sz = get_type_size0(ti, (type_t *)PyString_AsString(tp));
|
||||||
|
if (sz == BADSIZE)
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
return PyInt_FromLong(sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Read a typed idc object from the database
|
||||||
|
PyObject *py_unpack_object_from_idb(
|
||||||
|
til_t *ti,
|
||||||
|
PyObject *py_type,
|
||||||
|
PyObject *py_fields,
|
||||||
|
ea_t ea,
|
||||||
|
int pio_flags)
|
||||||
|
{
|
||||||
|
if (!PyString_Check(py_type) && !PyString_Check(py_fields))
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unpack
|
||||||
|
type_t *type = (type_t *) PyString_AsString(py_type);
|
||||||
|
p_list *fields = (p_list *) PyString_AsString(py_fields);
|
||||||
|
idc_value_t idc_obj;
|
||||||
|
error_t err = unpack_object_from_idb(&idc_obj, ti, type, fields, ea, NULL, pio_flags);
|
||||||
|
|
||||||
|
// Unpacking failed?
|
||||||
|
if (err != eOk)
|
||||||
|
return Py_BuildValue("(ii)", 0, err);
|
||||||
|
|
||||||
|
// Convert
|
||||||
|
PyObject *py_ret(NULL);
|
||||||
|
err = idcvar_to_pyvar(idc_obj, &py_ret);
|
||||||
|
// Conversion failed?
|
||||||
|
if (err != CIP_OK)
|
||||||
|
return Py_BuildValue("(ii)", 0, err);
|
||||||
|
return Py_BuildValue("(iO)", 1, py_ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Read a typed idc object from the byte vector
|
||||||
|
PyObject *py_unpack_object_from_bv(
|
||||||
|
til_t *ti,
|
||||||
|
PyObject *py_type,
|
||||||
|
PyObject *py_fields,
|
||||||
|
PyObject *py_bytes,
|
||||||
|
int pio_flags)
|
||||||
|
{
|
||||||
|
if (!PyString_Check(py_type) && !PyString_Check(py_fields) && !PyString_Check(py_bytes))
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_ValueError, "Incorrect argument type!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get type strings
|
||||||
|
type_t *type = (type_t *) PyString_AsString(py_type);
|
||||||
|
p_list *fields = (p_list *) PyString_AsString(py_fields);
|
||||||
|
|
||||||
|
// Make a byte vector
|
||||||
|
bytevec_t bytes;
|
||||||
|
bytes.resize(PyString_Size(py_bytes));
|
||||||
|
memcpy(bytes.begin(), PyString_AsString(py_bytes), bytes.size());
|
||||||
|
|
||||||
|
idc_value_t idc_obj;
|
||||||
|
error_t err = unpack_object_from_bv(&idc_obj, ti, type, fields, bytes, pio_flags);
|
||||||
|
|
||||||
|
// Unpacking failed?
|
||||||
|
if (err != eOk)
|
||||||
|
return Py_BuildValue("(ii)", 0, err);
|
||||||
|
|
||||||
|
// Convert
|
||||||
|
PyObject *py_ret(NULL);
|
||||||
|
err = idcvar_to_pyvar(idc_obj, &py_ret);
|
||||||
|
// Conversion failed?
|
||||||
|
if (err != CIP_OK)
|
||||||
|
return Py_BuildValue("(ii)", 0, err);
|
||||||
|
return Py_BuildValue("(iO)", 1, py_ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Write a typed idc object to the database
|
||||||
|
// Raises an exception if wrong parameters were passed or conversion fails
|
||||||
|
// Returns the error_t returned by idasdk.pack_object_to_idb
|
||||||
|
PyObject *py_pack_object_to_idb(
|
||||||
|
PyObject *py_obj,
|
||||||
|
til_t *ti,
|
||||||
|
PyObject *py_type,
|
||||||
|
PyObject *py_fields,
|
||||||
|
ea_t ea,
|
||||||
|
int pio_flags)
|
||||||
|
{
|
||||||
|
if (!PyString_Check(py_type) && !PyString_Check(py_fields))
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert Python object to IDC object
|
||||||
|
idc_value_t idc_obj;
|
||||||
|
if (!convert_pyobj_to_idc_exc(py_obj, &idc_obj))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Get type strings
|
||||||
|
type_t *type = (type_t *) PyString_AsString(py_type);
|
||||||
|
p_list *fields = (p_list *) PyString_AsString(py_fields);
|
||||||
|
|
||||||
|
// Pack
|
||||||
|
error_t err = pack_object_to_idb(&idc_obj, ti, type, fields, ea, pio_flags);
|
||||||
|
return PyInt_FromLong(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Returns a tuple(Boolean, PackedBuffer or Error Code)
|
||||||
|
PyObject *py_pack_object_to_bv(
|
||||||
|
PyObject *py_obj,
|
||||||
|
til_t *ti,
|
||||||
|
PyObject *py_type,
|
||||||
|
PyObject *py_fields,
|
||||||
|
ea_t base_ea,
|
||||||
|
int pio_flags=0)
|
||||||
|
{
|
||||||
|
if (!PyString_Check(py_type) && !PyString_Check(py_fields))
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert Python object to IDC object
|
||||||
|
idc_value_t idc_obj;
|
||||||
|
if (!convert_pyobj_to_idc_exc(py_obj, &idc_obj))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Get type strings
|
||||||
|
type_t *type = (type_t *) PyString_AsString(py_type);
|
||||||
|
p_list *fields = (p_list *) PyString_AsString(py_fields);
|
||||||
|
|
||||||
|
// Pack
|
||||||
|
relobj_t bytes;
|
||||||
|
error_t err = pack_object_to_bv(
|
||||||
|
&idc_obj,
|
||||||
|
ti,
|
||||||
|
type,
|
||||||
|
fields,
|
||||||
|
&bytes,
|
||||||
|
NULL,
|
||||||
|
pio_flags);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (err != eOk)
|
||||||
|
break;
|
||||||
|
if (!bytes.relocate(base_ea, inf.mf))
|
||||||
|
{
|
||||||
|
err = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Py_BuildValue("(is#)", 1, bytes.begin(), bytes.size());
|
||||||
|
} while (false);
|
||||||
|
return Py_BuildValue("(ii)", 0, err);
|
||||||
|
}
|
||||||
|
//</inline(py_typeinf)>
|
||||||
til_t * load_til(const char *tildir, const char *name)
|
til_t * load_til(const char *tildir, const char *name)
|
||||||
{
|
{
|
||||||
char errbuf[4096];
|
char errbuf[4096];
|
||||||
til_t *res;
|
til_t *res;
|
||||||
|
|
||||||
res = load_til(tildir, name, errbuf, sizeof(errbuf));
|
res = load_til(tildir, name, errbuf, sizeof(errbuf));
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
PyErr_SetString(PyExc_RuntimeError, errbuf);
|
PyErr_SetString(PyExc_RuntimeError, errbuf);
|
||||||
@ -165,9 +377,9 @@ til_t * load_til_header_wrap(const char *tildir, const char *name)
|
|||||||
{
|
{
|
||||||
char errbuf[4096];
|
char errbuf[4096];
|
||||||
til_t *res;
|
til_t *res;
|
||||||
|
|
||||||
res = load_til_header(tildir, name, errbuf, sizeof(errbuf));;
|
res = load_til_header(tildir, name, errbuf, sizeof(errbuf));;
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
PyErr_SetString(PyExc_RuntimeError, errbuf);
|
PyErr_SetString(PyExc_RuntimeError, errbuf);
|
||||||
@ -196,7 +408,7 @@ char *idc_get_type(ea_t ea, char *buf, size_t bufsize)
|
|||||||
{
|
{
|
||||||
type_t type[MAXSTR];
|
type_t type[MAXSTR];
|
||||||
p_list fnames[MAXSTR];
|
p_list fnames[MAXSTR];
|
||||||
|
|
||||||
if (get_ti(ea, type, sizeof(type), fnames, sizeof(fnames)))
|
if (get_ti(ea, type, sizeof(type), fnames, sizeof(fnames)))
|
||||||
{
|
{
|
||||||
int code = print_type_to_one_line(buf, bufsize, idati, type,
|
int code = print_type_to_one_line(buf, bufsize, idati, type,
|
||||||
@ -211,7 +423,7 @@ char *idc_guess_type(ea_t ea, char *buf, size_t bufsize)
|
|||||||
{
|
{
|
||||||
type_t type[MAXSTR];
|
type_t type[MAXSTR];
|
||||||
p_list fnames[MAXSTR];
|
p_list fnames[MAXSTR];
|
||||||
|
|
||||||
if (guess_type(ea, type, sizeof(type), fnames, sizeof(fnames)))
|
if (guess_type(ea, type, sizeof(type), fnames, sizeof(fnames)))
|
||||||
{
|
{
|
||||||
int code = print_type_to_one_line(buf, bufsize, idati, type,
|
int code = print_type_to_one_line(buf, bufsize, idati, type,
|
||||||
@ -234,7 +446,7 @@ int idc_set_local_type(int ordinal, const char *dcl, int flags)
|
|||||||
qstring name;
|
qstring name;
|
||||||
qtype type;
|
qtype type;
|
||||||
qtype fields;
|
qtype fields;
|
||||||
|
|
||||||
if (!parse_decl(idati, dcl, &name, &type, &fields, flags))
|
if (!parse_decl(idati, dcl, &name, &type, &fields, flags))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user