mirror of
https://github.com/idapython/src
synced 2026-06-08 14:47:00 +00:00
Initial SVN commit of version 0.9.54 sources.
This commit is contained in:
+461
@@ -0,0 +1,461 @@
|
||||
//------------------------------------------------------------
|
||||
// IDAPython - Python plugin for Interactive Disassembler Pro
|
||||
//
|
||||
// Copyright (c) 2004-2007 Gergely Erdelyi <dyce@d-dome.net>
|
||||
//
|
||||
// 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>
|
||||
#include <bytes.hpp>
|
||||
#include <diskio.hpp>
|
||||
#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
|
||||
#define VER_STATUS "final"
|
||||
|
||||
#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. */
|
||||
/* Print the filename and line number */
|
||||
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
|
||||
|
||||
/* QuickFix for the FILE* incompatibility problem */
|
||||
int ExecFile(char *FileName)
|
||||
{
|
||||
PyObject* PyFileObject = PyFile_FromString(FileName, "r");
|
||||
|
||||
if (!PyFileObject)
|
||||
{
|
||||
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);
|
||||
#endif
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
slashpath[i] = '\0';
|
||||
|
||||
/* Add the script't path to sys.path */
|
||||
snprintf(statement, sizeof(statement), "runscript(\"%s\")", slashpath);
|
||||
PyRun_SimpleString(statement);
|
||||
|
||||
/* 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"))
|
||||
{
|
||||
PyRun_SimpleString(statement);
|
||||
/* 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);
|
||||
|
||||
scriptbox = PyDict_GetItemString(dict, "ScriptBox_instance");
|
||||
|
||||
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))
|
||||
{
|
||||
ExecFile(PyString_AsString(pystr));
|
||||
}
|
||||
Py_DECREF(pystr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Print the exception info */
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
PyErr_Print();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool idaapi IDAPython_Menu_Callback(void *ud)
|
||||
{
|
||||
run((int)ud);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize the Python environment */
|
||||
bool IDAPython_Init(void)
|
||||
{
|
||||
char *options;
|
||||
char tmp[MAXSTR+64];
|
||||
char *initpath;
|
||||
bool result = 1;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Start the interpreter */
|
||||
Py_Initialize();
|
||||
|
||||
if (!Py_IsInitialized())
|
||||
{
|
||||
warning("IDAPython: Py_Initialize() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Init the SWIG wrapper */
|
||||
init_idaapi();
|
||||
|
||||
sprintf(tmp, "IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)", \
|
||||
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 */
|
||||
result = add_menu_item("File/IDC command...", "P~y~thon command...",
|
||||
"Alt-8", SETMENU_APP,
|
||||
(menu_item_callback_t *)IDAPython_Menu_Callback,
|
||||
(void *)IDAPYTHON_RUNSTATEMENT);
|
||||
|
||||
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);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
add_menu_item("File/IDC command...", "P~y~thon file...",
|
||||
"Alt-9", SETMENU_APP,
|
||||
(menu_item_callback_t *)IDAPython_Menu_Callback,
|
||||
(void *)IDAPYTHON_RUNFILE);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
initialized = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Cleaning up Python */
|
||||
void IDAPython_Term(void)
|
||||
{
|
||||
/* Remove the menu items before termination */
|
||||
#if 0
|
||||
// FIXME: This segfaults the Linux version. The non-existent items might cause this?
|
||||
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");
|
||||
#endif
|
||||
|
||||
/* 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;
|
||||
;;
|
||||
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
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user