2007-10-20 09:03:51 +02:00
|
|
|
//------------------------------------------------------------
|
|
|
|
// IDAPython - Python plugin for Interactive Disassembler Pro
|
|
|
|
//
|
2009-04-26 20:28:59 +02:00
|
|
|
// Copyright (c) 2004-2009 Gergely Erdelyi <dyce@d-dome.net>
|
2007-10-20 09:03:51 +02:00
|
|
|
//
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// For detailed copyright information see the file COPYING in
|
|
|
|
// the root of the distribution archive.
|
|
|
|
//------------------------------------------------------------
|
|
|
|
// python.cpp - Main plugin code
|
|
|
|
//------------------------------------------------------------
|
|
|
|
#include <Python.h>
|
|
|
|
|
|
|
|
/* This define fixes the redefinition of ssize_t */
|
|
|
|
#ifdef HAVE_SSIZE_T
|
|
|
|
#define _SSIZE_T_DEFINED 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ida.hpp>
|
|
|
|
#include <idp.hpp>
|
2008-10-11 11:09:46 +02:00
|
|
|
#include <ieee.h>
|
2007-10-20 09:03:51 +02:00
|
|
|
#include <bytes.hpp>
|
|
|
|
#include <diskio.hpp>
|
2008-04-12 09:32:34 +02:00
|
|
|
#include <expr.hpp>
|
2007-10-20 09:03:51 +02:00
|
|
|
#include <loader.hpp>
|
|
|
|
#include <kernwin.hpp>
|
|
|
|
#include <netnode.hpp>
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Python-style version tuple comes from the makefile */
|
|
|
|
/* Only the serial and status is set here */
|
|
|
|
#define VER_SERIAL 0
|
2009-01-25 17:30:05 +01:00
|
|
|
#define VER_STATUS "final"
|
2007-10-20 09:03:51 +02:00
|
|
|
|
|
|
|
#define IDAPYTHON_RUNFILE 0
|
|
|
|
#define IDAPYTHON_RUNSTATEMENT 1
|
|
|
|
#define IDAPYTHON_SCRIPTBOX 2
|
|
|
|
|
|
|
|
#define IDAPYTHON_DATA_STATEMENT 0
|
|
|
|
|
|
|
|
|
|
|
|
void init_idaapi(void);
|
|
|
|
void idaapi run(int arg);
|
|
|
|
|
|
|
|
static int initialized = 0;
|
|
|
|
|
|
|
|
|
|
|
|
/* This is a simple tracing code for debugging purposes. */
|
|
|
|
/* It might evolve into a tracing facility for user scripts. */
|
|
|
|
/* #define ENABLE_PYTHON_PROFILING */
|
|
|
|
|
|
|
|
#ifdef ENABLE_PYTHON_PROFILING
|
|
|
|
#include "compile.h"
|
|
|
|
#include "frameobject.h"
|
|
|
|
|
|
|
|
int tracefunc(PyObject *obj, _frame *frame, int what, PyObject *arg)
|
|
|
|
{
|
|
|
|
PyObject *str;
|
|
|
|
|
|
|
|
/* Catch line change events. */
|
2009-01-25 16:57:53 +01:00
|
|
|
/* Print the filename and line number */
|
2007-10-20 09:03:51 +02:00
|
|
|
if (what == PyTrace_LINE)
|
|
|
|
{
|
|
|
|
str = PyObject_Str(frame->f_code->co_filename);
|
|
|
|
if (str)
|
|
|
|
{
|
|
|
|
msg("PROFILING: %s:%d\n", PyString_AsString(str), frame->f_lineno);
|
|
|
|
Py_DECREF(str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-05-03 22:26:47 +02:00
|
|
|
/* Helper routines to make Python script execution breakable from IDA */
|
|
|
|
static int ninsns = 0; // number of times trace function was called
|
|
|
|
static bool box_displayed; // has the wait box been displayed?
|
|
|
|
static time_t start_time; // the start time of the execution
|
|
|
|
static int script_timeout = 2;
|
|
|
|
|
|
|
|
/* Exported to the Python environment */
|
|
|
|
void set_script_timeout(int timeout)
|
|
|
|
{
|
|
|
|
script_timeout = timeout;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This callback is called on various interpreter events */
|
|
|
|
int break_check(PyObject *obj, _frame *frame, int what, PyObject *arg)
|
|
|
|
{
|
|
|
|
if (wasBreak())
|
|
|
|
/* User pressed Cancel in the waitbox; send KeyboardInterrupt exception */
|
|
|
|
PyErr_SetInterrupt();
|
|
|
|
else if (!box_displayed && ++ninsns > 10)
|
|
|
|
{
|
|
|
|
/* We check the timer once every 10 calls */
|
|
|
|
ninsns = 0;
|
|
|
|
if (time(NULL) - start_time > script_timeout) /* Timeout elapsed? */
|
|
|
|
{
|
|
|
|
show_wait_box("Running Python script");
|
|
|
|
box_displayed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef ENABLE_PYTHON_PROFILING
|
|
|
|
return tracefunc(obj, frame, what, arg);
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Prepare for Python execution */
|
|
|
|
void begin_execution()
|
|
|
|
{
|
|
|
|
ninsns = 0;
|
|
|
|
box_displayed = false;
|
|
|
|
start_time = time(NULL);
|
|
|
|
PyEval_SetTrace(break_check, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called after Python execution finishes */
|
|
|
|
void end_execution()
|
|
|
|
{
|
|
|
|
if (box_displayed)
|
|
|
|
hide_wait_box();
|
|
|
|
#ifdef ENABLE_PYTHON_PROFILING
|
|
|
|
PyEval_SetTrace(tracefunc, NULL);
|
|
|
|
#else
|
|
|
|
PyEval_SetTrace(NULL, NULL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2008-04-12 09:32:34 +02:00
|
|
|
/* Simple Python statement runner function for IDC */
|
|
|
|
static const char idc_runpythonstatement_args[] = { VT_STR, 0 };
|
2009-01-25 17:30:05 +01:00
|
|
|
static error_t idaapi idc_runpythonstatement(idc_value_t *argv, idc_value_t *res)
|
2008-04-12 09:32:34 +02:00
|
|
|
{
|
2009-05-03 22:26:47 +02:00
|
|
|
begin_execution();
|
2008-04-12 09:32:34 +02:00
|
|
|
res->num = PyRun_SimpleString(argv[0].str);
|
2009-05-03 22:26:47 +02:00
|
|
|
end_execution();
|
2008-04-12 09:32:34 +02:00
|
|
|
return eOk;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-20 09:03:51 +02:00
|
|
|
/* QuickFix for the FILE* incompatibility problem */
|
2009-01-25 17:30:05 +01:00
|
|
|
int ExecFile(const char *FileName)
|
2007-10-20 09:03:51 +02:00
|
|
|
{
|
2009-01-25 17:30:05 +01:00
|
|
|
PyObject* PyFileObject = PyFile_FromString((char*)FileName, "r");
|
2007-10-20 09:03:51 +02:00
|
|
|
|
2009-01-25 16:57:53 +01:00
|
|
|
if (!PyFileObject)
|
2007-10-20 09:03:51 +02:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PyRun_SimpleFile(PyFile_AsFile(PyFileObject), FileName) == 0)
|
|
|
|
{
|
|
|
|
Py_DECREF(PyFileObject);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Py_DECREF(PyFileObject);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for the presence of a file in IDADIR/python */
|
|
|
|
bool CheckFile(char *filename)
|
|
|
|
{
|
|
|
|
char filepath[MAXSTR+1];
|
|
|
|
|
|
|
|
#if IDP_INTERFACE_VERSION >= 75
|
|
|
|
qmakepath(filepath, MAXSTR, idadir(NULL), "python", filename, NULL);
|
|
|
|
#elif IDP_INTERFACE_VERSION >= 69
|
|
|
|
qmakepath(filepath, idadir(NULL), "python", filename, NULL);
|
|
|
|
#else
|
|
|
|
qmakepath(filepath, idadir(), "python", filename, NULL);
|
2009-01-25 16:57:53 +01:00
|
|
|
#endif
|
2007-10-20 09:03:51 +02:00
|
|
|
|
|
|
|
if (!qfileexist(filepath))
|
|
|
|
{
|
|
|
|
warning("IDAPython: Missing required file %s", filename);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Execute the Python script from the plugin */
|
|
|
|
/* Default hotkey: Alt-9 */
|
|
|
|
void IDAPython_RunScript(char *script)
|
|
|
|
{
|
|
|
|
char statement[MAXSTR+32];
|
|
|
|
char slashpath[MAXSTR+1];
|
|
|
|
char *scriptpath;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (script)
|
|
|
|
{
|
|
|
|
scriptpath = script;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
scriptpath = askfile_c(0, "*.py", "Python file to run");
|
|
|
|
|
|
|
|
if (!scriptpath)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make a copy of the path with '\\' => '/' */
|
|
|
|
for (i=0; scriptpath[i]; i++)
|
|
|
|
{
|
|
|
|
if (scriptpath[i] == '\\')
|
|
|
|
{
|
|
|
|
slashpath[i] = '/';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
slashpath[i] = scriptpath[i];
|
|
|
|
}
|
|
|
|
}
|
2009-01-25 16:57:53 +01:00
|
|
|
|
2007-10-20 09:03:51 +02:00
|
|
|
slashpath[i] = '\0';
|
|
|
|
|
2009-01-25 16:57:53 +01:00
|
|
|
/* Add the script't path to sys.path */
|
2009-01-25 17:30:05 +01:00
|
|
|
qsnprintf(statement, sizeof(statement), "runscript(\"%s\")", slashpath);
|
2009-05-03 22:26:47 +02:00
|
|
|
begin_execution();
|
2007-10-20 09:03:51 +02:00
|
|
|
PyRun_SimpleString(statement);
|
2009-05-03 22:26:47 +02:00
|
|
|
end_execution();
|
2007-10-20 09:03:51 +02:00
|
|
|
|
|
|
|
/* Error handling */
|
|
|
|
if (PyErr_Occurred())
|
|
|
|
{
|
|
|
|
PyErr_Print();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Execute Python statement(s) from an editor window */
|
|
|
|
/* Default hotkey: Alt-8 */
|
|
|
|
void IDAPython_RunStatement(void)
|
|
|
|
{
|
|
|
|
char statement[4096];
|
|
|
|
netnode history;
|
|
|
|
|
|
|
|
/* Get the existing or create a new netnode in the database */
|
|
|
|
history.create("IDAPython_Data");
|
|
|
|
|
|
|
|
/* Fetch the previous statement */
|
|
|
|
if (history.supval(IDAPYTHON_DATA_STATEMENT, statement, sizeof(statement)) == -1)
|
|
|
|
{
|
|
|
|
statement[0] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (asktext(sizeof(statement), statement, statement, "Enter Python expressions"))
|
|
|
|
{
|
2009-05-03 22:26:47 +02:00
|
|
|
begin_execution();
|
2007-10-20 09:03:51 +02:00
|
|
|
PyRun_SimpleString(statement);
|
2009-05-03 22:26:47 +02:00
|
|
|
end_execution();
|
2007-10-20 09:03:51 +02:00
|
|
|
/* Store the statement to the database */
|
|
|
|
history.supset(IDAPYTHON_DATA_STATEMENT, statement);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* History of previously executed scripts */
|
|
|
|
/* 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);
|
|
|
|
|
2009-01-27 19:08:54 +01:00
|
|
|
scriptbox = PyDict_GetItemString(dict, "scriptbox");
|
2007-10-20 09:03:51 +02:00
|
|
|
|
|
|
|
if (!scriptbox)
|
|
|
|
{
|
|
|
|
warning("INTERNAL ERROR: ScriptBox_instance missing! Broken init.py?");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pystr = PyObject_CallMethod(scriptbox, "run", "");
|
|
|
|
|
|
|
|
if (pystr)
|
|
|
|
{
|
|
|
|
/* If the return value is string use it as path */
|
|
|
|
if (PyObject_TypeCheck(pystr, &PyString_Type))
|
|
|
|
{
|
2009-05-03 22:26:47 +02:00
|
|
|
begin_execution();
|
2007-10-20 09:03:51 +02:00
|
|
|
ExecFile(PyString_AsString(pystr));
|
2009-05-03 22:26:47 +02:00
|
|
|
end_execution();
|
2007-10-20 09:03:51 +02:00
|
|
|
}
|
|
|
|
Py_DECREF(pystr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Print the exception info */
|
|
|
|
if (PyErr_Occurred())
|
|
|
|
{
|
|
|
|
PyErr_Print();
|
|
|
|
}
|
|
|
|
}
|
2009-01-25 16:57:53 +01:00
|
|
|
}
|
2007-10-20 09:03:51 +02:00
|
|
|
|
|
|
|
bool idaapi IDAPython_Menu_Callback(void *ud)
|
|
|
|
{
|
|
|
|
run((int)ud);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-01-25 17:30:05 +01:00
|
|
|
/* Return a formatted error or just print it to the console */
|
|
|
|
static void handle_python_error(char *errbuf, size_t errbufsize)
|
2008-10-07 19:21:01 +02:00
|
|
|
{
|
|
|
|
PyObject *result;
|
|
|
|
PyObject *ptype, *pvalue, *ptraceback;
|
|
|
|
|
2009-01-25 17:30:05 +01:00
|
|
|
if ( errbufsize > 0 )
|
|
|
|
errbuf[0] = '\0';
|
2008-10-07 19:21:01 +02:00
|
|
|
|
2009-01-25 17:30:05 +01:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-10-07 19:21:01 +02:00
|
|
|
|
2009-01-25 17:30:05 +01:00
|
|
|
/* Convert return value from Python to IDC or report about an error */
|
|
|
|
static bool return_python_result(idc_value_t *rv,
|
|
|
|
PyObject *result,
|
|
|
|
char *errbuf,
|
|
|
|
size_t errbufsize)
|
|
|
|
{
|
2009-01-27 18:52:36 +01:00
|
|
|
if (errbufsize > 0)
|
|
|
|
errbuf[0] = '\0';
|
|
|
|
|
2008-10-07 19:21:01 +02:00
|
|
|
if (result == NULL)
|
|
|
|
{
|
2009-01-25 17:30:05 +01:00
|
|
|
handle_python_error(errbuf, errbufsize);
|
2008-10-07 19:21:01 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PyInt_Check(result))
|
|
|
|
{
|
|
|
|
rv->num = PyInt_AsLong(result);
|
|
|
|
rv->vtype = VT_LONG;
|
|
|
|
Py_XDECREF(result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PyString_Check(result))
|
|
|
|
{
|
|
|
|
rv->str = (char *)qalloc(PyString_Size(result)+1);
|
|
|
|
if (!rv->str)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2009-01-25 17:30:05 +01:00
|
|
|
qstrncpy(rv->str, PyString_AsString(result), MAXSTR);
|
2008-10-07 19:21:01 +02:00
|
|
|
rv->vtype = VT_STR;
|
|
|
|
Py_XDECREF(result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PyFloat_Check(result))
|
|
|
|
{
|
2009-01-25 17:30:05 +01:00
|
|
|
double dresult = PyFloat_AsDouble(result);
|
2008-10-11 11:09:46 +02:00
|
|
|
ieee_realcvt((void *)&dresult, rv->e, 3);
|
|
|
|
rv->vtype = VT_FLOAT;
|
2008-10-07 19:21:01 +02:00
|
|
|
Py_XDECREF(result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-01-27 18:52:36 +01:00
|
|
|
qsnprintf(errbuf, errbufsize, "ERROR: bad return value");
|
2008-10-07 19:21:01 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-01-25 17:30:05 +01:00
|
|
|
/* 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)
|
|
|
|
{
|
|
|
|
PyObject *main = PyImport_AddModule("__main__"); QASSERT(main != NULL);
|
|
|
|
PyObject *globals = PyModule_GetDict(main); QASSERT(globals != NULL);
|
|
|
|
|
|
|
|
PyCodeObject *code = (PyCodeObject *)Py_CompileString(expr, "<string>", Py_eval_input);
|
|
|
|
if (code == NULL)
|
|
|
|
{
|
|
|
|
handle_python_error(errbuf, errbufsize);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set the desired function name
|
|
|
|
Py_XDECREF(code->co_name);
|
|
|
|
code->co_name = PyString_FromString(name);
|
|
|
|
|
|
|
|
// create a function out of code
|
|
|
|
PyObject *func = PyFunction_New((PyObject *)code, globals);
|
|
|
|
if (func == NULL)
|
|
|
|
{
|
|
|
|
ERR:
|
|
|
|
handle_python_error(errbuf, errbufsize);
|
|
|
|
Py_XDECREF(code);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int err = PyDict_SetItemString(globals, name, func);
|
|
|
|
if (err)
|
|
|
|
goto ERR;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
{
|
|
|
|
// convert arguments to python
|
|
|
|
qvector<PyObject *> pargs;
|
|
|
|
|
|
|
|
for (int i=0; i<nargs; i++)
|
|
|
|
{
|
|
|
|
double dresult;
|
|
|
|
PyObject *pa;
|
|
|
|
switch (args[i].vtype)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
pargs.push_back(pa);
|
|
|
|
}
|
|
|
|
|
|
|
|
PyObject *main = PyImport_AddModule("__main__"); QASSERT(main != NULL);
|
|
|
|
PyObject *globals = PyModule_GetDict(main); QASSERT(globals != NULL);
|
|
|
|
PyObject *func = PyDict_GetItemString(globals, name);
|
|
|
|
|
|
|
|
if (func == NULL)
|
|
|
|
{
|
|
|
|
qsnprintf(errbuf, errbufsize, "undefined function %s", name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
PyCodeObject *code = (PyCodeObject *)PyFunction_GetCode(func);
|
|
|
|
PyObject *pres = PyEval_EvalCodeEx(code, globals, NULL, &pargs[0], nargs,
|
|
|
|
NULL, 0, NULL, 0, NULL);
|
|
|
|
|
|
|
|
// free argument objects
|
|
|
|
for (int i=0; i<nargs; i++)
|
|
|
|
Py_XDECREF(pargs[i]);
|
|
|
|
|
|
|
|
return return_python_result(result, pres, errbuf, errbufsize);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Compile callback for Python external language evaluator */
|
|
|
|
bool idaapi IDAPython_extlang_compile_file(const char *name,
|
|
|
|
char *errbuf,
|
|
|
|
size_t errbufsize)
|
|
|
|
{
|
|
|
|
PyObject *main = PyImport_AddModule("__main__"); QASSERT(main != NULL);
|
|
|
|
PyObject *globals = PyModule_GetDict(main); QASSERT(globals != NULL);
|
|
|
|
|
|
|
|
if (!ExecFile(name))
|
|
|
|
{
|
|
|
|
handle_python_error(errbuf, errbufsize);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculator callback for Python external language evaluator */
|
|
|
|
bool idaapi IDAPython_extlang_calcexpr(ea_t /*current_ea*/,
|
|
|
|
const char *expr,
|
|
|
|
idc_value_t *rv,
|
|
|
|
char *errbuf,
|
|
|
|
size_t errbufsize)
|
|
|
|
{
|
|
|
|
PyObject *result;
|
|
|
|
PyObject *module = PyImport_AddModule("__main__");
|
|
|
|
|
|
|
|
if (module == NULL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
PyObject *globals = PyModule_GetDict(module);
|
|
|
|
|
|
|
|
result = PyRun_String(expr, Py_eval_input, globals, globals);
|
|
|
|
|
|
|
|
VarFree(rv);
|
|
|
|
|
|
|
|
return return_python_result(rv, result, errbuf, errbufsize);
|
|
|
|
}
|
|
|
|
|
2009-01-25 16:57:53 +01:00
|
|
|
extlang_t extlang_python =
|
2008-10-07 19:21:01 +02:00
|
|
|
{
|
|
|
|
sizeof(extlang_t),
|
|
|
|
0,
|
|
|
|
"Python",
|
|
|
|
IDAPython_extlang_compile,
|
|
|
|
IDAPython_extlang_run,
|
2009-01-25 17:30:05 +01:00
|
|
|
IDAPython_extlang_calcexpr,
|
|
|
|
IDAPython_extlang_compile_file,
|
|
|
|
"py"
|
2008-10-07 19:21:01 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
void enable_extlang_python(bool enable)
|
|
|
|
{
|
|
|
|
if (enable)
|
|
|
|
{
|
|
|
|
register_extlang(&extlang_python);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
register_extlang(NULL);
|
|
|
|
}
|
|
|
|
}
|
2007-10-20 09:03:51 +02:00
|
|
|
|
2009-01-20 23:00:05 +01:00
|
|
|
#if IDA_SDK_VERSION >= 540
|
2009-01-19 21:38:59 +01:00
|
|
|
/* Execute a line in the Python CLI */
|
|
|
|
bool idaapi IDAPython_cli_execute_line(const char *line)
|
|
|
|
{
|
|
|
|
PyRun_SimpleString(line);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
cli_t cli_python =
|
|
|
|
{
|
|
|
|
sizeof(cli_t),
|
|
|
|
0,
|
|
|
|
"Python",
|
|
|
|
"Python - IDAPython plugin",
|
|
|
|
"Enter any Python expression",
|
|
|
|
IDAPython_cli_execute_line,
|
|
|
|
NULL,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Control the Python CLI status */
|
|
|
|
void enable_python_cli(bool enable)
|
|
|
|
{
|
|
|
|
if (enable)
|
|
|
|
{
|
|
|
|
install_command_interpreter(&cli_python);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
remove_command_interpreter(&cli_python);
|
|
|
|
}
|
|
|
|
}
|
2009-01-20 23:00:05 +01:00
|
|
|
#endif
|
2009-01-19 21:38:59 +01:00
|
|
|
|
2007-10-20 09:03:51 +02:00
|
|
|
/* Initialize the Python environment */
|
|
|
|
bool IDAPython_Init(void)
|
|
|
|
{
|
|
|
|
char *options;
|
|
|
|
char tmp[MAXSTR+64];
|
|
|
|
char *initpath;
|
|
|
|
bool result = 1;
|
2009-01-25 16:57:53 +01:00
|
|
|
|
2007-10-20 09:03:51 +02:00
|
|
|
/* Already initialized? */
|
|
|
|
if (initialized == 1)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for the presence of essential files */
|
|
|
|
initialized = 0;
|
|
|
|
|
|
|
|
result &= CheckFile("idc.py");
|
|
|
|
result &= CheckFile("init.py");
|
|
|
|
result &= CheckFile("idaapi.py");
|
|
|
|
result &= CheckFile("idautils.py");
|
|
|
|
|
|
|
|
if (!result)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2009-01-25 16:57:53 +01:00
|
|
|
|
2007-10-20 09:03:51 +02:00
|
|
|
/* Start the interpreter */
|
|
|
|
Py_Initialize();
|
|
|
|
|
|
|
|
if (!Py_IsInitialized())
|
|
|
|
{
|
|
|
|
warning("IDAPython: Py_Initialize() failed");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Init the SWIG wrapper */
|
|
|
|
init_idaapi();
|
|
|
|
|
2009-01-25 17:30:05 +01:00
|
|
|
qsnprintf(tmp, sizeof(tmp), "IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)", \
|
2007-10-20 09:03:51 +02:00
|
|
|
VER_MAJOR,
|
|
|
|
VER_MINOR,
|
|
|
|
VER_PATCH,
|
|
|
|
VER_STATUS,
|
|
|
|
VER_SERIAL);
|
|
|
|
|
|
|
|
PyRun_SimpleString(tmp);
|
|
|
|
|
|
|
|
#if IDP_INTERFACE_VERSION >= 75
|
|
|
|
qmakepath(tmp, MAXSTR, idadir("python"), "init.py", NULL);
|
|
|
|
#elif IDP_INTERFACE_VERSION >= 69
|
|
|
|
qmakepath(tmp, idadir("python"), "init.py", NULL);
|
|
|
|
#else
|
|
|
|
qmakepath(tmp, idadir(), "python", "init.py", NULL);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Pull in the Python side of init */
|
|
|
|
if (!ExecFile(tmp))
|
|
|
|
{
|
|
|
|
warning("IDAPython: error executing init.py");
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add menu items for all the functions */
|
|
|
|
/* Different paths are used for the GUI version */
|
2009-01-25 17:30:05 +01:00
|
|
|
add_menu_item("File/IDC command...", "P~y~thon command...",
|
2009-01-25 16:57:53 +01:00
|
|
|
"Alt-8", SETMENU_APP,
|
|
|
|
(menu_item_callback_t *)IDAPython_Menu_Callback,
|
2007-10-20 09:03:51 +02:00
|
|
|
(void *)IDAPYTHON_RUNSTATEMENT);
|
|
|
|
|
2009-01-25 16:57:53 +01:00
|
|
|
result = add_menu_item("File/Load file/IDC file...", "P~y~thon file...",
|
|
|
|
"Alt-9", SETMENU_APP,
|
|
|
|
(menu_item_callback_t *)IDAPython_Menu_Callback,
|
|
|
|
(void *)IDAPYTHON_RUNFILE);
|
|
|
|
|
2007-10-20 09:03:51 +02:00
|
|
|
if (!result)
|
|
|
|
{
|
2009-01-25 16:57:53 +01:00
|
|
|
add_menu_item("File/IDC command...", "P~y~thon file...",
|
|
|
|
"Alt-9", SETMENU_APP,
|
|
|
|
(menu_item_callback_t *)IDAPython_Menu_Callback,
|
|
|
|
(void *)IDAPYTHON_RUNFILE);
|
2007-10-20 09:03:51 +02:00
|
|
|
}
|
|
|
|
|
2009-01-25 16:57:53 +01:00
|
|
|
result = add_menu_item("View/Open subviews/Show strings", "Python S~c~ripts",
|
|
|
|
"Alt-7", SETMENU_APP,
|
|
|
|
(menu_item_callback_t *)IDAPython_Menu_Callback,
|
|
|
|
(void *)IDAPYTHON_SCRIPTBOX);
|
|
|
|
|
|
|
|
if (!result)
|
2007-10-20 09:03:51 +02:00
|
|
|
{
|
2009-01-25 16:57:53 +01:00
|
|
|
add_menu_item("View/Open subviews/Problems", "Python S~c~ripts",
|
|
|
|
"Alt-7", SETMENU_APP,
|
|
|
|
(menu_item_callback_t *)IDAPython_Menu_Callback,
|
|
|
|
(void *)IDAPYTHON_SCRIPTBOX);
|
2007-10-20 09:03:51 +02:00
|
|
|
}
|
2008-04-12 09:32:34 +02:00
|
|
|
|
|
|
|
/* Register a RunPythonStatement() function for IDC */
|
|
|
|
set_idc_func("RunPythonStatement", idc_runpythonstatement, idc_runpythonstatement_args);
|
2008-10-07 19:21:01 +02:00
|
|
|
|
2009-01-20 23:00:05 +01:00
|
|
|
#if IDA_SDK_VERSION >= 540
|
2009-01-19 21:38:59 +01:00
|
|
|
/* Enable the CLI by default */
|
|
|
|
enable_python_cli(true);
|
2009-01-20 23:00:05 +01:00
|
|
|
#endif
|
2009-01-19 21:38:59 +01:00
|
|
|
|
2007-10-20 09:03:51 +02:00
|
|
|
initialized = 1;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Cleaning up Python */
|
|
|
|
void IDAPython_Term(void)
|
|
|
|
{
|
|
|
|
/* Remove the menu items before termination */
|
|
|
|
del_menu_item("File/Load file/Python file...");
|
|
|
|
del_menu_item("File/Python file...");
|
|
|
|
del_menu_item("File/Python command...");
|
|
|
|
del_menu_item("View/Open subviews/Python Scripts");
|
2008-10-07 19:21:01 +02:00
|
|
|
|
2009-01-20 23:00:05 +01:00
|
|
|
#if IDA_SDK_VERSION >= 540
|
2009-01-19 21:38:59 +01:00
|
|
|
/* Remove the CLI */
|
|
|
|
enable_python_cli(false);
|
2009-01-20 23:00:05 +01:00
|
|
|
#endif
|
2009-01-19 21:38:59 +01:00
|
|
|
|
2008-10-07 19:21:01 +02:00
|
|
|
/* Remove the extlang */
|
|
|
|
register_extlang(NULL);
|
2009-01-25 16:57:53 +01:00
|
|
|
|
2007-10-20 09:03:51 +02:00
|
|
|
/* Shut the interpreter down */
|
|
|
|
Py_Finalize();
|
|
|
|
|
|
|
|
initialized = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Plugin init routine */
|
|
|
|
int idaapi init(void)
|
|
|
|
{
|
|
|
|
if (IDAPython_Init())
|
|
|
|
{
|
|
|
|
return PLUGIN_KEEP;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return PLUGIN_SKIP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Plugin term routine */
|
|
|
|
void idaapi term(void)
|
|
|
|
{
|
|
|
|
IDAPython_Term();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Plugin hotkey entry point */
|
|
|
|
void idaapi run(int arg)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
switch (arg)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
IDAPython_RunScript(NULL);
|
|
|
|
break;
|
|
|
|
;;
|
|
|
|
case 1:
|
|
|
|
IDAPython_RunStatement();
|
|
|
|
break;
|
|
|
|
;;
|
|
|
|
case 2:
|
|
|
|
IDAPython_ScriptBox();
|
|
|
|
break;
|
|
|
|
;;
|
2009-01-27 18:52:36 +01:00
|
|
|
case 3:
|
|
|
|
enable_extlang_python(true);
|
|
|
|
break;
|
|
|
|
;;
|
|
|
|
case 4:
|
|
|
|
enable_extlang_python(false);
|
|
|
|
break;
|
|
|
|
;;
|
2007-10-20 09:03:51 +02:00
|
|
|
default:
|
|
|
|
warning("IDAPython: unknown plugin argument %d", arg);
|
|
|
|
break;
|
|
|
|
;;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(...)
|
|
|
|
{
|
|
|
|
warning("Exception in Python interpreter. Reloading...");
|
|
|
|
IDAPython_Term();
|
|
|
|
IDAPython_Init();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// PLUGIN DESCRIPTION BLOCK
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
char comment[] = "IDAPython";
|
|
|
|
char help[] = "IDA Python Plugin\n";
|
|
|
|
char wanted_name[] = "IDAPython";
|
|
|
|
char wanted_hotkey[] = "Alt-9";
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
{
|
|
|
|
plugin_t PLUGIN = {
|
|
|
|
IDP_INTERFACE_VERSION,
|
|
|
|
0, // plugin flags
|
|
|
|
init, // initialize
|
|
|
|
|
|
|
|
term, // terminate. this pointer may be NULL.
|
|
|
|
|
|
|
|
run, // invoke plugin
|
|
|
|
|
|
|
|
comment, // long comment about the plugin
|
|
|
|
// it could appear in the status line
|
|
|
|
// or as a hint
|
|
|
|
|
|
|
|
help, // multiline help about the plugin
|
|
|
|
|
|
|
|
wanted_name, // the preferred short name of the plugin
|
|
|
|
wanted_hotkey // the preferred hotkey to run the plugin
|
|
|
|
};
|
|
|
|
}
|