summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2020-05-17 18:05:48 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2020-05-17 18:05:48 (GMT)
commitd110791309783e6e30df837a81cf8e14e1ac9641 (patch)
tree75e65909e080cc3ace578c7beb6f0bdae6dc18c1
parentf3e136eab9fd6adcb51988c9f70ca7f35552abc4 (diff)
Updated the plugin system and its Python documentation.
-rw-r--r--plugins/devdbg/speed.c2
-rw-r--r--plugins/devdbg/speed.h2
-rw-r--r--plugins/libcsem/semantic.c2
-rw-r--r--plugins/libcsem/semantic.h2
-rw-r--r--plugins/lnxsyscalls/core.c2
-rw-r--r--plugins/lnxsyscalls/core.h2
-rw-r--r--plugins/pychrysalide/Makefile.am1
-rw-r--r--plugins/pychrysalide/analysis/constants.c2
-rw-r--r--plugins/pychrysalide/constants.c95
-rw-r--r--plugins/pychrysalide/constants.h38
-rw-r--r--plugins/pychrysalide/core/constants.c56
-rw-r--r--plugins/pychrysalide/core/constants.h3
-rw-r--r--plugins/pychrysalide/core/logs.c32
-rw-r--r--plugins/pychrysalide/format/symbol.c20
-rw-r--r--plugins/pychrysalide/plugin.c790
-rw-r--r--plugins/pychrysalide/pychrysa.c2
-rw-r--r--plugins/python/abackup/plugin.py23
-rw-r--r--plugins/python/apkfiles/apkfiles.py23
-rw-r--r--plugins/python/checksec/plugin.py21
-rw-r--r--plugins/python/liveconv/plugin.py19
-rw-r--r--src/plugins/plugin.c10
21 files changed, 734 insertions, 413 deletions
diff --git a/plugins/devdbg/speed.c b/plugins/devdbg/speed.c
index 1378c66..c8416d1 100644
--- a/plugins/devdbg/speed.c
+++ b/plugins/devdbg/speed.c
@@ -218,7 +218,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_handle_binary_format_analysis(const GPlug
* *
******************************************************************************/
-G_MODULE_EXPORT void chrysalide_plugin_process_binary_disassembly(const GPluginModule *plugin, PluginAction action, GLoadedBinary *binary, GtkStatusStack *status, GProcContext *context)
+G_MODULE_EXPORT void chrysalide_plugin_process_disassembly_event(const GPluginModule *plugin, PluginAction action, GLoadedBinary *binary, GtkStatusStack *status, GProcContext *context)
{
speed_measure *measure; /* Suivi des progressions */
struct timeval point; /* Point de mesure courant */
diff --git a/plugins/devdbg/speed.h b/plugins/devdbg/speed.h
index 7d591fb..2347706 100644
--- a/plugins/devdbg/speed.h
+++ b/plugins/devdbg/speed.h
@@ -34,7 +34,7 @@
G_MODULE_EXPORT bool chrysalide_plugin_handle_binary_format_analysis(const GPluginModule *, PluginAction, GBinFormat *, wgroup_id_t, GtkStatusStack *);
/* Exécute une action pendant un désassemblage de binaire. */
-G_MODULE_EXPORT void chrysalide_plugin_process_binary_disassembly(const GPluginModule *, PluginAction , GLoadedBinary *, GtkStatusStack *, GProcContext *);
+G_MODULE_EXPORT void chrysalide_plugin_process_disassembly_event(const GPluginModule *, PluginAction , GLoadedBinary *, GtkStatusStack *, GProcContext *);
diff --git a/plugins/libcsem/semantic.c b/plugins/libcsem/semantic.c
index 00e174f..6786894 100644
--- a/plugins/libcsem/semantic.c
+++ b/plugins/libcsem/semantic.c
@@ -54,7 +54,7 @@ DEFINE_CHRYSALIDE_PLUGIN("CSem", "Semantic information relative to the libc",
* *
******************************************************************************/
-G_MODULE_EXPORT void chrysalide_plugin_process_binary_disassembly(const GPluginModule *plugin, PluginAction action, GLoadedBinary *binary, GtkStatusStack *status, GProcContext *context)
+G_MODULE_EXPORT void chrysalide_plugin_process_disassembly_event(const GPluginModule *plugin, PluginAction action, GLoadedBinary *binary, GtkStatusStack *status, GProcContext *context)
{
if (action == PGA_DISASSEMBLY_HOOKED_POST)
{
diff --git a/plugins/libcsem/semantic.h b/plugins/libcsem/semantic.h
index 58c14ef..016b85d 100644
--- a/plugins/libcsem/semantic.h
+++ b/plugins/libcsem/semantic.h
@@ -31,7 +31,7 @@
/* Exécute une action pendant un désassemblage de binaire. */
-G_MODULE_EXPORT void chrysalide_plugin_process_binary_disassembly(const GPluginModule *, PluginAction, GLoadedBinary *, GtkStatusStack *, GProcContext *);
+G_MODULE_EXPORT void chrysalide_plugin_process_disassembly_event(const GPluginModule *, PluginAction, GLoadedBinary *, GtkStatusStack *, GProcContext *);
diff --git a/plugins/lnxsyscalls/core.c b/plugins/lnxsyscalls/core.c
index 314f89f..bee11db 100644
--- a/plugins/lnxsyscalls/core.c
+++ b/plugins/lnxsyscalls/core.c
@@ -96,7 +96,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
* *
******************************************************************************/
-G_MODULE_EXPORT void chrysalide_plugin_process_binary_disassembly(const GPluginModule *plugin, PluginAction action, GLoadedBinary *binary, GtkStatusStack *status, GProcContext *context)
+G_MODULE_EXPORT void chrysalide_plugin_process_disassembly_event(const GPluginModule *plugin, PluginAction action, GLoadedBinary *binary, GtkStatusStack *status, GProcContext *context)
{
GBinFormat *format; /* Format du binaire chargé */
const char *arch; /* Architecture d'exécution */
diff --git a/plugins/lnxsyscalls/core.h b/plugins/lnxsyscalls/core.h
index dcf5c11..50b8ef0 100644
--- a/plugins/lnxsyscalls/core.h
+++ b/plugins/lnxsyscalls/core.h
@@ -34,7 +34,7 @@
G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *);
/* Exécute une action pendant un désassemblage de binaire. */
-G_MODULE_EXPORT void chrysalide_plugin_process_binary_disassembly(const GPluginModule *, PluginAction , GLoadedBinary *, GtkStatusStack *, GProcContext *);
+G_MODULE_EXPORT void chrysalide_plugin_process_disassembly_event(const GPluginModule *, PluginAction , GLoadedBinary *, GtkStatusStack *, GProcContext *);
diff --git a/plugins/pychrysalide/Makefile.am b/plugins/pychrysalide/Makefile.am
index 6bcaef4..5d6c3e6 100644
--- a/plugins/pychrysalide/Makefile.am
+++ b/plugins/pychrysalide/Makefile.am
@@ -6,6 +6,7 @@ libdir = $(pluginslibdir)
pychrysalide_la_SOURCES = \
access.h access.c \
+ constants.h constants.c \
constval.h constval.c \
helpers.h helpers.c \
plugin.h plugin.c \
diff --git a/plugins/pychrysalide/analysis/constants.c b/plugins/pychrysalide/analysis/constants.c
index 87f91a3..a162ac7 100644
--- a/plugins/pychrysalide/analysis/constants.c
+++ b/plugins/pychrysalide/analysis/constants.c
@@ -36,7 +36,7 @@
* *
* Paramètres : type = type dont le dictionnaire est à compléter. *
* *
-* Description : Définit les constantes relatives au contenus binaires. *
+* Description : Définit les constantes relatives aux contenus binaires. *
* *
* Retour : true en cas de succès de l'opération, false sinon. *
* *
diff --git a/plugins/pychrysalide/constants.c b/plugins/pychrysalide/constants.c
new file mode 100644
index 0000000..e31a8fe
--- /dev/null
+++ b/plugins/pychrysalide/constants.c
@@ -0,0 +1,95 @@
+
+/* 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_EXIT", PGA_PLUGIN_EXIT);
+ if (result) result = add_const_to_group(values, "NATIVE_LOADED", PGA_NATIVE_LOADED);
+ if (result) result = add_const_to_group(values, "GUI_THEME", PGA_GUI_THEME);
+ 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/constants.h b/plugins/pychrysalide/constants.h
new file mode 100644
index 0000000..21f9d0e
--- /dev/null
+++ b/plugins/pychrysalide/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_CONSTANTS_H
+#define _PLUGINS_PYCHRYSALIDE_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_CONSTANTS_H */
diff --git a/plugins/pychrysalide/core/constants.c b/plugins/pychrysalide/core/constants.c
index e61f451..f3ec530 100644
--- a/plugins/pychrysalide/core/constants.c
+++ b/plugins/pychrysalide/core/constants.c
@@ -73,3 +73,59 @@ bool define_core_logs_constants(PyObject *module)
return result;
}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
+* Description : Tente de convertir en constante LogMessageType. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_log_message_type(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+ unsigned long value; /* Valeur transcrite */
+
+ result = PyObject_IsInstance(arg, (PyObject *)&PyLong_Type);
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to LogMessageType");
+ break;
+
+ case 1:
+ value = PyLong_AsUnsignedLong(arg);
+
+ if (value > LMT_COUNT)
+ {
+ PyErr_SetString(PyExc_TypeError, "invalid value for LogMessageType");
+ result = 0;
+ }
+
+ else
+ *((LogMessageType *)dst) = value;
+
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/pychrysalide/core/constants.h b/plugins/pychrysalide/core/constants.h
index 38a8ebc..6ed6fbb 100644
--- a/plugins/pychrysalide/core/constants.h
+++ b/plugins/pychrysalide/core/constants.h
@@ -34,6 +34,9 @@
/* Définit les constantes pour les types de messages. */
bool define_core_logs_constants(PyObject *);
+/* Tente de convertir en constante LogMessageType. */
+int convert_to_log_message_type(PyObject *, void *);
+
#endif /* _PLUGINS_PYCHRYSALIDE_CORE_CONSTANTS_H */
diff --git a/plugins/pychrysalide/core/logs.c b/plugins/pychrysalide/core/logs.c
index 0965b4b..4e0bc7b 100644
--- a/plugins/pychrysalide/core/logs.c
+++ b/plugins/pychrysalide/core/logs.c
@@ -103,7 +103,7 @@ static PyObject *py_logs_get_verbosity(PyObject *self, PyObject *args)
static PyObject *py_logs_set_verbosity(PyObject *self, PyObject *args)
{
PyObject *result; /* Bilan à retourner */
- unsigned long verbosity; /* Niveau de filtre de message */
+ LogMessageType verbosity; /* Niveau de filtre de message */
#define LOGS_SET_VERBOSITY_METHOD PYTHON_METHOD_DEF \
( \
@@ -116,7 +116,7 @@ static PyObject *py_logs_set_verbosity(PyObject *self, PyObject *args)
" all kinds of logs get printed." \
)
- if (!PyArg_ParseTuple(args, "k", &verbosity))
+ if (!PyArg_ParseTuple(args, "O&", convert_to_log_message_type, &verbosity))
return NULL;
set_log_verbosity(verbosity);
@@ -145,7 +145,7 @@ static PyObject *py_logs_set_verbosity(PyObject *self, PyObject *args)
static PyObject *py_logs_log_message(PyObject *self, PyObject *args)
{
PyObject *result; /* Bilan à retourner */
- unsigned long type; /* Espèce du message */
+ LogMessageType type; /* Espèce du message */
const char *msg; /* Contenu du message */
#define LOGS_LOG_MESSAGE_METHOD PYTHON_METHOD_DEF \
@@ -159,29 +159,13 @@ static PyObject *py_logs_log_message(PyObject *self, PyObject *args)
" value." \
)
- if (!PyArg_ParseTuple(args, "ks", &type, &msg))
+ if (!PyArg_ParseTuple(args, "O&s", convert_to_log_message_type, &type, &msg))
return NULL;
- switch (type)
- {
- case LMT_INFO:
- case LMT_PROCESS:
- case LMT_WARNING:
- case LMT_BAD_BINARY:
- case LMT_ERROR:
- case LMT_EXT_ERROR:
- log_plugin_simple_message(type, msg);
- result = Py_None;
- Py_INCREF(result);
- break;
-
- default:
- PyErr_SetString(PyExc_ValueError,
- _("Invalid type of message"));
- result = NULL;
- break;
-
- }
+ log_plugin_simple_message(type, msg);
+
+ result = Py_None;
+ Py_INCREF(result);
return result;
diff --git a/plugins/pychrysalide/format/symbol.c b/plugins/pychrysalide/format/symbol.c
index c86b453..7ecc576 100644
--- a/plugins/pychrysalide/format/symbol.c
+++ b/plugins/pychrysalide/format/symbol.c
@@ -59,7 +59,7 @@ static PyObject *py_binary_symbol_new(PyTypeObject *, PyObject *, PyObject *);
static void py_binary_symbol_init_gclass(GBinSymbolClass *, gpointer);
/* Fournit une étiquette pour viser un symbole. */
-static char *g_binary_symbol_get_label_wrapper(const GBinSymbol *);
+static char *py_binary_symbol_get_label_wrapper(const GBinSymbol *);
/* Initialise une instance sur la base du dérivé de GObject. */
static int py_binary_symbol_init(PyObject *, PyObject *, PyObject *);
@@ -194,7 +194,7 @@ static PyObject *py_binary_symbol_new(PyTypeObject *type, PyObject *args, PyObje
static void py_binary_symbol_init_gclass(GBinSymbolClass *class, gpointer unused)
{
- class->get_label = g_binary_symbol_get_label_wrapper;
+ class->get_label = py_binary_symbol_get_label_wrapper;
}
@@ -211,12 +211,21 @@ static void py_binary_symbol_init_gclass(GBinSymbolClass *class, gpointer unused
* *
******************************************************************************/
-static char *g_binary_symbol_get_label_wrapper(const GBinSymbol *symbol)
+static char *py_binary_symbol_get_label_wrapper(const GBinSymbol *symbol)
{
char *result; /* Etiquette à retourner */
PyObject *pyobj; /* Objet Python concerné */
PyObject *pyret; /* Bilan de consultation */
+#define BINARY_SYMBOL_GET_LABEL_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _get_label, "$self, /", \
+ METH_VARARGS, \
+ "Abstract method used to provide the default label for a symbol.\n" \
+ "\n" \
+ "The returned value has to be a string." \
+)
+
result = NULL;
pyobj = pygobject_new(G_OBJECT(symbol));
@@ -275,8 +284,8 @@ static int py_binary_symbol_init(PyObject *self, PyObject *args, PyObject *kwds)
"Where range is a memory space defined by pychrysalide.arch.mrange and" \
" stype a pychrysalide.format.BinSymbol.SymbolType value." \
"\n" \
- "The following special method can be overridden:\n" \
- "* _get_label(self): provides a default label for the symbol."
+ "The following methods have to be defined for new classes:\n" \
+ "* pychrysalide.format.BinSymbol._get_label()."
/* Récupération des paramètres */
@@ -892,6 +901,7 @@ static int py_binary_symbol_set_label(PyObject *self, PyObject *value, void *clo
PyTypeObject *get_python_binary_symbol_type(void)
{
static PyMethodDef binary_symbol_methods[] = {
+ BINARY_SYMBOL_GET_LABEL_WRAPPER,
BINARY_SYMBOL_SET_FLAG_METHOD,
BINARY_SYMBOL_UNSET_FLAG_METHOD,
BINARY_SYMBOL_HAS_FLAG_METHOD,
diff --git a/plugins/pychrysalide/plugin.c b/plugins/pychrysalide/plugin.c
index 1736826..0d24f8c 100644
--- a/plugins/pychrysalide/plugin.c
+++ b/plugins/pychrysalide/plugin.c
@@ -37,8 +37,10 @@
#include "access.h"
+#include "constants.h"
#include "helpers.h"
#include "pychrysa.h"
+#include "core/constants.h"
@@ -54,9 +56,6 @@ static void py_plugin_module_init_gclass(GPluginModuleClass *, gpointer);
/* Initialise une instance sur la base du dérivé de GObject. */
static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds);
-/* Valide les fonctionnalités déclarées en actions. */
-static bool py_plugin_module_check_interface(PyObject *);
-
/* Accompagne la fin du chargement des modules natifs. */
static void py_plugin_module_notify_native_loaded_wrapper(GPluginModule *, PluginAction);
@@ -125,9 +124,6 @@ static void g_python_plugin_finalize(GPythonPlugin *);
/* Affiche un message dans le journal des messages système. */
static PyObject *py_plugin_module_log_message(PyObject *, PyObject *);
-/* Définit les constantes pour les greffons en Python. */
-static bool py_plugin_module_define_constants(PyTypeObject *);
-
/* ---------------------------------------------------------------------------------- */
@@ -250,24 +246,42 @@ static void py_plugin_module_init_gclass(GPluginModuleClass *class, gpointer unu
static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- const char *name; /* Désignation humaine courte */
- const char *desc; /* Description plus loquace */
- const char *version; /* Version du greffon */
- PyObject *actions_obj; /* Liste des actions offertes */
- int ret; /* Bilan de lecture des args. */
PyObject *new_kwds; /* Nouveau dictionnaire épuré */
+ int ret; /* Bilan d'un appel */
GPluginModule *plugin; /* Greffon à manipuler */
plugin_interface *iface; /* Interface à constituer */
+ PyObject *value; /* Valeur à présence imposée */
size_t i; /* Boucle de parcours */
PyObject *action; /* Identifiant d'une action */
- static char *kwlist[] = { "name", "desc", "version", "actions", NULL };
-
- /* Récupération des paramètres */
-
- ret = PyArg_ParseTupleAndKeywords(args, kwds, "sssO!", kwlist,
- &name, &desc, &version, &PyTuple_Type, &actions_obj);
- if (!ret) return -1;
+#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._notify_native_loaded();\n" \
+ "* pychrysalide.PluginModule._include_theme();\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 */
@@ -283,12 +297,34 @@ static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds)
plugin = G_PLUGIN_MODULE(pygobject_get(self));
- iface = malloc(sizeof(plugin_interface));
+ iface = calloc(1, sizeof(plugin_interface));
plugin->interface = iface;
- iface->name = strdup(name);
- iface->desc = strdup(desc);
- iface->version = strdup(version);
+#define LOAD_PYTHON_IFACE(attr) \
+ do \
+ { \
+ if (PyObject_HasAttrString(self, "_" #attr)) \
+ { \
+ value = PyObject_GetAttrString(self, "_" #attr); \
+ if (value != NULL) \
+ { \
+ if (PyUnicode_Check(value)) \
+ iface->attr = strdup(PyUnicode_AsUTF8(value)); \
+ Py_DECREF(value); \
+ } \
+ } \
+ if (iface->attr == NULL) \
+ { \
+ PyErr_SetString(PyExc_TypeError, _("A '_" #attr "' class attributes is missing.")); \
+ return -1; \
+ } \
+ } \
+ while (0);
+
+ LOAD_PYTHON_IFACE(name);
+ LOAD_PYTHON_IFACE(desc);
+ LOAD_PYTHON_IFACE(version);
+ LOAD_PYTHON_IFACE(url);
iface->container = false;
@@ -296,12 +332,21 @@ static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds)
iface->required[0] = "PyChrysalide";
iface->required_count = 1;
- iface->actions_count = PyTuple_Size(actions_obj);
+ if (PyObject_HasAttrString(self, "_actions"))
+ value = PyObject_GetAttrString(self, "_actions");
+
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, _("A '_actions' class attributes is missing."));
+ 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(actions_obj, i);
+ action = PyTuple_GetItem(value, i);
if (!PyLong_Check(action))
{
@@ -313,12 +358,6 @@ static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds)
}
- if (!py_plugin_module_check_interface(self))
- {
- PyErr_SetString(PyExc_TypeError, _("missing features for the declared actions."));
- return -1;
- }
-
return 0;
}
@@ -326,184 +365,158 @@ static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds)
/******************************************************************************
* *
-* Paramètres : self = greffon Python en cours d'initialisation. *
+* Paramètres : plugin = greffon à manipuler. *
+* action = type d'action attendue. *
+* unused = variable non utilisé pour l'usage de __VA_ARGS__. *
* *
-* Description : Valide les fonctionnalités déclarées en actions. *
+* Description : Accompagne la fin du chargement des modules natifs. *
* *
-* Retour : true si le greffon Python est à priori utilisable. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool py_plugin_module_check_interface(PyObject *self)
+static void py_plugin_module_notify_native_loaded_wrapper(GPluginModule *plugin, PluginAction action)
{
- bool result; /* Bilan à retourner */
- GPluginModule *plugin; /* Greffon à manipuler */
- size_t i; /* Boucle de parcours */
- uint32_t action; /* Identifiant d'une action */
- uint32_t category; /* Catégorie principale */
- uint32_t sub; /* Sous-catégorie visée */
+ 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_NATIVE_LOADED_WRAPPER PYTHON_WRAPPER_DEF \
+( \
+ _notify_native_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 action such as" \
+ " *NATIVE_LOADED*." \
+)
- result = true;
+ gstate = PyGILState_Ensure();
- plugin = G_PLUGIN_MODULE(pygobject_get(self));
+ pyobj = pygobject_new(G_OBJECT(plugin));
- for (i = 0; i < plugin->interface->actions_count && result; i++)
+ if (has_python_method(pyobj, "_notify_native_loaded"))
{
- action = plugin->interface->actions[i];
- category = MASK_PLUGIN_CATEGORY(action);
- sub = MASK_PLUGIN_SUB_CATEGORY(action);
-
- switch (category)
- {
- case DPC_BASIC:
+ args = PyTuple_New(1);
- switch (sub)
- {
- case DPS_NONE:
- break;
-
- case PGA_PLUGIN_INIT:
- result = has_python_method(self, "init");
- break;
-
- case PGA_PLUGIN_EXIT:
- result = has_python_method(self, "exit");
- break;
+ PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
- default:
- log_variadic_message(LMT_WARNING,
- _("Unknown sub-category '0x%02x' in plugin '%s'..."),
- sub, self->ob_type->tp_name);
- break;
+ pyret = run_python_method(pyobj, "_notify_native_loaded", args);
- }
+ Py_XDECREF(pyret);
+ Py_DECREF(args);
- break;
+ }
- case DPC_BINARY_PROCESSING:
+ Py_DECREF(pyobj);
- switch (sub)
- {
- case DPS_CONTENT:
+ PyGILState_Release(gstate);
- switch (action)
- {
- case PGA_CONTENT_EXPLORER:
- result = has_python_method(self, "handle_binary_content");
- break;
+}
- case PGA_CONTENT_RESOLVER:
- result = has_python_method(self, "handle_loaded_content");
- break;
- default:
- log_variadic_message(LMT_WARNING,
- _("Unknown action '0x%02x' in plugin '%s'..."),
- action, self->ob_type->tp_name);
- break;
+/******************************************************************************
+* *
+* 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*." \
+)
- break;
+ gstate = PyGILState_Ensure();
- case DPS_FORMAT:
+ pyobj = pygobject_new(G_OBJECT(plugin));
- switch (action)
- {
- case PGA_FORMAT_ANALYSIS_STARTED:
- case PGA_FORMAT_ANALYSIS_ENDED:
- case PGA_FORMAT_POST_ANALYSIS_STARTED:
- case PGA_FORMAT_POST_ANALYSIS_ENDED:
- result = has_python_method(self, "handle_format_analysis");
- break;
+ if (has_python_method(pyobj, "_include_theme"))
+ {
+ args = PyTuple_New(2);
- case PGA_FORMAT_PRELOAD:
- result = has_python_method(self, "preload_format");
- break;
+ darkness = (dark ? Py_True : Py_False);
+ Py_INCREF(darkness);
- case PGA_FORMAT_ATTACH_DEBUG:
- result = has_python_method(self, "attach_debug_format");
- break;
+ PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
+ PyTuple_SetItem(args, 1, darkness);
- default:
- log_variadic_message(LMT_WARNING,
- _("Unknown action '0x%02x' in plugin '%s'..."),
- action, self->ob_type->tp_name);
- break;
+ 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"));
- break;
+ else
+ {
+ length = PySequence_Length(pyret);
- case DPS_DISASSEMBLY:
- result = has_python_method(self, "process_disassembly");
- break;
+ for (i = 0; i < length; i++)
+ {
+ res = PySequence_GetItem(pyret, i);
- default:
- log_variadic_message(LMT_WARNING,
- _("Unknown sub-category '0x%02x' in plugin '%s'..."),
- sub, self->ob_type->tp_name);
- break;
+ 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));
}
- break;
+ Py_DECREF(res);
- default:
- log_variadic_message(LMT_WARNING,
- _("Unknown category '0x%02x' in plugin '%s'..."),
- category, self->ob_type->tp_name);
- break;
+ }
}
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : plugin = greffon à manipuler. *
-* action = type d'action attendue. *
-* unused = variable non utilisé pour l'usage de __VA_ARGS__. *
-* *
-* Description : Accompagne la fin du chargement des modules natifs. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void py_plugin_module_notify_native_loaded_wrapper(GPluginModule *plugin, PluginAction action)
-{
-
-}
+ Py_XDECREF(pyret);
+ Py_DECREF(args);
+ }
-/******************************************************************************
-* *
-* 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 : - *
-* *
-******************************************************************************/
+ Py_DECREF(pyobj);
-static void py_plugin_module_include_theme_wrapper(const GPluginModule *plugin, PluginAction action, gboolean dark, char ***resources, size_t *count)
-{
+ PyGILState_Release(gstate);
}
@@ -529,25 +542,47 @@ static void py_plugin_module_handle_binary_content_wrapper(const GPluginModule *
PyGILState_STATE gstate; /* Sauvegarde d'environnement */
PyObject *pyobj; /* Objet Python concerné */
PyObject *args; /* Arguments pour l'appel */
- PyObject *value; /* Valeurs obtenues */
+ 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));
- assert(has_python_method(pyobj, "handle_binary_content"));
+ if (has_python_method(pyobj, "_handle_binary_content"))
+ {
+ args = PyTuple_New(4);
- 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)));
- 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);
- value = run_python_method(pyobj, "handle_binary_content", args);
+ Py_XDECREF(pyret);
+ Py_DECREF(args);
- Py_XDECREF(value);
- Py_DECREF(args);
+ }
Py_DECREF(pyobj);
@@ -561,7 +596,7 @@ static void py_plugin_module_handle_binary_content_wrapper(const GPluginModule *
* Paramètres : plugin = greffon à manipuler. *
* action = type d'action attendue. *
* content = contenu chargé à traiter. *
-* wid = identifiant du groupe de traitement. *
+* gid = identifiant du groupe de traitement. *
* status = barre de statut à tenir informée. *
* *
* Description : Procède à une opération liée à un contenu chargé. *
@@ -572,30 +607,49 @@ static void py_plugin_module_handle_binary_content_wrapper(const GPluginModule *
* *
******************************************************************************/
-static void py_plugin_module_handle_loaded_content_wrapper(const GPluginModule *plugin, PluginAction action, GLoadedContent *content, wgroup_id_t wid, GtkStatusStack *status)
+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 *value; /* Valeurs obtenues */
+ 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));
- assert(has_python_method(pyobj, "handle_loaded_content"));
+ if (has_python_method(pyobj, "_handle_loaded_content"))
+ {
+ args = PyTuple_New(4);
- 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)));
- 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_loaded_content", args);
- value = run_python_method(pyobj, "handle_loaded_content", args);
+ Py_XDECREF(pyret);
+ Py_DECREF(args);
- Py_XDECREF(value);
- Py_DECREF(args);
+ }
Py_DECREF(pyobj);
@@ -625,25 +679,47 @@ static bool py_plugin_module_handle_binary_format_analysis_wrapper(const GPlugin
PyGILState_STATE gstate; /* Sauvegarde d'environnement */
PyObject *pyobj; /* Objet Python concerné */
PyObject *args; /* Arguments pour l'appel */
- PyObject *value; /* Valeurs obtenues */
+ 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.BinFormat" \
+ " 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*." \
+)
gstate = PyGILState_Ensure();
pyobj = pygobject_new(G_OBJECT(plugin));
- assert(has_python_method(pyobj, "handle_format_analysis"));
+ if (has_python_method(pyobj, "_handle_format_analysis"))
+ {
+ args = PyTuple_New(4);
- 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)));
- 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);
- value = run_python_method(pyobj, "handle_format_analysis", args);
+ Py_XDECREF(pyret);
+ Py_DECREF(args);
- Py_XDECREF(value);
- Py_DECREF(args);
+ }
Py_DECREF(pyobj);
@@ -675,25 +751,48 @@ static bool py_plugin_module_preload_binary_format_wrapper(const GPluginModule *
PyGILState_STATE gstate; /* Sauvegarde d'environnement */
PyObject *pyobj; /* Objet Python concerné */
PyObject *args; /* Arguments pour l'appel */
- PyObject *value; /* Valeurs obtenues */
+ 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));
- assert(has_python_method(pyobj, "preload_format"));
+ if (has_python_method(pyobj, "_preload_format"))
+ {
+ args = PyTuple_New(4);
- 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)));
- 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);
- value = run_python_method(pyobj, "preload_format", args);
+ Py_XDECREF(pyret);
+ Py_DECREF(args);
- Py_XDECREF(value);
- Py_DECREF(args);
+ }
Py_DECREF(pyobj);
@@ -723,23 +822,38 @@ static void py_plugin_module_attach_debug_format_wrapper(const GPluginModule *pl
PyGILState_STATE gstate; /* Sauvegarde d'environnement */
PyObject *pyobj; /* Objet Python concerné */
PyObject *args; /* Arguments pour l'appel */
- PyObject *value; /* Valeurs obtenues */
+ 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));
- assert(has_python_method(pyobj, "attach_debug_format"));
+ if (has_python_method(pyobj, "_attach_debug_format"))
+ {
+ args = PyTuple_New(2);
- args = PyTuple_New(2);
+ PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
+ PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(format)));
- 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);
- value = run_python_method(pyobj, "attach_debug_format", args);
+ Py_XDECREF(pyret);
+ Py_DECREF(args);
- Py_XDECREF(value);
- Py_DECREF(args);
+ }
Py_DECREF(pyobj);
@@ -769,25 +883,43 @@ static void py_plugin_module_process_disassembly_event_wrapper(const GPluginModu
PyGILState_STATE gstate; /* Sauvegarde d'environnement */
PyObject *pyobj; /* Objet Python concerné */
PyObject *args; /* Arguments pour l'appel */
- PyObject *value; /* Valeurs obtenues */
+ 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));
- assert(has_python_method(pyobj, "process_disassembly"));
+ if (has_python_method(pyobj, "_process_disassembly_event"))
+ {
+ args = PyTuple_New(4);
- 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)));
- 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);
- value = run_python_method(pyobj, "process_disassembly", args);
+ Py_XDECREF(pyret);
+ Py_DECREF(args);
- Py_XDECREF(value);
- Py_DECREF(args);
+ }
Py_DECREF(pyobj);
@@ -815,6 +947,85 @@ static void py_plugin_module_process_disassembly_event_wrapper(const GPluginModu
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);
}
@@ -941,12 +1152,15 @@ static void g_python_plugin_finalize(GPythonPlugin *plugin)
if (final != NULL)
{
- free(final->name);
- free(final->desc);
- free(final->version);
+ 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);
- assert(final->required_count == 1);
- free(final->required);
+ if (final->required != NULL)
+ free(final->required);
if (final->actions != NULL)
free(final->actions);
@@ -1059,86 +1273,31 @@ GPluginModule *g_python_plugin_new(const char *modname, const char *filename)
static PyObject *py_plugin_module_log_message(PyObject *self, PyObject *args)
{
PyObject *result; /* Bilan à retourner */
- unsigned long type; /* Espèce du message */
+ LogMessageType type; /* Espèce du message */
const char *msg; /* Contenu du message */
- if (!PyArg_ParseTuple(args, "ks", &type, &msg))
+#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;
- switch (type)
- {
- case LMT_INFO:
- case LMT_PROCESS:
- case LMT_WARNING:
- case LMT_BAD_BINARY:
- case LMT_ERROR:
- case LMT_EXT_ERROR:
- g_plugin_module_log_simple_message(G_PLUGIN_MODULE(pygobject_get(self)), type, msg);
- result = Py_None;
- Py_INCREF(result);
- break;
-
- default:
- PyErr_SetString(PyExc_ValueError,
- _("Invalid type of message"));
- result = NULL;
- break;
+ g_plugin_module_log_simple_message(G_PLUGIN_MODULE(pygobject_get(self)), type, msg);
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : obj_type = type dont le dictionnaire est à compléter. *
-* *
-* Description : Définit les constantes pour les greffons en Python. *
-* *
-* Retour : true en cas de succès de l'opération, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static bool py_plugin_module_define_constants(PyTypeObject *obj_type)
-{
- bool result; /* Bilan à retourner */
-
- result = true;
-
- result &= PyDict_AddULongMacro(obj_type, PGA_BASIC_NONE);
-
- result &= PyDict_AddULongMacro(obj_type, PGA_PLUGIN_INIT);
- result &= PyDict_AddULongMacro(obj_type, PGA_PLUGIN_EXIT);
-
- result &= PyDict_AddULongMacro(obj_type, PGA_NATIVE_LOADED);
-
- result &= PyDict_AddULongMacro(obj_type, PGA_CONTENT_EXPLORER);
- result &= PyDict_AddULongMacro(obj_type, PGA_CONTENT_RESOLVER);
- result &= PyDict_AddULongMacro(obj_type, PGA_CONTENT_ANALYZED);
-
- result &= PyDict_AddULongMacro(obj_type, PGA_FORMAT_ANALYSIS_STARTED);
- result &= PyDict_AddULongMacro(obj_type, PGA_FORMAT_PRELOAD);
- result &= PyDict_AddULongMacro(obj_type, PGA_FORMAT_ATTACH_DEBUG);
- result &= PyDict_AddULongMacro(obj_type, PGA_FORMAT_ANALYSIS_ENDED);
- result &= PyDict_AddULongMacro(obj_type, PGA_FORMAT_POST_ANALYSIS_STARTED);
- result &= PyDict_AddULongMacro(obj_type, PGA_FORMAT_POST_ANALYSIS_ENDED);
-
- result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_STARTED);
- result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_RAW);
- result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_HOOKED_LINK);
- result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_HOOKED_POST);
- result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_LIMITED);
- result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_LOOPS);
- result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_LINKED);
- result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_GROUPED);
- result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_RANKED);
- result &= PyDict_AddULongMacro(obj_type, PGA_DISASSEMBLY_ENDED);
-
- result &= PyDict_AddULongMacro(obj_type, PGA_DETECTION_OBFUSCATORS);
+ result = Py_None;
+ Py_INCREF(result);
return result;
@@ -1160,11 +1319,16 @@ static bool py_plugin_module_define_constants(PyTypeObject *obj_type)
PyTypeObject *get_python_plugin_module_type(void)
{
static PyMethodDef py_plugin_module_methods[] = {
- {
- "log_message", py_plugin_module_log_message,
- METH_VARARGS,
- "log_message(type, msg, /)\n--\n\nDisplay a message in the log window, if any."
- },
+ PLUGIN_MODULE_NOTIFY_NATIVE_LOADED_WRAPPER,
+ PLUGIN_MODULE_INCLUDE_THEME_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_LOG_MESSAGE_METHOD,
{ NULL }
};
@@ -1181,7 +1345,7 @@ PyTypeObject *get_python_plugin_module_type(void)
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
- .tp_doc = "Chrysalide plugin for Python.",
+ .tp_doc = PLUGIN_MODULE_DOC,
.tp_methods = py_plugin_module_methods,
.tp_getset = py_plugin_module_getseters,
@@ -1225,7 +1389,7 @@ bool ensure_python_plugin_module_is_registered(void)
if (!register_class_for_pygobject(dict, G_TYPE_PYTHON_PLUGIN, type, &PyGObject_Type))
return false;
- if (!py_plugin_module_define_constants(type))
+ if (!define_plugin_module_constants(type))
return false;
}
diff --git a/plugins/pychrysalide/pychrysa.c b/plugins/pychrysalide/pychrysa.c
index 333544a..df6cc9a 100644
--- a/plugins/pychrysalide/pychrysa.c
+++ b/plugins/pychrysalide/pychrysa.c
@@ -428,7 +428,7 @@ static bool add_plugin_module_to_python_module(PyObject *super)
"PyChrysalide is a module containing Chrysalide's features and designed for Python users.\n" \
"\n" \
"The whole API is defined in a single library named 'pychrysalide.so' and can be used in two ways:\n" \
- "* either from the Chrysalide's GUI, by registering hooks or GLib signals,\n" \
+ "* either from the Chrysalide's GUI, by registering hooks or GLib signals;\n" \
"* or from a shell command line, by setting PYTHONPATH to point to the directory containing the library.\n" \
"\n" \
"In both cases, this is a good start point to have a look at already existing plugins to quickly learn " \
diff --git a/plugins/python/abackup/plugin.py b/plugins/python/abackup/plugin.py
index d8f52b1..aea9a9c 100644
--- a/plugins/python/abackup/plugin.py
+++ b/plugins/python/abackup/plugin.py
@@ -34,27 +34,18 @@ from .password import PasswordReader
class AndroidBackupPlugin(PluginModule):
"""Open and process Android backup files."""
+ _name = 'AndroidBackup'
+ _desc = 'Add suppport for the Android backup file format'
+ _version = '0.1'
+ _url = 'https://www.chrysalide.re/'
- def __init__(self):
- """Initialize the plugin for Chrysalide."""
+ _actions = ( PluginModule.PluginAction.CONTENT_EXPLORER, )
- interface = {
- 'name' : 'AndroidBackup',
- 'desc' : 'Add suppport for the Android backup file format',
- 'version' : '0.1',
-
- 'actions' : ( PluginModule.PGA_CONTENT_EXPLORER, )
-
- }
-
- super(AndroidBackupPlugin, self).__init__(**interface)
-
-
- def handle_binary_content(self, action, content, wid, status):
+ def _handle_binary_content(self, action, content, wid, status):
"""Process an operation on a binary content."""
- assert(action == PluginModule.PGA_CONTENT_EXPLORER)
+ assert(action == PluginModule.PluginAction.CONTENT_EXPLORER)
try:
backup = AndroidBackup(content)
diff --git a/plugins/python/apkfiles/apkfiles.py b/plugins/python/apkfiles/apkfiles.py
index 47dfac4..98d31c7 100644
--- a/plugins/python/apkfiles/apkfiles.py
+++ b/plugins/python/apkfiles/apkfiles.py
@@ -12,27 +12,18 @@ import zipfile
class ApkFiles(PluginModule):
"""Open and process APK files."""
+ _name = 'ApkFiles'
+ _desc = 'Add suppport for the APK file format'
+ _version = '0.1'
+ _url = 'https://www.chrysalide.re/'
- def __init__(self):
- """Initialize the plugin for Chrysalide."""
+ _actions = ( PluginModule.PluginAction.CONTENT_EXPLORER, )
- interface = {
- 'name' : 'ApkFiles',
- 'desc' : 'Add suppport for the APK file format',
- 'version' : '0.1',
-
- 'actions' : ( PluginModule.PGA_CONTENT_EXPLORER, )
-
- }
-
- super(ApkFiles, self).__init__(**interface)
-
-
- def handle_binary_content(self, action, content, wid, status):
+ def _handle_binary_content(self, action, content, wid, status):
"""Process an operation on a binary content."""
- assert(action == PluginModule.PGA_CONTENT_EXPLORER)
+ assert(action == PluginModule.PluginAction.CONTENT_EXPLORER)
pseudo_file = io.BytesIO(content.data)
diff --git a/plugins/python/checksec/plugin.py b/plugins/python/checksec/plugin.py
index f1229bb..6ab213f 100644
--- a/plugins/python/checksec/plugin.py
+++ b/plugins/python/checksec/plugin.py
@@ -10,24 +10,15 @@ from pychrysalide.format.elf import ElfFormat
class CheckSec(PluginModule):
"""Check for Elf mititgations."""
+ _name = 'CheckSec'
+ _desc = 'Output the exploit mitigations compiled with a loaded binary'
+ _version = '0.1'
+ _url = 'https://www.chrysalide.re/'
- def __init__(self):
- """Initialize the plugin for Chrysalide."""
+ _actions = ( PluginModule.PluginAction.FORMAT_POST_ANALYSIS_ENDED, )
- interface = {
- 'name' : 'CheckSec',
- 'desc' : 'Output the exploit mitigations compiled with a loaded binary',
- 'version' : '0.1',
-
- 'actions' : ( PluginModule.PGA_FORMAT_POST_ANALYSIS_ENDED, )
-
- }
-
- super(CheckSec, self).__init__(**interface)
-
-
- def handle_format_analysis(self, action, format, gid, status):
+ def _handle_format_analysis(self, action, format, gid, status):
"""Get notified at the end of format analysis."""
if type(format) == ElfFormat:
diff --git a/plugins/python/liveconv/plugin.py b/plugins/python/liveconv/plugin.py
index a1a182e..eadbea0 100644
--- a/plugins/python/liveconv/plugin.py
+++ b/plugins/python/liveconv/plugin.py
@@ -8,21 +8,18 @@ from .panel import ConvPanel
class LiveConverter(PluginModule):
"""Convert raw values into interpreted values."""
+ _name = 'LiveConverter'
+ _desc = 'Convert raw values into interprered values'
+ _version = '0.1'
+ _url = 'https://www.chrysalide.re/'
- def __init__(self):
- """Initialize the plugin for Chrysalide."""
-
- interface = {
+ _actions = ( )
- 'name' : 'LiveConverter',
- 'desc' : 'Convert raw values into interprered values',
- 'version' : '0.1',
- 'actions' : ( )
-
- }
+ def __init__(self):
+ """Initialize the plugin for Chrysalide."""
- super(LiveConverter, self).__init__(**interface)
+ super(LiveConverter, self).__init__()
p = ConvPanel()
diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c
index 674b1a8..dc8fc59 100644
--- a/src/plugins/plugin.c
+++ b/src/plugins/plugin.c
@@ -424,7 +424,7 @@ GPluginModule *g_plugin_module_new(const gchar *filename)
break;
case DPS_DISASSEMBLY:
- valid = check_plugin_symbol(module, "chrysalide_plugin_process_binary_disassembly");
+ valid = check_plugin_symbol(module, "chrysalide_plugin_process_disassembly_event");
break;
case DPS_DETECTION:
@@ -684,7 +684,7 @@ static void g_plugin_module_init_gclass(GPluginModuleClass *class, GModule *modu
break;
case DPS_DISASSEMBLY:
- load_plugin_symbol(module, "chrysalide_plugin_process_binary_disassembly", &class->process_disass);
+ load_plugin_symbol(module, "chrysalide_plugin_process_disassembly_event", &class->process_disass);
break;
case DPS_DETECTION:
@@ -1130,7 +1130,7 @@ void g_plugin_module_handle_binary_content(const GPluginModule *plugin, PluginAc
* Paramètres : plugin = greffon à manipuler. *
* action = type d'action attendue. *
* content = contenu chargé à traiter. *
-* wid = identifiant du groupe de traitement. *
+* gid = identifiant du groupe de traitement. *
* status = barre de statut à tenir informée. *
* *
* Description : Procède à une opération liée à un contenu chargé. *
@@ -1141,13 +1141,13 @@ void g_plugin_module_handle_binary_content(const GPluginModule *plugin, PluginAc
* *
******************************************************************************/
-void g_plugin_module_handle_loaded_content(const GPluginModule *plugin, PluginAction action, GLoadedContent *content, wgroup_id_t wid, GtkStatusStack *status)
+void g_plugin_module_handle_loaded_content(const GPluginModule *plugin, PluginAction action, GLoadedContent *content, wgroup_id_t gid, GtkStatusStack *status)
{
GPluginModuleClass *class; /* Classe de l'instance active */
class = G_PLUGIN_MODULE_GET_CLASS(plugin);
- return class->handle_loaded(plugin, action, content, wid, status);
+ return class->handle_loaded(plugin, action, content, gid, status);
}