From 4fcc35a52ccb025b6d803d85e017931cd2452960 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sun, 6 Aug 2023 18:54:57 +0200 Subject: Extend the ROST grammar with a first batch of new features. --- configure.ac | 41 ++ plugins/kaitai/parsers/enum.c | 2 +- plugins/kaitai/parsers/struct.c | 2 +- plugins/pychrysalide/analysis/scan/scanner.c | 46 ++ src/Makefile.am | 6 + src/analysis/scan/context-int.h | 20 +- src/analysis/scan/context.c | 325 ++++++++++++- src/analysis/scan/context.h | 8 +- src/analysis/scan/core.c | 96 +++- src/analysis/scan/expr-int.h | 28 +- src/analysis/scan/expr.c | 354 +++++++++++++- src/analysis/scan/expr.h | 27 +- src/analysis/scan/exprs/Makefile.am | 20 +- src/analysis/scan/exprs/access-int.h | 17 +- src/analysis/scan/exprs/access.c | 269 ++++++----- src/analysis/scan/exprs/access.h | 27 +- src/analysis/scan/exprs/arithmetic-int.h | 60 +++ src/analysis/scan/exprs/arithmetic.c | 638 ++++++++++++++++++++++++++ src/analysis/scan/exprs/arithmetic.h | 67 +++ src/analysis/scan/exprs/arithmop-int.h | 60 --- src/analysis/scan/exprs/arithmop.c | 436 ------------------ src/analysis/scan/exprs/arithmop.h | 67 --- src/analysis/scan/exprs/boolop-int.h | 60 --- src/analysis/scan/exprs/boolop.c | 479 ------------------- src/analysis/scan/exprs/boolop.h | 65 --- src/analysis/scan/exprs/call-int.h | 12 +- src/analysis/scan/exprs/call.c | 280 +++++++---- src/analysis/scan/exprs/call.h | 22 +- src/analysis/scan/exprs/counter-int.h | 57 +++ src/analysis/scan/exprs/counter.c | 248 ++++++++++ src/analysis/scan/exprs/counter.h | 59 +++ src/analysis/scan/exprs/intersect-int.h | 58 +++ src/analysis/scan/exprs/intersect.c | 290 ++++++++++++ src/analysis/scan/exprs/intersect.h | 55 +++ src/analysis/scan/exprs/literal-int.h | 16 +- src/analysis/scan/exprs/literal.c | 363 +++++++++------ src/analysis/scan/exprs/literal.h | 49 +- src/analysis/scan/exprs/logical-int.h | 60 +++ src/analysis/scan/exprs/logical.c | 508 ++++++++++++++++++++ src/analysis/scan/exprs/logical.h | 65 +++ src/analysis/scan/exprs/range-int.h | 58 +++ src/analysis/scan/exprs/range.c | 352 ++++++++++++++ src/analysis/scan/exprs/range.h | 55 +++ src/analysis/scan/exprs/relational-int.h | 60 +++ src/analysis/scan/exprs/relational.c | 408 ++++++++++++++++ src/analysis/scan/exprs/relational.h | 56 +++ src/analysis/scan/exprs/relop-int.h | 60 --- src/analysis/scan/exprs/relop.c | 392 ---------------- src/analysis/scan/exprs/relop.h | 56 --- src/analysis/scan/exprs/set-int.h | 54 +++ src/analysis/scan/exprs/set.c | 379 +++++++++++++++ src/analysis/scan/exprs/set.h | 58 +++ src/analysis/scan/exprs/strop-int.h | 8 +- src/analysis/scan/exprs/strop.c | 207 ++++----- src/analysis/scan/exprs/strop.h | 22 +- src/analysis/scan/grammar.y | 394 +++++++++++----- src/analysis/scan/items/Makefile.am | 18 + src/analysis/scan/items/console/Makefile.am | 13 + src/analysis/scan/items/console/log.c | 303 ++++++++++++ src/analysis/scan/items/console/log.h | 58 +++ src/analysis/scan/items/count.c | 244 ++++++++++ src/analysis/scan/items/count.h | 58 +++ src/analysis/scan/items/datasize.c | 56 +-- src/analysis/scan/items/datasize.h | 22 +- src/analysis/scan/items/magic/Makefile.am | 16 + src/analysis/scan/items/magic/cookie.c | 122 +++++ src/analysis/scan/items/magic/cookie.h | 44 ++ src/analysis/scan/items/magic/mime-encoding.c | 270 +++++++++++ src/analysis/scan/items/magic/mime-encoding.h | 58 +++ src/analysis/scan/items/magic/mime-type.c | 270 +++++++++++ src/analysis/scan/items/magic/mime-type.h | 58 +++ src/analysis/scan/items/magic/type.c | 270 +++++++++++ src/analysis/scan/items/magic/type.h | 58 +++ src/analysis/scan/items/time/Makefile.am | 14 + src/analysis/scan/items/time/make.c | 350 ++++++++++++++ src/analysis/scan/items/time/make.h | 58 +++ src/analysis/scan/items/time/now.c | 243 ++++++++++ src/analysis/scan/items/time/now.h | 58 +++ src/analysis/scan/items/uint-int.h | 8 +- src/analysis/scan/items/uint.c | 137 ++++-- src/analysis/scan/items/uint.h | 23 +- src/analysis/scan/rule-int.h | 1 + src/analysis/scan/rule.c | 28 ++ src/analysis/scan/rule.h | 4 + src/analysis/scan/scanner-int.h | 2 + src/analysis/scan/scanner.c | 180 +++++++- src/analysis/scan/scanner.h | 15 +- src/analysis/scan/tokens.l | 40 +- src/common/szstr.h | 28 +- src/core/core.c | 11 + src/glibext/comparison-int.h | 5 +- src/glibext/comparison.c | 58 ++- src/rost.c | 22 +- tests/analysis/scan/booleans.py | 98 ++++ tests/analysis/scan/common.py | 52 +++ tests/analysis/scan/examples.py | 70 +++ tests/analysis/scan/expr.py | 169 ------- tests/analysis/scan/exprs.py | 122 ----- tests/analysis/scan/func.py | 16 - tests/analysis/scan/functions.py | 104 +++++ tests/analysis/scan/grammar.py | 327 +++++-------- tests/analysis/scan/matches.py | 27 ++ tests/analysis/scan/options.py | 16 - tests/analysis/scan/pyapi.py | 58 +++ tests/analysis/scan/sets.py | 118 +++++ 105 files changed, 9298 insertions(+), 3083 deletions(-) create mode 100644 src/analysis/scan/exprs/arithmetic-int.h create mode 100644 src/analysis/scan/exprs/arithmetic.c create mode 100644 src/analysis/scan/exprs/arithmetic.h delete mode 100644 src/analysis/scan/exprs/arithmop-int.h delete mode 100644 src/analysis/scan/exprs/arithmop.c delete mode 100644 src/analysis/scan/exprs/arithmop.h delete mode 100644 src/analysis/scan/exprs/boolop-int.h delete mode 100644 src/analysis/scan/exprs/boolop.c delete mode 100644 src/analysis/scan/exprs/boolop.h create mode 100644 src/analysis/scan/exprs/counter-int.h create mode 100644 src/analysis/scan/exprs/counter.c create mode 100644 src/analysis/scan/exprs/counter.h create mode 100644 src/analysis/scan/exprs/intersect-int.h create mode 100644 src/analysis/scan/exprs/intersect.c create mode 100644 src/analysis/scan/exprs/intersect.h create mode 100644 src/analysis/scan/exprs/logical-int.h create mode 100644 src/analysis/scan/exprs/logical.c create mode 100644 src/analysis/scan/exprs/logical.h create mode 100644 src/analysis/scan/exprs/range-int.h create mode 100644 src/analysis/scan/exprs/range.c create mode 100644 src/analysis/scan/exprs/range.h create mode 100644 src/analysis/scan/exprs/relational-int.h create mode 100644 src/analysis/scan/exprs/relational.c create mode 100644 src/analysis/scan/exprs/relational.h delete mode 100644 src/analysis/scan/exprs/relop-int.h delete mode 100644 src/analysis/scan/exprs/relop.c delete mode 100644 src/analysis/scan/exprs/relop.h create mode 100644 src/analysis/scan/exprs/set-int.h create mode 100644 src/analysis/scan/exprs/set.c create mode 100644 src/analysis/scan/exprs/set.h create mode 100644 src/analysis/scan/items/console/Makefile.am create mode 100644 src/analysis/scan/items/console/log.c create mode 100644 src/analysis/scan/items/console/log.h create mode 100644 src/analysis/scan/items/count.c create mode 100644 src/analysis/scan/items/count.h create mode 100644 src/analysis/scan/items/magic/Makefile.am create mode 100644 src/analysis/scan/items/magic/cookie.c create mode 100644 src/analysis/scan/items/magic/cookie.h create mode 100644 src/analysis/scan/items/magic/mime-encoding.c create mode 100644 src/analysis/scan/items/magic/mime-encoding.h create mode 100644 src/analysis/scan/items/magic/mime-type.c create mode 100644 src/analysis/scan/items/magic/mime-type.h create mode 100644 src/analysis/scan/items/magic/type.c create mode 100644 src/analysis/scan/items/magic/type.h create mode 100644 src/analysis/scan/items/time/Makefile.am create mode 100644 src/analysis/scan/items/time/make.c create mode 100644 src/analysis/scan/items/time/make.h create mode 100644 src/analysis/scan/items/time/now.c create mode 100644 src/analysis/scan/items/time/now.h create mode 100644 tests/analysis/scan/booleans.py create mode 100644 tests/analysis/scan/common.py create mode 100644 tests/analysis/scan/examples.py delete mode 100644 tests/analysis/scan/expr.py delete mode 100644 tests/analysis/scan/exprs.py delete mode 100644 tests/analysis/scan/func.py create mode 100644 tests/analysis/scan/functions.py create mode 100644 tests/analysis/scan/matches.py delete mode 100644 tests/analysis/scan/options.py create mode 100644 tests/analysis/scan/pyapi.py create mode 100644 tests/analysis/scan/sets.py diff --git a/configure.ac b/configure.ac index 6b6da96..165cb40 100644 --- a/configure.ac +++ b/configure.ac @@ -232,6 +232,10 @@ AC_ARG_ENABLE([curl-support], AS_HELP_STRING([--disable-curl-support], [disable cURL support [default=no]]), [], [enable_curl_support=yes]) +AC_ARG_ENABLE([magic-support], + AS_HELP_STRING([--disable-magic-support], [disable magic number recognition [default=no]]), + [], [enable_magic_support=yes]) + AC_ARG_ENABLE([python-bindings], AS_HELP_STRING([--disable-python-bindings], [disable Python bindings [default=no]]), [], [enable_python_bindings=yes]) @@ -503,6 +507,35 @@ AC_SUBST(LIBYAML_CFLAGS) AC_SUBST(LIBYAML_LIBS) +#--- Checks for libmagic + +AM_CONDITIONAL([BUILD_MAGIC_SUPPORT], [test "x$enable_magic_support" = "xyes"]) + +if test "x$BUILD_MAGIC_SUPPORT_TRUE" = "x"; then + AC_DEFINE(HAVE_MAGIC_SUPPORT, 1, + [Define to 1 if the magic support is available and enabled.]) +fi + + +PKG_CHECK_MODULES(LIBMAGIC,libmagic >= 5.44,[libmagic_found=yes],[libmagic_found=no]) + +if test "$libmagic_found" = "yes"; then + libmagic_version=`pkg-config libmagic --modversion` +else + libmagic_version='-' +fi + + +if test "x$enable_magic_support" = "xyes"; then + + AC_SUBST(LIBMAGIC_CFLAGS) + AC_SUBST(LIBMAGIC_LIBS) + + true # empty if/then body not allowed + +fi + + #--- Checks for Python if test "x$enable_debug" = "xyes"; then @@ -760,6 +793,7 @@ echo The small, fast and reliable database engine. : $libsqlite_version echo The cryptography and SSL/TLS toolkit......... : $libssl_version echo The client URL library....................... : $libcurl_version echo The YAML support library..................... : $libyaml_version +echo The magic number recognition library......... : $libmagic_version echo echo Available Python programming language........ : $python3_version @@ -781,6 +815,12 @@ else disable_curl_support="yes" fi +if test "x$enable_magic_support" = "xyes"; then + disable_magic_support="no" +else + disable_magic_support="yes" +fi + if test "x$enable_python_bindings" = "xyes"; then disable_python_bindings="no" else @@ -792,6 +832,7 @@ echo Print debugging messages..................... : $enable_debug echo Consider local resources..................... : $with_local_resources echo Disable GTK support.......................... : $disable_gtk_support echo Disable cURL support......................... : $disable_curl_support +echo Disable Magic support........................ : $disable_magic_support echo Disable Python bindings...................... : $disable_python_bindings echo Build a Python binary distribution........... : $build_python_package diff --git a/plugins/kaitai/parsers/enum.c b/plugins/kaitai/parsers/enum.c index 267aaba..27e5660 100644 --- a/plugins/kaitai/parsers/enum.c +++ b/plugins/kaitai/parsers/enum.c @@ -351,7 +351,7 @@ static int compare_enum_values_by_sized_label(const sized_string_t *l, const enu { int result; /* Bilan à retourner */ - result = szstrcmp(l, (*b)->label); + result = strncmp(l->data, (*b)->label, l->len); // FIXME return result; diff --git a/plugins/kaitai/parsers/struct.c b/plugins/kaitai/parsers/struct.c index 26089d3..128a788 100644 --- a/plugins/kaitai/parsers/struct.c +++ b/plugins/kaitai/parsers/struct.c @@ -578,7 +578,7 @@ GKaitaiEnum *g_kaitai_structure_get_enum(const GKaitaiStruct *kstruct, const siz { other = g_kaitai_enum_get_name(kstruct->enums[i]); - if (szstrcmp(name, other) == 0) + if (strncmp(name->data, other, name->len) == 0) // FIXME { result = kstruct->enums[i]; g_object_ref(G_OBJECT(result)); diff --git a/plugins/pychrysalide/analysis/scan/scanner.c b/plugins/pychrysalide/analysis/scan/scanner.c index bf5a5f5..befbc80 100644 --- a/plugins/pychrysalide/analysis/scan/scanner.c +++ b/plugins/pychrysalide/analysis/scan/scanner.c @@ -188,6 +188,51 @@ static PyObject *py_content_scanner_analyze(PyObject *self, PyObject *args) /****************************************************************************** * * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique le chemin d'un éventuel fichier de source. * +* * +* Retour : Chemin d'un éventuel fichier de définitions ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_content_scanner_get_filename(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GContentScanner *scanner; /* Analyseur à consulter */ + const char *filename; /* Chemin d'accès à transmettre*/ + +#define CONTENT_SCANNER_FILENAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + filename, py_content_scanner, \ + "Provide the access path to the source file of the rules'" \ + " definition, or *None* if these rules have not been loaded"\ + " from memory." \ +) + + scanner = G_CONTENT_SCANNER(pygobject_get(self)); + + filename = g_content_scanner_get_filename(scanner); + + if (filename != NULL) + result = PyUnicode_FromString(filename); + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : - * * * * Description : Fournit un accès à une définition de type à diffuser. * @@ -206,6 +251,7 @@ PyTypeObject *get_python_content_scanner_type(void) }; static PyGetSetDef py_content_scanner_getseters[] = { + CONTENT_SCANNER_FILENAME_ATTRIB, { NULL } }; diff --git a/src/Makefile.am b/src/Makefile.am index 1fe76bc..233fc10 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -66,6 +66,12 @@ libchrysacore_la_LDFLAGS += $(LIBCURL_LIBS) endif +if BUILD_MAGIC_SUPPORT + +libchrysacore_la_LDFLAGS += $(LIBMAGIC_LIBS) + +endif + ############################################################ diff --git a/src/analysis/scan/context-int.h b/src/analysis/scan/context-int.h index 94302bf..3a971b8 100644 --- a/src/analysis/scan/context-int.h +++ b/src/analysis/scan/context-int.h @@ -29,9 +29,12 @@ #include "expr.h" +#include "../../common/fnv1a.h" +#define ALLOCATION_STEP 10 + /* Mémorisation des correspondances partielles */ typedef struct _atom_match_tracker_t { @@ -41,12 +44,22 @@ typedef struct _atom_match_tracker_t } atom_match_tracker_t; -#define ALLOCATION_STEP 10 +/* Mémorisation des correspondances complètes, par motif */ +typedef struct _full_match_tracker_t +{ + GSearchPattern *pattern; /* Motif commun aux trouvailles*/ + + GScanMatch **matches; /* Correspondances confirmées */ + size_t allocated; /* Taille du talbeau préparé */ + size_t used; /* Nombre d'éléments présents */ + +} full_match_tracker_t; /* Condition définissant une règle de correspondance */ typedef struct _rule_condition_t { char *name; /* Désignation de la règle */ + fnv64_t name_hash; /* Empreinte de la désignation */ GScanExpression *expr; /* Condition de correspondance */ bool final_reduced; /* Réduction finale tentée ? */ @@ -66,9 +79,8 @@ struct _GScanContext atom_match_tracker_t *atom_trackers; /* Correspondances partielles */ - GScanMatch **full_matches; /* Correspondances confirmées */ - size_t full_allocated; /* Taille du talbeau préparé */ - size_t full_used; /* Nombre d'éléments présents */ + full_match_tracker_t **full_trackers; /* Correspondances confirmées */ + size_t full_count; /* Quantité de correspondances */ rule_condition_t *conditions; /* Ensemble de règles suivies */ size_t cond_count; /* Quantité de ces conditions */ diff --git a/src/analysis/scan/context.c b/src/analysis/scan/context.c index c19b76c..1f9c38e 100644 --- a/src/analysis/scan/context.c +++ b/src/analysis/scan/context.c @@ -25,11 +25,36 @@ #include +#include +#include #include #include "context-int.h" #include "exprs/literal.h" +#include "../../common/sort.h" + + + + + +/* ------------------- ADMINISTRATION DES CORRESPONDANCES TOTALES ------------------- */ + + +/* Initialise un suivi de trouvailles pour un premier motif. */ +static full_match_tracker_t *create_full_match_tracker(GSearchPattern *); + +/* Termine le suivi de trouvailles pour un motif. */ +static void delete_full_match_tracker(full_match_tracker_t *); + +/* Etablit la comparaison entre deux structures de suivi. */ +static int compare_full_match_trackers(const full_match_tracker_t **, const full_match_tracker_t **); + +/* Note l'existence d'une nouvelle correspondance pour un motif. */ +static void add_match_to_full_match_tracker(full_match_tracker_t *, GScanMatch *); + + + @@ -47,6 +72,131 @@ static void g_scan_context_finalize(GScanContext *); + + + + +/* ---------------------------------------------------------------------------------- */ +/* ADMINISTRATION DES CORRESPONDANCES TOTALES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : pattern = motif de recherche trouvé. * +* * +* Description : Initialise un suivi de trouvailles pour un premier motif. * +* * +* Retour : Structure de suivi mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static full_match_tracker_t *create_full_match_tracker(GSearchPattern *pattern) +{ + full_match_tracker_t *result; /* Structure à retourner */ + + result = malloc(sizeof(full_match_tracker_t)); + + result->pattern = pattern; + g_object_ref(G_OBJECT(pattern)); + + result->matches = malloc(ALLOCATION_STEP * sizeof(GScanMatch *)); + result->allocated = ALLOCATION_STEP; + result->used = 0; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = structure de gestion à manipuler. * +* * +* Description : Termine le suivi de trouvailles pour un motif. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void delete_full_match_tracker(full_match_tracker_t *tracker) +{ + size_t i; /* Boucle de parcours */ + + g_object_unref(G_OBJECT(tracker->pattern)); + + for (i = 0; i < tracker->used; i++) + g_object_unref(G_OBJECT(tracker->matches[i])); + + free(tracker->matches); + + free(tracker); + +} + + +/****************************************************************************** +* * +* Paramètres : a = première structure de suivi à consulter. * +* b = seconde structure de suivi à consulter. * +* * +* Description : Etablit la comparaison entre deux structures de suivi. * +* * +* Retour : Bilan : -1 (a < b), 0 (a == b) ou 1 (a > b). * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int compare_full_match_trackers(const full_match_tracker_t **a, const full_match_tracker_t **b) +{ + int result; /* Bilan à renvoyer */ + + result = sort_unsigned_long((unsigned long)(*a)->pattern, (unsigned long)(*b)->pattern); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = structure de gestion à manipuler. * +* match = correspondance complète établie. * +* * +* Description : Note l'existence d'une nouvelle correspondance pour un motif.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void add_match_to_full_match_tracker(full_match_tracker_t *tracker, GScanMatch *match) +{ + if (tracker->used == tracker->allocated) + { + tracker->allocated += ALLOCATION_STEP; + tracker->matches = realloc(tracker->matches, tracker->allocated * sizeof(GScanMatch *)); + } + + tracker->matches[tracker->used++] = match; + g_object_ref(G_OBJECT(match)); + +} + + + + + + + + + /* Indique le type défini pour un contexte de suivi d'analyse. */ G_DEFINE_TYPE(GScanContext, g_scan_context, G_TYPE_OBJECT); @@ -97,9 +247,8 @@ static void g_scan_context_init(GScanContext *context) context->atom_trackers = NULL; - context->full_matches = NULL; - context->full_allocated = 0; - context->full_used = 0; + context->full_trackers = NULL; + context->full_count = 0; context->conditions = NULL; context->cond_count = 0; @@ -127,8 +276,12 @@ static void g_scan_context_dispose(GScanContext *context) g_clear_object(&context->content); - for (i = 0; i < context->full_used; i++) - g_clear_object(&context->full_matches[i]); + for (i = 0; i < context->full_count; i++) + if (context->full_trackers[i] != NULL) + { + delete_full_match_tracker(context->full_trackers[i]); + context->full_trackers[i] = NULL; + } for (i = 0; i < context->cond_count; i++) g_clear_object(&context->conditions[i].expr); @@ -170,8 +323,8 @@ static void g_scan_context_finalize(GScanContext *context) } - if (context->full_matches != NULL) - free(context->full_matches); + if (context->full_trackers != NULL) + free(context->full_trackers); if (context->conditions != NULL) { @@ -387,14 +540,75 @@ const phys_t *g_scan_context_get_atom_matches(const GScanContext *context, patid void g_scan_context_register_full_match(GScanContext *context, GScanMatch *match) { - if (context->full_used == context->full_allocated) + GSearchPattern *pattern; /* Clef d'un suivi */ + full_match_tracker_t key; /* Modèle d'identification */ + full_match_tracker_t **found; /* Structure à actualiser */ + full_match_tracker_t *tracker; /* Nouveau suivi à intégrer */ + + pattern = g_scan_match_get_source(match); + + key.pattern = pattern; + + found = bsearch((full_match_tracker_t *[]) { &key }, context->full_trackers, context->full_count, + sizeof(full_match_tracker_t *), (__compar_fn_t)compare_full_match_trackers); + + if (found == NULL) { - context->full_allocated += ALLOCATION_STEP; - context->full_matches = realloc(context->full_matches, context->full_allocated * sizeof(GScanMatch *)); + tracker = create_full_match_tracker(pattern); + + context->full_trackers = qinsert(context->full_trackers, &context->full_count, + sizeof(full_match_tracker_t *), + (__compar_fn_t)compare_full_match_trackers, &tracker); + } + else + tracker = *found; - context->full_matches[context->full_used++] = match; - g_object_ref(G_OBJECT(match)); + add_match_to_full_match_tracker(tracker, match); + + g_object_unref(G_OBJECT(pattern)); + +} + + +/****************************************************************************** +* * +* Paramètres : context = instance à mettre à jour. * +* pattern = motif dont des correspondances sont à retrouver. * +* count = quantité de correspondances enregistrées. [OUT] * +* * +* Description : Fournit la liste de toutes les correspondances d'un motif. * +* * +* Retour : Liste courante de correspondances établies. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const GScanMatch **g_scan_context_get_full_matches(const GScanContext *context, const GSearchPattern *pattern, size_t *count) +{ + GScanMatch **result; /* Correspondance à renvoyer */ + full_match_tracker_t key; /* Modèle d'identification */ + full_match_tracker_t **found; /* Structure à actualiser */ + + key.pattern = pattern; + + found = bsearch((full_match_tracker_t *[]) { &key }, context->full_trackers, context->full_count, + sizeof(full_match_tracker_t *), (__compar_fn_t)compare_full_match_trackers); + + if (found == NULL) + { + result = NULL; + count = 0; + } + + else + { + result = (*found)->matches; + *count = (*found)->used; + } + + return result; } @@ -411,12 +625,25 @@ void g_scan_context_register_full_match(GScanContext *context, GScanMatch *match * * ******************************************************************************/ -void g_scan_context_display(const GScanContext *context) +void g_scan_context_display(GScanContext *context) { size_t i; /* Boucle de parcours */ + const rule_condition_t *cond; /* Conditions de orrespondance */ + /* + FIXME : ordre for (i = 0; i < context->full_used; i++) g_scan_match_display(context->full_matches[i]); + */ + + for (i = 0; i < context->cond_count; i++) + { + cond = &context->conditions[i]; + + if (g_scan_context_has_match_for_rule(context, cond->name)) + fprintf(stderr, "Rule '%s' has matched!\n", cond->name); + + } } @@ -445,7 +672,7 @@ bool g_scan_context_set_rule_condition(GScanContext *context, const char *name, /* Recherche d'antécédent */ - for (i = 0; context->cond_count; i++) + for (i = 0; i < context->cond_count; i++) if (strcmp(name, context->conditions[i].name) == 0) { result = false; @@ -461,8 +688,10 @@ bool g_scan_context_set_rule_condition(GScanContext *context, const char *name, new = &context->conditions[context->cond_count - 1]; new->name = strdup(name); + new->name_hash = fnv_64a_hash(name); - new->expr = g_scan_expression_duplicate(expr); + new->expr = expr;//g_scan_expression_duplicate(expr); + g_object_ref(G_OBJECT(expr)); // FIXME => REMME dup() new->final_reduced = false; } @@ -477,6 +706,50 @@ bool g_scan_context_set_rule_condition(GScanContext *context, const char *name, * Paramètres : context = mémoire de résultats d'analyse à consulter. * * name = désignation de la règle ciblée. * * * +* Description : Indique si un nom donné correspond à une règle. * +* * +* Retour : Bilan de la présence d'une règle désignée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_context_has_rule_for_name(const GScanContext *context, const char *name) +{ + bool result; /* Bilan à retourner */ + fnv64_t hash; /* Empreinte du nom à retrouver*/ + size_t i; /* Boucle de parcours */ + const rule_condition_t *cond; /* Condition connue du contexte*/ + + result = false; + + hash = fnv_64a_hash(name); + + for (i = 0; i < context->cond_count; i++) + { + cond = context->conditions + i; + + if (cond->name_hash != hash) + continue; + + if (strcmp(cond->name, name) == 0) + { + result = true; + break; + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : context = mémoire de résultats d'analyse à consulter. * +* name = désignation de la règle ciblée. * +* * * Description : Indique si une correspondance globale a pu être établie. * * * * Retour : Bilan final d'une analyse (false par défaut). * @@ -513,21 +786,27 @@ bool g_scan_context_has_match_for_rule(GScanContext *context, const char *name) if (!cond->final_reduced) { - cond->final_reduced = g_scan_expression_reduce(cond->expr, context, NULL, &new); + valid = g_scan_expression_reduce(cond->expr, context, NULL, &new); + if (!valid || new == NULL) goto exit; - if (cond->final_reduced && new != NULL) - { - g_object_unref(G_OBJECT(cond->expr)); - cond->expr = new; - } + g_object_unref(G_OBJECT(cond->expr)); + cond->expr = new; + + valid = g_scan_expression_reduce_to_boolean(cond->expr, context, NULL, &new); + if (!valid || new == NULL) goto exit; + + g_object_unref(G_OBJECT(cond->expr)); + cond->expr = new; + + cond->final_reduced = true; } /* Tentative de récupération d'un bilan final */ - if (G_IS_LITERAL_EXPRESSION(cond->expr)) + if (cond->final_reduced) { - valid = g_literal_expression_get_boolean_value(G_LITERAL_EXPRESSION(cond->expr), &result); + valid = g_scan_literal_expression_get_boolean_value(G_SCAN_LITERAL_EXPRESSION(cond->expr), &result); if (!valid) { diff --git a/src/analysis/scan/context.h b/src/analysis/scan/context.h index 92522f8..563a53e 100644 --- a/src/analysis/scan/context.h +++ b/src/analysis/scan/context.h @@ -86,12 +86,18 @@ const phys_t *g_scan_context_get_atom_matches(const GScanContext *, patid_t, siz /* Enregistre une correspondance complète avec un contenu. */ void g_scan_context_register_full_match(GScanContext *, GScanMatch *); +/* Fournit la liste de toutes les correspondances d'un motif. */ +const GScanMatch **g_scan_context_get_full_matches(const GScanContext *, const GSearchPattern *, size_t *); + /* Affiche les correspondances identifiées. */ -void g_scan_context_display(const GScanContext *); +void g_scan_context_display(GScanContext *); /* Intègre une condition de correspondance pour règle. */ bool g_scan_context_set_rule_condition(GScanContext *, const char *, const GScanExpression *); +/* Indique si un nom donné correspond à une règle. */ +bool g_scan_context_has_rule_for_name(const GScanContext *, const char *); + /* Indique si une correspondance globale a pu être établie. */ bool g_scan_context_has_match_for_rule(GScanContext *, const char *); diff --git a/src/analysis/scan/core.c b/src/analysis/scan/core.c index aef9abd..d940ab5 100644 --- a/src/analysis/scan/core.c +++ b/src/analysis/scan/core.c @@ -24,8 +24,20 @@ #include "core.h" +#include + + +#include "items/count.h" #include "items/datasize.h" #include "items/uint.h" +#include "items/console/log.h" +#ifdef HAVE_MAGIC_SUPPORT +# include "items/magic/type.h" +# include "items/magic/mime-encoding.h" +# include "items/magic/mime-type.h" +#endif +#include "items/time/make.h" +#include "items/time/now.h" @@ -43,25 +55,83 @@ bool populate_main_scan_namespace(GScanNamespace *space) { - bool result; + bool result; /* Bilan à retourner */ + GScanNamespace *ns; /* Nouvel espace de noms */ result = true; -#define REGISTER_FUNC(s, f) \ - ({ \ - bool __result; \ - __result = g_scan_namespace_register_item(s, G_REGISTERED_ITEM(f)); \ - g_object_unref(G_OBJECT(f)); \ - __result; \ +#define REGISTER_FUNC(s, f) \ + ({ \ + bool __result; \ + __result = g_scan_namespace_register_item(s, f); \ + g_object_unref(G_OBJECT(f)); \ + __result; \ }) - if (result) result = REGISTER_FUNC(space, g_datasize_function_new()); - //if (result) result = REGISTER_FUNC(space, g_datasize_function_new(), "filesize"); /* Alias */ + if (result) result = REGISTER_FUNC(space, g_scan_count_function_new()); + if (result) result = REGISTER_FUNC(space, g_scan_datasize_function_new()); + + if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_8_BITS_SIGNED, SRE_LITTLE)); + if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_8_BITS_UNSIGNED, SRE_LITTLE)); + + if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_16_BITS_SIGNED, SRE_LITTLE)); + if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_16_BITS_SIGNED, SRE_BIG)); + if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_16_BITS_UNSIGNED, SRE_LITTLE)); + if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_16_BITS_UNSIGNED, SRE_BIG)); + + if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_32_BITS_SIGNED, SRE_LITTLE)); + if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_32_BITS_SIGNED, SRE_BIG)); + if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_32_BITS_UNSIGNED, SRE_LITTLE)); + if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_32_BITS_UNSIGNED, SRE_BIG)); + + if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_64_BITS_SIGNED, SRE_LITTLE)); + if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_64_BITS_SIGNED, SRE_BIG)); + if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_64_BITS_UNSIGNED, SRE_LITTLE)); + if (result) result = REGISTER_FUNC(space, g_scan_uint_function_new(MDS_64_BITS_UNSIGNED, SRE_BIG)); + + /* Console */ + + if (result) + { + ns = g_scan_namespace_new("console"); + result = g_scan_namespace_register_item(space, G_REGISTERED_ITEM(ns)); + + if (result) result = REGISTER_FUNC(ns, g_scan_console_log_function_new()); + + g_object_unref(G_OBJECT(ns)); + + } + + /* Magic */ + +#ifdef HAVE_MAGIC_SUPPORT + if (result) + { + ns = g_scan_namespace_new("magic"); + result = g_scan_namespace_register_item(space, G_REGISTERED_ITEM(ns)); + + if (result) result = REGISTER_FUNC(ns, g_scan_magic_type_function_new()); + if (result) result = REGISTER_FUNC(ns, g_scan_mime_encoding_function_new()); + if (result) result = REGISTER_FUNC(ns, g_scan_mime_type_function_new()); + + g_object_unref(G_OBJECT(ns)); + + } +#endif + + /* Time */ + + if (result) + { + ns = g_scan_namespace_new("time"); + result = g_scan_namespace_register_item(space, G_REGISTERED_ITEM(ns)); + + if (result) result = REGISTER_FUNC(ns, g_scan_time_make_function_new()); + if (result) result = REGISTER_FUNC(ns, g_scan_time_now_function_new()); + + g_object_unref(G_OBJECT(ns)); - if (result) result = REGISTER_FUNC(space, g_uint_function_new(MDS_8_BITS_UNSIGNED)); - if (result) result = REGISTER_FUNC(space, g_uint_function_new(MDS_16_BITS_UNSIGNED)); - if (result) result = REGISTER_FUNC(space, g_uint_function_new(MDS_32_BITS_UNSIGNED)); - if (result) result = REGISTER_FUNC(space, g_uint_function_new(MDS_64_BITS_UNSIGNED)); + } return result; diff --git a/src/analysis/scan/expr-int.h b/src/analysis/scan/expr-int.h index dbfea6e..48668b5 100644 --- a/src/analysis/scan/expr-int.h +++ b/src/analysis/scan/expr-int.h @@ -39,16 +39,28 @@ typedef bool (* compare_expr_rich_fc) (const GScanExpression *, const GScanExpression *, RichCmpOperation, bool *); /* Vérifie la validité d'une expression. */ -typedef bool (* check_expr_validity_fc) (const GScanExpression *); +typedef bool (* check_expr_validity_fc) (const GScanExpression *); // REMME ? /* Reproduit une expression en place dans une nouvelle instance. */ -typedef GScanExpression * (* dup_expr_fc) (const GScanExpression *); +typedef GScanExpression * (* dup_expr_fc) (const GScanExpression *); // REMME ? /* Reproduit une expression en place dans une nouvelle instance. */ typedef void (* copy_expr_fc) (GScanExpression *, const GScanExpression *); /* Réduit une expression à une forme plus simple. */ -typedef bool (* reduce_expr_fc) (GScanExpression *, GScanContext *, GScanScope *, GScanExpression **); +typedef ScanReductionState (* reduce_expr_fc) (GScanExpression *, GScanContext *, GScanScope *, GScanExpression **); + +/* Réduit une expression à une forme booléenne. */ +typedef bool (* reduce_expr_to_bool_fc) (GScanExpression *, GScanContext *, GScanScope *, GScanExpression **); + +/* Dénombre les éléments portés par une expression. */ +typedef bool (* count_scan_expr_fc) (const GScanExpression *, size_t *); + +/* Fournit un élément donné issu d'un ensemble constitué. */ +typedef bool (* get_scan_expr_fc) (const GScanExpression *, size_t, GScanExpression **); + +/* Réalise l'intersection entre deux ensembles. */ +typedef GScanExpression * (* intersect_scan_expr_fc) (GScanExpression *, const GScanExpression *, GScanContext *, GScanScope *); /* Expression d'évaluation généraliste (instance) */ @@ -56,6 +68,8 @@ struct _GScanExpression { GObject parent; /* A laisser en premier */ + ScanReductionState state; /* Etat synthétisé de l'élément*/ + ExprValueType value_type; /* Type de valeur portée */ }; @@ -67,9 +81,15 @@ struct _GScanExpressionClass compare_expr_rich_fc cmp_rich; /* Comparaison de façon précise*/ check_expr_validity_fc check; /* Validation de la cohérence */ - copy_expr_fc copy; /* Reproduction d'expression */ + copy_expr_fc copyXXX; /* Reproduction d'expression */ dup_expr_fc dup; /* Reproduction d'expression */ + reduce_expr_fc reduce; /* Simplification d'expression */ + reduce_expr_to_bool_fc reduce_to_bool; /* Conversion en booléen */ + + count_scan_expr_fc count; /* Décompte d'éléments */ + get_scan_expr_fc get; /* Extraction d'un élément */ + intersect_scan_expr_fc intersect; /* Intersection entre ensembles*/ }; diff --git a/src/analysis/scan/expr.c b/src/analysis/scan/expr.c index 52d2c42..808b14f 100644 --- a/src/analysis/scan/expr.c +++ b/src/analysis/scan/expr.c @@ -28,6 +28,8 @@ #include "expr-int.h" +#include "exprs/literal.h" +#include "exprs/set.h" @@ -52,6 +54,9 @@ static void g_scan_expression_finalize(GScanExpression *); /* Reproduit une expression en place dans une nouvelle instance. */ static void g_scan_expression_copy(GScanExpression *, const GScanExpression *); +/* Réalise l'intersection entre deux ensembles. */ +static GScanExpression *_g_scan_expression_intersect(GScanExpression *, const GScanExpression *, GScanContext *, GScanScope *); + /* ----------------------- INTERFACE OFFRANT DES COMPARAISONS ----------------------- */ @@ -93,7 +98,8 @@ static void g_scan_expression_class_init(GScanExpressionClass *klass) object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_expression_dispose; object->finalize = (GObjectFinalizeFunc)g_scan_expression_finalize; - klass->copy = g_scan_expression_copy; + //klass->copy = g_scan_expression_copy; + klass->intersect = _g_scan_expression_intersect; } @@ -112,6 +118,7 @@ static void g_scan_expression_class_init(GScanExpressionClass *klass) static void g_scan_expression_init(GScanExpression *expr) { + expr->state = SRS_PENDING; } @@ -292,7 +299,7 @@ GScanExpression *g_scan_expression_duplicate(const GScanExpression *expr) class = G_SCAN_EXPRESSION_GET_CLASS(expr); - class->copy(result, expr); + //class->copy(result, expr); return result; @@ -314,7 +321,200 @@ GScanExpression *g_scan_expression_duplicate(const GScanExpression *expr) * * ******************************************************************************/ -bool g_scan_expression_reduce(GScanExpression *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +ScanReductionState g_scan_expression_reduce(GScanExpression *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + GScanExpressionClass *class; /* Classe à activer */ + + if (expr->state == SRS_REDUCED) + { + *out = expr; + g_object_ref(G_OBJECT(expr)); + } + + else + { + *out = NULL; + + class = G_SCAN_EXPRESSION_GET_CLASS(expr); + + if (class->reduce != NULL) + { + expr->state = class->reduce(expr, ctx, scope, out); + + if (expr->state != SRS_UNRESOLVABLE && *out == NULL) + { + *out = expr; + g_object_ref(G_OBJECT(expr)); + } + + } + + else + expr->state = SRS_UNRESOLVABLE; + +#ifndef NDEBUG + if (*out != NULL) + assert(expr->state != SRS_UNRESOLVABLE); +#endif + + } + + assert(expr->state != SRS_PENDING); + + + return expr->state; + +} + + +/****************************************************************************** +* * +* 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 : - * +* * +******************************************************************************/ + +bool g_scan_expression_reduce_to_boolean(GScanExpression *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + bool result; /* Bilan à retourner */ + GScanExpression *inter; /* Expression intermédiaire */ + GScanExpressionClass *class; /* Classe à activer */ + + *out = NULL; + + result = g_scan_expression_reduce(expr, ctx, scope, &inter); + if (!result) goto exit; + + if (inter != NULL) + { + class = G_SCAN_EXPRESSION_GET_CLASS(inter); + + if (class->reduce_to_bool != NULL) + result = class->reduce_to_bool(inter, ctx, scope, out); + else + result = false; + + g_object_unref(G_OBJECT(inter)); + + /* Validation d'un type booléen */ + if (result && *out != NULL) + { + if (!G_IS_SCAN_LITERAL_EXPRESSION(*out)) + { + g_clear_object(out); + result = false; + } + + if (g_scan_literal_expression_get_value_type(G_SCAN_LITERAL_EXPRESSION(*out)) != LVT_BOOLEAN) + { + g_clear_object(out); + result = false; + } + + } + + } + + exit: + +#ifndef NDEBUG + if (*out != NULL) + assert(result); +#endif + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* * +* Description : Détermine si l'expression peut représenter un ensemble. * +* * +* Retour : Bilan de la consultation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_expression_handle_set_features(const GScanExpression *expr) +{ + bool result; /* Bilan à retourner */ + GScanExpressionClass *class; /* Classe à activer */ + + class = G_SCAN_EXPRESSION_GET_CLASS(expr); + + result = (class->count != NULL); + + assert((result && (class->get != NULL)) || (!result && (class->get == NULL))); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* 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 : - * +* * +******************************************************************************/ + +bool g_scan_expression_count_items(const GScanExpression *expr, size_t *count) +{ + bool result; /* Bilan à retourner */ + GScanExpressionClass *class; /* Classe à activer */ + + *count = -1; + + class = G_SCAN_EXPRESSION_GET_CLASS(expr); + + if (class->count != NULL) + result = class->count(expr, count); + else + result = false; + +#ifndef NDEBUG + if (*count != -1) + assert(result); +#endif + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* index = indice de l'élément à transférer. * +* 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 : - * +* * +******************************************************************************/ + +bool g_scan_expression_get_item(const GScanExpression *expr, size_t index, GScanExpression **out) { bool result; /* Bilan à retourner */ GScanExpressionClass *class; /* Classe à activer */ @@ -323,7 +523,17 @@ bool g_scan_expression_reduce(GScanExpression *expr, GScanContext *ctx, GScanSco class = G_SCAN_EXPRESSION_GET_CLASS(expr); - result = class->reduce(expr, ctx, scope, out); + if (class->get != NULL) + { + result = class->get(expr, index, out); + + if (*out != NULL) + g_object_ref(G_OBJECT(*out)); + + } + + else + result = false; #ifndef NDEBUG if (*out != NULL) @@ -335,6 +545,133 @@ bool g_scan_expression_reduce(GScanExpression *expr, GScanContext *ctx, GScanSco } +/****************************************************************************** +* * +* 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_expression_intersect(GScanExpression *expr, const GScanExpression *other, GScanContext *ctx, GScanScope *scope) +{ + GScanExpression *result; /* Instance à retourner */ + size_t other_count; /* Taille du second ensemble */ + bool valid; /* Bilan de validité */ + size_t expr_count; /* Taille du premier ensemble */ + size_t k; /* Boucle de parcours #1 */ + GComparableItem *comparable; /* Premier élément à comparer */ + size_t i; /* Boucle de parcours #2 */ + GScanExpression *item; /* Elément à comparer */ + bool status; /* Bilan d'une comparaison */ + + result = NULL; + + valid = g_scan_expression_count_items(other, &other_count); + if (!valid) goto done; + + /* Intersection entre deux ensembles ? */ + if (g_scan_expression_handle_set_features(expr)) + { + valid = g_scan_expression_count_items(expr, &expr_count); + if (!valid) goto done; + + result = g_scan_generic_set_new(); + + for (k = 0; k < expr_count; k++) + { + valid = g_scan_expression_get_item(expr, k, &item); + if (!valid) break; + + comparable = G_COMPARABLE_ITEM(item); + + for (i = 0; i < other_count; i++) + { + valid = g_scan_expression_get_item(other, i, &item); + if (!valid) break; + + valid = g_comparable_item_compare_rich(comparable, G_COMPARABLE_ITEM(item), RCO_EQ, &status); + + if (valid && status) + g_scan_generic_set_add_item(G_SCAN_GENERIC_SET(result), item); + + g_object_unref(G_OBJECT(item)); + + } + + g_object_unref(G_OBJECT(comparable)); + + } + + } + + /* Intersection entre un élément et un ensemble */ + else + { + comparable = G_COMPARABLE_ITEM(expr); + + for (i = 0; i < other_count && result == NULL; i++) + { + valid = g_scan_expression_get_item(other, i, &item); + if (!valid) break; + + valid = g_comparable_item_compare_rich(comparable, G_COMPARABLE_ITEM(item), RCO_EQ, &status); + + if (valid && status) + result = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { true }); + + g_object_unref(G_OBJECT(item)); + + } + + if (result && result == NULL) + result = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { false }); + + } + + done: + + 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 : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_expression_intersect(GScanExpression *expr, const GScanExpression *other, GScanContext *ctx, GScanScope *scope) +{ + GScanExpression *result; /* Instance à retourner */ + GScanExpressionClass *class; /* Classe à activer */ + + class = G_SCAN_EXPRESSION_GET_CLASS(expr); + + result = class->intersect(expr, other, ctx, scope); + + return result; + +} + + /* ---------------------------------------------------------------------------------- */ /* INTERFACE OFFRANT DES COMPARAISONS */ @@ -364,7 +701,14 @@ static bool g_scan_expression_compare_rich(const GScanExpression *item, const GS class = G_SCAN_EXPRESSION_GET_CLASS(item); if (class->cmp_rich != NULL) - result = class->cmp_rich(item, other, op, status); + { + result = (G_TYPE_FROM_INSTANCE(item) == G_TYPE_FROM_INSTANCE(other)); // FIXME : subtype ? cf. literal ? + + if (result) + result = class->cmp_rich(item, other, op, status); + + } + else result = false; diff --git a/src/analysis/scan/expr.h b/src/analysis/scan/expr.h index d596222..dd4bc3f 100644 --- a/src/analysis/scan/expr.h +++ b/src/analysis/scan/expr.h @@ -64,6 +64,16 @@ typedef enum _ExprValueType } ExprValueType; +/* Etat de l'expression vis à vis des réductions */ +typedef enum _ScanReductionState +{ + SRS_PENDING, /* Nature à déterminer */ + SRS_REDUCED, /* Nature compacte finale */ + SRS_WAIT_FOR_SCAN, /* Nature vouée à évoluer */ + SRS_UNRESOLVABLE, /* Nature indéterminable */ + +} ScanReductionState; + /* Indique le type défini pour une expression de validation. */ GType g_scan_expression_get_type(void); @@ -78,7 +88,22 @@ bool g_scan_expression_check_validity(const GScanExpression *); GScanExpression *g_scan_expression_duplicate(const GScanExpression *); /* Réduit une expression à une forme plus simple. */ -bool g_scan_expression_reduce(GScanExpression *, GScanContext *, GScanScope *, GScanExpression **); +ScanReductionState g_scan_expression_reduce(GScanExpression *, GScanContext *, GScanScope *, GScanExpression **); + +/* Réduit une expression à une forme booléenne. */ +bool g_scan_expression_reduce_to_boolean(GScanExpression *, GScanContext *, GScanScope *, GScanExpression **); + +/* Détermine si l'expression peut représenter un ensemble. */ +bool g_scan_expression_handle_set_features(const GScanExpression *); + +/* Dénombre les éléments portés par une expression. */ +bool g_scan_expression_count_items(const GScanExpression *, size_t *); + +/* Fournit un élément donné issu d'un ensemble constitué. */ +bool g_scan_expression_get_item(const GScanExpression *, size_t, GScanExpression **); + +/* Réalise l'intersection entre deux ensembles. */ +GScanExpression *g_scan_expression_intersect(GScanExpression *, const GScanExpression *, GScanContext *, GScanScope *); diff --git a/src/analysis/scan/exprs/Makefile.am b/src/analysis/scan/exprs/Makefile.am index efe25fc..1266a63 100644 --- a/src/analysis/scan/exprs/Makefile.am +++ b/src/analysis/scan/exprs/Makefile.am @@ -5,16 +5,24 @@ noinst_LTLIBRARIES = libanalysisscanexprs.la libanalysisscanexprs_la_SOURCES = \ access-int.h \ access.h access.c \ - arithmop-int.h \ - arithmop.h arithmop.c \ - boolop-int.h \ - boolop.h boolop.c \ + arithmetic-int.h \ + arithmetic.h arithmetic.c \ call-int.h \ call.h call.c \ + counter-int.h \ + counter.h counter.c \ + intersect-int.h \ + intersect.h intersect.c \ literal-int.h \ literal.h literal.c \ - relop-int.h \ - relop.h relop.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 \ strop-int.h \ strop.h strop.c diff --git a/src/analysis/scan/exprs/access-int.h b/src/analysis/scan/exprs/access-int.h index 2212b48..725051c 100644 --- a/src/analysis/scan/exprs/access-int.h +++ b/src/analysis/scan/exprs/access-int.h @@ -32,8 +32,11 @@ +/* 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 _GNamedAccess +struct _GScanNamedAccess { GScanExpression parent; /* A laisser en premier */ @@ -46,23 +49,25 @@ struct _GNamedAccess char *target; /* Cible dans l'espace */ - struct _GNamedAccess *next; /* Evnetuel prochain élément */ + struct _GScanNamedAccess *next; /* Evnetuel prochain élément */ }; /* Accès à un élément d'expression sous-jacent (classe) */ -struct _GNamedAccessClass +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_named_access_create(GNamedAccess *, const sized_string_t *); +bool g_scan_named_access_create(GScanNamedAccess *, const sized_string_t *); -/* Réduit une expression à une forme plus simple. */ -bool _g_named_access_reduce(GNamedAccess *, GScanContext *, GScanScope *, GScanExpression **); +/* Prépare une réduction en menant une résolution locale. */ +GRegisteredItem *_g_scan_named_access_prepare_reduction(GScanNamedAccess *, GScanContext *, GScanScope *); diff --git a/src/analysis/scan/exprs/access.c b/src/analysis/scan/exprs/access.c index ad66f60..1c3a880 100644 --- a/src/analysis/scan/exprs/access.c +++ b/src/analysis/scan/exprs/access.c @@ -30,6 +30,7 @@ #include "access-int.h" +#include "literal.h" #include "../../../core/global.h" @@ -38,27 +39,27 @@ /* Initialise la classe des appels de fonction avec arguments. */ -static void g_named_access_class_init(GNamedAccessClass *); +static void g_scan_named_access_class_init(GScanNamedAccessClass *); /* Initialise une instance d'appel de fonction avec arguments. */ -static void g_named_access_init(GNamedAccess *); +static void g_scan_named_access_init(GScanNamedAccess *); /* Supprime toutes les références externes. */ -static void g_named_access_dispose(GNamedAccess *); +static void g_scan_named_access_dispose(GScanNamedAccess *); /* Procède à la libération totale de la mémoire. */ -static void g_named_access_finalize(GNamedAccess *); +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 --------------------- */ +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ -/* Reproduit une expression en place dans une nouvelle instance. */ -static void g_named_access_copy(GNamedAccess *, const GNamedAccess *); /* Réduit une expression à une forme plus simple. */ -static bool g_named_access_reduce(GNamedAccess *, GScanContext *, GScanScope *, GScanExpression **); +static ScanReductionState g_scan_named_access_reduce(GScanNamedAccess *, GScanContext *, GScanScope *, GScanExpression **); @@ -68,7 +69,7 @@ static bool g_named_access_reduce(GNamedAccess *, GScanContext *, GScanScope *, /* Indique le type défini pour un appel de fonction enregistrée. */ -G_DEFINE_TYPE(GNamedAccess, g_named_access, G_TYPE_SCAN_EXPRESSION); +G_DEFINE_TYPE(GScanNamedAccess, g_scan_named_access, G_TYPE_SCAN_EXPRESSION); /****************************************************************************** @@ -83,21 +84,22 @@ G_DEFINE_TYPE(GNamedAccess, g_named_access, G_TYPE_SCAN_EXPRESSION); * * ******************************************************************************/ -static void g_named_access_class_init(GNamedAccessClass *klass) +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_named_access_dispose; - object->finalize = (GObjectFinalizeFunc)g_named_access_finalize; + 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->copy = (copy_expr_fc)g_named_access_copy; - expr->reduce = (reduce_expr_fc)g_named_access_reduce; + expr->reduce = (reduce_expr_fc)g_scan_named_access_reduce; + + klass->copy = g_scan_named_access_copy; } @@ -114,7 +116,7 @@ static void g_named_access_class_init(GNamedAccessClass *klass) * * ******************************************************************************/ -static void g_named_access_init(GNamedAccess *access) +static void g_scan_named_access_init(GScanNamedAccess *access) { access->any = NULL; access->target = NULL; @@ -136,13 +138,13 @@ static void g_named_access_init(GNamedAccess *access) * * ******************************************************************************/ -static void g_named_access_dispose(GNamedAccess *access) +static void g_scan_named_access_dispose(GScanNamedAccess *access) { g_clear_object(&access->any); g_clear_object(&access->next); - G_OBJECT_CLASS(g_named_access_parent_class)->dispose(G_OBJECT(access)); + G_OBJECT_CLASS(g_scan_named_access_parent_class)->dispose(G_OBJECT(access)); } @@ -159,12 +161,12 @@ static void g_named_access_dispose(GNamedAccess *access) * * ******************************************************************************/ -static void g_named_access_finalize(GNamedAccess *access) +static void g_scan_named_access_finalize(GScanNamedAccess *access) { if (access->target != NULL) free(access->target); - G_OBJECT_CLASS(g_named_access_parent_class)->finalize(G_OBJECT(access)); + G_OBJECT_CLASS(g_scan_named_access_parent_class)->finalize(G_OBJECT(access)); } @@ -181,13 +183,13 @@ static void g_named_access_finalize(GNamedAccess *access) * * ******************************************************************************/ -GScanExpression *g_named_access_new(const sized_string_t *target) +GScanExpression *g_scan_named_access_new(const sized_string_t *target) { GScanExpression *result; /* Structure à retourner */ - result = g_object_new(G_TYPE_NAMED_ACCESS, NULL); + result = g_object_new(G_TYPE_SCAN_NAMED_ACCESS, NULL); - if (!g_named_access_create(G_NAMED_ACCESS(result), target)) + if (!g_scan_named_access_create(G_SCAN_NAMED_ACCESS(result), target)) g_clear_object(&result); return result; @@ -208,16 +210,14 @@ GScanExpression *g_named_access_new(const sized_string_t *target) * * ******************************************************************************/ -bool g_named_access_create(GNamedAccess *access, const sized_string_t *target) +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), EVT_PENDING); - if (!result) goto exit; - - access->target = strndup(target->data, target->len); + result = true; - exit: + if (target != NULL) + access->target = strndup(target->data, target->len); return result; @@ -226,10 +226,10 @@ bool g_named_access_create(GNamedAccess *access, const sized_string_t *target) /****************************************************************************** * * -* Paramètres : access = expression d'appel à actualiser. * -* base = zone de recherche pour la résolution à venir. * +* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * +* src = expression source à copier. * * * -* Description : Définit une base de recherche pour la cible d'accès. * +* Description : Reproduit un accès en place dans une nouvelle instance. * * * * Retour : - * * * @@ -237,55 +237,74 @@ bool g_named_access_create(GNamedAccess *access, const sized_string_t *target) * * ******************************************************************************/ -void g_named_access_set_base(GNamedAccess *access, GRegisteredItem *base) +static void g_scan_named_access_copy(GScanNamedAccess *dest, const GScanNamedAccess *src) { - g_clear_object(&access->base); + /** + * Les champs suivants sont voués à être remplacés ou supprimés. + * + * On évite donc une instanciation inutile. + */ - access->base = base; - g_object_ref(G_OBJECT(base)); + /* + 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 : access = expression d'appel à compléter. * -* next = expression d'appel suivante dans la chaîne. * +* Paramètres : accès = expression d'accès à copier. * +* resolved = nouvelle base à imposer. * * * -* Description : Complète la chaine d'accès à des expressions. * +* Description : Reproduit un accès en place dans une nouvelle instance. * * * -* Retour : - * +* Retour : Nouvelle instance d'expression d'accès. * * * * Remarques : - * * * ******************************************************************************/ -void g_named_access_attach_next(GNamedAccess *access, GNamedAccess *next) +GScanExpression *g_scan_named_access_duplicate(const GScanNamedAccess *access, GRegisteredItem *resolved) { - if (access->next != NULL) - g_named_access_attach_next(access->next, next); + GScanExpression *result; /* Instance copiée à retourner */ + GType type; /* Type d'objet à copier */ + GScanNamedAccessClass *class; /* Classe à activer */ - else - { - access->next = next; - g_object_ref(G_OBJECT(next)); - } + 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); -/* ---------------------------------------------------------------------------------- */ -/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ -/* ---------------------------------------------------------------------------------- */ + g_scan_named_access_set_base(G_SCAN_NAMED_ACCESS(result), resolved); + + return result; + +} /****************************************************************************** * * -* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * -* src = expression source à copier. * +* Paramètres : access = expression d'appel à actualiser. * +* base = zone de recherche pour la résolution à venir. * * * -* Description : Reproduit une expression en place dans une nouvelle instance.* +* Description : Définit une base de recherche pour la cible d'accès. * * * * Retour : - * * * @@ -293,27 +312,47 @@ void g_named_access_attach_next(GNamedAccess *access, GNamedAccess *next) * * ******************************************************************************/ -static void g_named_access_copy(GNamedAccess *dest, const GNamedAccess *src) +void g_scan_named_access_set_base(GScanNamedAccess *access, GRegisteredItem *base) { - GScanExpressionClass *class; /* Classe parente à solliciter */ + g_clear_object(&access->base); - class = G_SCAN_EXPRESSION_CLASS(g_named_access_parent_class); + access->base = base; + g_object_ref(G_OBJECT(base)); - class->copy(G_SCAN_EXPRESSION(dest), G_SCAN_EXPRESSION(src)); +} - if (src->any != NULL) + +/****************************************************************************** +* * +* 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 { - dest->any = src->any; - g_object_ref(src->any); + access->next = next; + g_object_ref(G_OBJECT(next)); } - if (src->target != NULL) - dest->target = strdup(src->target); +} - if (src->next != NULL) - dest->next = G_NAMED_ACCESS(g_scan_expression_duplicate(G_SCAN_EXPRESSION(src->next))); -} + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** @@ -321,24 +360,21 @@ static void g_named_access_copy(GNamedAccess *dest, const GNamedAccess *src) * 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. * +* Description : Prépare une réduction en menant une résolution locale. * * * -* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* Retour : Elément résolu avec les moyens du bord ou NULL si échec. * * * * Remarques : - * * * ******************************************************************************/ -bool _g_named_access_reduce(GNamedAccess *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +GRegisteredItem *_g_scan_named_access_prepare_reduction(GScanNamedAccess *expr, GScanContext *ctx, GScanScope *scope) { - bool result; /* Bilan à retourner */ + GRegisteredItem *result; /* Etat synthétisé à retourner */ GRegisteredItem *base; /* Base de recherche courante */ - GRegisteredItem *resolved; /* Cible concrète obtenue */ - GNamedAccess *new; /* Copie mise en place */ - result = true; + result = NULL; if (expr->target != NULL) { @@ -350,24 +386,7 @@ bool _g_named_access_reduce(GNamedAccess *expr, GScanContext *ctx, GScanScope *s else base = G_REGISTERED_ITEM(get_rost_root_namespace()); - result = g_registered_item_resolve(base, expr->target, ctx, scope, &resolved); - - g_object_unref(G_OBJECT(base)); - - if (result && resolved != NULL) - { - new = G_NAMED_ACCESS(g_scan_expression_duplicate(G_SCAN_EXPRESSION(expr))); - - g_clear_object(&new->base); - - free(new->target); - new->target = NULL; - - new->resolved = resolved; - - *out = G_SCAN_EXPRESSION(new); - - } + g_registered_item_resolve(base, expr->target, ctx, scope, &result); } @@ -379,8 +398,8 @@ bool _g_named_access_reduce(GNamedAccess *expr, GScanContext *ctx, GScanScope *s { assert(expr->resolved != NULL); - *out = G_SCAN_EXPRESSION(expr); - g_object_ref(G_OBJECT(*out)); + result = expr->resolved; + g_object_ref(G_OBJECT(result)); } @@ -404,25 +423,18 @@ bool _g_named_access_reduce(GNamedAccess *expr, GScanContext *ctx, GScanScope *s * * ******************************************************************************/ -static bool g_named_access_reduce(GNamedAccess *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +static ScanReductionState g_scan_named_access_reduce(GScanNamedAccess *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) { - bool result; /* Bilan à retourner */ - GNamedAccess *new; /* Eventuel étage suivant */ - GScanExpression *final; /* Expression d'évaluation */ + ScanReductionState result; /* Etat synthétisé à retourner */ + GRegisteredItem *resolved; /* Cible concrète obtenue */ GScanExpression *new_next; /* Nouvelle version du suivant */ + bool status; /* Bilan d'une autre règle */ - result = _g_named_access_reduce(expr, ctx, scope, out); + resolved = _g_scan_named_access_prepare_reduction(expr, ctx, scope); - if (result && *out != NULL) + if (resolved != NULL) { - assert(G_IS_NAMED_ACCESS(*out)); - - new = G_NAMED_ACCESS(*out); - *out = NULL; - - assert(new->target == NULL); - assert(G_IS_NAMED_ACCESS(new)); - assert(G_IS_REGISTERED_ITEM(new->resolved)); + result = SRS_PENDING; /** * Si l'élément résolu se trouve en fin de chaîne, alors cet élément @@ -430,15 +442,11 @@ static bool g_named_access_reduce(GNamedAccess *expr, GScanContext *ctx, GScanSc * 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 (new->next == NULL) + if (expr->next == NULL) { - result = g_registered_item_reduce(new->resolved, ctx, scope, &final); + status = g_registered_item_reduce(resolved, ctx, scope, out); - if (result && final != NULL) - { - g_clear_object(out); - *out = final; - } + result = (status ? SRS_REDUCED : SRS_UNRESOLVABLE); } @@ -448,21 +456,34 @@ static bool g_named_access_reduce(GNamedAccess *expr, GScanContext *ctx, GScanSc */ else { - new_next = g_scan_expression_duplicate(G_SCAN_EXPRESSION(new->next)); - assert(G_IS_NAMED_ACCESS(new_next)); - - g_named_access_set_base(G_NAMED_ACCESS(new_next), new->resolved); - - g_clear_object(out); + new_next = g_scan_named_access_duplicate(expr->next, resolved); result = g_scan_expression_reduce(new_next, ctx, scope, out); - if (result && *out == NULL) - *out = new_next; + g_object_unref(G_OBJECT(new_next)); } - g_object_unref(G_OBJECT(new)); + 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)) + { + status = g_scan_context_has_match_for_rule(ctx, expr->target); + + *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status); + result = SRS_REDUCED; + + } } diff --git a/src/analysis/scan/exprs/access.h b/src/analysis/scan/exprs/access.h index a04adc7..7c007a9 100644 --- a/src/analysis/scan/exprs/access.h +++ b/src/analysis/scan/exprs/access.h @@ -31,32 +31,35 @@ -#define G_TYPE_NAMED_ACCESS g_named_access_get_type() -#define G_NAMED_ACCESS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_NAMED_ACCESS, GNamedAccess)) -#define G_IS_NAMED_ACCESS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_NAMED_ACCESS)) -#define G_NAMED_ACCESS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_NAMED_ACCESS, GNamedAccessClass)) -#define G_IS_NAMED_ACCESS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_NAMED_ACCESS)) -#define G_NAMED_ACCESS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_NAMED_ACCESS, GNamedAccessClass)) +#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 _GNamedAccess GNamedAccess; +typedef struct _GScanNamedAccess GScanNamedAccess; /* Accès à un élément d'expression sous-jacent (classe) */ -typedef struct _GNamedAccessClass GNamedAccessClass; +typedef struct _GScanNamedAccessClass GScanNamedAccessClass; /* Indique le type défini pour un appel de fonction enregistrée. */ -GType g_named_access_get_type(void); +GType g_scan_named_access_get_type(void); /* Organise un accès à un élément d'expression sous-jacent. */ -GScanExpression *g_named_access_new(const sized_string_t *); +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 *, GRegisteredItem *); /* Définit une base de recherche pour la cible d'accès. */ -void g_named_access_set_base(GNamedAccess *, GRegisteredItem *); +void g_scan_named_access_set_base(GScanNamedAccess *, GRegisteredItem *); /* Complète la chaine d'accès à des expressions. */ -void g_named_access_attach_next(GNamedAccess *, GNamedAccess *); +void g_scan_named_access_attach_next(GScanNamedAccess *, GScanNamedAccess *); 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 . + */ + + +#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..0c01d2a --- /dev/null +++ b/src/analysis/scan/exprs/arithmetic.c @@ -0,0 +1,638 @@ + +/* 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 . + */ + + +#include "arithmetic.h" + + +#include + + +#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(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 = true; + + op->operator = operator; + + op->left = left; + g_object_ref(G_OBJECT(op->left)); + + op->right = right; + g_object_ref(G_OBJECT(op->right)); + + 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(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 . + */ + + +#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/arithmop-int.h b/src/analysis/scan/exprs/arithmop-int.h deleted file mode 100644 index 031de84..0000000 --- a/src/analysis/scan/exprs/arithmop-int.h +++ /dev/null @@ -1,60 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * arithmop-int.h - prototypes internes pour la gestion des opérations arithmétiques - * - * Copyright (C) 2022 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . - */ - - -#ifndef _ANALYSIS_SCAN_EXPRS_ARITHMOP_INT_H -#define _ANALYSIS_SCAN_EXPRS_ARITHMOP_INT_H - - -#include "arithmop.h" - - -#include "../expr-int.h" - - - -/* Opération arithmétique impliquant deux opérandes (instance) */ -struct _GArithmOperation -{ - 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 _GArithmOperationClass -{ - GScanExpressionClass parent; /* A laisser en premier */ - -}; - - -/* Met en place une opération arithmétique entre expressions. */ -bool g_arithmetic_operation_create(GArithmOperation *, ArithmeticExpressionOperator, GScanExpression *, GScanExpression *); - - - -#endif /* _ANALYSIS_SCAN_EXPRS_ARITHMOP_INT_H */ diff --git a/src/analysis/scan/exprs/arithmop.c b/src/analysis/scan/exprs/arithmop.c deleted file mode 100644 index 5f9e3f1..0000000 --- a/src/analysis/scan/exprs/arithmop.c +++ /dev/null @@ -1,436 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * arithmop.c - gestion des opérations arithmétiques - * - * Copyright (C) 2022 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . - */ - - -#include "arithmop.h" - - -#include "arithmop-int.h" -#include "literal.h" - - - -/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ - - -/* Initialise la classe des opérations arithmétiques. */ -static void g_arithmetic_operation_class_init(GArithmOperationClass *); - -/* Initialise une instance d'opération arithmétique. */ -static void g_arithmetic_operation_init(GArithmOperation *); - -/* Supprime toutes les références externes. */ -static void g_arithmetic_operation_dispose(GArithmOperation *); - -/* Procède à la libération totale de la mémoire. */ -static void g_arithmetic_operation_finalize(GArithmOperation *); - - - -/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ - - -/* Réalise une comparaison entre objets selon un critère précis. */ -static bool g_arithmetic_operation_compare_rich(const GArithmOperation *, const GArithmOperation *, RichCmpOperation, bool *); - -/* Reproduit une expression en place dans une nouvelle instance. */ -static void g_arithmetic_operation_copy(GArithmOperation *, const GArithmOperation *); - -/* Réduit une expression à une forme plus simple. */ -static bool g_arithmetic_operation_reduce(GArithmOperation *, GScanContext *, GScanScope *, GScanExpression **); - - - -/* ---------------------------------------------------------------------------------- */ -/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ -/* ---------------------------------------------------------------------------------- */ - - -/* Indique le type défini pour une opération de relation entre expressions. */ -G_DEFINE_TYPE(GArithmOperation, g_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_arithmetic_operation_class_init(GArithmOperationClass *klass) -{ - GObjectClass *object; /* Autre version de la classe */ - GScanExpressionClass *expr; /* Version de classe parente */ - - object = G_OBJECT_CLASS(klass); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_arithmetic_operation_dispose; - object->finalize = (GObjectFinalizeFunc)g_arithmetic_operation_finalize; - - expr = G_SCAN_EXPRESSION_CLASS(klass); - - expr->cmp_rich = (compare_expr_rich_fc)g_arithmetic_operation_compare_rich; - expr->copy = (copy_expr_fc)g_arithmetic_operation_copy; - expr->reduce = (reduce_expr_fc)g_arithmetic_operation_reduce; - -} - - -/****************************************************************************** -* * -* Paramètres : op = instance à initialiser. * -* * -* Description : Initialise une instance d'opération arithmétique. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_arithmetic_operation_init(GArithmOperation *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_arithmetic_operation_dispose(GArithmOperation *op) -{ - g_clear_object(&op->left); - g_clear_object(&op->right); - - G_OBJECT_CLASS(g_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_arithmetic_operation_finalize(GArithmOperation *op) -{ - G_OBJECT_CLASS(g_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_arithmetic_operation_new(ArithmeticExpressionOperator operator, GScanExpression *left, GScanExpression *right) -{ - GScanExpression *result; /* Structure à retourner */ - - result = g_object_new(G_TYPE_ARITHMETIC_OPERATION, NULL); - - if (!g_arithmetic_operation_create(G_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_arithmetic_operation_create(GArithmOperation *op, ArithmeticExpressionOperator operator, GScanExpression *left, GScanExpression *right) -{ - bool result; /* Bilan à retourner */ - ExprValueType vtype; /* Type de valeur portée */ - - result = false; - - vtype = g_scan_expression_get_value_type(left); - - if (vtype != EVT_INTEGER && vtype != EVT_PENDING) - goto exit; - - vtype = g_scan_expression_get_value_type(right); - - if (vtype != EVT_INTEGER && vtype != EVT_PENDING) - goto exit; - - if (!g_scan_expression_create(G_SCAN_EXPRESSION(op), EVT_INTEGER)) - 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)); - - result = true; - - 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_arithmetic_operation_compare_rich(const GArithmOperation *item, const GArithmOperation *other, RichCmpOperation op, bool *status) -{ - bool result; /* Etat à retourner */ - - result = g_type_is_a(G_TYPE_FROM_INSTANCE(other), G_TYPE_ARITHMETIC_OPERATION); - if (!result) goto done; - - if (item->operator != other->operator) - { - result = compare_rich_integer_values(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 : dest = emplacement d'enregistrement à constituer. [OUT] * -* src = expression source à copier. * -* * -* Description : Reproduit une expression en place dans une nouvelle instance.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_arithmetic_operation_copy(GArithmOperation *dest, const GArithmOperation *src) -{ - GScanExpressionClass *class; /* Classe parente à solliciter */ - - class = G_SCAN_EXPRESSION_CLASS(g_arithmetic_operation_parent_class); - - class->copy(G_SCAN_EXPRESSION(dest), G_SCAN_EXPRESSION(src)); - - dest->operator = src->operator; - - dest->left = g_scan_expression_duplicate(src->left); - dest->right = g_scan_expression_duplicate(src->right); - -} - - -/****************************************************************************** -* * -* 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 bool g_arithmetic_operation_reduce(GArithmOperation *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) -{ - bool result; /* Bilan à retourner */ - GScanExpression *new_left; /* Expression réduite (gauche) */ - GScanExpression *new_right; /* Expression réduite (droite) */ - GLiteralExpression *op_left; /* Opérande gauche final */ - GLiteralExpression *op_right; /* Opérande droite final */ - unsigned long long val_1; /* Première valeur à traiter */ - unsigned long long val_2; /* Seconde valeur à traiter */ - unsigned long long reduced; /* Valeur réduite finale */ - - /* Réduction des éléments considérés */ - - new_left = NULL; - new_right = NULL; - - result = g_scan_expression_reduce(expr->left, ctx, scope, &new_left); - if (!result) goto exit; - - result = g_scan_expression_reduce(expr->right, ctx, scope, &new_right); - if (!result) goto exit; - - /* Construction d'une réduction locale ? */ - - if (G_IS_LITERAL_EXPRESSION(new_left) && G_IS_LITERAL_EXPRESSION(new_right)) - { - op_left = G_LITERAL_EXPRESSION(new_left); - op_right = G_LITERAL_EXPRESSION(new_right); - - result = g_literal_expression_get_integer_value(op_left, &val_1); - if (!result) goto exit; - - result = g_literal_expression_get_integer_value(op_right, &val_2); - if (!result) goto exit; - - switch (expr->operator) - { - case AEO_PLUS: - reduced = val_1 + val_2; - break; - - case AEO_MINUS: - reduced = val_1 - val_2; - break; - - case AEO_MUL: - reduced = val_1 * val_2; - break; - - case AEO_DIV: - result = (val_2 != 0); - if (result) - reduced = val_1 / val_2; - break; - - case AEO_MOD: - result = (val_2 != 0); - if (result) - reduced = val_1 % val_2; - break; - - } - - if (result) - *out = g_literal_expression_new(EVT_INTEGER, &reduced); - - } - - /* Mise à jour de la progression ? */ - - else if ((new_left != NULL && new_left != expr->left) || (new_right != NULL && new_right != expr->right)) - { - if (new_left == NULL) - { - new_left = expr->left; - g_object_ref(G_OBJECT(new_left)); - } - - if (new_right == NULL) - { - new_right = expr->right; - g_object_ref(G_OBJECT(new_right)); - } - - *out = g_arithmetic_operation_new(expr->operator, new_left, new_right); - - } - - exit: - - g_clear_object(&new_left); - g_clear_object(&new_right); - - return result; - -} diff --git a/src/analysis/scan/exprs/arithmop.h b/src/analysis/scan/exprs/arithmop.h deleted file mode 100644 index dcc8bf8..0000000 --- a/src/analysis/scan/exprs/arithmop.h +++ /dev/null @@ -1,67 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * arithmop.h - prototypes pour la gestion des opérations arithmétiques - * - * Copyright (C) 2022 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . - */ - - -#ifndef _ANALYSIS_SCAN_EXPRS_ARITHMOP_H -#define _ANALYSIS_SCAN_EXPRS_ARITHMOP_H - - -#include "../expr.h" - - - -#define G_TYPE_ARITHMETIC_OPERATION g_arithmetic_operation_get_type() -#define G_ARITHMETIC_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ARITHMETIC_OPERATION, GArithmOperation)) -#define G_IS_ARITHMETIC_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ARITHMETIC_OPERATION)) -#define G_ARITHMETIC_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ARITHMETIC_OPERATION, GArithmOperationClass)) -#define G_IS_ARITHMETIC_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ARITHMETIC_OPERATION)) -#define G_ARITHMETIC_OPERATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ARITHMETIC_OPERATION, GArithmOperationClass)) - - -/* Opération arithmétique impliquant deux opérandes (instance) */ -typedef struct _GArithmOperation GArithmOperation; - -/* Opération arithmétique impliquant deux opérandes (classe) */ -typedef struct _GArithmOperationClass GArithmOperationClass; - - -/* 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_arithmetic_operation_get_type(void); - -/* Organise une opération arithmétique entre expressions. */ -GScanExpression *g_arithmetic_operation_new(ArithmeticExpressionOperator, GScanExpression *, GScanExpression *); - - - -#endif /* _ANALYSIS_SCAN_EXPRS_ARITHMOP_H */ diff --git a/src/analysis/scan/exprs/boolop-int.h b/src/analysis/scan/exprs/boolop-int.h deleted file mode 100644 index c381cfe..0000000 --- a/src/analysis/scan/exprs/boolop-int.h +++ /dev/null @@ -1,60 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * boolop-int.h - prototypes internes pour la gestion des opérations booléennes - * - * Copyright (C) 2022 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . - */ - - -#ifndef _ANALYSIS_SCAN_EXPRS_BOOLOP_INT_H -#define _ANALYSIS_SCAN_EXPRS_BOOLOP_INT_H - - -#include "boolop.h" - - -#include "../expr-int.h" - - - -/* Opération booléenne avec un ou deux opérandes (instance) */ -struct _GBoolOperation -{ - 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 _GBoolOperationClass -{ - GScanExpressionClass parent; /* A laisser en premier */ - -}; - - -/* Met en place une expression d'opération booléenne. */ -bool g_boolean_operation_create(GBoolOperation *, BooleanOperationType, GScanExpression *, GScanExpression *); - - - -#endif /* _ANALYSIS_SCAN_EXPRS_BOOLOP_INT_H */ diff --git a/src/analysis/scan/exprs/boolop.c b/src/analysis/scan/exprs/boolop.c deleted file mode 100644 index f6a80dd..0000000 --- a/src/analysis/scan/exprs/boolop.c +++ /dev/null @@ -1,479 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * boolop.c - gestion des opérations booléennes - * - * Copyright (C) 2022 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . - */ - - -#include "boolop.h" - - -#include - - -#include "boolop-int.h" -#include "literal.h" - - - -/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ - - -/* Initialise la classe des opérations booléennes. */ -static void g_boolean_operation_class_init(GBoolOperationClass *); - -/* Initialise une instance d'opération booléenne. */ -static void g_boolean_operation_init(GBoolOperation *); - -/* Supprime toutes les références externes. */ -static void g_boolean_operation_dispose(GBoolOperation *); - -/* Procède à la libération totale de la mémoire. */ -static void g_boolean_operation_finalize(GBoolOperation *); - - - -/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ - - -/* Réalise une comparaison entre objets selon un critère précis. */ -static bool g_boolean_operation_compare_rich(const GBoolOperation *, const GBoolOperation *, RichCmpOperation, bool *); - -/* Reproduit une expression en place dans une nouvelle instance. */ -static void g_boolean_operation_copy(GBoolOperation *, const GBoolOperation *); - -/* Réduit une expression à une forme plus simple. */ -static bool g_boolean_operation_reduce(GBoolOperation *, 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(GBoolOperation, g_boolean_operation, G_TYPE_SCAN_EXPRESSION); - - -/****************************************************************************** -* * -* Paramètres : klass = classe à initialiser. * -* * -* Description : Initialise la classe des opérations booléennes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_boolean_operation_class_init(GBoolOperationClass *klass) -{ - GObjectClass *object; /* Autre version de la classe */ - GScanExpressionClass *expr; /* Version de classe parente */ - - object = G_OBJECT_CLASS(klass); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_boolean_operation_dispose; - object->finalize = (GObjectFinalizeFunc)g_boolean_operation_finalize; - - expr = G_SCAN_EXPRESSION_CLASS(klass); - - expr->cmp_rich = (compare_expr_rich_fc)g_boolean_operation_compare_rich; - expr->copy = (copy_expr_fc)g_boolean_operation_copy; - expr->reduce = (reduce_expr_fc)g_boolean_operation_reduce; - -} - - -/****************************************************************************** -* * -* Paramètres : op = instance à initialiser. * -* * -* Description : Initialise une instance d'opération booléenne. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_boolean_operation_init(GBoolOperation *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_boolean_operation_dispose(GBoolOperation *op) -{ - g_clear_object(&op->first); - g_clear_object(&op->second); - - G_OBJECT_CLASS(g_boolean_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_boolean_operation_finalize(GBoolOperation *op) -{ - G_OBJECT_CLASS(g_boolean_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_boolean_operation_new(BooleanOperationType type, GScanExpression *first, GScanExpression *second) -{ - GScanExpression *result; /* Structure à retourner */ - - result = g_object_new(G_TYPE_BOOLEAN_OPERATION, NULL); - - if (!g_boolean_operation_create(G_BOOLEAN_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_boolean_operation_create(GBoolOperation *op, BooleanOperationType type, GScanExpression *first, GScanExpression *second) -{ - bool result; /* Bilan à retourner */ - - result = false; - - if (g_scan_expression_get_value_type(first) != EVT_BOOLEAN) - goto exit; - - if (g_scan_expression_get_value_type(second) != EVT_BOOLEAN) - goto exit; - - if (!g_scan_expression_create(G_SCAN_EXPRESSION(op), EVT_BOOLEAN)) - 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; - - } - - 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_boolean_operation_compare_rich(const GBoolOperation *item, const GBoolOperation *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(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 : dest = emplacement d'enregistrement à constituer. [OUT] * -* src = expression source à copier. * -* * -* Description : Reproduit une expression en place dans une nouvelle instance.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_boolean_operation_copy(GBoolOperation *dest, const GBoolOperation *src) -{ - GScanExpressionClass *class; /* Classe parente à solliciter */ - - class = G_SCAN_EXPRESSION_CLASS(g_boolean_operation_parent_class); - - class->copy(G_SCAN_EXPRESSION(dest), G_SCAN_EXPRESSION(src)); - - dest->type = src->type; - - dest->first = g_scan_expression_duplicate(src->first); - - if (src->second != NULL) - dest->second = g_scan_expression_duplicate(src->second); - -} - - -/****************************************************************************** -* * -* 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 bool g_boolean_operation_reduce(GBoolOperation *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) -{ - bool result; /* Bilan à retourner */ - GScanExpression *new_first; /* Expression réduite (gauche) */ - GScanExpression *new_second; /* Expression réduite (droite) */ - bool values[2]; /* Valeurs des éléments portés */ - bool valid[2]; /* Validité de ces valeurs */ - - /* Réduction des éléments considérés */ - - new_first = NULL; - new_second = NULL; - - result = g_scan_expression_reduce(expr->first, ctx, scope, &new_first); - if (!result) goto exit; - - if (expr->second == NULL) - new_second = NULL; - else - { - result = g_scan_expression_reduce(expr->second, ctx, scope, &new_second); - if (!result) goto exit; - } - - /* Construction d'une réduction locale ? */ - - valid[0] = G_IS_LITERAL_EXPRESSION(new_first); - - if (valid[0]) - valid[0] = g_literal_expression_get_boolean_value(G_LITERAL_EXPRESSION(new_first), &values[0]); - - valid[1] = G_IS_LITERAL_EXPRESSION(new_second); - - if (valid[1]) - valid[1] = g_literal_expression_get_boolean_value(G_LITERAL_EXPRESSION(new_second), &values[1]); - - switch (expr->type) - { - case BOT_AND: - if (valid[0] && valid[1]) - *out = g_literal_expression_new(EVT_BOOLEAN, (bool []) { values[0] && values[1] }); - - else if (valid[0] && !values[0]) - *out = g_literal_expression_new(EVT_BOOLEAN, (bool []) { false }); - - else if (valid[1] && !values[1]) - *out = g_literal_expression_new(EVT_BOOLEAN, (bool []) { false }); - - break; - - case BOT_OR: - if (valid[0] && valid[1]) - *out = g_literal_expression_new(EVT_BOOLEAN, (bool []) { values[0] || values[1] }); - - else if (valid[0] && values[0]) - *out = g_literal_expression_new(EVT_BOOLEAN, (bool []) { true }); - - else if (valid[1] && values[1]) - *out = g_literal_expression_new(EVT_BOOLEAN, (bool []) { true }); - - break; - - case BOT_NOT: - if (valid[0]) - *out = g_literal_expression_new(EVT_BOOLEAN, (bool []) { !values[0] }); - break; - - } - - /* Mise à jour de la progression ? */ - - if (*out == NULL) - { - if ((new_first != NULL && new_first != expr->first) || (new_second != NULL && new_second != expr->second)) - { - if (new_first == NULL) - { - new_first = expr->first; - g_object_ref(G_OBJECT(new_first)); - } - - if (new_second == NULL) - { - new_second = expr->second; - g_object_ref(G_OBJECT(new_second)); - } - - *out = g_boolean_operation_new(expr->type, new_first, new_second); - - } - - } - - exit: - - g_clear_object(&new_first); - g_clear_object(&new_second); - - return result; - -} diff --git a/src/analysis/scan/exprs/boolop.h b/src/analysis/scan/exprs/boolop.h deleted file mode 100644 index 4add5a1..0000000 --- a/src/analysis/scan/exprs/boolop.h +++ /dev/null @@ -1,65 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * boolop.h - prototypes pour la gestion des opérations booléennes - * - * Copyright (C) 2022 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . - */ - - -#ifndef _ANALYSIS_SCAN_EXPRS_BOOLOP_H -#define _ANALYSIS_SCAN_EXPRS_BOOLOP_H - - -#include "../expr.h" - - - -#define G_TYPE_BOOLEAN_OPERATION g_boolean_operation_get_type() -#define G_BOOLEAN_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BOOLEAN_OPERATION, GBoolOperation)) -#define G_IS_BOOLEAN_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BOOLEAN_OPERATION)) -#define G_BOOLEAN_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BOOLEAN_OPERATION, GBoolOperationClass)) -#define G_IS_BOOLEAN_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BOOLEAN_OPERATION)) -#define G_BOOLEAN_OPERATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BOOLEAN_OPERATION, GBoolOperationClass)) - - -/* Opération booléenne avec un ou deux opérandes (instance) */ -typedef struct _GBoolOperation GBoolOperation; - -/* Opération booléenne avec un ou deux opérandes (classe) */ -typedef struct _GBoolOperationClass GBoolOperationClass; - - -/* 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_boolean_operation_get_type(void); - -/* Organise un appel de fonction avec ses arguments. */ -GScanExpression *g_boolean_operation_new(BooleanOperationType, GScanExpression *, GScanExpression *); - - - -#endif /* _ANALYSIS_SCAN_EXPRS_BOOLOP_H */ diff --git a/src/analysis/scan/exprs/call-int.h b/src/analysis/scan/exprs/call-int.h index 631a25b..9646b95 100644 --- a/src/analysis/scan/exprs/call-int.h +++ b/src/analysis/scan/exprs/call-int.h @@ -2,7 +2,7 @@ /* 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) 2022 Cyrille Bagard + * Copyright (C) 2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -33,9 +33,9 @@ /* Exécution d'une fonction auxiliaire d'analyse (instance) */ -struct _GPendingCall +struct _GScanPendingCall { - GNamedAccess parent; /* A laisser en premier */ + GScanNamedAccess parent; /* A laisser en premier */ GScanExpression **args; /* Arguments d'appel fournis */ size_t count; /* Quantité de ces arguments */ @@ -43,15 +43,15 @@ struct _GPendingCall }; /* Exécution d'une fonction auxiliaire d'analyse (classe) */ -struct _GPendingCallClass +struct _GScanPendingCallClass { - GNamedAccessClass parent; /* A laisser en premier */ + GScanNamedAccessClass parent; /* A laisser en premier */ }; /* Met en place une expression d'appel. */ -bool g_pending_call_create(GPendingCall *, const sized_string_t *, GScanExpression **, size_t); +bool g_scan_pending_call_create(GScanPendingCall *, const sized_string_t *, GScanExpression **, size_t); diff --git a/src/analysis/scan/exprs/call.c b/src/analysis/scan/exprs/call.c index dde627c..2fd1ff1 100644 --- a/src/analysis/scan/exprs/call.c +++ b/src/analysis/scan/exprs/call.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * call.c - organisation d'un appel à un élément de scan enregistré * - * Copyright (C) 2022 Cyrille Bagard + * Copyright (C) 2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -38,27 +38,27 @@ /* Initialise la classe des appels de fonction avec arguments. */ -static void g_pending_call_class_init(GPendingCallClass *); +static void g_scan_pending_call_class_init(GScanPendingCallClass *); /* Initialise une instance d'appel de fonction avec arguments. */ -static void g_pending_call_init(GPendingCall *); +static void g_scan_pending_call_init(GScanPendingCall *); /* Supprime toutes les références externes. */ -static void g_pending_call_dispose(GPendingCall *); +static void g_scan_pending_call_dispose(GScanPendingCall *); /* Procède à la libération totale de la mémoire. */ -static void g_pending_call_finalize(GPendingCall *); +static void g_scan_pending_call_finalize(GScanPendingCall *); /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ -/* Reproduit une expression en place dans une nouvelle instance. */ -static void g_pending_call_copy(GPendingCall *, const GPendingCall *); - /* Réduit une expression à une forme plus simple. */ -static bool g_pending_call_reduce(GPendingCall *, GScanContext *, GScanScope *, GScanExpression **); +static ScanReductionState g_scan_pending_call_reduce(GScanPendingCall *, GScanContext *, GScanScope *, GScanExpression **); + +/* Reproduit un accès en place dans une nouvelle instance. */ +static void g_scan_pending_call_copy(GScanPendingCall *, const GScanPendingCall *); @@ -68,7 +68,7 @@ static bool g_pending_call_reduce(GPendingCall *, GScanContext *, GScanScope *, /* Indique le type défini pour un appel de fonction enregistrée. */ -G_DEFINE_TYPE(GPendingCall, g_pending_call, G_TYPE_NAMED_ACCESS); +G_DEFINE_TYPE(GScanPendingCall, g_scan_pending_call, G_TYPE_SCAN_NAMED_ACCESS); /****************************************************************************** @@ -83,21 +83,25 @@ G_DEFINE_TYPE(GPendingCall, g_pending_call, G_TYPE_NAMED_ACCESS); * * ******************************************************************************/ -static void g_pending_call_class_init(GPendingCallClass *klass) +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_pending_call_dispose; - object->finalize = (GObjectFinalizeFunc)g_pending_call_finalize; + 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->copy = (copy_expr_fc)g_pending_call_copy; - expr->reduce = (reduce_expr_fc)g_pending_call_reduce; + 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; } @@ -114,7 +118,7 @@ static void g_pending_call_class_init(GPendingCallClass *klass) * * ******************************************************************************/ -static void g_pending_call_init(GPendingCall *call) +static void g_scan_pending_call_init(GScanPendingCall *call) { call->args = NULL; call->count = 0; @@ -134,14 +138,14 @@ static void g_pending_call_init(GPendingCall *call) * * ******************************************************************************/ -static void g_pending_call_dispose(GPendingCall *call) +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_pending_call_parent_class)->dispose(G_OBJECT(call)); + G_OBJECT_CLASS(g_scan_pending_call_parent_class)->dispose(G_OBJECT(call)); } @@ -158,12 +162,12 @@ static void g_pending_call_dispose(GPendingCall *call) * * ******************************************************************************/ -static void g_pending_call_finalize(GPendingCall *call) +static void g_scan_pending_call_finalize(GScanPendingCall *call) { if (call->args != NULL) free(call->args); - G_OBJECT_CLASS(g_pending_call_parent_class)->finalize(G_OBJECT(call)); + G_OBJECT_CLASS(g_scan_pending_call_parent_class)->finalize(G_OBJECT(call)); } @@ -182,13 +186,13 @@ static void g_pending_call_finalize(GPendingCall *call) * * ******************************************************************************/ -GScanExpression *g_pending_call_new(const sized_string_t *target, GScanExpression **args, size_t count) +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_PENDING_CALL, NULL); + result = g_object_new(G_TYPE_SCAN_PENDING_CALL, NULL); - if (!g_pending_call_create(G_PENDING_CALL(result), target, args, count)) + if (!g_scan_pending_call_create(G_SCAN_PENDING_CALL(result), target, args, count)) g_clear_object(&result); return result; @@ -211,12 +215,12 @@ GScanExpression *g_pending_call_new(const sized_string_t *target, GScanExpressio * * ******************************************************************************/ -bool g_pending_call_create(GPendingCall *call, const sized_string_t *target, GScanExpression **args, size_t count) +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_named_access_create(G_NAMED_ACCESS(call), target); + result = g_scan_named_access_create(G_SCAN_NAMED_ACCESS(call), target); if (!result) goto exit; call->args = malloc(count * sizeof(GScanExpression *)); @@ -243,37 +247,6 @@ bool g_pending_call_create(GPendingCall *call, const sized_string_t *target, GSc /****************************************************************************** * * -* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * -* src = expression source à copier. * -* * -* Description : Reproduit une expression en place dans une nouvelle instance.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_pending_call_copy(GPendingCall *dest, const GPendingCall *src) -{ - GScanExpressionClass *class; /* Classe parente à solliciter */ - size_t i; /* Boucle de parcours */ - - class = G_SCAN_EXPRESSION_CLASS(g_pending_call_parent_class); - - class->copy(G_SCAN_EXPRESSION(dest), G_SCAN_EXPRESSION(src)); - - dest->args = malloc(src->count * sizeof(GScanExpression *)); - dest->count = src->count; - - for (i = 0; i < src->count; i++) - dest->args[i] = g_scan_expression_duplicate(src->args[i]); - -} - - -/****************************************************************************** -* * * Paramètres : expr = expression à consulter. * * ctx = contexte de suivi de l'analyse courante. * * scope = portée courante des variables locales. * @@ -287,89 +260,196 @@ static void g_pending_call_copy(GPendingCall *dest, const GPendingCall *src) * * ******************************************************************************/ -static bool g_pending_call_reduce(GPendingCall *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +static ScanReductionState g_scan_pending_call_reduce(GScanPendingCall *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) { - bool result; /* Bilan à retourner */ - GNamedAccess *new; /* Eventuel étage suivant */ - GPendingCall *new_call; /* Version en appel */ - size_t i; /* Boucle de parcours */ + ScanReductionState result; /* Etat synthétisé à retourner */ + GScanNamedAccess *access; /* Autre vision de l'expression*/ + GRegisteredItem *resolved; /* Cible concrète obtenue */ + size_t i; /* Boucle de parcours #1 */ GScanExpression *arg; /* Argument réduit à échanger */ - GObject *final; /* Expression ou élément ? */ + 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. */ GScanExpression *new_next; /* Nouvelle version du suivant */ + GObject *final; /* Expression ou élément ? */ + bool valid; /* Validité de l'élément */ - result = _g_named_access_reduce(G_NAMED_ACCESS(expr), ctx, scope, out); + access = G_SCAN_NAMED_ACCESS(expr); - if (result && *out != NULL) - { - assert(G_IS_NAMED_ACCESS(*out)); + resolved = _g_scan_named_access_prepare_reduction(access, ctx, scope); + + if (resolved == NULL) + result = SRS_UNRESOLVABLE; - new = G_NAMED_ACCESS(*out); - *out = NULL; + else + { + result = SRS_PENDING; - assert(new->target == NULL); - assert(G_IS_PENDING_CALL(new)); - assert(G_IS_REGISTERED_ITEM(new->resolved)); + /* Actualisation nécessaire des arguments ? */ - new_call = G_PENDING_CALL(new); + new_args = NULL; - for (i = 0; i < new_call->count; i++) + for (i = 0; i < expr->count; i++) { - result = g_scan_expression_reduce(new_call->args[i], ctx, scope, &arg); - if (!result) goto exit; + arg = expr->args[i]; - if (arg != NULL) + state = g_scan_expression_reduce(arg, ctx, scope, &new); + if (state == SRS_UNRESOLVABLE) { - g_object_unref(G_OBJECT(new_call->args[i])); - new_call->args[i] = arg; + 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[i]; + g_object_ref(G_OBJECT(new_args[k])); + } + + } + + new_args[i] = new; + + } + + else + { + if (new_args != NULL) + new_args[i] = new; + } } - result = g_registered_item_run_call(new->resolved, - new_call->args, - new_call->count, - ctx, scope, &final); + /* Suite des traitements */ - if (result && final != NULL) + if (result == SRS_WAIT_FOR_SCAN) { /** - * 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. + * Si changement il y a eu... */ - if (!G_IS_REGISTERED_ITEM(final)) + if (new_args != NULL) { - assert(new->next == NULL); - *out = G_SCAN_EXPRESSION(final); + *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_registered_item_run_call(resolved, + expr->args, + expr->count, + ctx, scope, &final); else - { - assert(new->next != NULL); + valid = g_registered_item_run_call(resolved, + new_args, + expr->count, + ctx, scope, &final); - new_next = g_scan_expression_duplicate(G_SCAN_EXPRESSION(new->next)); - assert(G_IS_NAMED_ACCESS(new_next)); + 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_REGISTERED_ITEM(final)) + { + assert(access->next == NULL); - g_named_access_set_base(G_NAMED_ACCESS(new_next), G_REGISTERED_ITEM(final)); + *out = G_SCAN_EXPRESSION(final); - result = g_scan_expression_reduce(new_next, ctx, scope, out); + result = SRS_REDUCED; - if (result && *out == NULL) - *out = new_next; + } else + { + assert(access->next != NULL); + + new_next = g_scan_named_access_duplicate(access->next, resolved); + + result = g_scan_expression_reduce(new_next, ctx, scope, out); + g_object_unref(G_OBJECT(new_next)); + } + } + else + result = SRS_UNRESOLVABLE; + } - exit: + /* Libération locale des arguments reconstruits */ - g_object_unref(G_OBJECT(new)); + 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 index c344036..c4d8964 100644 --- a/src/analysis/scan/exprs/call.h +++ b/src/analysis/scan/exprs/call.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * call.h - prototypes pour l'organisation d'un appel à un élément de scan enregistré * - * Copyright (C) 2022 Cyrille Bagard + * Copyright (C) 2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -30,26 +30,26 @@ -#define G_TYPE_PENDING_CALL g_pending_call_get_type() -#define G_PENDING_CALL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PENDING_CALL, GPendingCall)) -#define G_IS_PENDING_CALL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PENDING_CALL)) -#define G_PENDING_CALL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PENDING_CALL, GPendingCallClass)) -#define G_IS_PENDING_CALL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PENDING_CALL)) -#define G_PENDING_CALL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PENDING_CALL, GPendingCallClass)) +#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 _GPendingCall GPendingCall; +typedef struct _GScanPendingCall GScanPendingCall; /* Exécution d'une fonction auxiliaire d'analyse (classe) */ -typedef struct _GPendingCallClass GPendingCallClass; +typedef struct _GScanPendingCallClass GScanPendingCallClass; /* Indique le type défini pour un appel de fonction enregistrée. */ -GType g_pending_call_get_type(void); +GType g_scan_pending_call_get_type(void); /* Organise un appel de fonction avec ses arguments. */ -GScanExpression *g_pending_call_new(const sized_string_t *, GScanExpression **, size_t); +GScanExpression *g_scan_pending_call_new(const sized_string_t *, GScanExpression **, size_t); diff --git a/src/analysis/scan/exprs/counter-int.h b/src/analysis/scan/exprs/counter-int.h new file mode 100644 index 0000000..8c5e56b --- /dev/null +++ b/src/analysis/scan/exprs/counter-int.h @@ -0,0 +1,57 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * counter-int.h - prototypes internes pour le décompte de correspondances identifiées dans du contenu binaire + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_COUNTER_INT_H +#define _ANALYSIS_SCAN_EXPRS_COUNTER_INT_H + + +#include "counter.h" + + +#include "../expr-int.h" + + + +/* Décompte des identifications de motifs (instance) */ +struct _GScanMatchCounter +{ + GScanExpression parent; /* A laisser en premier */ + + GSearchPattern *pattern; /* Motif associé */ + +}; + +/* Décompte des identifications de motifs (classe) */ +struct _GScanMatchCounterClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un compteur de correspondances. */ +bool g_scan_match_counter_create(GScanMatchCounter *, GSearchPattern *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_COUNTER_INT_H */ diff --git a/src/analysis/scan/exprs/counter.c b/src/analysis/scan/exprs/counter.c new file mode 100644 index 0000000..290fd02 --- /dev/null +++ b/src/analysis/scan/exprs/counter.c @@ -0,0 +1,248 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * counter.c - décompte de correspondances identifiées dans du contenu binaire + * + * 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 . + */ + + +#include "counter.h" + + +#include "counter-int.h" +#include "literal.h" + + + +/* --------------------- INSTANCIATION D'UNE FORME DE CONDITION --------------------- */ + + +/* Initialise la classe des opérations booléennes. */ +static void g_scan_match_counter_class_init(GScanMatchCounterClass *); + +/* Initialise une instance d'opération booléenne. */ +static void g_scan_match_counter_init(GScanMatchCounter *); + +/* Supprime toutes les références externes. */ +static void g_scan_match_counter_dispose(GScanMatchCounter *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_match_counter_finalize(GScanMatchCounter *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réduit une expression à une forme plus simple. */ +static bool g_scan_match_counter_reduce(GScanMatchCounter *, 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(GScanMatchCounter, g_scan_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_match_counter_class_init(GScanMatchCounterClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_match_counter_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_match_counter_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)NULL; + expr->reduce = (reduce_expr_fc)g_scan_match_counter_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser. * +* * +* Description : Initialise une instance d'opération booléenne. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_match_counter_init(GScanMatchCounter *counter) +{ + counter->pattern = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_match_counter_dispose(GScanMatchCounter *counter) +{ + g_clear_object(&counter->pattern); + + G_OBJECT_CLASS(g_scan_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_match_counter_finalize(GScanMatchCounter *counter) +{ + G_OBJECT_CLASS(g_scan_match_counter_parent_class)->finalize(G_OBJECT(counter)); + +} + + +/****************************************************************************** +* * +* Paramètres : pattern = motif à impliquer. * +* * +* Description : Met en place un décompte de correspondances obtenues. * +* * +* Retour : Expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_match_counter_new(GSearchPattern *pattern) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_MATCH_COUNTER, NULL); + + if (!g_scan_match_counter_create(G_SCAN_MATCH_COUNTER(result), pattern)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : counter = instance à initialiser pleinement. * +* pattern = motif à impliquer. * +* * +* Description : Met en place un compteur de correspondances. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_match_counter_create(GScanMatchCounter *counter, GSearchPattern *pattern) +{ + bool result; /* Bilan à retourner */ + + result = true; + + counter->pattern = pattern; + g_object_ref(G_OBJECT(pattern)); + + 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 bool g_scan_match_counter_reduce(GScanMatchCounter *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + bool result; /* Bilan à retourner */ + size_t count; /* Quantité de correspondances */ + const GScanMatch **matches; /* Correspondances établies */ + + + matches = g_scan_context_get_full_matches(ctx, expr->pattern, &count); + + + printf("matches: %zu\n", count); + + + *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ count }); + result = true; + + + return result; + +} diff --git a/src/analysis/scan/exprs/counter.h b/src/analysis/scan/exprs/counter.h new file mode 100644 index 0000000..c90953e --- /dev/null +++ b/src/analysis/scan/exprs/counter.h @@ -0,0 +1,59 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * counter.h - prototypes pour le décompte de correspondances identifiées dans du contenu binaire + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_COUNTER_H +#define _ANALYSIS_SCAN_EXPRS_COUNTER_H + + +#include + + +#include "../expr.h" +#include "../pattern.h" + + + +#define G_TYPE_SCAN_MATCH_COUNTER g_scan_match_counter_get_type() +#define G_SCAN_MATCH_COUNTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MATCH_COUNTER, GScanMatchCounter)) +#define G_IS_SCAN_MATCH_COUNTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MATCH_COUNTER)) +#define G_SCAN_MATCH_COUNTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MATCH_COUNTER, GScanMatchCounterClass)) +#define G_IS_SCAN_MATCH_COUNTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MATCH_COUNTER)) +#define G_SCAN_MATCH_COUNTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MATCH_COUNTER, GScanMatchCounterClass)) + + +/* Décompte des identifications de motifs (instance) */ +typedef struct _GScanMatchCounter GScanMatchCounter; + +/* Décompte des identifications de motifs (classe) */ +typedef struct _GScanMatchCounterClass GScanMatchCounterClass; + + +/* Indique le type défini pour un décompte de résultats lors d'une recherche de motifs. */ +GType g_scan_match_counter_get_type(void); + +/* Met en place un décompte de correspondances obtenues. */ +GScanExpression *g_scan_match_counter_new(GSearchPattern *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_COUNTER_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 . + */ + + +#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..f0660e0 --- /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 . + */ + + +#include "intersect.h" + + +#include + + +#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(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(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 . + */ + + +#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/literal-int.h b/src/analysis/scan/exprs/literal-int.h index 875b3de..b0a0ec5 100644 --- a/src/analysis/scan/exprs/literal-int.h +++ b/src/analysis/scan/exprs/literal-int.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * literal-int.h - prototypes internes pour la représentation d'une valeur concrète * - * Copyright (C) 2022 Cyrille Bagard + * Copyright (C) 2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -28,24 +28,22 @@ #include "literal.h" -#include - - #include "../expr-int.h" /* Expression portant une valeur concrète (instance) */ -struct _GLiteralExpression +struct _GScanLiteralExpression { GScanExpression parent; /* A laisser en premier */ - ExprValueType value_type; /* Type de valeur portée */ + LiteralValueType value_type; /* Type de valeur portée */ union { bool boolean; /* Valeur booléenne */ - unsigned long long integer; /* Valeur entière 64 bits */ + 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 { @@ -58,7 +56,7 @@ struct _GLiteralExpression }; /* Expression portant une valeur concrète (classe) */ -struct _GLiteralExpressionClass +struct _GScanLiteralExpressionClass { GScanExpressionClass parent; /* A laisser en premier */ @@ -66,7 +64,7 @@ struct _GLiteralExpressionClass /* Met en place une expression de valeur concrête. */ -bool g_literal_expression_create(GLiteralExpression *, ExprValueType, ...); +bool g_scan_literal_expression_create(GScanLiteralExpression *, LiteralValueType, ...); diff --git a/src/analysis/scan/exprs/literal.c b/src/analysis/scan/exprs/literal.c index 119b871..e468382 100644 --- a/src/analysis/scan/exprs/literal.c +++ b/src/analysis/scan/exprs/literal.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * literal.c - représentation d'une valeur concrète * - * Copyright (C) 2022 Cyrille Bagard + * Copyright (C) 2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -37,16 +37,16 @@ /* Initialise la classe des expressions de valeur concrète. */ -static void g_literal_expression_class_init(GLiteralExpressionClass *); +static void g_scan_literal_expression_class_init(GScanLiteralExpressionClass *); /* Initialise une instance d'expression de valeur concrète. */ -static void g_literal_expression_init(GLiteralExpression *); +static void g_scan_literal_expression_init(GScanLiteralExpression *); /* Supprime toutes les références externes. */ -static void g_literal_expression_dispose(GLiteralExpression *); +static void g_scan_literal_expression_dispose(GScanLiteralExpression *); /* Procède à la libération totale de la mémoire. */ -static void g_literal_expression_finalize(GLiteralExpression *); +static void g_scan_literal_expression_finalize(GScanLiteralExpression *); @@ -54,13 +54,13 @@ static void g_literal_expression_finalize(GLiteralExpression *); /* Réalise une comparaison entre objets selon un critère précis. */ -static bool g_literal_expression_compare_rich(const GLiteralExpression *, const GLiteralExpression *, RichCmpOperation, bool *); +static bool g_scan_literal_expression_compare_rich(const GScanLiteralExpression *, const GScanLiteralExpression *, RichCmpOperation, bool *); -/* Reproduit une expression en place dans une nouvelle instance. */ -static void g_literal_expression_copy(GLiteralExpression *, const GLiteralExpression *); +/* Réduit une expression à une forme booléenne. */ +static bool g_scan_literal_expression_reduce_to_boolean(GScanLiteralExpression *, GScanContext *, GScanScope *, GScanExpression **); -/* Réduit une expression à une forme plus simple. */ -static bool g_literal_expression_reduce(GLiteralExpression *, GScanContext *, GScanScope *, GScanExpression **); +/* Dénombre les éléments portés par une expression. */ +static bool g_scan_literal_expression_count(const GScanLiteralExpression *, size_t *); @@ -70,7 +70,7 @@ static bool g_literal_expression_reduce(GLiteralExpression *, GScanContext *, GS /* Indique le type défini pour un appel de fonction enregistrée. */ -G_DEFINE_TYPE(GLiteralExpression, g_literal_expression, G_TYPE_SCAN_EXPRESSION); +G_DEFINE_TYPE(GScanLiteralExpression, g_scan_literal_expression, G_TYPE_SCAN_EXPRESSION); /****************************************************************************** @@ -85,21 +85,21 @@ G_DEFINE_TYPE(GLiteralExpression, g_literal_expression, G_TYPE_SCAN_EXPRESSION); * * ******************************************************************************/ -static void g_literal_expression_class_init(GLiteralExpressionClass *klass) +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_literal_expression_dispose; - object->finalize = (GObjectFinalizeFunc)g_literal_expression_finalize; + 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_literal_expression_compare_rich; - expr->copy = (copy_expr_fc)g_literal_expression_copy; - expr->reduce = (reduce_expr_fc)g_literal_expression_reduce; + 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; } @@ -116,8 +116,9 @@ static void g_literal_expression_class_init(GLiteralExpressionClass *klass) * * ******************************************************************************/ -static void g_literal_expression_init(GLiteralExpression *expr) +static void g_scan_literal_expression_init(GScanLiteralExpression *expr) { + G_SCAN_EXPRESSION(expr)->state = SRS_REDUCED; } @@ -134,9 +135,9 @@ static void g_literal_expression_init(GLiteralExpression *expr) * * ******************************************************************************/ -static void g_literal_expression_dispose(GLiteralExpression *expr) +static void g_scan_literal_expression_dispose(GScanLiteralExpression *expr) { - G_OBJECT_CLASS(g_literal_expression_parent_class)->dispose(G_OBJECT(expr)); + G_OBJECT_CLASS(g_scan_literal_expression_parent_class)->dispose(G_OBJECT(expr)); } @@ -153,9 +154,9 @@ static void g_literal_expression_dispose(GLiteralExpression *expr) * * ******************************************************************************/ -static void g_literal_expression_finalize(GLiteralExpression *expr) +static void g_scan_literal_expression_finalize(GScanLiteralExpression *expr) { - G_OBJECT_CLASS(g_literal_expression_parent_class)->finalize(G_OBJECT(expr)); + G_OBJECT_CLASS(g_scan_literal_expression_parent_class)->finalize(G_OBJECT(expr)); } @@ -167,25 +168,25 @@ static void g_literal_expression_finalize(GLiteralExpression *expr) * * * Description : Organise un appel de fonction avec ses arguments. * * * -* Retour : Fonction mise en place. * +* Retour : Expression mise en place. * * * * Remarques : - * * * ******************************************************************************/ -GScanExpression *g_literal_expression_new(ExprValueType vtype, ...) +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_LITERAL_EXPRESSION, NULL); + result = g_object_new(G_TYPE_SCAN_LITERAL_EXPRESSION, NULL); va_start(ap, vtype); ptr = va_arg(ap, void *); - if (!g_literal_expression_create(G_LITERAL_EXPRESSION(result), vtype, ptr)) + if (!g_scan_literal_expression_create(G_SCAN_LITERAL_EXPRESSION(result), vtype, ptr)) g_clear_object(&result); va_end(ap); @@ -209,12 +210,13 @@ GScanExpression *g_literal_expression_new(ExprValueType vtype, ...) * * ******************************************************************************/ -bool g_literal_expression_create(GLiteralExpression *expr, ExprValueType vtype, ...) +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 unsigned long long *integer; /* Valeur entière 64 bits */ + 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 */ @@ -223,89 +225,115 @@ bool g_literal_expression_create(GLiteralExpression *expr, ExprValueType vtype, char *tmp; /* Zone de travail temporaire */ int ret; /* Bilan d'une opération */ - result = g_scan_expression_create(G_SCAN_EXPRESSION(expr), vtype); + va_start(ap, vtype); - if (result) + switch (vtype) { - va_start(ap, vtype); + case LVT_BOOLEAN: + boolean = va_arg(ap, const bool *); + expr->value.boolean = *boolean; + result = true; + break; - switch (vtype) - { - case EVT_BOOLEAN: - boolean = va_arg(ap, const bool *); - expr->value.boolean = *boolean; - break; + case LVT_SIGNED_INTEGER: + s_integer = va_arg(ap, const long long *); + expr->value.s_integer = *s_integer; + result = true; + break; - case EVT_INTEGER: - integer = va_arg(ap, const unsigned long long *); - expr->value.integer = *integer; - 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 EVT_STRING: - string = va_arg(ap, const sized_string_t *); - szstrdup(&expr->value.string, string); - break; + case LVT_REG_EXPR: + raw = va_arg(ap, const char *); + len = strlen(raw); - case EVT_REG_EXPR: - raw = va_arg(ap, const char *); - len = strlen(raw); + result = (len > 2 && raw[0] == '/'); - result = (len > 2 && raw[0] == '/'); + cflags = REG_EXTENDED | REG_NOSUB; - cflags = REG_EXTENDED | REG_NOSUB; + for (i = 0; i < 2 && result; i++) + { + result = (len > 2); - for (i = 0; i < 2 && result; i++) + if (raw[len - 1] == 'i') { - result = (len > 2); + cflags |= REG_ICASE; + len -= 1; + } - 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] == 's') - { - cflags |= REG_NEWLINE; - len -= 1; - } + else if (raw[len - 1] == '/') + break; - else if (raw[len - 1] == '/') - break; + } - } + if (result) + result = (raw[len - 1] == '/'); - 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) - { - assert(len > 2); + expr->value.regex = strdup(raw); + + } + + break; - tmp = strndup(&raw[1], len - 2); - ret = regcomp(&expr->value.preg, tmp, cflags); - free(tmp); + default: + result = false; + break; - result = (ret == 0); + } - if (result) - expr->value.regex = strdup(raw); + va_end(ap); - } + expr->value_type = vtype; - break; + return result; - default: - result = false; - break; +} - } - va_end(ap); +/****************************************************************************** +* * +* 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 */ - expr->value_type = vtype; + result = expr->value_type; return result; @@ -314,7 +342,7 @@ bool g_literal_expression_create(GLiteralExpression *expr, ExprValueType vtype, /****************************************************************************** * * -* Paramètres : item = premier objet à consulter pour une comparaison. * +* 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. * @@ -325,14 +353,41 @@ bool g_literal_expression_create(GLiteralExpression *expr, ExprValueType vtype, * * ******************************************************************************/ -bool g_literal_expression_get_boolean_value(const GLiteralExpression *item, bool *value) +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 = (item->value_type == EVT_BOOLEAN); + result = (expr->value_type == LVT_SIGNED_INTEGER); if (result) - *value = item->value.boolean; + *value = expr->value.u_integer; return result; @@ -341,7 +396,7 @@ bool g_literal_expression_get_boolean_value(const GLiteralExpression *item, bool /****************************************************************************** * * -* Paramètres : item = premier objet à consulter pour une comparaison. * +* 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. * @@ -352,14 +407,14 @@ bool g_literal_expression_get_boolean_value(const GLiteralExpression *item, bool * * ******************************************************************************/ -bool g_literal_expression_get_integer_value(const GLiteralExpression *item, unsigned long long *value) +bool g_scan_literal_expression_get_unsigned_integer_value(const GScanLiteralExpression *expr, unsigned long long *value) { bool result; /* Etat à retourner */ - result = (item->value_type == EVT_INTEGER); + result = (expr->value_type == LVT_UNSIGNED_INTEGER); if (result) - *value = item->value.integer; + *value = expr->value.u_integer; return result; @@ -368,7 +423,7 @@ bool g_literal_expression_get_integer_value(const GLiteralExpression *item, unsi /****************************************************************************** * * -* Paramètres : item = premier objet à consulter pour une comparaison. * +* 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. * @@ -379,14 +434,14 @@ bool g_literal_expression_get_integer_value(const GLiteralExpression *item, unsi * * ******************************************************************************/ -bool g_literal_expression_get_string_value(const GLiteralExpression *item, const sized_string_t **value) +bool g_scan_literal_expression_get_string_value(const GScanLiteralExpression *expr, const sized_string_t **value) { bool result; /* Etat à retourner */ - result = (item->value_type == EVT_STRING); + result = (expr->value_type == LVT_STRING); if (result) - *value = &item->value.string; + *value = &expr->value.string; return result; @@ -395,7 +450,7 @@ bool g_literal_expression_get_string_value(const GLiteralExpression *item, const /****************************************************************************** * * -* Paramètres : item = premier objet à consulter pour une comparaison. * +* 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. * @@ -406,14 +461,14 @@ bool g_literal_expression_get_string_value(const GLiteralExpression *item, const * * ******************************************************************************/ -bool g_literal_expression_get_regex_value(const GLiteralExpression *item, const regex_t **value) +bool g_scan_literal_expression_get_regex_value(const GScanLiteralExpression *expr, const regex_t **value) { bool result; /* Etat à retourner */ - result = (item->value_type == EVT_REG_EXPR); + result = (expr->value_type == LVT_REG_EXPR); if (result) - *value = &item->value.preg; + *value = &expr->value.preg; return result; @@ -428,7 +483,7 @@ bool g_literal_expression_get_regex_value(const GLiteralExpression *item, const /****************************************************************************** * * -* Paramètres : item = premier objet à consulter pour une comparaison. * +* 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] * @@ -441,32 +496,32 @@ bool g_literal_expression_get_regex_value(const GLiteralExpression *item, const * * ******************************************************************************/ -static bool g_literal_expression_compare_rich(const GLiteralExpression *item, const GLiteralExpression *other, RichCmpOperation op, bool *status) +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_LITERAL_EXPRESSION); + result = g_type_is_a(G_TYPE_FROM_INSTANCE(other), G_TYPE_SCAN_LITERAL_EXPRESSION); if (!result) goto done; - if (item->value_type != other->value_type) + if (expr->value_type != other->value_type) { - *status = compare_rich_integer_values(item->value_type, other->value_type, op); + *status = compare_rich_integer_values_unsigned(expr->value_type, other->value_type, op); goto done; } - switch (item->value_type) + switch (expr->value_type) { - case EVT_BOOLEAN: + case LVT_BOOLEAN: switch (op) { case RCO_EQ: - *status = (item->value.boolean == other->value.boolean); + *status = (expr->value.boolean == other->value.boolean); result = true; break; case RCO_NE: - *status = (item->value.boolean != other->value.boolean); + *status = (expr->value.boolean != other->value.boolean); result = true; break; @@ -477,20 +532,25 @@ static bool g_literal_expression_compare_rich(const GLiteralExpression *item, co }; break; - case EVT_INTEGER: - *status = compare_rich_integer_values(item->value.integer, other->value.integer, op); + case LVT_SIGNED_INTEGER: + *status = compare_rich_integer_values_signed(expr->value.s_integer, other->value.s_integer, op); result = true; break; - case EVT_STRING: - cmp = szstrcmp(&item->value.string, &other->value.string); - *status = compare_rich_integer_values(cmp, 0, op); + case LVT_UNSIGNED_INTEGER: + *status = compare_rich_integer_values_unsigned(expr->value.u_integer, other->value.u_integer, op); result = true; break; - case EVT_REG_EXPR: - cmp = strcmp(item->value.regex, other->value.regex); - *status = compare_rich_integer_values(cmp, 0, op); + 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; @@ -509,62 +569,63 @@ static bool g_literal_expression_compare_rich(const GLiteralExpression *item, co /****************************************************************************** * * -* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * -* src = expression source à copier. * +* 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 : Reproduit une expression en place dans une nouvelle instance.* +* Description : Réduit une expression à une forme booléenne. * * * -* Retour : - * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * * * * Remarques : - * * * ******************************************************************************/ -static void g_literal_expression_copy(GLiteralExpression *dest, const GLiteralExpression *src) +static bool g_scan_literal_expression_reduce_to_boolean(GScanLiteralExpression *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) { - GScanExpressionClass *class; /* Classe parente à solliciter */ - - class = G_SCAN_EXPRESSION_CLASS(g_literal_expression_parent_class); - - class->copy(G_SCAN_EXPRESSION(dest), G_SCAN_EXPRESSION(src)); - - dest->value_type = src->value_type; + bool result; /* Bilan à retourner */ - switch (src->value_type) + switch (expr->value_type) { - case EVT_BOOLEAN: - dest->value.boolean = src->value.boolean; + case LVT_BOOLEAN: + *out = G_SCAN_EXPRESSION(expr); + g_object_ref(G_OBJECT(expr)); + result = true; break; - case EVT_INTEGER: - dest->value.integer = src->value.integer; + case LVT_SIGNED_INTEGER: + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ expr->value.s_integer != 0 }); + result = true; break; - case EVT_STRING: - szstrdup(&dest->value.string, &src->value.string); + case LVT_UNSIGNED_INTEGER: + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ expr->value.u_integer != 0 }); + result = true; break; - case EVT_REG_EXPR: - /*ptr = &expr->value.regex*//* FIXME */; + case LVT_STRING: + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ expr->value.string.len > 0 }); + result = true; break; default: - assert(false); + result = false; break; } + 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] * +* count = quantité d'éléments déterminée. [OUT] * * * -* Description : Réduit une expression à une forme plus simple. * +* 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. * * * @@ -572,14 +633,22 @@ static void g_literal_expression_copy(GLiteralExpression *dest, const GLiteralEx * * ******************************************************************************/ -static bool g_literal_expression_reduce(GLiteralExpression *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +static bool g_scan_literal_expression_count(const GScanLiteralExpression *expr, size_t *count) { bool result; /* Bilan à retourner */ - result = true; + switch (expr->value_type) + { + case LVT_STRING: + *count = expr->value.string.len; + result = true; + break; + + default: + result = false; + break; - *out = G_SCAN_EXPRESSION(expr); - g_object_ref(G_OBJECT(expr)); + } return result; diff --git a/src/analysis/scan/exprs/literal.h b/src/analysis/scan/exprs/literal.h index 7120c07..9352baf 100644 --- a/src/analysis/scan/exprs/literal.h +++ b/src/analysis/scan/exprs/literal.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * literal.h - prototypes pour la représentation d'une valeur concrète * - * Copyright (C) 2022 Cyrille Bagard + * Copyright (C) 2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -26,6 +26,7 @@ #include +#include #include "../expr.h" @@ -33,38 +34,56 @@ -#define G_TYPE_LITERAL_EXPRESSION g_literal_expression_get_type() -#define G_LITERAL_EXPRESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_LITERAL_EXPRESSION, GLiteralExpression)) -#define G_IS_LITERAL_EXPRESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_LITERAL_EXPRESSION)) -#define G_LITERAL_EXPRESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_LITERAL_EXPRESSION, GLiteralExpressionClass)) -#define G_IS_LITERAL_EXPRESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_LITERAL_EXPRESSION)) -#define G_LITERAL_EXPRESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_LITERAL_EXPRESSION, GLiteralExpressionClass)) +#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 _GLiteralExpression GLiteralExpression; +typedef struct _GScanLiteralExpression GScanLiteralExpression; /* Expression portant une valeur concrète (classe) */ -typedef struct _GLiteralExpressionClass GLiteralExpressionClass; +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_literal_expression_get_type(void); +GType g_scan_literal_expression_get_type(void); /* Organise un appel de fonction avec ses arguments. */ -GScanExpression *g_literal_expression_new(ExprValueType, ...); +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_literal_expression_get_boolean_value(const GLiteralExpression *, bool *); +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_literal_expression_get_integer_value(const GLiteralExpression *, unsigned long long *); +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_literal_expression_get_string_value(const GLiteralExpression *, const sized_string_t **); +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_literal_expression_get_regex_value(const GLiteralExpression *, const regex_t **); +bool g_scan_literal_expression_get_regex_value(const GScanLiteralExpression *, const regex_t **); 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 . + */ + + +#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..4c82b1e --- /dev/null +++ b/src/analysis/scan/exprs/logical.c @@ -0,0 +1,508 @@ + +/* 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 . + */ + + +#include "logical.h" + + +#include + + +#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(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 */ + + 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; + + } + + 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(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; + + } + + /* 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 . + */ + + +#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 . + */ + + +#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..f97b15e --- /dev/null +++ b/src/analysis/scan/exprs/range.c @@ -0,0 +1,352 @@ + +/* 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 . + */ + + +#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(GScanCompactRange *, GScanContext *, GScanScope *, GScanExpression **); + +/* Réduit une expression à une forme booléenne. */ +static bool g_scan_compact_range_reduce_to_boolean(GScanCompactRange *, GScanContext *, GScanScope *, GScanExpression **); + +/* Réalise l'intersection entre deux ensembles. */ +static GScanExpression *g_scan_compact_range_intersect(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 = true; + + range->start = start; + g_object_ref(G_OBJECT(start)); + + range->end = end; + g_object_ref(G_OBJECT(end)); + + 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(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(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(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 . + */ + + +#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 . + */ + + +#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..b56b599 --- /dev/null +++ b/src/analysis/scan/exprs/relational.c @@ -0,0 +1,408 @@ + +/* 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 . + */ + + +#include "relational.h" + + +#include + + +#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(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 = true; + + op->rel_type = type; + + op->left = left; + g_object_ref(G_OBJECT(op->left)); + + op->right = right; + g_object_ref(G_OBJECT(op->right)); + + 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(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 . + */ + + +#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/relop-int.h b/src/analysis/scan/exprs/relop-int.h deleted file mode 100644 index 3adbcf0..0000000 --- a/src/analysis/scan/exprs/relop-int.h +++ /dev/null @@ -1,60 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * relop-int.h - prototypes internes pour la gestion des opérations relationnelles - * - * Copyright (C) 2022 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . - */ - - -#ifndef _ANALYSIS_SCAN_EXPRS_RELOP_INT_H -#define _ANALYSIS_SCAN_EXPRS_RELOP_INT_H - - -#include "relop.h" - - -#include "../expr-int.h" - - - -/* Opération relationnelle impliquant deux opérandes (instance) */ -struct _GRelOperation -{ - 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 _GRelOperationClass -{ - GScanExpressionClass parent; /* A laisser en premier */ - -}; - - -/* Met en place une opération relationnelle entre expressions. */ -bool g_relational_operation_create(GRelOperation *, RichCmpOperation, GScanExpression *, GScanExpression *); - - - -#endif /* _ANALYSIS_SCAN_EXPRS_RELOP_INT_H */ diff --git a/src/analysis/scan/exprs/relop.c b/src/analysis/scan/exprs/relop.c deleted file mode 100644 index 7dc6864..0000000 --- a/src/analysis/scan/exprs/relop.c +++ /dev/null @@ -1,392 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * relop.c - gestion des opérations relationnelles - * - * Copyright (C) 2022 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . - */ - - -#include "relop.h" - - -#include "relop-int.h" -#include "literal.h" - - - -/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ - - -/* Initialise la classe des opérations de relations. */ -static void g_relational_operation_class_init(GRelOperationClass *); - -/* Initialise une instance d'opération de relation. */ -static void g_relational_operation_init(GRelOperation *); - -/* Supprime toutes les références externes. */ -static void g_relational_operation_dispose(GRelOperation *); - -/* Procède à la libération totale de la mémoire. */ -static void g_relational_operation_finalize(GRelOperation *); - - - -/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ - - -/* Réalise une comparaison entre objets selon un critère précis. */ -static bool g_relational_operation_compare_rich(const GRelOperation *, const GRelOperation *, RichCmpOperation, bool *); - -/* Reproduit une expression en place dans une nouvelle instance. */ -static void g_relational_operation_copy(GRelOperation *, const GRelOperation *); - -/* Réduit une expression à une forme plus simple. */ -static bool g_relational_operation_reduce(GRelOperation *, GScanContext *, GScanScope *, GScanExpression **); - - - -/* ---------------------------------------------------------------------------------- */ -/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ -/* ---------------------------------------------------------------------------------- */ - - -/* Indique le type défini pour une opération de relation entre expressions. */ -G_DEFINE_TYPE(GRelOperation, g_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_relational_operation_class_init(GRelOperationClass *klass) -{ - GObjectClass *object; /* Autre version de la classe */ - GScanExpressionClass *expr; /* Version de classe parente */ - - object = G_OBJECT_CLASS(klass); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_relational_operation_dispose; - object->finalize = (GObjectFinalizeFunc)g_relational_operation_finalize; - - expr = G_SCAN_EXPRESSION_CLASS(klass); - - expr->cmp_rich = (compare_expr_rich_fc)g_relational_operation_compare_rich; - expr->copy = (copy_expr_fc)g_relational_operation_copy; - expr->reduce = (reduce_expr_fc)g_relational_operation_reduce; - -} - - -/****************************************************************************** -* * -* Paramètres : op = instance à initialiser. * -* * -* Description : Initialise une instance d'opération de relation. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_relational_operation_init(GRelOperation *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_relational_operation_dispose(GRelOperation *op) -{ - g_clear_object(&op->left); - g_clear_object(&op->right); - - G_OBJECT_CLASS(g_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_relational_operation_finalize(GRelOperation *op) -{ - G_OBJECT_CLASS(g_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_relational_operation_new(RichCmpOperation type, GScanExpression *left, GScanExpression *right) -{ - GScanExpression *result; /* Structure à retourner */ - - result = g_object_new(G_TYPE_RELATIONAL_OPERATION, NULL); - - if (!g_relational_operation_create(G_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_relational_operation_create(GRelOperation *op, RichCmpOperation type, GScanExpression *left, GScanExpression *right) -{ - bool result; /* Bilan à retourner */ - - result = false; - - if (g_scan_expression_get_value_type(left) != g_scan_expression_get_value_type(left)) - goto exit; - - if (!g_scan_expression_create(G_SCAN_EXPRESSION(op), EVT_BOOLEAN)) - 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)); - - result = true; - - 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_relational_operation_compare_rich(const GRelOperation *item, const GRelOperation *other, RichCmpOperation op, bool *status) -{ - bool result; /* Etat à retourner */ - - result = g_type_is_a(G_TYPE_FROM_INSTANCE(other), G_TYPE_RELATIONAL_OPERATION); - if (!result) goto done; - - if (item->rel_type != other->rel_type) - { - *status = compare_rich_integer_values(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 : dest = emplacement d'enregistrement à constituer. [OUT] * -* src = expression source à copier. * -* * -* Description : Reproduit une expression en place dans une nouvelle instance.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_relational_operation_copy(GRelOperation *dest, const GRelOperation *src) -{ - GScanExpressionClass *class; /* Classe parente à solliciter */ - - class = G_SCAN_EXPRESSION_CLASS(g_relational_operation_parent_class); - - class->copy(G_SCAN_EXPRESSION(dest), G_SCAN_EXPRESSION(src)); - - dest->rel_type = src->rel_type; - - dest->left = g_scan_expression_duplicate(src->left); - dest->right = g_scan_expression_duplicate(src->right); - -} - - -/****************************************************************************** -* * -* 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 bool g_relational_operation_reduce(GRelOperation *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) -{ - bool result; /* Bilan à retourner */ - GScanExpression *new_left; /* Expression réduite (gauche) */ - GScanExpression *new_right; /* Expression réduite (droite) */ - 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; - - result = g_scan_expression_reduce(expr->left, ctx, scope, &new_left); - if (!result) goto exit; - - result = g_scan_expression_reduce(expr->right, ctx, scope, &new_right); - if (!result) goto exit; - - /* Construction d'une réduction locale ? */ - - if (G_IS_LITERAL_EXPRESSION(new_left) && G_IS_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_literal_expression_new(EVT_BOOLEAN, (bool []) { status }); - - } - - /* Mise à jour de la progression ? */ - - else if ((new_left != NULL && new_left != expr->left) || (new_right != NULL && new_right != expr->right)) - { - if (new_left == NULL) - { - new_left = expr->left; - g_object_ref(G_OBJECT(new_left)); - } - - if (new_right == NULL) - { - new_right = expr->right; - g_object_ref(G_OBJECT(new_right)); - } - - *out = g_relational_operation_new(expr->rel_type, new_left, new_right); - - } - - exit: - - g_clear_object(&new_left); - g_clear_object(&new_right); - - return result; - -} diff --git a/src/analysis/scan/exprs/relop.h b/src/analysis/scan/exprs/relop.h deleted file mode 100644 index ecbc8ef..0000000 --- a/src/analysis/scan/exprs/relop.h +++ /dev/null @@ -1,56 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * relop.h - prototypes pour la gestion des opérations relationnelles - * - * Copyright (C) 2022 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . - */ - - -#ifndef _ANALYSIS_SCAN_EXPRS_RELOP_H -#define _ANALYSIS_SCAN_EXPRS_RELOP_H - - -#include "../expr.h" -#include "../../../glibext/comparison.h" - - - -#define G_TYPE_RELATIONAL_OPERATION g_relational_operation_get_type() -#define G_RELATIONAL_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_RELATIONAL_OPERATION, GRelOperation)) -#define G_IS_RELATIONAL_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_RELATIONAL_OPERATION)) -#define G_RELATIONAL_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RELATIONAL_OPERATION, GRelOperationClass)) -#define G_IS_RELATIONAL_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RELATIONAL_OPERATION)) -#define G_RELATIONAL_OPERATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RELATIONAL_OPERATION, GRelOperationClass)) - - -/* Opération relationnelle impliquant deux opérandes (instance) */ -typedef struct _GRelOperation GRelOperation; - -/* Opération relationnelle impliquant deux opérandes (classe) */ -typedef struct _GRelOperationClass GRelOperationClass; - - -/* Indique le type défini pour une opération de relation entre expressions. */ -GType g_relational_operation_get_type(void); - -/* Organise une opération relationnelle entre expressions. */ -GScanExpression *g_relational_operation_new(RichCmpOperation, GScanExpression *, GScanExpression *); - - - -#endif /* _ANALYSIS_SCAN_EXPRS_RELOP_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..ebb4380 --- /dev/null +++ b/src/analysis/scan/exprs/set-int.h @@ -0,0 +1,54 @@ + +/* 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 . + */ + + +#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 */ + +}; + + + +#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..0a93ced --- /dev/null +++ b/src/analysis/scan/exprs/set.c @@ -0,0 +1,379 @@ + +/* 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 . + */ + + +#include "set.h" + + +#include +#include + + +#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(GScanGenericSet *, GScanContext *, GScanScope *, GScanExpression **); + +/* Réduit une expression à une forme booléenne. */ +static bool g_scan_generic_set_reduce_to_boolean(GScanGenericSet *, GScanContext *, GScanScope *, GScanExpression **); + +/* Dénombre les éléments portés par une expression. */ +static bool g_scan_generic_set_count_items(const GScanGenericSet *, size_t *); + +/* Fournit un élément donné issu d'un ensemble constitué. */ +static bool g_scan_generic_set_get_item(const GScanGenericSet *, size_t, 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 : Met en place 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); + + 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(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(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. * +* 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, 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. * +* 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, 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..f857ce9 --- /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 . + */ + + +#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); + +/* Met en place 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/strop-int.h b/src/analysis/scan/exprs/strop-int.h index 234ae8f..c2b40cf 100644 --- a/src/analysis/scan/exprs/strop-int.h +++ b/src/analysis/scan/exprs/strop-int.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * strop-int.h - prototypes internes pour la gestion des opérations booléennes * - * Copyright (C) 2022 Cyrille Bagard + * Copyright (C) 2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -34,7 +34,7 @@ /* Opération booléenne avec un ou deux opérandes (instance) */ -struct _GStringOperation +struct _GScanStringOperation { GScanExpression parent; /* A laisser en premier */ @@ -47,7 +47,7 @@ struct _GStringOperation }; /* Opération booléenne avec un ou deux opérandes (classe) */ -struct _GStringOperationClass +struct _GScanStringOperationClass { GScanExpressionClass parent; /* A laisser en premier */ @@ -55,7 +55,7 @@ struct _GStringOperationClass /* Met en place une expression d'opération traite une chaîne. */ -bool g_string_operation_create(GStringOperation *, StringOperationType, GScanExpression *, GScanExpression *, bool); +bool g_scan_string_operation_create(GScanStringOperation *, StringOperationType, GScanExpression *, GScanExpression *, bool); diff --git a/src/analysis/scan/exprs/strop.c b/src/analysis/scan/exprs/strop.c index 145e8da..c7c2878 100644 --- a/src/analysis/scan/exprs/strop.c +++ b/src/analysis/scan/exprs/strop.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * strop.c - gestion des opérations booléennes * - * Copyright (C) 2022 Cyrille Bagard + * Copyright (C) 2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -38,27 +38,24 @@ /* Initialise la classe des opérations visant des chaînes. */ -static void g_string_operation_class_init(GStringOperationClass *); +static void g_scan_string_operation_class_init(GScanStringOperationClass *); /* Initialise une instance d'opération visant une chaîne. */ -static void g_string_operation_init(GStringOperation *); +static void g_scan_string_operation_init(GScanStringOperation *); /* Supprime toutes les références externes. */ -static void g_string_operation_dispose(GStringOperation *); +static void g_scan_string_operation_dispose(GScanStringOperation *); /* Procède à la libération totale de la mémoire. */ -static void g_string_operation_finalize(GStringOperation *); +static void g_scan_string_operation_finalize(GScanStringOperation *); /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ -/* Reproduit une expression en place dans une nouvelle instance. */ -static void g_string_operation_copy(GStringOperation *, const GStringOperation *); - /* Réduit une expression à une forme plus simple. */ -static bool g_string_operation_reduce(GStringOperation *, GScanContext *, GScanScope *, GScanExpression **); +static ScanReductionState g_scan_string_operation_reduce(GScanStringOperation *, GScanContext *, GScanScope *, GScanExpression **); @@ -68,7 +65,7 @@ static bool g_string_operation_reduce(GStringOperation *, GScanContext *, GScanS /* Indique le type défini pour une opération traitant une chaîne de caractères. */ -G_DEFINE_TYPE(GStringOperation, g_string_operation, G_TYPE_SCAN_EXPRESSION); +G_DEFINE_TYPE(GScanStringOperation, g_scan_string_operation, G_TYPE_SCAN_EXPRESSION); /****************************************************************************** @@ -83,21 +80,20 @@ G_DEFINE_TYPE(GStringOperation, g_string_operation, G_TYPE_SCAN_EXPRESSION); * * ******************************************************************************/ -static void g_string_operation_class_init(GStringOperationClass *klass) +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_string_operation_dispose; - object->finalize = (GObjectFinalizeFunc)g_string_operation_finalize; + 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->copy = (copy_expr_fc)g_string_operation_copy; - expr->reduce = (reduce_expr_fc)g_string_operation_reduce; + expr->reduce = (reduce_expr_fc)g_scan_string_operation_reduce; } @@ -114,7 +110,7 @@ static void g_string_operation_class_init(GStringOperationClass *klass) * * ******************************************************************************/ -static void g_string_operation_init(GStringOperation *op) +static void g_scan_string_operation_init(GScanStringOperation *op) { op->left = NULL; op->right = NULL; @@ -134,12 +130,12 @@ static void g_string_operation_init(GStringOperation *op) * * ******************************************************************************/ -static void g_string_operation_dispose(GStringOperation *op) +static void g_scan_string_operation_dispose(GScanStringOperation *op) { g_clear_object(&op->left); g_clear_object(&op->right); - G_OBJECT_CLASS(g_string_operation_parent_class)->dispose(G_OBJECT(op)); + G_OBJECT_CLASS(g_scan_string_operation_parent_class)->dispose(G_OBJECT(op)); } @@ -156,9 +152,9 @@ static void g_string_operation_dispose(GStringOperation *op) * * ******************************************************************************/ -static void g_string_operation_finalize(GStringOperation *op) +static void g_scan_string_operation_finalize(GScanStringOperation *op) { - G_OBJECT_CLASS(g_string_operation_parent_class)->finalize(G_OBJECT(op)); + G_OBJECT_CLASS(g_scan_string_operation_parent_class)->finalize(G_OBJECT(op)); } @@ -178,13 +174,13 @@ static void g_string_operation_finalize(GStringOperation *op) * * ******************************************************************************/ -GScanExpression *g_string_operation_new(StringOperationType type, GScanExpression *first, GScanExpression *second, bool sensitive) +GScanExpression *g_scan_string_operation_new(StringOperationType type, GScanExpression *first, GScanExpression *second, bool sensitive) { GScanExpression *result; /* Structure à retourner */ - result = g_object_new(G_TYPE_STRING_OPERATION, NULL); + result = g_object_new(G_TYPE_SCAN_STRING_OPERATION, NULL); - if (!g_string_operation_create(G_STRING_OPERATION(result), type, first, second, sensitive)) + if (!g_scan_string_operation_create(G_SCAN_STRING_OPERATION(result), type, first, second, sensitive)) g_clear_object(&result); return result; @@ -198,7 +194,7 @@ GScanExpression *g_string_operation_new(StringOperationType type, GScanExpressio * 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. * +* sensitive = détermine la prise en compte de la casse. * * * * Description : Met en place une expression d'opération traite une chaîne. * * * @@ -208,22 +204,11 @@ GScanExpression *g_string_operation_new(StringOperationType type, GScanExpressio * * ******************************************************************************/ -bool g_string_operation_create(GStringOperation *op, StringOperationType type, GScanExpression *left, GScanExpression *right, bool sensitive) +bool g_scan_string_operation_create(GScanStringOperation *op, StringOperationType type, GScanExpression *left, GScanExpression *right, bool sensitive) { bool result; /* Bilan à retourner */ - ExprValueType vtype; /* Type de valeur portée */ - - result = false; - - vtype = g_scan_expression_get_value_type(left); - - if (vtype != EVT_STRING && vtype != EVT_PENDING) - goto exit; - - vtype = g_scan_expression_get_value_type(right); - if (vtype != EVT_STRING && vtype != EVT_REG_EXPR && vtype != EVT_PENDING) - goto exit; + result = true; op->type = type; @@ -251,10 +236,6 @@ bool g_string_operation_create(GStringOperation *op, StringOperationType type, G op->right = right; g_object_ref(G_OBJECT(op->right)); - result = true; - - exit: - return result; } @@ -268,36 +249,6 @@ bool g_string_operation_create(GStringOperation *op, StringOperationType type, G /****************************************************************************** * * -* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * -* src = expression source à copier. * -* * -* Description : Reproduit une expression en place dans une nouvelle instance.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_string_operation_copy(GStringOperation *dest, const GStringOperation *src) -{ - GScanExpressionClass *class; /* Classe parente à solliciter */ - - class = G_SCAN_EXPRESSION_CLASS(g_string_operation_parent_class); - - class->copy(G_SCAN_EXPRESSION(dest), G_SCAN_EXPRESSION(src)); - - dest->type = src->type; - dest->case_sensitive = src->case_sensitive; - - dest->left = g_scan_expression_duplicate(src->left); - dest->right = g_scan_expression_duplicate(src->right); - -} - - -/****************************************************************************** -* * * Paramètres : expr = expression à consulter. * * ctx = contexte de suivi de l'analyse courante. * * scope = portée courante des variables locales. * @@ -311,47 +262,65 @@ static void g_string_operation_copy(GStringOperation *dest, const GStringOperati * * ******************************************************************************/ -static bool g_string_operation_reduce(GStringOperation *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +static ScanReductionState g_scan_string_operation_reduce(GScanStringOperation *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) { - bool result; /* Bilan à retourner */ + ScanReductionState result; /* Etat synthétisé à retourner */ GScanExpression *new_left; /* Expression réduite (gauche) */ GScanExpression *new_right; /* Expression réduite (droite) */ - GLiteralExpression *op_left; /* Opérande gauche final */ - GLiteralExpression *op_right; /* Opérande droite final */ + 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 */ - int ret; /* Bilan de comparaison #2 */ /* Réduction des éléments considérés */ new_left = NULL; new_right = NULL; - result = g_scan_expression_reduce(expr->left, ctx, scope, &new_left); - if (!result) goto exit; + state_left = g_scan_expression_reduce(expr->left, ctx, scope, &new_left); + if (state_left == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + goto exit; + } - result = g_scan_expression_reduce(expr->right, ctx, scope, &new_right); - if (!result) 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_LITERAL_EXPRESSION(new_left) && G_IS_LITERAL_EXPRESSION(new_right)) + if (G_IS_SCAN_LITERAL_EXPRESSION(new_left) && G_IS_SCAN_LITERAL_EXPRESSION(new_right)) { - op_left = G_LITERAL_EXPRESSION(new_left); - op_right = G_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 = g_literal_expression_get_string_value(op_left, &strings[0]); - if (!result) goto exit; + result = SRS_REDUCED; switch (expr->type) { case SOT_CONTAINS: - result = g_literal_expression_get_string_value(op_right, &strings[1]); - if (!result) goto exit; + 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); @@ -359,13 +328,16 @@ static bool g_string_operation_reduce(GStringOperation *expr, GScanContext *ctx, else found = memcasemem(strings[0]->data, strings[0]->len, strings[1]->data, strings[1]->len); - result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { found != NULL }); + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { found != NULL }); break; case SOT_STARTSWITH: - result = g_literal_expression_get_string_value(op_right, &strings[1]); - if (!result) goto exit; + 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; @@ -381,13 +353,16 @@ static bool g_string_operation_reduce(GStringOperation *expr, GScanContext *ctx, } - result = g_literal_expression_new(EVT_BOOLEAN, &status); + *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status); break; case SOT_ENDSWITH: - result = g_literal_expression_get_string_value(op_right, &strings[1]); - if (!result) goto exit; + 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; @@ -405,23 +380,29 @@ static bool g_string_operation_reduce(GStringOperation *expr, GScanContext *ctx, } - result = g_literal_expression_new(EVT_BOOLEAN, &status); + *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status); break; case SOT_MATCHES: - result = g_literal_expression_get_regex_value(op_right, &preg); - if (!result) goto exit; + 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_literal_expression_new(EVT_BOOLEAN, (bool []) { ret != REG_NOMATCH }); + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []) { ret != REG_NOMATCH }); break; case SOT_IEQUALS: - result = g_literal_expression_get_string_value(op_right, &strings[1]); - if (!result) goto exit; + 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; @@ -432,7 +413,7 @@ static bool g_string_operation_reduce(GStringOperation *expr, GScanContext *ctx, status = (ret == 0); } - result = g_literal_expression_new(EVT_BOOLEAN, &status); + *out = g_scan_literal_expression_new(LVT_BOOLEAN, &status); break; } @@ -441,24 +422,26 @@ static bool g_string_operation_reduce(GStringOperation *expr, GScanContext *ctx, /* Mise à jour de la progression ? */ - else if ((new_left != NULL && new_left != expr->left) || (new_right != NULL && new_right != expr->right)) + else if (state_left == SRS_WAIT_FOR_SCAN || state_right == SRS_WAIT_FOR_SCAN) { - if (new_left == NULL) - { - new_left = expr->left; - g_object_ref(G_OBJECT(new_left)); - } + if (new_left != expr->left || new_right != expr->right) + *out = g_scan_string_operation_new(expr->type, new_left, new_right, expr->case_sensitive); - if (new_right == NULL) - { - new_right = expr->right; - g_object_ref(G_OBJECT(new_right)); - } + result = SRS_WAIT_FOR_SCAN; - *out = g_string_operation_new(expr->type, new_left, new_right, expr->case_sensitive); + } + + /* 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); diff --git a/src/analysis/scan/exprs/strop.h b/src/analysis/scan/exprs/strop.h index c7c0813..0a32269 100644 --- a/src/analysis/scan/exprs/strop.h +++ b/src/analysis/scan/exprs/strop.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * strop.h - prototypes pour la gestion des opérations booléennes * - * Copyright (C) 2022 Cyrille Bagard + * Copyright (C) 2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -29,19 +29,19 @@ -#define G_TYPE_STRING_OPERATION g_string_operation_get_type() -#define G_STRING_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_STRING_OPERATION, GStringOperation)) -#define G_IS_STRING_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_STRING_OPERATION)) -#define G_STRING_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_STRING_OPERATION, GStringOperationClass)) -#define G_IS_STRING_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_STRING_OPERATION)) -#define G_STRING_OPERATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_STRING_OPERATION, GStringOperationClass)) +#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 _GStringOperation GStringOperation; +typedef struct _GScanStringOperation GScanStringOperation; /* Opération booléenne avec un ou deux opérandes (classe) */ -typedef struct _GStringOperationClass GStringOperationClass; +typedef struct _GScanStringOperationClass GScanStringOperationClass; /* Types d'opérations booléennes supportées */ @@ -57,10 +57,10 @@ typedef enum _StringOperationType /* Indique le type défini pour une opération traitant une chaîne de caractères. */ -GType g_string_operation_get_type(void); +GType g_scan_string_operation_get_type(void); /* Organise un appel de fonction avec ses arguments. */ -GScanExpression *g_string_operation_new(StringOperationType, GScanExpression *, GScanExpression *, bool); +GScanExpression *g_scan_string_operation_new(StringOperationType, GScanExpression *, GScanExpression *, bool); diff --git a/src/analysis/scan/grammar.y b/src/analysis/scan/grammar.y index 525c5d1..19a4257 100644 --- a/src/analysis/scan/grammar.y +++ b/src/analysis/scan/grammar.y @@ -18,12 +18,15 @@ typedef void *yyscan_t; #include "scanner.h" #include "exprs/access.h" -#include "exprs/arithmop.h" -#include "exprs/boolop.h" +#include "exprs/arithmetic.h" #include "exprs/call.h" +#include "exprs/counter.h" +#include "exprs/intersect.h" #include "exprs/literal.h" +#include "exprs/logical.h" +#include "exprs/set.h" +#include "exprs/relational.h" #include "exprs/strop.h" -#include "exprs/relop.h" #include "patterns/tokens/plain.h" @@ -48,13 +51,12 @@ typedef void *yyscan_t; unsigned long long unsigned_integer; /* Valeur entière #1 */ signed long long signed_integer; /* Valeur entière #2 */ - double floating_number; /* Valeur à virgule flottante */ + //double floating_number; /* Valeur à virgule flottante */ sized_string_t sized_cstring; /* Chaîne de caractères */ - char byte; /* Octet unique */ + //char byte; /* Octet unique */ - unsigned long long integer; /* Valeur entière */ GScanRule *rule; /* Nouvelle règle à intégrer */ @@ -89,11 +91,17 @@ YY_DECL; } +%token INCLUDE "include" + %token RAW_RULE %token RULE_NAME %token STRINGS CONDITION %token IDENTIFIER +%token BYTES_ID +%token BYTES_ID_COUNTER +%token BYTES_ID_LOCATION +%token BYTES_ID_LENGTH %token NAME %token BRACE_IN BRACE_OUT ASSIGN COLON @@ -104,7 +112,8 @@ YY_DECL; %token TRUE_ "true" %token FALSE_ "false" -%token INTEGER +%token SIGNED_INTEGER +%token UNSIGNED_INTEGER %token STRING %token KB MB GB @@ -132,7 +141,7 @@ YY_DECL; %token PLUS "+" %token MINUS "-" %token MUL "*" -%token DIV "\\" +%token DIV "/" %token MOD "%" %token PAREN_O "(" @@ -145,16 +154,18 @@ YY_DECL; %token ALL "all" %token OF "of" %token THEM "them" +%token IN "in" %type RULE_NAME -%type IDENTIFIER +%type IDENTIFIER BYTES_ID_COUNTER %type NAME -%type INTEGER +%type SIGNED_INTEGER +%type UNSIGNED_INTEGER %type STRING %type rule @@ -162,16 +173,19 @@ YY_DECL; %type PLAIN_STRING %type MASKED_STRING -%type cexpression +%type cexpression _cexpression +%type pattern_match %type literal %type item_chain %type call_args -%type bool_expr -%type rel_expr -%type str_expr +%type logical_expr +%type relational_expr +%type string_op %type arithm_expr %type set_counter - +%type set +%type set_items +%type intersection %left OR @@ -181,11 +195,11 @@ YY_DECL; %left LT LE GT GE %left PLUS MINUS %left MUL DIV MOD +%left IN %right NOT - %destructor { printf("-------- Discarding symbol %p.\n", $$); } @@ -207,12 +221,24 @@ YY_DECL; rules : /* empty */ + | external rules | rule rules { g_content_scanner_add_rule(scanner, $1); } //rule : RAW_RULE RULE_NAME { printf("RULE %s\n", $2); } RAW_BLOCK { printf("BLOCK: %s\n", $4); } + +external : "include" STRING + { + bool __status; + __status = g_content_scanner_include_resource(scanner, $2.data); + if (!__status) + YYERROR; + } + + rule : RAW_RULE RULE_NAME { + //printf("--------built rule '%s'\n", $2.data); *built_rule = g_scan_rule_new($2.data); $$ = *built_rule; } @@ -220,6 +246,7 @@ rule : RAW_RULE RULE_NAME { $$ = $3; //printf("RULE %s -> %p\n", $2, $$); + //printf("end of rule\n"); } @@ -274,16 +301,18 @@ string_decl : IDENTIFIER ASSIGN PLAIN_STRING } ; -condition : /* empty */ - | CONDITION COLON cexpression - { - g_scan_rule_set_match_condition(*built_rule, $3); - g_object_ref(G_OBJECT($3)); - } - ; + condition : /* empty */ + | CONDITION COLON cexpression + { + g_scan_rule_set_match_condition(*built_rule, $3); + g_object_unref(G_OBJECT($3)); + } + ; -cexpression : IDENTIFIER - { + cexpression : _cexpression { $$ = $1; if ($$ == NULL) { printf("ERROR !!!\n"); YYERROR; } } + + _cexpression : IDENTIFIER + { printf("named var: %s\n", "$1"); /* GSearchPattern *__pat; @@ -297,112 +326,223 @@ cexpression : IDENTIFIER g_object_unref(G_OBJECT(__pat)); } */ - } - | literal { $$ = $1; } - | item_chain { $$ = $1; } - | bool_expr { $$ = $1; } - | rel_expr { $$ = $1; } - | str_expr { $$ = $1; } - | arithm_expr { $$ = $1; } - | set_counter { $$ = $1; } - | "(" cexpression ")" { $$ = $2; } + } + | literal { $$ = $1; } + | pattern_match { $$ = $1; } + | item_chain { $$ = $1; } + | logical_expr { $$ = $1; } + | relational_expr { $$ = $1; } + | string_op { $$ = $1; } + | arithm_expr { $$ = $1; } + | set_counter { $$ = $1; } + | set { $$ = $1; } + | intersection { $$ = $1; } + | "(" cexpression ")" { $$ = $2; } + ; + + pattern_match : BYTES_ID_COUNTER + { + GSearchPattern *__pat; + __pat = g_scan_rule_get_local_variable(*built_rule, $1.data); + $$ = g_scan_match_counter_new(__pat); + g_object_unref(G_OBJECT(__pat)); + } + ; + + literal : "true" + { + $$ = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ true }); + } + | "false" + { + $$ = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ false }); + } + | SIGNED_INTEGER + { + $$ = g_scan_literal_expression_new(LVT_SIGNED_INTEGER, &$1); + } + | UNSIGNED_INTEGER + { + $$ = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, &$1); + } + | UNSIGNED_INTEGER KB + { + unsigned long long __converted; + __converted = $1 * 1024; + $$ = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, &__converted); + } + | UNSIGNED_INTEGER MB + { + unsigned long long __converted; + __converted = $1 * 1048576; + $$ = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, &__converted); + } + | UNSIGNED_INTEGER GB + { + unsigned long long __converted; + __converted = $1 * 1073741824; + $$ = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, &__converted); + } + | STRING + { + $$ = g_scan_literal_expression_new(LVT_STRING, &$1); + } + ; + + item_chain : NAME { $$ = g_scan_named_access_new(&$1); } + | NAME "(" ")" { $$ = g_scan_pending_call_new(&$1, NULL, 0); } + | NAME "(" call_args ")" + { + size_t __i; + $$ = g_scan_pending_call_new(&$1, $3.args, $3.count); + for (__i = 0; __i < $3.count; __i++) + g_object_unref(G_OBJECT($3.args[__i])); + free($3.args); + } + | item_chain "." NAME + { + GScanExpression *__next; + __next = g_scan_named_access_new(&$3); + g_scan_named_access_attach_next(G_SCAN_NAMED_ACCESS($1), G_SCAN_NAMED_ACCESS(__next)); + $$ = $1; + } + | item_chain "." NAME "(" ")" + { + GScanExpression *__next; + __next = g_scan_pending_call_new(&$3, NULL, 0); + g_scan_named_access_attach_next(G_SCAN_NAMED_ACCESS($1), G_SCAN_NAMED_ACCESS(__next)); + $$ = $1; + } + | item_chain "." NAME "(" call_args ")" + { + GScanExpression *__next; + size_t __i; + __next = g_scan_pending_call_new(&$3, $5.args, $5.count); + for (__i = 0; __i < $5.count; __i++) + g_object_unref(G_OBJECT($5.args[__i])); + free($5.args); + g_scan_named_access_attach_next(G_SCAN_NAMED_ACCESS($1), G_SCAN_NAMED_ACCESS(__next)); + $$ = $1; + } + ; + + call_args : cexpression + { + $$.count = 1; + $$.args = malloc(sizeof(GScanExpression *)); + $$.args[0] = $1; + } + | call_args "," cexpression + { + $1.count++; + $1.args = realloc($1.args, $1.count * sizeof(GScanExpression *)); + $1.args[$1.count - 1] = $3; + $$ = $1; + } + ; + + logical_expr : cexpression "and" cexpression { $$ = g_scan_logical_operation_new(BOT_AND, $1, $3); } + | cexpression "or" cexpression { $$ = g_scan_logical_operation_new(BOT_OR, $1, $3); } + | "not" "(" cexpression ")" { $$ = g_scan_logical_operation_new(BOT_NOT, $3, NULL); } + ; + +relational_expr : cexpression "<" cexpression { $$ = g_scan_relational_operation_new(RCO_LT, $1, $3); } + | cexpression "<=" cexpression { $$ = g_scan_relational_operation_new(RCO_LE, $1, $3); } + | cexpression "==" cexpression { $$ = g_scan_relational_operation_new(RCO_EQ, $1, $3); } + | cexpression "!=" cexpression { $$ = g_scan_relational_operation_new(RCO_NE, $1, $3); } + | cexpression ">" cexpression { $$ = g_scan_relational_operation_new(RCO_GT, $1, $3); } + | cexpression ">=" cexpression { $$ = g_scan_relational_operation_new(RCO_GE, $1, $3); } + ; + + string_op : cexpression "contains" cexpression + { + $$ = g_scan_string_operation_new(SOT_CONTAINS, $1, $3, true); + } + | cexpression "startswith" cexpression + { + $$ = g_scan_string_operation_new(SOT_STARTSWITH, $1, $3, true); + } + | cexpression "endswith" cexpression + { + $$ = g_scan_string_operation_new(SOT_ENDSWITH, $1, $3, true); + } + | cexpression "matches" cexpression + { + $$ = g_scan_string_operation_new(SOT_MATCHES, $1, $3, true); + } + | cexpression "icontains" cexpression + { + $$ = g_scan_string_operation_new(SOT_CONTAINS, $1, $3, false); + } + | cexpression "istartswith" cexpression + { + $$ = g_scan_string_operation_new(SOT_STARTSWITH, $1, $3, false); + } + | cexpression "iendswith" cexpression + { + $$ = g_scan_string_operation_new(SOT_ENDSWITH, $1, $3, false); + } + | cexpression "iequals" cexpression + { + $$ = g_scan_string_operation_new(SOT_IEQUALS, $1, $3, false); + } + ; + + arithm_expr : cexpression "+" cexpression { $$ = g_scan_arithmetic_operation_new(AEO_PLUS, $1, $3); } + | cexpression "-" cexpression { $$ = g_scan_arithmetic_operation_new(AEO_MINUS, $1, $3); } + | cexpression "*" cexpression { $$ = g_scan_arithmetic_operation_new(AEO_MUL, $1, $3); } + | cexpression "/" cexpression { $$ = g_scan_arithmetic_operation_new(AEO_DIV, $1, $3); } + | cexpression "%" cexpression { $$ = g_scan_arithmetic_operation_new(AEO_MOD, $1, $3); } + ; + +set_counter : "none" "of" "them" { $$ = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ true }); } + | "any" "of" "them" { $$ = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ true }); } + | "all" "of" "them" { $$ = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ true }); } ; -literal : "true" { $$ = g_literal_expression_new(EVT_BOOLEAN, (bool []){ true }); } - | "false" { $$ = g_literal_expression_new(EVT_BOOLEAN, (bool []){ false }); } - | INTEGER { $$ = g_literal_expression_new(EVT_INTEGER, &$1); } - | INTEGER KB { $$ = g_literal_expression_new(EVT_INTEGER, (unsigned long long []){ $1 * 1024 }); } - | INTEGER MB { $$ = g_literal_expression_new(EVT_INTEGER, (unsigned long long []){ $1 * 1048576 }); } - | INTEGER GB { $$ = g_literal_expression_new(EVT_INTEGER, (unsigned long long []){ $1 * 1073741824 }); } - | STRING { $$ = g_literal_expression_new(EVT_STRING, &$1); } - ; -item_chain : NAME { $$ = g_named_access_new(&$1); } - | NAME "(" ")" { $$ = g_pending_call_new(&$1, NULL, 0); } - | NAME "(" call_args ")" - { - size_t __i; - $$ = g_pending_call_new(&$1, $3.args, $3.count); - for (__i = 0; __i < $3.count; __i++) - g_object_unref(G_OBJECT($3.args[__i])); - free($3.args); - } - | item_chain "." NAME - { - GScanExpression *__next; - __next = g_named_access_new(&$3); - g_named_access_attach_next(G_NAMED_ACCESS($1), G_NAMED_ACCESS(__next)); - $$ = $1; - } - | item_chain "." NAME "(" ")" - { - GScanExpression *__next; - __next = g_pending_call_new(&$3, NULL, 0); - g_named_access_attach_next(G_NAMED_ACCESS($1), G_NAMED_ACCESS(__next)); - $$ = $1; - } - | item_chain "." NAME "(" call_args ")" - { - GScanExpression *__next; - size_t __i; - __next = g_pending_call_new(&$3, $5.args, $5.count); - for (__i = 0; __i < $5.count; __i++) - g_object_unref(G_OBJECT($5.args[__i])); - free($5.args); - g_named_access_attach_next(G_NAMED_ACCESS($1), G_NAMED_ACCESS(__next)); - $$ = $1; - } - ; - -call_args : cexpression - { - $$.count = 1; - $$.args = malloc(sizeof(GScanExpression *)); - $$.args[0] = $1; - } - | call_args "," cexpression - { - $1.count++; - $1.args = realloc($1.args, $1.count * sizeof(GScanExpression *)); - $1.args[$1.count - 1] = $3; - $$ = $1; - } - ; - -bool_expr : cexpression "and" cexpression { $$ = g_boolean_operation_new(BOT_AND, $1, $3); } - | cexpression "or" cexpression { $$ = g_boolean_operation_new(BOT_OR, $1, $3); } - | "not" "(" cexpression ")" { $$ = g_boolean_operation_new(BOT_NOT, $3, NULL); } - ; - -rel_expr : cexpression "<" cexpression { $$ = g_relational_operation_new(RCO_LT, $1, $3); } - | cexpression "<=" cexpression { $$ = g_relational_operation_new(RCO_LE, $1, $3); } - | cexpression "==" cexpression { $$ = g_relational_operation_new(RCO_EQ, $1, $3); } - | cexpression "!=" cexpression { $$ = g_relational_operation_new(RCO_NE, $1, $3); } - | cexpression ">" cexpression { $$ = g_relational_operation_new(RCO_GT, $1, $3); } - | cexpression ">=" cexpression { $$ = g_relational_operation_new(RCO_GT, $1, $3); } - ; - -str_expr : cexpression "contains" cexpression { $$ = g_string_operation_new(SOT_CONTAINS, $1, $3, true); } - | cexpression "startswith" cexpression { $$ = g_string_operation_new(SOT_STARTSWITH, $1, $3, true); } - | cexpression "endswith" cexpression { $$ = g_string_operation_new(SOT_ENDSWITH, $1, $3, true); } - | cexpression "matches" cexpression { $$ = g_string_operation_new(SOT_MATCHES, $1, $3, true); } - | cexpression "icontains" cexpression { $$ = g_string_operation_new(SOT_CONTAINS, $1, $3, false); } - | cexpression "istartswith" cexpression { $$ = g_string_operation_new(SOT_STARTSWITH, $1, $3, false); } - | cexpression "iendswith" cexpression { $$ = g_string_operation_new(SOT_ENDSWITH, $1, $3, false); } - | cexpression "iequals" cexpression { $$ = g_string_operation_new(SOT_IEQUALS, $1, $3, false); } - ; - -arithm_expr : cexpression "+" cexpression { $$ = g_arithmetic_operation_new(AEO_PLUS, $1, $3); } - | cexpression "-" cexpression { $$ = g_arithmetic_operation_new(AEO_MINUS, $1, $3); } - | cexpression "*" cexpression { $$ = g_arithmetic_operation_new(AEO_MUL, $1, $3); } - | cexpression "\\" cexpression { $$ = g_arithmetic_operation_new(AEO_DIV, $1, $3); } - | cexpression "%" cexpression { $$ = g_arithmetic_operation_new(AEO_MOD, $1, $3); } - ; + set : "(" ")" + { + $$ = g_scan_generic_set_new(); + } + | "(" cexpression "," ")" + { + $$ = g_scan_generic_set_new(); + g_scan_generic_set_add_item(G_SCAN_GENERIC_SET($$), $2); + g_object_unref(G_OBJECT($2)); + } + | "(" set_items ")" + { + $$ = $2; + } + ; + + set_items : cexpression "," cexpression + { + $$ = g_scan_generic_set_new(); + g_scan_generic_set_add_item(G_SCAN_GENERIC_SET($$), $1); + g_object_unref(G_OBJECT($1)); + g_scan_generic_set_add_item(G_SCAN_GENERIC_SET($$), $3); + g_object_unref(G_OBJECT($3)); + } + | set_items "," cexpression + { + $$ = $1; + g_scan_generic_set_add_item(G_SCAN_GENERIC_SET($$), $3); + g_object_unref(G_OBJECT($3)); + } + ; + + intersection : cexpression "in" cexpression + { + $$ = g_scan_sets_intersection_new($1, $3); + g_object_unref(G_OBJECT($1)); + g_object_unref(G_OBJECT($3)); + } + ; + + -set_counter : "none" "of" "them" { $$ = g_literal_expression_new(EVT_BOOLEAN, (bool []){ true }); } - | "any" "of" "them" { $$ = g_literal_expression_new(EVT_BOOLEAN, (bool []){ true }); } - | "all" "of" "them" { $$ = g_literal_expression_new(EVT_BOOLEAN, (bool []){ true }); } - ; %% diff --git a/src/analysis/scan/items/Makefile.am b/src/analysis/scan/items/Makefile.am index 3a6bb62..ce39cad 100644 --- a/src/analysis/scan/items/Makefile.am +++ b/src/analysis/scan/items/Makefile.am @@ -2,14 +2,32 @@ noinst_LTLIBRARIES = libanalysisscanitems.la +if BUILD_MAGIC_SUPPORT + +MAGIC_LIBADD = magic/libanalysisscanitemsmagic.la + +MAGIC_SUBDIRS = magic + +endif + + libanalysisscanitems_la_SOURCES = \ + count.h count.c \ datasize.h datasize.c \ uint-int.h \ uint.h uint.c +libanalysisscanitems_la_LIBADD = \ + console/libanalysisscanitemsconsole.la \ + $(MAGIC_LIBADD) \ + time/libanalysisscanitemstime.la + libanalysisscanitems_la_CFLAGS = $(LIBGOBJ_CFLAGS) devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) dev_HEADERS = $(libanalysisscanitems_la_SOURCES:%c=) + + +SUBDIRS = console $(MAGIC_SUBDIRS) time diff --git a/src/analysis/scan/items/console/Makefile.am b/src/analysis/scan/items/console/Makefile.am new file mode 100644 index 0000000..4433789 --- /dev/null +++ b/src/analysis/scan/items/console/Makefile.am @@ -0,0 +1,13 @@ + +noinst_LTLIBRARIES = libanalysisscanitemsconsole.la + + +libanalysisscanitemsconsole_la_SOURCES = \ + log.h log.c + +libanalysisscanitemsconsole_la_CFLAGS = $(LIBGOBJ_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libanalysisscanitemsconsole_la_SOURCES:%c=) diff --git a/src/analysis/scan/items/console/log.c b/src/analysis/scan/items/console/log.c new file mode 100644 index 0000000..f4031c7 --- /dev/null +++ b/src/analysis/scan/items/console/log.c @@ -0,0 +1,303 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * log.c - affichage de message à partir des conditions d'une règle + * + * 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 . + */ + + +#include "log.h" + + +#include + + +#include "../../item-int.h" +#include "../../exprs/literal.h" + + + +/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */ + + +/* Initialise la classe des affichages de messages. */ +static void g_scan_console_log_function_class_init(GScanConsoleLogFunctionClass *); + +/* Initialise une instance d'affichage de message. */ +static void g_scan_console_log_function_init(GScanConsoleLogFunction *); + +/* Supprime toutes les références externes. */ +static void g_scan_console_log_function_dispose(GScanConsoleLogFunction *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_console_log_function_finalize(GScanConsoleLogFunction *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Indique le nom associé à une expression d'évaluation. */ +static char *g_scan_console_log_function_get_name(const GScanConsoleLogFunction *); + +/* Réduit une expression à une forme plus simple. */ +static bool g_scan_console_log_function_run_call(GScanConsoleLogFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE FONCTION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un afficheur de messages arbitraires. */ +G_DEFINE_TYPE(GScanConsoleLogFunction, g_scan_console_log_function, G_TYPE_REGISTERED_ITEM); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des affichages de messages. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_console_log_function_class_init(GScanConsoleLogFunctionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GRegisteredItemClass *registered; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_console_log_function_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_console_log_function_finalize; + + registered = G_REGISTERED_ITEM_CLASS(klass); + + registered->get_name = (get_registered_item_name_fc)g_scan_console_log_function_get_name; + registered->run_call = (run_registered_item_call_fc)g_scan_console_log_function_run_call; + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance à initialiser. * +* * +* Description : Initialise une instance d'affichage de message. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_console_log_function_init(GScanConsoleLogFunction *func) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_console_log_function_dispose(GScanConsoleLogFunction *func) +{ + G_OBJECT_CLASS(g_scan_console_log_function_parent_class)->dispose(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_console_log_function_finalize(GScanConsoleLogFunction *func) +{ + G_OBJECT_CLASS(g_scan_console_log_function_parent_class)->finalize(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Constitue une fonction d'affichage de messages quelconques. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanConsoleLogFunction *g_scan_console_log_function_new(void) +{ + GScanConsoleLogFunction *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_CONSOLE_LOG_FUNCTION, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* * +* Description : Indique le nom associé à une expression d'évaluation. * +* * +* Retour : Désignation humaine de l'expression d'évaluation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_console_log_function_get_name(const GScanConsoleLogFunction *item) +{ + char *result; /* Désignation à retourner */ + + result = strdup("log"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* args = liste d'éventuels arguments fournis. * +* count = taille de cette liste. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la résolution opérée. [OUT] * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_console_log_function_run_call(GScanConsoleLogFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours #1 */ + LiteralValueType vtype; /* Type de valeur portée */ + GScanLiteralExpression *literal; /* Version plus accessible */ + bool boolean; /* Valeur booléenne */ + long long sinteger; /* Valeur entière signée */ + unsigned long long uinteger; /* Valeur entière non signée */ + const sized_string_t *string; /* Description du chaîne */ + size_t k; /* Boucle de parcours #2 */ + + result = true; + + if (count == 0) + goto done; + + for (i = 0; i < count && result; i++) + result = G_IS_SCAN_LITERAL_EXPRESSION(args[i]); + + if (!result) + goto done; + + for (i = 0; i < count; i++) + { + literal = G_SCAN_LITERAL_EXPRESSION(args[i]); + + vtype = g_scan_literal_expression_get_value_type(literal); + + switch (vtype) + { + case LVT_BOOLEAN: + result = g_scan_literal_expression_get_boolean_value(literal, &boolean); + if (result) + fprintf(stderr, "%s", boolean ? "true" : "false"); + break; + + case LVT_SIGNED_INTEGER: + result = g_scan_literal_expression_get_signed_integer_value(literal, &sinteger); + if (result) + fprintf(stderr, "0x%llx", sinteger); + break; + + case LVT_UNSIGNED_INTEGER: + result = g_scan_literal_expression_get_unsigned_integer_value(literal, &uinteger); + if (result) + fprintf(stderr, "0x%llx", uinteger); + break; + + case LVT_STRING: + result = g_scan_literal_expression_get_string_value(literal, &string); + for (k = 0; k < string->len; k++) + { + if (isprint(string->data[k])) + fprintf(stderr, "%c", string->data[k]); + else + fprintf(stderr, "\\x%02hhx", string->data[k]); + } + break; + + default: + break; + + } + + } + + fprintf(stderr, "\n"); + + done: + + if (result) + *out = G_OBJECT(g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ result })); + + return result; + +} diff --git a/src/analysis/scan/items/console/log.h b/src/analysis/scan/items/console/log.h new file mode 100644 index 0000000..3e72ad8 --- /dev/null +++ b/src/analysis/scan/items/console/log.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * log.h - prototypes pour l'affichage de message à partir des conditions d'une règle + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_ITEMS_CONSOLE_LOG_H +#define _ANALYSIS_SCAN_ITEMS_CONSOLE_LOG_H + + +#include + + +#include "../../item.h" + + + +#define G_TYPE_SCAN_CONSOLE_LOG_FUNCTION g_scan_console_log_function_get_type() +#define G_SCAN_CONSOLE_LOG_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_CONSOLE_LOG_FUNCTION, GScanConsoleLogFunction)) +#define G_IS_SCAN_CONSOLE_LOG_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_CONSOLE_LOG_FUNCTION)) +#define G_SCAN_CONSOLE_LOG_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_CONSOLE_LOG_FUNCTION, GScanConsoleLogFunctionClass)) +#define G_IS_SCAN_CONSOLE_LOG_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_CONSOLE_LOG_FUNCTION)) +#define G_SCAN_CONSOLE_LOG_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_CONSOLE_LOG_FUNCTION, GScanConsoleLogFunctionClass)) + + +/* Mesure de la quantité de données scannées (instance) */ +typedef GRegisteredItem GScanConsoleLogFunction; + +/* Mesure de la quantité de données scannées (classe) */ +typedef GRegisteredItemClass GScanConsoleLogFunctionClass; + + +/* Indique le type défini pour un afficheur de messages arbitraires. */ +GType g_scan_console_log_function_get_type(void); + +/* Constitue une fonction d'affichage de messages quelconques. */ +GScanConsoleLogFunction *g_scan_console_log_function_new(void); + + + +#endif /* _ANALYSIS_SCAN_ITEMS_CONSOLE_LOG_H */ diff --git a/src/analysis/scan/items/count.c b/src/analysis/scan/items/count.c new file mode 100644 index 0000000..d87d33b --- /dev/null +++ b/src/analysis/scan/items/count.c @@ -0,0 +1,244 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * count.c - récupération de la taille du contenu scanné + * + * 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 . + */ + + +#include "count.h" + + +#include "../item-int.h" +#include "../exprs/arithmetic.h" +#include "../exprs/literal.h" + + + +/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */ + + +/* Initialise la classe des décomptes d'ensemble homogène. */ +static void g_scan_count_function_class_init(GScanCountFunctionClass *); + +/* Initialise une instance de décompte d'ensemble homogène. */ +static void g_scan_count_function_init(GScanCountFunction *); + +/* Supprime toutes les références externes. */ +static void g_scan_count_function_dispose(GScanCountFunction *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_count_function_finalize(GScanCountFunction *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Indique le nom associé à une expression d'évaluation. */ +static char *g_scan_count_function_get_name(const GScanCountFunction *); + +/* Réduit une expression à une forme plus simple. */ +static bool g_scan_count_function_run_call(GScanCountFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE FONCTION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un décompte d'ensemble. */ +G_DEFINE_TYPE(GScanCountFunction, g_scan_count_function, G_TYPE_REGISTERED_ITEM); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des décomptes d'ensemble homogène. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_count_function_class_init(GScanCountFunctionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GRegisteredItemClass *registered; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_count_function_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_count_function_finalize; + + registered = G_REGISTERED_ITEM_CLASS(klass); + + registered->get_name = (get_registered_item_name_fc)g_scan_count_function_get_name; + registered->run_call = (run_registered_item_call_fc)g_scan_count_function_run_call; + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance à initialiser. * +* * +* Description : Initialise une instance de décompte d'ensemble homogène. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_count_function_init(GScanCountFunction *func) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_count_function_dispose(GScanCountFunction *func) +{ + G_OBJECT_CLASS(g_scan_count_function_parent_class)->dispose(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_count_function_finalize(GScanCountFunction *func) +{ + G_OBJECT_CLASS(g_scan_count_function_parent_class)->finalize(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Constitue une fonction de décompte d'éléments d'un ensemble. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GRegisteredItem *g_scan_count_function_new(void) +{ + GScanCountFunction *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_COUNT_FUNCTION, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* * +* Description : Indique le nom associé à une expression d'évaluation. * +* * +* Retour : Désignation humaine de l'expression d'évaluation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_count_function_get_name(const GScanCountFunction *item) +{ + char *result; /* Désignation à retourner */ + + result = strdup("count"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* args = liste d'éventuels arguments fournis. * +* count = taille de cette liste. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la résolution opérée. [OUT] * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_count_function_run_call(GScanCountFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out) +{ + bool result; /* Bilan à retourner */ + size_t value; /* Nouveau décompte */ + + if (count != 1) + result = false; + + else + { + result = g_scan_expression_count_items(args[0], &value); + + if (result) + *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ value })); + + } + + return result; + +} diff --git a/src/analysis/scan/items/count.h b/src/analysis/scan/items/count.h new file mode 100644 index 0000000..2429e40 --- /dev/null +++ b/src/analysis/scan/items/count.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * count.h - prototypes pour la récupération de la taille du contenu scanné + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_ITEMS_COUNT_H +#define _ANALYSIS_SCAN_ITEMS_COUNT_H + + +#include + + +#include "../item.h" + + + +#define G_TYPE_SCAN_COUNT_FUNCTION g_scan_count_function_get_type() +#define G_SCAN_COUNT_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_COUNT_FUNCTION, GScanCountFunction)) +#define G_IS_SCAN_COUNT_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_COUNT_FUNCTION)) +#define G_SCAN_COUNT_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_COUNT_FUNCTION, GScanCountFunctionClass)) +#define G_IS_SCAN_COUNT_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_COUNT_FUNCTION)) +#define G_SCAN_COUNT_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_COUNT_FUNCTION, GScanCountFunctionClass)) + + +/* Mesure de la quantité de données scannées (instance) */ +typedef GRegisteredItem GScanCountFunction; + +/* Mesure de la quantité de données scannées (classe) */ +typedef GRegisteredItemClass GScanCountFunctionClass; + + +/* Indique le type défini pour un décompte d'ensemble. */ +GType g_scan_count_function_get_type(void); + +/* Constitue une fonction de décompte d'éléments d'un ensemble. */ +GRegisteredItem *g_scan_count_function_new(void); + + + +#endif /* _ANALYSIS_SCAN_ITEMS_COUNT_H */ diff --git a/src/analysis/scan/items/datasize.c b/src/analysis/scan/items/datasize.c index 618d0c3..55e2d3b 100644 --- a/src/analysis/scan/items/datasize.c +++ b/src/analysis/scan/items/datasize.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * datasize.c - récupération de la taille du contenu scanné * - * Copyright (C) 2022 Cyrille Bagard + * Copyright (C) 2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -33,16 +33,16 @@ /* Initialise la classe des mesures de quantité de données. */ -static void g_datasize_function_class_init(GDatasizeFunctionClass *); +static void g_scan_datasize_function_class_init(GScanDatasizeFunctionClass *); /* Initialise une instance de mesure de quantité de données. */ -static void g_datasize_function_init(GDatasizeFunction *); +static void g_scan_datasize_function_init(GScanDatasizeFunction *); /* Supprime toutes les références externes. */ -static void g_datasize_function_dispose(GDatasizeFunction *); +static void g_scan_datasize_function_dispose(GScanDatasizeFunction *); /* Procède à la libération totale de la mémoire. */ -static void g_datasize_function_finalize(GDatasizeFunction *); +static void g_scan_datasize_function_finalize(GScanDatasizeFunction *); @@ -50,13 +50,13 @@ static void g_datasize_function_finalize(GDatasizeFunction *); /* Indique le nom associé à une expression d'évaluation. */ -static char *g_datasize_function_get_name(const GDatasizeFunction *); +static char *g_scan_datasize_function_get_name(const GScanDatasizeFunction *); /* Réduit une expression à une forme plus simple. */ -static bool g_datasize_function_reduce(GDatasizeFunction *, GScanContext *, GScanScope *, GScanExpression **); +static bool g_scan_datasize_function_reduce(GScanDatasizeFunction *, GScanContext *, GScanScope *, GScanExpression **); /* Réduit une expression à une forme plus simple. */ -static bool g_datasize_function_run_call(GDatasizeFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **); +static bool g_scan_datasize_function_run_call(GScanDatasizeFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **); @@ -66,7 +66,7 @@ static bool g_datasize_function_run_call(GDatasizeFunction *, GScanExpression ** /* Indique le type défini pour une mesure de quantité de données scannées. */ -G_DEFINE_TYPE(GDatasizeFunction, g_datasize_function, G_TYPE_REGISTERED_ITEM); +G_DEFINE_TYPE(GScanDatasizeFunction, g_scan_datasize_function, G_TYPE_REGISTERED_ITEM); /****************************************************************************** @@ -81,21 +81,21 @@ G_DEFINE_TYPE(GDatasizeFunction, g_datasize_function, G_TYPE_REGISTERED_ITEM); * * ******************************************************************************/ -static void g_datasize_function_class_init(GDatasizeFunctionClass *klass) +static void g_scan_datasize_function_class_init(GScanDatasizeFunctionClass *klass) { GObjectClass *object; /* Autre version de la classe */ GRegisteredItemClass *registered; /* Version de classe parente */ object = G_OBJECT_CLASS(klass); - object->dispose = (GObjectFinalizeFunc/* ! */)g_datasize_function_dispose; - object->finalize = (GObjectFinalizeFunc)g_datasize_function_finalize; + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_datasize_function_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_datasize_function_finalize; registered = G_REGISTERED_ITEM_CLASS(klass); - registered->get_name = (get_registered_item_name_fc)g_datasize_function_get_name; - registered->reduce = (reduce_registered_item_fc)g_datasize_function_reduce; - registered->run_call = (run_registered_item_call_fc)g_datasize_function_run_call; + registered->get_name = (get_registered_item_name_fc)g_scan_datasize_function_get_name; + registered->reduce = (reduce_registered_item_fc)g_scan_datasize_function_reduce; + registered->run_call = (run_registered_item_call_fc)g_scan_datasize_function_run_call; } @@ -112,7 +112,7 @@ static void g_datasize_function_class_init(GDatasizeFunctionClass *klass) * * ******************************************************************************/ -static void g_datasize_function_init(GDatasizeFunction *func) +static void g_scan_datasize_function_init(GScanDatasizeFunction *func) { } @@ -130,9 +130,9 @@ static void g_datasize_function_init(GDatasizeFunction *func) * * ******************************************************************************/ -static void g_datasize_function_dispose(GDatasizeFunction *func) +static void g_scan_datasize_function_dispose(GScanDatasizeFunction *func) { - G_OBJECT_CLASS(g_datasize_function_parent_class)->dispose(G_OBJECT(func)); + G_OBJECT_CLASS(g_scan_datasize_function_parent_class)->dispose(G_OBJECT(func)); } @@ -149,9 +149,9 @@ static void g_datasize_function_dispose(GDatasizeFunction *func) * * ******************************************************************************/ -static void g_datasize_function_finalize(GDatasizeFunction *func) +static void g_scan_datasize_function_finalize(GScanDatasizeFunction *func) { - G_OBJECT_CLASS(g_datasize_function_parent_class)->finalize(G_OBJECT(func)); + G_OBJECT_CLASS(g_scan_datasize_function_parent_class)->finalize(G_OBJECT(func)); } @@ -168,11 +168,11 @@ static void g_datasize_function_finalize(GDatasizeFunction *func) * * ******************************************************************************/ -GDatasizeFunction *g_datasize_function_new(void) +GRegisteredItem *g_scan_datasize_function_new(void) { - GDatasizeFunction *result; /* Structure à retourner */ + GScanDatasizeFunction *result; /* Structure à retourner */ - result = g_object_new(G_TYPE_DATASIZE_FUNCTION, NULL); + result = g_object_new(G_TYPE_SCAN_DATASIZE_FUNCTION, NULL); return result; @@ -197,7 +197,7 @@ GDatasizeFunction *g_datasize_function_new(void) * * ******************************************************************************/ -static char *g_datasize_function_get_name(const GDatasizeFunction *item) +static char *g_scan_datasize_function_get_name(const GScanDatasizeFunction *item) { char *result; /* Désignation à retourner */ @@ -223,7 +223,7 @@ static char *g_datasize_function_get_name(const GDatasizeFunction *item) * * ******************************************************************************/ -static bool g_datasize_function_reduce(GDatasizeFunction *item, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +static bool g_scan_datasize_function_reduce(GScanDatasizeFunction *item, GScanContext *ctx, GScanScope *scope, GScanExpression **out) { bool result; /* Bilan à retourner */ GBinContent *content; /* Contenu à manipuler */ @@ -235,7 +235,7 @@ static bool g_datasize_function_reduce(GDatasizeFunction *item, GScanContext *ct size = g_binary_content_compute_size(content); - *out = g_literal_expression_new(EVT_INTEGER, (unsigned long long []){ size }); + *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ size }); g_object_unref(G_OBJECT(content)); @@ -261,11 +261,11 @@ static bool g_datasize_function_reduce(GDatasizeFunction *item, GScanContext *ct * * ******************************************************************************/ -static bool g_datasize_function_run_call(GDatasizeFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out) +static bool g_scan_datasize_function_run_call(GScanDatasizeFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out) { bool result; /* Bilan à retourner */ - result = g_datasize_function_reduce(item, ctx, scope, (GScanExpression **)out); + result = g_scan_datasize_function_reduce(item, ctx, scope, (GScanExpression **)out); return result; diff --git a/src/analysis/scan/items/datasize.h b/src/analysis/scan/items/datasize.h index bd8e185..476df2d 100644 --- a/src/analysis/scan/items/datasize.h +++ b/src/analysis/scan/items/datasize.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * datasize.h - prototypes pour la récupération de la taille du contenu scanné * - * Copyright (C) 2022 Cyrille Bagard + * Copyright (C) 2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -32,26 +32,26 @@ -#define G_TYPE_DATASIZE_FUNCTION g_datasize_function_get_type() -#define G_DATASIZE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_DATASIZE_FUNCTION, GDatasizeFunction)) -#define G_IS_DATASIZE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_DATASIZE_FUNCTION)) -#define G_DATASIZE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DATASIZE_FUNCTION, GDatasizeFunctionClass)) -#define G_IS_DATASIZE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DATASIZE_FUNCTION)) -#define G_DATASIZE_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DATASIZE_FUNCTION, GDatasizeFunctionClass)) +#define G_TYPE_SCAN_DATASIZE_FUNCTION g_scan_datasize_function_get_type() +#define G_SCAN_DATASIZE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_DATASIZE_FUNCTION, GScanDatasizeFunction)) +#define G_IS_SCAN_DATASIZE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_DATASIZE_FUNCTION)) +#define G_SCAN_DATASIZE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_DATASIZE_FUNCTION, GScanDatasizeFunctionClass)) +#define G_IS_SCAN_DATASIZE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_DATASIZE_FUNCTION)) +#define G_SCAN_DATASIZE_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_DATASIZE_FUNCTION, GScanDatasizeFunctionClass)) /* Mesure de la quantité de données scannées (instance) */ -typedef GRegisteredItem GDatasizeFunction; +typedef GRegisteredItem GScanDatasizeFunction; /* Mesure de la quantité de données scannées (classe) */ -typedef GRegisteredItemClass GDatasizeFunctionClass; +typedef GRegisteredItemClass GScanDatasizeFunctionClass; /* Indique le type défini pour une mesure de quantité de données scannées. */ -GType g_datasize_function_get_type(void); +GType g_scan_datasize_function_get_type(void); /* Constitue une fonction de récupération de taille de données. */ -GDatasizeFunction *g_datasize_function_new(void); +GRegisteredItem *g_scan_datasize_function_new(void); diff --git a/src/analysis/scan/items/magic/Makefile.am b/src/analysis/scan/items/magic/Makefile.am new file mode 100644 index 0000000..1d741ff --- /dev/null +++ b/src/analysis/scan/items/magic/Makefile.am @@ -0,0 +1,16 @@ + +noinst_LTLIBRARIES = libanalysisscanitemsmagic.la + + +libanalysisscanitemsmagic_la_SOURCES = \ + cookie.h cookie.c \ + mime-encoding.h mime-encoding.c \ + mime-type.h mime-type.c \ + type.h type.c + +libanalysisscanitemsmagic_la_CFLAGS = $(LIBGOBJ_CFLAGS) $(LIBMAGIC_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libanalysisscanitemsmagic_la_SOURCES:%c=) diff --git a/src/analysis/scan/items/magic/cookie.c b/src/analysis/scan/items/magic/cookie.c new file mode 100644 index 0000000..41f26a0 --- /dev/null +++ b/src/analysis/scan/items/magic/cookie.c @@ -0,0 +1,122 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * cookie.c - chargement des motifs de reconnaissance de contenus + * + * 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 . + */ + + +#include "cookie.h" + + +#include + + +#include + + +#include "../../../../core/logs.h" + + + +/* Référence des bibliothèques de reconnaissance */ +static magic_t __magic_cookie = 0; + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Charge les motifs de reconnaissance de contenus. * +* * +* Retour : Bilan de l'opération de chargemement. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool init_magic_cookie(void) +{ + bool result; /* Bilan à retourner */ + int ret; /* Bilan d'une opération */ + + __magic_cookie = magic_open(0); + + ret = magic_load(__magic_cookie, NULL); + result = (ret != -1); + + if (!result) + log_variadic_message(LMT_EXT_ERROR, _("cannot load magic database: %s"), magic_error(__magic_cookie)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Décharge les motifs de reconnaissance de contenus. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void exit_magic_cookie(void) +{ + magic_close(__magic_cookie); + +} + + +/****************************************************************************** +* * +* Paramètres : flags = forme de reconnaissance à préparer. * +* * +* Description : Fournit la référence aux mécanismes de reconnaissance. * +* * +* Retour : Cookie prêt à emploi. * +* * +* Remarques : - * +* * +******************************************************************************/ + +magic_t get_magic_cookie(int flags) +{ + magic_t result; /* Référence à retourner */ +#ifndef NDEBUG + int ret; /* Bilan de la préparation */ +#endif + + result = __magic_cookie; + assert(result != 0); + +#ifndef NDEBUG + ret = magic_setflags(result, flags); + assert(ret != -1); +#else + magic_setflags(result, flags); +#endif + + return result; + +} diff --git a/src/analysis/scan/items/magic/cookie.h b/src/analysis/scan/items/magic/cookie.h new file mode 100644 index 0000000..0ee2274 --- /dev/null +++ b/src/analysis/scan/items/magic/cookie.h @@ -0,0 +1,44 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * cookie.h - prototypes pour le chargement des motifs de reconnaissance de contenus + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_ITEMS_MAGIC_COOKIE_H +#define _ANALYSIS_SCAN_ITEMS_MAGIC_COOKIE_H + + +#include +#include + + + +/* Charge les motifs de reconnaissance de contenus. */ +bool init_magic_cookie(void); + +/* Décharge les motifs de reconnaissance de contenus. */ +void exit_magic_cookie(void); + +/* Fournit la référence aux mécanismes de reconnaissance. */ +magic_t get_magic_cookie(int); + + + +#endif /* _ANALYSIS_SCAN_ITEMS_MAGIC_COOKIE_H */ diff --git a/src/analysis/scan/items/magic/mime-encoding.c b/src/analysis/scan/items/magic/mime-encoding.c new file mode 100644 index 0000000..935515d --- /dev/null +++ b/src/analysis/scan/items/magic/mime-encoding.c @@ -0,0 +1,270 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * mime-encoding.c - reconnaissance de l'encodage d'un contenu + * + * 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 . + */ + + +#include "mime-encoding.h" + + +#include "cookie.h" +#include "../../item-int.h" +#include "../../exprs/literal.h" + + + +/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */ + + +/* Initialise la classe des reconnaissances de contenus. */ +static void g_scan_mime_encoding_function_class_init(GScanMimeEncodingFunctionClass *); + +/* Initialise une instance de reconnaissance de contenus. */ +static void g_scan_mime_encoding_function_init(GScanMimeEncodingFunction *); + +/* Supprime toutes les références externes. */ +static void g_scan_mime_encoding_function_dispose(GScanMimeEncodingFunction *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_mime_encoding_function_finalize(GScanMimeEncodingFunction *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Indique le nom associé à une expression d'évaluation. */ +static char *g_scan_mime_encoding_function_get_name(const GScanMimeEncodingFunction *); + +/* Réduit une expression à une forme plus simple. */ +static bool g_scan_mime_encoding_function_run_call(GScanMimeEncodingFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE FONCTION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une reconnaissance d'encodages de contenus. */ +G_DEFINE_TYPE(GScanMimeEncodingFunction, g_scan_mime_encoding_function, G_TYPE_REGISTERED_ITEM); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des reconnaissances de contenus. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_mime_encoding_function_class_init(GScanMimeEncodingFunctionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GRegisteredItemClass *registered; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_mime_encoding_function_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_mime_encoding_function_finalize; + + registered = G_REGISTERED_ITEM_CLASS(klass); + + registered->get_name = (get_registered_item_name_fc)g_scan_mime_encoding_function_get_name; + registered->run_call = (run_registered_item_call_fc)g_scan_mime_encoding_function_run_call; + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance à initialiser. * +* * +* Description : Initialise une instance de reconnaissance de contenus. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_mime_encoding_function_init(GScanMimeEncodingFunction *func) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_mime_encoding_function_dispose(GScanMimeEncodingFunction *func) +{ + G_OBJECT_CLASS(g_scan_mime_encoding_function_parent_class)->dispose(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_mime_encoding_function_finalize(GScanMimeEncodingFunction *func) +{ + G_OBJECT_CLASS(g_scan_mime_encoding_function_parent_class)->finalize(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Constitue une fonction de cernement d'encodages de contenus. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GRegisteredItem *g_scan_mime_encoding_function_new(void) +{ + GRegisteredItem *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_MIME_ENCODING_FUNCTION, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* * +* Description : Indique le nom associé à une expression d'évaluation. * +* * +* Retour : Désignation humaine de l'expression d'évaluation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_mime_encoding_function_get_name(const GScanMimeEncodingFunction *item) +{ + char *result; /* Désignation à retourner */ + + result = strdup("mime_encoding"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* args = liste d'éventuels arguments fournis. * +* count = taille de cette liste. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la résolution opérée. [OUT] * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_mime_encoding_function_run_call(GScanMimeEncodingFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out) +{ + bool result; /* Bilan à retourner */ + magic_t cookie; /* Référence des bibliothèques */ + GBinContent *content; /* Contenu à manipuler */ + vmpa2t pos; /* Tête de lecture */ + phys_t size; /* Quantité de données dispos. */ + const bin_t *data; /* Accès à des données */ + const char *desc; /* Description du contenu */ + sized_string_t string; /* Description à diffuser */ + + result = (count == 0); + if (!result) goto exit; + + cookie = get_magic_cookie(MAGIC_MIME_ENCODING); + + content = g_scan_context_get_content(ctx); + + g_binary_content_compute_start_pos(content, &pos); + + size = g_binary_content_compute_size(content); + + data = g_binary_content_get_raw_access(content, &pos, size); + + desc = magic_buffer(cookie, data, size); + + if (desc != NULL) + { + string.data = (char *)desc; + string.len = strlen(desc); + } + else + { + string.data = ""; + string.len = 0; + } + + *out = G_OBJECT(g_scan_literal_expression_new(LVT_STRING, &string)); + + g_object_unref(G_OBJECT(content)); + + exit: + + return result; + +} diff --git a/src/analysis/scan/items/magic/mime-encoding.h b/src/analysis/scan/items/magic/mime-encoding.h new file mode 100644 index 0000000..9349d55 --- /dev/null +++ b/src/analysis/scan/items/magic/mime-encoding.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * mime-encoding.h - prototypes pour la reconnaissance de l'encodage d'un contenu + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_ITEMS_MAGIC_MIME_ENCODING_H +#define _ANALYSIS_SCAN_ITEMS_MAGIC_MIME_ENCODING_H + + +#include + + +#include "../../item.h" + + + +#define G_TYPE_SCAN_MIME_ENCODING_FUNCTION g_scan_mime_encoding_function_get_type() +#define G_SCAN_MIME_ENCODING_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MIME_ENCODING_FUNCTION, GScanMimeEncodingFunction)) +#define G_IS_SCAN_MIME_ENCODING_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MIME_ENCODING_FUNCTION)) +#define G_SCAN_MIME_ENCODING_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MIME_ENCODING_FUNCTION, GScanMimeEncodingFunctionClass)) +#define G_IS_SCAN_MIME_ENCODING_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MIME_ENCODING_FUNCTION)) +#define G_SCAN_MIME_ENCODING_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MIME_ENCODING_FUNCTION, GScanMimeEncodingFunctionClass)) + + +/* Reconnaissance d'encodages de contenus (instance) */ +typedef GRegisteredItem GScanMimeEncodingFunction; + +/* Reconnaissance d'encodages de contenus (classe) */ +typedef GRegisteredItemClass GScanMimeEncodingFunctionClass; + + +/* Indique le type défini pour une reconnaissance d'encodages de contenus. */ +GType g_scan_mime_encoding_function_get_type(void); + +/* Constitue une fonction de cernement d'encodages de contenus. */ +GRegisteredItem *g_scan_mime_encoding_function_new(void); + + + +#endif /* _ANALYSIS_SCAN_ITEMS_MAGIC_MIME_ENCODING_H */ diff --git a/src/analysis/scan/items/magic/mime-type.c b/src/analysis/scan/items/magic/mime-type.c new file mode 100644 index 0000000..95e441d --- /dev/null +++ b/src/analysis/scan/items/magic/mime-type.c @@ -0,0 +1,270 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * type.c - reconnaissance du type MIME d'un contenu + * + * 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 . + */ + + +#include "mime-type.h" + + +#include "cookie.h" +#include "../../item-int.h" +#include "../../exprs/literal.h" + + + +/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */ + + +/* Initialise la classe des reconnaissances de contenus. */ +static void g_scan_mime_type_function_class_init(GScanMimeTypeFunctionClass *); + +/* Initialise une instance de reconnaissance de contenus. */ +static void g_scan_mime_type_function_init(GScanMimeTypeFunction *); + +/* Supprime toutes les références externes. */ +static void g_scan_mime_type_function_dispose(GScanMimeTypeFunction *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_mime_type_function_finalize(GScanMimeTypeFunction *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Indique le nom associé à une expression d'évaluation. */ +static char *g_scan_mime_type_function_get_name(const GScanMimeTypeFunction *); + +/* Réduit une expression à une forme plus simple. */ +static bool g_scan_mime_type_function_run_call(GScanMimeTypeFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE FONCTION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une reconnaissance de types de contenus. */ +G_DEFINE_TYPE(GScanMimeTypeFunction, g_scan_mime_type_function, G_TYPE_REGISTERED_ITEM); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des reconnaissances de contenus. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_mime_type_function_class_init(GScanMimeTypeFunctionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GRegisteredItemClass *registered; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_mime_type_function_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_mime_type_function_finalize; + + registered = G_REGISTERED_ITEM_CLASS(klass); + + registered->get_name = (get_registered_item_name_fc)g_scan_mime_type_function_get_name; + registered->run_call = (run_registered_item_call_fc)g_scan_mime_type_function_run_call; + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance à initialiser. * +* * +* Description : Initialise une instance de reconnaissance de contenus. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_mime_type_function_init(GScanMimeTypeFunction *func) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_mime_type_function_dispose(GScanMimeTypeFunction *func) +{ + G_OBJECT_CLASS(g_scan_mime_type_function_parent_class)->dispose(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_mime_type_function_finalize(GScanMimeTypeFunction *func) +{ + G_OBJECT_CLASS(g_scan_mime_type_function_parent_class)->finalize(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Constitue une fonction d'identification de types de contenus.* +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GRegisteredItem *g_scan_mime_type_function_new(void) +{ + GRegisteredItem *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_MIME_TYPE_FUNCTION, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* * +* Description : Indique le nom associé à une expression d'évaluation. * +* * +* Retour : Désignation humaine de l'expression d'évaluation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_mime_type_function_get_name(const GScanMimeTypeFunction *item) +{ + char *result; /* Désignation à retourner */ + + result = strdup("mime_type"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* args = liste d'éventuels arguments fournis. * +* count = taille de cette liste. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la résolution opérée. [OUT] * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_mime_type_function_run_call(GScanMimeTypeFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out) +{ + bool result; /* Bilan à retourner */ + magic_t cookie; /* Référence des bibliothèques */ + GBinContent *content; /* Contenu à manipuler */ + vmpa2t pos; /* Tête de lecture */ + phys_t size; /* Quantité de données dispos. */ + const bin_t *data; /* Accès à des données */ + const char *desc; /* Description du contenu */ + sized_string_t string; /* Description à diffuser */ + + result = (count == 0); + if (!result) goto exit; + + cookie = get_magic_cookie(MAGIC_MIME_TYPE); + + content = g_scan_context_get_content(ctx); + + g_binary_content_compute_start_pos(content, &pos); + + size = g_binary_content_compute_size(content); + + data = g_binary_content_get_raw_access(content, &pos, size); + + desc = magic_buffer(cookie, data, size); + + if (desc != NULL) + { + string.data = (char *)desc; + string.len = strlen(desc); + } + else + { + string.data = ""; + string.len = 0; + } + + *out = G_OBJECT(g_scan_literal_expression_new(LVT_STRING, &string)); + + g_object_unref(G_OBJECT(content)); + + exit: + + return result; + +} diff --git a/src/analysis/scan/items/magic/mime-type.h b/src/analysis/scan/items/magic/mime-type.h new file mode 100644 index 0000000..e02ce0f --- /dev/null +++ b/src/analysis/scan/items/magic/mime-type.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * mime-type.h - prototypes pour la reconnaissance du type MIME d'un contenu + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_ITEMS_MAGIC_MIME_TYPE_H +#define _ANALYSIS_SCAN_ITEMS_MAGIC_MIME_TYPE_H + + +#include + + +#include "../../item.h" + + + +#define G_TYPE_SCAN_MIME_TYPE_FUNCTION g_scan_mime_type_function_get_type() +#define G_SCAN_MIME_TYPE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MIME_TYPE_FUNCTION, GScanMimeTypeFunction)) +#define G_IS_SCAN_MIME_TYPE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MIME_TYPE_FUNCTION)) +#define G_SCAN_MIME_TYPE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MIME_TYPE_FUNCTION, GScanMimeTypeFunctionClass)) +#define G_IS_SCAN_MIME_TYPE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MIME_TYPE_FUNCTION)) +#define G_SCAN_MIME_TYPE_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MIME_TYPE_FUNCTION, GScanMimeTypeFunctionClass)) + + +/* Reconnaissance de types de contenus (instance) */ +typedef GRegisteredItem GScanMimeTypeFunction; + +/* Reconnaissance de types de contenus (classe) */ +typedef GRegisteredItemClass GScanMimeTypeFunctionClass; + + +/* Indique le type défini pour une reconnaissance de types de contenus. */ +GType g_scan_mime_type_function_get_type(void); + +/* Constitue une fonction d'identification de types de contenus. */ +GRegisteredItem *g_scan_mime_type_function_new(void); + + + +#endif /* _ANALYSIS_SCAN_ITEMS_MAGIC_MIME_TYPE_H */ diff --git a/src/analysis/scan/items/magic/type.c b/src/analysis/scan/items/magic/type.c new file mode 100644 index 0000000..f87c34a --- /dev/null +++ b/src/analysis/scan/items/magic/type.c @@ -0,0 +1,270 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * type.c - reconnaissance du type d'un contenu + * + * 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 . + */ + + +#include "type.h" + + +#include "cookie.h" +#include "../../item-int.h" +#include "../../exprs/literal.h" + + + +/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */ + + +/* Initialise la classe des reconnaissances de contenus. */ +static void g_scan_magic_type_function_class_init(GScanMagicTypeFunctionClass *); + +/* Initialise une instance de reconnaissance de contenus. */ +static void g_scan_magic_type_function_init(GScanMagicTypeFunction *); + +/* Supprime toutes les références externes. */ +static void g_scan_magic_type_function_dispose(GScanMagicTypeFunction *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_magic_type_function_finalize(GScanMagicTypeFunction *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Indique le nom associé à une expression d'évaluation. */ +static char *g_scan_magic_type_function_get_name(const GScanMagicTypeFunction *); + +/* Réduit une expression à une forme plus simple. */ +static bool g_scan_magic_type_function_run_call(GScanMagicTypeFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE FONCTION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une reconnaissance de types de contenus. */ +G_DEFINE_TYPE(GScanMagicTypeFunction, g_scan_magic_type_function, G_TYPE_REGISTERED_ITEM); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des reconnaissances de contenus. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_magic_type_function_class_init(GScanMagicTypeFunctionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GRegisteredItemClass *registered; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_magic_type_function_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_magic_type_function_finalize; + + registered = G_REGISTERED_ITEM_CLASS(klass); + + registered->get_name = (get_registered_item_name_fc)g_scan_magic_type_function_get_name; + registered->run_call = (run_registered_item_call_fc)g_scan_magic_type_function_run_call; + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance à initialiser. * +* * +* Description : Initialise une instance de reconnaissance de contenus. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_magic_type_function_init(GScanMagicTypeFunction *func) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_magic_type_function_dispose(GScanMagicTypeFunction *func) +{ + G_OBJECT_CLASS(g_scan_magic_type_function_parent_class)->dispose(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_magic_type_function_finalize(GScanMagicTypeFunction *func) +{ + G_OBJECT_CLASS(g_scan_magic_type_function_parent_class)->finalize(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Constitue une fonction d'identification de types de contenus.* +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GRegisteredItem *g_scan_magic_type_function_new(void) +{ + GRegisteredItem *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_MAGIC_TYPE_FUNCTION, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* * +* Description : Indique le nom associé à une expression d'évaluation. * +* * +* Retour : Désignation humaine de l'expression d'évaluation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_magic_type_function_get_name(const GScanMagicTypeFunction *item) +{ + char *result; /* Désignation à retourner */ + + result = strdup("type"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* args = liste d'éventuels arguments fournis. * +* count = taille de cette liste. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la résolution opérée. [OUT] * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_magic_type_function_run_call(GScanMagicTypeFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out) +{ + bool result; /* Bilan à retourner */ + magic_t cookie; /* Référence des bibliothèques */ + GBinContent *content; /* Contenu à manipuler */ + vmpa2t pos; /* Tête de lecture */ + phys_t size; /* Quantité de données dispos. */ + const bin_t *data; /* Accès à des données */ + const char *desc; /* Description du contenu */ + sized_string_t string; /* Description à diffuser */ + + result = (count == 0); + if (!result) goto exit; + + cookie = get_magic_cookie(MAGIC_NONE); + + content = g_scan_context_get_content(ctx); + + g_binary_content_compute_start_pos(content, &pos); + + size = g_binary_content_compute_size(content); + + data = g_binary_content_get_raw_access(content, &pos, size); + + desc = magic_buffer(cookie, data, size); + + if (desc != NULL) + { + string.data = (char *)desc; + string.len = strlen(desc); + } + else + { + string.data = ""; + string.len = 0; + } + + *out = G_OBJECT(g_scan_literal_expression_new(LVT_STRING, &string)); + + g_object_unref(G_OBJECT(content)); + + exit: + + return result; + +} diff --git a/src/analysis/scan/items/magic/type.h b/src/analysis/scan/items/magic/type.h new file mode 100644 index 0000000..bfad213 --- /dev/null +++ b/src/analysis/scan/items/magic/type.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * type.h - prototypes pour la reconnaissance du type d'un contenu + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_ITEMS_MAGIC_TYPE_H +#define _ANALYSIS_SCAN_ITEMS_MAGIC_TYPE_H + + +#include + + +#include "../../item.h" + + + +#define G_TYPE_SCAN_MAGIC_TYPE_FUNCTION g_scan_magic_type_function_get_type() +#define G_SCAN_MAGIC_TYPE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MAGIC_TYPE_FUNCTION, GScanMagicTypeFunction)) +#define G_IS_SCAN_MAGIC_TYPE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MAGIC_TYPE_FUNCTION)) +#define G_SCAN_MAGIC_TYPE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MAGIC_TYPE_FUNCTION, GScanMagicTypeFunctionClass)) +#define G_IS_SCAN_MAGIC_TYPE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MAGIC_TYPE_FUNCTION)) +#define G_SCAN_MAGIC_TYPE_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MAGIC_TYPE_FUNCTION, GScanMagicTypeFunctionClass)) + + +/* Reconnaissance de types de contenus (instance) */ +typedef GRegisteredItem GScanMagicTypeFunction; + +/* Reconnaissance de types de contenus (classe) */ +typedef GRegisteredItemClass GScanMagicTypeFunctionClass; + + +/* Indique le type défini pour une reconnaissance de types de contenus. */ +GType g_scan_magic_type_function_get_type(void); + +/* Constitue une fonction d'identification de types de contenus. */ +GRegisteredItem *g_scan_magic_type_function_new(void); + + + +#endif /* _ANALYSIS_SCAN_ITEMS_MAGIC_TYPE_H */ diff --git a/src/analysis/scan/items/time/Makefile.am b/src/analysis/scan/items/time/Makefile.am new file mode 100644 index 0000000..e5330be --- /dev/null +++ b/src/analysis/scan/items/time/Makefile.am @@ -0,0 +1,14 @@ + +noinst_LTLIBRARIES = libanalysisscanitemstime.la + + +libanalysisscanitemstime_la_SOURCES = \ + make.h make.c \ + now.h now.c + +libanalysisscanitemstime_la_CFLAGS = $(LIBGOBJ_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libanalysisscanitemstime_la_SOURCES:%c=) diff --git a/src/analysis/scan/items/time/make.c b/src/analysis/scan/items/time/make.c new file mode 100644 index 0000000..477a77c --- /dev/null +++ b/src/analysis/scan/items/time/make.c @@ -0,0 +1,350 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * make.c - construction de volume de secondes à partir d'une date + * + * 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 . + */ + + +#include "make.h" + + +#include +#include + + +#include "../../item-int.h" +#include "../../exprs/literal.h" + + + +/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */ + + +/* Initialise la classe des conversions de dates en secondes. */ +static void g_scan_time_make_function_class_init(GScanTimeMakeFunctionClass *); + +/* Initialise une instance de convertisseur de date en secondes. */ +static void g_scan_time_make_function_init(GScanTimeMakeFunction *); + +/* Supprime toutes les références externes. */ +static void g_scan_time_make_function_dispose(GScanTimeMakeFunction *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_time_make_function_finalize(GScanTimeMakeFunction *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Indique le nom associé à une expression d'évaluation. */ +static char *g_scan_time_make_function_get_name(const GScanTimeMakeFunction *); + +/* Réduit une expression à une forme plus simple. */ +static bool g_scan_time_make_function_run_call(GScanTimeMakeFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE FONCTION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une conversion de date en nombre de secondes. */ +G_DEFINE_TYPE(GScanTimeMakeFunction, g_scan_time_make_function, G_TYPE_REGISTERED_ITEM); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des conversions de dates en secondes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_time_make_function_class_init(GScanTimeMakeFunctionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GRegisteredItemClass *registered; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_time_make_function_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_time_make_function_finalize; + + registered = G_REGISTERED_ITEM_CLASS(klass); + + registered->get_name = (get_registered_item_name_fc)g_scan_time_make_function_get_name; + registered->run_call = (run_registered_item_call_fc)g_scan_time_make_function_run_call; + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance à initialiser. * +* * +* Description : Initialise une instance de convertisseur de date en secondes.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_time_make_function_init(GScanTimeMakeFunction *func) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_time_make_function_dispose(GScanTimeMakeFunction *func) +{ + G_OBJECT_CLASS(g_scan_time_make_function_parent_class)->dispose(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_time_make_function_finalize(GScanTimeMakeFunction *func) +{ + G_OBJECT_CLASS(g_scan_time_make_function_parent_class)->finalize(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Constitue une fonction de décompte du temps écoulé. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GRegisteredItem *g_scan_time_make_function_new(void) +{ + GRegisteredItem *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_TIME_MAKE_FUNCTION, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* * +* Description : Indique le nom associé à une expression d'évaluation. * +* * +* Retour : Désignation humaine de l'expression d'évaluation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_time_make_function_get_name(const GScanTimeMakeFunction *item) +{ + char *result; /* Désignation à retourner */ + + result = strdup("make"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* args = liste d'éventuels arguments fournis. * +* count = taille de cette liste. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la résolution opérée. [OUT] * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_time_make_function_run_call(GScanTimeMakeFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out) +{ + bool result; /* Bilan à retourner */ + bool status; /* Possibilité de construction */ + size_t i; /* Boucle de parcours */ + LiteralValueType vtype; /* Type de valeur portée */ + struct tm date; /* Date à mettre en place */ + unsigned long long value; /* Valeur entière à utiliser */ + time_t computed; /* Nombre de secondes déterminé*/ + + /* Validation des arguments */ + + result = (count == 3 || count == 6); + if (!result) goto exit; + + status = true; + + for (i = 0; i < count && status; i++) + { + status = G_IS_SCAN_LITERAL_EXPRESSION(args[i]); + if (!status) break; + + vtype = g_scan_literal_expression_get_value_type(G_SCAN_LITERAL_EXPRESSION(args[i])); + + status = (vtype == LVT_UNSIGNED_INTEGER); + if (!status) break; + + } + + if (!status) goto exit; + + /* Lecture des arguments */ + + memset(&date, 0, sizeof(struct tm)); + + status = g_scan_literal_expression_get_unsigned_integer_value(G_SCAN_LITERAL_EXPRESSION(args[0]), &value); + assert(status); + if (!status) goto exit; + + if (value < 1900) + { + result = false; + goto exit; + } + + date.tm_year = value - 1900; + + status = g_scan_literal_expression_get_unsigned_integer_value(G_SCAN_LITERAL_EXPRESSION(args[1]), &value); + assert(status); + if (!status) goto exit; + + if (value > 12) + { + result = false; + goto exit; + } + + date.tm_mon = value - 1; + + status = g_scan_literal_expression_get_unsigned_integer_value(G_SCAN_LITERAL_EXPRESSION(args[2]), &value); + assert(status); + if (!status) goto exit; + + if (value < 1 || value > 31) + { + result = false; + goto exit; + } + + date.tm_mday = value; + + if (count == 6) + { + status = g_scan_literal_expression_get_unsigned_integer_value(G_SCAN_LITERAL_EXPRESSION(args[3]), &value); + assert(status); + if (!status) goto exit; + + if (value >= 24) + { + result = false; + goto exit; + } + + date.tm_hour = value; + + status = g_scan_literal_expression_get_unsigned_integer_value(G_SCAN_LITERAL_EXPRESSION(args[4]), &value); + assert(status); + if (!status) goto exit; + + if (value >= 60) + { + result = false; + goto exit; + } + + date.tm_min = value; + + status = g_scan_literal_expression_get_unsigned_integer_value(G_SCAN_LITERAL_EXPRESSION(args[5]), &value); + assert(status); + if (!status) goto exit; + + if (value >= 60) + { + result = false; + goto exit; + } + + date.tm_sec = value; + + } + + /* Construction de la valeur finale */ + + computed = timegm(&date); + + if (computed != (time_t)-1) + *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ computed })); + + exit: + + return result; + +} diff --git a/src/analysis/scan/items/time/make.h b/src/analysis/scan/items/time/make.h new file mode 100644 index 0000000..958a392 --- /dev/null +++ b/src/analysis/scan/items/time/make.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * make.h - prototypes pour une construction de volume de secondes à partir d'une date + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_ITEMS_TIME_MAKE_H +#define _ANALYSIS_SCAN_ITEMS_TIME_MAKE_H + + +#include + + +#include "../../item.h" + + + +#define G_TYPE_SCAN_TIME_MAKE_FUNCTION g_scan_time_make_function_get_type() +#define G_SCAN_TIME_MAKE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TIME_MAKE_FUNCTION, GScanTimeMakeFunction)) +#define G_IS_SCAN_TIME_MAKE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TIME_MAKE_FUNCTION)) +#define G_SCAN_TIME_MAKE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TIME_MAKE_FUNCTION, GScanTimeMakeFunctionClass)) +#define G_IS_SCAN_TIME_MAKE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TIME_MAKE_FUNCTION)) +#define G_SCAN_TIME_MAKE_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TIME_MAKE_FUNCTION, GScanTimeMakeFunctionClass)) + + +/* Convertisseur de date en nombre de secondes depuis le 01/01/1970 (instance) */ +typedef GRegisteredItem GScanTimeMakeFunction; + +/* Convertisseur de date en nombre de secondes depuis le 01/01/1970 (classe) */ +typedef GRegisteredItemClass GScanTimeMakeFunctionClass; + + +/* Indique le type défini pour une conversion de date en nombre de secondes. */ +GType g_scan_time_make_function_get_type(void); + +/* Constitue une fonction de décompte du temps écoulé. */ +GRegisteredItem *g_scan_time_make_function_new(void); + + + +#endif /* _ANALYSIS_SCAN_ITEMS_TIME_MAKE_H */ diff --git a/src/analysis/scan/items/time/now.c b/src/analysis/scan/items/time/now.c new file mode 100644 index 0000000..16c4aef --- /dev/null +++ b/src/analysis/scan/items/time/now.c @@ -0,0 +1,243 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * now.c - décompte du temps écoulé depuis Epoch + * + * 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 . + */ + + +#include "now.h" + + +#include + + +#include "../../item-int.h" +#include "../../exprs/literal.h" + + + +/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */ + + +/* Initialise la classe des décomptes de temps écoulé. */ +static void g_scan_time_now_function_class_init(GScanTimeNowFunctionClass *); + +/* Initialise une instance de décompte de temps écoulé. */ +static void g_scan_time_now_function_init(GScanTimeNowFunction *); + +/* Supprime toutes les références externes. */ +static void g_scan_time_now_function_dispose(GScanTimeNowFunction *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_time_now_function_finalize(GScanTimeNowFunction *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Indique le nom associé à une expression d'évaluation. */ +static char *g_scan_time_now_function_get_name(const GScanTimeNowFunction *); + +/* Réduit une expression à une forme plus simple. */ +static bool g_scan_time_now_function_run_call(GScanTimeNowFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE FONCTION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un décompte de secondes écoulées depuis le 01/01/1970. */ +G_DEFINE_TYPE(GScanTimeNowFunction, g_scan_time_now_function, G_TYPE_REGISTERED_ITEM); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des décomptes de temps écoulé. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_time_now_function_class_init(GScanTimeNowFunctionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GRegisteredItemClass *registered; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_time_now_function_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_time_now_function_finalize; + + registered = G_REGISTERED_ITEM_CLASS(klass); + + registered->get_name = (get_registered_item_name_fc)g_scan_time_now_function_get_name; + registered->run_call = (run_registered_item_call_fc)g_scan_time_now_function_run_call; + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance à initialiser. * +* * +* Description : Initialise une instance de décompte de temps écoulé. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_time_now_function_init(GScanTimeNowFunction *func) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_time_now_function_dispose(GScanTimeNowFunction *func) +{ + G_OBJECT_CLASS(g_scan_time_now_function_parent_class)->dispose(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_time_now_function_finalize(GScanTimeNowFunction *func) +{ + G_OBJECT_CLASS(g_scan_time_now_function_parent_class)->finalize(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Constitue une fonction de décompte du temps écoulé. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GRegisteredItem *g_scan_time_now_function_new(void) +{ + GRegisteredItem *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_TIME_NOW_FUNCTION, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* * +* Description : Indique le nom associé à une expression d'évaluation. * +* * +* Retour : Désignation humaine de l'expression d'évaluation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_time_now_function_get_name(const GScanTimeNowFunction *item) +{ + char *result; /* Désignation à retourner */ + + result = strdup("now"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* args = liste d'éventuels arguments fournis. * +* count = taille de cette liste. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la résolution opérée. [OUT] * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_time_now_function_run_call(GScanTimeNowFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out) +{ + bool result; /* Bilan à retourner */ + time_t now; /* Date relative courante */ + + result = (count == 0); + if (!result) goto exit; + + now = time(NULL); + + *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ now })); + + exit: + + return result; + +} diff --git a/src/analysis/scan/items/time/now.h b/src/analysis/scan/items/time/now.h new file mode 100644 index 0000000..6b3faa2 --- /dev/null +++ b/src/analysis/scan/items/time/now.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * now.h - prototypes pour le décompte du temps écoulé depuis Epoch + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_ITEMS_TIME_NOW_H +#define _ANALYSIS_SCAN_ITEMS_TIME_NOW_H + + +#include + + +#include "../../item.h" + + + +#define G_TYPE_SCAN_TIME_NOW_FUNCTION g_scan_time_now_function_get_type() +#define G_SCAN_TIME_NOW_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TIME_NOW_FUNCTION, GScanTimeNowFunction)) +#define G_IS_SCAN_TIME_NOW_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TIME_NOW_FUNCTION)) +#define G_SCAN_TIME_NOW_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TIME_NOW_FUNCTION, GScanTimeNowFunctionClass)) +#define G_IS_SCAN_TIME_NOW_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TIME_NOW_FUNCTION)) +#define G_SCAN_TIME_NOW_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TIME_NOW_FUNCTION, GScanTimeNowFunctionClass)) + + +/* Décompte du nombre de seccondes écoulées depuis le 01/01/1970 (instance) */ +typedef GRegisteredItem GScanTimeNowFunction; + +/* Décompte du nombre de seccondes écoulées depuis le 01/01/1970 (classe) */ +typedef GRegisteredItemClass GScanTimeNowFunctionClass; + + +/* Indique le type défini pour un décompte de secondes écoulées depuis le 01/01/1970. */ +GType g_scan_time_now_function_get_type(void); + +/* Constitue une fonction de décompte du temps écoulé. */ +GRegisteredItem *g_scan_time_now_function_new(void); + + + +#endif /* _ANALYSIS_SCAN_ITEMS_TIME_NOW_H */ diff --git a/src/analysis/scan/items/uint-int.h b/src/analysis/scan/items/uint-int.h index 1fa83c5..972d7a0 100644 --- a/src/analysis/scan/items/uint-int.h +++ b/src/analysis/scan/items/uint-int.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * uint-int.h - prototypes internes pour la lecture d'un mot à partir de données binaires * - * Copyright (C) 2022 Cyrille Bagard + * Copyright (C) 2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -33,7 +33,7 @@ /* Fonction conduisant à la lecture d'un mot (instance) */ -struct _GUintFunction +struct _GScanUintFunction { GRegisteredItem parent; /* A laisser en premier */ @@ -43,7 +43,7 @@ struct _GUintFunction }; /* Fonction conduisant à la lecture d'un mot (classe) */ -struct _GUintFunctionClass +struct _GScanUintFunctionClass { GRegisteredItemClass parent; /* A laisser en premier */ @@ -51,7 +51,7 @@ struct _GUintFunctionClass /* Met en place un nouvelle fonction de lecture d'entiers. */ -bool g_uint_function_create(GUintFunction *, MemoryDataSize); +bool g_scan_uint_function_create(GScanUintFunction *, MemoryDataSize, SourceEndian); diff --git a/src/analysis/scan/items/uint.c b/src/analysis/scan/items/uint.c index 4fea494..66c7fa9 100644 --- a/src/analysis/scan/items/uint.c +++ b/src/analysis/scan/items/uint.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * uint.c - lecture d'un mot à partir de données binaires * - * Copyright (C) 2022 Cyrille Bagard + * Copyright (C) 2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -29,6 +29,7 @@ #include "uint-int.h" #include "../exprs/literal.h" +#include "../../../common/extstr.h" @@ -36,16 +37,16 @@ /* Initialise la classe des lectures de valeurs entières. */ -static void g_uint_function_class_init(GUintFunctionClass *); +static void g_scan_uint_function_class_init(GScanUintFunctionClass *); /* Initialise une instance de lecture de valeur entière. */ -static void g_uint_function_init(GUintFunction *); +static void g_scan_uint_function_init(GScanUintFunction *); /* Supprime toutes les références externes. */ -static void g_uint_function_dispose(GUintFunction *); +static void g_scan_uint_function_dispose(GScanUintFunction *); /* Procède à la libération totale de la mémoire. */ -static void g_uint_function_finalize(GUintFunction *); +static void g_scan_uint_function_finalize(GScanUintFunction *); @@ -53,10 +54,10 @@ static void g_uint_function_finalize(GUintFunction *); /* Indique le nom associé à une expression d'évaluation. */ -static char *g_uint_function_get_name(const GUintFunction *); +static char *g_scan_uint_function_get_name(const GScanUintFunction *); /* Réduit une expression à une forme plus simple. */ -static bool g_uint_function_run_call(GUintFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **); +static bool g_scan_uint_function_run_call(GScanUintFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **); @@ -66,7 +67,7 @@ static bool g_uint_function_run_call(GUintFunction *, GScanExpression **, size_t /* Indique le type défini pour une lecture de mot à partir de données binaires. */ -G_DEFINE_TYPE(GUintFunction, g_uint_function, G_TYPE_REGISTERED_ITEM); +G_DEFINE_TYPE(GScanUintFunction, g_scan_uint_function, G_TYPE_REGISTERED_ITEM); /****************************************************************************** @@ -81,20 +82,20 @@ G_DEFINE_TYPE(GUintFunction, g_uint_function, G_TYPE_REGISTERED_ITEM); * * ******************************************************************************/ -static void g_uint_function_class_init(GUintFunctionClass *klass) +static void g_scan_uint_function_class_init(GScanUintFunctionClass *klass) { GObjectClass *object; /* Autre version de la classe */ GRegisteredItemClass *registered; /* Version de classe parente */ object = G_OBJECT_CLASS(klass); - object->dispose = (GObjectFinalizeFunc/* ! */)g_uint_function_dispose; - object->finalize = (GObjectFinalizeFunc)g_uint_function_finalize; + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_uint_function_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_uint_function_finalize; registered = G_REGISTERED_ITEM_CLASS(klass); - registered->get_name = (get_registered_item_name_fc)g_uint_function_get_name; - registered->run_call = (run_registered_item_call_fc)g_uint_function_run_call; + registered->get_name = (get_registered_item_name_fc)g_scan_uint_function_get_name; + registered->run_call = (run_registered_item_call_fc)g_scan_uint_function_run_call; } @@ -111,7 +112,7 @@ static void g_uint_function_class_init(GUintFunctionClass *klass) * * ******************************************************************************/ -static void g_uint_function_init(GUintFunction *func) +static void g_scan_uint_function_init(GScanUintFunction *func) { func->size = MDS_UNDEFINED; func->endian = SRE_LITTLE; @@ -131,9 +132,9 @@ static void g_uint_function_init(GUintFunction *func) * * ******************************************************************************/ -static void g_uint_function_dispose(GUintFunction *func) +static void g_scan_uint_function_dispose(GScanUintFunction *func) { - G_OBJECT_CLASS(g_uint_function_parent_class)->dispose(G_OBJECT(func)); + G_OBJECT_CLASS(g_scan_uint_function_parent_class)->dispose(G_OBJECT(func)); } @@ -150,9 +151,9 @@ static void g_uint_function_dispose(GUintFunction *func) * * ******************************************************************************/ -static void g_uint_function_finalize(GUintFunction *func) +static void g_scan_uint_function_finalize(GScanUintFunction *func) { - G_OBJECT_CLASS(g_uint_function_parent_class)->finalize(G_OBJECT(func)); + G_OBJECT_CLASS(g_scan_uint_function_parent_class)->finalize(G_OBJECT(func)); } @@ -169,13 +170,13 @@ static void g_uint_function_finalize(GUintFunction *func) * * ******************************************************************************/ -GUintFunction *g_uint_function_new(MemoryDataSize size) +GRegisteredItem *g_scan_uint_function_new(MemoryDataSize size, SourceEndian endian) { - GUintFunction *result; /* Structure à retourner */ + GRegisteredItem *result; /* Structure à retourner */ - result = g_object_new(G_TYPE_UINT_FUNCTION, NULL); + result = g_object_new(G_TYPE_SCAN_UINT_FUNCTION, NULL); - if (!g_uint_function_create(result, size)) + if (!g_scan_uint_function_create(G_SCAN_UINT_FUNCTION(result), size, endian)) g_clear_object(&result); return result; @@ -196,13 +197,14 @@ GUintFunction *g_uint_function_new(MemoryDataSize size) * * ******************************************************************************/ -bool g_uint_function_create(GUintFunction *func, MemoryDataSize size) +bool g_scan_uint_function_create(GScanUintFunction *func, MemoryDataSize size, SourceEndian endian) { bool result; /* Bilan à retourner */ result = true; func->size = size; + func->endian = endian; return result; @@ -227,26 +229,26 @@ bool g_uint_function_create(GUintFunction *func, MemoryDataSize size) * * ******************************************************************************/ -static char *g_uint_function_get_name(const GUintFunction *item) +static char *g_scan_uint_function_get_name(const GScanUintFunction *item) { char *result; /* Désignation à retourner */ - switch (item->size) + switch (item->size & ~MDS_SIGN) { case MDS_8_BITS_UNSIGNED: - result = strdup("uint8"); + result = strdup("int8"); break; case MDS_16_BITS_UNSIGNED: - result = strdup("uint16"); + result = strdup("int16"); break; case MDS_32_BITS_UNSIGNED: - result = strdup("uint32"); + result = strdup("int32"); break; case MDS_64_BITS_UNSIGNED: - result = strdup("uint64"); + result = strdup("int64"); break; default: @@ -256,6 +258,16 @@ static char *g_uint_function_get_name(const GUintFunction *item) } + if (result) + { + if (!MDS_IS_SIGNED(item->size)) + result = strprep(result, "u"); + + if (item->endian == SRE_BIG) + result = stradd(result, "be"); + + } + return result; } @@ -278,21 +290,25 @@ static char *g_uint_function_get_name(const GUintFunction *item) * * ******************************************************************************/ -static bool g_uint_function_run_call(GUintFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out) +static bool g_scan_uint_function_run_call(GScanUintFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out) { bool result; /* Bilan à retourner */ unsigned long long offset; /* Position du mot ciblé */ GBinContent *content; /* Contenu à manipuler */ vmpa2t pos; /* Tête de lecture */ - uint8_t val_8; /* Valeur entière sur 8 bits */ - uint16_t val_16; /* Valeur entière sur 16 bits */ - uint32_t val_32; /* Valeur entière sur 32 bits */ - uint64_t val_64; /* Valeur entière sur 64 bits */ - - result = (count == 1 && G_IS_LITERAL_EXPRESSION(args[0])); + uint8_t val_s8; /* Valeur entière sur 8 bits */ + uint8_t val_u8; /* Valeur entière sur 8 bits */ + uint16_t val_s16; /* Valeur entière sur 16 bits */ + uint16_t val_u16; /* Valeur entière sur 16 bits */ + uint32_t val_s32; /* Valeur entière sur 32 bits */ + uint32_t val_u32; /* Valeur entière sur 32 bits */ + uint64_t val_s64; /* Valeur entière sur 64 bits */ + uint64_t val_u64; /* Valeur entière sur 64 bits */ + + result = (count == 1 && G_IS_SCAN_LITERAL_EXPRESSION(args[0])); if (!result) goto exit; - result = g_literal_expression_get_integer_value(G_LITERAL_EXPRESSION(args[0]), &offset); + result = g_scan_literal_expression_get_unsigned_integer_value(G_SCAN_LITERAL_EXPRESSION(args[0]), &offset); if (!result) goto exit; content = g_scan_context_get_content(ctx); @@ -302,29 +318,60 @@ static bool g_uint_function_run_call(GUintFunction *item, GScanExpression **args switch (item->size) { + case MDS_8_BITS_SIGNED: + result = g_binary_content_read_s8(content, &pos, &val_s8); + if (result) + *out = G_OBJECT(g_scan_literal_expression_new(LVT_SIGNED_INTEGER, + (long long []){ val_s8 })); + break; + case MDS_8_BITS_UNSIGNED: - result = g_binary_content_read_u8(content, &pos, &val_8); + result = g_binary_content_read_u8(content, &pos, &val_u8); if (result) - *out = G_OBJECT(g_literal_expression_new(EVT_INTEGER, (unsigned long long []){ val_8 })); + *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, + (unsigned long long []){ val_u8 })); + break; + + case MDS_16_BITS_SIGNED: + result = g_binary_content_read_s16(content, &pos, item->endian, &val_s16); + if (result) + *out = G_OBJECT(g_scan_literal_expression_new(LVT_SIGNED_INTEGER, + (long long []){ val_s16 })); break; case MDS_16_BITS_UNSIGNED: - result = g_binary_content_read_u16(content, &pos, item->endian, &val_16); + result = g_binary_content_read_u16(content, &pos, item->endian, &val_u16); if (result) - *out = G_OBJECT(g_literal_expression_new(EVT_INTEGER, (unsigned long long []){ val_16 })); + *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, + (unsigned long long []){ val_u16 })); + break; + + case MDS_32_BITS_SIGNED: + result = g_binary_content_read_s32(content, &pos, item->endian, &val_s32); + if (result) + *out = G_OBJECT(g_scan_literal_expression_new(LVT_SIGNED_INTEGER, + (long long []){ val_s32 })); break; case MDS_32_BITS_UNSIGNED: - result = g_binary_content_read_u32(content, &pos, item->endian, &val_32); + result = g_binary_content_read_u32(content, &pos, item->endian, &val_u32); if (result) - *out = G_OBJECT(g_literal_expression_new(EVT_INTEGER, (unsigned long long []){ val_32 })); + *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, + (unsigned long long []){ val_u32 })); break; + case MDS_64_BITS_SIGNED: + result = g_binary_content_read_s64(content, &pos, item->endian, &val_s64); + if (result) + *out = G_OBJECT(g_scan_literal_expression_new(LVT_SIGNED_INTEGER, + (long long []){ val_s64 })); + break; case MDS_64_BITS_UNSIGNED: - result = g_binary_content_read_u64(content, &pos, item->endian, &val_64); + result = g_binary_content_read_u64(content, &pos, item->endian, &val_u64); if (result) - *out = G_OBJECT(g_literal_expression_new(EVT_INTEGER, (unsigned long long []){ val_64 })); + *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, + (unsigned long long []){ val_u64 })); break; default: diff --git a/src/analysis/scan/items/uint.h b/src/analysis/scan/items/uint.h index 60f2975..abc2231 100644 --- a/src/analysis/scan/items/uint.h +++ b/src/analysis/scan/items/uint.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * uint.h - prototypes pour la lecture d'un mot à partir de données binaires * - * Copyright (C) 2022 Cyrille Bagard + * Copyright (C) 2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -28,30 +28,31 @@ #include +#include "../item.h" #include "../../../arch/archbase.h" -#define G_TYPE_UINT_FUNCTION g_uint_function_get_type() -#define G_UINT_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_UINT_FUNCTION, GUintFunction)) -#define G_IS_UINT_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_UINT_FUNCTION)) -#define G_UINT_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_UINT_FUNCTION, GUintFunctionClass)) -#define G_IS_UINT_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_UINT_FUNCTION)) -#define G_UINT_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_UINT_FUNCTION, GUintFunctionClass)) +#define G_TYPE_SCAN_UINT_FUNCTION g_scan_uint_function_get_type() +#define G_SCAN_UINT_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_UINT_FUNCTION, GScanUintFunction)) +#define G_IS_SCAN_UINT_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_UINT_FUNCTION)) +#define G_SCAN_UINT_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_UINT_FUNCTION, GScanUintFunctionClass)) +#define G_IS_SCAN_UINT_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_UINT_FUNCTION)) +#define G_SCAN_UINT_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_UINT_FUNCTION, GScanUintFunctionClass)) /* Fonction conduisant à la lecture d'un mot (instance) */ -typedef struct _GUintFunction GUintFunction; +typedef struct _GScanUintFunction GScanUintFunction; /* Fonction conduisant à la lecture d'un mot (classe) */ -typedef struct _GUintFunctionClass GUintFunctionClass; +typedef struct _GScanUintFunctionClass GScanUintFunctionClass; /* Indique le type défini pour une lecture de mot à partir de données binaires. */ -GType g_uint_function_get_type(void); +GType g_scan_uint_function_get_type(void); /* Constitue une fonction de lecture de valeur entière. */ -GUintFunction *g_uint_function_new(MemoryDataSize); +GRegisteredItem *g_scan_uint_function_new(MemoryDataSize, SourceEndian); diff --git a/src/analysis/scan/rule-int.h b/src/analysis/scan/rule-int.h index b43c20b..cc10b08 100644 --- a/src/analysis/scan/rule-int.h +++ b/src/analysis/scan/rule-int.h @@ -38,6 +38,7 @@ struct _GScanRule GObject parent; /* A laisser en premier */ char *name; /* Désignation de la règle */ + fnv64_t name_hash; /* Empreinte de la désignation */ GSearchPattern **data_locals; /* Variables de données */ size_t data_allocated; /* Taille allouée du tableau */ diff --git a/src/analysis/scan/rule.c b/src/analysis/scan/rule.c index bf37585..6ca97ab 100644 --- a/src/analysis/scan/rule.c +++ b/src/analysis/scan/rule.c @@ -91,6 +91,7 @@ static void g_scan_rule_class_init(GScanRuleClass *klass) static void g_scan_rule_init(GScanRule *rule) { rule->name = NULL; + rule->name_hash = 0; rule->data_locals = NULL; rule->data_allocated = 0; @@ -168,6 +169,33 @@ GScanRule *g_scan_rule_new(const char *name) result = g_object_new(G_TYPE_SCAN_RULE, NULL); result->name = strdup(name); + result->name_hash = fnv_64a_hash(name); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à compléter. * +* hash = empreinte précalculée associée au nom. [OUT] * +* * +* Description : Indique le nom associé à une règle de détection. * +* * +* Retour : Désignation humaine associée à la règle. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_scan_rule_get_name(const GScanRule *rule, fnv64_t *hash) +{ + const char *result; /* Désignation à retourner */ + + result = rule->name; + + *hash = rule->name_hash; return result; diff --git a/src/analysis/scan/rule.h b/src/analysis/scan/rule.h index e240da9..12a435c 100644 --- a/src/analysis/scan/rule.h +++ b/src/analysis/scan/rule.h @@ -33,6 +33,7 @@ #include "pattern.h" #include "expr.h" #include "patterns/backend.h" +#include "../../common/fnv1a.h" @@ -57,6 +58,9 @@ GType g_scan_rule_get_type(void); /* Crée une règle de détection statique à l'aide de motifs. */ GScanRule *g_scan_rule_new(const char *); +/* Indique le nom associé à une règle de détection. */ +const char *g_scan_rule_get_name(const GScanRule *, fnv64_t *); + /* Intègre une nouvelle variable locale à une règle. */ void g_scan_rule_add_local_variable(GScanRule *, GSearchPattern *); diff --git a/src/analysis/scan/scanner-int.h b/src/analysis/scan/scanner-int.h index 54b4f62..4fcda87 100644 --- a/src/analysis/scan/scanner-int.h +++ b/src/analysis/scan/scanner-int.h @@ -37,6 +37,8 @@ struct _GContentScanner { GObject parent; /* A laisser en premier */ + char *filename; /* Eventuel fichier d'origine */ + GScanRule **rules; /* Règles de détection */ size_t rule_count; /* Nombre de ces règles */ diff --git a/src/analysis/scan/scanner.c b/src/analysis/scan/scanner.c index d52c0fc..ce8d677 100644 --- a/src/analysis/scan/scanner.c +++ b/src/analysis/scan/scanner.c @@ -25,11 +25,15 @@ #include +#include +#include #include "decl.h" #include "scanner-int.h" #include "../contents/file.h" +#include "../../common/extstr.h" +#include "../../core/logs.h" @@ -45,6 +49,9 @@ static void g_content_scanner_dispose(GContentScanner *); /* Procède à la libération totale de la mémoire. */ static void g_content_scanner_finalize(GContentScanner *); +/* Intègre une nouvelle règle de détection. */ +static bool _g_content_scanner_add_rule(GContentScanner *, GScanRule *); + /* Indique le type défini pour une recherche dans du binaire. */ @@ -89,6 +96,8 @@ static void g_content_scanner_class_init(GContentScannerClass *klass) static void g_content_scanner_init(GContentScanner *scanner) { + scanner->filename = NULL; + scanner->rules = NULL; scanner->rule_count = 0; @@ -137,6 +146,9 @@ static void g_content_scanner_dispose(GContentScanner *scanner) static void g_content_scanner_finalize(GContentScanner *scanner) { + if (scanner->filename != NULL) + free(scanner->filename); + if (scanner->rules != NULL) free(scanner->rules); @@ -250,6 +262,8 @@ bool g_content_scanner_create_from_file(GContentScanner *scanner, const char *fi content = g_file_content_new(filename); if (content == NULL) goto no_content; + scanner->filename = strdup(filename); + size = g_binary_content_compute_size(content); g_binary_content_compute_start_pos(content, &start); @@ -268,25 +282,187 @@ bool g_content_scanner_create_from_file(GContentScanner *scanner, const char *fi /****************************************************************************** * * +* Paramètres : scanner = scanner de contenus à consulter. * +* * +* Description : Indique le chemin d'un éventuel fichier de source. * +* * +* Retour : Chemin d'un éventuel fichier de définitions ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_content_scanner_get_filename(const GContentScanner *scanner) +{ + const char *result; /* Chemin à retourner */ + + result = scanner->filename; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : scanner = gestionnaire de recherche à compléter. * +* path = chemin vers une définition de règles à intégrer. * +* * +* Description : Inclut les définitions d'un fichier de règles externe. * +* * +* Retour : Bilan de l'inclusion à retourner. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_content_scanner_include_resource(GContentScanner *scanner, const char *path) +{ + bool result; /* Bilan à retourner */ + GContentScanner *included; /* Définition à inclure */ + char *tmp; /* Copie de travail */ + char *filename; /* Chemin d'accès reconstruit */ + size_t i; /* Boucle de parcours */ + const char *inc_name; /* Nom de la nouvelle règle */ + + /* Cas le plus simple : un chemin absolu */ + if (path[0] == '/') + included = g_content_scanner_new_from_file(path); + + /* Chemin relatif à l'emplacement de la définition courante ? */ + else if (scanner->filename != NULL) + { + tmp = strdup(scanner->filename); + + filename = strdup(dirname(tmp)); + filename = stradd(filename, G_DIR_SEPARATOR_S); + filename = stradd(filename, path); + + included = g_content_scanner_new_from_file(filename); + + free(filename); + free(tmp); + + } + + else + included = NULL; + + /* Inclusion des règles chargées */ + + result = (included != NULL); + + if (result) + { + for (i = 0; i < included->rule_count && result; i++) + { + result = _g_content_scanner_add_rule(scanner, included->rules[i]); + + if (!result) + { + inc_name = g_scan_rule_get_name(included->rules[i], (fnv64_t []) { 0 }); + + log_variadic_message(LMT_ERROR, "Can not import from '%s': rule '%s' already exists!", + path, inc_name); + + } + + } + + g_object_unref(G_OBJECT(included)); + + } + + return result; + + + +} + + +/****************************************************************************** +* * * Paramètres : scanner = gestionnaire de recherche à compléter. * * rule = règle de détection à intégrer. * * * * Description : Intègre une nouvelle règle de détection. * * * -* Retour : - * +* Retour : Bilan de l'ajout à retourner. * * * * Remarques : - * * * ******************************************************************************/ -void g_content_scanner_add_rule(GContentScanner *scanner, GScanRule *rule) +static bool _g_content_scanner_add_rule(GContentScanner *scanner, GScanRule *rule) { + bool result; /* Bilan à retourner */ + const char *inc_name; /* Nom de la nouvelle règle */ + fnv64_t inc_hash; /* Empreinte de ce nom */ + size_t i; /* Boucle de parcours */ + const char *cur_name; /* Nom d'une règle en place */ + fnv64_t cur_hash; /* Empreinte de ce nom */ + + result = false; + + inc_name = g_scan_rule_get_name(rule, &inc_hash); + + for (i = 0; i < scanner->rule_count; i++) + { + cur_name = g_scan_rule_get_name(scanner->rules[i], &cur_hash); + + if (inc_hash != cur_hash) + continue; + + if (strcmp(inc_name, cur_name) == 0) + goto exit_add; + + } + + result = true; + scanner->rules = realloc(scanner->rules, ++scanner->rule_count * sizeof(GScanRule *)); scanner->rules[scanner->rule_count - 1] = rule; g_object_ref(G_OBJECT(rule)); + exit_add: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : scanner = gestionnaire de recherche à compléter. * +* rule = règle de détection à intégrer. * +* * +* Description : Intègre une nouvelle règle de détection. * +* * +* Retour : Bilan de l'ajout à retourner. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_content_scanner_add_rule(GContentScanner *scanner, GScanRule *rule) +{ + bool result; /* Bilan à retourner */ + const char *inc_name; /* Nom de la nouvelle règle */ + + result = _g_content_scanner_add_rule(scanner, rule); + + if (!result) + { + inc_name = g_scan_rule_get_name(rule, (fnv64_t []) { 0 }); + + log_variadic_message(LMT_ERROR, "Can not add rule: '%s' already exists!", inc_name); + + } + + return result; + } diff --git a/src/analysis/scan/scanner.h b/src/analysis/scan/scanner.h index 8a3919a..f838344 100644 --- a/src/analysis/scan/scanner.h +++ b/src/analysis/scan/scanner.h @@ -59,19 +59,18 @@ GContentScanner *g_content_scanner_new_from_text(const char *); /* Prépare une recherche de motifs dans du contenu binaire. */ GContentScanner *g_content_scanner_new_from_file(const char *); +/* Indique le chemin d'un éventuel fichier de source. */ +const char *g_content_scanner_get_filename(const GContentScanner *); + +/* Inclut les définitions d'un fichier de règles externe. */ +bool g_content_scanner_include_resource(GContentScanner *, const char *); + /* Intègre une nouvelle règle de détection. */ -void g_content_scanner_add_rule(GContentScanner *, GScanRule *); +bool g_content_scanner_add_rule(GContentScanner *, GScanRule *); /* Définit l'expression d'une correspondance recherchée. */ GScanContext *g_content_scanner_analyze(GContentScanner *, GScanOptions *, GBinContent *); - - -/* Lance une analyse d'un élément, fichier ou répertoire. */ -//void g_content_scanner_analyze(GContentScanner *, const char *); - - - #endif /* _ANALYSIS_SCAN_SCANNER_H */ diff --git a/src/analysis/scan/tokens.l b/src/analysis/scan/tokens.l index b541786..f3dbc79 100644 --- a/src/analysis/scan/tokens.l +++ b/src/analysis/scan/tokens.l @@ -82,6 +82,7 @@ %option yylineno %option never-interactive +%x include_path %x rule_intro %x raw_block @@ -105,6 +106,14 @@ +"include" { PUSH_STATE(include_path); return INCLUDE; } + +"\"" { + POP_STATE; + *used = 0; + PUSH_STATE(strlit); + } + "rule" { PUSH_STATE(rule_intro); return RAW_RULE; } [A-Za-z0-9_]+ { @@ -116,8 +125,8 @@ [ \t]* { } "{" { POP_STATE; PUSH_STATE(raw_block); return BRACE_IN; } -"strings" { PUSH_STATE(strings); PUSH_STATE(wait_for_colon); return STRINGS; } -"condition" { PUSH_STATE(condition); PUSH_STATE(wait_for_colon); return CONDITION; } +"strings" { POP_STATE; PUSH_STATE(strings); PUSH_STATE(wait_for_colon); return STRINGS; } +"condition" { POP_STATE; PUSH_STATE(condition); PUSH_STATE(wait_for_colon); return CONDITION; } @@ -127,8 +136,11 @@ "true" { return TRUE_; } "false" { return FALSE_; } -(0|[1-9][0-9]*) { yylval->integer = strtoull(yytext, NULL, 10); return INTEGER; } -0x[0-9a-f]+ { yylval->integer = strtoull(yytext, NULL, 16); return INTEGER; } +-(0|[1-9][0-9]*) { yylval->signed_integer = strtoll(yytext, NULL, 10); return SIGNED_INTEGER; } +-0x[0-9a-f]+ { yylval->signed_integer = strtoll(yytext, NULL, 16); return SIGNED_INTEGER; } + +(0|[1-9][0-9]*) { yylval->unsigned_integer = strtoull(yytext, NULL, 10); return UNSIGNED_INTEGER; } +0x[0-9a-f]+ { yylval->unsigned_integer = strtoull(yytext, NULL, 16); return UNSIGNED_INTEGER; } [kK][bB] { return KB; } [mM][bB] { return MB; } @@ -141,8 +153,6 @@ "\"" { POP_STATE; - EXTEND_BUFFER_IF_NEEDED(1); - (*buf)[(*used)++] = '\0'; yylval->sized_cstring.data = *buf; yylval->sized_cstring.len = *used; return STRING; @@ -195,7 +205,7 @@ "+" { return PLUS; } "-" { return MINUS; } "*" { return MUL; } -"\\" { return DIV; } +"/" { return DIV; } "%" { return MOD; } "(" { return PAREN_O; } @@ -208,6 +218,7 @@ "all" { return ALL; } "of" { return OF; } "them" { return THEM; } +"in" { return IN; } $[A-Za-z0-9_]* { @@ -215,6 +226,21 @@ yylval->sized_cstring.len = yyleng - 1; return IDENTIFIER; } + +$[A-Za-z_][A-Za-z0-9_]* { + yylval->sized_cstring.data = yytext + 1; + yylval->sized_cstring.len = yyleng - 1; + return BYTES_ID; + } + +#[A-Za-z_][A-Za-z0-9_]* { + yylval->sized_cstring.data = yytext + 1; + yylval->sized_cstring.len = yyleng - 1; + return BYTES_ID_COUNTER; + } + + + [A-Za-z_][A-Za-z0-9_]* { yylval->sized_cstring.data = yytext; yylval->sized_cstring.len = yyleng; diff --git a/src/common/szstr.h b/src/common/szstr.h index 54beb9a..d73e489 100644 --- a/src/common/szstr.h +++ b/src/common/szstr.h @@ -29,6 +29,9 @@ #include +#include "sort.h" + + /* Structure associant une chaîne et sa taille */ typedef struct _sized_string_t @@ -66,9 +69,28 @@ typedef struct _sized_string_t } \ } \ while (0) - -#define szstrcmp(ss, rs) \ - strncmp((ss)->data, (rs)/*->data*/, (ss)->len) + +#define szstrcmp(s1, s2) \ + ({ \ + int __ret; \ + size_t __n; \ + __n = (s1)->len < (s2)->len ? (s1)->len : (s2)->len; \ + __ret = strncmp((s1)->data, (s2)->data, __n); \ + if (__ret == 0) \ + __ret = sort_unsigned_long_long((s1)->len, (s2)->len); \ + __ret; \ + }) + +#define szmemcmp(s1, s2) \ + ({ \ + int __ret; \ + size_t __n; \ + __n = (s1)->len < (s2)->len ? (s1)->len : (s2)->len; \ + __ret = memcmp((s1)->data, (s2)->data, __n); \ + if (__ret == 0) \ + __ret = sort_unsigned_long_long((s1)->len, (s2)->len); \ + __ret; \ + }) diff --git a/src/core/core.c b/src/core/core.c index 8d4daa7..26469ff 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -41,6 +41,9 @@ #include "processors.h" #include "queue.h" #include "../analysis/scan/core.h" +#ifdef HAVE_MAGIC_SUPPORT +# include "../analysis/scan/items/magic/cookie.h" +#endif #include "../common/io.h" #include "../common/xdg.h" #include "../glibext/linesegment.h" @@ -102,6 +105,10 @@ bool load_all_core_components(bool cs) explorer = g_content_explorer_new(); set_current_content_explorer(explorer); +#ifdef HAVE_MAGIC_SUPPORT + if (result) result = init_magic_cookie(); +#endif + resolver = g_content_resolver_new(); set_current_content_resolver(resolver); @@ -152,6 +159,10 @@ void unload_all_core_components(bool cs) set_rost_root_namespace(NULL); +#ifdef HAVE_MAGIC_SUPPORT + exit_magic_cookie(); +#endif + set_current_content_resolver(NULL); set_current_content_explorer(NULL); diff --git a/src/glibext/comparison-int.h b/src/glibext/comparison-int.h index efb289a..446f25d 100644 --- a/src/glibext/comparison-int.h +++ b/src/glibext/comparison-int.h @@ -48,7 +48,10 @@ typedef GComparableItemIface GComparableItemInterface; /* Réalise une comparaison riche entre valeurs entière. */ -bool compare_rich_integer_values(unsigned long long, unsigned long long, RichCmpOperation); +bool compare_rich_integer_values_signed(long long, long long, RichCmpOperation); + +/* Réalise une comparaison riche entre valeurs entière. */ +bool compare_rich_integer_values_unsigned(unsigned long long, unsigned long long, RichCmpOperation); diff --git a/src/glibext/comparison.c b/src/glibext/comparison.c index 463f354..8ce6941 100644 --- a/src/glibext/comparison.c +++ b/src/glibext/comparison.c @@ -101,7 +101,63 @@ bool g_comparable_item_compare_rich(const GComparableItem *item, const GComparab * * ******************************************************************************/ -bool compare_rich_integer_values(unsigned long long a, unsigned long long b, RichCmpOperation op) +bool compare_rich_integer_values_signed(long long a, long long b, RichCmpOperation op) +{ + bool result; /* Bilan à retourner */ + + switch (op) + { + case RCO_LT: + result = (a < b); + break; + + case RCO_LE: + result = (a <= b); + break; + + case RCO_EQ: + result = (a == b); + break; + + case RCO_NE: + result = (a != b); + break; + + case RCO_GT: + result = (a > b); + break; + + case RCO_GE: + result = (a >= b); + break; + + default: + assert(false); + result = false; + break; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : a = premier élément à consulter pour une comparaison. * +* b = second objet à consulter pour une comparaison. * +* op = opération de comparaison à réaliser. * +* * +* Description : Réalise une comparaison riche entre valeurs entière. * +* * +* Retour : Bilan des opérations de comparaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool compare_rich_integer_values_unsigned(unsigned long long a, unsigned long long b, RichCmpOperation op) { bool result; /* Bilan à retourner */ diff --git a/src/rost.c b/src/rost.c index 37ca098..40fe587 100644 --- a/src/rost.c +++ b/src/rost.c @@ -275,31 +275,33 @@ int main(int argc, char **argv) set_log_verbosity(verbosity); - /* - if (!load_all_core_components(false)) + if (!load_all_core_components(true)) goto done; - */ /* Traitement des recherches */ scanner = g_content_scanner_new_from_file(rules); - content = g_file_content_new(target); + if (scanner != NULL) + { + content = g_file_content_new(target); + + context = g_content_scanner_analyze(scanner, options, content); - context = g_content_scanner_analyze(scanner, options, content); + g_scan_context_display(context); - g_scan_context_display(context); + g_object_unref(G_OBJECT(context)); + g_object_unref(G_OBJECT(content)); - g_object_unref(G_OBJECT(context)); - g_object_unref(G_OBJECT(content)); + g_object_unref(G_OBJECT(scanner)); - g_object_unref(G_OBJECT(scanner)); + } g_object_unref(G_OBJECT(options)); /* Sortie */ - //unload_all_core_components(false); + unload_all_core_components(false); #ifdef TRACK_GOBJECT_LEAKS remember_gtypes_for_leaks(); diff --git a/tests/analysis/scan/booleans.py b/tests/analysis/scan/booleans.py new file mode 100644 index 0000000..aa3c1a3 --- /dev/null +++ b/tests/analysis/scan/booleans.py @@ -0,0 +1,98 @@ + +from common import RostTestClass + + +class TestRostBooleans(RostTestClass): + """TestCases for booleans and ROST.""" + + def testFinalCondition(self): + """Validate the final condition.""" + + rule = ''' +rule test { + + condition: + false + +} +''' + + self.check_rule_failure(rule) + + + rule = ''' +rule test { + + condition: + true + +} +''' + + self.check_rule_success(rule) + + + def testBasicBooleanOperations(self): + """Evaluate basic boolean operations.""" + + rule = ''' +rule test { + + condition: + true and false + +} +''' + + self.check_rule_failure(rule) + + + rule = ''' +rule test { + + condition: + true or false + +} +''' + + self.check_rule_success(rule) + + + def testImplicitCast(self): + """Imply implicit casts to booleans.""" + + rule = ''' +rule test { + + condition: + true and 0 + +} +''' + + self.check_rule_failure(rule) + + + rule = ''' +rule test { + + condition: + 1 or false + +} +''' + + self.check_rule_success(rule) + + + rule = ''' +rule test { + + condition: + 1 or () + +} +''' + + self.check_rule_success(rule) diff --git a/tests/analysis/scan/common.py b/tests/analysis/scan/common.py new file mode 100644 index 0000000..3b52e38 --- /dev/null +++ b/tests/analysis/scan/common.py @@ -0,0 +1,52 @@ + +from chrysacase import ChrysalideTestCase +from pychrysalide.analysis.contents import MemoryContent +from pychrysalide.analysis.scan import ContentScanner +from pychrysalide.analysis.scan import ScanOptions +from pychrysalide.analysis.scan.patterns.backends import AcismBackend + + +class RostTestClass(ChrysalideTestCase): + """TestCase for analysis.scan.ScanExpression.""" + + @classmethod + def setUpClass(cls): + + super(RostTestClass, cls).setUpClass() + + cls._options = ScanOptions() + cls._options.backend_for_data = AcismBackend + + cls._empty_content = MemoryContent(b'') + + + def _validate_rule_result(self, rule, content, expected): + """Check for scan success or failure.""" + + scanner = ContentScanner(rule) + ctx = scanner.analyze(self._options, content) + + self.assertIsNotNone(ctx) + + if expected: + self.assertTrue(ctx.has_match_for_rule('test')) + else: + self.assertFalse(ctx.has_match_for_rule('test')) + + + def check_rule_success(self, rule, content = None): + """Check for scan success.""" + + if content is None: + content = self._empty_content + + self._validate_rule_result(rule, content, True) + + + def check_rule_failure(self, rule, content = None): + """Check for scan failure.""" + + if content is None: + content = self._empty_content + + self._validate_rule_result(rule, content, False) diff --git a/tests/analysis/scan/examples.py b/tests/analysis/scan/examples.py new file mode 100644 index 0000000..74b5094 --- /dev/null +++ b/tests/analysis/scan/examples.py @@ -0,0 +1,70 @@ + +from common import RostTestClass +from pychrysalide.analysis.contents import MemoryContent + + +class TestRostExamples(RostTestClass): + """TestCases for the examples provides in the ROST documentation.""" + + def testComments(self): + """Ensure comments do not bother rule definitions.""" + + rule = ''' +/* + Multi-line header... +*/ + +rule test { // comment + + /* + * Some context + */ + + condition: /* List of condition(s) */ + true // Dummy condition + +} +''' + + self.check_rule_success(rule) + + + def testArithmeticPrecedence(self): + """Take care of arithmetic operators precedence.""" + + rule = ''' +rule test { // MulFirst + + condition: + 1 + 4 * (3 + 2) == 21 + and + (1 + 4) * (3 + 2) == 25 + +} +''' + + self.check_rule_success(rule) + + + def testUintCast(self): + """Process nested integer values from binary content.""" + + cnt = MemoryContent(b'\x4d\x5a\x00\x00' + b'\x50\x45\x00\x00' + 52 * b'\x00' + b'\x04\x00\x00\x00') + + rule = ''' +rule test { // IsPE + + condition: + + // MZ signature at offset 0 and ... + + uint16(0) == 0x5a4d and + + // ... PE signature at offset stored in the MZ header at offset 0x3c + + uint32(uint32(0x3c)) == 0x00004550 + +} +''' + + self.check_rule_success(rule, cnt) diff --git a/tests/analysis/scan/expr.py b/tests/analysis/scan/expr.py deleted file mode 100644 index dbe8c55..0000000 --- a/tests/analysis/scan/expr.py +++ /dev/null @@ -1,169 +0,0 @@ - - -from chrysacase import ChrysalideTestCase -from pychrysalide.analysis.scan import ScanExpression -from pychrysalide.glibext import ComparableItem - - -class TestScanExpression(ChrysalideTestCase): - """TestCase for analysis.scan.ScanExpression.""" - - - def testDirectInstances(self): - """Reject direct instances.""" - - with self.assertRaisesRegex(RuntimeError, 'pychrysalide.analysis.scan.ScanExpression is an abstract class'): - - e = ScanExpression() - - - def testBooleanComparison(self): - """Compare custom scan expressions.""" - - class StrLenExpr(ScanExpression): - - def __init__(self, value): - super().__init__(ScanExpression.ExprValueType.STRING) - self._value = value - - def _cmp_rich(self, other, op): - - if op == ComparableItem.RichCmpOperation.EQ: - return len(self._value) == len(other._value) - - - e0 = StrLenExpr('00000000000') - - e1 = StrLenExpr('00000000000') - - e2 = StrLenExpr('000000000000000000000000000') - - self.assertTrue(e0 == e1) - - # !? - # Python teste e0 != e1 (non implémenté), puis e1 != e0 (pareil) et en déduit une différence ! - # self.assertFalse(e0 != e1) - - self.assertFalse(e0 == e2) - - # TypeError: '<' not supported between instances of 'StrLenExpr' and 'StrLenExpr' - with self.assertRaisesRegex(TypeError, '\'<\' not supported between instances'): - self.assertTrue(e0 < e1) - - - - - - - # def testTypeSubclassing(self): - # """Verify the data type subclassing is working.""" - - # class MyType(DataType): - - # def __init__(self, num): - # super(MyType, self).__init__() - # self._num = num - - # def _to_string(self, include): - # return '%x' % self._num - - # def _dup(self): - # return MyType(self._num) - - # tp = MyType(0x123) - - # self.assertEqual(str(tp), '123') - - # tp2 = tp.dup() - - # self.assertEqual(str(tp), str(tp2)) - - - # def testTypeDefaultProperties(self): - # """Check for default values of some type properties.""" - - # class MyPropType(DataType): - # pass - - # tp = MyPropType() - - # self.assertTrue(tp.handle_namespaces) - - # self.assertFalse(tp.is_pointer) - - # self.assertFalse(tp.is_reference) - - # class MyPropType2(DataType): - - # def _handle_namespaces(self): - # return True - - # def _is_pointer(self): - # return 123 < 1234 - - # def _is_reference(self): - # return False - - # tp2 = MyPropType2() - - # self.assertTrue(tp.handle_namespaces) - - # self.assertTrue(tp2.is_pointer) - - # self.assertFalse(tp2.is_reference) - - - # def testTypeNamespaces(self): - # """Test the type namespace property.""" - - # class MyNSType(DataType): - - # def __init__(self, name): - # super(MyNSType, self).__init__() - # self._name = name - - # def _to_string(self, include): - # return self._name - - # tp = MyNSType('TP') - # ns = MyNSType('NS') - - # self.assertIsNone(tp.namespace) - - # tp.namespace = (ns, '.') - - # self.assertEqual(str(tp), 'NS.TP') - - # self.assertEqual(tp.namespace, (ns, '.')) - - - # def testTypeHash(self): - # """Hash a user-defined type.""" - - # class MyUserType(DataType): - - # def __init__(self, name): - # super(MyUserType, self).__init__() - # self._name = name - - # def _hash(self): - # return hash(self._name) - - # tp = MyUserType('random') - - # self.assertEqual(tp.hash, hash('random') & ((1 << 32) - 1)) - - # class MyOutOfRangeUserType(DataType): - - # hard_coded_hash = -8752470794866657507 - - # def __init__(self, name): - # super(MyOutOfRangeUserType, self).__init__() - # self._name = name - - # def _hash(self): - # return self.hard_coded_hash - - # tp = MyOutOfRangeUserType('out-of-range') - - # self.assertEqual(tp.hash, MyOutOfRangeUserType.hard_coded_hash & ((1 << 32) - 1)) diff --git a/tests/analysis/scan/exprs.py b/tests/analysis/scan/exprs.py deleted file mode 100644 index c89dc59..0000000 --- a/tests/analysis/scan/exprs.py +++ /dev/null @@ -1,122 +0,0 @@ - -from chrysacase import ChrysalideTestCase -from pychrysalide.analysis.contents import MemoryContent -from pychrysalide.analysis.scan import ContentScanner -from pychrysalide.analysis.scan import ScanOptions -from pychrysalide.analysis.scan.patterns.backends import AcismBackend - - -class TestScanExpressions(ChrysalideTestCase): - """TestCase for analysis.scan.exprs.*.""" - - @classmethod - def setUpClass(cls): - - super(TestScanExpressions, cls).setUpClass() - - cls._options = ScanOptions() - cls._options.backend_for_data = AcismBackend - - - def testBasicStringOperations(self): - """Evaluate basic string operations.""" - - cnt = MemoryContent(b'empty') - - rule = ''' -rule test { - - condition: - "123abc456" contains "abc" - -} -''' - - scanner = ContentScanner(rule) - ctx = scanner.analyze(self._options, cnt) - - self.assertTrue(ctx.has_match_for_rule('test')) - - rule = ''' -rule test { - - condition: - "123\t456" contains "\t" - -} -''' - - scanner = ContentScanner(rule) - ctx = scanner.analyze(self._options, cnt) - - self.assertTrue(ctx.has_match_for_rule('test')) - - rule = ''' -rule test { - - condition: - "123-456" startswith "1" - -} -''' - - scanner = ContentScanner(rule) - ctx = scanner.analyze(self._options, cnt) - - self.assertTrue(ctx.has_match_for_rule('test')) - - rule = ''' -rule test { - - condition: - "123-456" startswith "1234" - -} -''' - - scanner = ContentScanner(rule) - ctx = scanner.analyze(self._options, cnt) - - self.assertFalse(ctx.has_match_for_rule('test')) - - rule = ''' -rule test { - - condition: - "123-456" endswith "6" - -} -''' - - scanner = ContentScanner(rule) - ctx = scanner.analyze(self._options, cnt) - - self.assertTrue(ctx.has_match_for_rule('test')) - - rule = ''' -rule test { - - condition: - "123-456" endswith "3456" - -} -''' - - scanner = ContentScanner(rule) - ctx = scanner.analyze(self._options, cnt) - - self.assertFalse(ctx.has_match_for_rule('test')) - - rule = ''' -rule test { - - condition: - "ABCD" iequals "AbCd" - -} -''' - - scanner = ContentScanner(rule) - ctx = scanner.analyze(self._options, cnt) - - self.assertTrue(ctx.has_match_for_rule('test')) diff --git a/tests/analysis/scan/func.py b/tests/analysis/scan/func.py deleted file mode 100644 index bd7d0ce..0000000 --- a/tests/analysis/scan/func.py +++ /dev/null @@ -1,16 +0,0 @@ - - -from chrysacase import ChrysalideTestCase -from pychrysalide.analysis.scan import ScanFunction - - -class TestScanFunction(ChrysalideTestCase): - """TestCase for analysis.scan.ScanFunction.""" - - - def testDirectInstances(self): - """Reject direct instances.""" - - with self.assertRaisesRegex(RuntimeError, 'pychrysalide.analysis.scan.ScanFunction is an abstract class'): - - f = ScanFunction('name') diff --git a/tests/analysis/scan/functions.py b/tests/analysis/scan/functions.py new file mode 100644 index 0000000..8553018 --- /dev/null +++ b/tests/analysis/scan/functions.py @@ -0,0 +1,104 @@ + +from common import RostTestClass +from pychrysalide.analysis.contents import MemoryContent + + +class TestRostFunctions(RostTestClass): + """TestCases for the core functions of ROST.""" + + # Core + # ==== + + def testDatasize(self): + """Handle the size of the provided data.""" + + cnt = MemoryContent(b'\x01\x02\x03\x04') + + cases = [ + 'datasize == 4', + 'uint16(0) == 0x201 and uint16(datasize - 2) == 0x0403', + ] + + for c in cases: + + rule = ''' +rule test { + + condition: + %s + +} +''' % c + + self.check_rule_success(rule, cnt) + + + # Modules + # ======= + + def testConsole(self): + """Ensure logging always returns true.""" + + rule = ''' +rule test { + + condition: + console.log() + +} +''' + + self.check_rule_success(rule) + + + def testMagic(self): + """Scan text content with the Magic module.""" + + cnt = MemoryContent(b'aaaa') + + cases = [ + [ 'type', 'ASCII text, with no line terminators' ], + [ 'mime_encoding', 'us-ascii' ], + [ 'mime_type', 'text/plain' ], + ] + + for target, expected in cases: + + rule = ''' +rule test { + + condition: + magic.%s() == "%s" + +} +''' % (target, expected) + + self.check_rule_success(rule, cnt) + + + def testTime(self): + """Check current time.""" + + # Cf. https://www.epochconverter.com/ + + rule = ''' +rule test { + + condition: + time.make(2023, 8, 5, 22, 8, 41) == 0x64cec869 + +} +''' + + self.check_rule_success(rule) + + rule = ''' +rule test { + + condition: + time.now() >= 0x64cec874 and time.now() <= time.now() + +} +''' + + self.check_rule_success(rule) diff --git a/tests/analysis/scan/grammar.py b/tests/analysis/scan/grammar.py index 5a2e1d5..8b18f81 100644 --- a/tests/analysis/scan/grammar.py +++ b/tests/analysis/scan/grammar.py @@ -1,286 +1,191 @@ -from chrysacase import ChrysalideTestCase -from pychrysalide.analysis.contents import MemoryContent -from pychrysalide.analysis.scan import ContentScanner -from pychrysalide.analysis.scan import ScanOptions -from pychrysalide.analysis.scan.patterns.backends import AcismBackend +from common import RostTestClass -class TestRostGrammar(ChrysalideTestCase): - """TestCase for analysis.scan.ScanExpression.""" +class TestRostGrammar(RostTestClass): + """TestCases for the ROST grammar.""" - @classmethod - def setUpClass(cls): + def testRelationalExpressions(self): + """Build expressions with relational comparisons.""" - super(TestRostGrammar, cls).setUpClass() + cases = [ - cls._options = ScanOptions() - cls._options.backend_for_data = AcismBackend + # Regular + [ '-1', '<=', '2', True ], + [ '-1', '<=', '2', True ], + [ '"aaa"', '==', '"aaa"', True ], + [ '"aaa"', '<', '"aaaa"', True ], + [ '""', '<', '"aaaa"', True ], + # Cast + [ 'false', '==', '0', True ], + [ 'false', '==', '1', False ], + [ 'true', '!=', '0', True ], + [ '1', '==', 'true', True ], + [ 'false', '==', '()', True ], + [ 'true', '==', '(0,)', True ], - def testComments(self): - """Ensure comments do not bother rule definitions.""" + ] - cnt = MemoryContent(b'no_real_content') + for op1, kwd, op2, expected in cases: - rule = ''' -/* - Multi-line header... -*/ - -rule test { // comment - - /* - * Some context - */ - - condition: /* List of condition(s) */ - true // Dummy condition - -} -''' - - scanner = ContentScanner(rule) - ctx = scanner.analyze(self._options, cnt) - - self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) - - - def testUintCast(self): - """Process nested integer values from binary content.""" - - cnt = MemoryContent(b'\x4d\x5a\x00\x00' + b'\x50\x45\x00\x00' + 52 * b'\x00' + b'\x04\x00\x00\x00') - - rule = ''' -rule IsPE { - - condition: - - // MZ signature at offset 0 and ... - - uint16(0) == 0x5a4d and - - // ... PE signature at offset stored in the MZ header at offset 0x3c - - uint32(uint32(0x3c)) == 0x00004550 - -} -''' - - scanner = ContentScanner(rule) - ctx = scanner.analyze(self._options, cnt) - - self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('IsPE')) - - - def testBasicBooleanConditions(self): - """Evaluate basic boolean conditions.""" - - cnt = MemoryContent(b'0123') - - rule = ''' -rule test { - - condition: - true and false - -} -''' - - scanner = ContentScanner(rule) - - ctx = scanner.analyze(self._options, cnt) - - self.assertTrue(not(ctx is None)) - self.assertFalse(ctx.has_match_for_rule('test')) - - rule = ''' + rule = ''' rule test { condition: - true or false + %s %s %s } -''' +''' % (op1, kwd, op2) - scanner = ContentScanner(rule) + if expected: + self.check_rule_success(rule) + else: + self.check_rule_failure(rule) - ctx = scanner.analyze(self._options, cnt) - self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) + def testLogicalOperations(self): + """Evaluate some logical operations.""" + cases = [ + [ 'true and false', False ], + [ 'false or false', False ], + [ 'true and true or false', True ], + [ 'false or true and false', False ], + [ '1 or false', True ], + ] - def testArithmeticOpeations(self): - """Compute some arithmetic operations.""" + for cond, expected in cases: - cnt = MemoryContent(b'0123') - - rule = ''' + rule = ''' rule test { condition: - 1 + 4 * 3 + 2 == 15 + %s } -''' - - scanner = ContentScanner(rule) - - ctx = scanner.analyze(self._options, cnt) +''' % (cond) - self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) + if expected: + self.check_rule_success(rule) + else: + self.check_rule_failure(rule) - rule = ''' -rule test { + def testArithmeticOperations(self): + """Evaluate some arithmetic operations.""" - condition: - (1 + 4) * 3 + 2 == 17 + cases = [ -} -''' + # Clever + '1 + 2 == 3', + '10 + -3 == 7', + '-3 + 10 == 7', + '-10 - 1 < 0', + '-10 - 1 == -11', + '(-10 - 1) == -11', + '(-1 - -10) == 9', + '-2 * -3 == 6', + '-2 * 3 == -6', - scanner = ContentScanner(rule) + # Legacy + '1 + 4 * 3 + 2 == 15', + '(1 + 4) * 3 + 2 == 17', + '1 + 4 * (3 + 2) == 21', + '(1 + 4) * (3 + 2) == 25', - ctx = scanner.analyze(self._options, cnt) + ] - self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) + for c in cases: - - rule = ''' + rule = ''' rule test { condition: - 1 + 4 * (3 + 2) == 21 + %s } -''' +''' % (c) - scanner = ContentScanner(rule) + self.check_rule_success(rule) - ctx = scanner.analyze(self._options, cnt) - self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) + def testBasicStringsOperations(self): + """Build expressions with basic strings operations.""" + cases = [ - rule = ''' -rule test { + # Clever + [ '123---456', 'contains', '---', True ], + [ '123---456', 'contains', 'xxx', False ], + [ '---123---456', 'startswith', '---', True ], + [ '---123---456', 'startswith', 'xxx', False ], + [ '123---456---', 'endswith', '---', True ], + [ '123---456---', 'endswith', 'xxx', False ], + [ 'AAA---BBB', 'icontains', 'aaa', True ], + [ 'AAA---BBB', 'icontains', 'xxx', False ], + [ 'AAA---BBB', 'istartswith', 'aAa', True ], + [ 'AAA---BBB', 'istartswith', 'xxx', False ], + [ 'AAA---BBB', 'iendswith', 'bBb', True ], + [ 'AAA---BBB', 'iendswith', 'xxx', False ], + [ 'AzertY', 'iequals', 'AZERTY', True ], + [ 'AzertY', 'iequals', 'AZERTY-', False ], - condition: - (1 + 4) * (3 + 2) == 25 - -} -''' + # Legacy + [ '123\t456', 'contains', '\t', True ], + [ '123-456', 'startswith', '1', True ], + [ '123-456', 'startswith', '1234', False ], + [ '123-456', 'endswith', '6', True ], + [ '123-456', 'endswith', '3456', False ], - scanner = ContentScanner(rule) + ] - ctx = scanner.analyze(self._options, cnt) + for op1, kwd, op2, expected in cases: - self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) - - - def testSizeUnits(self): - """Evaluate size units.""" - - cnt = MemoryContent(b'0123') - - - rule = ''' -rule test { - - condition: - 1KB == 1024 - -} -''' - - scanner = ContentScanner(rule) - - ctx = scanner.analyze(self._options, cnt) - - self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) - - - rule = ''' + rule = ''' rule test { condition: - 2MB == 2 * 1024 * 1024 + "%s" %s "%s" } -''' +''' % (op1, kwd, op2) - scanner = ContentScanner(rule) + if expected: + self.check_rule_success(rule) + else: + self.check_rule_failure(rule) - ctx = scanner.analyze(self._options, cnt) - - self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) - - - rule = ''' -rule test { - - condition: - 4Kb == (4 * 1024) - -} -''' - - scanner = ContentScanner(rule) - - ctx = scanner.analyze(self._options, cnt) - - self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) - - - rule = ''' -rule test { - - condition: - 1KB <= 1024 and 1024 < 1MB - -} -''' - - scanner = ContentScanner(rule) - - ctx = scanner.analyze(self._options, cnt) - - self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) + def testSizeUnits(self): + """Evaluate size units.""" - def testNamespace(self): - """Resolve main functions with the root scan namesapce.""" + cases = [ + '1KB == 1024', + '2MB == 2 * 1024 * 1024', + '4Kb == (4 * 1024)', + '1KB <= 1024 and 1024 < 1MB', + ] - cnt = MemoryContent(b'\x01\x02\x03\x04') + for c in cases: - rule = ''' + rule = ''' rule test { condition: - datasize == 4 + %s } -''' +''' % (c) - scanner = ContentScanner(rule) + self.check_rule_success(rule) - ctx = scanner.analyze(self._options, cnt) - self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) - rule = ''' -rule test { - condition: - uint16(0) == 0x201 and uint16(datasize - 2) == 0x0403 -} -''' +# TODO : test matches - scanner = ContentScanner(rule) - ctx = scanner.analyze(self._options, cnt) - self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) diff --git a/tests/analysis/scan/matches.py b/tests/analysis/scan/matches.py new file mode 100644 index 0000000..0d7556e --- /dev/null +++ b/tests/analysis/scan/matches.py @@ -0,0 +1,27 @@ + +from common import RostTestClass +from pychrysalide.analysis.contents import MemoryContent + + +class TestRostMatchs(RostTestClass): + """TestCases for the ROST pattern matching engine.""" + + def testCountMatches(self): + """Count matches patterns.""" + + cnt = MemoryContent(b'aaa aaa bbb aaa') + + rule = ''' +rule test { + + strings: + $a = "aaa" + $b = "bbb" + + condition: + #a == 3 and #b < 2 + +} +''' + + self.check_rule_success(rule, cnt) diff --git a/tests/analysis/scan/options.py b/tests/analysis/scan/options.py deleted file mode 100644 index 7617b3a..0000000 --- a/tests/analysis/scan/options.py +++ /dev/null @@ -1,16 +0,0 @@ - - -from chrysacase import ChrysalideTestCase -from gi._constants import TYPE_INVALID -from pychrysalide.analysis.scan import ScanOptions - - -class TestScanOptions(ChrysalideTestCase): - """TestCase for analysis.scan.ScanOptions.""" - - def testEmptyOptions(self): - """Check default scan options.""" - - ops = ScanOptions() - - self.assertEqual(ops.backend_for_data, TYPE_INVALID) diff --git a/tests/analysis/scan/pyapi.py b/tests/analysis/scan/pyapi.py new file mode 100644 index 0000000..1bba44e --- /dev/null +++ b/tests/analysis/scan/pyapi.py @@ -0,0 +1,58 @@ + +from chrysacase import ChrysalideTestCase +from gi._constants import TYPE_INVALID +from pychrysalide.analysis.scan import ScanExpression +from pychrysalide.analysis.scan import ScanOptions +from pychrysalide.glibext import ComparableItem + + +class TestRostPythonAPI(ChrysalideTestCase): + """TestCase for the ROST Python API.""" + + def testEmptyOptions(self): + """Check default scan options.""" + + ops = ScanOptions() + + self.assertEqual(ops.backend_for_data, TYPE_INVALID) + + + def testDirectInstancesOfExpression(self): + """Reject direct instances of ROST expressions.""" + + with self.assertRaisesRegex(RuntimeError, 'pychrysalide.analysis.scan.ScanExpression is an abstract class'): + + e = ScanExpression() + + def testBooleanComparison(self): + """Compare custom scan expressions.""" + + class StrLenExpr(ScanExpression): + + def __init__(self, value): + super().__init__(ScanExpression.ExprValueType.STRING) + self._value = value + + def _cmp_rich(self, other, op): + + if op == ComparableItem.RichCmpOperation.EQ: + return len(self._value) == len(other._value) + + + e0 = StrLenExpr('00000000000') + + e1 = StrLenExpr('00000000000') + + e2 = StrLenExpr('000000000000000000000000000') + + self.assertTrue(e0 == e1) + + # !? + # Python teste e0 != e1 (non implémenté), puis e1 != e0 (pareil) et en déduit une différence ! + # self.assertFalse(e0 != e1) + + self.assertFalse(e0 == e2) + + # TypeError: '<' not supported between instances of 'StrLenExpr' and 'StrLenExpr' + with self.assertRaisesRegex(TypeError, '\'<\' not supported between instances'): + self.assertTrue(e0 < e1) diff --git a/tests/analysis/scan/sets.py b/tests/analysis/scan/sets.py new file mode 100644 index 0000000..1d10fbf --- /dev/null +++ b/tests/analysis/scan/sets.py @@ -0,0 +1,118 @@ + +from common import RostTestClass + + +class TestRostSets(RostTestClass): + """TestCases for sets support in ROST.""" + + def testSetsAsBooleans(self): + """Convert sets to boolean.""" + + rule = ''' +rule test { + + condition: + () + +} +''' + + self.check_rule_failure(rule) + + + rule = ''' +rule test { + + condition: + (1, ) + +} +''' + + self.check_rule_success(rule) + + + rule = ''' +rule test { + + condition: + ("aaa", true, 123) + +} +''' + + self.check_rule_success(rule) + + + def testStringAsArray(self): + """Handle strings as arrays.""" + + rule = ''' +rule test { + + condition: + count("aaa") + +} +''' + + self.check_rule_success(rule) + + + rule = ''' +rule test { + + condition: + count("aaa") == 3 + +} +''' + + self.check_rule_success(rule) + + + def testSetsIntersections(self): + """Perform sets intersections.""" + + rule = ''' +rule test { + + condition: + ("aaa", "bbb") in ("AAA", "BBB", "aaa") + +} +''' + + self.check_rule_success(rule) + + + rule = ''' +rule test { + + condition: + ("aaa", "bbb") in ("123", ) + +} +''' + + self.check_rule_failure(rule) + + + + + + + + + + + + + + # TODO : + + # test : intersection(a, a) == a + + # test : "123" in "0123456789" + # test : "123" in "012987" + -- cgit v0.11.2-87-g4458