/* Chrysalide - Outil d'analyse de fichiers binaires * plugin.c - interactions avec un greffon Python * * Copyright (C) 2018-2019 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide 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. * * Chrysalide 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 #include #include #include #include #include #include #include "access.h" #include "helpers.h" #include "pychrysa.h" /* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ /* Accompagne la création d'une instance dérivée en Python. */ static PyObject *py_plugin_module_new(PyTypeObject *, PyObject *, PyObject *); /* Initialise la classe des greffons d'extension. */ static void py_plugin_module_init_gclass(GPluginModuleClass *, gpointer); /* Initialise une instance sur la base du dérivé de GObject. */ static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds); /* Valide les fonctionnalités déclarées en actions. */ static bool py_plugin_module_check_interface(PyObject *); /* Accompagne la fin du chargement des modules natifs. */ static void py_plugin_module_notify_native_loaded_wrapper(GPluginModule *, PluginAction); /* Complète une liste de resources pour thème. */ static void py_plugin_module_include_theme_wrapper(const GPluginModule *, PluginAction, gboolean, char ***, size_t *); /* Procède à une opération liée à un contenu binaire. */ static void py_plugin_module_handle_binary_content_wrapper(const GPluginModule *, PluginAction, GBinContent *, wgroup_id_t, GtkStatusStack *); /* Procède à une opération liée à un contenu chargé. */ static void py_plugin_module_handle_loaded_content_wrapper(const GPluginModule *, PluginAction, GLoadedContent *, wgroup_id_t, GtkStatusStack *); /* Procède à une opération liée à l'analyse d'un format. */ static bool py_plugin_module_handle_binary_format_analysis_wrapper(const GPluginModule *, PluginAction, GBinFormat *, wgroup_id_t, GtkStatusStack *); /* Procède à un préchargement de format de fichier. */ static bool py_plugin_module_preload_binary_format_wrapper(const GPluginModule *, PluginAction, GBinFormat *, GPreloadInfo *, GtkStatusStack *); /* Procède au rattachement d'éventuelles infos de débogage. */ static void py_plugin_module_attach_debug_format_wrapper(const GPluginModule *, PluginAction, GExeFormat *); /* Exécute une action pendant un désassemblage de binaire. */ static void py_plugin_module_process_disassembly_event_wrapper(const GPluginModule *, PluginAction, GLoadedBinary *, GtkStatusStack *, GProcContext *); /* Effectue la détection d'effets d'outils externes. */ static void py_plugin_module_detect_external_tools_wrapper(const GPluginModule *, PluginAction, const GLoadedContent *, bool, char ***, size_t *); /* --------------------- INTERFACE INTERNE POUR GREFFONS PYTHON --------------------- */ /* Ligne de représentation de code binaire (instance) */ struct _GPythonPlugin { GPluginModule parent; /* Instance parente */ }; /* 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 *); /* Supprime toutes les références externes. */ static void g_python_plugin_dispose(GPythonPlugin *); /* Description : Procède à la libération totale de la mémoire. */ static void g_python_plugin_finalize(GPythonPlugin *); /* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */ /* Affiche un message dans le journal des messages système. */ static PyObject *py_plugin_module_log_message(PyObject *, PyObject *); /* Définit les constantes pour les greffons en Python. */ static bool py_plugin_module_define_constants(PyTypeObject *); /* ---------------------------------------------------------------------------------- */ /* GLUE POUR CREATION DEPUIS PYTHON */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : type = type du nouvel objet à mettre en place. * * args = éventuelle liste d'arguments. * * kwds = éventuel dictionnaire de valeurs mises à disposition. * * * * Description : Accompagne la création d'une instance dérivée en Python. * * * * Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_plugin_module_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *result; /* Objet à retourner */ PyTypeObject *base; /* Type de base à dériver */ bool first_time; /* Evite les multiples passages*/ GType gtype; /* Nouveau type de processeur */ bool status; /* Bilan d'un enregistrement */ /* Validations diverses */ base = get_python_plugin_module_type(); if (type == base) { result = NULL; PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name); goto exit; } /* Mise en place d'un type dédié */ first_time = (g_type_from_name(type->tp_name) == 0); gtype = build_dynamic_type(G_TYPE_PYTHON_PLUGIN, type->tp_name, (GClassInitFunc)py_plugin_module_init_gclass, NULL, NULL); if (first_time) { status = register_class_for_dynamic_pygobject(gtype, type, base); if (!status) { result = NULL; goto exit; } } /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ result = PyType_GenericNew(type, args, kwds); exit: return result; } /****************************************************************************** * * * Paramètres : class = classe à initialiser. * * unused = données non utilisées ici. * * * * Description : Initialise la classe des greffons d'extension. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void py_plugin_module_init_gclass(GPluginModuleClass *class, gpointer unused) { class->init = NULL; class->exit = NULL; class->native_loaded = py_plugin_module_notify_native_loaded_wrapper; class->include_theme = py_plugin_module_include_theme_wrapper; class->handle_content = py_plugin_module_handle_binary_content_wrapper; class->handle_loaded = py_plugin_module_handle_loaded_content_wrapper; class->handle_fmt_analysis = py_plugin_module_handle_binary_format_analysis_wrapper; class->preload_format = py_plugin_module_preload_binary_format_wrapper; class->attach_debug = py_plugin_module_attach_debug_format_wrapper; class->process_disass = py_plugin_module_process_disassembly_event_wrapper; class->detect = py_plugin_module_detect_external_tools_wrapper; } /****************************************************************************** * * * Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * * Description : Initialise une instance sur la base du dérivé de GObject. * * * * Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds) { const char *name; /* Désignation humaine courte */ const char *desc; /* Description plus loquace */ const char *version; /* Version du greffon */ PyObject *actions_obj; /* Liste des actions offertes */ int ret; /* Bilan de lecture des args. */ PyObject *new_kwds; /* Nouveau dictionnaire épuré */ GPluginModule *plugin; /* Greffon à manipuler */ plugin_interface *iface; /* Interface à constituer */ size_t i; /* Boucle de parcours */ PyObject *action; /* Identifiant d'une action */ static char *kwlist[] = { "name", "desc", "version", "actions", NULL }; /* Récupération des paramètres */ ret = PyArg_ParseTupleAndKeywords(args, kwds, "sssO!", kwlist, &name, &desc, &version, &PyTuple_Type, &actions_obj); if (!ret) return -1; /* Initialisation d'un objet GLib */ new_kwds = PyDict_New(); ret = PyGObject_Type.tp_init(self, args, new_kwds); Py_DECREF(new_kwds); if (ret == -1) return -1; /* Eléments de base */ plugin = G_PLUGIN_MODULE(pygobject_get(self)); iface = malloc(sizeof(plugin_interface)); plugin->interface = iface; iface->name = strdup(name); iface->desc = strdup(desc); iface->version = strdup(version); iface->container = false; iface->required = malloc(sizeof(char *)); iface->required[0] = "PyChrysalide"; iface->required_count = 1; iface->actions_count = PyTuple_Size(actions_obj); iface->actions = malloc(iface->actions_count * sizeof(plugin_action_t)); for (i = 0; i < iface->actions_count; i++) { action = PyTuple_GetItem(actions_obj, i); if (!PyLong_Check(action)) { PyErr_SetString(PyExc_TypeError, _("invalid type for plugin action.")); return -1; } iface->actions[i] = PyLong_AsUnsignedLong(action); } if (!py_plugin_module_check_interface(self)) { PyErr_SetString(PyExc_TypeError, _("missing features for the declared actions.")); return -1; } return 0; } /****************************************************************************** * * * Paramètres : self = greffon Python en cours d'initialisation. * * * * Description : Valide les fonctionnalités déclarées en actions. * * * * Retour : true si le greffon Python est à priori utilisable. * * * * Remarques : - * * * ******************************************************************************/ static bool py_plugin_module_check_interface(PyObject *self) { bool result; /* Bilan à retourner */ GPluginModule *plugin; /* Greffon à manipuler */ size_t i; /* Boucle de parcours */ uint32_t action; /* Identifiant d'une action */ uint32_t category; /* Catégorie principale */ uint32_t sub; /* Sous-catégorie visée */ result = true; plugin = G_PLUGIN_MODULE(pygobject_get(self)); for (i = 0; i < plugin->interface->actions_count && result; i++) { action = plugin->interface->actions[i]; category = MASK_PLUGIN_CATEGORY(action); sub = MASK_PLUGIN_SUB_CATEGORY(action); switch (category) { case DPC_BASIC: switch (sub) { case DPS_NONE: break; case PGA_PLUGIN_INIT: result = has_python_method(self, "init"); break; case PGA_PLUGIN_EXIT: result = has_python_method(self, "exit"); break; default: log_variadic_message(LMT_WARNING, _("Unknown sub-category '0x%02x' in plugin '%s'..."), sub, self->ob_type->tp_name); break; } break; case DPC_BINARY_PROCESSING: switch (sub) { case DPS_CONTENT: switch (action) { case PGA_CONTENT_EXPLORER: result = has_python_method(self, "handle_binary_content"); break; case PGA_CONTENT_RESOLVER: result = has_python_method(self, "handle_loaded_content"); break; default: log_variadic_message(LMT_WARNING, _("Unknown action '0x%02x' in plugin '%s'..."), action, self->ob_type->tp_name); break; } break; case DPS_FORMAT: switch (action) { case PGA_FORMAT_ANALYSIS_STARTED: case PGA_FORMAT_ANALYSIS_ENDED: case PGA_FORMAT_POST_ANALYSIS_STARTED: case PGA_FORMAT_POST_ANALYSIS_ENDED: result = has_python_method(self, "handle_format_analysis"); break; case PGA_FORMAT_PRELOAD: result = has_python_method(self, "preload_format"); break; case PGA_FORMAT_ATTACH_DEBUG: result = has_python_method(self, "attach_debug_format"); break; default: log_variadic_message(LMT_WARNING, _("Unknown action '0x%02x' in plugin '%s'..."), action, self->ob_type->tp_name); break; } break; case DPS_DISASSEMBLY: result = has_python_method(self, "process_disassembly"); break; default: log_variadic_message(LMT_WARNING, _("Unknown sub-category '0x%02x' in plugin '%s'..."), sub, self->ob_type->tp_name); break; } break; default: log_variadic_message(LMT_WARNING, _("Unknown category '0x%02x' in plugin '%s'..."), category, self->ob_type->tp_name); break; } } return result; } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * unused = variable non utilisé pour l'usage de __VA_ARGS__. * * * * Description : Accompagne la fin du chargement des modules natifs. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void py_plugin_module_notify_native_loaded_wrapper(GPluginModule *plugin, PluginAction action) { } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * dark = indique une préférence pour la variante foncée. * * resources = liste de ressources à constituer. [OUT] * * count = taille de cette liste. [OUT] * * * * Description : Complète une liste de resources pour thème. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void py_plugin_module_include_theme_wrapper(const GPluginModule *plugin, PluginAction action, gboolean dark, char ***resources, size_t *count) { } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * content = contenu binaire à traiter. * * wid = identifiant du groupe de traitement. * * status = barre de statut à tenir informée. * * * * Description : Procède à une opération liée à un contenu binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void py_plugin_module_handle_binary_content_wrapper(const GPluginModule *plugin, PluginAction action, GBinContent *content, wgroup_id_t wid, GtkStatusStack *status) { PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *args; /* Arguments pour l'appel */ PyObject *value; /* Valeurs obtenues */ gstate = PyGILState_Ensure(); pyobj = pygobject_new(G_OBJECT(plugin)); assert(has_python_method(pyobj, "handle_binary_content")); args = PyTuple_New(4); PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(content))); PyTuple_SetItem(args, 2, PyLong_FromUnsignedLong(wid)); PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status))); value = run_python_method(pyobj, "handle_binary_content", args); Py_XDECREF(value); Py_DECREF(args); Py_DECREF(pyobj); PyGILState_Release(gstate); } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * content = contenu chargé à traiter. * * wid = identifiant du groupe de traitement. * * status = barre de statut à tenir informée. * * * * Description : Procède à une opération liée à un contenu chargé. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void py_plugin_module_handle_loaded_content_wrapper(const GPluginModule *plugin, PluginAction action, GLoadedContent *content, wgroup_id_t wid, GtkStatusStack *status) { PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *args; /* Arguments pour l'appel */ PyObject *value; /* Valeurs obtenues */ gstate = PyGILState_Ensure(); pyobj = pygobject_new(G_OBJECT(plugin)); assert(has_python_method(pyobj, "handle_loaded_content")); args = PyTuple_New(4); PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(content))); PyTuple_SetItem(args, 2, PyLong_FromUnsignedLong(wid)); PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status))); value = run_python_method(pyobj, "handle_loaded_content", args); Py_XDECREF(value); Py_DECREF(args); Py_DECREF(pyobj); PyGILState_Release(gstate); } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * format = format de binaire à manipuler pendant l'opération. * * gid = groupe de travail dédié. * * status = barre de statut à tenir informée. * * * * Description : Procède à une opération liée à l'analyse d'un format. * * * * Retour : Bilan de l'exécution du traitement. * * * * Remarques : - * * * ******************************************************************************/ static bool py_plugin_module_handle_binary_format_analysis_wrapper(const GPluginModule *plugin, PluginAction action, GBinFormat *format, wgroup_id_t gid, GtkStatusStack *status) { PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *args; /* Arguments pour l'appel */ PyObject *value; /* Valeurs obtenues */ gstate = PyGILState_Ensure(); pyobj = pygobject_new(G_OBJECT(plugin)); assert(has_python_method(pyobj, "handle_format_analysis")); args = PyTuple_New(4); PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(format))); PyTuple_SetItem(args, 2, PyLong_FromUnsignedLong(gid)); PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status))); value = run_python_method(pyobj, "handle_format_analysis", args); Py_XDECREF(value); Py_DECREF(args); Py_DECREF(pyobj); PyGILState_Release(gstate); return true; } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * format = format de binaire à manipuler pendant l'opération. * * info = informations à constituer en avance de phase. * * status = barre de statut à tenir informée. * * * * Description : Procède à un préchargement de format de fichier. * * * * Retour : Bilan de l'exécution du traitement. * * * * Remarques : - * * * ******************************************************************************/ static bool py_plugin_module_preload_binary_format_wrapper(const GPluginModule *plugin, PluginAction action, GBinFormat *format, GPreloadInfo *info, GtkStatusStack *status) { PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *args; /* Arguments pour l'appel */ PyObject *value; /* Valeurs obtenues */ gstate = PyGILState_Ensure(); pyobj = pygobject_new(G_OBJECT(plugin)); assert(has_python_method(pyobj, "preload_format")); args = PyTuple_New(4); PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(format))); PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(info))); PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status))); value = run_python_method(pyobj, "preload_format", args); Py_XDECREF(value); Py_DECREF(args); Py_DECREF(pyobj); PyGILState_Release(gstate); return true; } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * format = format de binaire à manipuler pendant l'opération. * * * * Description : Procède au rattachement d'éventuelles infos de débogage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void py_plugin_module_attach_debug_format_wrapper(const GPluginModule *plugin, PluginAction action, GExeFormat *format) { PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *args; /* Arguments pour l'appel */ PyObject *value; /* Valeurs obtenues */ gstate = PyGILState_Ensure(); pyobj = pygobject_new(G_OBJECT(plugin)); assert(has_python_method(pyobj, "attach_debug_format")); args = PyTuple_New(2); PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(format))); value = run_python_method(pyobj, "attach_debug_format", args); Py_XDECREF(value); Py_DECREF(args); Py_DECREF(pyobj); PyGILState_Release(gstate); } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * binary = binaire dont le contenu est en cours de traitement. * * status = barre de statut à tenir informée. * * context = contexte de désassemblage. * * * * Description : Exécute une action pendant un désassemblage de binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void py_plugin_module_process_disassembly_event_wrapper(const GPluginModule *plugin, PluginAction action, GLoadedBinary *binary, GtkStatusStack *status, GProcContext *context) { PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *args; /* Arguments pour l'appel */ PyObject *value; /* Valeurs obtenues */ gstate = PyGILState_Ensure(); pyobj = pygobject_new(G_OBJECT(plugin)); assert(has_python_method(pyobj, "process_disassembly")); args = PyTuple_New(4); PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(binary))); PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(status))); PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(context))); value = run_python_method(pyobj, "process_disassembly", args); Py_XDECREF(value); Py_DECREF(args); Py_DECREF(pyobj); PyGILState_Release(gstate); } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * content = élément chargé à consulter. * * version = précise si les versions doivent être recherchées. * * names = désignations humaines correspondantes, à libérer. * * count = nombre de types d'obscurcissement trouvés. [OUT] * * * * Description : Effectue la détection d'effets d'outils externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void py_plugin_module_detect_external_tools_wrapper(const GPluginModule *plugin, PluginAction action, const GLoadedContent *content, bool version, char ***names, size_t *count) { } /* ---------------------------------------------------------------------------------- */ /* INTERFACE INTERNE POUR GREFFONS PYTHON */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini 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) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_python_plugin_dispose; object->finalize = (GObjectFinalizeFunc)g_python_plugin_finalize; } /****************************************************************************** * * * Paramètres : plugin = instance à initialiser. * * * * Description : Initialise l'instance d'un greffon Python. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_python_plugin_init(GPythonPlugin *plugin) { } /****************************************************************************** * * * Paramètres : plugin = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_python_plugin_dispose(GPythonPlugin *plugin) { PyThreadState *tstate; /* Contexte d'environnement */ /** * Cf. https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock * * Cependant, comme on se trouve à priori dans le thread principal de l'interpréteur, * PyGILState_Ensure() ne pose aucun verrou. Ce qui aboutit à la situation suivante : * * Fatal Python error: drop_gil: GIL is not locked * * On peut forcer les choses avec PyEval_AcquireLock(), mais cette fonction est marquée * comme dépréciée depuis Python 3.2. * * Donc on choisit les alternatives officielles. * * Cependant, PyThreadState_Get() renvoit l'erreur suivante : * * Fatal Python error: PyThreadState_Get: no current thread * * Donc on se rabat sur une sauvegarde, qui n'est initialisée que lorsque l'interpréteur * est intégré dans l'éditeur. */ tstate = get_pychrysalide_main_tstate(); if (tstate != NULL) PyEval_RestoreThread(tstate); if (tstate != NULL) PyEval_SaveThread(); G_OBJECT_CLASS(g_python_plugin_parent_class)->dispose(G_OBJECT(plugin)); } /****************************************************************************** * * * Paramètres : plugin = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_python_plugin_finalize(GPythonPlugin *plugin) { plugin_interface *final; /* Interface finale conservée */ final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface; if (final != NULL) { free(final->name); free(final->desc); free(final->version); assert(final->required_count == 1); free(final->required); if (final->actions != NULL) free(final->actions); free(final); } G_OBJECT_CLASS(g_python_plugin_parent_class)->finalize(G_OBJECT(plugin)); } /****************************************************************************** * * * 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 */ name = PyUnicode_FromString(modname); if (name == NULL) goto bad_exit; module = PyImport_Import(name); Py_DECREF(name); if (module == NULL) goto no_import; dict = PyModule_GetDict(module); class = PyDict_GetItemString(dict, "AutoLoad"); if (class == NULL) goto no_class; if (!PyType_Check(class->ob_type)) goto no_class; instance = PyObject_CallFunction(class, NULL); if (instance == NULL) goto no_instance; result = G_PYTHON_PLUGIN(pygobject_get(instance)); G_PLUGIN_MODULE(result)->filename = strdup(filename); /** * L'instance Python et l'objet GLib résultante sont un même PyGObject. * * Donc pas besoin de toucher au comptage des références ici, la libération * se réalisera à la fin, quand l'objet GLib sera libéré. */ Py_DECREF(module); return G_PLUGIN_MODULE(result); no_instance: log_pychrysalide_exception(_("An error occured when building the 'AutoLoad' instance")); no_class: if (class == NULL) log_pychrysalide_simple_message(LMT_ERROR, _("An error occured when looking for the 'AutoLoad': item not found!")); no_import: Py_XDECREF(module); log_pychrysalide_exception(_("An error occured when importing '%s'"), modname); bad_exit: return NULL; } /* ---------------------------------------------------------------------------------- */ /* MODULE PYTHON POUR LES SCRIPTS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : self = objet Python concerné par l'appel. * * args = arguments fournis à l'appel. * * * * Description : Affiche un message dans le journal des messages système. * * * * Retour : Rien en équivalent Python. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_plugin_module_log_message(PyObject *self, PyObject *args) { PyObject *result; /* Bilan à retourner */ unsigned long type; /* Espèce du message */ const char *msg; /* Contenu du message */ if (!PyArg_ParseTuple(args, "ks", &type, &msg)) return NULL; switch (type) { case LMT_INFO: case LMT_PROCESS: case LMT_WARNING: case LMT_BAD_BINARY: case LMT_ERROR: case LMT_EXT_ERROR: g_plugin_module_log_simple_message(G_PLUGIN_MODULE(pygobject_get(self)), type, msg); result = Py_None; Py_INCREF(result); break; default: PyErr_SetString(PyExc_ValueError, _("Invalid type of message")); result = NULL; break; } return result; } /****************************************************************************** * * * Paramètres : obj_type = type dont le dictionnaire est à compléter. * * * * Description : Définit les constantes pour les greffons en Python. * * * * Retour : true en cas de succès de l'opération, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool py_plugin_module_define_constants(PyTypeObject *obj_type) { bool result; /* Bilan à retourner */ result = true; result &= PyDict_AddULongMacro(obj_type, PGA_BASIC_NONE); result &= PyDict_AddULongMacro(obj_type, PGA_PLUGIN_INIT); result &= PyDict_AddULongMacro(obj_type, PGA_PLUGIN_EXIT); result &= PyDict_AddULongMacro(obj_type, PGA_NATIVE_LOADED); result &= PyDict_AddULongMacro(obj_type, PGA_CONTENT_EXPLORER); result &= PyDict_AddULongMacro(obj_type, PGA_CONTENT_RESOLVER); result &= PyDict_AddULongMacro(obj_type, PGA_CONTENT_ANALYZED); result &= PyDict_AddULongMacro(obj_type, PGA_FORMAT_ANALYSIS_STARTED); result &= PyDict_AddULongMacro(obj_type, PGA_FORMAT_PRELOAD); result &= PyDict_AddULongMacro(obj_type, PGA_FORMAT_ATTACH_DEBUG); result &= PyDict_AddULongMacro(obj_type, PGA_FORMAT_ANALYSIS_ENDED); result &= PyDict_AddULongMacro(obj_type, PGA_FORMAT_POST_ANALYSIS_STARTED); result &= PyDict_AddULongMacro(obj_type, PGA_FORMAT_POST_ANALYSIS_ENDED); result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_STARTED); result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_RAW); result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_HOOKED_LINK); result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_HOOKED_POST); result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_LIMITED); result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_LOOPS); result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_LINKED); result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_GROUPED); result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_RANKED); result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_ENDED); result &= PyDict_AddULongMacro(obj_type, PGA_DETECTION_OBFUSCATORS); return result; } /****************************************************************************** * * * Paramètres : - * * * * Description : Fournit un accès à une définition de type à diffuser. * * * * Retour : Définition d'objet pour Python. * * * * Remarques : - * * * ******************************************************************************/ PyTypeObject *get_python_plugin_module_type(void) { static PyMethodDef py_plugin_module_methods[] = { { "log_message", py_plugin_module_log_message, METH_VARARGS, "log_message(type, msg, /)\n--\n\nDisplay a message in the log window, if any." }, { NULL } }; static PyGetSetDef py_plugin_module_getseters[] = { { NULL } }; static PyTypeObject py_plugin_module_type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "pychrysalide.PluginModule", .tp_basicsize = sizeof(PyGObject), .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_doc = "Chrysalide plugin for Python.", .tp_methods = py_plugin_module_methods, .tp_getset = py_plugin_module_getseters, .tp_init = py_plugin_module_init, .tp_new = py_plugin_module_new, }; return &py_plugin_module_type; } /****************************************************************************** * * * Paramètres : - * * * * Description : Prend en charge l'objet 'pychrysalide.PluginModule'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool ensure_python_plugin_module_is_registered(void) { PyTypeObject *type; /* Type Python 'PluginModule' */ PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ type = get_python_plugin_module_type(); if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) { module = get_access_to_python_module("pychrysalide"); dict = PyModule_GetDict(module); if (!register_class_for_pygobject(dict, G_TYPE_PYTHON_PLUGIN, type, &PyGObject_Type)) return false; if (!py_plugin_module_define_constants(type)) return false; } return true; }