diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2021-02-07 20:30:07 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2021-02-07 20:30:07 (GMT) |
commit | 42540e681161aab0a1c27c66541ed5dc833ca411 (patch) | |
tree | a7a1329435252b7b1ac8981b6ab3a3abddcfe457 /plugins/pychrysalide/plugins | |
parent | 7c17177918f1bb94be7c84ca9b839155623ff05f (diff) |
Created the right place for plugins in the Python API.
Diffstat (limited to 'plugins/pychrysalide/plugins')
-rw-r--r-- | plugins/pychrysalide/plugins/Makefile.am | 24 | ||||
-rw-r--r-- | plugins/pychrysalide/plugins/constants.c | 100 | ||||
-rw-r--r-- | plugins/pychrysalide/plugins/constants.h | 38 | ||||
-rw-r--r-- | plugins/pychrysalide/plugins/module.c | 104 | ||||
-rw-r--r-- | plugins/pychrysalide/plugins/module.h | 42 | ||||
-rw-r--r-- | plugins/pychrysalide/plugins/plugin.c | 1884 | ||||
-rw-r--r-- | plugins/pychrysalide/plugins/plugin.h | 75 |
7 files changed, 2267 insertions, 0 deletions
diff --git a/plugins/pychrysalide/plugins/Makefile.am b/plugins/pychrysalide/plugins/Makefile.am new file mode 100644 index 0000000..0ab8c15 --- /dev/null +++ b/plugins/pychrysalide/plugins/Makefile.am @@ -0,0 +1,24 @@ + +noinst_LTLIBRARIES = libpychrysaplugins.la + +libpychrysaplugins_la_SOURCES = \ + constants.h constants.c \ + plugin.h plugin.c \ + module.h module.c + +libpychrysaplugins_la_LIBADD = + +libpychrysaplugins_la_LDFLAGS = + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libpychrysaplugins_la_SOURCES:%c=) + + +AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src + +AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) + +SUBDIRS = diff --git a/plugins/pychrysalide/plugins/constants.c b/plugins/pychrysalide/plugins/constants.c new file mode 100644 index 0000000..9de044a --- /dev/null +++ b/plugins/pychrysalide/plugins/constants.c @@ -0,0 +1,100 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.c - ajout des constantes principales + * + * Copyright (C) 2020 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 "constants.h" + + +#include <plugins/plugin-def.h> + + +#include "../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes relatives aux greffons Python. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool define_plugin_module_constants(PyTypeObject *type) +{ + bool result; /* Bilan à retourner */ + PyObject *values; /* Groupe de valeurs à établir */ + + result = true; + + values = PyDict_New(); + + if (result) result = add_const_to_group(values, "BASIC_NONE", PGA_BASIC_NONE); + if (result) result = add_const_to_group(values, "PLUGIN_INIT", PGA_PLUGIN_INIT); + if (result) result = add_const_to_group(values, "PLUGIN_LOADED", PGA_PLUGIN_LOADED); + if (result) result = add_const_to_group(values, "PLUGIN_EXIT", PGA_PLUGIN_EXIT); + if (result) result = add_const_to_group(values, "NATIVE_PLUGINS_LOADED", PGA_NATIVE_PLUGINS_LOADED); + if (result) result = add_const_to_group(values, "ALL_PLUGINS_LOADED", PGA_ALL_PLUGINS_LOADED); + if (result) result = add_const_to_group(values, "TYPE_BUILDING", PGA_TYPE_BUILDING); + if (result) result = add_const_to_group(values, "GUI_THEME", PGA_GUI_THEME); + if (result) result = add_const_to_group(values, "PANEL_CREATION", PGA_PANEL_CREATION); + if (result) result = add_const_to_group(values, "PANEL_DOCKING", PGA_PANEL_DOCKING); + if (result) result = add_const_to_group(values, "CONTENT_EXPLORER", PGA_CONTENT_EXPLORER); + if (result) result = add_const_to_group(values, "CONTENT_RESOLVER", PGA_CONTENT_RESOLVER); + if (result) result = add_const_to_group(values, "CONTENT_ANALYZED", PGA_CONTENT_ANALYZED); + if (result) result = add_const_to_group(values, "FORMAT_ANALYSIS_STARTED", PGA_FORMAT_ANALYSIS_STARTED); + if (result) result = add_const_to_group(values, "FORMAT_PRELOAD", PGA_FORMAT_PRELOAD); + if (result) result = add_const_to_group(values, "FORMAT_ATTACH_DEBUG", PGA_FORMAT_ATTACH_DEBUG); + if (result) result = add_const_to_group(values, "FORMAT_ANALYSIS_ENDED", PGA_FORMAT_ANALYSIS_ENDED); + if (result) result = add_const_to_group(values, "FORMAT_POST_ANALYSIS_STARTED", PGA_FORMAT_POST_ANALYSIS_STARTED); + if (result) result = add_const_to_group(values, "FORMAT_POST_ANALYSIS_ENDED", PGA_FORMAT_POST_ANALYSIS_ENDED); + if (result) result = add_const_to_group(values, "DISASSEMBLY_STARTED", PGA_DISASSEMBLY_STARTED); + if (result) result = add_const_to_group(values, "DISASSEMBLY_RAW", PGA_DISASSEMBLY_RAW); + if (result) result = add_const_to_group(values, "DISASSEMBLY_HOOKED_LINK", PGA_DISASSEMBLY_HOOKED_LINK); + if (result) result = add_const_to_group(values, "DISASSEMBLY_HOOKED_POST", PGA_DISASSEMBLY_HOOKED_POST); + if (result) result = add_const_to_group(values, "DISASSEMBLY_LIMITED", PGA_DISASSEMBLY_LIMITED); + if (result) result = add_const_to_group(values, "DISASSEMBLY_LOOPS", PGA_DISASSEMBLY_LOOPS); + if (result) result = add_const_to_group(values, "DISASSEMBLY_LINKED", PGA_DISASSEMBLY_LINKED); + if (result) result = add_const_to_group(values, "DISASSEMBLY_GROUPED", PGA_DISASSEMBLY_GROUPED); + if (result) result = add_const_to_group(values, "DISASSEMBLY_RANKED", PGA_DISASSEMBLY_RANKED); + if (result) result = add_const_to_group(values, "DISASSEMBLY_ENDED", PGA_DISASSEMBLY_ENDED); + if (result) result = add_const_to_group(values, "DETECTION_OBFUSCATORS", PGA_DETECTION_OBFUSCATORS); + + if (!result) + { + Py_DECREF(values); + goto exit; + } + + result = attach_constants_group_to_type(type, false, "PluginAction", values, + "Features with which plugins can extend the core of Chrysalide."); + + exit: + + return result; + +} diff --git a/plugins/pychrysalide/plugins/constants.h b/plugins/pychrysalide/plugins/constants.h new file mode 100644 index 0000000..71abcff --- /dev/null +++ b/plugins/pychrysalide/plugins/constants.h @@ -0,0 +1,38 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.h - prototypes pour l'ajout des constantes principales + * + * Copyright (C) 2020 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 + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_PLUGINS_CONSTANTS_H +#define _PLUGINS_PYCHRYSALIDE_PLUGINS_CONSTANTS_H + + +#include <Python.h> +#include <stdbool.h> + + +/* Définit les constantes relatives aux greffons Python. */ +bool define_plugin_module_constants(PyTypeObject *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_PLUGINS_CONSTANTS_H */ diff --git a/plugins/pychrysalide/plugins/module.c b/plugins/pychrysalide/plugins/module.c new file mode 100644 index 0000000..c38caa3 --- /dev/null +++ b/plugins/pychrysalide/plugins/module.c @@ -0,0 +1,104 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire plugins en tant que module + * + * Copyright (C) 2021 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 "module.h" + + +#include <assert.h> + + +#include "plugin.h" +#include "../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Ajoute le module 'plugins' à un module Python. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_plugins_module(PyObject *super) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_PLUGINS_DOC \ + "This module provides features to deal with plugins: the definitions" \ + " required to build new Python plugins as well as functions to" \ + " interact with existing plugins.\n" \ + "\n" \ + "The module is also the place for all plugins without another home." + + static PyModuleDef py_chrysalide_plugins_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.plugins", + .m_doc = PYCHRYSALIDE_PLUGINS_DOC, + + .m_size = -1, + + }; + + module = build_python_module(super, &py_chrysalide_plugins_module); + + result = (module != NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'plugins'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_plugins_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_plugin_module_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/plugins/module.h b/plugins/pychrysalide/plugins/module.h new file mode 100644 index 0000000..e2b10b9 --- /dev/null +++ b/plugins/pychrysalide/plugins/module.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire plugins en tant que module + * + * Copyright (C) 2021 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 + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_PLUGINS_MODULE_H +#define _PLUGINS_PYCHRYSALIDE_PLUGINS_MODULE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Ajoute le module 'plugins' à un module Python. */ +bool add_plugins_module(PyObject *); + +/* Intègre les objets du module 'plugins'. */ +bool populate_plugins_module(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_PLUGINS_MODULE_H */ diff --git a/plugins/pychrysalide/plugins/plugin.c b/plugins/pychrysalide/plugins/plugin.c new file mode 100644 index 0000000..e5ee1ad --- /dev/null +++ b/plugins/pychrysalide/plugins/plugin.c @@ -0,0 +1,1884 @@ + +/* 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 <assert.h> +#include <libgen.h> +#include <malloc.h> +#include <pygobject.h> +#include <string.h> + + +#include <common/extstr.h> +#include <plugins/dt.h> +#include <plugins/plugin-int.h> +#include <plugins/pglist.h> +#include <plugins/self.h> + + +#include "constants.h" +#include "../access.h" +#include "../core.h" +#include "../helpers.h" +#include "../core/constants.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); + +/* Encadre une étape de la vie d'un greffon. */ +static bool py_plugin_module_manage_wrapper(GPluginModule *); + +/* Accompagne la fin du chargement des modules natifs. */ +static void py_plugin_module_notify_plugins_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 *); + +/* Rend compte de la création d'un panneau. */ +static void py_plugin_module_notify_panel_creation_wrapper(const GPluginModule *, PluginAction, GPanelItem *); + +/* Rend compte d'un affichage ou d'un retrait de panneau. */ +static void py_plugin_module_notify_panel_docking_wrapper(const GPluginModule *, PluginAction, GPanelItem *, bool); + +/* 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_known_format_analysis_wrapper(const GPluginModule *, PluginAction, GKnownFormat *, 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 *); + +/* Fournit le nom brut associé au greffon. */ +static char *g_python_plugin_get_modname(const GPythonPlugin *); + + + +/* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */ + + +/* Construit le nom d'un fichier de configuration du greffon. */ +static PyObject *py_plugin_module_build_config_filename(PyObject *, PyObject *); + +/* Affiche un message dans le journal des messages système. */ +static PyObject *py_plugin_module_log_message(PyObject *, PyObject *); + +/* Fournit le nom brut associé au greffon. */ +static PyObject *py_plugin_module_get_modname(PyObject *, void *); + +/* Indique le fichier contenant le greffon manipulé. */ +static PyObject *py_plugin_module_get_filename(PyObject *, void *); + + + +/* ---------------------------------------------------------------------------------- */ +/* 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->manage = py_plugin_module_manage_wrapper; + class->exit = NULL; + + class->plugins_loaded = py_plugin_module_notify_plugins_loaded_wrapper; + + class->include_theme = py_plugin_module_include_theme_wrapper; + class->notify_panel = py_plugin_module_notify_panel_creation_wrapper; + class->notify_docking = py_plugin_module_notify_panel_docking_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_known_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) +{ + int ret; /* Bilan d'un appel */ + GPluginModule *plugin; /* Greffon à manipuler */ + plugin_interface *iface; /* Interface à constituer */ + GPluginModule *dependency; /* Module nécessaire */ + PyObject *value; /* Valeur à présence imposée */ + size_t i; /* Boucle de parcours */ + PyObject *action; /* Identifiant d'une action */ + +#define PLUGIN_MODULE_DOC \ + "PythonModule is the class allowing the creation of Chrysalide plugins" \ + " for Python." \ + "\n" \ + "Calls to the *__init__* constructor of this abstract object expect" \ + " no particular argument.\n" \ + "\n" \ + "Several items have to be defined as class attributes in the final" \ + " class:\n" \ + "* *_name*: a string providing a small name for the plugin;\n" \ + "* *_desc*: a string for a human readable description of the plugin;\n" \ + "* *_version*: a string providing the version of the plugin;\n" \ + "* *_url*: a string for the homepage describing the plugin;\n" \ + "* *_actions*: a tuple of pychrysalide.PluginModule.PluginAction" \ + " defining the features the plugin is bringing; this list can be" \ + " empty.\n" \ + "\n" \ + "Depending on the implemented actions, some of the following methods" \ + " have to be defined for new classes:\n" \ + "* pychrysalide.PluginModule._init_config();\n" \ + "* pychrysalide.PluginModule._notify_plugins_loaded();\n" \ + "* pychrysalide.PluginModule._include_theme();\n" \ + "* pychrysalide.PluginModule._on_panel_creation;\n" \ + "* pychrysalide.PluginModule._on_panel_docking();\n" \ + "* pychrysalide.PluginModule._handle_binary_content();\n" \ + "* pychrysalide.PluginModule._handle_loaded_content();\n" \ + "* pychrysalide.PluginModule._handle_format_analysis();\n" \ + "* pychrysalide.PluginModule._preload_format();\n" \ + "* pychrysalide.PluginModule._attach_debug_format();\n" \ + "* pychrysalide.PluginModule._process_disassembly_event();\n" \ + "* pychrysalide.PluginModule._detect_external_tools()." + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + plugin = G_PLUGIN_MODULE(pygobject_get(self)); + + iface = calloc(1, sizeof(plugin_interface)); + plugin->interface = iface; + +#define LOAD_PYTHON_IFACE(attr) \ + do \ + { \ + value = PyObject_GetAttrString(self, "_" #attr); \ + if (value == NULL) \ + { \ + PyErr_SetString(PyExc_TypeError, _("A '_" #attr "' class attributes is missing.")); \ + return -1; \ + } \ + if (PyUnicode_Check(value)) \ + { \ + iface->attr = strdup(PyUnicode_AsUTF8(value)); \ + Py_DECREF(value); \ + } \ + else \ + { \ + Py_DECREF(value); \ + PyErr_SetString(PyExc_TypeError, _("The '_" #attr "' class attributes must be a string.")); \ + return -1; \ + } \ + assert(iface->attr != NULL); \ + } \ + while (0); + + LOAD_PYTHON_IFACE(name); + LOAD_PYTHON_IFACE(desc); + LOAD_PYTHON_IFACE(version); + LOAD_PYTHON_IFACE(url); + + iface->container = false; + + /** + * Comme le greffon n'est pas passé par la résolution des dépendances, + * orchestrée par la fonction g_plugin_module_resolve_dependencies(), + * on simule l'effet attendu en obtenant une référence par un appel à + * get_plugin_by_name(). + * + * L'incrémentation des références doit coller au plus près de + * l'inscription nominative du greffon : en cas de sortie impromptue + * (lorsqu'une erreur intervient pendant un chargement par exemple), + * l'état de l'ensemble est ainsi cohérent au moment du retrait du + * greffon fautif via la fonction g_plugin_module_dispose(). + */ + + lock_plugin_list_for_reading(); + dependency = get_plugin_by_name("PyChrysalide", NULL); + unlock_plugin_list_for_reading(); + + assert(dependency != NULL); + + if (dependency == NULL) + { + PyErr_SetString(PyExc_TypeError, _("The internal name of the Python plugin has changed!")); + return -1; + } + + iface->required = malloc(sizeof(char *)); + iface->required[0] = "PyChrysalide"; + iface->required_count = 1; + + /* Validation du reste de l'interface */ + + value = PyObject_GetAttrString(self, "_actions"); + + if (value == NULL) + { + PyErr_SetString(PyExc_TypeError, _("An '_actions' class attributes is missing.")); + return -1; + } + + if (!PyTuple_Check(value)) + { + Py_DECREF(value); + PyErr_SetString(PyExc_TypeError, _("The '_actions' class attributes must be a tuple.")); + return -1; + } + + iface->actions_count = PyTuple_Size(value); + iface->actions = malloc(iface->actions_count * sizeof(plugin_action_t)); + + for (i = 0; i < iface->actions_count; i++) + { + action = PyTuple_GetItem(value, i); + + if (!PyLong_Check(action)) + { + Py_DECREF(value); + PyErr_SetString(PyExc_TypeError, _("invalid type for plugin action.")); + return -1; + } + + iface->actions[i] = PyLong_AsUnsignedLong(action); + + } + + Py_DECREF(value); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* * +* Description : Encadre une étape de la vie d'un greffon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_plugin_module_manage_wrapper(GPluginModule *plugin) +{ + bool result; /* Bilan à faire remonter */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan d'exécution */ + +#define PLUGIN_MODULE_MANAGE_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _manage, "$self, action, /", \ + METH_VARARGS, \ + "Abstract method called to react to several steps of the plugin" \ + " life.\n" \ + "\n" \ + "The expected action is a pychrysalide.PluginModule.PluginAction" \ + " value.\n" \ + "\n" \ + "This method has to be defined in order to handle actions such as" \ + " *PLUGIN_LOADED*." \ +) + + result = true; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(plugin)); + + if (has_python_method(pyobj, "_manage")) + { + args = PyTuple_New(1); + + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(PGA_PLUGIN_LOADED)); + + pyret = run_python_method(pyobj, "_manage", args); + + result = (pyret == Py_True); + + Py_XDECREF(pyret); + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* action = type d'action attendue. * +* * +* Description : Accompagne la fin du chargement des modules natifs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *plugin, PluginAction action) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan d'exécution */ + +#define PLUGIN_MODULE_NOTIFY_PLUGINS_LOADED_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _notify_plugins_loaded, "$self, action, /", \ + METH_VARARGS, \ + "Abstract method called once all the (native?) plugins are" \ + " loaded.\n" \ + "\n" \ + "The expected action is a pychrysalide.PluginModule.PluginAction" \ + " value.\n" \ + "\n" \ + "This method has to be defined in order to handle actions such as" \ + " *NATIVE_PLUGINS_LOADED* or *PLUGINS_LOADED*." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(plugin)); + + if (has_python_method(pyobj, "_notify_plugins_loaded")) + { + args = PyTuple_New(1); + + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); + + pyret = run_python_method(pyobj, "_notify_plugins_loaded", args); + + Py_XDECREF(pyret); + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + +} + + +/****************************************************************************** +* * +* 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) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *darkness; /* Valeur booléenne à joindre */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan d'exécution */ + Py_ssize_t length; /* Nombre d'éléments collectés */ + Py_ssize_t i; /* Boucle de parcours */ + PyObject *res; /* Ressource à ajouter */ + +#define PLUGIN_MODULE_INCLUDE_THEME_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _include_theme, "$self, action, dark, /", \ + METH_VARARGS, \ + "Abstract method called once all the native plugins are loaded.\n" \ + "\n" \ + "The expected action is a pychrysalide.PluginModule.PluginAction" \ + " value and the *dark* parameter indicates if a dark theme is" \ + " being to get loaded.\n" \ + "\n" \ + "The expected result is a list of CSS definition resource URIs," \ + " provided as strings such as 'resource:///org/xxx/extra.css'" \ + " for instance.\n" \ + "\n" \ + "This method has to be defined in order to handle action such as" \ + " *GUI_THEME*." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(plugin)); + + if (has_python_method(pyobj, "_include_theme")) + { + args = PyTuple_New(2); + + darkness = (dark ? Py_True : Py_False); + Py_INCREF(darkness); + + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); + PyTuple_SetItem(args, 1, darkness); + + pyret = run_python_method(pyobj, "_include_theme", args); + + if (!PySequence_Check(pyret)) + g_plugin_module_log_simple_message(plugin, LMT_ERROR, _("The returned value must be a string list")); + + else + { + length = PySequence_Length(pyret); + + for (i = 0; i < length; i++) + { + res = PySequence_GetItem(pyret, i); + + if (!PyUnicode_Check(res)) + g_plugin_module_log_variadic_message(plugin, LMT_ERROR, + _("The returned #%zd value must be a string")); + + else + { + *resources = realloc(*resources, ++(*count) * sizeof(char **)); + *resources[*count - 1] = strdup(PyUnicode_DATA(res)); + } + + Py_DECREF(res); + + } + + } + + Py_XDECREF(pyret); + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* action = type d'action attendue. * +* item = nouveau panneau créé. * +* * +* Description : Rend compte de la création d'un panneau. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_plugin_module_notify_panel_creation_wrapper(const GPluginModule *plugin, PluginAction action, GPanelItem *item) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan d'exécution */ + +#define PLUGIN_MODULE_ON_PANEL_CREATION_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _on_panel_creation, "$self, action, item, /", \ + METH_VARARGS, \ + "Abstract method called when a new instance of panel is created.\n" \ + "\n" \ + "The expected *action* is a pychrysalide.PluginModule.PluginAction" \ + " value and the *item* is a pychrysalide.gui.PanelItem instance.\n" \ + "\n" \ + "This method has to be defined in order to handle action such as" \ + " *PANEL_CREATION*." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(plugin)); + + if (has_python_method(pyobj, "_on_panel_creation")) + { + args = PyTuple_New(2); + + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); + PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(item))); + + pyret = run_python_method(pyobj, "_on_panel_creation", args); + + Py_XDECREF(pyret); + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* action = type d'action attendue. * +* item = panneau marqué par un changement d'affichage. * +* dock = indique une accroche et non un décrochage. * +* * +* Description : Rend compte d'un affichage ou d'un retrait de panneau. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_plugin_module_notify_panel_docking_wrapper(const GPluginModule *plugin, PluginAction action, GPanelItem *item, bool dock) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pydock; /* Valeur booléenne à joindre */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan d'exécution */ + +#define PLUGIN_MODULE_ON_PANEL_DOCKING_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _on_panel_docking, "$self, action, item, dock, /", \ + METH_VARARGS, \ + "Abstract method called when a panel is docked or undocked into" \ + " the Chrysalide main graphical interface.\n" \ + "\n" \ + "The expected *action* is a pychrysalide.PluginModule.PluginAction" \ + " value, the *item* is a pychrysalide.gui.PanelItem instance and" \ + " the *dock* parameter indicates if the panel request a docking" \ + " operation or an undocking one.\n" \ + "\n" \ + "This method has to be defined in order to handle action such as" \ + " *PANEL_DOCKING*." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(plugin)); + + if (has_python_method(pyobj, "_on_panel_docking")) + { + args = PyTuple_New(3); + + pydock = (dock ? Py_True : Py_False); + Py_INCREF(pydock); + + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); + PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(item))); + PyTuple_SetItem(args, 2, pydock); + + pyret = run_python_method(pyobj, "_on_panel_docking", args); + + Py_XDECREF(pyret); + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + +} + + +/****************************************************************************** +* * +* 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 *pyret; /* Bilan d'exécution */ + +#define PLUGIN_MODULE_HANDLE_BINARY_CONTENT_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _handle_binary_content, "$self, action, content, wid, status, /", \ + METH_VARARGS, \ + "Abstract method used to explore a binary content (and possibly to add new" \ + " contents to explore) or to load a recognized binary content into a" \ + " pychrysalide.analysis.LoadedContent instance.\n" \ + "\n" \ + "The expected action is a pychrysalide.PluginModule.PluginAction" \ + " value and the initial binary content is a pychrysalide.analysis.BinContent" \ + " instance. A tracking identifier is provided and is aimed to be" \ + " used with methods from pychrysalide.analysis.ContentExplorer and" \ + " pychrysalide.analysis.ContentResolver. A reference to the main status bar" \ + " may also be provided, as a pychrysalide.gtkext.StatusStack instance if" \ + " running in graphical mode or None otherwise.\n" \ + "\n" \ + "This method has to be defined in order to handle actions such as" \ + " *CONTENT_EXPLORER* or *CONTENT_RESOLVER*." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(plugin)); + + if (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))); + + pyret = run_python_method(pyobj, "_handle_binary_content", args); + + Py_XDECREF(pyret); + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* action = type d'action attendue. * +* content = contenu chargé à traiter. * +* gid = 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 gid, GtkStatusStack *status) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan d'exécution */ + +#define PLUGIN_MODULE_HANDLE_LOADED_CONTENT_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _handle_loaded_content, "$self, action, content, gid, status, /", \ + METH_VARARGS, \ + "Abstract method run once a loaded binary has been analyzed with success.\n" \ + "\n" \ + "The expected action is a pychrysalide.PluginModule.PluginAction" \ + " value and the analyzed content is a pychrysalide.analysis.LoadedContent" \ + " instance. The identifier refers to the working queue used to process the" \ + " analysis. A reference to the main status bar may also be provided, as a" \ + " pychrysalide.gtkext.StatusStack instance if running in graphical mode or" \ + " None otherwise.\n" \ + "\n" \ + "This method has to be defined in order to handle action such as" \ + " *CONTENT_ANALYZED*." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(plugin)); + + if (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(gid)); + PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status))); + + pyret = run_python_method(pyobj, "_handle_loaded_content", args); + + Py_XDECREF(pyret); + 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_known_format_analysis_wrapper(const GPluginModule *plugin, PluginAction action, GKnownFormat *format, wgroup_id_t gid, GtkStatusStack *status) +{ + bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan d'exécution */ + +#define PLUGIN_MODULE_HANDLE_BINARY_FORMAT_ANALYSIS_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _handle_binary_format_analysis, "$self, action, format, gid, status, /", \ + METH_VARARGS, \ + "Abstract method run at several different steps of a binary format analysis:\n" \ + "* at the beginning and at the end of the main analysis pass;\n" \ + "* at the beginning and at the end of the extra final pass.\n" \ + "\n" \ + "The expected action is a pychrysalide.PluginModule.PluginAction" \ + " value and the provided format is a pychrysalide.format.KnownFormat" \ + " instance. The identifier refers to the working queue used to process the" \ + " analysis. A reference to the main status bar may also be provided, as a" \ + " pychrysalide.gtkext.StatusStack instance if running in graphical mode or" \ + " None otherwise.\n" \ + "\n" \ + "This method has to be defined in order to handle actions such as" \ + " *FORMAT_ANALYSIS_STARTED*, *FORMAT_ANALYSIS_ENDED*," \ + " *FORMAT_POST_ANALYSIS_STARTED* or *FORMAT_POST_ANALYSIS_ENDED*." \ +) + + result = false; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(plugin)); + + if (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))); + + pyret = run_python_method(pyobj, "_handle_format_analysis", args); + + result = (pyret == Py_True); + + Py_XDECREF(pyret); + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* 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 *pyret; /* Bilan d'exécution */ + +#define PLUGIN_MODULE_PRELOAD_BINARY_FORMAT_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _preload_binary_format, "$self, action, format, info, status, /", \ + METH_VARARGS, \ + "Abstract method which is an opportunity to setup instructions or comments" \ + " ahead of the disassembling process.\n" \ + "\n" \ + "Format fields do not need to get disassembled and may be annotated for" \ + " instance.\n" \ + "\n" \ + "The expected action is a pychrysalide.PluginModule.PluginAction" \ + " value and the provided format is a pychrysalide.format.BinFormat" \ + " instance. The information holder to fill is a pychrysalide.format.PreloadInfo"\ + " instance. A reference to the main status bar may also be provided, as a" \ + " pychrysalide.gtkext.StatusStack instance if running in graphical mode or" \ + " None otherwise.\n" \ + "\n" \ + "This method has to be defined in order to handle action such as" \ + " *FORMAT_PRELOAD*." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(plugin)); + + if (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))); + + pyret = run_python_method(pyobj, "_preload_format", args); + + Py_XDECREF(pyret); + 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 *pyret; /* Bilan d'exécution */ + +#define PLUGIN_MODULE_ATTACH_DEBUG_FORMAT_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _attach_debug_format, "$self, action, format, /", \ + METH_VARARGS, \ + "Abstract method called when a debugger is attached to a binary format.\n" \ + "\n" \ + "The expected action is a pychrysalide.PluginModule.PluginAction" \ + " value and the provided format is a pychrysalide.format.ExeFormat instance.\n" \ + "\n" \ + "This method has to be defined in order to handle action such as" \ + " *FORMAT_ATTACH_DEBUG*." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(plugin)); + + if (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))); + + pyret = run_python_method(pyobj, "_attach_debug_format", args); + + Py_XDECREF(pyret); + 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 *pyret; /* Bilan d'exécution */ + +#define PLUGIN_MODULE_PROCESS_DISASSEMBLY_EVENT_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _process_disassembly_event, "$self, action, format, /", \ + METH_VARARGS, \ + "Abstract method run at several different steps of a binary analysis.\n" \ + "\n" \ + "The expected action is a pychrysalide.PluginModule.PluginAction" \ + " value and the provided format is a pychrysalide.format.ExeFormat instance.\n" \ + "\n" \ + "This method has to be defined in order to handle actions such as" \ + " *DISASSEMBLY_STARTED*, *DISASSEMBLY_RAW*, *DISASSEMBLY_HOOKED_LINK*," \ + " *DISASSEMBLY_HOOKED_POST*, *DISASSEMBLY_LIMITED*, *DISASSEMBLY_LOOPS*," \ + " *DISASSEMBLY_LINKED*, *DISASSEMBLY_GROUPED*, *DISASSEMBLY_RANKED*," \ + " *DISASSEMBLY_ENDED*." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(plugin)); + + if (has_python_method(pyobj, "_process_disassembly_event")) + { + 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))); + + pyret = run_python_method(pyobj, "_process_disassembly_event", args); + + Py_XDECREF(pyret); + 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) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *details; /* Valeur booléenne à joindre */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan d'exécution */ + Py_ssize_t length; /* Nombre d'éléments collectés */ + Py_ssize_t i; /* Boucle de parcours */ + PyObject *res; /* Ressource à ajouter */ + +#define PLUGIN_MODULE_DETECT_EXTERNAL_TOOLS_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _detect_external_tools, "$self, action, content, version, /", \ + METH_VARARGS, \ + "Abstract method called when a detection of tools used the build" \ + " the analyzed content is required.\n" \ + "\n" \ + "The expected action is a pychrysalide.PluginModule.PluginAction" \ + " value and the content is a pychrysalide.analysis.LoadedContent" \ + " instance. The *version* parameter is a boolean value indicating" \ + " if some extra details about the tools version are wished.\n" \ + "\n" \ + "The expected result is a list of strings.\n" \ + "\n" \ + "This method has to be defined in order to handle action such as" \ + " *DETECTION_OBFUSCATORS*." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(plugin)); + + if (has_python_method(pyobj, "_detect_external_tools")) + { + args = PyTuple_New(3); + + details = (version ? Py_True : Py_False); + Py_INCREF(details); + + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); + PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(content))); + PyTuple_SetItem(args, 2, details); + + pyret = run_python_method(pyobj, "_detect_external_tools", args); + + if (!PySequence_Check(pyret)) + g_plugin_module_log_simple_message(plugin, LMT_ERROR, _("The returned value must be a string list")); + + else + { + length = PySequence_Length(pyret); + + for (i = 0; i < length; i++) + { + res = PySequence_GetItem(pyret, i); + + if (!PyUnicode_Check(res)) + g_plugin_module_log_variadic_message(plugin, LMT_ERROR, + _("The returned #%zd value must be a string")); + + else + { + *names = realloc(*names, ++(*count) * sizeof(char **)); + *names[*count - 1] = strdup(PyUnicode_DATA(res)); + } + + Py_DECREF(res); + + } + + } + + Py_XDECREF(pyret); + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* 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 */ + GPluginModuleClass *plugin; /* Version parente de la classe*/ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_python_plugin_dispose; + object->finalize = (GObjectFinalizeFunc)g_python_plugin_finalize; + + plugin = G_PLUGIN_MODULE_CLASS(klass); + + plugin->get_modname = (pg_get_modname_fc)g_python_plugin_get_modname; + +} + + +/****************************************************************************** +* * +* 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) +{ +#if 0 + 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(); +#endif + + 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) + { + if (final->name != NULL) free(final->name); + if (final->desc != NULL) free(final->desc); + if (final->version != NULL) free(final->version); + if (final->url != NULL) free(final->url); + + assert(final->required_count == 1); + + if (final->required != NULL) + 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 : plugin = greffon à valider. * +* * +* Description : Fournit le nom brut associé au greffon. * +* * +* Retour : Désignation brute du greffon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_python_plugin_get_modname(const GPythonPlugin *plugin) +{ + char *result; /* Désignation brute à renvoyer*/ + char *path; /* Chemin à traiter */ + + path = strdup(g_plugin_module_get_filename(G_PLUGIN_MODULE(plugin))); + + result = strdup(basename(path)); + + free(path); + + 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 */ + + 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_plugin_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 : Construit le nom d'un fichier de configuration du greffon. * +* * +* Retour : Chemin d'accès déterminé, ou NULL en cas d'erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_plugin_module_build_config_filename(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + const char *final; /* Suffixe de fichier imposé */ + int create; /* Volonté de création */ + char *filename; /* Nom de fichier déterminé */ + +#define PLUGIN_MODULE_BUILD_CONFIG_FILENAME_METHOD PYTHON_METHOD_DEF \ +( \ + build_config_filename, "final, /, create=False", \ + METH_VARARGS, py_plugin_module, \ + "Build a filename suitable for the plugin configuration, ending with" \ + " the *final* suffix.\n" \ + "\n" \ + "If the *create* parameter is set, the path to this filename is" \ + " created.\n" \ + "\n" \ + "The result is a string or None on failure." \ +) + + create = 0; + + if (!PyArg_ParseTuple(args, "s|p", &final, &create)) + return NULL; + + filename = g_plugin_module_build_config_filename(G_PLUGIN_MODULE(pygobject_get(self)), final, create); + + if (filename != NULL) + { + result = PyUnicode_FromString(filename); + free(filename); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* 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 */ + LogMessageType type; /* Espèce du message */ + const char *msg; /* Contenu du message */ + +#define PLUGIN_MODULE_LOG_MESSAGE_METHOD PYTHON_METHOD_DEF \ +( \ + log_message, "type, msg, /", \ + METH_VARARGS, py_plugin_module, \ + "Display a message in the log window, in graphical mode, or in the" \ + " console output if none.\n" \ + "\n" \ + "The type of the message has to be a pychrysalide.core.LogMessageType" \ + " value." \ + "\n" \ + "The only difference with the main pychrysalide.core.log_message()" \ + " function is that messages are automatically prefixed with the plugin" \ + " name here." \ +) + + if (!PyArg_ParseTuple(args, "O&s", convert_to_log_message_type, &type, &msg)) + return NULL; + + g_plugin_module_log_simple_message(G_PLUGIN_MODULE(pygobject_get(self)), type, msg); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit le nom brut associé au greffon. * +* * +* Retour : Désignation brute du greffon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_plugin_module_get_modname(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GPluginModule *plugin; /* Version native du greffon */ + char *modname; /* Désignation brute */ + +#define PLUGIN_MODULE_MODNAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + modname, py_plugin_module, \ + "Raw module name of the plugin." \ +) + + plugin = G_PLUGIN_MODULE(pygobject_get(self)); + modname = g_plugin_module_get_modname(plugin); + + result = PyUnicode_FromString(modname); + + free(modname); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique le fichier contenant le greffon manipulé. * +* * +* Retour : Chemin d'accès au greffon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_plugin_module_get_filename(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GPluginModule *plugin; /* Version native du greffon */ + const char *filename; /* Chemin d'accès associé */ + +#define PLUGIN_MODULE_FILENAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + filename, py_plugin_module, \ + "Filename of the plugin." \ +) + + plugin = G_PLUGIN_MODULE(pygobject_get(self)); + filename = g_plugin_module_get_filename(plugin); + + result = PyUnicode_FromString(filename); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la configuration mise en place pour le greffon. * +* * +* Retour : Configuration dédiée à l'extension. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_plugin_module_get_config(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GPluginModule *plugin; /* Version native du greffon */ + GGenConfig *config; /* Configuration associée */ + +#define PLUGIN_MODULE_CONFIG_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + config, py_plugin_module, \ + "Dedicated configuration for the plugin." \ + "\n" \ + "The value is a pychrysalide.glibext.GenConfig instance" \ + " or None if the configuration is not yet created.\n" \ + "\n" \ + "As configuration storage path depends on the plugin name," \ + " all plugin properties have to get fully loaded by the" \ + " core before the configuration can be setup." \ + "automatically" \ +) + + plugin = G_PLUGIN_MODULE(pygobject_get(self)); + config = g_plugin_module_get_config(plugin); + + if (config == NULL) + { + result = Py_None; + Py_INCREF(result); + } + + else + { + result = pygobject_new(G_OBJECT(config)); + + g_object_unref(G_OBJECT(config)); + + } + + 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[] = { + PLUGIN_MODULE_MANAGE_WRAPPER, + PLUGIN_MODULE_NOTIFY_PLUGINS_LOADED_WRAPPER, + PLUGIN_MODULE_INCLUDE_THEME_WRAPPER, + PLUGIN_MODULE_ON_PANEL_CREATION_WRAPPER, + PLUGIN_MODULE_ON_PANEL_DOCKING_WRAPPER, + PLUGIN_MODULE_HANDLE_BINARY_CONTENT_WRAPPER, + PLUGIN_MODULE_HANDLE_LOADED_CONTENT_WRAPPER, + PLUGIN_MODULE_HANDLE_BINARY_FORMAT_ANALYSIS_WRAPPER, + PLUGIN_MODULE_PRELOAD_BINARY_FORMAT_WRAPPER, + PLUGIN_MODULE_ATTACH_DEBUG_FORMAT_WRAPPER, + PLUGIN_MODULE_PROCESS_DISASSEMBLY_EVENT_WRAPPER, + PLUGIN_MODULE_DETECT_EXTERNAL_TOOLS_WRAPPER, + PLUGIN_MODULE_BUILD_CONFIG_FILENAME_METHOD, + PLUGIN_MODULE_LOG_MESSAGE_METHOD, + { NULL } + }; + + static PyGetSetDef py_plugin_module_getseters[] = { + PLUGIN_MODULE_MODNAME_ATTRIB, + PLUGIN_MODULE_FILENAME_ATTRIB, + PLUGIN_MODULE_CONFIG_ATTRIB, + { NULL } + }; + + static PyTypeObject py_plugin_module_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.PluginModule", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = PLUGIN_MODULE_DOC, + + .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.plugins"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_PYTHON_PLUGIN, type, &PyGObject_Type)) + return false; + + if (!define_plugin_module_constants(type)) + return false; + + } + + return true; + +} diff --git a/plugins/pychrysalide/plugins/plugin.h b/plugins/pychrysalide/plugins/plugin.h new file mode 100644 index 0000000..2a31cf2 --- /dev/null +++ b/plugins/pychrysalide/plugins/plugin.h @@ -0,0 +1,75 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plugin.h - prototypes pour les interactions avec un greffon Python + * + * Copyright (C) 2018 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 + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_PLUGINS_PLUGIN_H +#define _PLUGINS_PYCHRYSALIDE_PLUGINS_PLUGIN_H + + +#include <Python.h> +#include <glib-object.h> +#include <stdbool.h> + + +#include <plugins/plugin.h> + + + +/* --------------------- INTERFACE INTERNE POUR GREFFONS PYTHON --------------------- */ + + +#define G_TYPE_PYTHON_PLUGIN (g_python_plugin_get_type()) +#define G_PYTHON_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PYTHON_PLUGIN, GPythonPlugin)) +#define G_IS_PYTHON_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PYTHON_PLUGIN)) +#define G_PYTHON_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PYTHON_PLUGIN, GPythonPluginClass)) +#define G_IS_PYTHON_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PYTHON_PLUGIN)) +#define G_PYTHON_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PYTHON_PLUGIN, GPythonPluginClass)) + + +/* Ligne de représentation de code binaire (instance) */ +typedef struct _GPythonPlugin GPythonPlugin; + +/* Ligne de représentation de code binaire (classe) */ +typedef struct _GPythonPluginClass GPythonPluginClass; + + +/* Indique le type défini par la GLib pour le greffon Python. */ +GType g_python_plugin_get_type(void); + +/* Crée un greffon à partir de code Python. */ +GPluginModule *g_python_plugin_new(const char *, const char *); + + + +/* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */ + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_plugin_module_type(void); + +/* Prend en charge l'objet 'pychrysalide.PluginModule'. */ +bool ensure_python_plugin_module_is_registered(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_PLUGINS_PLUGIN_H */ |