diff options
Diffstat (limited to 'src/analysis/scan/exprs')
43 files changed, 8452 insertions, 0 deletions
diff --git a/src/analysis/scan/exprs/Makefile.am b/src/analysis/scan/exprs/Makefile.am new file mode 100644 index 0000000..c97fa25 --- /dev/null +++ b/src/analysis/scan/exprs/Makefile.am @@ -0,0 +1,40 @@ + +noinst_LTLIBRARIES = libanalysisscanexprs.la + + +libanalysisscanexprs_la_SOURCES = \ + access-int.h \ + access.h access.c \ + arithmetic-int.h \ + arithmetic.h arithmetic.c \ + call-int.h \ + call.h call.c \ + extract-int.h \ + extract.h extract.c \ + handler-int.h \ + handler.h handler.c \ + intersect-int.h \ + intersect.h intersect.c \ + item-int.h \ + item.h item.c \ + literal-int.h \ + literal.h literal.c \ + logical-int.h \ + logical.h logical.c \ + range-int.h \ + range.h range.c \ + relational-int.h \ + relational.h relational.c \ + set-int.h \ + set.h set.c \ + setcounter-int.h \ + setcounter.h setcounter.c \ + strop-int.h \ + strop.h strop.c + +libanalysisscanexprs_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libanalysisscanexprs_la_SOURCES:%c=) diff --git a/src/analysis/scan/exprs/access-int.h b/src/analysis/scan/exprs/access-int.h new file mode 100644 index 0000000..be37241 --- /dev/null +++ b/src/analysis/scan/exprs/access-int.h @@ -0,0 +1,74 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * access-int.h - prototypes internes pour l'accès à un élément d'expression sous-jacent + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_ACCESS_INT_H +#define _ANALYSIS_SCAN_EXPRS_ACCESS_INT_H + + +#include "access.h" + + +#include "../expr-int.h" + + + +/* Reproduit un accès en place dans une nouvelle instance. */ +typedef void (* copy_scan_access_fc) (GScanNamedAccess *, const GScanNamedAccess *); + +/* Accès à un élément d'expression sous-jacent (instance) */ +struct _GScanNamedAccess +{ + GScanExpression parent; /* A laisser en premier */ + + union + { + GScanRegisteredItem *base; /* Base de recherche */ + GScanRegisteredItem *resolved; /* Elément ciblé au final */ + GObject *any; /* Accès indistinct */ + }; + + char *target; /* Cible dans l'espace */ + + struct _GScanNamedAccess *next; /* Evnetuel prochain élément */ + +}; + +/* Accès à un élément d'expression sous-jacent (classe) */ +struct _GScanNamedAccessClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + + copy_scan_access_fc copy; /* Reproduction d'accès */ + +}; + + +/* Met en place une expression d'accès. */ +bool g_scan_named_access_create(GScanNamedAccess *, const sized_string_t *); + +/* Prépare une réduction en menant une résolution locale. */ +GScanRegisteredItem *_g_scan_named_access_prepare_reduction(const GScanNamedAccess *, GScanContext *, GScanScope *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_ACCESS_INT_H */ diff --git a/src/analysis/scan/exprs/access.c b/src/analysis/scan/exprs/access.c new file mode 100644 index 0000000..342c2d7 --- /dev/null +++ b/src/analysis/scan/exprs/access.c @@ -0,0 +1,508 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * access.c - accès à un élément d'expression sous-jacent + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "access.h" + + +#include <assert.h> +#include <malloc.h> +#include <string.h> + + +#include "access-int.h" +#include "literal.h" +#include "../../../core/global.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des appels de fonction avec arguments. */ +static void g_scan_named_access_class_init(GScanNamedAccessClass *); + +/* Initialise une instance d'appel de fonction avec arguments. */ +static void g_scan_named_access_init(GScanNamedAccess *); + +/* Supprime toutes les références externes. */ +static void g_scan_named_access_dispose(GScanNamedAccess *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_named_access_finalize(GScanNamedAccess *); + +/* Reproduit un accès en place dans une nouvelle instance. */ +static void g_scan_named_access_copy(GScanNamedAccess *, const GScanNamedAccess *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réduit une expression à une forme plus simple. */ +static ScanReductionState g_scan_named_access_reduce(const GScanNamedAccess *, GScanContext *, GScanScope *, GScanExpression **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un appel de fonction enregistrée. */ +G_DEFINE_TYPE(GScanNamedAccess, g_scan_named_access, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des appels de fonction avec arguments. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_named_access_class_init(GScanNamedAccessClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_named_access_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_named_access_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)NULL; + expr->reduce = (reduce_expr_fc)g_scan_named_access_reduce; + + klass->copy = g_scan_named_access_copy; + +} + + +/****************************************************************************** +* * +* Paramètres : access = instance à initialiser. * +* * +* Description : Initialise une instance d'appel de fonction avec arguments. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_named_access_init(GScanNamedAccess *access) +{ + access->any = NULL; + access->target = NULL; + + access->next = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : access = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_named_access_dispose(GScanNamedAccess *access) +{ + g_clear_object(&access->any); + + g_clear_object(&access->next); + + G_OBJECT_CLASS(g_scan_named_access_parent_class)->dispose(G_OBJECT(access)); + +} + + +/****************************************************************************** +* * +* Paramètres : access = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_named_access_finalize(GScanNamedAccess *access) +{ + if (access->target != NULL) + free(access->target); + + G_OBJECT_CLASS(g_scan_named_access_parent_class)->finalize(G_OBJECT(access)); + +} + + +/****************************************************************************** +* * +* Paramètres : target = désignation de l'objet d'appel à identifier. * +* * +* Description : Organise un accès à un élément d'expression sous-jacent. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_named_access_new(const sized_string_t *target) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_NAMED_ACCESS, NULL); + + if (!g_scan_named_access_create(G_SCAN_NAMED_ACCESS(result), target)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : access = instance à initialiser pleinement. * +* target = désignation de l'objet d'appel à identifier. * +* * +* Description : Met en place une expression d'accès. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_named_access_create(GScanNamedAccess *access, const sized_string_t *target) +{ + bool result; /* Bilan à retourner */ + + result = g_scan_expression_create(G_SCAN_EXPRESSION(access), SRS_PENDING); + if (!result) goto exit; + + if (target != NULL) + access->target = strndup(target->data, target->len); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * +* src = expression source à copier. * +* * +* Description : Reproduit un accès en place dans une nouvelle instance. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_named_access_copy(GScanNamedAccess *dest, const GScanNamedAccess *src) +{ + /** + * Les champs suivants sont voués à être remplacés ou supprimés. + * + * On évite donc une instanciation inutile. + */ + + /* + if (src->any != NULL) + { + dest->any = src->any; + g_object_ref(src->any); + } + */ + + if (src->target != NULL) + dest->target = strdup(src->target); + + if (src->next != NULL) + { + dest->next = src->next; + g_object_ref(src->next); + } + +} + + +/****************************************************************************** +* * +* Paramètres : accès = expression d'accès à copier. * +* resolved = nouvelle base à imposer. * +* * +* Description : Reproduit un accès en place dans une nouvelle instance. * +* * +* Retour : Nouvelle instance d'expression d'accès. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_named_access_duplicate(const GScanNamedAccess *access, GScanRegisteredItem *resolved) +{ + GScanExpression *result; /* Instance copiée à retourner */ + GType type; /* Type d'objet à copier */ + GScanNamedAccessClass *class; /* Classe à activer */ + + type = G_TYPE_FROM_INSTANCE(access); + + result = g_object_new(type, NULL); + + class = G_SCAN_NAMED_ACCESS_GET_CLASS(access); + + class->copy(G_SCAN_NAMED_ACCESS(result), access); + + g_scan_named_access_set_base(G_SCAN_NAMED_ACCESS(result), resolved); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : access = expression d'appel à actualiser. * +* base = zone de recherche pour la résolution à venir. * +* * +* Description : Définit une base de recherche pour la cible d'accès. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_named_access_set_base(GScanNamedAccess *access, GScanRegisteredItem *base) +{ + g_clear_object(&access->base); + + access->base = base; + g_object_ref(G_OBJECT(base)); + +} + + +/****************************************************************************** +* * +* Paramètres : access = expression d'appel à compléter. * +* next = expression d'appel suivante dans la chaîne. * +* * +* Description : Complète la chaine d'accès à des expressions. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_named_access_attach_next(GScanNamedAccess *access, GScanNamedAccess *next) +{ + if (access->next != NULL) + g_scan_named_access_attach_next(access->next, next); + + else + { + access->next = next; + g_object_ref(G_OBJECT(next)); + } + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* * +* Description : Prépare une réduction en menant une résolution locale. * +* * +* Retour : Elément résolu avec les moyens du bord ou NULL si échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanRegisteredItem *_g_scan_named_access_prepare_reduction(const GScanNamedAccess *expr, GScanContext *ctx, GScanScope *scope) +{ + GScanRegisteredItem *result; /* Etat synthétisé à retourner */ + GScanRegisteredItem *base; /* Base de recherche courante */ + + result = NULL; + + if (expr->target != NULL) + { + if (expr->base != NULL) + { + base = expr->base; + g_object_ref(G_OBJECT(base)); + } + else + base = G_SCAN_REGISTERED_ITEM(get_rost_root_namespace()); + + g_scan_registered_item_resolve(base, expr->target, ctx, scope, &result); + + g_object_unref(G_OBJECT(base)); + + } + + /** + * Si plus aucune indication n'est diponible pour avancer dans les réductions, + * c'est que l'opération est déjà conclue. + */ + else + { + assert(expr->resolved != NULL); + + result = expr->resolved; + g_object_ref(G_OBJECT(result)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à 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 ScanReductionState g_scan_named_access_reduce(const GScanNamedAccess *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + ScanReductionState result; /* Etat synthétisé à retourner */ + GScanRegisteredItem *resolved; /* Cible concrète obtenue */ + GScanExpression *new_next; /* Nouvelle version du suivant */ + const char *current_rule; /* Nom de la règle courante */ + bool status; /* Bilan d'une autre règle */ + + resolved = _g_scan_named_access_prepare_reduction(expr, ctx, scope); + + if (resolved != NULL) + { + result = SRS_PENDING; + + /** + * Si l'élément résolu se trouve en fin de chaîne, alors cet élément + * est sollicité pour obtenir une expression d'évaluation classique. + * Le produit de cette réduction finale bénéficie d'une promotion et + * représente à lui seul la réduction produite pour la chaîne. + */ + if (expr->next == NULL) + { + status = g_scan_registered_item_reduce(resolved, ctx, scope, out); + + result = (status ? SRS_REDUCED : SRS_UNRESOLVABLE); + + } + + /** + * Sinon, l'élément résolu constitue une base pour l'étage suivant de + * la chaîne de résolution. + */ + else + { + new_next = g_scan_named_access_duplicate(expr->next, resolved); + + result = g_scan_expression_reduce(new_next, ctx, scope, out); + + g_object_unref(G_OBJECT(new_next)); + + } + + g_object_unref(G_OBJECT(resolved)); + + } + + /** + * Si le nom fournit le correspond à aucun élément de la grammaire, + * des recherches sont menées ailleurs. + */ + else + { + result = SRS_UNRESOLVABLE; + + if (g_scan_context_has_rule_for_name(ctx, expr->target)) + { + current_rule = g_scan_scope_get_rule_name(scope); + + /* Si référence circulaire il y a... */ + if (strcmp(current_rule, expr->target) == 0) + result = SRS_UNRESOLVABLE; + + else + { + status = g_scan_context_has_match_for_rule(ctx, expr->target); + + *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status); + result = SRS_REDUCED; + + } + + } + + } + + return result; + +} diff --git a/src/analysis/scan/exprs/access.h b/src/analysis/scan/exprs/access.h new file mode 100644 index 0000000..bf83dd0 --- /dev/null +++ b/src/analysis/scan/exprs/access.h @@ -0,0 +1,66 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * access.h - prototypes pour l'accès à un élément d'expression sous-jacent + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_ACCESS_H +#define _ANALYSIS_SCAN_EXPRS_ACCESS_H + + +#include "../expr.h" +#include "../item.h" +#include "../../../common/szstr.h" + + + +#define G_TYPE_SCAN_NAMED_ACCESS g_scan_named_access_get_type() +#define G_SCAN_NAMED_ACCESS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_NAMED_ACCESS, GScanNamedAccess)) +#define G_IS_SCAN_NAMED_ACCESS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_NAMED_ACCESS)) +#define G_SCAN_NAMED_ACCESS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_NAMED_ACCESS, GScanNamedAccessClass)) +#define G_IS_SCAN_NAMED_ACCESS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_NAMED_ACCESS)) +#define G_SCAN_NAMED_ACCESS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_NAMED_ACCESS, GScanNamedAccessClass)) + + +/* Accès à un élément d'expression sous-jacent (instance) */ +typedef struct _GScanNamedAccess GScanNamedAccess; + +/* Accès à un élément d'expression sous-jacent (classe) */ +typedef struct _GScanNamedAccessClass GScanNamedAccessClass; + + +/* Indique le type défini pour un appel de fonction enregistrée. */ +GType g_scan_named_access_get_type(void); + +/* Organise un accès à un élément d'expression sous-jacent. */ +GScanExpression *g_scan_named_access_new(const sized_string_t *); + +/* Reproduit un accès en place dans une nouvelle instance. */ +GScanExpression *g_scan_named_access_duplicate(const GScanNamedAccess *, GScanRegisteredItem *); + +/* Définit une base de recherche pour la cible d'accès. */ +void g_scan_named_access_set_base(GScanNamedAccess *, GScanRegisteredItem *); + +/* Complète la chaine d'accès à des expressions. */ +void g_scan_named_access_attach_next(GScanNamedAccess *, GScanNamedAccess *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_ACCESS_H */ diff --git a/src/analysis/scan/exprs/arithmetic-int.h b/src/analysis/scan/exprs/arithmetic-int.h new file mode 100644 index 0000000..c5010b0 --- /dev/null +++ b/src/analysis/scan/exprs/arithmetic-int.h @@ -0,0 +1,60 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * arithmetic-int.h - prototypes internes pour la gestion des opérations arithmétiques + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_ARITHMETIC_INT_H +#define _ANALYSIS_SCAN_EXPRS_ARITHMETIC_INT_H + + +#include "arithmetic.h" + + +#include "../expr-int.h" + + + +/* Opération arithmétique impliquant deux opérandes (instance) */ +struct _GScanArithmeticOperation +{ + GScanExpression parent; /* A laisser en premier */ + + ArithmeticExpressionOperator operator; /* Type d'opération menée */ + + GScanExpression *left; /* Expression impactée #1 */ + GScanExpression *right; /* Expression impactée #2 */ + +}; + +/* Opération arithmétique impliquant deux opérandes (classe) */ +struct _GScanArithmeticOperationClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une opération arithmétique entre expressions. */ +bool g_scan_arithmetic_operation_create(GScanArithmeticOperation *, ArithmeticExpressionOperator, GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_ARITHMETIC_INT_H */ diff --git a/src/analysis/scan/exprs/arithmetic.c b/src/analysis/scan/exprs/arithmetic.c new file mode 100644 index 0000000..06cfc48 --- /dev/null +++ b/src/analysis/scan/exprs/arithmetic.c @@ -0,0 +1,641 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * arithmetic.c - gestion des opérations arithmétiques + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "arithmetic.h" + + +#include <assert.h> + + +#include "arithmetic-int.h" +#include "literal.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des opérations arithmétiques. */ +static void g_scan_arithmetic_operation_class_init(GScanArithmeticOperationClass *); + +/* Initialise une instance d'opération arithmétique. */ +static void g_scan_arithmetic_operation_init(GScanArithmeticOperation *); + +/* Supprime toutes les références externes. */ +static void g_scan_arithmetic_operation_dispose(GScanArithmeticOperation *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_arithmetic_operation_finalize(GScanArithmeticOperation *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réalise une comparaison entre objets selon un critère précis. */ +static bool g_scan_arithmetic_operation_compare_rich(const GScanArithmeticOperation *, const GScanArithmeticOperation *, RichCmpOperation, bool *); + +/* Réduit une expression à une forme plus simple. */ +static ScanReductionState g_scan_arithmetic_operation_reduce(const GScanArithmeticOperation *, GScanContext *, GScanScope *, GScanExpression **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une opération de relation entre expressions. */ +G_DEFINE_TYPE(GScanArithmeticOperation, g_scan_arithmetic_operation, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des opérations arithmétiques. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_arithmetic_operation_class_init(GScanArithmeticOperationClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_arithmetic_operation_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_arithmetic_operation_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)g_scan_arithmetic_operation_compare_rich; + expr->reduce = (reduce_expr_fc)g_scan_arithmetic_operation_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser. * +* * +* Description : Initialise une instance d'opération arithmétique. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_arithmetic_operation_init(GScanArithmeticOperation *op) +{ + op->left = NULL; + op->right = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_arithmetic_operation_dispose(GScanArithmeticOperation *op) +{ + g_clear_object(&op->left); + g_clear_object(&op->right); + + G_OBJECT_CLASS(g_scan_arithmetic_operation_parent_class)->dispose(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_arithmetic_operation_finalize(GScanArithmeticOperation *op) +{ + G_OBJECT_CLASS(g_scan_arithmetic_operation_parent_class)->finalize(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : operator = type d'opération arithmétique à représenter. * +* left = premier opérande concerné. * +* right = éventuel second opérande impliqué ou NULL. * +* * +* Description : Organise une opération arithmétique entre expressions. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_arithmetic_operation_new(ArithmeticExpressionOperator operator, GScanExpression *left, GScanExpression *right) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_ARITHMETIC_OPERATION, NULL); + + if (!g_scan_arithmetic_operation_create(G_SCAN_ARITHMETIC_OPERATION(result), operator, left, right)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser pleinement. * +* operator = type d'opération booléenne à représenter. * +* left = premier opérande concerné. * +* right = éventuel second opérande impliqué ou NULL. * +* * +* Description : Met en place une opération arithmétique entre expressions. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_arithmetic_operation_create(GScanArithmeticOperation *op, ArithmeticExpressionOperator operator, GScanExpression *left, GScanExpression *right) +{ + bool result; /* Bilan à retourner */ + + result = g_scan_expression_create(G_SCAN_EXPRESSION(op), SRS_PENDING); + if (!result) goto exit; + + op->operator = operator; + + op->left = left; + g_object_ref(G_OBJECT(op->left)); + + op->right = right; + g_object_ref(G_OBJECT(op->right)); + + exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = premier objet à consulter pour une comparaison. * +* other = second objet à consulter pour une comparaison. * +* op = opération de comparaison à réaliser. * +* status = bilan des opérations de comparaison. [OUT] * +* * +* Description : Réalise une comparaison entre objets selon un critère précis.* +* * +* Retour : true si la comparaison a pu être effectuée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_arithmetic_operation_compare_rich(const GScanArithmeticOperation *item, const GScanArithmeticOperation *other, RichCmpOperation op, bool *status) +{ + bool result; /* Etat à retourner */ + + result = g_type_is_a(G_TYPE_FROM_INSTANCE(other), G_TYPE_SCAN_ARITHMETIC_OPERATION); + if (!result) goto done; + + if (item->operator != other->operator) + { + result = compare_rich_integer_values_unsigned(item->operator, other->operator, op); + goto done; + } + + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item), G_COMPARABLE_ITEM(other), RCO_EQ, status); + if (!result || STATUS_NOT_EQUAL(*status, op)) goto done; + + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->left), + G_COMPARABLE_ITEM(other->left), + op, status); + if (!result || STATUS_NOT_EQUAL(*status, op)) goto done; + + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->right), + G_COMPARABLE_ITEM(other->right), + op, status); + + done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à 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 ScanReductionState g_scan_arithmetic_operation_reduce(const GScanArithmeticOperation *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + ScanReductionState result; /* Etat synthétisé à retourner */ + GScanExpression *new_left; /* Expression réduite (gauche) */ + GScanExpression *new_right; /* Expression réduite (droite) */ + ScanReductionState state_left; /* Etat synthétisé #1 */ + ScanReductionState state_right; /* Etat synthétisé #2 */ + GScanLiteralExpression *op_left; /* Opérande gauche final */ + GScanLiteralExpression *op_right; /* Opérande droite final */ + LiteralValueType vtype_left; /* Type de valeur portée #1 */ + LiteralValueType vtype_right; /* Type de valeur portée #2 */ + long long val_1_s; /* Première valeur à traiter */ + unsigned long long val_1_u; /* Première valeur à traiter */ + long long val_2_s; /* Seconde valeur à traiter */ + unsigned long long val_2_u; /* Seconde valeur à traiter */ + LiteralValueType state_final; /* Nature de la valeur finale */ + long long reduced_s; /* Valeur réduite finale */ + unsigned long long reduced_u; /* Valeur réduite finale */ + + /* Réduction des éléments considérés */ + + new_left = NULL; + new_right = NULL; + + state_left = g_scan_expression_reduce(expr->left, ctx, scope, &new_left); + if (state_left == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + state_right = g_scan_expression_reduce(expr->right, ctx, scope, &new_right); + if (state_right == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + /* Construction d'une réduction locale ? */ + + if (G_IS_SCAN_LITERAL_EXPRESSION(new_left) && G_IS_SCAN_LITERAL_EXPRESSION(new_right)) + { + /* Récupération de l'opérande de gauche */ + + op_left = G_SCAN_LITERAL_EXPRESSION(new_left); + vtype_left = g_scan_literal_expression_get_value_type(op_left); + + if (vtype_left == LVT_SIGNED_INTEGER) + { + if (!g_scan_literal_expression_get_signed_integer_value(op_left, &val_1_s)) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + } + else if (vtype_left == LVT_UNSIGNED_INTEGER) + { + if (!g_scan_literal_expression_get_unsigned_integer_value(op_left, &val_1_u)) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + } + else + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + /* Récupération de l'opérande de droite */ + + op_right = G_SCAN_LITERAL_EXPRESSION(new_right); + vtype_right = g_scan_literal_expression_get_value_type(op_right); + + if (vtype_right == LVT_SIGNED_INTEGER) + { + if (!g_scan_literal_expression_get_signed_integer_value(op_right, &val_2_s)) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + } + else if (vtype_right == LVT_UNSIGNED_INTEGER) + { + if (!g_scan_literal_expression_get_unsigned_integer_value(op_right, &val_2_u)) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + } + else + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + /* Partie des calculs */ + + result = SRS_REDUCED; + + switch (expr->operator) + { + case AEO_PLUS: + if (vtype_left == LVT_SIGNED_INTEGER) + { + if (vtype_right == LVT_SIGNED_INTEGER) + { + state_final = LVT_SIGNED_INTEGER; + reduced_s = val_1_s + val_2_s; + } + else + { + assert(vtype_right == LVT_UNSIGNED_INTEGER); + + if ((long long)val_2_u > val_1_s) + { + state_final = LVT_UNSIGNED_INTEGER; + reduced_u = val_1_s + (long long)val_2_u; + } + else + { + state_final = LVT_SIGNED_INTEGER; + reduced_s = val_1_s + (long long)val_2_u; + } + + } + } + else + { + assert(vtype_left == LVT_UNSIGNED_INTEGER); + + if (vtype_right == LVT_SIGNED_INTEGER) + { + if ((long long)val_1_u > val_2_s) + { + state_final = LVT_UNSIGNED_INTEGER; + reduced_u = (long long)val_1_u + val_2_s; + } + else + { + state_final = LVT_SIGNED_INTEGER; + reduced_s = (long long)val_1_u + val_2_s; + } + + } + else + { + assert(vtype_right == LVT_UNSIGNED_INTEGER); + + state_final = LVT_UNSIGNED_INTEGER; + reduced_u = val_1_u + val_2_u; + + } + } + break; + + case AEO_MINUS: + if (vtype_left == LVT_SIGNED_INTEGER) + { + if (vtype_right == LVT_SIGNED_INTEGER) + { + if (val_2_s < val_1_s) + { + state_final = LVT_UNSIGNED_INTEGER; + reduced_u = val_1_s - val_2_s; + } + else + { + state_final = LVT_SIGNED_INTEGER; + reduced_s = val_1_s - val_2_s; + } + + } + else + { + assert(vtype_right == LVT_UNSIGNED_INTEGER); + + state_final = LVT_SIGNED_INTEGER; + reduced_s = val_1_s - (long long)val_2_u; + + } + } + else + { + assert(vtype_left == LVT_UNSIGNED_INTEGER); + + if (vtype_right == LVT_SIGNED_INTEGER) + { + state_final = LVT_UNSIGNED_INTEGER; + reduced_u = (long long)val_1_u - val_2_s; + } + else + { + assert(vtype_right == LVT_UNSIGNED_INTEGER); + + if (val_1_u > val_2_u) + { + state_final = LVT_UNSIGNED_INTEGER; + reduced_u = val_1_u - val_2_u; + } + else + { + state_final = LVT_SIGNED_INTEGER; + reduced_s = val_1_u - val_2_u; + } + + } + } + break; + + case AEO_MUL: + if (vtype_left == LVT_SIGNED_INTEGER) + { + if (vtype_right == LVT_SIGNED_INTEGER) + { + state_final = LVT_UNSIGNED_INTEGER; + reduced_u = val_1_s * val_2_s; + } + else + { + assert(vtype_right == LVT_UNSIGNED_INTEGER); + + state_final = LVT_SIGNED_INTEGER; + reduced_s = val_1_s * (long long)val_2_u; + + } + } + else + { + assert(vtype_left == LVT_UNSIGNED_INTEGER); + + if (vtype_right == LVT_SIGNED_INTEGER) + { + state_final = LVT_SIGNED_INTEGER; + reduced_s = (long long)val_1_u * val_2_s; + } + else + { + assert(vtype_right == LVT_UNSIGNED_INTEGER); + + state_final = LVT_UNSIGNED_INTEGER; + reduced_u = val_1_u * val_2_u; + + } + } + break; + + case AEO_DIV: + if ((vtype_right == LVT_SIGNED_INTEGER && val_2_s == 0) + || (vtype_right == LVT_UNSIGNED_INTEGER && val_2_u == 0)) + { + result = SRS_UNRESOLVABLE; + break; + } + + if (vtype_left == LVT_SIGNED_INTEGER) + { + if (vtype_right == LVT_SIGNED_INTEGER) + { + state_final = LVT_UNSIGNED_INTEGER; + reduced_u = val_1_s / val_2_s; + } + else + { + assert(vtype_right == LVT_UNSIGNED_INTEGER); + + state_final = LVT_SIGNED_INTEGER; + reduced_s = val_1_s / (long long)val_2_u; + + } + } + else + { + assert(vtype_left == LVT_UNSIGNED_INTEGER); + + if (vtype_right == LVT_SIGNED_INTEGER) + { + state_final = LVT_SIGNED_INTEGER; + reduced_s = (long long)val_1_u / val_2_s; + } + else + { + assert(vtype_right == LVT_UNSIGNED_INTEGER); + + state_final = LVT_UNSIGNED_INTEGER; + reduced_u = val_1_u / val_2_u; + + } + } + break; + + case AEO_MOD: + result = SRS_UNRESOLVABLE; + /* FIXME + result = (val_2 != 0); + if (result) + reduced = val_1 % val_2; + */ + break; + + } + + if (result == SRS_REDUCED) + { + if (state_final == LVT_SIGNED_INTEGER) + *out = g_scan_literal_expression_new(LVT_SIGNED_INTEGER, &reduced_s); + else + { + assert(state_final == LVT_UNSIGNED_INTEGER); + *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, &reduced_u); + } + + } + + } + + /* Mise à jour de la progression ? */ + + else if (state_left == SRS_WAIT_FOR_SCAN || state_right == SRS_WAIT_FOR_SCAN) + { + if (new_left != expr->left || new_right != expr->right) + *out = g_scan_arithmetic_operation_new(expr->operator, new_left, new_right); + + result = SRS_WAIT_FOR_SCAN; + + } + + /* Cas des situations où les expressions ne sont pas exploitables (!) */ + else + { + assert(state_left == SRS_REDUCED && state_right == SRS_REDUCED); + + result = SRS_UNRESOLVABLE; + + } + + /* Sortie propre */ + + exit: + + g_clear_object(&new_left); + g_clear_object(&new_right); + + return result; + +} diff --git a/src/analysis/scan/exprs/arithmetic.h b/src/analysis/scan/exprs/arithmetic.h new file mode 100644 index 0000000..8a1e844 --- /dev/null +++ b/src/analysis/scan/exprs/arithmetic.h @@ -0,0 +1,67 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * arithmetic.h - prototypes pour la gestion des opérations arithmétiques + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_ARITHMETIC_H +#define _ANALYSIS_SCAN_EXPRS_ARITHMETIC_H + + +#include "../expr.h" + + + +#define G_TYPE_SCAN_ARITHMETIC_OPERATION g_scan_arithmetic_operation_get_type() +#define G_SCAN_ARITHMETIC_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_ARITHMETIC_OPERATION, GScanArithmeticOperation)) +#define G_IS_SCAN_ARITHMETIC_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_ARITHMETIC_OPERATION)) +#define G_SCAN_ARITHMETIC_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_ARITHMETIC_OPERATION, GScanArithmeticOperationClass)) +#define G_IS_SCAN_ARITHMETIC_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_ARITHMETIC_OPERATION)) +#define G_SCAN_ARITHMETIC_OPERATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_ARITHMETIC_OPERATION, GScanArithmeticOperationClass)) + + +/* Opération arithmétique impliquant deux opérandes (instance) */ +typedef struct _GScanArithmeticOperation GScanArithmeticOperation; + +/* Opération arithmétique impliquant deux opérandes (classe) */ +typedef struct _GScanArithmeticOperationClass GScanArithmeticOperationClass; + + +/* Type d'opération arithmétique */ +typedef enum _ArithmeticExpressionOperator +{ + AEO_PLUS, /* Opération binaire "+" */ + AEO_MINUS, /* Opération binaire "-" */ + AEO_MUL, /* Opération binaire "*" */ + AEO_DIV, /* Opération binaire "\" */ + AEO_MOD, /* Opération binaire "%" */ + +} ArithmeticExpressionOperator; + + +/* Indique le type défini pour une opération arithmétique entre expressions. */ +GType g_scan_arithmetic_operation_get_type(void); + +/* Organise une opération arithmétique entre expressions. */ +GScanExpression *g_scan_arithmetic_operation_new(ArithmeticExpressionOperator, GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_ARITHMETIC_H */ diff --git a/src/analysis/scan/exprs/call-int.h b/src/analysis/scan/exprs/call-int.h new file mode 100644 index 0000000..9646b95 --- /dev/null +++ b/src/analysis/scan/exprs/call-int.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * call-int.h - prototypes internes pour l'organisation d'un appel à un élément de scan enregistré + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_CALL_INT_H +#define _ANALYSIS_SCAN_EXPRS_CALL_INT_H + + +#include "call.h" + + +#include "access-int.h" + + + +/* Exécution d'une fonction auxiliaire d'analyse (instance) */ +struct _GScanPendingCall +{ + GScanNamedAccess parent; /* A laisser en premier */ + + GScanExpression **args; /* Arguments d'appel fournis */ + size_t count; /* Quantité de ces arguments */ + +}; + +/* Exécution d'une fonction auxiliaire d'analyse (classe) */ +struct _GScanPendingCallClass +{ + GScanNamedAccessClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une expression d'appel. */ +bool g_scan_pending_call_create(GScanPendingCall *, const sized_string_t *, GScanExpression **, size_t); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_CALL_INT_H */ diff --git a/src/analysis/scan/exprs/call.c b/src/analysis/scan/exprs/call.c new file mode 100644 index 0000000..3997ff6 --- /dev/null +++ b/src/analysis/scan/exprs/call.c @@ -0,0 +1,467 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * call.c - organisation d'un appel à un élément de scan enregistré + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "call.h" + + +#include <assert.h> +#include <malloc.h> +#include <string.h> + + +#include "call-int.h" +#include "../../../core/global.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des appels de fonction avec arguments. */ +static void g_scan_pending_call_class_init(GScanPendingCallClass *); + +/* Initialise une instance d'appel de fonction avec arguments. */ +static void g_scan_pending_call_init(GScanPendingCall *); + +/* Supprime toutes les références externes. */ +static void g_scan_pending_call_dispose(GScanPendingCall *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_pending_call_finalize(GScanPendingCall *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réduit une expression à une forme plus simple. */ +static ScanReductionState g_scan_pending_call_reduce(const GScanPendingCall *, GScanContext *, GScanScope *, GScanExpression **); + +/* Reproduit un accès en place dans une nouvelle instance. */ +static void g_scan_pending_call_copy(GScanPendingCall *, const GScanPendingCall *); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un appel de fonction enregistrée. */ +G_DEFINE_TYPE(GScanPendingCall, g_scan_pending_call, G_TYPE_SCAN_NAMED_ACCESS); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des appels de fonction avec arguments. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pending_call_class_init(GScanPendingCallClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + GScanNamedAccessClass *access; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_pending_call_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_pending_call_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)NULL; + expr->reduce = (reduce_expr_fc)g_scan_pending_call_reduce; + + access = G_SCAN_NAMED_ACCESS_CLASS(klass); + + access->copy = (copy_scan_access_fc)g_scan_pending_call_copy; + +} + + +/****************************************************************************** +* * +* Paramètres : call = instance à initialiser. * +* * +* Description : Initialise une instance d'appel de fonction avec arguments. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pending_call_init(GScanPendingCall *call) +{ + call->args = NULL; + call->count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : call = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pending_call_dispose(GScanPendingCall *call) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < call->count; i++) + g_clear_object(&call->args[i]); + + G_OBJECT_CLASS(g_scan_pending_call_parent_class)->dispose(G_OBJECT(call)); + +} + + +/****************************************************************************** +* * +* Paramètres : call = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pending_call_finalize(GScanPendingCall *call) +{ + if (call->args != NULL) + free(call->args); + + G_OBJECT_CLASS(g_scan_pending_call_parent_class)->finalize(G_OBJECT(call)); + +} + + +/****************************************************************************** +* * +* Paramètres : target = désignation de l'objet d'appel à identifier. * +* args = éventuelle liste d'arguments à actionner. * +* count = quantité de ces arguments. * +* * +* Description : Organise un appel de fonction avec ses arguments. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_pending_call_new(const sized_string_t *target, GScanExpression **args, size_t count) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_PENDING_CALL, NULL); + + if (!g_scan_pending_call_create(G_SCAN_PENDING_CALL(result), target, args, count)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : call = instance à initialiser pleinement. * +* target = désignation de l'objet d'appel à identifier. * +* args = éventuelle liste d'arguments à actionner. * +* count = quantité de ces arguments. * +* * +* Description : Met en place une expression d'appel. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_pending_call_create(GScanPendingCall *call, const sized_string_t *target, GScanExpression **args, size_t count) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + + result = g_scan_named_access_create(G_SCAN_NAMED_ACCESS(call), target); + if (!result) goto exit; + + call->args = malloc(count * sizeof(GScanExpression *)); + call->count = count; + + for (i = 0; i < count; i++) + { + call->args[i] = args[i]; + g_object_ref(G_OBJECT(args[i])); + } + + exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : expr = expression à 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 ScanReductionState g_scan_pending_call_reduce(const GScanPendingCall *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + ScanReductionState result; /* Etat synthétisé à retourner */ + GScanNamedAccess *access; /* Autre vision de l'expression*/ + GScanRegisteredItem *resolved; /* Cible concrète obtenue */ + size_t i; /* Boucle de parcours #1 */ + GScanExpression *arg; /* Argument réduit à échanger */ + GScanExpression *new; /* Nouvelle réduction obtenue */ + ScanReductionState state; /* Etat synthétisé d'un élément*/ + size_t k; /* Boucle de parcours #2 */ + GScanExpression **new_args; /* Nouvelle séquence d'args. */ + GObject *final; /* Expression ou élément ? */ + bool valid; /* Validité de l'élément */ + GScanExpression *new_next; /* Nouvelle version du suivant */ + + access = G_SCAN_NAMED_ACCESS(expr); + + resolved = _g_scan_named_access_prepare_reduction(access, ctx, scope); + + if (resolved == NULL) + result = SRS_UNRESOLVABLE; + + else + { + result = SRS_PENDING; + + /* Actualisation nécessaire des arguments ? */ + + new_args = NULL; + + for (i = 0; i < expr->count; i++) + { + arg = expr->args[i]; + + state = g_scan_expression_reduce(arg, ctx, scope, &new); + if (state == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + break; + } + + if (state == SRS_WAIT_FOR_SCAN) + result = SRS_WAIT_FOR_SCAN; + + if (new != arg) + { + if (new_args == NULL) + { + new_args = calloc(expr->count, sizeof(GScanExpression *)); + + for (k = 0; k < i; k++) + { + new_args[k] = expr->args[k]; + g_object_ref(G_OBJECT(new_args[k])); + } + + } + + new_args[i] = new; + + } + + else + { + if (new_args != NULL) + new_args[i] = new; + + else + g_object_unref(G_OBJECT(new)); + + } + + } + + /* Suite des traitements */ + + if (result == SRS_WAIT_FOR_SCAN) + { + /** + * Si changement il y a eu... + */ + if (new_args != NULL) + { + *out = g_scan_pending_call_new(NULL, new_args, expr->count); + + /** + * Fonctionnement équivalent de : + * g_scan_named_access_set_base(G_SCAN_NAMED_ACCESS(*out), resolved); + */ + G_SCAN_NAMED_ACCESS(*out)->resolved = resolved; + g_object_ref(G_OBJECT(resolved)); + + if (G_SCAN_NAMED_ACCESS(expr)->next != NULL) + g_scan_named_access_attach_next(G_SCAN_NAMED_ACCESS(*out), G_SCAN_NAMED_ACCESS(expr)->next); + + } + + } + + else if (result == SRS_PENDING) + { + if (new_args == NULL) + valid = g_scan_registered_item_run_call(resolved, + expr->args, + expr->count, + ctx, scope, &final); + else + valid = g_scan_registered_item_run_call(resolved, + new_args, + expr->count, + ctx, scope, &final); + + if (valid && final != NULL) + { + /** + * Si le produit de l'appel à la fonction est une expression d'évaluation + * classique, alors ce produit constitue la réduction finale de la chaîne. + * + * Ce cas de figure ne se rencontre normalement qu'en bout de chaîne. + */ + if (!G_IS_SCAN_REGISTERED_ITEM(final)) + { + if (access->next != NULL) + result = SRS_UNRESOLVABLE; + + else + { + *out = G_SCAN_EXPRESSION(final); + g_object_ref(G_OBJECT(final)); + + result = SRS_REDUCED; + + } + + } + else + { + assert(access->next != NULL); + + new_next = g_scan_named_access_duplicate(access->next, G_SCAN_REGISTERED_ITEM(final)); + + result = g_scan_expression_reduce(new_next, ctx, scope, out); + + g_object_unref(G_OBJECT(new_next)); + + } + + } + + else + result = SRS_UNRESOLVABLE; + + g_clear_object(&final); + + } + + /* Libération locale des arguments reconstruits */ + + if (new_args != NULL) + { + for (i = 0; i < expr->count; i++) + g_clear_object(&new_args[i]); + } + + g_object_unref(G_OBJECT(resolved)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * +* src = expression source à copier. * +* * +* Description : Reproduit un accès en place dans une nouvelle instance. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pending_call_copy(GScanPendingCall *dest, const GScanPendingCall *src) +{ + GScanNamedAccessClass *class; /* Classe parente à solliciter */ + size_t i; /* Boucle de parcours */ + + class = G_SCAN_NAMED_ACCESS_CLASS(g_scan_pending_call_parent_class); + + class->copy(G_SCAN_NAMED_ACCESS(dest), G_SCAN_NAMED_ACCESS(src)); + + dest->args = malloc(src->count * sizeof(GScanExpression *)); + dest->count = src->count; + + for (i = 0; i < src->count; i++) + { + dest->args[i] = src->args[i]; + g_object_ref(G_OBJECT(src->args[i])); + } + +} diff --git a/src/analysis/scan/exprs/call.h b/src/analysis/scan/exprs/call.h new file mode 100644 index 0000000..c4d8964 --- /dev/null +++ b/src/analysis/scan/exprs/call.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * call.h - prototypes pour l'organisation d'un appel à un élément de scan enregistré + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_CALL_H +#define _ANALYSIS_SCAN_EXPRS_CALL_H + + +#include "../expr.h" +#include "../../../common/szstr.h" + + + +#define G_TYPE_SCAN_PENDING_CALL g_scan_pending_call_get_type() +#define G_SCAN_PENDING_CALL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_PENDING_CALL, GScanPendingCall)) +#define G_IS_SCAN_PENDING_CALL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_PENDING_CALL)) +#define G_SCAN_PENDING_CALL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_PENDING_CALL, GScanPendingCallClass)) +#define G_IS_SCAN_PENDING_CALL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_PENDING_CALL)) +#define G_SCAN_PENDING_CALL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_PENDING_CALL, GScanPendingCallClass)) + + +/* Exécution d'une fonction auxiliaire d'analyse (instance) */ +typedef struct _GScanPendingCall GScanPendingCall; + +/* Exécution d'une fonction auxiliaire d'analyse (classe) */ +typedef struct _GScanPendingCallClass GScanPendingCallClass; + + +/* Indique le type défini pour un appel de fonction enregistrée. */ +GType g_scan_pending_call_get_type(void); + +/* Organise un appel de fonction avec ses arguments. */ +GScanExpression *g_scan_pending_call_new(const sized_string_t *, GScanExpression **, size_t); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_CALL_H */ diff --git a/src/analysis/scan/exprs/extract-int.h b/src/analysis/scan/exprs/extract-int.h new file mode 100644 index 0000000..562e537 --- /dev/null +++ b/src/analysis/scan/exprs/extract-int.h @@ -0,0 +1,57 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * extract-int.h - prototypes internes pour l'organisation d'une extraction d'un élément d'une série interne + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_EXTRACT_INT_H +#define _ANALYSIS_SCAN_EXPRS_EXTRACT_INT_H + + +#include "extract.h" + + +#include "access-int.h" + + + +/* Extraction d'un élément donné au sein d'une série interne (instance) */ +struct _GScanPendingExtraction +{ + GScanNamedAccess parent; /* A laisser en premier */ + + GScanExpression *index; /* Arguments d'appel fournis */ + +}; + +/* Extraction d'un élément donné au sein d'une série interne (classe) */ +struct _GScanPendingExtractionClass +{ + GScanNamedAccessClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une expression d'extraction d'élément interne. */ +bool g_scan_pending_extraction_create(GScanPendingExtraction *, const sized_string_t *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_EXTRACT_INT_H */ diff --git a/src/analysis/scan/exprs/extract.c b/src/analysis/scan/exprs/extract.c new file mode 100644 index 0000000..b140ed9 --- /dev/null +++ b/src/analysis/scan/exprs/extract.c @@ -0,0 +1,396 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * extract.c - organisation d'une extraction d'un élément d'une série interne + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "extract.h" + + +#include <assert.h> +#include <string.h> + + +#include "extract-int.h" +#include "../../../core/global.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des extractions d'éléments internes. */ +static void g_scan_pending_extraction_class_init(GScanPendingExtractionClass *); + +/* Initialise une instance d'extraction d'élément interne. */ +static void g_scan_pending_extraction_init(GScanPendingExtraction *); + +/* Supprime toutes les références externes. */ +static void g_scan_pending_extraction_dispose(GScanPendingExtraction *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_pending_extraction_finalize(GScanPendingExtraction *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réduit une expression à une forme plus simple. */ +static ScanReductionState g_scan_pending_extraction_reduce(const GScanPendingExtraction *, GScanContext *, GScanScope *, GScanExpression **); + +/* Reproduit un accès en place dans une nouvelle instance. */ +static void g_scan_pending_extraction_copy(GScanPendingExtraction *, const GScanPendingExtraction *); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une extraction d'élément de série interne. */ +G_DEFINE_TYPE(GScanPendingExtraction, g_scan_pending_extraction, G_TYPE_SCAN_NAMED_ACCESS); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des extractions d'éléments internes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pending_extraction_class_init(GScanPendingExtractionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + GScanNamedAccessClass *access; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_pending_extraction_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_pending_extraction_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)NULL; + expr->reduce = (reduce_expr_fc)g_scan_pending_extraction_reduce; + + access = G_SCAN_NAMED_ACCESS_CLASS(klass); + + access->copy = (copy_scan_access_fc)g_scan_pending_extraction_copy; + +} + + +/****************************************************************************** +* * +* Paramètres : extract = instance à initialiser. * +* * +* Description : Initialise une instance d'extraction d'élément interne. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pending_extraction_init(GScanPendingExtraction *extract) +{ + extract->index = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : extract = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pending_extraction_dispose(GScanPendingExtraction *extract) +{ + g_clear_object(&extract->index); + + G_OBJECT_CLASS(g_scan_pending_extraction_parent_class)->dispose(G_OBJECT(extract)); + +} + + +/****************************************************************************** +* * +* Paramètres : extract = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pending_extraction_finalize(GScanPendingExtraction *extract) +{ + G_OBJECT_CLASS(g_scan_pending_extraction_parent_class)->finalize(G_OBJECT(extract)); + +} + + +/****************************************************************************** +* * +* Paramètres : target = désignation de l'objet d'appel à identifier. * +* index = indice de l'élément à extraire. * +* * +* Description : Organise l'extraction d'un élément d'une série interne. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_pending_extraction_new(const sized_string_t *target, GScanExpression *index) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_PENDING_EXTRACTION, NULL); + + if (!g_scan_pending_extraction_create(G_SCAN_PENDING_EXTRACTION(result), target, index)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : extract = instance à initialiser pleinement. * +* target = désignation de l'objet d'appel à identifier. * +* index = indice de l'élément à extraire. * +* * +* Description : Met en place une expression d'extraction d'élément interne. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_pending_extraction_create(GScanPendingExtraction *extract, const sized_string_t *target, GScanExpression *index) +{ + bool result; /* Bilan à retourner */ + + result = g_scan_named_access_create(G_SCAN_NAMED_ACCESS(extract), target); + if (!result) goto exit; + + extract->index = index; + g_object_ref(G_OBJECT(index)); + + exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : expr = expression à 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 ScanReductionState g_scan_pending_extraction_reduce(const GScanPendingExtraction *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + ScanReductionState result; /* Etat synthétisé à retourner */ + GScanNamedAccess *access; /* Autre vision de l'expression*/ + GScanRegisteredItem *resolved; /* Cible concrète obtenue */ + GScanExpression *new; /* Nouvelle réduction obtenue */ + GObject *final; /* Expression ou élément ? */ + GScanExpression *new_next; /* Nouvelle version du suivant */ + + access = G_SCAN_NAMED_ACCESS(expr); + + resolved = _g_scan_named_access_prepare_reduction(access, ctx, scope); + + if (resolved == NULL) + result = SRS_UNRESOLVABLE; + + else + { + /* Actualisation nécessaire des arguments ? */ + + result = g_scan_expression_reduce(expr->index, ctx, scope, &new); + + /* Suite des traitements */ + + if (result == SRS_WAIT_FOR_SCAN) + { + /** + * Si changement il y a eu... + */ + if (new != expr->index) + { + *out = g_scan_pending_extraction_new(NULL, new); + + /** + * Fonctionnement équivalent de : + * g_scan_named_access_set_base(G_SCAN_NAMED_ACCESS(*out), resolved); + */ + G_SCAN_NAMED_ACCESS(*out)->resolved = resolved; + g_object_ref(G_OBJECT(resolved)); + + if (G_SCAN_NAMED_ACCESS(expr)->next != NULL) + g_scan_named_access_attach_next(G_SCAN_NAMED_ACCESS(*out), G_SCAN_NAMED_ACCESS(expr)->next); + + } + + } + + else if (result == SRS_REDUCED) + { + final = g_scan_registered_item_extract_at(resolved, new, ctx, scope); + + if (final != NULL) + { + /** + * Si le produit de l'appel à la fonction est une expression d'évaluation + * classique, alors ce produit constitue la réduction finale de la chaîne. + * + * Ce cas de figure ne se rencontre normalement qu'en bout de chaîne. + */ + if (!G_IS_SCAN_REGISTERED_ITEM(final)) + { + if (access->next != NULL) + result = SRS_UNRESOLVABLE; + + else + { + *out = G_SCAN_EXPRESSION(final); + g_object_ref(G_OBJECT(final)); + + result = SRS_REDUCED; + + } + + } + else + { + if (access->next != NULL) + { + new_next = g_scan_named_access_duplicate(access->next, G_SCAN_REGISTERED_ITEM(final)); + + result = g_scan_expression_reduce(new_next, ctx, scope, out); + + g_object_unref(G_OBJECT(new_next)); + + } + + /** + * Le cas ci-après est typique de l'extension Kaitai : field[n] + * renvoie vers une instance GScanRegisteredItem (GKaitaiBrowser). + * + * Il n'y a donc pas d'expression en jeu, et l'élément est le dernier + * de la liste. + */ + else + { + if (g_scan_registered_item_reduce(G_SCAN_REGISTERED_ITEM(final), ctx, scope, out)) + result = SRS_REDUCED; + else + result = SRS_UNRESOLVABLE; + + } + + } + + } + + else + result = SRS_UNRESOLVABLE; + + g_clear_object(&final); + + } + + /* Libération locale des arguments reconstruits */ + + g_clear_object(&new); + + g_object_unref(G_OBJECT(resolved)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * +* src = expression source à copier. * +* * +* Description : Reproduit un accès en place dans une nouvelle instance. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pending_extraction_copy(GScanPendingExtraction *dest, const GScanPendingExtraction *src) +{ + GScanNamedAccessClass *class; /* Classe parente à solliciter */ + + class = G_SCAN_NAMED_ACCESS_CLASS(g_scan_pending_extraction_parent_class); + + class->copy(G_SCAN_NAMED_ACCESS(dest), G_SCAN_NAMED_ACCESS(src)); + + dest->index = src->index; + g_object_ref(G_OBJECT(src->index)); + +} diff --git a/src/analysis/scan/exprs/extract.h b/src/analysis/scan/exprs/extract.h new file mode 100644 index 0000000..8ed1cfa --- /dev/null +++ b/src/analysis/scan/exprs/extract.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * extract.h - prototypes pour l'organisation d'une extraction d'un élément d'une série interne + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_EXTRACT_H +#define _ANALYSIS_SCAN_EXPRS_EXTRACT_H + + +#include "../expr.h" +#include "../../../common/szstr.h" + + + +#define G_TYPE_SCAN_PENDING_EXTRACTION g_scan_pending_extraction_get_type() +#define G_SCAN_PENDING_EXTRACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_PENDING_EXTRACTION, GScanPendingExtraction)) +#define G_IS_SCAN_PENDING_EXTRACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_PENDING_EXTRACTION)) +#define G_SCAN_PENDING_EXTRACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_PENDING_EXTRACTION, GScanPendingExtractionClass)) +#define G_IS_SCAN_PENDING_EXTRACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_PENDING_EXTRACTION)) +#define G_SCAN_PENDING_EXTRACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_PENDING_EXTRACTION, GScanPendingExtractionClass)) + + +/* Extraction d'un élément donné au sein d'une série interne (instance) */ +typedef struct _GScanPendingExtraction GScanPendingExtraction; + +/* Extraction d'un élément donné au sein d'une série interne (classe) */ +typedef struct _GScanPendingExtractionClass GScanPendingExtractionClass; + + +/* Indique le type défini pour une extraction d'élément de série interne. */ +GType g_scan_pending_extraction_get_type(void); + +/* Organise l'extraction d'un élément d'une série interne. */ +GScanExpression *g_scan_pending_extraction_new(const sized_string_t *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_EXTRACT_H */ diff --git a/src/analysis/scan/exprs/handler-int.h b/src/analysis/scan/exprs/handler-int.h new file mode 100644 index 0000000..e051b30 --- /dev/null +++ b/src/analysis/scan/exprs/handler-int.h @@ -0,0 +1,68 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * handler-int.h - prototypes internes pour la manipulation des correspondances établies lors d'un scan + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_HANDLER_INT_H +#define _ANALYSIS_SCAN_EXPRS_HANDLER_INT_H + + +#include "handler.h" + + +#include "../expr-int.h" + + + +/* Manipulation des correspondances établies lors d'un scan de binaire (instance) */ +struct _GScanPatternHandler +{ + GScanExpression parent; /* A laisser en premier */ + + union + { + const GSearchPattern **patterns; /* Motifs associés */ + GSearchPattern **ref_patterns; /* Motifs associés */ + }; + size_t count; /* Nombre de ces motifs */ + bool shared; /* Définition de propriété */ + + ScanHandlerType type; /* Manipulation attendue */ + +}; + +/* Manipulation des correspondances établies lors d'un scan de binaire (classe) */ +struct _GScanPatternHandlerClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une manipulation de correspondances établies. */ +bool g_scan_pattern_handler_create_shared(GScanPatternHandler *, const GSearchPattern ** const, size_t, ScanHandlerType); + +/* Met en place une manipulation de correspondances établies. */ +bool g_scan_pattern_handler_create_and_ref(GScanPatternHandler *, GSearchPattern ** const, size_t, ScanHandlerType); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_HANDLER_INT_H */ diff --git a/src/analysis/scan/exprs/handler.c b/src/analysis/scan/exprs/handler.c new file mode 100644 index 0000000..2706dae --- /dev/null +++ b/src/analysis/scan/exprs/handler.c @@ -0,0 +1,622 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * handler.c - manipulation des correspondances établies lors d'un scan + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "handler.h" + + +#include <assert.h> + + +#include "literal.h" +#include "handler-int.h" +#include "../matches/bytes.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des manipulations de correspondances. */ +static void g_scan_pattern_handler_class_init(GScanPatternHandlerClass *); + +/* Initialise une instance de manipulation de correspondances. */ +static void g_scan_pattern_handler_init(GScanPatternHandler *); + +/* Supprime toutes les références externes. */ +static void g_scan_pattern_handler_dispose(GScanPatternHandler *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_pattern_handler_finalize(GScanPatternHandler *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réduit une expression à une forme plus simple. */ +static ScanReductionState g_scan_pattern_handler_reduce(const GScanPatternHandler *, GScanContext *, GScanScope *, GScanExpression **); + +/* Réduit une expression à une forme booléenne. */ +static bool g_scan_pattern_handler_reduce_to_boolean(const GScanPatternHandler *, GScanContext *, GScanScope *, GScanExpression **); + +/* Dénombre les éléments portés par une expression. */ +static bool g_scan_pattern_handler_count_items(const GScanPatternHandler *, GScanContext *, size_t *); + +/* Fournit un élément donné issu d'un ensemble constitué. */ +static bool g_scan_pattern_handler_get_item(const GScanPatternHandler *, size_t, GScanContext *, GScanExpression **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une manipulation de correspondances établies lors d'un scan. */ +G_DEFINE_TYPE(GScanPatternHandler, g_scan_pattern_handler, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des manipulations de correspondances. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pattern_handler_class_init(GScanPatternHandlerClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_pattern_handler_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_pattern_handler_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->reduce = (reduce_expr_fc)g_scan_pattern_handler_reduce; + expr->reduce_to_bool = (reduce_expr_to_bool_fc)g_scan_pattern_handler_reduce_to_boolean; + expr->count = (count_scan_expr_fc)g_scan_pattern_handler_count_items; + expr->get = (get_scan_expr_fc)g_scan_pattern_handler_get_item; + +} + + +/****************************************************************************** +* * +* Paramètres : handler = instance à initialiser. * +* * +* Description : Initialise une instance de manipulation de correspondances. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pattern_handler_init(GScanPatternHandler *handler) +{ + handler->patterns = NULL; + handler->count = 0; + handler->shared = true; + + handler->type = SHT_RAW; + +} + + +/****************************************************************************** +* * +* Paramètres : handler = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pattern_handler_dispose(GScanPatternHandler *handler) +{ + size_t i; /* Boucle de parcours */ + + if (!handler->shared) + for (i = 0; i < handler->count; i++) + g_clear_object(&handler->ref_patterns[i]); + + G_OBJECT_CLASS(g_scan_pattern_handler_parent_class)->dispose(G_OBJECT(handler)); + +} + + +/****************************************************************************** +* * +* Paramètres : handler = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pattern_handler_finalize(GScanPatternHandler *handler) +{ + if (handler->patterns != NULL) + free(handler->patterns); + + G_OBJECT_CLASS(g_scan_pattern_handler_parent_class)->finalize(G_OBJECT(handler)); + +} + + +/****************************************************************************** +* * +* Paramètres : patterns = motifs à impliquer. * +* count = quantité de ces motifs. * +* type = type de manipulation attendue. * +* * +* Description : Met en place une manipulation de correspondances établies. * +* * +* Retour : Expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_pattern_handler_new_shared(const GSearchPattern ** const patterns, size_t count, ScanHandlerType type) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_PATTERN_HANDLER, NULL); + + if (!g_scan_pattern_handler_create_shared(G_SCAN_PATTERN_HANDLER(result), patterns, count, type)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : handler = instance à initialiser pleinement. * +* patterns = motifs à impliquer. * +* count = quantité de ces motifs. * +* type = type de manipulation attendue. * +* * +* Description : Met en place une manipulation de correspondances établies. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_pattern_handler_create_shared(GScanPatternHandler *handler, const GSearchPattern ** const patterns, size_t count, ScanHandlerType type) +{ + bool result; /* Bilan à retourner */ + + result = g_scan_expression_create(G_SCAN_EXPRESSION(handler), SRS_WAIT_FOR_SCAN); + if (!result) goto exit; + + handler->patterns = malloc(count * sizeof(GSearchPattern *)); + handler->count = count; + + memcpy(handler->patterns, patterns, count * sizeof(GSearchPattern *)); + + handler->shared = true; + + handler->type = type; + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : patterns = motifs à impliquer. * +* count = quantité de ces motifs. * +* type = type de manipulation attendue. * +* * +* Description : Met en place une manipulation de correspondances établies. * +* * +* Retour : Expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_pattern_handler_new(GSearchPattern ** const patterns, size_t count, ScanHandlerType type) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_PATTERN_HANDLER, NULL); + + if (!g_scan_pattern_handler_create_and_ref(G_SCAN_PATTERN_HANDLER(result), patterns, count, type)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : handler = instance à initialiser pleinement. * +* patterns = motifs à impliquer. * +* count = quantité de ces motifs. * +* type = type de manipulation attendue. * +* * +* Description : Met en place une manipulation de correspondances établies. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_pattern_handler_create_and_ref(GScanPatternHandler *handler, GSearchPattern ** const patterns, size_t count, ScanHandlerType type) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + + result = g_scan_expression_create(G_SCAN_EXPRESSION(handler), SRS_WAIT_FOR_SCAN); + if (!result) goto exit; + + handler->patterns = malloc(count * sizeof(GSearchPattern *)); + handler->count = count; + + memcpy(handler->patterns, patterns, count * sizeof(GSearchPattern *)); + + for (i = 0; i < count; i++) + g_object_ref(G_OBJECT(patterns[i])); + + handler->shared = false; + + handler->type = type; + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : handler = instance à initialiser pleinement. * +* * +* Description : Indique le type de manipulation de correspondances spécifié. * +* * +* Retour : Type de manipulation de correspondances représentée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +ScanHandlerType g_scan_pattern_handler_get_handler_type(const GScanPatternHandler *handler) +{ + ScanHandlerType result; /* Nature à retourner */ + + result = handler->type; + + return result; + +} + + +#if 0 /* FIXME */ + +/****************************************************************************** +* * +* Paramètres : handler = instance à initialiser pleinement. * +* ctx = contexte de suivi de l'analyse courante. * +* count = quantité de correspondances enregistrées. [OUT] * +* * +* Description : Fournit la liste de toutes les correspondances représentées. * +* * +* Retour : Liste courante de correspondances établies. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanMatch **g_scan_pattern_handler_get_all_matches(const GScanPatternHandler *handler, GScanContext *ctx, size_t *count) +{ + GScanMatch **result; /* Liste à retourner */ + size_t used; /* Indice pour le stockage */ + size_t i; /* Boucle de parcours #1 */ + size_t partial; /* Décompte partiel */ + const GScanMatch **matches; /* Correspondances en place */ + size_t k; /* Boucle de parcours #2 */ + + result = NULL; + + if (!g_scan_pattern_handler_count_items(handler, ctx, count)) + { + *count = 0; + goto exit; + } + + if (*count == 0) + goto exit; + + result = malloc(*count * sizeof(GScanMatch *)); + + used = 0; + + for (i = 0; i < handler->count; i++) + { + matches = g_scan_context_get_full_matches(ctx, handler->patterns[i], &partial); + + for (k = 0; k < partial; k++) + { + result[used++] = matches[k]; + g_object_ref(G_OBJECT(matches[k])); + } + + } + + exit: + + return result; + +} +#endif + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : expr = expression à 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 ScanReductionState g_scan_pattern_handler_reduce(const GScanPatternHandler *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + ScanReductionState result; /* Etat synthétisé à retourner */ + size_t count; /* Quantité de correspondances */ + + if (g_scan_context_is_scan_done(ctx)) + { + if (expr->type == SHT_COUNTER) + { + if (!g_scan_pattern_handler_count_items(expr, ctx, &count)) + result = SRS_UNRESOLVABLE; + + else + { + result = SRS_REDUCED; + *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ count }); + } + + } + + else + result = SRS_REDUCED; + + } + + else + result = SRS_WAIT_FOR_SCAN; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à 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 booléenne. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_pattern_handler_reduce_to_boolean(const GScanPatternHandler *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + bool result; /* Bilan à retourner */ + size_t count; /* Quantité de correspondances */ + + result = g_scan_pattern_handler_count_items(expr, ctx, &count); + + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ count > 0 }); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* count = quantité d'éléments déterminée. [OUT] * +* * +* Description : Dénombre les éléments portés par une expression. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_pattern_handler_count_items(const GScanPatternHandler *expr, GScanContext *ctx, size_t *count) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + + result = true; + + assert(g_scan_context_is_scan_done(ctx)); + + *count = 0; + + for (i = 0; i < expr->count; i++) + *count += g_scan_context_count_full_matches(ctx, expr->patterns[i]); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* index = indice de l'élément à transférer. * +* ctx = contexte de suivi de l'analyse courante. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * +* * +* Description : Fournit un élément donné issu d'un ensemble constitué. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_pattern_handler_get_item(const GScanPatternHandler *expr, size_t index, GScanContext *ctx, GScanExpression **out) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + size_t count; /* Quantité de correspondances */ + GScanMatches *matches; /* Correspondances d'un motif */ + const match_area_t *area; /* Zone de correspondance */ + GBinContent *content; /* Contenu binaire à relire */ + vmpa2t pos; /* Tête de lecture */ + const bin_t *data; /* Accès aux données brutes */ + sized_string_t binary; /* Conversion de formats */ + + result = false; + + assert(g_scan_context_is_scan_done(ctx)); + + /* Identification du motif concerné */ + + for (i = 0; i < expr->count; i++) + { + count = g_scan_context_count_full_matches(ctx, expr->patterns[i]); + + if (index < count) + break; + else + index -= count; + + } + + if (i == expr->count) goto done; + + /* Identification de la correspondance concernée */ + + matches = g_scan_context_get_full_matches(ctx, expr->patterns[i]); + if (matches == NULL) goto done; + + area = g_scan_bytes_matches_get(G_SCAN_BYTES_MATCHES(matches), index); + if (area == NULL) goto done_with_matches; + + /* Traitement adapté de la requête */ + + switch (expr->type) + { + case SHT_RAW: + content = g_scan_context_get_content(ctx); + + init_vmpa(&pos, area->start, VMPA_NO_VIRTUAL); + + data = g_binary_content_get_raw_access(content, &pos, area->end - area->start); + + binary.static_bin_data = data; + binary.len = area->end - area->start; + + *out = g_scan_literal_expression_new(LVT_STRING, &binary); + + g_object_unref(G_OBJECT(content)); + result = true; + break; + + case SHT_COUNTER: + assert(false); + break; + + case SHT_START: + *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, + (unsigned long long []){ area->start }); + result = true; + break; + + case SHT_LENGTH: + *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, + (unsigned long long []){ area->end - area->start }); + result = true; + break; + + case SHT_END: + *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, + (unsigned long long []){ area->end }); + result = true; + break; + + } + + done_with_matches: + + g_object_unref(G_OBJECT(matches)); + + done: + + return result; + +} diff --git a/src/analysis/scan/exprs/handler.h b/src/analysis/scan/exprs/handler.h new file mode 100644 index 0000000..a1ddf98 --- /dev/null +++ b/src/analysis/scan/exprs/handler.h @@ -0,0 +1,80 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * handler.h - prototypes pour la manipulation des correspondances établies lors d'un scan + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_HANDLER_H +#define _ANALYSIS_SCAN_EXPRS_HANDLER_H + + +#include "../expr.h" + + + +#define G_TYPE_SCAN_PATTERN_HANDLER g_scan_pattern_handler_get_type() +#define G_SCAN_PATTERN_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_PATTERN_HANDLER, GScanPatternHandler)) +#define G_IS_SCAN_PATTERN_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_PATTERN_HANDLER)) +#define G_SCAN_PATTERN_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_PATTERN_HANDLER, GScanPatternHandlerClass)) +#define G_IS_SCAN_PATTERN_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_PATTERN_HANDLER)) +#define G_SCAN_PATTERN_HANDLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_PATTERN_HANDLER, GScanPatternHandlerClass)) + + +/* Manipulation des correspondances établies lors d'un scan de binaire (instance) */ +typedef struct _GScanPatternHandler GScanPatternHandler; + +/* Manipulation des correspondances établies lors d'un scan de binaire (classe) */ +typedef struct _GScanPatternHandlerClass GScanPatternHandlerClass; + + +/* Type de manipulation représentée */ +typedef enum _ScanHandlerType +{ + SHT_RAW, /* Correspondances brutes */ + SHT_COUNTER, /* Dénombrement de résultats */ + SHT_START, /* Départs de correspondances */ + SHT_LENGTH, /* Taille de correspondances */ + SHT_END, /* Fins de correspondances */ + +} ScanHandlerType; + + +/* Indique le type défini pour une manipulation de correspondances établies lors d'un scan. */ +GType g_scan_pattern_handler_get_type(void); + +/* Met en place une manipulation de correspondances établies. */ +GScanExpression *g_scan_pattern_handler_new_shared(const GSearchPattern ** const, size_t, ScanHandlerType); + +/* Met en place une manipulation de correspondances établies. */ +GScanExpression *g_scan_pattern_handler_new(GSearchPattern ** const, size_t, ScanHandlerType); + +/* Indique le type de manipulation de correspondances spécifié. */ +ScanHandlerType g_scan_pattern_handler_get_handler_type(const GScanPatternHandler *); + +#if 0 /* FIXME */ + +/* Fournit la liste de toutes les correspondances représentées. */ +GScanMatch **g_scan_pattern_handler_get_all_matches(const GScanPatternHandler *, GScanContext *, size_t *); + +#endif + + + +#endif /* _ANALYSIS_SCAN_EXPRS_HANDLER_H */ diff --git a/src/analysis/scan/exprs/intersect-int.h b/src/analysis/scan/exprs/intersect-int.h new file mode 100644 index 0000000..83e4251 --- /dev/null +++ b/src/analysis/scan/exprs/intersect-int.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * intersect-int.h - prototypes internes pour l'intersection d'ensembles aux types indentiques + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_INTERSECT_INT_H +#define _ANALYSIS_SCAN_EXPRS_INTERSECT_INT_H + + +#include "intersect.h" + + +#include "../expr-int.h" + + + +/* Opération d'intersection entre deux ensembles (instance) */ +struct _GScanSetsIntersection +{ + GScanExpression parent; /* A laisser en premier */ + + GScanExpression *first; /* Expression impactée #1 */ + GScanExpression *second; /* Expression impactée #2 */ + +}; + +/* Opération d'intersection entre deux ensembles (classe) */ +struct _GScanSetsIntersectionClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une expression d'opération booléenne. */ +bool g_scan_sets_intersection_create(GScanSetsIntersection *, GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_INTERSECT_INT_H */ diff --git a/src/analysis/scan/exprs/intersect.c b/src/analysis/scan/exprs/intersect.c new file mode 100644 index 0000000..c56d28c --- /dev/null +++ b/src/analysis/scan/exprs/intersect.c @@ -0,0 +1,290 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * intersect.c - intersection d'ensembles aux types indentiques + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "intersect.h" + + +#include <assert.h> + + +#include "intersect-int.h" +#include "literal.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des intersections entre deux ensembles. */ +static void g_scan_sets_intersection_class_init(GScanSetsIntersectionClass *); + +/* Initialise une instance d'intersection entre deux ensembles. */ +static void g_scan_sets_intersection_init(GScanSetsIntersection *); + +/* Supprime toutes les références externes. */ +static void g_scan_sets_intersection_dispose(GScanSetsIntersection *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_sets_intersection_finalize(GScanSetsIntersection *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réduit une expression à une forme plus simple. */ +static ScanReductionState g_scan_sets_intersection_reduce(const GScanSetsIntersection *, GScanContext *, GScanScope *, GScanExpression **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une intersection entre deux ensembles. */ +G_DEFINE_TYPE(GScanSetsIntersection, g_scan_sets_intersection, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des intersections entre deux ensembles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_sets_intersection_class_init(GScanSetsIntersectionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_sets_intersection_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_sets_intersection_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->reduce = (reduce_expr_fc)g_scan_sets_intersection_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser. * +* * +* Description : Initialise une instance d'intersection entre deux ensembles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_sets_intersection_init(GScanSetsIntersection *inter) +{ + inter->first = NULL; + inter->second = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : inter = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_sets_intersection_dispose(GScanSetsIntersection *inter) +{ + g_clear_object(&inter->first); + g_clear_object(&inter->second); + + G_OBJECT_CLASS(g_scan_sets_intersection_parent_class)->dispose(G_OBJECT(inter)); + +} + + +/****************************************************************************** +* * +* Paramètres : inter = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_sets_intersection_finalize(GScanSetsIntersection *inter) +{ + G_OBJECT_CLASS(g_scan_sets_intersection_parent_class)->finalize(G_OBJECT(inter)); + +} + + +/****************************************************************************** +* * +* Paramètres : type = type d'opération booléenne à représenter. * +* first = premier élément concerné. * +* second = second élément concerné. * +* * +* Description : Organise une intersection entre deux ensembles. * +* * +* Retour : Expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_sets_intersection_new(GScanExpression *first, GScanExpression *second) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_SETS_INTERSECTION, NULL); + + if (!g_scan_sets_intersection_create(G_SCAN_SETS_INTERSECTION(result), first, second)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : inter = instance à initialiser pleinement. * +* first = premier élément concerné. * +* second = second élément concerné. * +* * +* Description : Met en place une expression d'opération booléenne. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_sets_intersection_create(GScanSetsIntersection *inter, GScanExpression *first, GScanExpression *second) +{ + bool result; /* Bilan à retourner */ + + result = true; + + inter->first = first; + g_object_ref(G_OBJECT(first)); + + inter->second = second; + g_object_ref(G_OBJECT(second)); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : expr = expression à 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 ScanReductionState g_scan_sets_intersection_reduce(const GScanSetsIntersection *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + ScanReductionState result; /* Etat synthétisé à retourner */ + GScanExpression *new_first; /* Nouvelle réduction #1 */ + GScanExpression *new_second; /* Nouvelle réduction #2 */ + ScanReductionState state_first; /* Etat synthétisé #1 */ + ScanReductionState state_second; /* Etat synthétisé #2 */ + + new_first = NULL; + new_second = NULL; + + state_first = g_scan_expression_reduce(expr->first, ctx, scope, &new_first); + if (state_first == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + state_second = g_scan_expression_reduce(expr->second, ctx, scope, &new_second); + if (state_second == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + if (state_first == SRS_WAIT_FOR_SCAN || state_second == SRS_WAIT_FOR_SCAN) + { + if (new_first != expr->first || new_second != expr->second) + *out = g_scan_sets_intersection_new(new_first, new_second); + + result = SRS_WAIT_FOR_SCAN; + + } + + else + { + assert(state_first == SRS_REDUCED && state_second == SRS_REDUCED); + + *out = g_scan_expression_intersect(new_first, new_second, ctx, scope); + + result = (*out != NULL ? SRS_REDUCED : SRS_UNRESOLVABLE); + + } + + exit: + + g_clear_object(&new_first); + g_clear_object(&new_second); + + return result; + +} diff --git a/src/analysis/scan/exprs/intersect.h b/src/analysis/scan/exprs/intersect.h new file mode 100644 index 0000000..56efdff --- /dev/null +++ b/src/analysis/scan/exprs/intersect.h @@ -0,0 +1,55 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * intersect.h - prototypes pour l'intersection d'ensembles aux types indentiques + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_INTERSECT_H +#define _ANALYSIS_SCAN_EXPRS_INTERSECT_H + + +#include "../expr.h" + + + +#define G_TYPE_SCAN_SETS_INTERSECTION g_scan_sets_intersection_get_type() +#define G_SCAN_SETS_INTERSECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_SETS_INTERSECTION, GScanSetsIntersection)) +#define G_IS_SCAN_SETS_INTERSECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_SETS_INTERSECTION)) +#define G_SCAN_SETS_INTERSECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_SETS_INTERSECTION, GScanSetsIntersectionClass)) +#define G_IS_SCAN_SETS_INTERSECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_SETS_INTERSECTION)) +#define G_SCAN_SETS_INTERSECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_SETS_INTERSECTION, GScanSetsIntersectionClass)) + + +/* Opération d'intersection entre deux ensembles (instance) */ +typedef struct _GScanSetsIntersection GScanSetsIntersection; + +/* Opération d'intersection entre deux ensembles (classe) */ +typedef struct _GScanSetsIntersectionClass GScanSetsIntersectionClass; + + +/* Indique le type défini pour une intersection entre deux ensembles. */ +GType g_scan_sets_intersection_get_type(void); + +/* Organise une intersection entre deux ensembles. */ +GScanExpression *g_scan_sets_intersection_new(GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_INTERSECT_H */ diff --git a/src/analysis/scan/exprs/item-int.h b/src/analysis/scan/exprs/item-int.h new file mode 100644 index 0000000..56b159a --- /dev/null +++ b/src/analysis/scan/exprs/item-int.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item-int.h - prototypes internes pour la récupération d'un élément à partir d'une série + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_ITEM_INT_H +#define _ANALYSIS_SCAN_EXPRS_ITEM_INT_H + + +#include "item.h" + + +#include "../expr-int.h" + + + +/* Accès à un élément donné d'une série établie (instance) */ +struct _GScanSetItem +{ + GScanExpression parent; /* A laisser en premier */ + + GScanExpression *set; /* Série d'éléments à consulter*/ + GScanExpression *index; /* Indice de l'élément visé */ + +}; + +/* Accès à un élément donné d'une série établie (classe) */ +struct _GScanSetItemClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un accès à un élément donné d'une série. */ +bool g_scan_set_item_create(GScanSetItem *, GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_ITEM_INT_H */ diff --git a/src/analysis/scan/exprs/item.c b/src/analysis/scan/exprs/item.c new file mode 100644 index 0000000..a5a6fdf --- /dev/null +++ b/src/analysis/scan/exprs/item.c @@ -0,0 +1,353 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item.c - récupération d'un élément à partir d'une série + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "set.h" + + +#include <assert.h> + + +#include "literal.h" +#include "item-int.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des accès à un élément de série. */ +static void g_scan_set_item_class_init(GScanSetItemClass *); + +/* Initialise une instance d'accès à un élément de série. */ +static void g_scan_set_item_init(GScanSetItem *); + +/* Supprime toutes les références externes. */ +static void g_scan_set_item_dispose(GScanSetItem *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_set_item_finalize(GScanSetItem *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réduit une expression à une forme plus simple. */ +static ScanReductionState g_scan_set_item_reduce(const GScanSetItem *, GScanContext *, GScanScope *, GScanExpression **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour la récupération d'un élément à partir d'une série. */ +G_DEFINE_TYPE(GScanSetItem, g_scan_set_item, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des accès à un élément de série. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_set_item_class_init(GScanSetItemClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_set_item_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_set_item_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->reduce = (reduce_expr_fc)g_scan_set_item_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : item = instance à initialiser. * +* * +* Description : Initialise une instance d'accès à un élément de série. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_set_item_init(GScanSetItem *item) +{ + item->set = NULL; + item->index = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : item = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_set_item_dispose(GScanSetItem *item) +{ + g_clear_object(&item->set); + g_clear_object(&item->index); + + G_OBJECT_CLASS(g_scan_set_item_parent_class)->dispose(G_OBJECT(item)); + +} + + +/****************************************************************************** +* * +* Paramètres : item = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_set_item_finalize(GScanSetItem *item) +{ + G_OBJECT_CLASS(g_scan_set_item_parent_class)->finalize(G_OBJECT(item)); + +} + + +/****************************************************************************** +* * +* Paramètres : set = ensemble d'éléments à considérer. * +* index = indice de l'élément à viser. * +* * +* Description : Met en place un accès à un élément donné d'une série. * +* * +* Retour : Expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_set_item_new(GScanExpression *set, GScanExpression *index) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_SET_ITEM, NULL); + + if (!g_scan_set_item_create(G_SCAN_SET_ITEM(result), set, index)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = instance à initialiser pleinement. * +* set = ensemble d'éléments à considérer. * +* index = indice de l'élément à viser. * +* * +* Description : Met en place un accès à un élément donné d'une série. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_set_item_create(GScanSetItem *item, GScanExpression *set, GScanExpression *index) +{ + bool result; /* Bilan à retourner */ + + result = g_scan_expression_create(G_SCAN_EXPRESSION(item), SRS_PENDING); + if (!result) goto exit; + + item->set = set; + g_object_ref(G_OBJECT(set)); + + item->index = index; + g_object_ref(G_OBJECT(index)); + + exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : expr = expression à 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 ScanReductionState g_scan_set_item_reduce(const GScanSetItem *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + ScanReductionState result; /* Etat synthétisé à retourner */ + GScanExpression *new_set; /* Expression réduite (série) */ + GScanExpression *new_index; /* Expression réduite (indice) */ + ScanReductionState state_set; /* Etat synthétisé #1 */ + ScanReductionState state_index; /* Etat synthétisé #2 */ + GScanLiteralExpression *op_index; /* Indice d'accès final */ + LiteralValueType vtype; /* Type de valeur portée */ + long long val_s; /* Valeur de l'indice (signée) */ + unsigned long long val_u; /* Valeur de l'indice (!signée)*/ + bool status; /* Statut final de récupération*/ + + /* Réduction des éléments considérés */ + + new_set = NULL; + new_index = NULL; + + state_set = g_scan_expression_reduce(expr->set, ctx, scope, &new_set); + if (state_set == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + state_index = g_scan_expression_reduce(expr->index, ctx, scope, &new_index); + if (state_index == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + /* Validation de la nature des éléments en jeu */ + + if (state_set == SRS_REDUCED && !g_scan_expression_handle_set_features(new_set)) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + if (state_index == SRS_REDUCED && !G_IS_SCAN_LITERAL_EXPRESSION(new_index)) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + /* Tentative d'accès à un élément de série */ + + if (state_set == SRS_REDUCED && state_index == SRS_REDUCED) + { + op_index = G_SCAN_LITERAL_EXPRESSION(new_index); + vtype = g_scan_literal_expression_get_value_type(op_index); + + if (vtype == LVT_SIGNED_INTEGER) + { + if (!g_scan_literal_expression_get_signed_integer_value(op_index, &val_s)) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + if (val_s < 0) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + status = g_scan_expression_get_item(expr->set, val_s, ctx, out); + + } + + else if (vtype == LVT_UNSIGNED_INTEGER) + { + if (!g_scan_literal_expression_get_unsigned_integer_value(op_index, &val_u)) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + status = g_scan_expression_get_item(expr->set, val_u, ctx, out); + + } + + else + status = false; + + result = (status ? SRS_REDUCED : SRS_UNRESOLVABLE); + + } + + /* Mise à jour de la progression ? */ + + else + { + assert(state_set == SRS_WAIT_FOR_SCAN || state_index == SRS_WAIT_FOR_SCAN); + + if (new_set != expr->set || new_index != expr->index) + *out = g_scan_set_item_new(new_set, new_index); + + result = SRS_WAIT_FOR_SCAN; + + } + + /* Sortie propre */ + + exit: + + g_clear_object(&new_set); + g_clear_object(&new_index); + + return result; + +} diff --git a/src/analysis/scan/exprs/item.h b/src/analysis/scan/exprs/item.h new file mode 100644 index 0000000..9d3cdfb --- /dev/null +++ b/src/analysis/scan/exprs/item.h @@ -0,0 +1,55 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item.h - prototypes pour la récupération d'un élément à partir d'une série + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_ITEM_H +#define _ANALYSIS_SCAN_EXPRS_ITEM_H + + +#include "../expr.h" + + + +#define G_TYPE_SCAN_SET_ITEM g_scan_set_item_get_type() +#define G_SCAN_SET_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_SET_ITEM, GScanSetItem)) +#define G_IS_SCAN_SET_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_SET_ITEM)) +#define G_SCAN_SET_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_SET_ITEM, GScanSetItemClass)) +#define G_IS_SCAN_SET_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_SET_ITEM)) +#define G_SCAN_SET_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_SET_ITEM, GScanSetItemClass)) + + +/* Accès à un élément donné d'une série établie (instance) */ +typedef struct _GScanSetItem GScanSetItem; + +/* Accès à un élément donné d'une série établie (classe) */ +typedef struct _GScanSetItemClass GScanSetItemClass; + + +/* Indique le type défini pour la récupération d'un élément à partir d'une série. */ +GType g_scan_set_item_get_type(void); + +/* Met en place un accès à un élément donné d'une série. */ +GScanExpression *g_scan_set_item_new(GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_ITEM_H */ diff --git a/src/analysis/scan/exprs/literal-int.h b/src/analysis/scan/exprs/literal-int.h new file mode 100644 index 0000000..b0a0ec5 --- /dev/null +++ b/src/analysis/scan/exprs/literal-int.h @@ -0,0 +1,71 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * literal-int.h - prototypes internes pour la représentation d'une valeur concrète + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_LITERAL_INT_H +#define _ANALYSIS_SCAN_EXPRS_LITERAL_INT_H + + +#include "literal.h" + + +#include "../expr-int.h" + + + +/* Expression portant une valeur concrète (instance) */ +struct _GScanLiteralExpression +{ + GScanExpression parent; /* A laisser en premier */ + + LiteralValueType value_type; /* Type de valeur portée */ + + union + { + bool boolean; /* Valeur booléenne */ + long long s_integer; /* Valeur entière 64 bits */ + unsigned long long u_integer; /* Valeur entière 64 bits */ + sized_string_t string; /* Chaîne de caractères */ + struct + { + char *regex; /* Formulation d'origine */ + regex_t preg; /* Expression rationnelle */ + }; + + } value; + +}; + +/* Expression portant une valeur concrète (classe) */ +struct _GScanLiteralExpressionClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une expression de valeur concrête. */ +bool g_scan_literal_expression_create(GScanLiteralExpression *, LiteralValueType, ...); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_LITERAL_INT_H */ diff --git a/src/analysis/scan/exprs/literal.c b/src/analysis/scan/exprs/literal.c new file mode 100644 index 0000000..b7aed5b --- /dev/null +++ b/src/analysis/scan/exprs/literal.c @@ -0,0 +1,734 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * literal.c - représentation d'une valeur concrète + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "literal.h" + + +#include <assert.h> +#include <stdarg.h> +#include <string.h> + + +#include "literal-int.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des expressions de valeur concrète. */ +static void g_scan_literal_expression_class_init(GScanLiteralExpressionClass *); + +/* Initialise une instance d'expression de valeur concrète. */ +static void g_scan_literal_expression_init(GScanLiteralExpression *); + +/* Supprime toutes les références externes. */ +static void g_scan_literal_expression_dispose(GScanLiteralExpression *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_literal_expression_finalize(GScanLiteralExpression *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réalise une comparaison entre objets selon un critère précis. */ +static bool g_scan_literal_expression_compare_rich(const GScanLiteralExpression *, const GScanLiteralExpression *, RichCmpOperation, bool *); + +/* Réduit une expression à une forme booléenne. */ +static bool g_scan_literal_expression_reduce_to_boolean(const GScanLiteralExpression *, GScanContext *, GScanScope *, GScanExpression **); + +/* Dénombre les éléments portés par une expression. */ +static bool g_scan_literal_expression_count(const GScanLiteralExpression *, GScanContext *, size_t *); + +/* Fournit un élément donné issu d'un ensemble constitué. */ +static bool g_scan_literal_expression_get_item(const GScanLiteralExpression *, size_t, GScanContext *, GScanExpression **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un appel de fonction enregistrée. */ +G_DEFINE_TYPE(GScanLiteralExpression, g_scan_literal_expression, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des expressions de valeur concrète. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_literal_expression_class_init(GScanLiteralExpressionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_literal_expression_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_literal_expression_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)g_scan_literal_expression_compare_rich; + expr->reduce_to_bool = (reduce_expr_to_bool_fc)g_scan_literal_expression_reduce_to_boolean; + expr->count = (count_scan_expr_fc)g_scan_literal_expression_count; + expr->get = (get_scan_expr_fc)g_scan_literal_expression_get_item; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = instance à initialiser. * +* * +* Description : Initialise une instance d'expression de valeur concrète. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_literal_expression_init(GScanLiteralExpression *expr) +{ + G_SCAN_EXPRESSION(expr)->state = SRS_REDUCED; + + memset(&expr->value, 0, sizeof(expr->value)); + +} + + +/****************************************************************************** +* * +* Paramètres : expr = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_literal_expression_dispose(GScanLiteralExpression *expr) +{ + G_OBJECT_CLASS(g_scan_literal_expression_parent_class)->dispose(G_OBJECT(expr)); + +} + + +/****************************************************************************** +* * +* Paramètres : expr = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_literal_expression_finalize(GScanLiteralExpression *expr) +{ + switch (expr->value_type) + { + case LVT_STRING: + exit_szstr(&expr->value.string); + break; + + case LVT_REG_EXPR: + if (expr->value.regex != NULL) + { + free(expr->value.regex); + regfree(&expr->value.preg); + } + break; + + default: + break; + + } + + G_OBJECT_CLASS(g_scan_literal_expression_parent_class)->finalize(G_OBJECT(expr)); + +} + + +/****************************************************************************** +* * +* Paramètres : vtype = type de valeur associée par l'expression. * +* ... = valeur concrête à intégrer. * +* * +* Description : Organise un appel de fonction avec ses arguments. * +* * +* Retour : Expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_literal_expression_new(LiteralValueType vtype, ...) +{ + GScanExpression *result; /* Structure à retourner */ + va_list ap; /* Liste d'arguements */ + void *ptr; /* Vision générique de valeur */ + + result = g_object_new(G_TYPE_SCAN_LITERAL_EXPRESSION, NULL); + + va_start(ap, vtype); + + ptr = va_arg(ap, void *); + + if (!g_scan_literal_expression_create(G_SCAN_LITERAL_EXPRESSION(result), vtype, ptr)) + g_clear_object(&result); + + va_end(ap); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = instance à initialiser pleinement. * +* vtype = type de valeur associée par l'expression. * +* ... = valeur concrête à intégrer. * +* * +* Description : Met en place une expression de valeur concrête. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_literal_expression_create(GScanLiteralExpression *expr, LiteralValueType vtype, ...) +{ + bool result; /* Bilan à retourner */ + va_list ap; /* Liste d'arguements */ + const bool *boolean; /* Valeur booléenne */ + const long long *s_integer; /* Valeur entière 64 bits #1 */ + const unsigned long long *u_integer; /* Valeur entière 64 bits #2 */ + const sized_string_t *string; /* Chaîne de caractères */ + const char *raw; /* Chaîne de caractères brute */ + size_t len; /* Taille de la chaîne */ + int cflags; /* Détails de compilation */ + unsigned int i; /* Boucle de parcours */ + char *tmp; /* Zone de travail temporaire */ + int ret; /* Bilan d'une opération */ + + result = g_scan_expression_create(G_SCAN_EXPRESSION(expr), SRS_REDUCED); + if (!result) goto exit; + + va_start(ap, vtype); + + switch (vtype) + { + case LVT_BOOLEAN: + boolean = va_arg(ap, const bool *); + expr->value.boolean = *boolean; + result = true; + break; + + case LVT_SIGNED_INTEGER: + s_integer = va_arg(ap, const long long *); + expr->value.s_integer = *s_integer; + result = true; + break; + + case LVT_UNSIGNED_INTEGER: + u_integer = va_arg(ap, const unsigned long long *); + expr->value.u_integer = *u_integer; + result = true; + break; + + case LVT_STRING: + string = va_arg(ap, const sized_string_t *); + szstrdup(&expr->value.string, string); + result = true; + break; + + case LVT_REG_EXPR: + raw = va_arg(ap, const char *); + len = strlen(raw); + + result = (len > 2 && raw[0] == '/'); + + cflags = REG_EXTENDED | REG_NOSUB; + + for (i = 0; i < 2 && result; i++) + { + result = (len > 2); + + if (raw[len - 1] == 'i') + { + cflags |= REG_ICASE; + len -= 1; + } + + else if (raw[len - 1] == 's') + { + cflags |= REG_NEWLINE; + len -= 1; + } + + else if (raw[len - 1] == '/') + break; + + } + + if (result) + result = (raw[len - 1] == '/'); + + if (result) + { + assert(len > 2); + + tmp = strndup(&raw[1], len - 2); + ret = regcomp(&expr->value.preg, tmp, cflags); + free(tmp); + + result = (ret == 0); + + if (result) + expr->value.regex = strdup(raw); + + } + + break; + + default: + result = false; + break; + + } + + va_end(ap); + + expr->value_type = vtype; + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* * +* Description : Indique le type de valeur portée par une expression. * +* * +* Retour : Type de valeur associée à l'expression. * +* * +* Remarques : - * +* * +******************************************************************************/ + +LiteralValueType g_scan_literal_expression_get_value_type(const GScanLiteralExpression *expr) +{ + LiteralValueType result; /* Type à retourner */ + + result = expr->value_type; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = premier objet à consulter pour une comparaison. * +* value = valeur portée portée par l'expression. [OUT] * +* * +* Description : Indique la valeur portée par une expression booléenne. * +* * +* Retour : true si l'expression est de type booléen, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_literal_expression_get_boolean_value(const GScanLiteralExpression *expr, bool *value) +{ + bool result; /* Etat à retourner */ + + result = (expr->value_type == LVT_BOOLEAN); + + if (result) + *value = expr->value.boolean; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = premier objet à consulter pour une comparaison. * +* value = valeur portée portée par l'expression. [OUT] * +* * +* Description : Indique la valeur portée par une expression d'entier. * +* * +* Retour : true si l'expression est de type entier, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_literal_expression_get_signed_integer_value(const GScanLiteralExpression *expr, long long *value) +{ + bool result; /* Etat à retourner */ + + result = (expr->value_type == LVT_SIGNED_INTEGER); + + if (result) + *value = expr->value.u_integer; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = premier objet à consulter pour une comparaison. * +* value = valeur portée portée par l'expression. [OUT] * +* * +* Description : Indique la valeur portée par une expression d'entier. * +* * +* Retour : true si l'expression est de type entier, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_literal_expression_get_unsigned_integer_value(const GScanLiteralExpression *expr, unsigned long long *value) +{ + bool result; /* Etat à retourner */ + + result = (expr->value_type == LVT_UNSIGNED_INTEGER); + + if (result) + *value = expr->value.u_integer; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = premier objet à consulter pour une comparaison. * +* value = valeur portée portée par l'expression. [OUT] * +* * +* Description : Indique la valeur portée par une expression de chaîne. * +* * +* Retour : true si l'expression est de type entier, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_literal_expression_get_string_value(const GScanLiteralExpression *expr, const sized_string_t **value) +{ + bool result; /* Etat à retourner */ + + result = (expr->value_type == LVT_STRING); + + if (result) + *value = &expr->value.string; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = premier objet à consulter pour une comparaison. * +* value = valeur portée portée par l'expression. [OUT] * +* * +* Description : Indique la valeur portée par une expression rationnelle. * +* * +* Retour : true si l'expression est de type entier, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_literal_expression_get_regex_value(const GScanLiteralExpression *expr, const regex_t **value) +{ + bool result; /* Etat à retourner */ + + result = (expr->value_type == LVT_REG_EXPR); + + if (result) + *value = &expr->value.preg; + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : expr = premier objet à consulter pour une comparaison. * +* other = second objet à consulter pour une comparaison. * +* op = opération de comparaison à réaliser. * +* status = bilan des opérations de comparaison. [OUT] * +* * +* Description : Réalise une comparaison entre objets selon un critère précis.* +* * +* Retour : true si la comparaison a pu être effectuée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_literal_expression_compare_rich(const GScanLiteralExpression *expr, const GScanLiteralExpression *other, RichCmpOperation op, bool *status) +{ + bool result; /* Etat à retourner */ + int cmp; /* Bilan intermédiaire */ + + result = g_type_is_a(G_TYPE_FROM_INSTANCE(other), G_TYPE_SCAN_LITERAL_EXPRESSION); + if (!result) goto done; + + if (expr->value_type != other->value_type) + { + *status = compare_rich_integer_values_unsigned(expr->value_type, other->value_type, op); + goto done; + } + + switch (expr->value_type) + { + case LVT_BOOLEAN: + switch (op) + { + case RCO_EQ: + *status = (expr->value.boolean == other->value.boolean); + result = true; + break; + + case RCO_NE: + *status = (expr->value.boolean != other->value.boolean); + result = true; + break; + + default: + result = false; + break; + + }; + break; + + case LVT_SIGNED_INTEGER: + *status = compare_rich_integer_values_signed(expr->value.s_integer, other->value.s_integer, op); + result = true; + break; + + case LVT_UNSIGNED_INTEGER: + *status = compare_rich_integer_values_unsigned(expr->value.u_integer, other->value.u_integer, op); + result = true; + break; + + case LVT_STRING: + cmp = szstrcmp(&expr->value.string, &other->value.string); + *status = compare_rich_integer_values_signed(cmp, 0, op); + result = true; + break; + + case LVT_REG_EXPR: + cmp = strcmp(expr->value.regex, other->value.regex); + *status = compare_rich_integer_values_signed(cmp, 0, op); + result = true; + break; + + default: + result = false; + break; + + } + + done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à 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 booléenne. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_literal_expression_reduce_to_boolean(const GScanLiteralExpression *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + bool result; /* Bilan à retourner */ + + switch (expr->value_type) + { + case LVT_BOOLEAN: + *out = G_SCAN_EXPRESSION(expr); + g_object_ref(G_OBJECT(expr)); + result = true; + break; + + case LVT_SIGNED_INTEGER: + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ expr->value.s_integer != 0 }); + result = true; + break; + + case LVT_UNSIGNED_INTEGER: + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ expr->value.u_integer != 0 }); + result = true; + break; + + case LVT_STRING: + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ expr->value.string.len > 0 }); + result = true; + break; + + default: + result = false; + break; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* count = quantité d'éléments déterminée. [OUT] * +* * +* Description : Dénombre les éléments portés par une expression. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_literal_expression_count(const GScanLiteralExpression *expr, GScanContext *ctx, size_t *count) +{ + bool result; /* Bilan à retourner */ + + switch (expr->value_type) + { + case LVT_STRING: + *count = expr->value.string.len; + result = true; + break; + + default: + result = false; + break; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* index = indice de l'élément à transférer. * +* ctx = contexte de suivi de l'analyse courante. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * +* * +* Description : Fournit un élément donné issu d'un ensemble constitué. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_literal_expression_get_item(const GScanLiteralExpression *expr, size_t index, GScanContext *ctx, GScanExpression **out) +{ + bool result; /* Bilan à retourner */ + sized_string_t ch; /* Caractère extrait */ + + switch (expr->value_type) + { + case LVT_STRING: + + result = (index < expr->value.string.len); + + if (result) + { + ch.data = expr->value.string.data + index; + ch.len = 1; + + *out = g_scan_literal_expression_new(LVT_STRING, &ch); + + } + + break; + + default: + result = false; + break; + + } + + return result; + +} diff --git a/src/analysis/scan/exprs/literal.h b/src/analysis/scan/exprs/literal.h new file mode 100644 index 0000000..9352baf --- /dev/null +++ b/src/analysis/scan/exprs/literal.h @@ -0,0 +1,90 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * literal.h - prototypes pour la représentation d'une valeur concrète + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_LITERAL_H +#define _ANALYSIS_SCAN_EXPRS_LITERAL_H + + +#include <regex.h> +#include <stdbool.h> + + +#include "../expr.h" +#include "../../../common/szstr.h" + + + +#define G_TYPE_SCAN_LITERAL_EXPRESSION g_scan_literal_expression_get_type() +#define G_SCAN_LITERAL_EXPRESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_LITERAL_EXPRESSION, GScanLiteralExpression)) +#define G_IS_SCAN_LITERAL_EXPRESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_LITERAL_EXPRESSION)) +#define G_SCAN_LITERAL_EXPRESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_LITERAL_EXPRESSION, GScanLiteralExpressionClass)) +#define G_IS_SCAN_LITERAL_EXPRESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_LITERAL_EXPRESSION)) +#define G_SCAN_LITERAL_EXPRESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_LITERAL_EXPRESSION, GScanLiteralExpressionClass)) + + +/* Expression portant une valeur concrète (instance) */ +typedef struct _GScanLiteralExpression GScanLiteralExpression; + +/* Expression portant une valeur concrète (classe) */ +typedef struct _GScanLiteralExpressionClass GScanLiteralExpressionClass; + + +/* Types naturel équivalant à l'expression */ +typedef enum _LiteralValueType +{ + LVT_BOOLEAN, /* Valeur booléenne */ + LVT_SIGNED_INTEGER, /* Nombre entier 64 bits #1 */ + LVT_UNSIGNED_INTEGER, /* Nombre entier 64 bits #2 */ + LVT_STRING, /* Chaîne de caractères */ + LVT_REG_EXPR, /* Expression rationnelle */ + +} LiteralValueType; + + +/* Indique le type défini pour un appel de fonction enregistrée. */ +GType g_scan_literal_expression_get_type(void); + +/* Organise un appel de fonction avec ses arguments. */ +GScanExpression *g_scan_literal_expression_new(LiteralValueType, ...); + +/* Indique le type de valeur portée par une expression. */ +LiteralValueType g_scan_literal_expression_get_value_type(const GScanLiteralExpression *); + +/* Indique la valeur portée par une expression booléenne. */ +bool g_scan_literal_expression_get_boolean_value(const GScanLiteralExpression *, bool *); + +/* Indique la valeur portée par une expression d'entier. */ +bool g_scan_literal_expression_get_signed_integer_value(const GScanLiteralExpression *, long long *); + +/* Indique la valeur portée par une expression d'entier. */ +bool g_scan_literal_expression_get_unsigned_integer_value(const GScanLiteralExpression *, unsigned long long *); + +/* Indique la valeur portée par une expression de chaîne. */ +bool g_scan_literal_expression_get_string_value(const GScanLiteralExpression *, const sized_string_t **); + +/* Indique la valeur portée par une expression rationnelle. */ +bool g_scan_literal_expression_get_regex_value(const GScanLiteralExpression *, const regex_t **); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_LITERAL_H */ diff --git a/src/analysis/scan/exprs/logical-int.h b/src/analysis/scan/exprs/logical-int.h new file mode 100644 index 0000000..6df55d0 --- /dev/null +++ b/src/analysis/scan/exprs/logical-int.h @@ -0,0 +1,60 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * logical-int.h - prototypes internes pour la gestion des opérations booléennes + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_LOGICAL_INT_H +#define _ANALYSIS_SCAN_EXPRS_LOGICAL_INT_H + + +#include "logical.h" + + +#include "../expr-int.h" + + + +/* Opération booléenne avec un ou deux opérandes (instance) */ +struct _GScanLogicalOperation +{ + GScanExpression parent; /* A laisser en premier */ + + BooleanOperationType type; /* Type d'opération menée */ + + GScanExpression *first; /* Expression impactée #1 */ + GScanExpression *second; /* Expression impactée #2 */ + +}; + +/* Opération booléenne avec un ou deux opérandes (classe) */ +struct _GScanLogicalOperationClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une expression d'opération booléenne. */ +bool g_scan_logical_operation_create(GScanLogicalOperation *, BooleanOperationType, GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_LOGICAL_INT_H */ diff --git a/src/analysis/scan/exprs/logical.c b/src/analysis/scan/exprs/logical.c new file mode 100644 index 0000000..3b07843 --- /dev/null +++ b/src/analysis/scan/exprs/logical.c @@ -0,0 +1,518 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * logical.c - gestion des opérations booléennes + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "logical.h" + + +#include <assert.h> + + +#include "logical-int.h" +#include "literal.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des opérations booléennes. */ +static void g_scan_logical_operation_class_init(GScanLogicalOperationClass *); + +/* Initialise une instance d'opération booléenne. */ +static void g_scan_logical_operation_init(GScanLogicalOperation *); + +/* Supprime toutes les références externes. */ +static void g_scan_logical_operation_dispose(GScanLogicalOperation *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_logical_operation_finalize(GScanLogicalOperation *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réalise une comparaison entre objets selon un critère précis. */ +static bool g_scan_logical_operation_compare_rich(const GScanLogicalOperation *, const GScanLogicalOperation *, RichCmpOperation, bool *); + +/* Réduit une expression à une forme plus simple. */ +static ScanReductionState g_scan_logical_operation_reduce(const GScanLogicalOperation *, GScanContext *, GScanScope *, GScanExpression **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une opération booléenne sur expression(s). */ +G_DEFINE_TYPE(GScanLogicalOperation, g_scan_logical_operation, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des opérations booléennes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_logical_operation_class_init(GScanLogicalOperationClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_logical_operation_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_logical_operation_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)g_scan_logical_operation_compare_rich; + expr->reduce = (reduce_expr_fc)g_scan_logical_operation_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser. * +* * +* Description : Initialise une instance d'opération booléenne. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_logical_operation_init(GScanLogicalOperation *op) +{ + op->first = NULL; + op->second = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_logical_operation_dispose(GScanLogicalOperation *op) +{ + g_clear_object(&op->first); + g_clear_object(&op->second); + + G_OBJECT_CLASS(g_scan_logical_operation_parent_class)->dispose(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_logical_operation_finalize(GScanLogicalOperation *op) +{ + G_OBJECT_CLASS(g_scan_logical_operation_parent_class)->finalize(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : type = type d'opération booléenne à représenter. * +* first = premier opérande concerné. * +* second = éventuel second opérande impliqué ou NULL. * +* * +* Description : Organise un appel de fonction avec ses arguments. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_logical_operation_new(BooleanOperationType type, GScanExpression *first, GScanExpression *second) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_BOOLEAN_OPERATION, NULL); + + if (!g_scan_logical_operation_create(G_SCAN_LOGICAL_OPERATION(result), type, first, second)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = instance à initialiser pleinement. * +* type = type d'opération booléenne à représenter. * +* first = premier opérande concerné. * +* second = éventuel second opérande impliqué ou NULL. * +* * +* Description : Met en place une expression d'opération booléenne. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_logical_operation_create(GScanLogicalOperation *op, BooleanOperationType type, GScanExpression *first, GScanExpression *second) +{ + bool result; /* Bilan à retourner */ + + result = g_scan_expression_create(G_SCAN_EXPRESSION(op), SRS_PENDING); + if (!result) goto exit; + + op->type = type; + + switch (type) + { + case BOT_AND: + case BOT_OR: + op->first = first; + g_object_ref(G_OBJECT(op->first)); + + op->second = second; + g_object_ref(G_OBJECT(op->second)); + + result = true; + break; + + case BOT_NOT: + op->first = first; + g_object_ref(G_OBJECT(op->first)); + + result = (second == NULL); + assert(second == NULL); + break; + + default: + result = false; + break; + + } + + exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = premier objet à consulter pour une comparaison. * +* other = second objet à consulter pour une comparaison. * +* op = opération de comparaison à réaliser. * +* status = bilan des opérations de comparaison. [OUT] * +* * +* Description : Réalise une comparaison entre objets selon un critère précis.* +* * +* Retour : true si la comparaison a pu être effectuée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_logical_operation_compare_rich(const GScanLogicalOperation *item, const GScanLogicalOperation *other, RichCmpOperation op, bool *status) +{ + bool result; /* Etat à retourner */ + + result = g_type_is_a(G_TYPE_FROM_INSTANCE(other), G_TYPE_BOOLEAN_OPERATION); + if (!result) goto done; + + if (item->type != other->type) + { + *status = compare_rich_integer_values_unsigned(item->type, other->type, op); + goto done; + } + + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item), G_COMPARABLE_ITEM(other), RCO_EQ, status); + if (!result || STATUS_NOT_EQUAL(*status, op)) goto done; + + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->first), + G_COMPARABLE_ITEM(other->first), + op, status); + if (!result || STATUS_NOT_EQUAL(*status, op)) goto done; + + if (item->second == NULL) + { + assert(other->second == NULL); + + switch (op) + { + case RCO_LT: + case RCO_NE: + case RCO_GT: + *status = false; + break; + + case RCO_LE: + case RCO_EQ: + case RCO_GE: + *status = true; + break; + + } + + } + + else + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->second), + G_COMPARABLE_ITEM(other->second), + op, status); + + done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à 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 ScanReductionState g_scan_logical_operation_reduce(const GScanLogicalOperation *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + ScanReductionState result; /* Etat synthétisé à retourner */ + GScanExpression *new_first; /* Expression réduite (gauche) */ + ScanReductionState state[2]; /* Bilan de sous-réductons */ + GScanExpression *new_second; /* Expression réduite (droite) */ + GScanExpression *bool_operands[2]; /* Expressions booléennes */ + bool values[2]; /* Valeurs des éléments portés */ + bool valid[2]; /* Validité de ces valeurs */ + + /* Réduction des éléments considérés */ + + state[0] = g_scan_expression_reduce(expr->first, ctx, scope, &new_first); + + if (expr->second != NULL) + state[1] = g_scan_expression_reduce(expr->second, ctx, scope, &new_second); + else + { + new_second = NULL; + state[1] = SRS_REDUCED; + } + + /* Récupération des valeurs booléennes */ + + if (new_first != NULL) + { + valid[0] = g_scan_expression_reduce_to_boolean(new_first, ctx, scope, &bool_operands[0]); + + if (valid[0]) + valid[0] = g_scan_literal_expression_get_boolean_value(G_SCAN_LITERAL_EXPRESSION(bool_operands[0]), + &values[0]); + else + bool_operands[0] = NULL; + + } + else + { + bool_operands[0] = NULL; + valid[0] = false; + } + + if (new_second != NULL) + { + valid[1] = g_scan_expression_reduce_to_boolean(new_second, ctx, scope, &bool_operands[1]); + + if (valid[1]) + valid[1] = g_scan_literal_expression_get_boolean_value(G_SCAN_LITERAL_EXPRESSION(bool_operands[1]), + &values[1]); + else + bool_operands[1] = NULL; + + } + else + { + bool_operands[1] = NULL; + valid[1] = false; + } + + /* Construction d'une réduction locale ? */ + + switch (expr->type) + { + case BOT_AND: + if (valid[0] && valid[1]) + { + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { values[0] && values[1] }); + result = SRS_REDUCED; + } + + else if (valid[0] && !values[0]) + { + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { false }); + result = SRS_REDUCED; + } + + else if (valid[1] && !values[1]) + { + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { false }); + result = SRS_REDUCED; + } + + else + { + if (state[0] == SRS_UNRESOLVABLE || state[1] == SRS_UNRESOLVABLE) + result = SRS_UNRESOLVABLE; + else + { + assert(state[0] == SRS_WAIT_FOR_SCAN || state[1] == SRS_WAIT_FOR_SCAN); + result = SRS_WAIT_FOR_SCAN; + } + } + + break; + + case BOT_OR: + if (valid[0] && valid[1]) + { + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { values[0] || values[1] }); + result = SRS_REDUCED; + } + + else if (valid[0] && values[0]) + { + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { true }); + result = SRS_REDUCED; + } + + else if (valid[1] && values[1]) + { + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { true }); + result = SRS_REDUCED; + } + + else + { + if (state[0] == SRS_UNRESOLVABLE || state[1] == SRS_UNRESOLVABLE) + result = SRS_UNRESOLVABLE; + else + { + assert(state[0] == SRS_WAIT_FOR_SCAN || state[1] == SRS_WAIT_FOR_SCAN); + result = SRS_WAIT_FOR_SCAN; + } + } + + break; + + case BOT_NOT: + if (valid[0]) + { + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { !values[0] }); + result = SRS_REDUCED; + } + + else + { + if (state[0] == SRS_UNRESOLVABLE) + result = SRS_UNRESOLVABLE; + else + { + assert(state[0] == SRS_WAIT_FOR_SCAN); + result = SRS_WAIT_FOR_SCAN; + } + } + + break; + + /* Pour GCC... */ + default: + result = SRS_UNRESOLVABLE; + break; + + } + + /* Mise à jour de la progression ? */ + + if (result == SRS_WAIT_FOR_SCAN) + { + if (new_first != expr->first || new_second != expr->second) + { + assert(new_first != NULL); + assert(new_second != NULL || expr->second == NULL); + + *out = g_scan_logical_operation_new(expr->type, new_first, new_second); + + } + + } + + /* Sortie propre */ + + g_clear_object(&bool_operands[0]); + g_clear_object(&bool_operands[1]); + + g_clear_object(&new_first); + g_clear_object(&new_second); + + return result; + +} diff --git a/src/analysis/scan/exprs/logical.h b/src/analysis/scan/exprs/logical.h new file mode 100644 index 0000000..e98bf11 --- /dev/null +++ b/src/analysis/scan/exprs/logical.h @@ -0,0 +1,65 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * logical.h - prototypes pour la gestion des opérations booléennes + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_LOGICAL_H +#define _ANALYSIS_SCAN_EXPRS_LOGICAL_H + + +#include "../expr.h" + + + +#define G_TYPE_BOOLEAN_OPERATION g_scan_logical_operation_get_type() +#define G_SCAN_LOGICAL_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BOOLEAN_OPERATION, GScanLogicalOperation)) +#define G_IS_BOOLEAN_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BOOLEAN_OPERATION)) +#define G_SCAN_LOGICAL_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BOOLEAN_OPERATION, GScanLogicalOperationClass)) +#define G_IS_BOOLEAN_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BOOLEAN_OPERATION)) +#define G_SCAN_LOGICAL_OPERATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BOOLEAN_OPERATION, GScanLogicalOperationClass)) + + +/* Opération booléenne avec un ou deux opérandes (instance) */ +typedef struct _GScanLogicalOperation GScanLogicalOperation; + +/* Opération booléenne avec un ou deux opérandes (classe) */ +typedef struct _GScanLogicalOperationClass GScanLogicalOperationClass; + + +/* Types d'opérations booléennes supportées */ +typedef enum _BooleanOperationType +{ + BOT_AND, /* Opérateur binaire "and" */ + BOT_OR, /* Opérateur binaire "or" */ + BOT_NOT, /* Opérateur unaire "not" */ + +} BooleanOperationType; + + +/* Indique le type défini pour une opération booléenne sur expression(s). */ +GType g_scan_logical_operation_get_type(void); + +/* Organise un appel de fonction avec ses arguments. */ +GScanExpression *g_scan_logical_operation_new(BooleanOperationType, GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_LOGICAL_H */ diff --git a/src/analysis/scan/exprs/range-int.h b/src/analysis/scan/exprs/range-int.h new file mode 100644 index 0000000..6257874 --- /dev/null +++ b/src/analysis/scan/exprs/range-int.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * range-int.h - prototypes internes pour la représentation compacte d'un éventail de valeurs + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_RANGE_INT_H +#define _ANALYSIS_SCAN_EXPRS_RANGE_INT_H + + +#include "range.h" + + +#include "../expr-int.h" + + + +/* Représentation compacte d'un éventail de valeurs (instance) */ +struct _GScanCompactRange +{ + GScanExpression parent; /* A laisser en premier */ + + GScanExpression *start; /* Point de départ */ + GScanExpression *end; /* Point d'arrivée */ + +}; + +/* Représentation compacte d'un éventail de valeurs (classe) */ +struct _GScanCompactRangeClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une réprésentation d'un éventail de valeurs. */ +bool g_scan_compact_range_create(GScanCompactRange *, GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_RANGE_INT_H */ diff --git a/src/analysis/scan/exprs/range.c b/src/analysis/scan/exprs/range.c new file mode 100644 index 0000000..9716149 --- /dev/null +++ b/src/analysis/scan/exprs/range.c @@ -0,0 +1,355 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * range.c - représentation compacte d'un éventail de valeurs + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "range.h" + + +#include "literal.h" +#include "range-int.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des éventail de valeurs. */ +static void g_scan_compact_range_class_init(GScanCompactRangeClass *); + +/* Initialise une instance d'éventail de valeurs. */ +static void g_scan_compact_range_init(GScanCompactRange *); + +/* Supprime toutes les références externes. */ +static void g_scan_compact_range_dispose(GScanCompactRange *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_compact_range_finalize(GScanCompactRange *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réduit une expression à une forme plus simple. */ +static ScanReductionState g_scan_compact_range_reduce(const GScanCompactRange *, GScanContext *, GScanScope *, GScanExpression **); + +/* Réduit une expression à une forme booléenne. */ +static bool g_scan_compact_range_reduce_to_boolean(const GScanCompactRange *, GScanContext *, GScanScope *, GScanExpression **); + +/* Réalise l'intersection entre deux ensembles. */ +static GScanExpression *g_scan_compact_range_intersect(const GScanCompactRange *expr, const GScanExpression *, GScanContext *, GScanScope *); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une représentation compacte d'un éventail de valeurs. */ +G_DEFINE_TYPE(GScanCompactRange, g_scan_compact_range, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des éventail de valeurs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_compact_range_class_init(GScanCompactRangeClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_compact_range_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_compact_range_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->reduce = (reduce_expr_fc)g_scan_compact_range_reduce; + expr->reduce_to_bool = (reduce_expr_to_bool_fc)g_scan_compact_range_reduce_to_boolean; + expr->intersect = (intersect_scan_expr_fc)g_scan_compact_range_intersect; + +} + + +/****************************************************************************** +* * +* Paramètres : range = instance à initialiser. * +* * +* Description : Initialise une instance d'éventail de valeurs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_compact_range_init(GScanCompactRange *range) +{ + range->start = NULL; + range->end = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : range = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_compact_range_dispose(GScanCompactRange *range) +{ + g_clear_object(&range->start); + g_clear_object(&range->end); + + G_OBJECT_CLASS(g_scan_compact_range_parent_class)->dispose(G_OBJECT(range)); + +} + + +/****************************************************************************** +* * +* Paramètres : range = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_compact_range_finalize(GScanCompactRange *range) +{ + G_OBJECT_CLASS(g_scan_compact_range_parent_class)->finalize(G_OBJECT(range)); + +} + + +/****************************************************************************** +* * +* Paramètres : start = point de départ de la plage de valeurs. * +* end = point d'arrivée de la plage de valeurs. * +* * +* Description : Organise une réprésentation d'un éventail de valeurs. * +* * +* Retour : Expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_compact_range_new(GScanExpression *start, GScanExpression *end) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_COMPACT_RANGE, NULL); + + if (!g_scan_compact_range_create(G_SCAN_COMPACT_RANGE(result), start, end)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : range = instance à initialiser pleinement. * +* start = point de départ de la plage de valeurs. * +* end = point d'arrivée de la plage de valeurs. * +* * +* Description : Met en place une réprésentation d'un éventail de valeurs. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_compact_range_create(GScanCompactRange *range, GScanExpression *start, GScanExpression *end) +{ + bool result; /* Bilan à retourner */ + + result = g_scan_expression_create(G_SCAN_EXPRESSION(range), SRS_PENDING); + if (!result) goto exit; + + range->start = start; + g_object_ref(G_OBJECT(start)); + + range->end = end; + g_object_ref(G_OBJECT(end)); + + exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : expr = expression à 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 ScanReductionState g_scan_compact_range_reduce(const GScanCompactRange *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + ScanReductionState result; /* Etat synthétisé à retourner */ + GScanExpression *new_start; /* Nouvelle réduction #1 */ + GScanExpression *new_end; /* Nouvelle réduction #2 */ + ScanReductionState state_start; /* Etat synthétisé #1 */ + ScanReductionState state_end; /* Etat synthétisé #2 */ + + new_start = NULL; + new_end = NULL; + + state_start = g_scan_expression_reduce(expr->start, ctx, scope, &new_start); + if (state_start == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + state_end = g_scan_expression_reduce(expr->end, ctx, scope, &new_end); + if (state_end == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + if (state_start == SRS_WAIT_FOR_SCAN || state_end == SRS_WAIT_FOR_SCAN) + result = SRS_WAIT_FOR_SCAN; + else + result = SRS_REDUCED; + + if (new_start != expr->start || new_end != expr->end) + *out = g_scan_compact_range_new(new_start, new_end); + + exit: + + g_clear_object(&new_start); + g_clear_object(&new_end); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à 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 booléenne. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_compact_range_reduce_to_boolean(const GScanCompactRange *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + bool result; /* Bilan à retourner */ + bool status; /* Bilan d'une comparaison */ + + result = G_IS_SCAN_LITERAL_EXPRESSION(expr->start) && G_IS_SCAN_LITERAL_EXPRESSION(expr->end); + if (!result) goto exit; + + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(expr->start), + G_COMPARABLE_ITEM(expr->end), + RCO_LE, &status); + if (!result) goto exit; + + *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à filtrer. * +* other = expression utilisée pour le filtrage. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* * +* Description : Réalise l'intersection entre deux ensembles. * +* * +* Retour : Intersection entre les deux ensembles ou NULL en cas d'échec.* +* * +* Remarques : - * +* * +******************************************************************************/ + +static GScanExpression *g_scan_compact_range_intersect(const GScanCompactRange *expr, const GScanExpression *other, GScanContext *ctx, GScanScope *scope) +{ + GScanExpression *result; /* Instance à retourner */ + + + + + result = true; // TODO + + + + + return result; + +} diff --git a/src/analysis/scan/exprs/range.h b/src/analysis/scan/exprs/range.h new file mode 100644 index 0000000..4b7ad04 --- /dev/null +++ b/src/analysis/scan/exprs/range.h @@ -0,0 +1,55 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * range.h - prototypes pour la représentation compacte d'un éventail de valeurs + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_SET_H +#define _ANALYSIS_SCAN_EXPRS_SET_H + + +#include "../expr.h" + + + +#define G_TYPE_SCAN_COMPACT_RANGE g_scan_compact_range_get_type() +#define G_SCAN_COMPACT_RANGE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_COMPACT_RANGE, GScanCompactRange)) +#define G_IS_SCAN_COMPACT_RANGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_COMPACT_RANGE)) +#define G_SCAN_COMPACT_RANGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_COMPACT_RANGE, GScanCompactRangeClass)) +#define G_IS_SCAN_COMPACT_RANGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_COMPACT_RANGE)) +#define G_SCAN_COMPACT_RANGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_COMPACT_RANGE, GScanCompactRangeClass)) + + +/* Représentation compacte d'un éventail de valeurs (instance) */ +typedef struct _GScanCompactRange GScanCompactRange; + +/* Représentation compacte d'un éventail de valeurs (classe) */ +typedef struct _GScanCompactRangeClass GScanCompactRangeClass; + + +/* Indique le type défini pour une représentation compacte d'un éventail de valeurs. */ +GType g_scan_compact_range_get_type(void); + +/* Organise une réprésentation d'un éventail de valeurs. */ +GScanExpression *g_scan_compact_range_new(GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_SET_H */ diff --git a/src/analysis/scan/exprs/relational-int.h b/src/analysis/scan/exprs/relational-int.h new file mode 100644 index 0000000..813b89d --- /dev/null +++ b/src/analysis/scan/exprs/relational-int.h @@ -0,0 +1,60 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * relational-int.h - prototypes internes pour la gestion des opérations relationnelles + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_RELATIONAL_INT_H +#define _ANALYSIS_SCAN_EXPRS_RELATIONAL_INT_H + + +#include "relational.h" + + +#include "../expr-int.h" + + + +/* Opération relationnelle impliquant deux opérandes (instance) */ +struct _GScanRelationalOperation +{ + GScanExpression parent; /* A laisser en premier */ + + RichCmpOperation rel_type; /* Type de relation étudiée */ + + GScanExpression *left; /* Expression impactée #1 */ + GScanExpression *right; /* Expression impactée #2 */ + +}; + +/* Opération relationnelle impliquant deux opérandes (classe) */ +struct _GScanRelationalOperationClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une opération relationnelle entre expressions. */ +bool g_scan_relational_operation_create(GScanRelationalOperation *, RichCmpOperation, GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_RELATIONAL_INT_H */ diff --git a/src/analysis/scan/exprs/relational.c b/src/analysis/scan/exprs/relational.c new file mode 100644 index 0000000..74a972b --- /dev/null +++ b/src/analysis/scan/exprs/relational.c @@ -0,0 +1,411 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * relational.c - gestion des opérations relationnelles + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "relational.h" + + +#include <assert.h> + + +#include "relational-int.h" +#include "literal.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des opérations de relations. */ +static void g_scan_relational_operation_class_init(GScanRelationalOperationClass *); + +/* Initialise une instance d'opération de relation. */ +static void g_scan_relational_operation_init(GScanRelationalOperation *); + +/* Supprime toutes les références externes. */ +static void g_scan_relational_operation_dispose(GScanRelationalOperation *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_relational_operation_finalize(GScanRelationalOperation *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réalise une comparaison entre objets selon un critère précis. */ +static bool g_scan_relational_operation_compare_rich(const GScanRelationalOperation *, const GScanRelationalOperation *, RichCmpOperation, bool *); + +/* Réduit une expression à une forme plus simple. */ +static ScanReductionState g_scan_relational_operation_reduce(const GScanRelationalOperation *, GScanContext *, GScanScope *, GScanExpression **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une opération de relation entre expressions. */ +G_DEFINE_TYPE(GScanRelationalOperation, g_scan_relational_operation, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des opérations de relations. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_relational_operation_class_init(GScanRelationalOperationClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_relational_operation_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_relational_operation_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)g_scan_relational_operation_compare_rich; + expr->reduce = (reduce_expr_fc)g_scan_relational_operation_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser. * +* * +* Description : Initialise une instance d'opération de relation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_relational_operation_init(GScanRelationalOperation *op) +{ + op->left = NULL; + op->right = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_relational_operation_dispose(GScanRelationalOperation *op) +{ + g_clear_object(&op->left); + g_clear_object(&op->right); + + G_OBJECT_CLASS(g_scan_relational_operation_parent_class)->dispose(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_relational_operation_finalize(GScanRelationalOperation *op) +{ + G_OBJECT_CLASS(g_scan_relational_operation_parent_class)->finalize(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : type = type d'opération booléenne à représenter. * +* left = premier opérande concerné. * +* right = éventuel second opérande impliqué ou NULL. * +* * +* Description : Organise une opération relationnelle entre expressions. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_relational_operation_new(RichCmpOperation type, GScanExpression *left, GScanExpression *right) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_RELATIONAL_OPERATION, NULL); + + if (!g_scan_relational_operation_create(G_SCAN_RELATIONAL_OPERATION(result), type, left, right)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser pleinement. * +* type = type d'opération booléenne à représenter. * +* left = premier opérande concerné. * +* right = éventuel second opérande impliqué ou NULL. * +* * +* Description : Met en place une opération relationnelle entre expressions. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_relational_operation_create(GScanRelationalOperation *op, RichCmpOperation type, GScanExpression *left, GScanExpression *right) +{ + bool result; /* Bilan à retourner */ + + result = g_scan_expression_create(G_SCAN_EXPRESSION(op), SRS_PENDING); + if (!result) goto exit; + + op->rel_type = type; + + op->left = left; + g_object_ref(G_OBJECT(op->left)); + + op->right = right; + g_object_ref(G_OBJECT(op->right)); + + exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = premier objet à consulter pour une comparaison. * +* other = second objet à consulter pour une comparaison. * +* op = opération de comparaison à réaliser. * +* status = bilan des opérations de comparaison. [OUT] * +* * +* Description : Réalise une comparaison entre objets selon un critère précis.* +* * +* Retour : true si la comparaison a pu être effectuée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_relational_operation_compare_rich(const GScanRelationalOperation *item, const GScanRelationalOperation *other, RichCmpOperation op, bool *status) +{ + bool result; /* Etat à retourner */ + + result = g_type_is_a(G_TYPE_FROM_INSTANCE(other), G_TYPE_SCAN_RELATIONAL_OPERATION); + if (!result) goto done; + + if (item->rel_type != other->rel_type) + { + *status = compare_rich_integer_values_unsigned(item->rel_type, other->rel_type, op); + goto done; + } + + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item), G_COMPARABLE_ITEM(other), RCO_EQ, status); + if (!result || STATUS_NOT_EQUAL(*status, op)) goto done; + + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->left), + G_COMPARABLE_ITEM(other->left), + op, status); + if (!result || STATUS_NOT_EQUAL(*status, op)) goto done; + + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->right), + G_COMPARABLE_ITEM(other->right), + op, status); + + done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à 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 ScanReductionState g_scan_relational_operation_reduce(const GScanRelationalOperation *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + ScanReductionState result; /* Etat synthétisé à retourner */ + GScanExpression *new_left; /* Expression réduite (gauche) */ + GScanExpression *new_right; /* Expression réduite (droite) */ + ScanReductionState state_left; /* Etat synthétisé #1 */ + ScanReductionState state_right; /* Etat synthétisé #2 */ + LiteralValueType vtype_left; /* Type de valeur portée #1 */ + LiteralValueType vtype_right; /* Type de valeur portée #2 */ + GScanExpression *casted; /* Nouvelle forme en booléen */ + bool status; /* Bilan d'une comparaison */ + bool valid; /* Validité de ce bilan obtenu */ + + /* Réduction des éléments considérés */ + + new_left = NULL; + new_right = NULL; + + state_left = g_scan_expression_reduce(expr->left, ctx, scope, &new_left); + if (state_left == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + state_right = g_scan_expression_reduce(expr->right, ctx, scope, &new_right); + if (state_right == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + /* Transtypage vers des booléens imposé ? */ + + if (expr->rel_type == RCO_EQ || expr->rel_type == RCO_NE) + { + if (G_IS_SCAN_LITERAL_EXPRESSION(new_left)) + { + vtype_left = g_scan_literal_expression_get_value_type(G_SCAN_LITERAL_EXPRESSION(new_left)); + + if (vtype_left == LVT_BOOLEAN) + { + if (g_scan_expression_reduce_to_boolean(new_right, ctx, scope, &casted)) + { + g_object_unref(G_OBJECT(new_right)); + new_right = casted; + } + } + + } + + if (G_IS_SCAN_LITERAL_EXPRESSION(new_right)) + { + vtype_right = g_scan_literal_expression_get_value_type(G_SCAN_LITERAL_EXPRESSION(new_right)); + + if (vtype_right == LVT_BOOLEAN) + { + if (g_scan_expression_reduce_to_boolean(new_left, ctx, scope, &casted)) + { + g_object_unref(G_OBJECT(new_left)); + new_left = casted; + } + } + + } + + } + + /* Construction d'une réduction locale ? */ + + if (G_IS_SCAN_LITERAL_EXPRESSION(new_left) && G_IS_SCAN_LITERAL_EXPRESSION(new_right)) + { + valid = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(new_left), + G_COMPARABLE_ITEM(new_right), + expr->rel_type, &status); + + if (valid) + { + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { status }); + result = SRS_REDUCED; + } + else + result = SRS_UNRESOLVABLE; + + } + + /* Mise à jour de la progression ? */ + + else if (state_left == SRS_WAIT_FOR_SCAN || state_right == SRS_WAIT_FOR_SCAN) + { + if (new_left != expr->left || new_right != expr->right) + *out = g_scan_relational_operation_new(expr->rel_type, new_left, new_right); + + result = SRS_WAIT_FOR_SCAN; + + } + + /* Cas des situations où les expressions ne sont pas exploitables (!) */ + else + { + assert(state_left == SRS_REDUCED && state_right == SRS_REDUCED); + + result = SRS_UNRESOLVABLE; + + } + + /* Sortie propre */ + + exit: + + g_clear_object(&new_left); + g_clear_object(&new_right); + + return result; + +} diff --git a/src/analysis/scan/exprs/relational.h b/src/analysis/scan/exprs/relational.h new file mode 100644 index 0000000..10d58a6 --- /dev/null +++ b/src/analysis/scan/exprs/relational.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * relational.h - prototypes pour la gestion des opérations relationnelles + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_RELATIONAL_H +#define _ANALYSIS_SCAN_EXPRS_RELATIONAL_H + + +#include "../expr.h" +#include "../../../glibext/comparison.h" + + + +#define G_TYPE_SCAN_RELATIONAL_OPERATION g_scan_relational_operation_get_type() +#define G_SCAN_RELATIONAL_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_RELATIONAL_OPERATION, GScanRelationalOperation)) +#define G_IS_SCAN_RELATIONAL_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_RELATIONAL_OPERATION)) +#define G_SCAN_RELATIONAL_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_RELATIONAL_OPERATION, GScanRelationalOperationClass)) +#define G_IS_SCAN_RELATIONAL_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_RELATIONAL_OPERATION)) +#define G_SCAN_RELATIONAL_OPERATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_RELATIONAL_OPERATION, GScanRelationalOperationClass)) + + +/* Opération relationnelle impliquant deux opérandes (instance) */ +typedef struct _GScanRelationalOperation GScanRelationalOperation; + +/* Opération relationnelle impliquant deux opérandes (classe) */ +typedef struct _GScanRelationalOperationClass GScanRelationalOperationClass; + + +/* Indique le type défini pour une opération de relation entre expressions. */ +GType g_scan_relational_operation_get_type(void); + +/* Organise une opération relationnelle entre expressions. */ +GScanExpression *g_scan_relational_operation_new(RichCmpOperation, GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_RELATIONAL_H */ diff --git a/src/analysis/scan/exprs/set-int.h b/src/analysis/scan/exprs/set-int.h new file mode 100644 index 0000000..10ca8d0 --- /dev/null +++ b/src/analysis/scan/exprs/set-int.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * set-int.h - prototypes internes pour la base d'ensembles de valeurs diverses, de types hétérogènes ou homogènes + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_SET_INT_H +#define _ANALYSIS_SCAN_EXPRS_SET_INT_H + + +#include "set.h" + + +#include "../expr-int.h" + + + +/* Base d'un ensemble d'éléments homogènes ou hétérogènes (instance) */ +struct _GScanGenericSet +{ + GScanExpression parent; /* A laisser en premier */ + + GScanExpression **items; /* Liste d'éléments embarqués */ + size_t count; /* Quantité de ces éléments */ + +}; + +/* Base d'un ensemble d'éléments homogènes ou hétérogènes (classe) */ +struct _GScanGenericSetClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un ensemble d'éléments homogènes ou hétérogènes. */ +bool g_scan_generic_set_create(GScanGenericSet *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_SET_INT_H */ diff --git a/src/analysis/scan/exprs/set.c b/src/analysis/scan/exprs/set.c new file mode 100644 index 0000000..438e7e3 --- /dev/null +++ b/src/analysis/scan/exprs/set.c @@ -0,0 +1,407 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * set.c - base d'ensembles de valeurs diverses, de types hétérogènes ou homogènes + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "set.h" + + +#include <assert.h> +#include <malloc.h> + + +#include "literal.h" +#include "set-int.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des bases d'ensembles d'éléments. */ +static void g_scan_generic_set_class_init(GScanGenericSetClass *); + +/* Initialise une instance de base d'ensemble d'éléments. */ +static void g_scan_generic_set_init(GScanGenericSet *); + +/* Supprime toutes les références externes. */ +static void g_scan_generic_set_dispose(GScanGenericSet *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_generic_set_finalize(GScanGenericSet *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réduit une expression à une forme plus simple. */ +static ScanReductionState g_scan_generic_set_reduce(const GScanGenericSet *, GScanContext *, GScanScope *, GScanExpression **); + +/* Réduit une expression à une forme booléenne. */ +static bool g_scan_generic_set_reduce_to_boolean(const GScanGenericSet *, GScanContext *, GScanScope *, GScanExpression **); + +/* Dénombre les éléments portés par une expression. */ +static bool g_scan_generic_set_count_items(const GScanGenericSet *, GScanContext *, size_t *); + +/* Fournit un élément donné issu d'un ensemble constitué. */ +static bool g_scan_generic_set_get_item(const GScanGenericSet *, size_t, GScanContext *, GScanExpression **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une base d'ensembles d'éléments homogènes ou hétérogènes. */ +G_DEFINE_TYPE(GScanGenericSet, g_scan_generic_set, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des bases d'ensembles d'éléments. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_generic_set_class_init(GScanGenericSetClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_generic_set_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_generic_set_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->reduce = (reduce_expr_fc)g_scan_generic_set_reduce; + expr->reduce_to_bool = (reduce_expr_to_bool_fc)g_scan_generic_set_reduce_to_boolean; + expr->count = (count_scan_expr_fc)g_scan_generic_set_count_items; + expr->get = (get_scan_expr_fc)g_scan_generic_set_get_item; + +} + + +/****************************************************************************** +* * +* Paramètres : set = instance à initialiser. * +* * +* Description : Initialise une instance de base d'ensemble d'éléments. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_generic_set_init(GScanGenericSet *set) +{ + set->items = NULL; + set->count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : set = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_generic_set_dispose(GScanGenericSet *set) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < set->count; i++) + g_clear_object(&set->items[i]); + + G_OBJECT_CLASS(g_scan_generic_set_parent_class)->dispose(G_OBJECT(set)); + +} + + +/****************************************************************************** +* * +* Paramètres : set = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_generic_set_finalize(GScanGenericSet *set) +{ + if (set->items != NULL) + free(set->items); + + G_OBJECT_CLASS(g_scan_generic_set_parent_class)->finalize(G_OBJECT(set)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Constitue un ensemble d'éléments homogènes ou hétérogènes. * +* * +* Retour : Expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_generic_set_new(void) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_GENERIC_SET, NULL); + + if (!g_scan_generic_set_create(G_SCAN_GENERIC_SET(result))) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : set = instance à initialiser pleinement. * +* * +* Description : Met en place un ensemble d'éléments homogènes ou hétérogènes.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_generic_set_create(GScanGenericSet *set) +{ + bool result; /* Bilan à retourner */ + + result = g_scan_expression_create(G_SCAN_EXPRESSION(set), SRS_PENDING); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : set = ensemble à compléter. * +* item = nouvel élément à intégrer. * +* * +* Description : Ajoute un nouvel élément à un ensemble. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_generic_set_add_item(GScanGenericSet *set, GScanExpression *item) +{ + set->items = realloc(set->items, ++set->count * sizeof(GScanExpression *)); + + set->items[set->count - 1] = item; + g_object_ref(G_OBJECT(item)); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : expr = expression à 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 ScanReductionState g_scan_generic_set_reduce(const GScanGenericSet *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + ScanReductionState result; /* Etat synthétisé à retourner */ + size_t i; /* Boucle de parcours #1 */ + GScanExpression *item; /* Elément en cours d'analyse */ + GScanExpression *new; /* Nouvelle réduction obtenue */ + ScanReductionState state; /* Etat synthétisé d'un élément*/ + size_t k; /* Boucle de parcours #2 */ + + result = SRS_REDUCED; + + for (i = 0; i < expr->count; i++) + { + item = expr->items[i]; + + state = g_scan_expression_reduce(item, ctx, scope, &new); + if (state == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + g_clear_object(out); + break; + } + + if (state == SRS_WAIT_FOR_SCAN) + result = SRS_WAIT_FOR_SCAN; + + if (new != item) + { + if (*out == NULL) + { + *out = g_scan_generic_set_new(); + + for (k = 0; k < i; k++) + g_scan_generic_set_add_item(G_SCAN_GENERIC_SET(*out), expr->items[k]); + + } + + g_scan_generic_set_add_item(G_SCAN_GENERIC_SET(*out), new); + + } + + else + { + if (*out != NULL) + g_scan_generic_set_add_item(G_SCAN_GENERIC_SET(*out), item); + } + + g_object_unref(G_OBJECT(new)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à 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 booléenne. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_generic_set_reduce_to_boolean(const GScanGenericSet *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + bool result; /* Bilan à retourner */ + + result = true; + + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ expr->count > 0 }); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* count = quantité d'éléments déterminée. [OUT] * +* * +* Description : Dénombre les éléments portés par une expression. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_generic_set_count_items(const GScanGenericSet *expr, GScanContext *ctx, size_t *count) +{ + bool result; /* Bilan à retourner */ + + result = true; + + *count = expr->count; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* index = indice de l'élément à transférer. * +* ctx = contexte de suivi de l'analyse courante. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * +* * +* Description : Fournit un élément donné issu d'un ensemble constitué. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_generic_set_get_item(const GScanGenericSet *expr, size_t index, GScanContext *ctx, GScanExpression **out) +{ + bool result; /* Bilan à retourner */ + + result = (index < expr->count); + + if (result) + *out = expr->items[index]; + + return result; + +} diff --git a/src/analysis/scan/exprs/set.h b/src/analysis/scan/exprs/set.h new file mode 100644 index 0000000..c9fb3b3 --- /dev/null +++ b/src/analysis/scan/exprs/set.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * set.h - prototypes pour la base d'ensembles de valeurs diverses, de types hétérogènes ou homogènes + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_SET_H +#define _ANALYSIS_SCAN_EXPRS_SET_H + + +#include "../expr.h" + + + +#define G_TYPE_SCAN_GENERIC_SET g_scan_generic_set_get_type() +#define G_SCAN_GENERIC_SET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_GENERIC_SET, GScanGenericSet)) +#define G_IS_SCAN_GENERIC_SET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_GENERIC_SET)) +#define G_SCAN_GENERIC_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_GENERIC_SET, GScanGenericSetClass)) +#define G_IS_SCAN_GENERIC_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_GENERIC_SET)) +#define G_SCAN_GENERIC_SET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_GENERIC_SET, GScanGenericSetClass)) + + +/* Base d'un ensemble d'éléments homogènes ou hétérogènes (instance) */ +typedef struct _GScanGenericSet GScanGenericSet; + +/* Base d'un ensemble d'éléments homogènes ou hétérogènes (classe) */ +typedef struct _GScanGenericSetClass GScanGenericSetClass; + + +/* Indique le type défini pour une base d'ensembles d'éléments homogènes ou hétérogènes. */ +GType g_scan_generic_set_get_type(void); + +/* Constitue un ensemble d'éléments homogènes ou hétérogènes. */ +GScanExpression *g_scan_generic_set_new(void); + +/* Ajoute un nouvel élément à un ensemble. */ +void g_scan_generic_set_add_item(GScanGenericSet *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_SET_H */ diff --git a/src/analysis/scan/exprs/setcounter-int.h b/src/analysis/scan/exprs/setcounter-int.h new file mode 100644 index 0000000..c9e3da5 --- /dev/null +++ b/src/analysis/scan/exprs/setcounter-int.h @@ -0,0 +1,69 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * setcounter-int.h - prototypes internes pour le décompte global de correspondances locales + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_SETCOUNTER_INT_H +#define _ANALYSIS_SCAN_EXPRS_SETCOUNTER_INT_H + + +#include "setcounter.h" + + +#include "../expr-int.h" + + + +/* Décompte global de correspondances locales (instance) */ +struct _GScanSetMatchCounter +{ + GScanExpression parent; /* A laisser en premier */ + + union + { + const GSearchPattern **patterns; /* Motifs associés */ + GSearchPattern **ref_patterns; /* Motifs associés */ + }; + size_t count; /* Nombre de ces motifs */ + bool shared; /* Définition de propriété */ + + ScanSetCounterType type; /* Type de décompte */ + size_t number; /* Eventuel volume associé */ + +}; + +/* Décompte global de correspondances locales (classe) */ +struct _GScanSetMatchCounterClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un décompte de motifs avec correspondances. */ +bool g_scan_set_match_counter_create_shared(GScanSetMatchCounter *, const GSearchPattern ** const, size_t); + +/* Met en place un décompte de motifs avec correspondances. */ +bool g_scan_set_match_counter_create_and_ref(GScanSetMatchCounter *, GSearchPattern ** const, size_t); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_SETCOUNTER_INT_H */ diff --git a/src/analysis/scan/exprs/setcounter.c b/src/analysis/scan/exprs/setcounter.c new file mode 100644 index 0000000..bed315e --- /dev/null +++ b/src/analysis/scan/exprs/setcounter.c @@ -0,0 +1,477 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * setcounter.c - décompte global de correspondances locales + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "setcounter.h" + + +#include <assert.h> +#include <string.h> + + +#include "setcounter-int.h" +#include "literal.h" + + + +/* --------------------- INSTANCIATION D'UNE FORME DE CONDITION --------------------- */ + + +/* Initialise la classe des opérations booléennes. */ +static void g_scan_set_match_counter_class_init(GScanSetMatchCounterClass *); + +/* Initialise une instance d'opération booléenne. */ +static void g_scan_set_match_counter_init(GScanSetMatchCounter *); + +/* Supprime toutes les références externes. */ +static void g_scan_set_match_counter_dispose(GScanSetMatchCounter *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_set_match_counter_finalize(GScanSetMatchCounter *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réduit une expression à une forme plus simple. */ +static ScanReductionState g_scan_set_match_counter_reduce(const GScanSetMatchCounter *, GScanContext *, GScanScope *, GScanExpression **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INSTANCIATION D'UNE FORME DE CONDITION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un décompte de résultats lors d'une recherche de motifs. */ +G_DEFINE_TYPE(GScanSetMatchCounter, g_scan_set_match_counter, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des opérations booléennes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_set_match_counter_class_init(GScanSetMatchCounterClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_set_match_counter_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_set_match_counter_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)NULL; + expr->reduce = (reduce_expr_fc)g_scan_set_match_counter_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser. * +* * +* Description : Initialise une instance d'opération booléenne. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_set_match_counter_init(GScanSetMatchCounter *counter) +{ + counter->patterns = NULL; + counter->count = 0; + counter->shared = true; + + counter->type = SSCT_NONE; + counter->number = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_set_match_counter_dispose(GScanSetMatchCounter *counter) +{ + size_t i; /* Boucle de parcours */ + + if (!counter->shared) + for (i = 0; i < counter->count; i++) + g_clear_object(&counter->ref_patterns[i]); + + G_OBJECT_CLASS(g_scan_set_match_counter_parent_class)->dispose(G_OBJECT(counter)); + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_set_match_counter_finalize(GScanSetMatchCounter *counter) +{ + if (counter->patterns != NULL) + free(counter->patterns); + + G_OBJECT_CLASS(g_scan_set_match_counter_parent_class)->finalize(G_OBJECT(counter)); + +} + + +/****************************************************************************** +* * +* Paramètres : patterns = motifs à impliquer. * +* count = quantité de ces motifs. * +* * +* Description : Constitue un décompte de motifs avec correspondances. * +* * +* Retour : Expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_set_match_counter_new_shared(const GSearchPattern ** const patterns, size_t count) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_SET_MATCH_COUNTER, NULL); + + if (!g_scan_set_match_counter_create_shared(G_SCAN_SET_MATCH_COUNTER(result), patterns, count)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : counter = instance à initialiser pleinement. * +* patterns = motifs à impliquer. * +* count = quantité de ces motifs. * +* * +* Description : Met en place un décompte de motifs avec correspondances. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_set_match_counter_create_shared(GScanSetMatchCounter *counter, const GSearchPattern ** const patterns, size_t count) +{ + bool result; /* Bilan à retourner */ + + result = g_scan_expression_create(G_SCAN_EXPRESSION(counter), SRS_WAIT_FOR_SCAN); + if (!result) goto exit; + + counter->patterns = malloc(count * sizeof(GSearchPattern *)); + counter->count = count; + + memcpy(counter->patterns, patterns, count * sizeof(GSearchPattern *)); + + counter->shared = true; + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : patterns = motifs à impliquer. * +* count = quantité de ces motifs. * +* * +* Description : Constitue un décompte de motifs avec correspondances. * +* * +* Retour : Expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_set_match_counter_new(GSearchPattern ** const patterns, size_t count) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_SET_MATCH_COUNTER, NULL); + + if (!g_scan_set_match_counter_create_and_ref(G_SCAN_SET_MATCH_COUNTER(result), patterns, count)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : counter = instance à initialiser pleinement. * +* patterns = motifs à impliquer. * +* count = quantité de ces motifs. * +* * +* Description : Met en place un décompte de motifs avec correspondances. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_set_match_counter_create_and_ref(GScanSetMatchCounter *counter, GSearchPattern ** const patterns, size_t count) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + + result = g_scan_expression_create(G_SCAN_EXPRESSION(counter), SRS_WAIT_FOR_SCAN); + if (!result) goto exit; + + counter->patterns = malloc(count * sizeof(GSearchPattern *)); + counter->count = count; + + memcpy(counter->patterns, patterns, count * sizeof(GSearchPattern *)); + + for (i = 0; i < count; i++) + g_object_ref(G_OBJECT(patterns[i])); + + counter->shared = false; + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : counter = décompte à compléter. * +* patterns = motifs à impliquer. * +* count = quantité de ces motifs. * +* * +* Description : Ajoute de nouveaux motifs à un ensemble à décompter. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_set_match_counter_add_extra_shared_patterns(GScanSetMatchCounter *counter, const GSearchPattern ** const patterns, size_t count) +{ + size_t first; /* Premier emplacement libre */ + + assert(counter->shared); + + first = counter->count; + + counter->count += count; + counter->patterns = realloc(counter->patterns, counter->count * sizeof(GSearchPattern *)); + + memcpy(counter->patterns + first, patterns, count * sizeof(GSearchPattern *)); + +} + + +/****************************************************************************** +* * +* Paramètres : counter = décompte à compléter. * +* patterns = motifs à impliquer. * +* count = quantité de ces motifs. * +* * +* Description : Ajoute de nouveaux motifs à un ensemble à décompter. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_set_match_counter_add_and_ref_extra_patterns(GScanSetMatchCounter *counter, GSearchPattern ** const patterns, size_t count) +{ + size_t first; /* Premier emplacement libre */ + size_t i; /* Boucle de parcours */ + + assert(!counter->shared); + + first = counter->count; + + counter->count += count; + counter->patterns = realloc(counter->patterns, counter->count * sizeof(GSearchPattern *)); + + memcpy(counter->patterns + first, patterns, count * sizeof(GSearchPattern *)); + + for (i = 0; i < count; i++) + g_object_ref(G_OBJECT(patterns[i])); + +} + + +/****************************************************************************** +* * +* Paramètres : counter = décompte à configurer. * +* type = type de décompte à considérer. * +* number = volume minimal de motifs avec correspondances. * +* * +* Description : Précise le volume de motifs avec correspondances à retrouver.* +* * +* Retour : Bilan de validité des arguments fournis. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_set_match_counter_define_expected_matches(GScanSetMatchCounter *counter, ScanSetCounterType type, size_t *number) +{ + bool result; /* Bilan à retourner */ + + counter->type = type; + + if (type == SSCT_NUMBER) + { + counter->number = *number; + result = (counter->number <= counter->count); + } + else + result = true; + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : expr = expression à 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 ScanReductionState g_scan_set_match_counter_reduce(const GScanSetMatchCounter *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + ScanReductionState result; /* Etat synthétisé à retourner */ + size_t matched; /* Qté de motifs avec résultats*/ + size_t i; /* Boucle de parcours */ + GScanMatches *matches; /* Série de correspondances */ + size_t count; /* Quantité de correspondances */ + bool status; /* Bilan d'évaluation finale */ + + if (g_scan_context_is_scan_done(ctx)) + { + matched = 0; + + for (i = 0; i < expr->count; i++) + { + matches = g_scan_context_get_full_matches(ctx, expr->patterns[i]); + + if (matches != NULL) + { + count = g_scan_matches_count(matches); + + if (count > 0) + matched++; + + g_object_unref(G_OBJECT(matches)); + + } + + } + + switch (expr->type) + { + case SSCT_NONE: + status = (matched == 0); + break; + + case SSCT_ANY: + status = (matched >= 1); + break; + + case SSCT_ALL: + status = (matched == expr->count); + break; + + case SSCT_NUMBER: + status = (matched >= expr->number); + break; + + } + + *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status); + + result = SRS_REDUCED; + + } + else + result = SRS_WAIT_FOR_SCAN; + + return result; + +} diff --git a/src/analysis/scan/exprs/setcounter.h b/src/analysis/scan/exprs/setcounter.h new file mode 100644 index 0000000..28c92b4 --- /dev/null +++ b/src/analysis/scan/exprs/setcounter.h @@ -0,0 +1,81 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * setcounter.h - prototypes pour le décompte global de correspondances locales + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_SETCOUNTER_H +#define _ANALYSIS_SCAN_EXPRS_SETCOUNTER_H + + +#include <glib-object.h> + + +#include "../expr.h" +#include "../pattern.h" + + + +#define G_TYPE_SCAN_SET_MATCH_COUNTER g_scan_set_match_counter_get_type() +#define G_SCAN_SET_MATCH_COUNTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_SET_MATCH_COUNTER, GScanSetMatchCounter)) +#define G_IS_SCAN_SET_MATCH_COUNTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_SET_MATCH_COUNTER)) +#define G_SCAN_SET_MATCH_COUNTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_SET_MATCH_COUNTER, GScanSetMatchCounterClass)) +#define G_IS_SCAN_SET_MATCH_COUNTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_SET_MATCH_COUNTER)) +#define G_SCAN_SET_MATCH_COUNTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_SET_MATCH_COUNTER, GScanSetMatchCounterClass)) + + +/* Décompte global de correspondances locales (instance) */ +typedef struct _GScanSetMatchCounter GScanSetMatchCounter; + +/* Décompte global de correspondances locales (classe) */ +typedef struct _GScanSetMatchCounterClass GScanSetMatchCounterClass; + + +/* Indique le type défini pour un décompte de résultats lors d'une recherche de motifs. */ +GType g_scan_set_match_counter_get_type(void); + +/* Met en place un décompte de correspondances obtenues. */ +GScanExpression *g_scan_set_match_counter_new_shared(const GSearchPattern ** const, size_t); + +/* Met en place un décompte de correspondances obtenues. */ +GScanExpression *g_scan_set_match_counter_new(GSearchPattern ** const, size_t); + +/* Ajoute de nouveaux motifs à un ensemble à décompter. */ +void g_scan_set_match_counter_add_extra_shared_patterns(GScanSetMatchCounter *, const GSearchPattern ** const, size_t); + +/* Ajoute de nouveaux motifs à un ensemble à décompter. */ +void g_scan_set_match_counter_add_and_ref_extra_patterns(GScanSetMatchCounter *, GSearchPattern ** const, size_t); + +/* Formes de volume de correspondances */ +typedef enum _ScanSetCounterType +{ + SSCT_NONE, /* Aucun motif avec résultats */ + SSCT_ANY, /* Au moins un motif trouvé */ + SSCT_ALL, /* Tous les motifs présents */ + SSCT_NUMBER, /* Au moins n motifs avec rés. */ + +} ScanSetCounterType; + +/* Précise le volume de motifs avec correspondances à retrouver. */ +bool g_scan_set_match_counter_define_expected_matches(GScanSetMatchCounter *, ScanSetCounterType, size_t *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_SETCOUNTER_H */ diff --git a/src/analysis/scan/exprs/strop-int.h b/src/analysis/scan/exprs/strop-int.h new file mode 100644 index 0000000..c2b40cf --- /dev/null +++ b/src/analysis/scan/exprs/strop-int.h @@ -0,0 +1,62 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * strop-int.h - prototypes internes pour la gestion des opérations booléennes + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_STROP_INT_H +#define _ANALYSIS_SCAN_EXPRS_STROP_INT_H + + +#include "strop.h" + + +#include "../expr-int.h" +#include "../../../common/extstr.h" + + + +/* Opération booléenne avec un ou deux opérandes (instance) */ +struct _GScanStringOperation +{ + GScanExpression parent; /* A laisser en premier */ + + StringOperationType type; /* Type d'opération menée */ + bool case_sensitive; /* Respect de la casse ? */ + + GScanExpression *left; /* Expression impactée #1 */ + GScanExpression *right; /* Expression impactée #2 */ + +}; + +/* Opération booléenne avec un ou deux opérandes (classe) */ +struct _GScanStringOperationClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une expression d'opération traite une chaîne. */ +bool g_scan_string_operation_create(GScanStringOperation *, StringOperationType, GScanExpression *, GScanExpression *, bool); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_STROP_INT_H */ diff --git a/src/analysis/scan/exprs/strop.c b/src/analysis/scan/exprs/strop.c new file mode 100644 index 0000000..c188c36 --- /dev/null +++ b/src/analysis/scan/exprs/strop.c @@ -0,0 +1,455 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * strop.c - gestion des opérations booléennes + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "strop.h" + + +#include <assert.h> +#include <string.h> +#include <strings.h> + + +#include "strop-int.h" +#include "literal.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des opérations visant des chaînes. */ +static void g_scan_string_operation_class_init(GScanStringOperationClass *); + +/* Initialise une instance d'opération visant une chaîne. */ +static void g_scan_string_operation_init(GScanStringOperation *); + +/* Supprime toutes les références externes. */ +static void g_scan_string_operation_dispose(GScanStringOperation *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_string_operation_finalize(GScanStringOperation *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réduit une expression à une forme plus simple. */ +static ScanReductionState g_scan_string_operation_reduce(const GScanStringOperation *, GScanContext *, GScanScope *, GScanExpression **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une opération traitant une chaîne de caractères. */ +G_DEFINE_TYPE(GScanStringOperation, g_scan_string_operation, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des opérations visant des chaînes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_string_operation_class_init(GScanStringOperationClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_string_operation_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_string_operation_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)NULL; + expr->reduce = (reduce_expr_fc)g_scan_string_operation_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser. * +* * +* Description : Initialise une instance d'opération visant une chaîne. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_string_operation_init(GScanStringOperation *op) +{ + op->left = NULL; + op->right = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_string_operation_dispose(GScanStringOperation *op) +{ + g_clear_object(&op->left); + g_clear_object(&op->right); + + G_OBJECT_CLASS(g_scan_string_operation_parent_class)->dispose(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_string_operation_finalize(GScanStringOperation *op) +{ + G_OBJECT_CLASS(g_scan_string_operation_parent_class)->finalize(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : type = type d'opération booléenne à représenter. * +* first = premier opérande concerné. * +* second = éventuel second opérande impliqué ou NULL. * +* sensitive = détermine la prise en compte de la casse. * +* * +* Description : Organise un appel de fonction avec ses arguments. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_string_operation_new(StringOperationType type, GScanExpression *first, GScanExpression *second, bool sensitive) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_STRING_OPERATION, NULL); + + if (!g_scan_string_operation_create(G_SCAN_STRING_OPERATION(result), type, first, second, sensitive)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser pleinement. * +* type = type d'opération booléenne à représenter. * +* left = premier opérande concerné. * +* right = éventuel second opérande impliqué ou NULL. * +* sensitive = détermine la prise en compte de la casse. * +* * +* Description : Met en place une expression d'opération traite une chaîne. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_string_operation_create(GScanStringOperation *op, StringOperationType type, GScanExpression *left, GScanExpression *right, bool sensitive) +{ + bool result; /* Bilan à retourner */ + + result = g_scan_expression_create(G_SCAN_EXPRESSION(op), SRS_PENDING); + if (!result) goto exit; + + op->type = type; + + switch (type) + { + case SOT_CONTAINS: + case SOT_STARTSWITH: + case SOT_ENDSWITH: + op->case_sensitive = sensitive; + break; + + case SOT_MATCHES: + break; + + case SOT_IEQUALS: + assert(!sensitive); + op->case_sensitive = false; + break; + + } + + op->left = left; + g_object_ref(G_OBJECT(op->left)); + + op->right = right; + g_object_ref(G_OBJECT(op->right)); + + exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : expr = expression à 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 ScanReductionState g_scan_string_operation_reduce(const GScanStringOperation *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + ScanReductionState result; /* Etat synthétisé à retourner */ + GScanExpression *new_left; /* Expression réduite (gauche) */ + GScanExpression *new_right; /* Expression réduite (droite) */ + ScanReductionState state_left; /* Etat synthétisé #1 */ + ScanReductionState state_right; /* Etat synthétisé #2 */ + GScanLiteralExpression *op_left; /* Opérande gauche final */ + GScanLiteralExpression *op_right; /* Opérande droite final */ + const sized_string_t *strings[2]; /* Chaînes en jeu */ + const void *found; /* Présence d'une bribe ? */ + bool status; /* Bilan de comparaison #1 */ + int ret; /* Bilan de comparaison #2 */ + size_t offset; /* Point de départ d'analyse */ + const regex_t *preg; /* Expression rationnelle */ + + /* Réduction des éléments considérés */ + + new_left = NULL; + new_right = NULL; + + state_left = g_scan_expression_reduce(expr->left, ctx, scope, &new_left); + if (state_left == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + state_right = g_scan_expression_reduce(expr->right, ctx, scope, &new_right); + if (state_right == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + /* Construction d'une réduction locale ? */ + + if (G_IS_SCAN_LITERAL_EXPRESSION(new_left) && G_IS_SCAN_LITERAL_EXPRESSION(new_right)) + { + op_left = G_SCAN_LITERAL_EXPRESSION(new_left); + op_right = G_SCAN_LITERAL_EXPRESSION(new_right); + + if (!g_scan_literal_expression_get_string_value(op_left, &strings[0])) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + result = SRS_REDUCED; + + switch (expr->type) + { + case SOT_CONTAINS: + + if (!g_scan_literal_expression_get_string_value(op_right, &strings[1])) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + if (expr->case_sensitive) + found = memmem(strings[0]->data, strings[0]->len, strings[1]->data, strings[1]->len); + + else + found = memcasemem(strings[0]->data, strings[0]->len, strings[1]->data, strings[1]->len); + + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { found != NULL }); + break; + + case SOT_STARTSWITH: + + if (!g_scan_literal_expression_get_string_value(op_right, &strings[1])) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + if (strings[0]->len < strings[1]->len) + status = false; + + else + { + if (expr->case_sensitive) + ret = memcmp(strings[0]->data, strings[1]->data, strings[1]->len); + else + ret = memcasecmp(strings[0]->data, strings[1]->data, strings[1]->len); + + status = (ret == 0); + + } + + *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status); + break; + + case SOT_ENDSWITH: + + if (!g_scan_literal_expression_get_string_value(op_right, &strings[1])) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + if (strings[0]->len < strings[1]->len) + status = false; + + else + { + offset = strings[0]->len - strings[1]->len; + + if (expr->case_sensitive) + ret = memcmp(strings[0]->data + offset, strings[1]->data, strings[1]->len); + else + ret = memcasecmp(strings[0]->data + offset, strings[1]->data, strings[1]->len); + + status = (ret == 0); + + } + + *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status); + break; + + case SOT_MATCHES: + + if (!g_scan_literal_expression_get_regex_value(op_right, &preg)) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + ret = regexec(preg, strings[0]->data, 0, NULL, 0); + + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { ret != REG_NOMATCH }); + break; + + case SOT_IEQUALS: + + if (!g_scan_literal_expression_get_string_value(op_right, &strings[1])) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + if (strings[0]->len != strings[1]->len) + status = false; + + else + { + ret = memcasecmp(strings[0]->data, strings[1]->data, strings[1]->len); + status = (ret == 0); + } + + *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status); + break; + + } + + } + + /* Mise à jour de la progression ? */ + + else if (state_left == SRS_WAIT_FOR_SCAN || state_right == SRS_WAIT_FOR_SCAN) + { + if (new_left != expr->left || new_right != expr->right) + *out = g_scan_string_operation_new(expr->type, new_left, new_right, expr->case_sensitive); + + result = SRS_WAIT_FOR_SCAN; + + } + + /* Cas des situations où les expressions ne sont pas exploitables (!) */ + else + { + assert(state_left == SRS_REDUCED && state_right == SRS_REDUCED); + + result = SRS_UNRESOLVABLE; + + } + + /* Sortie propre */ + + exit: + + g_clear_object(&new_left); + g_clear_object(&new_right); + + return result; + +} diff --git a/src/analysis/scan/exprs/strop.h b/src/analysis/scan/exprs/strop.h new file mode 100644 index 0000000..0a32269 --- /dev/null +++ b/src/analysis/scan/exprs/strop.h @@ -0,0 +1,67 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * strop.h - prototypes pour la gestion des opérations booléennes + * + * 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_STROP_H +#define _ANALYSIS_SCAN_EXPRS_STROP_H + + +#include "../expr.h" + + + +#define G_TYPE_SCAN_STRING_OPERATION g_scan_string_operation_get_type() +#define G_SCAN_STRING_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_STRING_OPERATION, GScanStringOperation)) +#define G_IS_SCAN_STRING_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_STRING_OPERATION)) +#define G_SCAN_STRING_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_STRING_OPERATION, GScanStringOperationClass)) +#define G_IS_SCAN_STRING_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_STRING_OPERATION)) +#define G_SCAN_STRING_OPERATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_STRING_OPERATION, GScanStringOperationClass)) + + +/* Opération booléenne avec un ou deux opérandes (instance) */ +typedef struct _GScanStringOperation GScanStringOperation; + +/* Opération booléenne avec un ou deux opérandes (classe) */ +typedef struct _GScanStringOperationClass GScanStringOperationClass; + + +/* Types d'opérations booléennes supportées */ +typedef enum _StringOperationType +{ + SOT_CONTAINS, /* Opérateurs "[i]contains" */ + SOT_STARTSWITH, /* Opérateurs "[i]startswith" */ + SOT_ENDSWITH, /* Opérateurs "[i]endswith" */ + SOT_MATCHES, /* Opérateur "matches" */ + SOT_IEQUALS, /* Opérateur "iequals" */ + +} StringOperationType; + + +/* Indique le type défini pour une opération traitant une chaîne de caractères. */ +GType g_scan_string_operation_get_type(void); + +/* Organise un appel de fonction avec ses arguments. */ +GScanExpression *g_scan_string_operation_new(StringOperationType, GScanExpression *, GScanExpression *, bool); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_STROP_H */ |