From bfd453d597d23b5c782aa8d40eb744d2ab56838e Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Mon, 1 Jul 2019 21:22:17 +0200 Subject: Introduced attributes for loaded contents. --- plugins/pychrysalide/analysis/Makefile.am | 1 + plugins/pychrysalide/analysis/cattribs.c | 376 +++++++++++++++++++++++++++ plugins/pychrysalide/analysis/cattribs.h | 45 ++++ plugins/pychrysalide/analysis/content.c | 82 ++++++ plugins/pychrysalide/analysis/module.c | 2 + plugins/pychrysalide/glibext/configuration.c | 12 +- src/analysis/Makefile.am | 1 + src/analysis/cattribs.c | 344 ++++++++++++++++++++++++ src/analysis/cattribs.h | 63 +++++ src/analysis/content-int.h | 9 + src/analysis/content.c | 60 +++++ src/analysis/content.h | 7 + src/analysis/contents/file.c | 63 +++++ src/core/params.c | 2 +- src/glibext/configuration.c | 27 +- src/glibext/configuration.h | 7 +- src/main.c | 14 +- tests/analysis/cattribs.py | 142 ++++++++++ 18 files changed, 1248 insertions(+), 9 deletions(-) create mode 100644 plugins/pychrysalide/analysis/cattribs.c create mode 100644 plugins/pychrysalide/analysis/cattribs.h create mode 100644 src/analysis/cattribs.c create mode 100644 src/analysis/cattribs.h create mode 100644 tests/analysis/cattribs.py diff --git a/plugins/pychrysalide/analysis/Makefile.am b/plugins/pychrysalide/analysis/Makefile.am index 0405243..65f2150 100644 --- a/plugins/pychrysalide/analysis/Makefile.am +++ b/plugins/pychrysalide/analysis/Makefile.am @@ -4,6 +4,7 @@ noinst_LTLIBRARIES = libpychrysaanalysis.la libpychrysaanalysis_la_SOURCES = \ binary.h binary.c \ block.h block.c \ + cattribs.h cattribs.c \ content.h content.c \ loaded.h loaded.c \ loading.h loading.c \ diff --git a/plugins/pychrysalide/analysis/cattribs.c b/plugins/pychrysalide/analysis/cattribs.c new file mode 100644 index 0000000..be5c5b1 --- /dev/null +++ b/plugins/pychrysalide/analysis/cattribs.c @@ -0,0 +1,376 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * cattribs.c - équivalent Python du fichier "analysis/cattribs.h" + * + * Copyright (C) 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 "cattribs.h" + + +#include + + +#include + + +#include + + +#include "../access.h" +#include "../helpers.h" + + + +/* Crée un nouvel objet Python de type 'ContentAttributes'. */ +static PyObject *py_content_attributes_new(PyTypeObject *, PyObject *, PyObject *); + +/* Fournit l'ensemble des clefs d'un ensemble d'attributs. */ +static PyObject *py_content_attributes_subscript(PyObject *, PyObject *); + +/* Fournit le fichier de base compris dans le chemin initial. */ +static PyObject *py_content_attributes_get_filename(PyObject *, void *); + +/* Fournit l'ensemble des clefs d'un ensemble d'attributs. */ +static PyObject *py_content_attributes_get_keys(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : type = type de l'objet à instancier. * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Crée un nouvel objet Python de type 'ContentAttributes'. * +* * +* Retour : Instance Python mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_content_attributes_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *result; /* Instance à retourner */ + const char *path; /* Chemin d'accès à traiter */ + int ret; /* Bilan de lecture des args. */ + GContentAttributes *attribs; /* Création GLib à transmettre */ + +#define CONTENT_ATTRIBUTES_DOC \ + "ContentAttributes is a set of values used at binary content loading.\n" \ + "\n" \ + "Such parameters are useful to transmit password for encrypted contents" \ + " for instance. These parameters can be accessed like dictionary items:\n" \ + "\n" \ + " password = attributes['password']\n" \ + " attributes['password'] = 'updated'\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ContentAttributes(path)\n" \ + "\n" \ + "Where path is a list of parameters: '[...]&key0=value0&key1=value1...'" + + ret = PyArg_ParseTuple(args, "s", &path); + if (!ret) return NULL; + + attribs = g_content_attributes_new(path); + + if (attribs != NULL) + { + g_object_ref_sink(G_OBJECT(attribs)); + result = pygobject_new(G_OBJECT(attribs)); + g_object_unref(attribs); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* key = clef d'accès servant d'indice. * +* * +* Description : Fournit l'ensemble des clefs d'un ensemble d'attributs. * +* * +* Retour : Valeur associée à la clef trouvée, ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_content_attributes_subscript(PyObject *self, PyObject *key) +{ + PyObject *result; /* Valeur à retourner */ + void *keyval; /* Valeur brute de la clef */ + GContentAttributes *cattribs; /* Version native */ + const char *value; /* Valeur brute trouvée */ + + result = NULL; + + if (!PyUnicode_Check(key)) + PyErr_SetString(PyExc_TypeError, "key must be a string value"); + + else + { + keyval = PyUnicode_DATA(key); + + cattribs = G_CONTENT_ATTRIBUTES(pygobject_get(self)); + + value = g_content_attributes_get_value(cattribs, keyval); + + if (value == NULL) + PyErr_SetString(PyExc_KeyError, "attribute value not found for the provided key"); + + else + result = PyUnicode_FromString(value); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit l'ensemble des clefs d'un ensemble d'attributs. * +* * +* Retour : Liste de clefs des attributes conservés dans l'ensemble. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_content_attributes_get_keys(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GContentAttributes *cattribs; /* Version native */ + size_t count; /* Nombre d'éléments à traiter */ + const char **keys; /* Clefs des attributs */ + size_t i; /* Boucle de parcours */ + +#define CONTENT_ATTRIBUTES_KEYS_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + keys, py_content_attributes, \ + "Keys of all attributes contained in a set of values." \ +) + + cattribs = G_CONTENT_ATTRIBUTES(pygobject_get(self)); + + keys = g_content_attributes_get_keys(cattribs, &count); + + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + PyTuple_SetItem(result, i, PyUnicode_FromString(keys[i])); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit le fichier de base compris dans le chemin initial. * +* * +* Retour : Nom de fichier renvoyant vers un contenu à charger ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_content_attributes_get_filename(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GContentAttributes *cattribs; /* Version native */ + const char *filename; /* Nom de fichier natif */ + +#define CONTENT_ATTRIBUTES_FILENAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + filename, py_content_attributes, \ + "Filename extracted from the path provided to the attribute set," \ + " constructor, or None if no filename was defined." \ +) + + cattribs = G_CONTENT_ATTRIBUTES(pygobject_get(self)); + + filename = g_content_attributes_get_filename(cattribs); + + if (filename != NULL) + result = PyUnicode_FromString(filename); + + else + { + result = Py_None; + Py_INCREF(result); + } + + 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_content_attributes_type(void) +{ + static PyMappingMethods py_content_attributes_mapping = { + .mp_length = NULL, + .mp_subscript = py_content_attributes_subscript, + .mp_ass_subscript = NULL + }; + + static PyMethodDef py_content_attributes_methods[] = { + { NULL } + }; + + static PyGetSetDef py_content_attributes_getseters[] = { + CONTENT_ATTRIBUTES_FILENAME_ATTRIB, + CONTENT_ATTRIBUTES_KEYS_ATTRIB, + { NULL } + }; + + static PyTypeObject py_content_attributes_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.ContentAttributes", + + .tp_as_mapping = &py_content_attributes_mapping, + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = CONTENT_ATTRIBUTES_DOC, + + .tp_methods = py_content_attributes_methods, + .tp_getset = py_content_attributes_getseters, + .tp_new = py_content_attributes_new + + }; + + return &py_content_attributes_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.....ContentAttributes'.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_content_attributes_is_registered(void) +{ + PyTypeObject *type; /* Type 'ContentAttributes' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_content_attributes_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_ATTRIBUTES, type, &PyGObject_Type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* 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 ensemble d'attributs pour contenu. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_content_attributes(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_content_attributes_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 content attributes"); + break; + + case 1: + *((GContentAttributes **)dst) = G_CONTENT_ATTRIBUTES(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/cattribs.h b/plugins/pychrysalide/analysis/cattribs.h new file mode 100644 index 0000000..b348826 --- /dev/null +++ b/plugins/pychrysalide/analysis/cattribs.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * cattribs.h - prototypes pour l'équivalent Python du fichier "analysis/cattribs.h" + * + * Copyright (C) 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 + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_CATTRIBS_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_CATTRIBS_H + + +#include +#include + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_content_attributes_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.ContentAttributes'. */ +bool ensure_python_content_attributes_is_registered(void); + +/* Tente de convertir en ensemble d'attributs pour contenu. */ +int convert_to_content_attributes(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_CATTRIBS_H */ diff --git a/plugins/pychrysalide/analysis/content.c b/plugins/pychrysalide/analysis/content.c index f332167..5f8694a 100644 --- a/plugins/pychrysalide/analysis/content.c +++ b/plugins/pychrysalide/analysis/content.c @@ -36,6 +36,7 @@ #include +#include "cattribs.h" #include "../access.h" #include "../helpers.h" #include "../arch/vmpa.h" @@ -60,6 +61,12 @@ static PyObject *py_binary_content_read_u32(PyObject *, PyObject *); /* Lit un nombre non signé sur huit octets. */ static PyObject *py_binary_content_read_u64(PyObject *, PyObject *); +/* Associe un ensemble d'attributs au contenu binaire. */ +static int py_binary_content_set_attributes(PyObject *, PyObject *, void *); + +/* Fournit l'ensemble des attributs associés à un contenu. */ +static PyObject *py_binary_content_get_attributes(PyObject *, void *); + /* Fournit une empreinte unique (SHA256) pour les données. */ static PyObject *py_binary_content_get_checksum(PyObject *, void *); @@ -348,6 +355,80 @@ static PyObject *py_binary_content_read_u64(PyObject *self, PyObject *args) /****************************************************************************** * * * Paramètres : self = contenu binaire à manipuler. * +* value = jeu d'attributs à lier au contenu courant. * +* closure = adresse non utilisée ici. * +* * +* Description : Associe un ensemble d'attributs au contenu binaire. * +* * +* Retour : Jeu d'attributs liés au contenu courant. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_binary_content_set_attributes(PyObject *self, PyObject *value, void *closure) +{ + int result; /* Bilan à renvoyer */ + GBinContent *content; /* Version GLib du format */ + GContentAttributes *attribs; /* Version native des attributs*/ + + content = G_BIN_CONTENT(pygobject_get(self)); + + if (!convert_to_content_attributes(value, &attribs)) + result = -1; + + else + { + g_binary_content_set_attributes(content, attribs); + result = 0; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = contenu binaire à manipuler. * +* closure = adresse non utilisée ici. * +* * +* Description : Fournit l'ensemble des attributs associés à un contenu. * +* * +* Retour : Jeu d'attributs liés au contenu courant. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_content_get_attributes(PyObject *self, void *closure) +{ + PyObject *result; /* Instance à retourner */ + GBinContent *content; /* Version GLib du format */ + GContentAttributes *attribs; /* Attributs à transmettre */ + +#define BINARY_CONTENT_ATTRIBUTES_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + attributes, py_binary_content, \ + "Provide or define the attributes linked to the binary content." \ +) + + content = G_BIN_CONTENT(pygobject_get(self)); + + attribs = g_binary_content_get_attributes(content); + + result = pygobject_new(G_OBJECT(attribs)); + + g_object_unref(attribs); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = contenu binaire à manipuler. * * closure = adresse non utilisée ici. * * * * Description : Fournit une empreinte unique (SHA256) pour les données. * @@ -552,6 +633,7 @@ PyTypeObject *get_python_binary_content_type(void) }; static PyGetSetDef py_binary_content_getseters[] = { + BINARY_CONTENT_ATTRIBUTES_ATTRIB, { "checksum", py_binary_content_get_checksum, NULL, "Compute a SHA256 hash as chechsum of handled data.", NULL diff --git a/plugins/pychrysalide/analysis/module.c b/plugins/pychrysalide/analysis/module.c index cf0671e..1a9a1d9 100644 --- a/plugins/pychrysalide/analysis/module.c +++ b/plugins/pychrysalide/analysis/module.c @@ -30,6 +30,7 @@ #include "binary.h" #include "block.h" +#include "cattribs.h" #include "content.h" #include "loaded.h" #include "loading.h" @@ -111,6 +112,7 @@ bool populate_analysis_module(void) if (result) result = ensure_python_loaded_binary_is_registered(); if (result) result = ensure_python_code_block_is_registered(); if (result) result = ensure_python_block_list_is_registered(); + if (result) result = ensure_python_content_attributes_is_registered(); if (result) result = ensure_python_binary_content_is_registered(); if (result) result = ensure_python_loaded_content_is_registered(); if (result) result = ensure_python_content_explorer_is_registered(); diff --git a/plugins/pychrysalide/glibext/configuration.c b/plugins/pychrysalide/glibext/configuration.c index 0fefc13..6b890a8 100644 --- a/plugins/pychrysalide/glibext/configuration.c +++ b/plugins/pychrysalide/glibext/configuration.c @@ -833,13 +833,19 @@ static PyObject *py_generic_config_new(PyTypeObject *type, PyObject *args, PyObj int ret; /* Bilan de lecture des args. */ GGenConfig *config; /* Version GLib du format */ - ret = PyArg_ParseTuple(args, "s", &name); + name = NULL; + + ret = PyArg_ParseTuple(args, "|s", &name); if (!ret) return NULL; - config = g_generic_config_new(name); + if (name == NULL) + config = g_generic_config_new(); + else + config = g_generic_config_new_from_file(name); + g_object_ref_sink(G_OBJECT(config)); result = pygobject_new(G_OBJECT(config)); - g_object_unref(config); + g_object_unref(G_OBJECT(config)); return result; diff --git a/src/analysis/Makefile.am b/src/analysis/Makefile.am index c4a66de..39b960c 100644 --- a/src/analysis/Makefile.am +++ b/src/analysis/Makefile.am @@ -5,6 +5,7 @@ libanalysis_la_SOURCES = \ binary.h binary.c \ block-int.h \ block.h block.c \ + cattribs.h cattribs.c \ content-int.h \ content.h content.c \ loaded-int.h \ diff --git a/src/analysis/cattribs.c b/src/analysis/cattribs.c new file mode 100644 index 0000000..ebebb83 --- /dev/null +++ b/src/analysis/cattribs.c @@ -0,0 +1,344 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * cattribs.c - rassemblement des attributs utiles au chargement d'un contenu binaire + * + * Copyright (C) 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 Chrysalide. If not, see . + */ + + +#include "cattribs.h" + + +#include +#include + + +#include "../glibext/configuration.h" + + + +/* Ensemble d'attributs pour contenu binaire (instance) */ +struct _GContentAttributes +{ + GObject parent; /* A laisser en premier */ + + char *filename; /* Fichier de base du chemin */ + + GGenConfig **configs; /* Paramètres par niveaux */ + size_t count; /* Quantité de ces niveaux */ + +}; + +/* Ensemble d'attributs pour contenu binaire (classe) */ +struct _GContentAttributesClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/* Initialise la classe des ensembles d'attributs pour contenus. */ +static void g_content_attributes_class_init(GContentAttributesClass *); + +/* Initialise un ensemble d'attributs pour contenu binaire. */ +static void g_content_attributes_init(GContentAttributes *); + +/* Supprime toutes les références externes. */ +static void g_content_attributes_dispose(GContentAttributes *); + +/* Procède à la libération totale de la mémoire. */ +static void g_content_attributes_finalize(GContentAttributes *); + + + +/* Indique le type défini pour un ensemble d'attributs de contenu binaire. */ +G_DEFINE_TYPE(GContentAttributes, g_content_attributes, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des ensembles d'attributs pour contenus.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_content_attributes_class_init(GContentAttributesClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_content_attributes_dispose; + object->finalize = (GObjectFinalizeFunc)g_content_attributes_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : binary = instance à initialiser. * +* * +* Description : Initialise un ensemble d'attributs pour contenu binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_content_attributes_init(GContentAttributes *attribs) +{ + attribs->filename = NULL; + + attribs->configs = malloc(sizeof(GGenConfig *)); + attribs->count = 1; + + attribs->configs[0] = g_generic_config_new(); + +} + + +/****************************************************************************** +* * +* Paramètres : attribs = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_content_attributes_dispose(GContentAttributes *attribs) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < attribs->count; i++) + g_clear_object(&attribs->configs[i]); + + G_OBJECT_CLASS(g_content_attributes_parent_class)->dispose(G_OBJECT(attribs)); + +} + + +/****************************************************************************** +* * +* Paramètres : attribs = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_content_attributes_finalize(GContentAttributes *attribs) +{ + free(attribs->configs); + + G_OBJECT_CLASS(g_content_attributes_parent_class)->finalize(G_OBJECT(attribs)); + +} + + +/****************************************************************************** +* * +* Paramètres : path = chemin d'accès à un contenu à charger. * +* * +* Description : Construit un ensemble d'attribut pour contenu binaire. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GContentAttributes *g_content_attributes_new(const char *path) +{ + GContentAttributes *result; /* Adresse à retourner */ + GGenConfig *config; /* Niveau de config. courant */ + const char *iter; /* Boucle de parcours */ + const char *next; /* Prochain marqueur rencontré */ + char *part; /* Clef et sa valeur */ + char *eq; /* Signe '=' rencontré */ + + result = g_object_new(G_TYPE_CONTENT_ATTRIBUTES, NULL); + + iter = strchr(path, '&'); + + if (iter == NULL) + result->filename = strdup(path); + + else + { + if (iter != path) + result->filename = strndup(path, iter - path); + + config = result->configs[0]; + + do + { + iter++; + + next = strchr(iter, '&'); + + if (next == NULL) + next = path + strlen(path); + + /* Présence de deux '&' consécutifs */ + if (iter == next) + { + result->configs = realloc(result->configs, ++result->count * sizeof(GGenConfig *)); + + result->configs[result->count - 1] = g_generic_config_new(); + + config = result->configs[result->count - 1]; + + } + + /* Traitement d'une nouvelle combinaison */ + else + { + part = strndup(iter, next - iter); + + eq = strchr(part, '='); + + if (eq != NULL) + { + *eq = '\0'; + + if (eq[1] != '\0') + g_generic_config_create_or_udpdate_param(config, part, CPT_STRING, NULL, eq + 1); + + } + + free(part); + + } + + iter = strchr(iter, '&'); + + } + while (iter != NULL); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attribs = ensemble d'attributs de contenu à consulter. * +* * +* Description : Fournit le fichier de base compris dans le chemin initial. * +* * +* Retour : Nom de fichier renvoyant vers un contenu à charger ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_content_attributes_get_filename(const GContentAttributes *attribs) +{ + char *result; /* Nom de fichier à retourner */ + + result = attribs->filename; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attribs = ensemble d'attributs de contenu à consulter. * +* count = taille de la liste de clefs renvoyées. [OUT] * +* * +* Description : Fournit l'ensemble des clefs d'un ensemble d'attributs. * +* * +* Retour : Liste de clefs des attributes conservés dans l'ensemble. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char **g_content_attributes_get_keys(const GContentAttributes *attribs, size_t *count) +{ + const char **result; /* Liste à retourner */ + GList *list; /* Liste de paramètres */ + GList *iter; /* Boucle de parcours */ + GCfgParam *param; /* Paramètre d'un ensemble */ + const char *key; /* Clef d'un paramètre */ + + result = NULL; + *count = 0; + + list = g_generic_config_list_params(attribs->configs[0]); + + for (iter = g_list_first(list); iter != NULL; iter = g_list_next(iter)) + { + param = G_CFG_PARAM(iter->data); + + key = g_config_param_get_path(param); + + result = realloc(result, ++(*count) * sizeof(char *)); + + result[*count - 1] = strdup(key); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attribs = ensemble d'attributs de contenu à consulter. * +* key = désignation de l'attribut visé par la procédure. * +* * +* Description : Indique la valeur d'un attribut appartenant à un ensemble. * +* * +* Retour : Valeur de l'attribut recherché, s'il a été trouvé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_content_attributes_get_value(const GContentAttributes *attribs, const char *key) +{ + const char *result; /* Trouvaille à retourner */ + bool status; + + status = g_generic_config_get_value(attribs->configs[0], key, &result); + + if (!status) + result = NULL; + + return result; + +} diff --git a/src/analysis/cattribs.h b/src/analysis/cattribs.h new file mode 100644 index 0000000..c2e8a2e --- /dev/null +++ b/src/analysis/cattribs.h @@ -0,0 +1,63 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * cattribs.h - prototypes pour le rassemblement des attributs utiles au chargement d'un contenu binaire + * + * Copyright (C) 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 Chrysalide. If not, see . + */ + + +#ifndef _ANALYSIS_CATTRIBS_H +#define _ANALYSIS_CATTRIBS_H + + +#include + + +#define G_TYPE_CONTENT_ATTRIBUTES g_content_attributes_get_type() +#define G_CONTENT_ATTRIBUTES(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_CONTENT_ATTRIBUTES, GContentAttributes)) +#define G_IS_CONTENT_ATTRIBUTES(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_CONTENT_ATTRIBUTES)) +#define G_CONTENT_ATTRIBUTES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_CONTENT_ATTRIBUTES, GContentAttributesClass)) +#define G_IS_CONTENT_ATTRIBUTES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_CONTENT_ATTRIBUTES)) +#define G_CONTENT_ATTRIBUTES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_CONTENT_ATTRIBUTES, GContentAttributesClass)) + + +/* Ensemble d'attributs pour contenu binaire (instance) */ +typedef struct _GContentAttributes GContentAttributes; + +/* Ensemble d'attributs pour contenu binaire (classe) */ +typedef struct _GContentAttributesClass GContentAttributesClass; + + +/* Indique le type défini pour un ensemble d'attributs de contenu binaire. */ +GType g_content_attributes_get_type(void); + +/* Construit un ensemble d'attribut pour contenu binaire. */ +GContentAttributes *g_content_attributes_new(const char *); + +/* Fournit le fichier de base compris dans le chemin initial. */ +const char *g_content_attributes_get_filename(const GContentAttributes *); + +/* Fournit l'ensemble des clefs d'un ensemble d'attributs. */ +const char **g_content_attributes_get_keys(const GContentAttributes *, size_t *); + +/* Indique la valeur d'un attribut appartenant à un ensemble. */ +const char *g_content_attributes_get_value(const GContentAttributes *, const char *); + + + +#endif /* _ANALYSIS_CATTRIBS_H */ diff --git a/src/analysis/content-int.h b/src/analysis/content-int.h index f3d698e..24247ed 100644 --- a/src/analysis/content-int.h +++ b/src/analysis/content-int.h @@ -29,6 +29,12 @@ +/* Associe un ensemble d'attributs au contenu binaire. */ +typedef void (* set_content_attributes) (GBinContent *, GContentAttributes *); + +/* Fournit l'ensemble des attributs associés à un contenu. */ +typedef GContentAttributes * (* get_content_attributes) (const GBinContent *); + /* Donne l'origine d'un contenu binaire. */ typedef GBinContent * (* get_content_root_fc) (GBinContent *); @@ -86,6 +92,9 @@ struct _GBinContentIface { GTypeInterface base_iface; /* A laisser en premier */ + set_content_attributes set_attribs; /* Enregistrement d'attributs */ + get_content_attributes get_attribs; /* Fourniture d'attributs */ + get_content_root_fc get_root; /* Renvoie à l'origine */ describe_content_fc describe; /* Fournit une description */ diff --git a/src/analysis/content.c b/src/analysis/content.c index dbece37..41a00bc 100644 --- a/src/analysis/content.c +++ b/src/analysis/content.c @@ -98,6 +98,66 @@ GBinContent *g_binary_content_new_from_xml(xmlXPathContextPtr context, const cha /****************************************************************************** * * +* Paramètres : content = contenu binaire à actualiser. * +* attribs = jeu d'attributs à lier au contenu courant. * +* * +* Description : Associe un ensemble d'attributs au contenu binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_binary_content_set_attributes(GBinContent *content, GContentAttributes *attribs) +{ + GContentAttributes *old; /* Ancien jeu d'attributs */ + GBinContentIface *iface; /* Interface utilisée */ + + iface = G_BIN_CONTENT_GET_IFACE(content); + + old = iface->get_attribs(content); + + if (old != NULL) + g_object_unref(G_OBJECT(old)); + + iface->set_attribs(content, attribs); + + g_object_ref_sink(G_OBJECT(attribs)); + +} + + +/****************************************************************************** +* * +* Paramètres : content = contenu binaire à consulter. * +* * +* Description : Fournit l'ensemble des attributs associés à un contenu. * +* * +* Retour : Jeu d'attributs liés au contenu courant. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GContentAttributes *g_binary_content_get_attributes(const GBinContent *content) +{ + GContentAttributes *result; /* Instance à retourner */ + GBinContentIface *iface; /* Interface utilisée */ + + iface = G_BIN_CONTENT_GET_IFACE(content); + + result = iface->get_attribs(content); + + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : content = contenu binaire à consulter. * * * * Description : Donne l'origine d'un contenu binaire. * diff --git a/src/analysis/content.h b/src/analysis/content.h index f16a164..3e12aa3 100644 --- a/src/analysis/content.h +++ b/src/analysis/content.h @@ -29,6 +29,7 @@ #include +#include "cattribs.h" #include "../arch/vmpa.h" #include "../common/endianness.h" #include "../common/leb128.h" @@ -57,6 +58,12 @@ GType g_binary_content_get_type(void) G_GNUC_CONST; /* Charge en mémoire un contenu binaire à partir d'XML. */ GBinContent *g_binary_content_new_from_xml(xmlXPathContextPtr, const char *, const char *); +/* Associe un ensemble d'attributs au contenu binaire. */ +void g_binary_content_set_attributes(GBinContent *, GContentAttributes *); + +/* Fournit l'ensemble des attributs associés à un contenu. */ +GContentAttributes *g_binary_content_get_attributes(const GBinContent *); + /* Donne l'origine d'un contenu binaire. */ GBinContent *g_binary_content_get_root(GBinContent *); diff --git a/src/analysis/contents/file.c b/src/analysis/contents/file.c index 5beb0e3..951828f 100644 --- a/src/analysis/contents/file.c +++ b/src/analysis/contents/file.c @@ -44,6 +44,8 @@ struct _GFileContent { GObject parent; /* A laisser en premier */ + GContentAttributes *attribs; /* Attributs liés au contenu */ + char *filename; /* Fichier chargé en mémoire */ bin_t *data; /* Contenu binaire représenté */ @@ -74,6 +76,12 @@ static void g_file_content_dispose(GFileContent *); /* Procède à la libération totale de la mémoire. */ static void g_file_content_finalize(GFileContent *); +/* Associe un ensemble d'attributs au contenu binaire. */ +static void g_file_content_set_attributes(GFileContent *, GContentAttributes *); + +/* Fournit l'ensemble des attributs associés à un contenu. */ +static GContentAttributes *g_file_content_get_attributes(const GFileContent *); + /* Donne l'origine d'un contenu binaire. */ static GBinContent *g_file_content_get_root(GFileContent *); @@ -170,6 +178,13 @@ static void g_file_content_class_init(GFileContentClass *klass) static void g_file_content_init(GFileContent *content) { + GContentAttributes *empty; /* Jeu d'attributs vide */ + + content->attribs = NULL; + + empty = g_content_attributes_new(""); + + g_binary_content_set_attributes(G_BIN_CONTENT(content), empty); } @@ -188,6 +203,9 @@ static void g_file_content_init(GFileContent *content) static void g_file_content_interface_init(GBinContentInterface *iface) { + iface->set_attribs = (set_content_attributes)g_file_content_set_attributes; + iface->get_attribs = (get_content_attributes)g_file_content_get_attributes; + iface->get_root = (get_content_root_fc)g_file_content_get_root; iface->describe = (describe_content_fc)g_file_content_describe; @@ -231,6 +249,8 @@ static void g_file_content_interface_init(GBinContentInterface *iface) static void g_file_content_dispose(GFileContent *content) { + g_clear_object(&content->attribs); + G_OBJECT_CLASS(g_file_content_parent_class)->dispose(G_OBJECT(content)); } @@ -385,6 +405,49 @@ GBinContent *g_file_content_new_from_xml(xmlXPathContextPtr context, const char /****************************************************************************** * * +* Paramètres : content = contenu binaire à actualiser. * +* attribs = jeu d'attributs à lier au contenu courant. * +* * +* Description : Associe un ensemble d'attributs au contenu binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_file_content_set_attributes(GFileContent *content, GContentAttributes *attribs) +{ + content->attribs = attribs; + +} + + +/****************************************************************************** +* * +* Paramètres : content = contenu binaire à consulter. * +* * +* Description : Fournit l'ensemble des attributs associés à un contenu. * +* * +* Retour : Jeu d'attributs liés au contenu courant. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GContentAttributes *g_file_content_get_attributes(const GFileContent *content) +{ + GContentAttributes *result; /* Instance à retourner */ + + result = content->attribs; + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : content = contenu binaire à consulter. * * * * Description : Donne l'origine d'un contenu binaire. * diff --git a/src/core/params.c b/src/core/params.c index 6467182..ef331e7 100644 --- a/src/core/params.c +++ b/src/core/params.c @@ -112,7 +112,7 @@ bool load_main_config_parameters(void) GCfgParam *param; /* Paramètre chargé */ char *string; /* Valeur sous forme de texte */ - config = g_generic_config_new("main"); + config = g_generic_config_new_from_file("main"); set_main_configuration(config); string = get_author_name(); diff --git a/src/glibext/configuration.c b/src/glibext/configuration.c index 8f2103d..a91ef34 100644 --- a/src/glibext/configuration.c +++ b/src/glibext/configuration.c @@ -1258,9 +1258,32 @@ static void g_generic_config_finalize(GGenConfig *config) /****************************************************************************** * * +* Paramètres : - * +* * +* Description : Crée un gestionnaire configuration générique. * +* * +* Retour : Elément mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GGenConfig *g_generic_config_new(void) +{ + GGenConfig *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_GEN_CONFIG, NULL); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : name = désignation de la configuration. * * * -* Description : Crée une description de partie de code vierge. * +* Description : Crée un gestionnaire configuration générique. * * * * Retour : Elément mis en place. * * * @@ -1268,7 +1291,7 @@ static void g_generic_config_finalize(GGenConfig *config) * * ******************************************************************************/ -GGenConfig *g_generic_config_new(const char *name) +GGenConfig *g_generic_config_new_from_file(const char *name) { GGenConfig *result; /* Structure à retourner */ char *suffix; /* Fin du nom de fichier */ diff --git a/src/glibext/configuration.h b/src/glibext/configuration.h index 0f352ea..350d6eb 100644 --- a/src/glibext/configuration.h +++ b/src/glibext/configuration.h @@ -156,8 +156,11 @@ typedef struct _GGenConfigClass GGenConfigClass; /* Indique le type défini par la GLib pour les configurations génériques. */ GType g_generic_config_get_type(void); -/* Crée une description de partie de code vierge. */ -GGenConfig *g_generic_config_new(const char *); +/* Crée un gestionnaire configuration générique. */ +GGenConfig *g_generic_config_new(void); + +/* Crée un gestionnaire configuration générique. */ +GGenConfig *g_generic_config_new_from_file(const char *); /* Indique le fichier utilisé pour l'enregistrement XML. */ const char *g_generic_config_get_filename(const GGenConfig *); diff --git a/src/main.c b/src/main.c index c2aaf56..5dc9e3c 100644 --- a/src/main.c +++ b/src/main.c @@ -491,6 +491,8 @@ static int open_binaries(char **files, int count) int result; /* Bilan à retourner */ GStudyProject *project; /* Projet courant à compléter */ int i; /* Boucle de parcours */ + GContentAttributes *attribs; /* Attributs à lier au contenu */ + const char *filename; /* Chemin d'accès au contenu */ GBinContent *content; /* Contenu binaire à charger */ result = EXIT_SUCCESS; @@ -499,16 +501,26 @@ static int open_binaries(char **files, int count) for (i = 0; i < count && result == EXIT_SUCCESS; i++) { - content = g_file_content_new(files[i]); + attribs = g_content_attributes_new(files[i]); + + filename = g_content_attributes_get_filename(attribs); + + content = g_file_content_new(filename); if (content != NULL) { + g_binary_content_set_attributes(content, attribs); + g_study_project_discover_binary_content(project, content, !is_batch_mode(), NULL, NULL); g_object_unref(G_OBJECT(content)); + } else + { + g_object_unref(G_OBJECT(attribs)); result = EXIT_FAILURE; + } } diff --git a/tests/analysis/cattribs.py b/tests/analysis/cattribs.py new file mode 100644 index 0000000..1a7f7da --- /dev/null +++ b/tests/analysis/cattribs.py @@ -0,0 +1,142 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + + +# S'assure du bon fonctionnement des attributs de contenus binaires à charger + + +from chrysacase import ChrysalideTestCase +from pychrysalide.analysis import ContentAttributes + + +class TestProjectFeatures(ChrysalideTestCase): + """TestCase for binary content attributes.""" + + def testEmptyContentAttributeSet(self): + """Check properties of empty content attribute set.""" + + attribs = ContentAttributes('') + self.assertIsNotNone(attribs) + + self.assertIsNone(attribs.filename) + + self.assertEqual(len(attribs.keys), 0) + + + def testContentAttributeSet(self): + """Check properties of a basic content attribute set.""" + + model = { + 'a': '0', + 'bb': '1', + 'ccc': '2', + 'dddd': '3', + } + + filename = 'filename' + path = filename + + for k in model.keys(): + path += '&%s=%s' % (k, model[k]) + + attribs = ContentAttributes(path) + self.assertIsNotNone(attribs) + + self.assertEqual(attribs.filename, filename) + + kcount = 0 + + for key in attribs.keys: + self.assertTrue(key in model.keys()) + kcount += 1 + + self.assertEqual(kcount, len(model.keys())) + + + def testMultiContentAttributeSet(self): + """Check properties of a multi level content attribute set.""" + + model = { + 'a': '0', + 'bb': '1', + 'ccc': '2', + 'dddd': '3', + } + + path = '' + + for k in model.keys(): + path += '&%s=%s' % (k, model[k]) + + path += '&' + + for k in model.keys(): + path += '&e%s=%s' % (k, model[k]) + + attribs = ContentAttributes(path) + self.assertIsNotNone(attribs) + + self.assertIsNone(attribs.filename) + + kcount = 0 + + for key in attribs.keys: + self.assertTrue(key in model.keys()) + kcount += 1 + + self.assertEqual(kcount, len(model.keys())) + + + def testEmptyContentAttributeSet(self): + """Check properties of empty content attribute sets.""" + + path = '&&' + + attribs = ContentAttributes(path) + self.assertIsNotNone(attribs) + + self.assertIsNone(attribs.filename) + + self.assertEqual(len(attribs.keys), 0) + + path = '&&&' + + attribs = ContentAttributes(path) + self.assertIsNotNone(attribs) + + self.assertIsNone(attribs.filename) + + self.assertEqual(len(attribs.keys), 0) + + path = 'filename' + + attribs = ContentAttributes(path) + self.assertIsNotNone(attribs) + + self.assertEqual(len(attribs.keys), 0) + + self.assertEqual(attribs.filename, path) + + + def testContentAttributesKeyAccess(self): + """Test some access keys for content attributes.""" + + model = { + 'a': '0', + } + + path = '' + + for k in model.keys(): + path += '&%s=%s' % (k, model[k]) + + attribs = ContentAttributes(path) + self.assertIsNotNone(attribs) + + with self.assertRaisesRegex(Exception, 'key must be a string value'): + + val = attribs[2] + + with self.assertRaisesRegex(Exception, 'attribute value not found for the provided key'): + + val = attribs['2'] -- cgit v0.11.2-87-g4458