summaryrefslogtreecommitdiff
path: root/src/analysis/scan/patterns/tokens/nodes/any.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/analysis/scan/patterns/tokens/nodes/any.c')
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/any.c765
1 files changed, 765 insertions, 0 deletions
diff --git a/src/analysis/scan/patterns/tokens/nodes/any.c b/src/analysis/scan/patterns/tokens/nodes/any.c
new file mode 100644
index 0000000..4334fff
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/any.c
@@ -0,0 +1,765 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * any.c - suite d'octets quelconques
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "any.h"
+
+
+#include <assert.h>
+
+
+#include "any-int.h"
+
+
+
+/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
+
+
+/* Initialise la classe des séries d'octets quelconques. */
+static void g_scan_token_node_any_class_init(GScanTokenNodeAnyClass *);
+
+/* Initialise une instance de série d'octets quelconques. */
+static void g_scan_token_node_any_init(GScanTokenNodeAny *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_node_any_dispose(GScanTokenNodeAny *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_node_any_finalize(GScanTokenNodeAny *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Inscrit la définition d'un motif dans un moteur de recherche. */
+static bool g_scan_token_node_any_enroll(GScanTokenNodeAny *, GEngineBackend *, size_t, size_t *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_any_check_backward(const GScanTokenNodeAny *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DECOMPOSITION DE MOTIF RECHERCHE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une série d'octets quelconque, vide ou non. */
+G_DEFINE_TYPE(GScanTokenNodeAny, g_scan_token_node_any, G_TYPE_SCAN_TOKEN_NODE);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des séries d'octets quelconques. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_any_class_init(GScanTokenNodeAnyClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanTokenNodeClass *node; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_any_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_token_node_any_finalize;
+
+ node = G_SCAN_TOKEN_NODE_CLASS(klass);
+
+ node->apply = (apply_scan_token_node_flags_fc)NULL;
+ node->visit = (visit_scan_token_node_fc)NULL;
+ node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_any_enroll;
+ node->check_forward = (check_scan_token_node_fc)g_scan_token_node_any_check_forward;
+ node->check_backward = (check_scan_token_node_fc)g_scan_token_node_any_check_backward;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : any = instance à initialiser. *
+* *
+* Description : Initialise une instance de série d'octets quelconques. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_any_init(GScanTokenNodeAny *any)
+{
+ any->min = 0;
+ any->has_max = false;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : any = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_any_dispose(GScanTokenNodeAny *any)
+{
+ G_OBJECT_CLASS(g_scan_token_node_any_parent_class)->dispose(G_OBJECT(any));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : any = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_any_finalize(GScanTokenNodeAny *any)
+{
+ G_OBJECT_CLASS(g_scan_token_node_any_parent_class)->finalize(G_OBJECT(any));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : min = éventuelle quantité minimale à retrouver. *
+* max = éventuelle quantité maximale à retrouver. *
+* *
+* Description : Construit un noeud pointant une série d'octets quelconques. *
+* *
+* Retour : Mécanismes mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenNode *g_scan_token_node_any_new(const phys_t *min, const phys_t *max)
+{
+ GScanTokenNode *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_ANY, NULL);
+
+ if (!g_scan_token_node_any_create(G_SCAN_TOKEN_NODE_ANY(result), min, max))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : any = séquence d'octets quelconques à initialiser pleinement.*
+* min = éventuelle quantité minimale à retrouver. *
+* max = éventuelle quantité maximale à retrouver. *
+* *
+* Description : Met en place un noeud pointant une série d'octets. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_node_any_create(GScanTokenNodeAny *any, const phys_t *min, const phys_t *max)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ if (min != NULL)
+ any->min = *min;
+ else
+ any->min = 0;
+
+ if (max != NULL)
+ {
+ any->max = *max;
+
+ result = (any->min <= any->max);
+
+ if (result && any->min == any->max)
+ result = (any->min > 0);
+
+ }
+
+ any->has_max = (max != NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : any = séquence d'octets quelconques à étendre. *
+* extra = étendue supplémentaire à intégrer. *
+* *
+* Description : Etend un noeud pointant une série d'octets. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_any_merge(GScanTokenNodeAny *any, GScanTokenNodeAny *extra)
+{
+ any->min += extra->min;
+
+ if (any->has_max && extra->has_max)
+ any->max += extra->max;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à enregistrer. *
+* backend = moteur de recherche à préchauffer. *
+* maxsize = taille max. des atomes (mise en commun optimisée). *
+* slow = niveau de ralentissement induit (0 = idéal). [OUT] *
+* *
+* Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_token_node_any_enroll(GScanTokenNodeAny *node, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+ bool result; /* Statut à retourner */
+ bool forced; /* Inclusion dans un scan ? */
+
+ result = true;
+
+ forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
+
+ if (forced)
+ *slow += (maxsize * 4);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* cflags = altérations de traitement à respecter. *
+* skip = détermine si l'analyse est différée. [OUT] *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
+{
+ ScanTokenNodeFlags flags; /* Particularités du noeud */
+ bool forced; /* Inclusion dans un scan ? */
+ phys_t size; /* Quantité d'octets considérés*/
+ phys_t match_size; /* Taille de correspondance */
+ phys_t i; /* Boucle de parcours #1 */
+ match_area_t *space; /* Nouvelle zone à intégrer */
+ match_area_t *area; /* Correspondance à valider */
+ match_area_t *next; /* Correspondance suivante */
+ phys_t after; /* Espace disposible après */
+ phys_t min_end; /* Fin la plus proche possible */
+ phys_t max_end; /* Fin la plus éloignée trouvée*/
+ bool updated; /* Existence de correspondance */
+ size_t rcount; /* Quantité de bornes présentes*/
+ const node_offset_range_t *ranges; /* Bornes d'espace à parcourir */
+ size_t r; /* Boucle de parcours #2 */
+ phys_t updated_edge; /* Nouvelle bordure de motif */
+ match_area_t *new_area; /* Copie de correspondance */
+
+ if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
+
+ if (*skip)
+ return;
+
+ flags = g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node));
+
+ forced = (flags & STNF_MAIN);
+
+ assert((!params->initialized && forced) || (params->initialized & !forced));
+
+ /**
+ * La situation forcée correspond au cas particulier d'une définition
+ * complètement abstraite : ??, ?? ??, etc.
+ */
+ if (forced)
+ {
+ size = params->content_end - params->content_start;
+
+ if (node->has_max && 0 /* greedy ? */)
+ {
+ match_size = node->max;
+
+ if (match_size > size)
+ match_size = node->min;
+
+ }
+ else
+ match_size = node->min;
+
+ /**
+ * Si le contenu binaire est trop petit pour contenir au moins un enregistrement,
+ * aucune correspondance n'est enregistrée. Comme le noeud est le principale, ie.
+ * seul et unique, l'analyse s'arrête ensuite d'elle même.
+ *
+ * Si le contenu binaire est suffisamment large, des espaces sont créés et l'analyse
+ * se termine ensuite. La conservation des espaces n'est donc pas utile, ni réalisée.
+ */
+
+ if (match_size <= size)
+ {
+ size -= (match_size - 1);
+
+ assert(cflags & TNCF_UPDATE_IN_PLACE);
+
+ for (i = 0; i < size; i++)
+ {
+ space = g_umem_slice_alloc(params->allocator);
+
+ space->start = params->content_start + i;
+ space->end = space->start + match_size;
+
+ add_tail_match_area(space, &params->main_areas);
+
+ }
+
+ params->main_count += size;
+
+ }
+
+ }
+
+ /**
+ * Situation usuelle : des espaces séparent deux noeuds.
+ */
+ else
+ {
+ assert(params->initialized);
+
+ /**
+ * Les espaces existants sont à compléter. La présence de tels espaces
+ * restant à traiter peut provenir d'un aiguillage imposé par un motif
+ * tel que :
+ *
+ * ( aa ?? ?? | bb cc dd ) [0-5] ee ee
+ *
+ * Deux espaces sont à considérer avant de rechercher des octets ee :
+ * [2-7] et [0-5].
+ *
+ * Note : ces espaces peuvent être disjoints.
+ *
+ * Si aucun espace n'est en place, un est créé.
+ */
+
+ extend_node_search_offset(&params->offset, node->min, node->max, node->has_max);
+
+ /**
+ * Si un décalage enregistré ne peut être consommé par un noeud, les
+ * résultats sont étendus ici à minima ou maxima.
+ */
+
+ if (flags & STNF_LAST)
+ {
+ assert(offsets_exist(&params->offset));
+
+ if (0x0) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count);
+
+ for_each_match_area_safe(area, &params->main_areas, next)
+ {
+ assert(area->end <= params->content_end);
+
+ after = params->content_end - area->end;
+
+ if (0x0) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end);
+
+ min_end = params->content_end;
+ max_end = params->content_start;
+
+ updated = false;
+
+ ranges = get_node_search_offset_ranges_2(&params->offset, &rcount);
+
+ for (r = 0; r < rcount; r++)
+ {
+ if (ranges[r].min > after)
+ continue;
+
+ updated_edge = area->end + ranges[r].min;
+
+ if (updated_edge < min_end)
+ min_end = updated_edge;
+
+ if (ranges[r].has_max)
+ {
+ if (ranges[r].max > after)
+ updated_edge = params->content_end;
+ else
+ updated_edge = area->end + ranges[r].max;
+
+ if (updated_edge > max_end)
+ max_end = updated_edge;
+
+ }
+
+ updated = true;
+
+ }
+
+ if (updated)
+ {
+ /**
+ * Si seuls les rejets sont d'intérêt, les correspondances établies
+ * ne se voient pas mises à jours ni retirées.
+ */
+
+ if ((cflags & TNCF_KEEP_DISCARDED) == 0)
+ {
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ area->end = (1 /* greedy */ ? min_end : max_end);
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ new_area = g_umem_slice_alloc(params->allocator);
+
+ *new_area = *area;
+
+ new_area->end = (1 /* greedy */ ? min_end : max_end);
+
+ add_tail_match_area(new_area, &params->created_areas);
+ params->created_count++;
+
+ }
+
+#ifndef NDEBUG
+ else
+ assert(false);
+#endif
+
+ }
+
+ }
+
+ else
+ {
+ /**
+ * Si la liste principale doit être mise à jour...
+ */
+
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ {
+ del_match_area(area, &params->main_areas);
+ assert(params->main_count > 0);
+ params->main_count--;
+ }
+
+ /**
+ * Au cas où le rejet est d'intérêt, l'absence de correspondance
+ * est conservée dans une liste dédiée.
+ */
+
+ if (cflags & TNCF_KEEP_DISCARDED)
+ {
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ {
+ add_tail_match_area(area, &params->kept_areas);
+ params->kept_count++;
+ }
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ new_area = g_umem_slice_alloc(params->allocator);
+
+ *new_area = *area;
+
+ new_area->end = (1 /* greedy */ ? min_end : max_end);
+
+ add_tail_match_area(new_area, &params->kept_areas);
+ params->kept_count++;
+
+ }
+
+#ifndef NDEBUG
+ else
+ assert(false);
+#endif
+
+ }
+
+ }
+
+ }
+
+ disable_all_ranges_in_node_search_offset(&params->offset);
+
+ }
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* params = accès direct aux éléments utiles aux validations. *
+* cflags = altérations de traitement à respecter. *
+* skip = détermine si l'analyse est différée. [OUT] *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_any_check_backward(const GScanTokenNodeAny *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
+{
+ ScanTokenNodeFlags flags; /* Particularités du noeud */
+#ifndef NDEBUG
+ bool forced; /* Inclusion dans un scan ? */
+#endif
+ match_area_t *area; /* Correspondance à valider */
+ match_area_t *next; /* Correspondance suivante */
+ phys_t before; /* Espace disposible avant */
+ phys_t min_start; /* Début le plus proche trouvé */
+ phys_t max_start; /* Début le plus distant trouvé*/
+ bool updated; /* Existence de correspondance */
+ size_t rcount; /* Quantité de bornes présentes*/
+ const node_offset_range_t *ranges; /* Bornes d'espace à parcourir */
+ size_t r; /* Boucle de parcours */
+ phys_t updated_edge; /* Nouvelle bordure de motif */
+ match_area_t *new_area; /* Copie de correspondance */
+
+ if (0x0) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
+
+ if (*skip)
+ return;
+
+ /**
+ * En lecture à rebourd, au moins un noeud a été solicité pour analyse (lors
+ * du sens de lecture normal). Donc l'initialisation a déjà dû avoir lieu.
+ */
+
+ assert(params->initialized);
+
+ flags = g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node));
+
+ /**
+ * Si les recherches associées au noeud ont été forcées, alors les traitements
+ * liés ont déjà été effectués, et l'appel de cette fonction aurait dû être sauté.
+ */
+#ifndef NDEBUG
+ forced = (flags & STNF_MAIN);
+ assert(!forced);
+#endif
+
+ /**
+ * Les considérations pour l'extension des espaces en place sont identiques
+ * à celles formulées dans la fonction g_scan_token_node_any_check_forward().
+ */
+
+ extend_node_search_offset(&params->offset, node->min, node->max, node->has_max);
+
+ /**
+ * Si un décalage enregistré ne peut être consommé par un noeud, les
+ * résultats sont étendus ici à minima ou maxima.
+ */
+
+ if (flags & STNF_FIRST)
+ {
+ assert(offsets_exist(&params->offset));
+
+ if (0x0) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count);
+
+ for_each_match_area_safe(area, &params->main_areas, next)
+ {
+ assert(params->content_start <= area->start);
+
+ before = area->start - params->content_start;
+
+ if (0x0) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end);
+
+ min_start = params->content_start;
+ max_start = params->content_end;
+
+ updated = false;
+
+ ranges = get_node_search_offset_ranges_2(&params->offset, &rcount);
+
+ for (r = 0; r < rcount; r++)
+ {
+ if (ranges[r].min > before)
+ continue;
+
+ updated_edge = area->start - ranges[r].min;
+
+ if (updated_edge > min_start)
+ min_start = updated_edge;
+
+ if (ranges[r].has_max)
+ {
+ if (ranges[r].max > before)
+ updated_edge = params->content_start;
+ else
+ updated_edge = area->start - ranges[r].max;
+
+ if (updated_edge < max_start)
+ max_start = updated_edge;
+
+ }
+
+ updated = true;
+
+ }
+
+ if (updated)
+ {
+ /**
+ * Si seuls les rejets sont d'intérêt, les correspondances établies
+ * ne se voient pas mises à jours ni retirées.
+ */
+
+ if ((cflags & TNCF_KEEP_DISCARDED) == 0)
+ {
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ area->start = (1 /* greedy */ ? min_start : max_start);
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ new_area = g_umem_slice_alloc(params->allocator);
+
+ *new_area = *area;
+
+ new_area->start = (1 /* greedy */ ? min_start : max_start);
+
+ add_tail_match_area(new_area, &params->created_areas);
+ params->created_count++;
+
+ }
+
+#ifndef NDEBUG
+ else
+ assert(false);
+#endif
+
+ }
+
+ }
+
+ else
+ {
+ /**
+ * Si la liste principale doit être mise à jour...
+ */
+
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ {
+ del_match_area(area, &params->main_areas);
+ assert(params->main_count > 0);
+ params->main_count--;
+ }
+
+ /**
+ * Au cas où le rejet est d'intérêt, l'absence de correspondance
+ * est conservée dans une liste dédiée.
+ */
+
+ if (cflags & TNCF_KEEP_DISCARDED)
+ {
+ if (cflags & TNCF_UPDATE_IN_PLACE)
+ {
+ add_tail_match_area(area, &params->kept_areas);
+ params->kept_count++;
+ }
+
+ else if (cflags & TNCF_CREATE_NEW)
+ {
+ new_area = g_umem_slice_alloc(params->allocator);
+
+ *new_area = *area;
+
+ new_area->start = (1 /* greedy */ ? min_start : max_start);
+
+ add_tail_match_area(new_area, &params->kept_areas);
+ params->kept_count++;
+
+ }
+
+#ifndef NDEBUG
+ else
+ assert(false);
+#endif
+
+ }
+
+ }
+
+ }
+
+ disable_all_ranges_in_node_search_offset(&params->offset);
+
+ }
+
+}