IDAPython 1.3.0 / IDA Pro 5.6

(For older versions please use the 1.2.90 branch)
This commit is contained in:
elias.bachaalany 2010-01-05 18:24:04 +00:00
parent ab7a03431e
commit 277facf240
20 changed files with 2104 additions and 253 deletions

View File

@ -9,8 +9,8 @@ REQUIREMENTS
[Tested versions are in brackets]
- IDA and IDA SDK [5.4]
http://www.datarescue.com/idabase/
- IDA and IDA SDK [5.6]
http://www.hex-rays.com/idapro/
- Python [2.5.1, 2.6.1]
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
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
2, Patch the SDK using GNU Patch with one of patches from patches/ directory.
You will have to use the -P option depending on which directory you
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/
2, On Mac OS X copy libida.dylib from the IDA install directory to
swigsdk-versions/5.6/lib/gcc32.mac/
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
It is possible to build the plugin for different Python versions by
running build.py with the corresponding Python binary. The option
--ea64 builds the 64-bit version as well.
running build.py with the corresponding Python binary.
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.

View File

@ -61,6 +61,15 @@ Start IDA with the following command line options:
If you want fully unattended execution mode, make sure your script
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:
@ -71,7 +80,7 @@ ${HOME}/.idapro/
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.

View File

@ -22,7 +22,7 @@ from distutils import sysconfig
# Start of user configurable options
VERBOSE = True
IDA_MAJOR_VERSION = 5
IDA_MINOR_VERSION = 5
IDA_MINOR_VERSION = 6
if 'IDA' in os.environ:
IDA_SDK = os.environ['IDA']
else:
@ -32,8 +32,8 @@ else:
# IDAPython version
VERSION_MAJOR = 1
VERSION_MINOR = 2
VERSION_PATCH = 90
VERSION_MINOR = 3
VERSION_PATCH = 0
# Determine Python version
PYTHON_MAJOR_VERSION = int(platform.python_version()[0])
@ -296,7 +296,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
platform_macros = [ "__LINUX__" ]
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "lib"
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 = ""
extra_link_parameters = ""
# Platform-specific settings for the Windows build
@ -305,7 +305,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
platform_macros = [ "__NT__" ]
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "libs"
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"
SWIG_OPTIONS += " -D__NT__ "
extra_link_parameters = ""
@ -316,7 +316,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
platform_macros = [ "__MAC__" ]
python_libpath = "."
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"
extra_link_parameters = ""
@ -326,7 +326,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
if ea64:
platform_macros.append("__EA64__")
if '--early-load' in sys.argv:
if not '--no-early-load' in sys.argv:
platform_macros.append("PLUGINFIX")
# Build the wrapper from the interface files
@ -394,7 +394,7 @@ def build_binary_package(ea64, nukeold):
binmanifest = []
if nukeold:
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"))
build_distribution(binmanifest, BINDISTDIR, ea64, nukeold)

View File

@ -48,15 +48,20 @@ extern "C"
#define IDAPYTHON_DATA_STATEMENT 0
#ifdef __EA64__
#define PYTHON_DIR_NAME "python64"
#else
#define PYTHON_DIR_NAME "python"
#endif
void init_idaapi(void);
void idaapi run(int arg);
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. */
/* It might evolve into a tracing facility for user scripts. */
@ -141,34 +146,99 @@ void end_execution()
#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 */
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)
{
begin_execution();
res->num = PyRun_SimpleString(argv[0].str);
end_execution();
PyObject *globals = GetMainGlobals();
if (globals == NULL)
{
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;
}
/* QuickFix for the FILE* incompatibility problem */
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;
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);
return 1;
}
else
{
Py_DECREF(PyFileObject);
return 0;
if ( !PyErr_Occurred() )
PyErr_Print();
return 0;
}
return 1;
}
/* 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 */
/* Default hotkey: Alt-9 */
void IDAPython_RunScript(char *script)
void IDAPython_RunScript(const char *script)
{
char statement[MAXSTR+32];
char slashpath[MAXSTR+1];
char *scriptpath;
const char *scriptpath;
int i;
@ -255,15 +325,13 @@ void IDAPython_RunStatement(void)
/* Default hotkey: Alt-7 */
void IDAPython_ScriptBox(void)
{
PyObject *module;
PyObject *dict;
PyObject *scriptbox;
PyObject *pystr;
/* Get globals() */
/* These two should never fail */
module = PyImport_AddModule("__main__");
dict = PyModule_GetDict(module);
/* This should never fail */
dict = GetMainGlobals();
scriptbox = PyDict_GetItemString(dict, "scriptbox");
@ -296,37 +364,52 @@ void IDAPython_ScriptBox(void)
bool idaapi IDAPython_Menu_Callback(void *ud)
{
run((int)ud);
run((size_t)ud);
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;
PyObject *ptype, *pvalue, *ptraceback;
if ( errbufsize > 0 )
errbuf[0] = '\0';
if (PyErr_Occurred())
if (attrname == NULL)
{
// take the filename.ext part
qstrncpy(modname, qbasename(full_name), sz);
// take the filename part only
qsplitfile(modname, NULL, NULL);
return true;
}
else
{
const char *p = strchr(full_name, '.');
if (p == NULL)
{
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();
qstrncpy(modname, "idaapi", sz);
qstrncpy(attrname, full_name, sz);
}
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,
PyObject *result,
char *errbuf,
@ -340,48 +423,24 @@ static bool return_python_result(idc_value_t *rv,
handle_python_error(errbuf, errbufsize);
return false;
}
if (PyInt_Check(result))
bool ok = true;
if (pyvar_to_idcvar(result, rv) <= 0)
{
rv->num = PyInt_AsLong(result);
rv->vtype = VT_LONG;
Py_XDECREF(result);
return true;
qsnprintf(errbuf, errbufsize, "ERROR: bad return value");
ok = false;
}
if (PyString_Check(result))
{
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;
Py_XDECREF(result);
return ok;
}
/* Compile callback for Python external language evaluator */
bool idaapi IDAPython_extlang_compile(const char *name,
ea_t /*current_ea*/,
const char *expr,
char *errbuf,
size_t errbufsize)
ea_t /*current_ea*/,
const char *expr,
char *errbuf,
size_t errbufsize)
{
PyObject *main = PyImport_AddModule("__main__"); QASSERT(main != NULL);
PyObject *globals = PyModule_GetDict(main); QASSERT(globals != NULL);
PyObject *globals = GetMainGlobals(); QASSERT(globals != NULL);
PyCodeObject *code = (PyCodeObject *)Py_CompileString(expr, "<string>", Py_eval_input);
if (code == NULL)
@ -413,77 +472,211 @@ bool idaapi IDAPython_extlang_compile(const char *name,
/* Run callback for Python external language evaluator */
bool idaapi IDAPython_extlang_run(const char *name,
int nargs,
const idc_value_t args[],
idc_value_t *result,
char *errbuf,
size_t errbufsize)
int nargs,
const idc_value_t args[],
idc_value_t *result,
char *errbuf,
size_t errbufsize)
{
// convert arguments to python
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;
PyObject *pa;
switch (args[i].vtype)
for (int i=0; i<nargs; i++)
{
case VT_LONG:
pa = PyInt_FromLong(args[i].num);
break;
case VT_STR:
pa = PyString_FromString(args[i].str);
break;
case VT_FLOAT:
ieee_realcvt(&dresult, (ushort *)args[i].e, 013);
pa = PyFloat_FromDouble(dresult);
break;
default:
qsnprintf(errbuf, errbufsize, "arg#%d has wrong type %d", i, args[i].vtype);
return false;
PyObject *py_obj(NULL);
int cvt = idcvar_to_pyvar(args[i], &py_obj);
if (cvt <= 0)
{
qsnprintf(errbuf, errbufsize, "arg#%d has wrong type %d", i, args[i].vtype);
ok = false;
break;
}
pargs.push_back(py_obj);
// do not decrement reference of opaque objects
do_decref.push_back(cvt == 1);
}
pargs.push_back(pa);
}
if (!ok)
break;
PyObject *main = PyImport_AddModule("__main__"); QASSERT(main != NULL);
PyObject *globals = PyModule_GetDict(main); QASSERT(globals != NULL);
PyObject *func = PyDict_GetItemString(globals, name);
if (imported_module)
{
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)
{
qsnprintf(errbuf, errbufsize, "undefined function %s", name);
return false;
}
if (func == NULL)
{
qsnprintf(errbuf, errbufsize, "undefined function %s", name);
ok = false;
break;
}
PyCodeObject *code = (PyCodeObject *)PyFunction_GetCode(func);
PyObject *pres = PyEval_EvalCodeEx(code, globals, NULL, &pargs[0], nargs,
NULL, 0, NULL, 0, NULL);
PyCodeObject *code = (PyCodeObject *)PyFunction_GetCode(func);
PyObject *pres = PyEval_EvalCodeEx(code, globals, NULL, &pargs[0], nargs,
NULL, 0, NULL, 0, NULL);
ok = return_python_result(result, pres, errbuf, errbufsize);
} while (false);
// free argument objects
for (int i=0; i<nargs; i++)
Py_XDECREF(pargs[i]);
for (int i=0; i<nargs; 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 */
bool idaapi IDAPython_extlang_compile_file(const char *name,
char *errbuf,
size_t errbufsize)
bool idaapi IDAPython_extlang_compile_file(const char *script_path,
char *errbuf,
size_t errbufsize)
{
PyObject *main = PyImport_AddModule("__main__"); QASSERT(main != NULL);
PyObject *globals = PyModule_GetDict(main); QASSERT(globals != NULL);
PyObject *globals = GetMainGlobals(); QASSERT(globals != NULL);
if (!ExecFile(name))
if (!ExecFile(script_path))
{
handle_python_error(errbuf, errbufsize);
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;
}
/* 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 */
bool idaapi IDAPython_extlang_calcexpr(ea_t /*current_ea*/,
const char *expr,
@ -492,18 +685,16 @@ bool idaapi IDAPython_extlang_calcexpr(ea_t /*current_ea*/,
size_t errbufsize)
{
PyObject *result;
PyObject *module = PyImport_AddModule("__main__");
if (module == NULL)
PyObject *globals = GetMainGlobals();
if (globals == NULL)
return false;
PyObject *globals = PyModule_GetDict(module);
begin_execution();
begin_execution();
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);
}
@ -517,25 +708,52 @@ extlang_t extlang_python =
IDAPython_extlang_run,
IDAPython_extlang_calcexpr,
IDAPython_extlang_compile_file,
"py"
"py",
IDAPython_extlang_create_object
};
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)
register_extlang(&extlang_python);
SELECT_EXTLANG(&extlang_python);
else
register_extlang(NULL);
SELECT_EXTLANG(NULL);
#undef SELECT_EXTLANG
}
#if IDA_SDK_VERSION >= 540
/* Execute a line in the Python CLI */
bool idaapi IDAPython_cli_execute_line(const char *line)
{
begin_execution();
PyRun_SimpleString(line);
end_execution();
return true;
const char *first_line = strrchr(line, '\n');
if (first_line == NULL)
first_line = line;
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 =
@ -560,6 +778,12 @@ void enable_python_cli(bool enable)
}
#endif
/* Prints the IDAPython copyright banner */
void print_banner()
{
PyRun_SimpleString("print_banner()");
}
/* Install python menu items */
static void install_python_menus()
{
@ -593,22 +817,65 @@ static void install_python_menus()
(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
add_menu_item is called too early */
static int idaapi menu_installer_cb(void *, int code, va_list)
{
if ( code != ui_ready_to_run )
return 0;
const char *script;
int when;
install_python_menus();
unhook_from_notification_point(HT_UI, menu_installer_cb, NULL);
switch ( code )
{
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;
}
/* Initialize the Python environment */
bool IDAPython_Init(void)
{
char *options;
char tmp[MAXSTR+64];
bool result = true;
@ -631,9 +898,9 @@ bool IDAPython_Init(void)
qsnprintf(tmp, sizeof(tmp), "libpython%d.%d.so",
PY_MAJOR_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;
}
#endif
@ -648,7 +915,6 @@ bool IDAPython_Init(void)
/* Init the SWIG wrapper */
init_idaapi();
/* Set IDAPYTHON_VERSION in Python */
qsnprintf(tmp, sizeof(tmp), "IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)", \
VER_MAJOR,
@ -656,32 +922,41 @@ bool IDAPython_Init(void)
VER_PATCH,
VER_STATUS,
VER_SERIAL);
begin_execution();
begin_execution();
PyRun_SimpleString(tmp);
end_execution();
end_execution();
/* Pull in the Python side of init */
qmakepath(tmp, MAXSTR, idadir(PYTHON_DIR_NAME), "init.py", NULL);
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;
}
/* Init pywraps (hand made/custom wrapper) */
if (!init_pywraps())
{
warning("IDAPython: init_pywraps() failed!");
return false;
}
#ifdef ENABLE_PYTHON_PROFILING
PyEval_SetTrace(tracefunc, NULL);
#endif
/* Batch-mode operation: */
/* A script specified on the command line is run */
options = (char *)get_plugin_options("IDAPython");
if (options)
IDAPython_RunScript(options);
parse_options();
if ( g_run_when == run_on_init )
IDAPython_RunScript(g_run_script);
#ifdef PLUGINFIX
hook_to_notification_point(HT_UI, menu_installer_cb, NULL);
#else
install_python_menus();
print_banner();
#endif
/* Register a RunPythonStatement() function for IDC */
set_idc_func("RunPythonStatement", idc_runpythonstatement, idc_runpythonstatement_args);
@ -691,6 +966,10 @@ bool IDAPython_Init(void)
enable_python_cli(true);
#endif
#if IDA_SDK_VERSION >= 560
install_extlang(&extlang_python);
#endif
initialized = 1;
return true;
@ -714,8 +993,14 @@ void IDAPython_Term(void)
#endif
/* Remove the extlang */
#if IDA_SDK_VERSION >= 560
remove_extlang(&extlang_python);
#else
register_extlang(NULL);
#endif
/* De-init pywraps */
deinit_pywraps();
/* Shut the interpreter down */
Py_Finalize();

View File

@ -438,10 +438,12 @@ def Eval(expr):
if err:
return "IDC_FAILURE: "+err
else:
if rv.vtype == '\x01': # string
if rv.vtype == '\x01': # VT_STR
return rv.str
elif rv.vtype == '\x02': # long
return rv.num
elif rv.vtype == '\x07': # VT_STR2
return rv.c_str()
else:
raise NotImplementedError, "Eval() supports only expressions returning strings or longs"
@ -6165,6 +6167,13 @@ def GetType(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):
"""
@ -6191,6 +6200,16 @@ def SetType(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):
"""

View File

@ -113,18 +113,12 @@ sys.stdout = sys.stderr = MyStdOut()
sys.argv = [ "" ]
# Have to make sure Python finds our modules
if _idaapi.idainfo_is_64bit(_idaapi.cvar.inf):
pythonDir = "python64"
else:
pythonDir = "python"
sys.path.append(_idaapi.idadir(pythonDir))
print_banner()
sys.path.append(_idaapi.idadir("python"))
#-----------------------------------------------------------
# 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 idautils import *
import idaapi

View File

@ -22,8 +22,8 @@
%ignore clrFlbits;
%ignore get_8bit;
%ignore get_ascii_char;
%ignore del_typeinfo;
%ignore del_operand_typeinfo;
%ignore del_opinfo;
%ignore del_one_opinfo;
%ignore doCode;
%ignore get_repeatable_cmt;
%ignore get_any_indented_cmt;
@ -72,11 +72,11 @@
%clear(const void *buf, size_t size);
%clear(void *buf, ssize_t size);
%clear(typeinfo_t *);
%clear(opinfo_t *);
%rename (nextthat) py_nextthat;
%rename (prevthat) py_prevthat;
%{
//<code(py_bytes)>
//------------------------------------------------------------------------

View File

@ -10,7 +10,7 @@ typedef struct
%rename (get_manual_regions) py_get_manual_regions;
%ignore set_manual_regions;
%include "dbg.hpp"
%ignore DBG_Callback;
%feature("director") DBG_Hooks;
%{
@ -250,7 +250,7 @@ int idaapi DBG_Callback(void *ud, int notification_code, va_list va)
return 0;
}
}
catch (Swig::DirectorException &e)
catch (Swig::DirectorException &)
{
msg("Exception in IDP Hook function:\n");
if (PyErr_Occurred())

View File

@ -27,6 +27,7 @@
%ignore qlfile;
%ignore make_linput;
%ignore unmake_linput;
%ignore create_remote_linput;
// FIXME: These should be wrapped for completeness
%ignore eread;
@ -44,6 +45,7 @@
%{
//<code(py_diskio)>
//--------------------------------------------------------------------------
int idaapi py_enumerate_files_cb(const char *file, void *ud)
{
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
};
//--------------------------------------------------------------------------
void _from_cobject(PyObject *pycobject)
{
this->set_linput((linput_t *)PyCObject_AsVoidPtr(pycobject));
}
//--------------------------------------------------------------------------
void assign(const loader_input_t &rhs)
{
@ -79,19 +87,30 @@ private:
li = rhs.li;
own = OWN_FROM_LI;
}
public:
//--------------------------------------------------------------------------
loader_input_t(const loader_input_t &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;
own = OWN_NONE;
fn.qclear();
__idc_cvt_id__ = 2; // Opaque object
if (pycobject != NULL && PyCObject_Check(pycobject))
{
_from_cobject(pycobject);
}
else
{
li = NULL;
own = OWN_NONE;
fn.qclear();
}
}
//--------------------------------------------------------------------------
@ -152,7 +171,7 @@ public:
if (!PyCObject_Check(pycobject))
return NULL;
loader_input_t *l = new loader_input_t();
l->set_linput((linput_t *)PyCObject_AsVoidPtr(pycobject));
l->_from_cobject(pycobject);
return l;
}
@ -285,6 +304,12 @@ public:
Py_RETURN_NONE;
}
//--------------------------------------------------------------------------
int file2base(int32 pos, ea_t ea1, ea_t ea2, int patchable)
{
return ::file2base(li, pos, ea1, ea2, patchable);
}
//--------------------------------------------------------------------------
int32 size()
{
@ -308,6 +333,7 @@ public:
};
//--------------------------------------------------------------------------
PyObject *py_enumerate_files(PyObject *path, PyObject *fname, PyObject *callback)
{
do

View File

@ -2,6 +2,8 @@
%ignore funcset_t;
%ignore extlang_t;
%ignore extlang;
%ignore extlangs_t;
%ignore extlangs;
%ignore register_extlang;
%ignore IDCFuncs;
%ignore set_idc_func;
@ -28,6 +30,8 @@
%ignore find_builtin_idc_func;
%ignore idc_lx;
%ignore idc_vars;
%ignore idc_resolve_label;
%ignore idc_resolver_ea;
%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);
}
%}
%ignore CompileLine(const char *line, char *errbuf, size_t errbufsize, uval_t (idaapi*_getname)(const char *name)=NULL);
%rename (CompileLine) CompileLine_wrap;

View File

@ -7,13 +7,29 @@ private:
bool own;
qstring fn;
//--------------------------------------------------------------------------
void assign(const qfile_t &rhs)
{
fn = rhs.fn;
fp = rhs.fp;
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:
int __idc_cvt_id__;
//--------------------------------------------------------------------------
qfile_t(const qfile_t &rhs)
{
@ -21,11 +37,14 @@ public:
}
//--------------------------------------------------------------------------
qfile_t()
qfile_t(PyObject *pycobject = NULL)
{
fp = NULL;
own = true;
fn.qclear();
__idc_cvt_id__ = 2; // Opaque object
if (pycobject != NULL && PyCObject_Check(pycobject))
_from_cobject(pycobject);
}
//--------------------------------------------------------------------------

View File

@ -35,6 +35,7 @@
}
%pythoncode %{
#<pycode(py_gdl)>
# -----------------------------------------------------------------------
class BasicBlock:
def __init__(self, id, bb, f):
@ -96,5 +97,5 @@ class FlowChart:
if index >= self.size:
raise StopIteration
return BasicBlock(index, self._q[index], self)
#</pycode(py_gdl)>
%}

View File

@ -481,12 +481,6 @@ private:
//grcode_user_draw, // render node of a user-defined graph
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()
{
@ -494,7 +488,9 @@ private:
return;
// 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);
self = NULL;
}
@ -600,10 +596,15 @@ private:
Py_XDECREF(attr);
}
// Bind py_graph_t to python object
// Keep a reference
this->self = 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
HWND hwnd = NULL;

View File

@ -4,6 +4,9 @@
%ignore idainfo::retrieve;
%ignore idainfo::read;
%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(ushort &where,ushort bit,int value);

View File

@ -45,24 +45,697 @@
#include "typeinf.hpp"
#include "ua.hpp"
#include "xref.hpp"
#include "ieee.h"
#include "err.h"
#include "fpro.h"
#include <map>
#ifdef __NT__
#include "graph.hpp"
#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
%feature("compactdefaultargs");
#ifdef __EA64__
%constant ea_t BADADDR = 0xFFFFFFFFFFFFFFFF;
%constant sel_t BADSEL = 0xFFFFFFFFFFFFFFFF;
%constant nodeidx_t BADNODE = 0xFFFFFFFFFFFFFFFF;
#else
%constant ea_t BADADDR = 0xFFFFFFFF;
%constant sel_t BADSEL = 0xFFFFFFFF;
%constant nodeidx_t BADNODE = 0xFFFFFFFF;
#ifdef __GNUC__
%constant ea_t BADADDR = 0xFFFFFFFFFFFFFFFFll;
%constant sel_t BADSEL = 0xFFFFFFFFFFFFFFFFll;
%constant nodeidx_t BADNODE = 0xFFFFFFFFFFFFFFFFll;
#else // __GNUC__
%constant ea_t BADADDR = 0xFFFFFFFFFFFFFFFFui64;
%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
// 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_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)>
%}

View File

@ -1,7 +1,7 @@
%ignore debugger_t;
%ignore memory_info_t;
%ignore register_info_t;
%ignore appcall;
%apply unsigned char { char dtyp };
%include "idd.hpp"
@ -11,11 +11,7 @@
%{
//<code(py_idd)>
#ifndef PYUL_DEFINED
#define PYUL_DEFINED
typedef unsigned PY_LONG_LONG pyul_t;
#endif
//-------------------------------------------------------------------------
bool dbg_can_query()
{
// 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));
}
//-------------------------------------------------------------------------
PyObject *meminfo_vec_t_to_py(meminfo_vec_t &areas)
{
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;
// startEA endEA name sclass sbase bitness perm
PyList_SetItem(py_list, i,
Py_BuildValue("(KKssKii)",
PyList_SetItem(py_list, i,
Py_BuildValue("(KKssKii)",
pyul_t(mi.startEA),
pyul_t(mi.endEA),
mi.name.c_str(),
mi.sclass.c_str(),
pyul_t(mi.sbase),
(unsigned int)(mi.bitness),
(unsigned int)(mi.bitness),
(unsigned int)mi.perm));
}
return py_list;
}
//-------------------------------------------------------------------------
PyObject *dbg_get_memory_info()
{
if (!dbg_can_query())
@ -59,11 +57,12 @@ PyObject *dbg_get_memory_info()
return meminfo_vec_t_to_py(areas);
}
//-------------------------------------------------------------------------
PyObject *dbg_get_registers()
{
if (dbg == NULL)
Py_RETURN_NONE;
PyObject *py_list = PyList_New(dbg->registers_size);
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
PyList_SetItem(py_list, i,
Py_BuildValue("(sIIINI)",
ri.name,
ri.flags,
(unsigned int)ri.register_class,
PyList_SetItem(py_list, i,
Py_BuildValue("(sIIINI)",
ri.name,
ri.flags,
(unsigned int)ri.register_class,
(unsigned int)ri.dtyp,
py_bits,
(unsigned int)ri.bit_strings_default));
@ -101,6 +100,7 @@ PyObject *dbg_get_registers()
return py_list;
}
//-------------------------------------------------------------------------
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))
@ -113,6 +113,7 @@ PyObject *dbg_get_thread_sreg_base(PyObject *py_tid, PyObject *py_sreg_value)
return Py_BuildValue("K", pyul_t(answer));
}
//-------------------------------------------------------------------------
PyObject *dbg_read_memory(PyObject *py_ea, PyObject *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;
}
//-------------------------------------------------------------------------
PyObject *dbg_write_memory(PyObject *py_ea, PyObject *py_buf)
{
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_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)>
%}
%rename (appcall) py_appcall;
%inline %{
//<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_memory_info();
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)>
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;
}
%}
%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)>
%}

View File

@ -50,7 +50,7 @@
%ignore processor_t::gen_stkvar_def;
%ignore processor_t::u_outspec;
%ignore processor_t::is_align_insn;
%ignore IDB_Callback;
%ignore processor_t::idp_notify;
%ignore processor_t::notify;
%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;
ea_t ea, ea2;
bool repeatable_cmt;
type_t *type;
/*type_t *type;*/
/* p_list *fnames; */
int n;
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);
}
}
catch (Swig::DirectorException &e)
catch (Swig::DirectorException &)
{
msg("Exception in IDP Hook function:\n");
if (PyErr_Occurred())

View File

@ -156,14 +156,6 @@ uint32 choose_choose(PyObject *self,
//<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
#define POPUP_NAMES_COUNT 4

View File

@ -13,6 +13,7 @@
// TODO: These could be wrapped if needed
%ignore load_info_t;
%ignore add_plugin_option;
%ignore build_loaders_list;
%ignore free_loaders_list;
%ignore get_loader_name_from_dll;

View File

@ -10,6 +10,10 @@
%ignore get_de;
%ignore skip_ptr_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 typlen;
%ignore typncpy;
@ -133,22 +137,230 @@
%ignore build_anon_type_name;
%ignore type_names;
%ignore get_compiler_id;
%ignore reloc_info_t;
%ignore relobj_t;
%ignore regobj_t;
%ignore build_func_type;
%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
%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(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)
{
char errbuf[4096];
til_t *res;
res = load_til(tildir, name, errbuf, sizeof(errbuf));
if (!res)
{
PyErr_SetString(PyExc_RuntimeError, errbuf);
@ -165,9 +377,9 @@ til_t * load_til_header_wrap(const char *tildir, const char *name)
{
char errbuf[4096];
til_t *res;
res = load_til_header(tildir, name, errbuf, sizeof(errbuf));;
if (!res)
{
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];
p_list fnames[MAXSTR];
if (get_ti(ea, type, sizeof(type), fnames, sizeof(fnames)))
{
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];
p_list fnames[MAXSTR];
if (guess_type(ea, type, sizeof(type), fnames, sizeof(fnames)))
{
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;
qtype type;
qtype fields;
if (!parse_decl(idati, dcl, &name, &type, &fields, flags))
return 0;