/* Chrysalide - Outil d'analyse de fichiers binaires * plugin.c - interactions avec un greffon donné * * Copyright (C) 2009-2017 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "plugin.h" #include #include #include #include #include #include #include #include "plugin-int.h" #include "../core/formats.h" /* Initialise la classe des greffons. */ static void g_plugin_module_class_init(GPluginModuleClass *); /* Initialise une instance de greffon. */ static void g_plugin_module_init(GPluginModule *); /* Supprime toutes les références externes. */ static void g_plugin_module_dispose(GPluginModule *); /* Procède à la libération totale de la mémoire. */ static void g_plugin_module_finalize(GPluginModule *); /* Indique le type défini pour un greffon. */ G_DEFINE_TYPE(GPluginModule, g_plugin_module, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : class = classe à initialiser. * * * * Description : Initialise la classe des greffons. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_plugin_module_class_init(GPluginModuleClass *class) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(class); object->dispose = (GObjectFinalizeFunc/* ! */)g_plugin_module_dispose; object->finalize = (GObjectFinalizeFunc)g_plugin_module_finalize; } /****************************************************************************** * * * Paramètres : plugin = instance à initialiser. * * * * Description : Initialise une instance de greffon. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_plugin_module_init(GPluginModule *plugin) { } /****************************************************************************** * * * Paramètres : plugin = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_plugin_module_dispose(GPluginModule *plugin) { if (plugin->exit != NULL) plugin->exit(plugin, NULL /* FIXME */); if (plugin->module != NULL) g_module_close(plugin->module); G_OBJECT_CLASS(g_plugin_module_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_plugin_module_finalize(GPluginModule *plugin) { free(plugin->filename); G_OBJECT_CLASS(g_plugin_module_parent_class)->finalize(G_OBJECT(plugin)); } /****************************************************************************** * * * Paramètres : filename = nom du fichier à charger. * * ref = espace de référencement global. * * * * Description : Crée un module pour un greffon donné. * * * * Retour : Adresse de la structure mise en place. * * * * Remarques : - * * * ******************************************************************************/ GPluginModule *g_plugin_module_new(const gchar *filename, GObject *ref) { GPluginModule *result; /* Structure à retourner */ plugin_abi_version_t current; /* Version de l'ABI actuelle */ 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 */ format_match_fc matcher; /* Routine de reconnaissance */ result = g_object_new(G_TYPE_PLUGIN_MODULE, NULL); result->filename = strdup(filename); result->module = g_module_open(filename, G_MODULE_BIND_LAZY); if (result->module == NULL) { log_variadic_message(LMT_ERROR, _("Error while loading the plugin candidate '%s' : %s"), filename, g_module_error()); goto bad_plugin; } #define load_plugin_symbol(mod, sym, dest) \ ({ \ bool __result; \ if (!g_module_symbol(mod, sym, (gpointer *)dest)) \ { \ log_variadic_message(LMT_ERROR, \ _("No '%s' entry in plugin candidate '%s'"), \ sym, result->filename); \ __result = false; \ } \ else __result = true; \ __result; \ }) /* Récupération de la version d'ABI */ if (!load_plugin_symbol(result->module, "_chrysalide_plugin", &result->interface)) goto bad_plugin; current = CURRENT_ABI_VERSION; if (0 /* check_version() */) { log_variadic_message(LMT_ERROR, _("Bad version... '%s'"), filename); goto bad_plugin; } /* Localisation des différents points d'entrée déclarés */ for (i = 0; i < result->interface->actions_count; i++) { action = result->interface->actions[i]; category = MASK_PLUGIN_CATEGORY(action); sub = MASK_PLUGIN_SUB_CATEGORY(action); switch (category) { case DPC_BASIC: switch (sub) { case DPS_NONE: break; case PGA_PLUGIN_INIT: if (!load_plugin_symbol(result->module, "chrysalide_plugin_init", &result->init)) goto bad_plugin; break; case PGA_PLUGIN_EXIT: if (!load_plugin_symbol(result->module, "chrysalide_plugin_exit", &result->exit)) goto bad_plugin; break; default: log_variadic_message(LMT_WARNING, _("Unknown sub-category '0x%02x' in plugin '%s'..."), sub, filename); break; } break; case DPC_BINARY_PROCESSING: switch (sub) { case DPS_FORMAT: switch (action) { case PGA_FORMAT_MATCHER: if (!load_plugin_symbol(result->module, "is_format_matching", &matcher)) goto bad_plugin; if (!register_format_matcher(matcher, result)) goto bad_plugin; break; case PGA_FORMAT_LOADER_LAST: if (!load_plugin_symbol(result->module, "handle_binary_format", &result->handle_format)) goto bad_plugin; break; case PGA_FORMAT_PRELOAD: if (!load_plugin_symbol(result->module, "preload_binary_format", &result->preload_format)) goto bad_plugin; break; default: log_variadic_message(LMT_WARNING, _("Unknown action '0x%02x' in plugin '%s'..."), result->interface->actions[i], filename); break; } break; case DPS_DISASSEMBLY: if (!load_plugin_symbol(result->module, "process_binary_disassembly", &result->process_disass)) goto bad_plugin; break; default: log_variadic_message(LMT_WARNING, _("Unknown sub-category '0x%02x' in plugin '%s'..."), sub, filename); break; } break; default: log_variadic_message(LMT_WARNING, _("Unknown category '0x%02x' in plugin '%s'..."), category, filename); break; } } /* Conclusion */ if (!g_plugin_module_load(result, ref)) goto bad_plugin; return result; bad_plugin: g_object_unref(G_OBJECT(result)); return NULL; } /****************************************************************************** * * * Paramètres : plugin = greffon à valider. * * ref = espace de référencement global. * * * * Description : Termine le chargement du greffon préparé. * * * * Retour : Bilan du chargement effectif. * * * * Remarques : - * * * ******************************************************************************/ bool g_plugin_module_load(GPluginModule *plugin, GObject *ref) { bool result; /* Bilan à faire remonter */ char *dir; /* Répertoire modifiable */ result = true; dir = strdup(plugin->filename); dir = dirname(dir); if (plugin->init != NULL) { if (!plugin->init(plugin, ref)) { log_variadic_message(LMT_ERROR, _("Plugin '%s' failed to load itself..."), plugin->filename); result = false; } } if (result) log_variadic_message(LMT_PROCESS, _("Loaded the '%s' file as plugin from the '%s' directory"), strrchr(plugin->filename, G_DIR_SEPARATOR) + 1, dir); free(dir); return result; } /****************************************************************************** * * * Paramètres : plugin = greffon à consulter. * * * * Description : Fournit la description du greffon dans son intégralité. * * * * Retour : Interfaçage renseigné. * * * * Remarques : - * * * ******************************************************************************/ const plugin_interface *g_plugin_module_get_interface(const GPluginModule *plugin) { return plugin->interface; } /****************************************************************************** * * * Paramètres : plugin = greffon à consulter. * * msg = message à faire apparaître à l'écran. * * * * Description : Présente dans le journal un message simple. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_plugin_module_log_simple_message(const GPluginModule *plugin, LogMessageType type, const char *msg) { size_t len; /* Taille tampon disponible */ char *buffer; /* Tampon du msg reconstitué */ len = 4 + strlen(plugin->interface->name) + 6 + strlen(msg) + 1; buffer = calloc(len, sizeof(char)); strcpy(buffer, "["); strcat(buffer, plugin->interface->name); strcat(buffer, "] "); strcat(buffer, msg); log_simple_message(type, buffer); free(buffer); } /****************************************************************************** * * * Paramètres : plugin = greffon à consulter. * * type = espèce du message à ajouter. * * fmt = format du message à faire apparaître à l'écran. * * ... = éventuels arguments venant compléter le message. * * * * Description : Présente dans le journal un message complexe. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_plugin_module_log_variadic_message(const GPluginModule *plugin, LogMessageType type, const char *fmt, ...) { size_t len; /* Taille tampon disponible */ char *buffer; /* Tampon du msg reconstitué */ int ret; /* Bilan d'une impression */ char *ptr; /* Nouvelle allocation */ va_list ap; /* Liste d'arguments variable */ len = VARIADIC_LOG_BUFSIZE; buffer = calloc(len, sizeof(char)); while (buffer != NULL) { va_start(ap, fmt); ret = vsnprintf(buffer, len, fmt, ap); va_end(ap); if (ret >= 0 && ret < len) break; else { if (ret > -1) len += 1; /* glibc 2.1 */ else len *= 2; /* glibc 2.0 */ if ((ptr = realloc(buffer, len)) == NULL) { free(buffer); buffer = NULL; } else buffer = ptr; } } g_plugin_module_log_simple_message(plugin, type, buffer); free(buffer); } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * format = format de binaire à manipuler pendant l'opération. * * status = barre de statut à tenir informée. * * * * Description : Procède à une opération liée au format de fichier uniquement.* * * * Retour : Bilan de l'exécution du traitement. * * * * Remarques : - * * * ******************************************************************************/ bool g_plugin_module_handle_binary_format(const GPluginModule *plugin, PluginAction action, GBinFormat *format, GtkStatusStack *status) { return plugin->handle_format(plugin, action, format, status); } /****************************************************************************** * * * 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 : - * * * ******************************************************************************/ bool g_plugin_module_preload_binary_format(const GPluginModule *plugin, PluginAction action, GBinFormat *format, GPreloadInfo *info, GtkStatusStack *status) { return plugin->preload_format(plugin, action, format, info, status); } /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * binary = binaire dont le contenu est en cours de traitement. * * * * Description : Exécute une action pendant un désassemblage de binaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_plugin_module_process_disassembly_event(const GPluginModule *plugin, PluginAction action, GLoadedBinary *binary) { plugin->process_disass(plugin, action, binary); }