summaryrefslogtreecommitdiff
path: root/plugins/pychrysalide/plugins
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2021-02-07 20:30:07 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2021-02-07 20:30:07 (GMT)
commit42540e681161aab0a1c27c66541ed5dc833ca411 (patch)
treea7a1329435252b7b1ac8981b6ab3a3abddcfe457 /plugins/pychrysalide/plugins
parent7c17177918f1bb94be7c84ca9b839155623ff05f (diff)
Created the right place for plugins in the Python API.
Diffstat (limited to 'plugins/pychrysalide/plugins')
-rw-r--r--plugins/pychrysalide/plugins/Makefile.am24
-rw-r--r--plugins/pychrysalide/plugins/constants.c100
-rw-r--r--plugins/pychrysalide/plugins/constants.h38
-rw-r--r--plugins/pychrysalide/plugins/module.c104
-rw-r--r--plugins/pychrysalide/plugins/module.h42
-rw-r--r--plugins/pychrysalide/plugins/plugin.c1884
-rw-r--r--plugins/pychrysalide/plugins/plugin.h75
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 */