/* Chrysalide - Outil d'analyse de fichiers binaires * context.c - suivi d'analyses via contextes * * Copyright (C) 2022 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 Foobar. If not, see . */ #include "context.h" #include #include #include "context-int.h" #include "exprs/literal.h" /* Initialise la classe des contextes de suivi d'analyses. */ static void g_scan_context_class_init(GScanContextClass *); /* Initialise une instance de contexte de suivi d'analyse. */ static void g_scan_context_init(GScanContext *); /* Supprime toutes les références externes. */ static void g_scan_context_dispose(GScanContext *); /* Procède à la libération totale de la mémoire. */ static void g_scan_context_finalize(GScanContext *); /* Indique le type défini pour un contexte de suivi d'analyse. */ G_DEFINE_TYPE(GScanContext, g_scan_context, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des contextes de suivi d'analyses. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_scan_context_class_init(GScanContextClass *klass) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_context_dispose; object->finalize = (GObjectFinalizeFunc)g_scan_context_finalize; } /****************************************************************************** * * * Paramètres : context = instance à initialiser. * * * * Description : Initialise une instance de contexte de suivi d'analyse. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_scan_context_init(GScanContext *context) { context->options = NULL; context->content = NULL; context->next_patid = 0; context->atom_trackers = NULL; context->full_matches = NULL; context->full_allocated = 0; context->full_used = 0; context->conditions = NULL; context->cond_count = 0; } /****************************************************************************** * * * Paramètres : context = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_scan_context_dispose(GScanContext *context) { size_t i; /* Boucle de parcours */ g_clear_object(&context->options); g_clear_object(&context->content); for (i = 0; i < context->full_used; i++) g_clear_object(&context->full_matches[i]); for (i = 0; i < context->cond_count; i++) g_clear_object(&context->conditions[i].expr); G_OBJECT_CLASS(g_scan_context_parent_class)->dispose(G_OBJECT(context)); } /****************************************************************************** * * * Paramètres : context = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_scan_context_finalize(GScanContext *context) { size_t i; /* Boucle de parcours */ atom_match_tracker_t *atracker; /* Conservateur à manipuler #1 */ if (context->atom_trackers != NULL) { for (i = 0; i < context->next_patid; i++) { atracker = context->atom_trackers + i; if (atracker->matches != NULL) free(atracker->matches); } free(context->atom_trackers); } if (context->full_matches != NULL) free(context->full_matches); if (context->conditions != NULL) { for (i = 0; i < context->cond_count; i++) free(context->conditions[i].name); free(context->conditions); } G_OBJECT_CLASS(g_scan_context_parent_class)->finalize(G_OBJECT(context)); } /****************************************************************************** * * * Paramètres : options = ensemble d'options d'analyses à respecter. * * * * Description : Définit un contexte pour suivi d'analyse. * * * * Retour : Fonction mise en place. * * * * Remarques : - * * * ******************************************************************************/ GScanContext *g_scan_context_new(GScanOptions *options) { GScanContext *result; /* Structure à retourner */ result = g_object_new(G_TYPE_SCAN_CONTEXT, NULL); result->options = options; g_object_ref(G_OBJECT(options)); return result; } /****************************************************************************** * * * Paramètres : context = instance à consulter. * * * * Description : Fournit l'ensemble des options à respecter pour les analyses.* * * * Retour : Ensemble d'options en vigueur. * * * * Remarques : - * * * ******************************************************************************/ GScanOptions *g_scan_context_get_options(GScanContext *context) { GScanOptions *result; /* Ensemble à retourner */ result = context->options; g_object_ref(G_OBJECT(result)); return result; } /****************************************************************************** * * * Paramètres : context = instance à consulter. * * * * Description : Fournit un identifiant unique pour un motif recherché. * * * * Retour : Identifiant nouveau à utiliser. * * * * Remarques : - * * * ******************************************************************************/ patid_t g_scan_context_get_new_pattern_id(GScanContext *context) { patid_t result; /* Identifiant à retourner */ result = context->next_patid++; return result; } /****************************************************************************** * * * Paramètres : context = instance à consulter. * * content = contenu binaire en cours d'analyse. * * * * Description : Définit le contenu principal à analyser. * * * * Retour : Content binaire associé au context. * * * * Remarques : - * * * ******************************************************************************/ void g_scan_context_set_content(GScanContext *context, GBinContent *content) { g_clear_object(&context->content); context->content = content; g_object_ref(G_OBJECT(content)); context->atom_trackers = calloc(context->next_patid, sizeof(atom_match_tracker_t)); } /****************************************************************************** * * * Paramètres : context = instance à consulter. * * * * Description : Fournit une référence au contenu principal analysé. * * * * Retour : Content binaire associé au context. * * * * Remarques : - * * * ******************************************************************************/ GBinContent *g_scan_context_get_content(const GScanContext *context) { GBinContent *result; /* Instance à retourner */ result = context->content; g_object_ref(G_OBJECT(result)); return result; } /****************************************************************************** * * * Paramètres : context = instance à mettre à jour. * * id = identifiant du motif trouvé. * * offset = localisation du motif au sein d'un contenu. * * * * Description : Enregistre une correspondance partielle dans un contenu. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_scan_context_register_atom_match(GScanContext *context, patid_t id, phys_t offset) { atom_match_tracker_t *tracker; /* Gestionnaire concerné */ tracker = &context->atom_trackers[id]; if (tracker->used == tracker->allocated) { tracker->allocated += ALLOCATION_STEP; tracker->matches = realloc(tracker->matches, tracker->allocated * sizeof(phys_t)); } tracker->matches[tracker->used++] = offset; } /****************************************************************************** * * * Paramètres : context = instance à mettre à jour. * * id = identifiant du motif trouvé. * * count = nombre de localisations renvoyées. [OUT] * * * * Description : Retourne tous les correspondances partielles notées. * * * * Retour : Liste interne des localisations conservées. * * * * Remarques : - * * * ******************************************************************************/ const phys_t *g_scan_context_get_atom_matches(const GScanContext *context, patid_t id, size_t *count) { const phys_t *result; /* Liste constituée à renvoyer */ atom_match_tracker_t *tracker; /* Gestionnaire concerné */ tracker = &context->atom_trackers[id]; result = tracker->matches; *count = tracker->used; return result; } /****************************************************************************** * * * Paramètres : context = instance à mettre à jour. * * match = représentation d'une plein ecorrespondance. * * * * Description : Enregistre une correspondance complète avec un contenu. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_scan_context_register_full_match(GScanContext *context, GScanMatch *match) { if (context->full_used == context->full_allocated) { context->full_allocated += ALLOCATION_STEP; context->full_matches = realloc(context->full_matches, context->full_allocated * sizeof(GScanMatch *)); } context->full_matches[context->full_used++] = match; g_object_ref(G_OBJECT(match)); } /****************************************************************************** * * * Paramètres : context = mémoire de résultats d'analyse à consulter. * * * * Description : Affiche les correspondances identifiées. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_scan_context_display(const GScanContext *context) { size_t i; /* Boucle de parcours */ for (i = 0; i < context->full_used; i++) g_scan_match_display(context->full_matches[i]); } /****************************************************************************** * * * Paramètres : context = mémoire de résultats d'analyse à compléter. * * name = désignation de la règle ciblée. * * expr = expression de condition à réduire. * * * * Description : Intègre une condition de correspondance pour règle. * * * * Retour : Bilan final d'une intégration (false si nom déjà présent). * * * * Remarques : - * * * ******************************************************************************/ bool g_scan_context_set_rule_condition(GScanContext *context, const char *name, const GScanExpression *expr) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ rule_condition_t *new; /* Nouvel élément à intégrer */ result = true; /* Recherche d'antécédent */ for (i = 0; context->cond_count; i++) if (strcmp(name, context->conditions[i].name) == 0) { result = false; break; } /* Ajout d'un nouvel élément ? */ if (result) { context->conditions = realloc(context->conditions, ++context->cond_count * sizeof(rule_condition_t)); new = &context->conditions[context->cond_count - 1]; new->name = strdup(name); new->expr = g_scan_expression_duplicate(expr); new->final_reduced = false; } return result; } /****************************************************************************** * * * Paramètres : context = mémoire de résultats d'analyse à consulter. * * name = désignation de la règle ciblée. * * * * Description : Indique si une correspondance globale a pu être établie. * * * * Retour : Bilan final d'une analyse (false par défaut). * * * * Remarques : - * * * ******************************************************************************/ bool g_scan_context_has_match_for_rule(GScanContext *context, const char *name) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ rule_condition_t *cond; /* Condition à considérer */ GScanExpression *new; /* Nouvelle expression réduite */ bool valid; /* Validité d'une récupération */ result = false; /* Recherche de la règle visée */ cond = NULL; for (i = 0; i < context->cond_count; i++) if (strcmp(name, context->conditions[i].name) == 0) { cond = &context->conditions[i]; break; } if (cond == NULL) goto exit; /* Tentative de réduction finale */ if (!cond->final_reduced) { cond->final_reduced = g_scan_expression_reduce(cond->expr, context, NULL, &new); if (cond->final_reduced && new != NULL) { g_object_unref(G_OBJECT(cond->expr)); cond->expr = new; } } /* Tentative de récupération d'un bilan final */ if (G_IS_LITERAL_EXPRESSION(cond->expr)) { valid = g_literal_expression_get_boolean_value(G_LITERAL_EXPRESSION(cond->expr), &result); if (!valid) { assert(!result); result = false; } } exit: return result; }