diff options
Diffstat (limited to 'plugins/pychrysa/plugin.c')
-rw-r--r-- | plugins/pychrysa/plugin.c | 861 |
1 files changed, 861 insertions, 0 deletions
diff --git a/plugins/pychrysa/plugin.c b/plugins/pychrysa/plugin.c new file mode 100644 index 0000000..b04dd09 --- /dev/null +++ b/plugins/pychrysa/plugin.c @@ -0,0 +1,861 @@ + +/* OpenIDA - Outil d'analyse de fichiers binaires + * plugin.c - interactions avec un greffon Python + * + * Copyright (C) 2010-2012 Cyrille Bagard + * + * This file is part of OpenIDA. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "plugin.h" + + +#include "../../src/analysis/binary.h" +#include "../../src/plugins/plugin-int.h" + + +#include "analysis/binary.h" +#include "debug/debugger.h" + + + + + + +/* --------------------- INTERFACE INTERNE POUR GREFFONS PYTHON --------------------- */ + + +/* Ligne de représentation de code binaire (instance) */ +struct _GPythonPlugin +{ + GPluginModule parent; /* Instance parente */ + + PyObject *module; /* Script Python chargé */ + PyObject *instance; /* Instance Python du greffon */ + +}; + + +/* Ligne de représentation de code binaire (classe) */ +struct _GPythonPluginClass +{ + GPluginModuleClass parent; /* Classe parente */ + +}; + + +/* Initialise la classe des greffons Python. */ +static void g_python_plugin_class_init(GPythonPluginClass *); + +/* Initialise l'instance d'un greffon Python. */ +static void g_python_plugin_init(GPythonPlugin *); + +/* Indique l'utilité pratique du greffon. */ +static PluginAction g_python_plugin_get_action(const GPythonPlugin *); + +/* Indentifie un format à associer à un contenu binaire. */ +static MatchingFormatAction g_python_plugin_is_matching(const GPythonPlugin *, char **, bin_t **, off_t *); + +/* Exécute une action définie sur un binaire chargé. */ +static bool g_python_plugin_execute(GPythonPlugin *, GOpenidaBinary *, PluginAction); + + +/* Exécute une action relative à un débogueur. */ +static bool g_python_plugin_handle_debugger(const GPythonPlugin *, GBinaryDebugger *, PluginAction); + + + +/* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */ + + +/* Classe plugin pour Python */ +typedef struct _pychrysa_plugin +{ + PyObject_HEAD + +} pychrysa_plugin; + + + + + + +/* Crée un nouveau greffon Python abstrait. */ +static PyObject *pychrysa_plugin_new(PyTypeObject *, PyObject *, PyObject *); + +/* Exécute une action valide pour le greffon Python. */ +static PyObject *pychrysa_plugin_run(PyObject *, PyObject *); + + + +/* Définit les constantes pour les greffons en Python. */ +static bool pychrysa_plugin_define_constants(PyObject *); + +/* Définit le comportement par défaut d'un greffon Python. */ +static PyObject *pychrysa_plugin_get_action(PyObject *, PyObject *); + +/* Définit l'issue de la recherche d'un format par défaut. */ +static PyObject *pychrysa_plugin_is_matching(PyObject *, PyObject *); + + +/* Exécute une action relative à un débogueur. */ +static PyObject *pychrysa_plugin_handle_debugger(PyObject *, PyObject *); + + + + + + + + + + + +int +main2(const char *filename, const char *method) +{ + PyObject *pName, *pModule, *pDict, *pFunc; + PyObject *pArgs, *pValue; + int i; + return 0; + pName = PyString_FromString/*PyUnicode_FromString*/(filename); + /* Error checking of pName left out */ + + pModule = PyImport_Import(pName); + Py_DECREF(pName); + + if (pModule != NULL) { + pFunc = PyObject_GetAttrString(pModule, method); + /* pFunc is a new reference */ + + if (pFunc && PyCallable_Check(pFunc)) { + pArgs = PyTuple_New(0/*argc - 3*/); +#if 0 + for (i = 0; i < argc - 3; ++i) { + pValue = PyLong_FromLong(atoi(argv[i + 3])); + if (!pValue) { + Py_DECREF(pArgs); + Py_DECREF(pModule); + fprintf(stderr, "Cannot convert argument\n"); + return 1; + } + /* pValue reference stolen here: */ + PyTuple_SetItem(pArgs, i, pValue); + } +#endif + pValue = PyObject_CallObject(pFunc, pArgs); + Py_DECREF(pArgs); + if (pValue != NULL) { + printf("Result of call: %ld\n", PyLong_AsLong(pValue)); + Py_DECREF(pValue); + } + else { + Py_DECREF(pFunc); + Py_DECREF(pModule); + PyErr_Print(); + fprintf(stderr,"Call failed\n"); + return 1; + } + } + else { + if (PyErr_Occurred()) + PyErr_Print(); + fprintf(stderr, "Cannot find function \"%s\"\n", method); + } + Py_XDECREF(pFunc); + Py_DECREF(pModule); + } + else { + PyErr_Print(); + fprintf(stderr, "Failed to load \"%s\"\n", filename); + return 1; + } + return 0; +} + + + + + + + + + + + + + + + +/* ---------------------------------------------------------------------------------- */ +/* INTERFACE INTERNE POUR GREFFONS PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type définit par la GLib pour le greffon Python. */ +G_DEFINE_TYPE(GPythonPlugin, g_python_plugin, G_TYPE_PLUGIN_MODULE); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des greffons Python. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_python_plugin_class_init(GPythonPluginClass *klass) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = instance à initialiser. * +* * +* Description : Initialise l'instance d'un greffon Python. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_python_plugin_init(GPythonPlugin *plugin) +{ + GPluginModule *plugin_parent; /* Instance parente */ + + plugin_parent = G_PLUGIN_MODULE(plugin); + + plugin_parent->exec_on_bin = (execute_action_on_binary_fc)g_python_plugin_execute; + plugin_parent->handle_debugger = (execute_on_debugger_fc)g_python_plugin_handle_debugger; + +} + + + + +PyObject *run_python_method(PyObject *module, const char *method, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + PyObject *func; /* Fonction visée */ + + result = NULL; + + func = PyObject_GetAttrString(module, method); + if (func == NULL) return NULL; + + if (PyCallable_Check(func)) + { + result = PyObject_CallObject(func, args); + if (result == NULL) PyErr_Print(); + } + else if (PyErr_Occurred()) PyErr_Print(); + + Py_DECREF(func); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modname = nom du module à charger. * +* filename = chemin d'accès au code Python à charger. * +* * +* Description : Crée un greffon à partir de code Python. * +* * +* Retour : Adresse de la structure mise en place ou NULL si erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GPluginModule *g_python_plugin_new(const char *modname, const char *filename) +{ + GPythonPlugin *result; /* Structure à retourner */ + PyObject *name; /* Chemin d'accès pour Python */ + PyObject *module; /* Script Python chargé */ + PyObject *dict; /* Dictionnaire associé */ + PyObject *class; /* Classe à instancier */ + PyObject *instance; /* Instance Python du greffon */ + +#if PY_VERSION_HEX >= 0x03000000 + name = PyUnicode_FromString(filename); +#else + name = PyString_FromString(filename); +#endif + if (name == NULL) goto gppn_bad_exit; + + module = PyImport_Import(name); + Py_DECREF(name); + + if (module == NULL) + { + PyErr_Print(); + goto gppn_bad_exit; + } + + dict = PyModule_GetDict(module); + class = PyDict_GetItemString(dict, modname); + Py_DECREF(dict); + + if (class == NULL) goto gppn_no_class; + if (!PyType_Check(class->ob_type)) goto gppn_no_class; + + instance = PyObject_CallFunction(class, NULL); + if (instance == NULL) goto gppn_no_instance; + + Py_DECREF(class); + + result = g_object_new(G_TYPE_PYTHON_PLUGIN, NULL); + + G_PLUGIN_MODULE(result)->get_action = g_python_plugin_get_action; + + G_PLUGIN_MODULE(result)->is_matching = g_python_plugin_is_matching; + + result->module = module; + result->instance = instance; + + return G_PLUGIN_MODULE(result); + + gppn_no_instance: + + Py_DECREF(class); + + gppn_no_class: + + Py_DECREF(module); + + gppn_bad_exit: + + return NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon de prise en charge à utiliser. * +* * +* Description : Indique l'utilité pratique du greffon. * +* * +* Retour : Action(s) codifiée(s), PGA_NONE par défaut. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PluginAction g_python_plugin_get_action(const GPythonPlugin *plugin) +{ + PluginAction result; /* Valeur à retourner */ + PyObject *value; /* Valeur obtenue */ + + value = run_python_method(plugin->instance, "get_action", NULL); + + result = PyLong_AsLong(value); + Py_DECREF(value); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon de prise en charge à utiliser. * +* filename = éventuel nom de fichier associé ou NULL. [OUT] * +* data = données chargées. [OUT] * +* length = quantité de ces données. [OUT] * +* * +* Description : Indentifie un format à associer à un contenu binaire. * +* * +* Retour : Bilan de la recherche de correspondances. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static MatchingFormatAction g_python_plugin_is_matching(const GPythonPlugin *plugin, char **filename, bin_t **data, off_t *length) +{ + MatchingFormatAction result; /* Valeur à retourner */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *value; /* Valeurs obtenues */ + PyObject *action; /* Action à faire suivre */ + PyObject *new_filename; /* Nouveau fichier */ + PyObject *new_data; /* Nouvelles données */ + char *tmp; /* Stockage avant recopie */ + + if (*filename == NULL) + return MFA_NONE; + + args = PyTuple_New(2); + + PyTuple_SetItem(args, 0, PyString_FromString(*filename)); + PyTuple_SetItem(args, 1, PyByteArray_FromStringAndSize(*data, *length)); + + value = run_python_method(plugin->instance, "is_matching", args); + + if (value != NULL && PyTuple_Check(value) && PyTuple_Size(value) == 3) + { + action = PyTuple_GetItem(value, 0); + new_filename = PyTuple_GetItem(value, 1); + new_data = PyTuple_GetItem(value, 2); + + if (action == NULL || new_filename == NULL || new_data == NULL) + goto is_matching_bad; + + if (!PyInt_Check(action) + || (new_filename != Py_None && !PyString_Check(new_filename)) + || (new_data != Py_None && !PyByteArray_Check(new_data))) + goto is_matching_bad; + + result = PyInt_AsLong(action); + if (result >= MFA_COUNT) goto is_matching_bad; + + if (result != MFA_NONE && new_data == Py_None) goto is_matching_bad; + + if (new_filename != Py_None) + *filename = strdup(PyString_AsString(new_filename)); + /** + * La suppression de la part du greffon n'est permise que + * si une prise en charge est assurée. + */ + else if (result != MFA_NONE) + *filename = NULL; + + /** + * Pareil que précédemment. + */ + if (new_data != Py_None) + { + tmp = PyByteArray_AsString(new_data); + *length = PyByteArray_Size(new_data); + + *data = (bin_t *)calloc(*length, sizeof(bin_t)); + memcpy(*data, tmp, *length * sizeof(bin_t)); + + } + + goto is_matching_ok; + + } + + is_matching_bad: + + printf("<LOG>Bad result from is_matching() plugin function.\n"); + + result = MFA_NONE; + + is_matching_ok: + + Py_XDECREF(value); + Py_DECREF(args); + + return result; + +} + + + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon de prise en charge à utiliser. * +* binary = représentation binaire à traiter. * +* action = action attendue. * +* * +* Description : Exécute une action définie sur un binaire chargé. * +* * +* Retour : true si une action a été menée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_python_plugin_execute(GPythonPlugin *plugin, GOpenidaBinary *binary, PluginAction action) +{ + PyObject *args; /* Arguments pour l'appel */ + PyObject *arg; /* Un des arguments de l'appel */ + PyObject *value; /* Valeur obtenue */ + + + + printf("I am running !!"); + + args = PyTuple_New(1); + + + arg = Py_BuildValue("O&", py_binary_new_from_existing, binary); + PyTuple_SetItem(args, 0, arg); + + + value = run_python_method(plugin->module, "get_instance", args); + + if (value != NULL) + { + printf("Result of call: %ld\n", PyLong_AsLong(value)); + Py_DECREF(value); + } + + + Py_DECREF(args); + + + + + + +} + + + + + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à consulter. * +* debugger = débogueur à l'origine de l'opération. * +* action = action attendue. * +* * +* Description : Exécute une action relative à un débogueur. * +* * +* Retour : true si une action a été menée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_python_plugin_handle_debugger(const GPythonPlugin *plugin, GBinaryDebugger *debugger, PluginAction action) +{ + bool result; /* Bilan à remonter */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *value; /* Valeurs obtenues */ + + args = PyTuple_New(2); + + PyTuple_SetItem(args, 0, py_binary_debugger_from_c(debugger)); + PyTuple_SetItem(args, 1, PyInt_FromLong(action)); + + value = run_python_method(plugin->instance, "handle_debugger", args); + + result = (value == Py_True); + + Py_XDECREF(value); + Py_DECREF(args); + + return result; + +} + + + + + + + +/* ---------------------------------------------------------------------------------- */ +/* MODULE PYTHON POUR LES SCRIPTS */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : type = type de l'objet à instancier. * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Crée un nouveau greffon Python abstrait. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *pychrysa_plugin_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + pychrysa_plugin *result; /* Instance à retourner */ + + result = (pychrysa_plugin *)type->tp_alloc(type, 0); + + return (PyObject *)result; + +} + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : dict = dictionnaire à compléter. * +* * +* Description : Définit les constantes pour les greffons en Python. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool pychrysa_plugin_define_constants(PyObject *dict) +{ + int ret; /* Bilan d'un ajout */ + + ret = PyDict_SetItemString(dict, "PGA_NONE", PyInt_FromLong(PGA_NONE)); + if (ret == -1) return false; + + ret = PyDict_SetItemString(dict, "PGA_FORMAT_MATCHER", PyInt_FromLong(PGA_FORMAT_MATCHER)); + if (ret == -1) return false; + + ret = PyDict_SetItemString(dict, "PGA_DISASSEMBLE", PyInt_FromLong(PGA_DISASSEMBLE)); + if (ret == -1) return false; + + ret = PyDict_SetItemString(dict, "PGA_CODE_PROCESS", PyInt_FromLong(PGA_CODE_PROCESS)); + if (ret == -1) return false; + + ret = PyDict_SetItemString(dict, "PGA_DEBUGGER_ATTACH", PyInt_FromLong(PGA_DEBUGGER_ATTACH)); + if (ret == -1) return false; + + ret = PyDict_SetItemString(dict, "PGA_DEBUGGER_DETACH", PyInt_FromLong(PGA_DEBUGGER_DETACH)); + if (ret == -1) return false; + + /* PGA_FORMAT_MATCHER */ + + ret = PyDict_SetItemString(dict, "MFA_NONE", PyInt_FromLong(MFA_NONE)); + if (ret == -1) return false; + + ret = PyDict_SetItemString(dict, "MFA_MATCHED", PyInt_FromLong(MFA_MATCHED)); + if (ret == -1) return false; + + ret = PyDict_SetItemString(dict, "MFA_RELOAD", PyInt_FromLong(MFA_RELOAD)); + if (ret == -1) return false; + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe assurant le lien avec l'éditeur de messages. * +* args = arguments fournis à l'appel. * +* * +* Description : Définit le comportement par défaut d'un greffon Python. * +* * +* Retour : Rien en équivalent Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *pychrysa_plugin_get_action(PyObject *self, PyObject *args) +{ + return PyInt_FromLong(PGA_NONE); + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe assurant le lien avec l'éditeur de messages. * +* args = arguments fournis à l'appel. * +* * +* Description : Définit l'issue de la recherche d'un format par défaut. * +* * +* Retour : Rien en équivalent Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *pychrysa_plugin_is_matching(PyObject *self, PyObject *args) +{ + PyObject *result; /* Liste à retourner */ + + result = PyTuple_New(3); + + PyTuple_SetItem(result, 0, PyInt_FromLong(MFA_NONE)); + PyTuple_SetItem(result, 1, Py_None); + PyTuple_SetItem(result, 2, Py_None); + + return result; + +} + + + + +/****************************************************************************** +* * +* Paramètres : self = classe assurant le lien avec l'éditeur de messages. * +* args = arguments fournis à l'appel. * +* * +* Description : Exécute une action relative à un débogueur. * +* * +* Retour : True en équivalent Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *pychrysa_plugin_handle_debugger(PyObject *self, PyObject *args) +{ + Py_RETURN_TRUE; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe assurant le lien avec l'éditeur de messages. * +* args = arguments fournis à l'appel. * +* * +* Description : Exécute une action valide pour le greffon Python. * +* * +* Retour : Rien en équivalent Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *pychrysa_plugin_run(PyObject *self, PyObject *args) +{ + return Py_None; + +} + + + + + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Ajoute l'objet 'plugin' au module Python. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_plugin_to_python_module(PyObject *module) +{ + int ret; /* Bilan d'un appel */ + + +static PyMethodDef pychrysa_plugin_methods[] = { + { "get_action", (PyCFunction)pychrysa_plugin_get_action, METH_NOARGS, + "Register the plugin for given actions." + }, + { "is_matching", (PyCFunction)pychrysa_plugin_is_matching, METH_VARARGS, + "Define if the given file can be handled." + }, + { "handle_debugger", (PyCFunction)pychrysa_plugin_handle_debugger, METH_VARARGS, + "Be notify about debugger attaching or detaching." + }, + { "run", (PyCFunction)pychrysa_plugin_run, METH_VARARGS, + "Run the plugin for a specific action." + }, + NULL +}; + + +static PyTypeObject pychrysa_plugin_type = { + + PyObject_HEAD_INIT(NULL) + +#if PY_VERSION_HEX < 0x03000000 + 0, /*ob_size*/ +#endif + + "plugin.Plugin", /* tp_name */ + sizeof(pychrysa_plugin), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved / tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "PyCHRYSA Plugin objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + pychrysa_plugin_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + (newfunc)pychrysa_plugin_new, /* tp_new */ +}; + + + + + if (PyType_Ready(&pychrysa_plugin_type) < 0) + return false; + + + if (!pychrysa_plugin_define_constants(pychrysa_plugin_type.tp_dict)) + return false; + + + + + Py_INCREF(&pychrysa_plugin_type); + PyModule_AddObject(module, "Plugin", (PyObject *)&pychrysa_plugin_type); + + + return true; /* FIXME */ + + +} |