diff options
Diffstat (limited to 'plugins/kaitai/rost/browser.c')
-rw-r--r-- | plugins/kaitai/rost/browser.c | 474 |
1 files changed, 474 insertions, 0 deletions
diff --git a/plugins/kaitai/rost/browser.c b/plugins/kaitai/rost/browser.c new file mode 100644 index 0000000..075c5ff --- /dev/null +++ b/plugins/kaitai/rost/browser.c @@ -0,0 +1,474 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * browser.c - accès à des définitions Kaitai depuis ROST + * + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + + +#include "browser.h" + + +#include <assert.h> +#include <string.h> + + +#include <analysis/scan/exprs/literal.h> + + +#include "browser-int.h" +#include "../records/item.h" +#include "../records/list.h" +#include "../records/value.h" + + + +/* ---------------------- PARCOURS DE CORRESPONDANCES ETABLIES ---------------------- */ + + +/* Initialise la classe des parcours de correspondances Kaitai. */ +static void g_kaitai_browser_class_init(GKaitaiBrowserClass *); + +/* Initialise un parcours de correspondances Kaitai. */ +static void g_kaitai_browser_init(GKaitaiBrowser *); + +/* Supprime toutes les références externes. */ +static void g_kaitai_browser_dispose(GKaitaiBrowser *); + +/* Procède à la libération totale de la mémoire. */ +static void g_kaitai_browser_finalize(GKaitaiBrowser *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Indique le nom associé à une expression d'évaluation. */ +static char *g_kaitai_browser_get_name(const GKaitaiBrowser *); + +/* Lance une résolution d'élément à solliciter. */ +static bool g_kaitai_browser_resolve(GKaitaiBrowser *, const char *, GScanContext *, GScanScope *, GScanRegisteredItem **); + +/* Réduit une expression à une forme plus simple. */ +static bool g_kaitai_browser_reduce(GKaitaiBrowser *, GScanContext *, GScanScope *, GScanExpression **); + +/* Effectue une extraction d'élément à partir d'une série. */ +static GObject *g_kaitai_browser_extract_at(GKaitaiBrowser *, const GScanExpression *, GScanContext *, GScanScope *); + + + +/* ---------------------------------------------------------------------------------- */ +/* PARCOURS DE CORRESPONDANCES ETABLIES */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un parcours de correspondances Kaitai pour ROST. */ +G_DEFINE_TYPE(GKaitaiBrowser, g_kaitai_browser, G_TYPE_SCAN_REGISTERED_ITEM); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des parcours de correspondances Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_browser_class_init(GKaitaiBrowserClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanRegisteredItemClass *registered; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_browser_dispose; + object->finalize = (GObjectFinalizeFunc)g_kaitai_browser_finalize; + + registered = G_SCAN_REGISTERED_ITEM_CLASS(klass); + + registered->get_name = (get_registered_item_name_fc)g_kaitai_browser_get_name; + registered->resolve = (resolve_registered_item_fc)g_kaitai_browser_resolve; + registered->reduce = (reduce_registered_item_fc)g_kaitai_browser_reduce; + registered->extract = (extract_registered_item_at)g_kaitai_browser_extract_at; + +} + + +/****************************************************************************** +* * +* Paramètres : browser = instance à initialiser. * +* * +* Description : Initialise un parcours de correspondances Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_browser_init(GKaitaiBrowser *browser) +{ + browser->path = NULL; + browser->record = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : browser = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_browser_dispose(GKaitaiBrowser *browser) +{ + g_clear_object(&browser->record); + + G_OBJECT_CLASS(g_kaitai_browser_parent_class)->dispose(G_OBJECT(browser)); + +} + + +/****************************************************************************** +* * +* Paramètres : browser = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_browser_finalize(GKaitaiBrowser *browser) +{ + if (browser->path != NULL) + free(browser->path); + + G_OBJECT_CLASS(g_kaitai_browser_parent_class)->finalize(G_OBJECT(browser)); + +} + + +/****************************************************************************** +* * +* Paramètres : path = chemin vers l'enregistrement fourni. * +* record = correspondance racine à considérer. * +* * +* Description : Crée un nouveau parcours de correspondances Kaitai. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiBrowser *g_kaitai_browser_new(const char *path, GMatchRecord *record) +{ + GKaitaiBrowser *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_KAITAI_BROWSER, NULL); + + if (!g_kaitai_browser_create(result, path, record)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : browser = encadrement d'un parcours de correspondances. * +* path = chemin vers l'enregistrement fourni. * +* record = correspondance racine à considérer. * +* * +* Description : Met en place un nouveau parcours de correspondances Kaitai. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_browser_create(GKaitaiBrowser *browser, const char *path, GMatchRecord *record) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (path != NULL) + browser->path = strdup(path); + + browser->record = record; + g_object_ref(G_OBJECT(browser->record)); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* * +* Description : Indique le nom associé à une expression d'évaluation. * +* * +* Retour : Désignation humaine de l'expression d'évaluation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_kaitai_browser_get_name(const GKaitaiBrowser *item) +{ + char *result; /* Désignation à retourner */ + int ret; /* Statut de construction */ + + if (item->path == NULL) + result = strdup("kaitai://"); + + else + { + ret = asprintf(&result, "kaitai://%s", item->path); + assert(ret > 0); + + if (ret <= 0) + result = strdup("kaitai://???"); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* target = désignation de l'objet d'appel à identifier. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la résolution opérée. [OUT]* +* * +* Description : Lance une résolution d'élément à solliciter. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_kaitai_browser_resolve(GKaitaiBrowser *item, const char *target, GScanContext *ctx, GScanScope *scope, GScanRegisteredItem **out) +{ + bool result; /* Bilan à retourner */ + GMatchRecord *found; /* Correspondance trouvée */ + char *path; + int ret; /* Statut de construction */ + + found = g_match_record_find_by_name(item->record, target, strlen(target), 1); + result = (found != NULL); + + if (result) + { + ret = asprintf(&path, "%s.%s", item->path, target); + assert(ret > 0); + + if (ret <= 0) + path = strdup("!?"); + + *out = G_SCAN_REGISTERED_ITEM(g_kaitai_browser_new(path, found)); + + free(path); + g_object_unref(G_OBJECT(found)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_kaitai_browser_reduce(GKaitaiBrowser *item, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + bool result; /* Bilan à retourner */ + size_t count; /* Décompte total à considérer */ + resolved_value_t value; /* Valeur brute à transformer */ + + if (G_IS_RECORD_LIST(item->record)) + { + count = g_record_list_count_records(G_RECORD_LIST(item->record)); + + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ count > 0 }); + + result = true; + + } + + else + { + if (G_IS_RECORD_ITEM(item->record)) + result = g_record_item_get_value(G_RECORD_ITEM(item->record), &value); + + else if (G_IS_RECORD_VALUE(item->record)) + result = g_record_value_compute_and_aggregate_value(G_RECORD_VALUE(item->record), &value); + + else + result = false; + + if (result) + { + switch (value.type) + { + case GVT_UNSIGNED_INTEGER: + *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, &value.unsigned_integer); + break; + + case GVT_SIGNED_INTEGER: + *out = g_scan_literal_expression_new(LVT_SIGNED_INTEGER, &value.signed_integer); + break; + + case GVT_FLOAT: + /* TODO */ + break; + + case GVT_BOOLEAN: + *out = g_scan_literal_expression_new(LVT_BOOLEAN, &value.status); + break; + + case GVT_BYTES: + *out = g_scan_literal_expression_new(LVT_STRING, &value.bytes); + break; + + default: + break; + + } + + EXIT_RESOLVED_VALUE(value); + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* index = indice de l'élément à cibler. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* * +* Description : Effectue une extraction d'élément à partir d'une série. * +* * +* Retour : Elément de série obtenu ou NULL si erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GObject *g_kaitai_browser_extract_at(GKaitaiBrowser *item, const GScanExpression *index, GScanContext *ctx, GScanScope *scope) +{ + GObject *result; /* Elément récupéré à renvoyer */ + GScanLiteralExpression *literal; /* Accès direct à l'indice */ + LiteralValueType vtype; /* Type de valeur portée */ + unsigned long long at; /* Valeur concrète du point */ + bool status; /* Bilan d'obtention d'indice */ + GRecordList *list; /* Accès direct à la liste */ + size_t count; /* Décompte total à considérer */ + GMatchRecord *found; /* Correspondance trouvée */ + char *path; + int ret; /* Statut de construction */ + + result = NULL; + + /* Validations préliminaires */ + + if (!G_IS_RECORD_LIST(item->record)) goto exit; + if (!G_IS_SCAN_LITERAL_EXPRESSION(index)) goto exit; + + literal = G_SCAN_LITERAL_EXPRESSION(index); + + vtype = g_scan_literal_expression_get_value_type(literal); + if (vtype != LVT_UNSIGNED_INTEGER) goto exit; + + status = g_scan_literal_expression_get_unsigned_integer_value(literal, &at); + if (!status) goto exit; + + list = G_RECORD_LIST(item->record); + + count = g_record_list_count_records(list); + if (at >= count) goto exit; + + /* Récupération de l'élément visé */ + + found = g_record_list_get_record(list, at); + if (found == NULL) goto exit; + + ret = asprintf(&path, "%s[%llu]", item->path, at); + assert(ret > 0); + + if (ret <= 0) + path = strdup("!?"); + + result = G_OBJECT(g_kaitai_browser_new(path, found)); + + free(path); + g_object_unref(G_OBJECT(found)); + + exit: + + return result; + +} |