summaryrefslogtreecommitdiff
path: root/src/analysis
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2023-10-11 23:16:21 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2023-10-11 23:16:21 (GMT)
commitab6b87b7309e2d00926615f6557016bee6ab0b71 (patch)
treebf69b93d2f0548fc845e68ae1e8519bd33d1da24 /src/analysis
parent404097b7b07b336b427b3682ec2bc48d831cb2e9 (diff)
Add two new functions to ROST grammar: modpath and maxcommon.
Diffstat (limited to 'src/analysis')
-rw-r--r--src/analysis/scan/core.c4
-rw-r--r--src/analysis/scan/exprs/handler-int.h6
-rw-r--r--src/analysis/scan/exprs/handler.c132
-rw-r--r--src/analysis/scan/exprs/handler.h5
-rw-r--r--src/analysis/scan/exprs/literal.c52
-rw-r--r--src/analysis/scan/grammar.y8
-rw-r--r--src/analysis/scan/items/Makefile.am2
-rw-r--r--src/analysis/scan/items/maxcommon.c366
-rw-r--r--src/analysis/scan/items/maxcommon.h58
-rw-r--r--src/analysis/scan/items/modpath.c301
-rw-r--r--src/analysis/scan/items/modpath.h58
-rw-r--r--src/analysis/scan/matches/bytes-int.h3
-rw-r--r--src/analysis/scan/matches/bytes.c56
-rw-r--r--src/analysis/scan/matches/bytes.h6
-rw-r--r--src/analysis/scan/matches/pending.c55
-rw-r--r--src/analysis/scan/matches/pending.h6
-rw-r--r--src/analysis/scan/patterns/modifier-int.h4
-rw-r--r--src/analysis/scan/patterns/modifier.c27
-rw-r--r--src/analysis/scan/patterns/modifier.h3
-rw-r--r--src/analysis/scan/patterns/modifiers/hex.c35
-rw-r--r--src/analysis/scan/patterns/modifiers/list.c32
-rw-r--r--src/analysis/scan/patterns/modifiers/plain.c35
-rw-r--r--src/analysis/scan/patterns/modifiers/rev.c35
-rw-r--r--src/analysis/scan/patterns/modifiers/xor.c43
-rw-r--r--src/analysis/scan/patterns/token.c28
-rw-r--r--src/analysis/scan/patterns/token.h3
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/plain.c42
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/plain.h3
-rw-r--r--src/analysis/scan/rule.c3
29 files changed, 1379 insertions, 32 deletions
diff --git a/src/analysis/scan/core.c b/src/analysis/scan/core.c
index fdee1c7..7b1a455 100644
--- a/src/analysis/scan/core.c
+++ b/src/analysis/scan/core.c
@@ -30,6 +30,8 @@
#include "items/count.h"
#include "items/datasize.h"
+#include "items/maxcommon.h"
+#include "items/modpath.h"
#include "items/uint.h"
#include "items/console/log.h"
#ifdef INCLUDE_MAGIC_SUPPORT
@@ -249,6 +251,8 @@ bool populate_main_scan_namespace(GScanNamespace *space)
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_maxcommon_function_new());
+ if (result) result = REGISTER_FUNC(space, g_scan_modpath_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));
diff --git a/src/analysis/scan/exprs/handler-int.h b/src/analysis/scan/exprs/handler-int.h
index f707fdb..a38dd03 100644
--- a/src/analysis/scan/exprs/handler-int.h
+++ b/src/analysis/scan/exprs/handler-int.h
@@ -37,7 +37,9 @@ struct _GScanPatternHandler
{
GScanExpression parent; /* A laisser en premier */
- GSearchPattern *pattern; /* Motif associé */
+ GSearchPattern **patterns; /* Motifs associés */
+ size_t count; /* Nombre de ces motifs */
+
ScanHandlerType type; /* Manipulation attendue */
};
@@ -51,7 +53,7 @@ struct _GScanPatternHandlerClass
/* Met en place une manipulation de correspondances établies. */
-bool g_scan_pattern_handler_create(GScanPatternHandler *, GSearchPattern *, ScanHandlerType);
+bool g_scan_pattern_handler_create(GScanPatternHandler *, GSearchPattern ** const, size_t, ScanHandlerType);
diff --git a/src/analysis/scan/exprs/handler.c b/src/analysis/scan/exprs/handler.c
index 1676522..1b6416e 100644
--- a/src/analysis/scan/exprs/handler.c
+++ b/src/analysis/scan/exprs/handler.c
@@ -122,7 +122,9 @@ static void g_scan_pattern_handler_class_init(GScanPatternHandlerClass *klass)
static void g_scan_pattern_handler_init(GScanPatternHandler *handler)
{
- handler->pattern = NULL;
+ handler->patterns = NULL;
+ handler->count = 0;
+
handler->type = SHT_RAW;
}
@@ -142,7 +144,10 @@ static void g_scan_pattern_handler_init(GScanPatternHandler *handler)
static void g_scan_pattern_handler_dispose(GScanPatternHandler *handler)
{
- g_clear_object(&handler->pattern);
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < handler->count; i++)
+ g_clear_object(&handler->patterns[i]);
G_OBJECT_CLASS(g_scan_pattern_handler_parent_class)->dispose(G_OBJECT(handler));
@@ -170,8 +175,9 @@ static void g_scan_pattern_handler_finalize(GScanPatternHandler *handler)
/******************************************************************************
* *
-* Paramètres : pattern = motif à impliquer. *
-* type = type de manipulation attendue. *
+* Paramètres : patterns = motifs à impliquer. *
+* count = quantité de ces motifs. *
+* type = type de manipulation attendue. *
* *
* Description : Met en place une manipulation de correspondances établies. *
* *
@@ -181,13 +187,13 @@ static void g_scan_pattern_handler_finalize(GScanPatternHandler *handler)
* *
******************************************************************************/
-GScanExpression *g_scan_pattern_handler_new(GSearchPattern *pattern, ScanHandlerType type)
+GScanExpression *g_scan_pattern_handler_new(GSearchPattern ** const patterns, size_t count, ScanHandlerType type)
{
GScanExpression *result; /* Structure à retourner */
result = g_object_new(G_TYPE_SCAN_PATTERN_HANDLER, NULL);
- if (!g_scan_pattern_handler_create(G_SCAN_PATTERN_HANDLER(result), pattern, type))
+ if (!g_scan_pattern_handler_create(G_SCAN_PATTERN_HANDLER(result), patterns, count, type))
g_clear_object(&result);
return result;
@@ -197,9 +203,10 @@ GScanExpression *g_scan_pattern_handler_new(GSearchPattern *pattern, ScanHandler
/******************************************************************************
* *
-* Paramètres : handler = instance à initialiser pleinement. *
-* pattern = motif à impliquer. *
-* type = type de manipulation attendue. *
+* Paramètres : handler = instance à initialiser pleinement. *
+* patterns = motifs à impliquer. *
+* count = quantité de ces motifs. *
+* type = type de manipulation attendue. *
* *
* Description : Met en place une manipulation de correspondances établies. *
* *
@@ -209,15 +216,22 @@ GScanExpression *g_scan_pattern_handler_new(GSearchPattern *pattern, ScanHandler
* *
******************************************************************************/
-bool g_scan_pattern_handler_create(GScanPatternHandler *handler, GSearchPattern *pattern, ScanHandlerType type)
+bool g_scan_pattern_handler_create(GScanPatternHandler *handler, GSearchPattern ** const patterns, size_t count, ScanHandlerType type)
{
bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
result = g_scan_expression_create(G_SCAN_EXPRESSION(handler), SRS_WAIT_FOR_SCAN);
if (!result) goto exit;
- handler->pattern = pattern;
- g_object_ref(G_OBJECT(pattern));
+ handler->patterns = malloc(count * sizeof(GSearchPattern *));
+ handler->count = count;
+
+ for (i = 0; i < count; i++)
+ {
+ handler->patterns[i] = patterns[i];
+ g_object_ref(G_OBJECT(patterns[i]));
+ }
handler->type = type;
@@ -228,6 +242,63 @@ bool g_scan_pattern_handler_create(GScanPatternHandler *handler, GSearchPattern
}
+/******************************************************************************
+* *
+* Paramètres : handler = instance à initialiser pleinement. *
+* ctx = contexte de suivi de l'analyse courante. *
+* count = quantité de correspondances enregistrées. [OUT] *
+* *
+* Description : Fournit la liste de toutes les correspondances représentées. *
+* *
+* Retour : Liste courante de correspondances établies. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanMatch **g_scan_pattern_handler_get_all_matches(const GScanPatternHandler *handler, GScanContext *ctx, size_t *count)
+{
+ GScanMatch **result; /* Liste à retourner */
+ size_t used; /* Indice pour le stockage */
+ size_t i; /* Boucle de parcours #1 */
+ size_t partial; /* Décompte partiel */
+ const GScanMatch **matches; /* Correspondances en place */
+ size_t k; /* Boucle de parcours #2 */
+
+ result = NULL;
+
+ if (!g_scan_pattern_handler_count_items(handler, ctx, count))
+ {
+ *count = 0;
+ goto exit;
+ }
+
+ if (*count == 0)
+ goto exit;
+
+ result = malloc(*count * sizeof(GScanMatch *));
+
+ used = 0;
+
+ for (i = 0; i < handler->count; i++)
+ {
+ matches = g_scan_context_get_full_matches(ctx, handler->patterns[i], &partial);
+
+ for (k = 0; k < partial; k++)
+ {
+ result[used++] = matches[k];
+ g_object_ref(G_OBJECT(matches[k]));
+ }
+
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
/* ---------------------------------------------------------------------------------- */
/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
@@ -284,9 +355,7 @@ static bool g_scan_pattern_handler_reduce_to_boolean(const GScanPatternHandler *
bool result; /* Bilan à retourner */
size_t count; /* Quantité de correspondances */
- result = true;
-
- g_scan_context_get_full_matches(ctx, expr->pattern, &count);
+ result = g_scan_pattern_handler_count_items(expr, ctx, &count);
*out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ count > 0 });
@@ -312,12 +381,20 @@ static bool g_scan_pattern_handler_reduce_to_boolean(const GScanPatternHandler *
static bool g_scan_pattern_handler_count_items(const GScanPatternHandler *expr, GScanContext *ctx, size_t *count)
{
bool result; /* Bilan à retourner */
+ size_t partial; /* Décompte partiel */
+ size_t i; /* Boucle de parcours */
result = true;
assert(g_scan_context_is_scan_done(ctx));
- g_scan_context_get_full_matches(ctx, expr->pattern, count);
+ *count = 0;
+
+ for (i = 0; i < expr->count; i++)
+ {
+ g_scan_context_get_full_matches(ctx, expr->patterns[i], &partial);
+ *count += partial;
+ }
return result;
@@ -342,6 +419,7 @@ static bool g_scan_pattern_handler_count_items(const GScanPatternHandler *expr,
static bool g_scan_pattern_handler_get_item(const GScanPatternHandler *expr, size_t index, GScanContext *ctx, GScanExpression **out)
{
bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
size_t count; /* Quantité de correspondances */
const GScanMatch **matches; /* Correspondances en place */
const GScanBytesMatch *match; /* Correspondance ciblée */
@@ -353,18 +431,32 @@ static bool g_scan_pattern_handler_get_item(const GScanPatternHandler *expr, siz
const bin_t *data; /* Accès aux données brutes */
sized_string_t binary; /* Conversion de formats */
+ result = false;
+
assert(g_scan_context_is_scan_done(ctx));
- matches = g_scan_context_get_full_matches(ctx, expr->pattern, &count);
+ /* Identification du motif concerné */
- result = (index < count);
- if (!result) goto done;
+ for (i = 0; i < expr->count; i++)
+ {
+ matches = g_scan_context_get_full_matches(ctx, expr->patterns[i], &count);
+
+ if (index < count)
+ break;
+ else
+ index -= count;
+
+ }
+
+ if (i == expr->count) goto done;
result = G_IS_SCAN_BYTES_MATCH(matches[index]);
if (!result) goto done;
match = G_SCAN_BYTES_MATCH(matches[index]);
+ /* Traitement adapté de la requête */
+
len = g_scan_bytes_match_get_location(match, &start, &end);
switch (expr->type)
@@ -376,7 +468,7 @@ static bool g_scan_pattern_handler_get_item(const GScanPatternHandler *expr, siz
data = g_binary_content_get_raw_access(content, &pos, len);
- binary.data = data;
+ binary.static_bin_data = data;
binary.len = len;
*out = g_scan_literal_expression_new(LVT_STRING, &binary);
diff --git a/src/analysis/scan/exprs/handler.h b/src/analysis/scan/exprs/handler.h
index 8ad700a..36985e7 100644
--- a/src/analysis/scan/exprs/handler.h
+++ b/src/analysis/scan/exprs/handler.h
@@ -59,7 +59,10 @@ typedef enum _ScanHandlerType
GType g_scan_pattern_handler_get_type(void);
/* Met en place une manipulation de correspondances établies. */
-GScanExpression *g_scan_pattern_handler_new(GSearchPattern *, ScanHandlerType);
+GScanExpression *g_scan_pattern_handler_new(GSearchPattern ** const, size_t, ScanHandlerType);
+
+/* Fournit la liste de toutes les correspondances représentées. */
+GScanMatch **g_scan_pattern_handler_get_all_matches(const GScanPatternHandler *, GScanContext *, size_t *);
diff --git a/src/analysis/scan/exprs/literal.c b/src/analysis/scan/exprs/literal.c
index de7e32a..b1a094c 100644
--- a/src/analysis/scan/exprs/literal.c
+++ b/src/analysis/scan/exprs/literal.c
@@ -62,6 +62,9 @@ static bool g_scan_literal_expression_reduce_to_boolean(const GScanLiteralExpres
/* Dénombre les éléments portés par une expression. */
static bool g_scan_literal_expression_count(const GScanLiteralExpression *, GScanContext *, size_t *);
+/* Fournit un élément donné issu d'un ensemble constitué. */
+static bool g_scan_literal_expression_get_item(const GScanLiteralExpression *, size_t, GScanContext *, GScanExpression **);
+
/* ---------------------------------------------------------------------------------- */
@@ -100,6 +103,7 @@ static void g_scan_literal_expression_class_init(GScanLiteralExpressionClass *kl
expr->cmp_rich = (compare_expr_rich_fc)g_scan_literal_expression_compare_rich;
expr->reduce_to_bool = (reduce_expr_to_bool_fc)g_scan_literal_expression_reduce_to_boolean;
expr->count = (count_scan_expr_fc)g_scan_literal_expression_count;
+ expr->get = (get_scan_expr_fc)g_scan_literal_expression_get_item;
}
@@ -659,3 +663,51 @@ static bool g_scan_literal_expression_count(const GScanLiteralExpression *expr,
return result;
}
+
+
+/******************************************************************************
+* *
+* Paramètres : expr = expression à consulter. *
+* index = indice de l'élément à transférer. *
+* ctx = contexte de suivi de l'analyse courante. *
+* out = zone d'enregistrement de la réduction opérée. [OUT] *
+* *
+* Description : Fournit un élément donné issu d'un ensemble constitué. *
+* *
+* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_scan_literal_expression_get_item(const GScanLiteralExpression *expr, size_t index, GScanContext *ctx, GScanExpression **out)
+{
+ bool result; /* Bilan à retourner */
+ sized_string_t ch; /* Caractère extrait */
+
+ switch (expr->value_type)
+ {
+ case LVT_STRING:
+
+ result = (index < expr->value.string.len);
+
+ if (result)
+ {
+ ch.data = expr->value.string.data + index;
+ ch.len = 1;
+
+ *out = g_scan_literal_expression_new(LVT_STRING, &ch);
+
+ }
+
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/src/analysis/scan/grammar.y b/src/analysis/scan/grammar.y
index 2863e21..36f6df9 100644
--- a/src/analysis/scan/grammar.y
+++ b/src/analysis/scan/grammar.y
@@ -1376,7 +1376,7 @@ relational_expr : cexpression "<" cexpression { $$ = g_scan_relational_operatio
$$ = NULL;
else
{
- $$ = g_scan_pattern_handler_new(__pat, SHT_RAW);
+ $$ = g_scan_pattern_handler_new((GSearchPattern *[]) { __pat }, 1, SHT_RAW);
g_object_unref(G_OBJECT(__pat));
}
}
@@ -1400,7 +1400,7 @@ relational_expr : cexpression "<" cexpression { $$ = g_scan_relational_operatio
$$ = NULL;
else
{
- $$ = g_scan_pattern_handler_new(__pat, SHT_START);
+ $$ = g_scan_pattern_handler_new((GSearchPattern *[]) { __pat }, 1, SHT_START);
g_object_unref(G_OBJECT(__pat));
}
}
@@ -1412,7 +1412,7 @@ relational_expr : cexpression "<" cexpression { $$ = g_scan_relational_operatio
$$ = NULL;
else
{
- $$ = g_scan_pattern_handler_new(__pat, SHT_LENGTH);
+ $$ = g_scan_pattern_handler_new((GSearchPattern *[]) { __pat }, 1, SHT_LENGTH);
g_object_unref(G_OBJECT(__pat));
}
}
@@ -1424,7 +1424,7 @@ relational_expr : cexpression "<" cexpression { $$ = g_scan_relational_operatio
$$ = NULL;
else
{
- $$ = g_scan_pattern_handler_new(__pat, SHT_END);
+ $$ = g_scan_pattern_handler_new((GSearchPattern *[]) { __pat }, 1, SHT_END);
g_object_unref(G_OBJECT(__pat));
}
}
diff --git a/src/analysis/scan/items/Makefile.am b/src/analysis/scan/items/Makefile.am
index 89ae41e..9263c7b 100644
--- a/src/analysis/scan/items/Makefile.am
+++ b/src/analysis/scan/items/Makefile.am
@@ -14,6 +14,8 @@ endif
libanalysisscanitems_la_SOURCES = \
count.h count.c \
datasize.h datasize.c \
+ maxcommon.h maxcommon.c \
+ modpath.h modpath.c \
uint-int.h \
uint.h uint.c
diff --git a/src/analysis/scan/items/maxcommon.c b/src/analysis/scan/items/maxcommon.c
new file mode 100644
index 0000000..a2e0f2a
--- /dev/null
+++ b/src/analysis/scan/items/maxcommon.c
@@ -0,0 +1,366 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * maxcommon.c - détermination de la plus grand occurrence au sein d'un ensemble d'éléments
+ *
+ * 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 "maxcommon.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+
+
+#include "../item-int.h"
+#include "../exprs/literal.h"
+#include "../../../glibext/comparison-int.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des repérages de plus grande occurrence. */
+static void g_scan_maxcommon_function_class_init(GScanMaxcommonFunctionClass *);
+
+/* Initialise une instance de repérage d'occurrence maximake. */
+static void g_scan_maxcommon_function_init(GScanMaxcommonFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_maxcommon_function_dispose(GScanMaxcommonFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_maxcommon_function_finalize(GScanMaxcommonFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_maxcommon_function_get_name(const GScanMaxcommonFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_maxcommon_function_run_call(GScanMaxcommonFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un décompte d'élément le plus représenté dans une série. */
+G_DEFINE_TYPE(GScanMaxcommonFunction, g_scan_maxcommon_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des repérages de plus grande occurrence.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_maxcommon_function_class_init(GScanMaxcommonFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_maxcommon_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_maxcommon_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_maxcommon_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_maxcommon_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance de repérage d'occurrence maximake. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_maxcommon_function_init(GScanMaxcommonFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_maxcommon_function_dispose(GScanMaxcommonFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_maxcommon_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_maxcommon_function_finalize(GScanMaxcommonFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_maxcommon_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une fonction de calcul de plus grande occurrence. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_scan_maxcommon_function_new(void)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_MAXCOMMON_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_maxcommon_function_get_name(const GScanMaxcommonFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("maxcommon");
+
+ 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_maxcommon_function_run_call(GScanMaxcommonFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ size_t used; /* Prochain emplacement libre */
+ GScanExpression **collected; /* Représentants de groupes */
+ size_t *scores; /* Taille de ces groupes */
+ size_t i; /* Boucle de parcours #1 */
+ size_t k; /* Boucle de parcours #2 */
+ bool status; /* Bilan de la comparaison */
+ bool equal; /* Egalité établie ? */
+ size_t arg0_count; /* Taille de l'argument unique */
+ GScanExpression *arg0_item; /* Elément de cet argument */
+ size_t best; /* Meilleur score identifié */
+
+ result = (count > 0);
+ if (!result) goto exit;
+
+ used = 0;
+
+ /* Si la série à étudier est directement fournie */
+ if (count > 1)
+ {
+ collected = malloc(count * sizeof(GScanExpression *));
+ scores = malloc(count * sizeof(size_t));
+
+ for (i = 0; i < count; i++)
+ {
+ for (k = 0; k < used; k++)
+ {
+ status = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(args[i]),
+ G_COMPARABLE_ITEM(collected[k]),
+ RCO_EQ, &equal);
+
+ if (status && equal)
+ break;
+
+ }
+
+ if (k < used)
+ scores[k]++;
+
+ else
+ {
+ collected[used] = args[i];
+ g_object_ref(G_OBJECT(args[i]));
+ scores[used] = 1;
+
+ used++;
+
+ }
+
+ }
+
+ }
+
+ /* Sinon on considère que l'arguement unique porte la liste (idéalement) */
+ else
+ {
+ if (G_IS_SCAN_LITERAL_EXPRESSION(args[0]) || !g_scan_expression_handle_set_features(args[0]))
+ {
+ best = 1;
+ goto quick_unique;
+ }
+
+#ifndef NDEBUG
+ g_scan_expression_count_items(args[0], ctx, &arg0_count);
+#else
+ status = bool g_scan_expression_count_items(args[0], ctx, &arg0_count);
+ assert(status);
+#endif
+
+ collected = malloc(arg0_count * sizeof(GScanExpression *));
+ scores = malloc(arg0_count * sizeof(size_t));
+
+ for (i = 0; i < arg0_count; i++)
+ {
+#ifndef NDEBUG
+ g_scan_expression_get_item(args[0], i, ctx, &arg0_item);
+#else
+ status = g_scan_expression_get_item(args[0], i, ctx, &arg0_item);
+ assert(status);
+#endif
+
+ for (k = 0; k < used; k++)
+ {
+ status = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(arg0_item),
+ G_COMPARABLE_ITEM(collected[k]),
+ RCO_EQ, &equal);
+
+ if (status && equal)
+ break;
+
+ }
+
+ if (k < used)
+ {
+ g_object_unref(G_OBJECT(arg0_item));
+ scores[k]++;
+ }
+
+ else
+ {
+ collected[used] = arg0_item;
+ scores[used] = 1;
+
+ used++;
+
+ }
+
+ }
+
+ }
+
+ /* Analyse des résultats */
+
+ best = 0;
+
+ for (i = 0; i < used; i++)
+ if (scores[i] > best)
+ best = scores[i];
+
+ for (i = 0; i < used; i++)
+ g_object_unref(G_OBJECT(collected[i]));
+
+ free(collected);
+ free(scores);
+
+ quick_unique:
+
+ assert(best > 0);
+
+ *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ best }));
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/maxcommon.h b/src/analysis/scan/items/maxcommon.h
new file mode 100644
index 0000000..a834c00
--- /dev/null
+++ b/src/analysis/scan/items/maxcommon.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * maxcommon.h - prototypes pour la détermination de la plus grand occurrence au sein d'un ensemble d'éléments
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_MAXCOMMON_H
+#define _ANALYSIS_SCAN_ITEMS_MAXCOMMON_H
+
+
+#include <glib-object.h>
+
+
+#include "../item.h"
+
+
+
+#define G_TYPE_SCAN_MAXCOMMON_FUNCTION g_scan_maxcommon_function_get_type()
+#define G_SCAN_MAXCOMMON_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MAXCOMMON_FUNCTION, GScanMaxcommonFunction))
+#define G_IS_SCAN_MAXCOMMON_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MAXCOMMON_FUNCTION))
+#define G_SCAN_MAXCOMMON_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MAXCOMMON_FUNCTION, GScanMaxcommonFunctionClass))
+#define G_IS_SCAN_MAXCOMMON_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MAXCOMMON_FUNCTION))
+#define G_SCAN_MAXCOMMON_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MAXCOMMON_FUNCTION, GScanMaxcommonFunctionClass))
+
+
+/* Détermination de la plus grand occurrence au sein d'un ensemble (instance) */
+typedef GScanRegisteredItem GScanMaxcommonFunction;
+
+/* Détermination de la plus grand occurrence au sein d'un ensemble (classe) */
+typedef GScanRegisteredItemClass GScanMaxcommonFunctionClass;
+
+
+/* Indique le type défini pour un décompte d'élément le plus représenté dans une série. */
+GType g_scan_maxcommon_function_get_type(void);
+
+/* Constitue une fonction de calcul de plus grande occurrence. */
+GScanRegisteredItem *g_scan_maxcommon_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_MAXCOMMON_H */
diff --git a/src/analysis/scan/items/modpath.c b/src/analysis/scan/items/modpath.c
new file mode 100644
index 0000000..2171bda
--- /dev/null
+++ b/src/analysis/scan/items/modpath.c
@@ -0,0 +1,301 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * modpath.c - récupération des combinaisons de modification de motifs
+ *
+ * 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 "modpath.h"
+
+
+#include "../item-int.h"
+
+
+#include "../exprs/handler.h"
+#include "../exprs/literal.h"
+#include "../exprs/set.h"
+#include "../matches/bytes.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des énumérations de formules de motifs. */
+static void g_scan_modpath_function_class_init(GScanModpathFunctionClass *);
+
+/* Initialise une instance d'énumération de formules de motifs. */
+static void g_scan_modpath_function_init(GScanModpathFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_modpath_function_dispose(GScanModpathFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_modpath_function_finalize(GScanModpathFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_modpath_function_get_name(const GScanModpathFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_modpath_function_run_call(GScanModpathFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTRODUCTION D'UNE NOUVELLE FONCTION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une énumération de formules créant des motifs. */
+G_DEFINE_TYPE(GScanModpathFunction, g_scan_modpath_function, G_TYPE_SCAN_REGISTERED_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des énumérations de formules de motifs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_modpath_function_class_init(GScanModpathFunctionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GScanRegisteredItemClass *registered; /* Version de classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_modpath_function_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_modpath_function_finalize;
+
+ registered = G_SCAN_REGISTERED_ITEM_CLASS(klass);
+
+ registered->get_name = (get_registered_item_name_fc)g_scan_modpath_function_get_name;
+ registered->run_call = (run_registered_item_call_fc)g_scan_modpath_function_run_call;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance à initialiser. *
+* *
+* Description : Initialise une instance d'énumération de formules de motifs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_modpath_function_init(GScanModpathFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : func = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_modpath_function_dispose(GScanModpathFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_modpath_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_modpath_function_finalize(GScanModpathFunction *func)
+{
+ G_OBJECT_CLASS(g_scan_modpath_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Constitue une fonction d'énumération des formules de motifs. *
+* *
+* Retour : Fonction mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRegisteredItem *g_scan_modpath_function_new(void)
+{
+ GScanRegisteredItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_MODPATH_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_modpath_function_get_name(const GScanModpathFunction *item)
+{
+ char *result; /* Désignation à retourner */
+
+ result = strdup("modpath");
+
+ 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_modpath_function_run_call(GScanModpathFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours #1 */
+ size_t mcount; /* Quantité de correspondances */
+ GScanMatch **matches; /* Correspondances établies */
+ size_t k; /* Boucle de parcours #2 */
+ sized_string_t path; /* Combinaison à conserver */
+ GScanExpression *subitem; /* Nouvel élément à transmettre*/
+
+ /* Validation préalable du type des arguments */
+
+ result = true;
+
+ for (i = 0; i < count && result; i++)
+ result = G_IS_SCAN_PATTERN_HANDLER(args[i]);
+
+ if (!result)
+ goto exit;
+
+ /* Construction des chemins attendus */
+
+ *out = G_OBJECT(g_scan_generic_set_new());
+
+ for (i = 0; i < count; i++)
+ {
+ matches = g_scan_pattern_handler_get_all_matches(G_SCAN_PATTERN_HANDLER(args[i]), ctx, &mcount);
+ if (mcount == 0) continue;
+
+ /**
+ * La série est à priori constituée d'éléments de même type, donc
+ * un test unique suffit.
+ */
+ if (!G_IS_SCAN_BYTES_MATCH(matches[0]))
+ {
+ for (k = 0; k < mcount; k++)
+ g_object_unref(G_OBJECT(matches[k]));
+ }
+
+ else
+ {
+ for (k = 0; k < mcount; k++)
+ {
+ path.data = g_scan_bytes_match_get_modifier_path(G_SCAN_BYTES_MATCH(matches[k]));
+ if (path.data == NULL) continue;
+
+ path.len = strlen(path.data);
+
+ printf(" >> add '%s'\n", path.data);
+
+ subitem = g_scan_literal_expression_new(LVT_STRING, &path);
+
+ g_scan_generic_set_add_item(G_SCAN_GENERIC_SET(*out), subitem);
+
+ g_object_unref(G_OBJECT(subitem));
+
+ exit_szstr(&path);
+
+ g_object_unref(G_OBJECT(matches[k]));
+
+ }
+
+ }
+
+ free(matches);
+
+ }
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/scan/items/modpath.h b/src/analysis/scan/items/modpath.h
new file mode 100644
index 0000000..3a78ef7
--- /dev/null
+++ b/src/analysis/scan/items/modpath.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * modpath.h - prototypes pour la récupération des combinaisons de modification de motifs
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_ITEMS_MODPATH_H
+#define _ANALYSIS_SCAN_ITEMS_MODPATH_H
+
+
+#include <glib-object.h>
+
+
+#include "../item.h"
+
+
+
+#define G_TYPE_SCAN_MODPATH_FUNCTION g_scan_modpath_function_get_type()
+#define G_SCAN_MODPATH_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MODPATH_FUNCTION, GScanModpathFunction))
+#define G_IS_SCAN_MODPATH_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MODPATH_FUNCTION))
+#define G_SCAN_MODPATH_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MODPATH_FUNCTION, GScanModpathFunctionClass))
+#define G_IS_SCAN_MODPATH_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MODPATH_FUNCTION))
+#define G_SCAN_MODPATH_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MODPATH_FUNCTION, GScanModpathFunctionClass))
+
+
+/* Récupération de formules à l'origine de la construction de motifs (instance) */
+typedef GScanRegisteredItem GScanModpathFunction;
+
+/* Récupération de formules à l'origine de la construction de motifs (classe) */
+typedef GScanRegisteredItemClass GScanModpathFunctionClass;
+
+
+/* Indique le type défini pour une énumération de formules créant des motifs. */
+GType g_scan_modpath_function_get_type(void);
+
+/* Constitue une fonction d'énumération des formules de motifs. */
+GScanRegisteredItem *g_scan_modpath_function_new(void);
+
+
+
+#endif /* _ANALYSIS_SCAN_ITEMS_MODPATH_H */
diff --git a/src/analysis/scan/matches/bytes-int.h b/src/analysis/scan/matches/bytes-int.h
index 6f7e60b..f57cb9f 100644
--- a/src/analysis/scan/matches/bytes-int.h
+++ b/src/analysis/scan/matches/bytes-int.h
@@ -42,6 +42,9 @@ struct _GScanBytesMatch
phys_t start; /* Début du motif représenté */
phys_t len; /* Taille du motif représenté */
+ size_t mod_path_index; /* Indice de construction */
+ bool has_mod_path; /* Validité du champ précédent */
+
};
/* Correspondance trouvée avec une chaîne (classe) */
diff --git a/src/analysis/scan/matches/bytes.c b/src/analysis/scan/matches/bytes.c
index de101c4..f0b97fe 100644
--- a/src/analysis/scan/matches/bytes.c
+++ b/src/analysis/scan/matches/bytes.c
@@ -30,6 +30,7 @@
#include "bytes-int.h"
+#include "../patterns/token.h"
#include "../../../common/cpp.h"
#include "../../../core/logs.h"
@@ -121,6 +122,8 @@ static void g_scan_bytes_match_init(GScanBytesMatch *match)
match->start = VMPA_NO_PHYSICAL;
match->len = VMPA_NO_PHYSICAL;
+ match->has_mod_path = false;
+
}
@@ -285,6 +288,59 @@ phys_t g_scan_bytes_match_get_location(const GScanBytesMatch *match, phys_t *sta
}
+/******************************************************************************
+* *
+* Paramètres : match = informations de correspondance à compléter. *
+* index = indice de la combinaison de modificateurs ciblée. *
+* *
+* Description : Mémorise l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_bytes_match_remember_modifier_path(GScanBytesMatch *match, size_t index)
+{
+ match->mod_path_index = index;
+ match->has_mod_path = true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : match = informations de correspondance à consulter. *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison gagnante. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_scan_bytes_match_get_modifier_path(const GScanBytesMatch *match)
+{
+ char *result; /* Combinaison à retourner */
+ GBytesToken *pattern; /* Autre version du motif */
+
+ if (match->has_mod_path)
+ {
+ pattern = G_BYTES_TOKEN(G_SCAN_MATCH(match)->source);
+ result = g_bytes_token_get_modifier_path(pattern, match->mod_path_index);
+ }
+
+ else
+ result = NULL;
+
+ return result;
+
+}
+
+
+
/* ---------------------------------------------------------------------------------- */
/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
/* ---------------------------------------------------------------------------------- */
diff --git a/src/analysis/scan/matches/bytes.h b/src/analysis/scan/matches/bytes.h
index e599ee4..bd7425d 100644
--- a/src/analysis/scan/matches/bytes.h
+++ b/src/analysis/scan/matches/bytes.h
@@ -60,6 +60,12 @@ GBinContent *g_scan_bytes_match_get_content(const GScanBytesMatch *);
/* Indique la localisation d'une correspondance établie. */
phys_t g_scan_bytes_match_get_location(const GScanBytesMatch *, phys_t *, phys_t *);
+/* Mémorise l'origine d'une correspondance à partir d'un indice. */
+void g_scan_bytes_match_remember_modifier_path(GScanBytesMatch *, size_t);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+char *g_scan_bytes_match_get_modifier_path(const GScanBytesMatch *);
+
#endif /* _ANALYSIS_SCAN_MATCHES_BYTES_H */
diff --git a/src/analysis/scan/matches/pending.c b/src/analysis/scan/matches/pending.c
index 9ed4de3..57c63d7 100644
--- a/src/analysis/scan/matches/pending.c
+++ b/src/analysis/scan/matches/pending.c
@@ -48,10 +48,6 @@ static int compare_match_area(const match_area_t *, const match_area_t *);
-
-
-
-
/* ---------------------------------------------------------------------------------- */
/* MEMORISATION D'UNE ZONE BORNEE */
/* ---------------------------------------------------------------------------------- */
@@ -82,6 +78,12 @@ static int compare_match_area(const match_area_t *a, const match_area_t *b)
if (result == 0)
result = sort_unsigned_long_long(a->ttl, b->ttl);
+ if (result == 0)
+ result = sort_unsigned_long_long(a->has_mod_path, b->has_mod_path);
+
+ if (result == 0)
+ result = sort_unsigned_long_long(a->mod_path_index, b->mod_path_index);
+
return result;
}
@@ -293,6 +295,51 @@ void add_pending_match(pending_matches_t *matches, phys_t start, phys_t length)
area->ttl = 1;
+ area->has_mod_path = false;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : matches = suivi de correspondances à compléter. *
+* start = point de départ d'une nouvelle correspondance. *
+* length = taille de la zone couverte. *
+* index = indice de construction pour le motif concerné. *
+* *
+* Description : Ajoute au suivi la définition d'une nouvelle correspondance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void add_pending_match_with_path(pending_matches_t *matches, phys_t start, phys_t length, size_t index)
+{
+ match_area_t *area; /* Zone à initialiser */
+
+ if (matches->used == matches->allocated)
+ {
+ matches->allocated += PENDING_ALLOC_SIZE;
+
+ matches->areas = realloc(matches->areas, matches->allocated * sizeof(match_area_t));
+
+ }
+
+ area = &matches->areas[matches->used++];
+
+ area->start = start;
+ area->end = start + length;
+
+ assert(matches->content_start <= area->start);
+ assert(area->end <= matches->content_end);
+
+ area->ttl = 1;
+
+ area->mod_path_index = index;
+ area->has_mod_path = true;
+
}
diff --git a/src/analysis/scan/matches/pending.h b/src/analysis/scan/matches/pending.h
index 6df01c9..f4ac7a2 100644
--- a/src/analysis/scan/matches/pending.h
+++ b/src/analysis/scan/matches/pending.h
@@ -41,6 +41,9 @@ typedef struct _match_area_t
unsigned long ttl; /* Durée de vie pour analyse */
+ size_t mod_path_index; /* Indice de construction */
+ bool has_mod_path; /* Validité du champ précédent */
+
} match_area_t;
/* Suivi de correspondances */
@@ -86,6 +89,9 @@ match_area_t * const *get_all_pending_matches(const pending_matches_t *, size_t
/* Ajoute au suivi la définition d'une nouvelle correspondance. */
void add_pending_match(pending_matches_t *, phys_t, phys_t);
+/* Ajoute au suivi la définition d'une nouvelle correspondance. */
+void add_pending_match_with_path(pending_matches_t *, phys_t, phys_t, size_t);
+
/* Etend une zone couverte dans le suivi des correspondances. */
void extend_pending_match_beginning(pending_matches_t *, size_t, phys_t);
diff --git a/src/analysis/scan/patterns/modifier-int.h b/src/analysis/scan/patterns/modifier-int.h
index e1de2d8..c9b3a36 100644
--- a/src/analysis/scan/patterns/modifier-int.h
+++ b/src/analysis/scan/patterns/modifier-int.h
@@ -41,6 +41,9 @@ typedef bool (* can_token_modifier_handle_arg) (const GScanTokenModifier *, cons
/* Transforme une séquence d'octets pour motif de recherche. */
typedef bool (* transform_scan_token_with_fc) (const GScanTokenModifier *, const sized_binary_t *, size_t, const modifier_arg_t *, sized_binary_t **, size_t *);
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+typedef char * (* get_modifier_path) (const GScanTokenModifier *, size_t *);
+
/* Transformation d'une séquence d'octets en une ou plusieurs autres formes (instance) */
struct _GScanTokenModifier
@@ -59,6 +62,7 @@ struct _GScanTokenModifierClass
transform_scan_token_fc transform; /* Opération de transformation */
can_token_modifier_handle_arg can_handle; /* Support d'argument donné */
transform_scan_token_with_fc transform_with; /* Opération encadrée */
+ get_modifier_path get_path; /* Rappel d'une combinaison */
};
diff --git a/src/analysis/scan/patterns/modifier.c b/src/analysis/scan/patterns/modifier.c
index 65f671f..9efd404 100644
--- a/src/analysis/scan/patterns/modifier.c
+++ b/src/analysis/scan/patterns/modifier.c
@@ -249,3 +249,30 @@ bool g_scan_token_modifier_transform_with_arg(const GScanTokenModifier *modifier
return result;
}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_scan_token_modifier_get_path(const GScanTokenModifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+ GScanTokenModifierClass *class; /* Classe à activer */
+
+ class = G_SCAN_TOKEN_MODIFIER_GET_CLASS(modifier);
+
+ result = class->get_path(modifier, index);
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/modifier.h b/src/analysis/scan/patterns/modifier.h
index ce2589a..9030a72 100644
--- a/src/analysis/scan/patterns/modifier.h
+++ b/src/analysis/scan/patterns/modifier.h
@@ -65,6 +65,9 @@ bool g_scan_token_modifier_can_handle_arg(const GScanTokenModifier *, const modi
/* Transforme une séquence d'octets pour motif de recherche. */
bool g_scan_token_modifier_transform_with_arg(const GScanTokenModifier *, const sized_binary_t *, size_t, const modifier_arg_t *, sized_binary_t **, size_t *);
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+char *g_scan_token_modifier_get_path(const GScanTokenModifier *, size_t *);
+
#endif /* _ANALYSIS_SCAN_MODIFIER_H */
diff --git a/src/analysis/scan/patterns/modifiers/hex.c b/src/analysis/scan/patterns/modifiers/hex.c
index 849d9ff..4a41c7d 100644
--- a/src/analysis/scan/patterns/modifiers/hex.c
+++ b/src/analysis/scan/patterns/modifiers/hex.c
@@ -58,6 +58,9 @@ static char *g_scan_hex_modifier_get_name(const GScanHexModifier *);
/* Transforme une séquence d'octets pour motif de recherche. */
static bool g_scan_hex_modifier_transform(const GScanHexModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_hex_modifier_get_path(const GScanHexModifier *, size_t *);
+
/* ---------------------------------------------------------------------------------- */
@@ -96,6 +99,7 @@ static void g_scan_hex_modifier_class_init(GScanHexModifierClass *klass)
modifier->get_name = (get_scan_modifier_name_fc)g_scan_hex_modifier_get_name;
modifier->transform = (transform_scan_token_fc)g_scan_hex_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_hex_modifier_get_path;
}
@@ -259,3 +263,34 @@ static bool g_scan_hex_modifier_transform(const GScanHexModifier *modifier, cons
return result;
}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_hex_modifier_get_path(const GScanHexModifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("hex");
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/modifiers/list.c b/src/analysis/scan/patterns/modifiers/list.c
index 0390f47..040d2f8 100644
--- a/src/analysis/scan/patterns/modifiers/list.c
+++ b/src/analysis/scan/patterns/modifiers/list.c
@@ -58,6 +58,9 @@ static char *g_scan_modifier_list_get_name(const GScanModifierList *);
/* Transforme une séquence d'octets pour motif de recherche. */
static bool g_scan_modifier_list_transform(const GScanModifierList *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_modifier_list_get_path(const GScanModifierList *, size_t *);
+
/* ---------------------------------------------------------------------------------- */
@@ -96,6 +99,7 @@ static void g_scan_modifier_list_class_init(GScanModifierListClass *klass)
modifier->get_name = (get_scan_modifier_name_fc)g_scan_modifier_list_get_name;
modifier->transform = (transform_scan_token_fc)g_scan_modifier_list_transform;
+ modifier->get_path = (get_modifier_path)g_scan_modifier_list_get_path;
}
@@ -404,3 +408,31 @@ static bool g_scan_modifier_list_transform(const GScanModifierList *modifier, co
return result;
}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_modifier_list_get_path(const GScanModifierList *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+ size_t i; /* Boucle de parcours #1 */
+
+ result = NULL;
+
+ for (i = 0; i < modifier->count && result == NULL; i++)
+ result = g_scan_token_modifier_get_path(modifier->modifiers[i], index);
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/modifiers/plain.c b/src/analysis/scan/patterns/modifiers/plain.c
index 9ed0d7b..ad09129 100644
--- a/src/analysis/scan/patterns/modifiers/plain.c
+++ b/src/analysis/scan/patterns/modifiers/plain.c
@@ -58,6 +58,9 @@ static char *g_scan_plain_modifier_get_name(const GScanPlainModifier *);
/* Transforme une séquence d'octets pour motif de recherche. */
static bool g_scan_plain_modifier_transform(const GScanPlainModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_plain_modifier_get_path(const GScanPlainModifier *, size_t *);
+
/* ---------------------------------------------------------------------------------- */
@@ -96,6 +99,7 @@ static void g_scan_plain_modifier_class_init(GScanPlainModifierClass *klass)
modifier->get_name = (get_scan_modifier_name_fc)g_scan_plain_modifier_get_name;
modifier->transform = (transform_scan_token_fc)g_scan_plain_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_plain_modifier_get_path;
}
@@ -252,3 +256,34 @@ static bool g_scan_plain_modifier_transform(const GScanPlainModifier *modifier,
return result;
}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_plain_modifier_get_path(const GScanPlainModifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("plain");
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/modifiers/rev.c b/src/analysis/scan/patterns/modifiers/rev.c
index 9d74afe..ef4d5fa 100644
--- a/src/analysis/scan/patterns/modifiers/rev.c
+++ b/src/analysis/scan/patterns/modifiers/rev.c
@@ -58,6 +58,9 @@ static char *g_scan_reverse_modifier_get_name(const GScanReverseModifier *);
/* Transforme une séquence d'octets pour motif de recherche. */
static bool g_scan_reverse_modifier_transform(const GScanReverseModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_reverse_modifier_get_path(const GScanReverseModifier *, size_t *);
+
/* ---------------------------------------------------------------------------------- */
@@ -96,6 +99,7 @@ static void g_scan_reverse_modifier_class_init(GScanReverseModifierClass *klass)
modifier->get_name = (get_scan_modifier_name_fc)g_scan_reverse_modifier_get_name;
modifier->transform = (transform_scan_token_fc)g_scan_reverse_modifier_transform;
+ modifier->get_path = (get_modifier_path)g_scan_reverse_modifier_get_path;
}
@@ -254,3 +258,34 @@ static bool g_scan_reverse_modifier_transform(const GScanReverseModifier *modifi
return result;
}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_reverse_modifier_get_path(const GScanReverseModifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (*index > 0)
+ {
+ result = NULL;
+ (*index)--;
+ }
+
+ else
+ result = strdup("rev");
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/modifiers/xor.c b/src/analysis/scan/patterns/modifiers/xor.c
index 53d75a5..d932c82 100644
--- a/src/analysis/scan/patterns/modifiers/xor.c
+++ b/src/analysis/scan/patterns/modifiers/xor.c
@@ -27,6 +27,7 @@
#include <assert.h>
#include <malloc.h>
#include <stdint.h>
+#include <stdio.h>
#include <string.h>
@@ -66,6 +67,9 @@ static bool g_scan_xor_modifier_can_handle_arg(const GScanXorModifier *, const m
/* Transforme une séquence d'octets pour motif de recherche. */
static bool g_scan_xor_modifier_transform_with_arg(const GScanXorModifier *, const sized_binary_t *, size_t, const modifier_arg_t *, sized_binary_t **, size_t *);
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_xor_modifier_get_path(const GScanXorModifier *, size_t *);
+
/* ---------------------------------------------------------------------------------- */
@@ -106,6 +110,7 @@ static void g_scan_xor_modifier_class_init(GScanXorModifierClass *klass)
modifier->transform = (transform_scan_token_fc)g_scan_xor_modifier_transform;
modifier->can_handle = (can_token_modifier_handle_arg)g_scan_xor_modifier_can_handle_arg;
modifier->transform_with = (transform_scan_token_with_fc)g_scan_xor_modifier_transform_with_arg;
+ modifier->get_path = (get_modifier_path)g_scan_xor_modifier_get_path;
}
@@ -393,3 +398,41 @@ static bool g_scan_xor_modifier_transform_with_arg(const GScanXorModifier *modif
return result;
}
+
+
+/******************************************************************************
+* *
+* Paramètres : modifier = modificateur à consulter. *
+* index = indice de la combinaison ciblée. [OUT] *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_scan_xor_modifier_get_path(const GScanXorModifier *modifier, size_t *index)
+{
+ char *result; /* Combinaison à retourner */
+ int ret; /* Bilan intermédiaire */
+
+ if (*index > 255)
+ {
+ result = NULL;
+ (*index) -= 256;
+ }
+
+ else
+ {
+ ret = asprintf(&result, "xor(0x%02hhx)", (unsigned char)*index);
+
+ if (ret == -1)
+ result = strdup("xor(0x?)");
+
+ }
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/token.c b/src/analysis/scan/patterns/token.c
index 8b3a843..030e4a1 100644
--- a/src/analysis/scan/patterns/token.c
+++ b/src/analysis/scan/patterns/token.c
@@ -30,6 +30,7 @@
#include "token-int.h"
+#include "tokens/nodes/plain.h"
#include "../../../common/cpp.h"
#include "../../../core/logs.h"
@@ -342,6 +343,33 @@ void g_bytes_token_check(const GBytesToken *token, GScanContext *context, GBinCo
}
+/******************************************************************************
+* *
+* Paramètres : token = définition de la bribe à consulter. *
+* index = indice de la combinaison de modificateurs ciblée. *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison gagnante. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_bytes_token_get_modifier_path(const GBytesToken *token, size_t index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (G_IS_SCAN_TOKEN_NODE_PLAIN(token->root))
+ result = g_scan_token_node_plain_get_modifier_path(G_SCAN_TOKEN_NODE_PLAIN(token->root), index);
+ else
+ result = NULL;
+
+ return result;
+
+}
+
+
/* ---------------------------------------------------------------------------------- */
/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
diff --git a/src/analysis/scan/patterns/token.h b/src/analysis/scan/patterns/token.h
index a71e367..2816bf8 100644
--- a/src/analysis/scan/patterns/token.h
+++ b/src/analysis/scan/patterns/token.h
@@ -64,6 +64,9 @@ bool g_bytes_token_enroll(GBytesToken *, GScanContext *, GEngineBackend *, size_
/* Transforme les correspondances locales en trouvailles. */
void g_bytes_token_check(const GBytesToken *, GScanContext *, GBinContent *, pending_matches_t *);
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+char *g_bytes_token_get_modifier_path(const GBytesToken *, size_t);
+
#endif /* _ANALYSIS_SCAN_PATTERNS_TOKEN_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/plain.c b/src/analysis/scan/patterns/tokens/nodes/plain.c
index 5d89cf8..7309574 100644
--- a/src/analysis/scan/patterns/tokens/nodes/plain.c
+++ b/src/analysis/scan/patterns/tokens/nodes/plain.c
@@ -277,6 +277,35 @@ ScanPlainNodeFlags g_scan_token_node_plain_get_flags(const GScanTokenNodePlain *
}
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à consulter. *
+* index = indice de la combinaison de modificateurs ciblée. *
+* *
+* Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+* *
+* Retour : Version humainement lisible de la combinaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_scan_token_node_plain_get_modifier_path(const GScanTokenNodePlain *node, size_t index)
+{
+ char *result; /* Combinaison à retourner */
+
+ if (node->modifier == NULL)
+ result = strdup("plain");
+
+ else
+ result = g_scan_token_modifier_get_path(node->modifier, (size_t []){ index });
+
+ return result;
+
+
+}
+
+
/* ---------------------------------------------------------------------------------- */
/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
@@ -511,6 +540,7 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const
static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
{
bool initialized; /* Initialisation du suivi ? */
+ bool track_path; /* Conservation du chemin */
bool nocase; /* Pas d'intérêt pour la casse */
size_t ocount; /* Quantité de bornes présentes*/
size_t i; /* Boucle de parcours #1 */
@@ -531,6 +561,10 @@ static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *nod
initialized = are_pending_matches_initialized(matches);
+ track_path = (G_SCAN_TOKEN_NODE(node)->flags & STNF_MAIN);
+
+ assert((track_path && !initialized) || !track_path);
+
nocase = (node->flags & SPNF_CASE_INSENSITIVE);
get_node_search_offset_ranges(offset, &ocount);
@@ -568,12 +602,18 @@ static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *nod
status = check_scan_token_node_plain_content(raw, atom, nocase, new_begin, content);
if ((status && !not) || (!status && not))
+ {
/**
* Il ne peut y avoir qu'une seule séquence d'octets à un même
* emplacement, donc le couple (new_begin, len) enregistré est
* unique.
*/
- add_pending_match(matches, new_begin, raw->len);
+ if (track_path)
+ add_pending_match_with_path(matches, new_begin, raw->len, i);
+ else
+ add_pending_match(matches, new_begin, raw->len);
+
+ }
}
diff --git a/src/analysis/scan/patterns/tokens/nodes/plain.h b/src/analysis/scan/patterns/tokens/nodes/plain.h
index c8f3920..abf71de 100644
--- a/src/analysis/scan/patterns/tokens/nodes/plain.h
+++ b/src/analysis/scan/patterns/tokens/nodes/plain.h
@@ -75,6 +75,9 @@ GScanTokenNode *g_scan_token_node_plain_new(const sized_binary_t *, GScanTokenMo
/* Indique les propriétés particulières d'un noeud de texte. */
ScanPlainNodeFlags g_scan_token_node_plain_get_flags(const GScanTokenNodePlain *);
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+char *g_scan_token_node_plain_get_modifier_path(const GScanTokenNodePlain *, size_t);
+
#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_H */
diff --git a/src/analysis/scan/rule.c b/src/analysis/scan/rule.c
index 77a05b4..5826db9 100644
--- a/src/analysis/scan/rule.c
+++ b/src/analysis/scan/rule.c
@@ -623,6 +623,9 @@ void g_scan_rule_check(GScanRule *rule, GEngineBackend *backend, GScanContext *c
match = g_scan_bytes_match_new(G_SEARCH_PATTERN(pattern), content,
area->start, area->end - area->start);
+ if (area->has_mod_path)
+ g_scan_bytes_match_remember_modifier_path(G_SCAN_BYTES_MATCH(match), area->mod_path_index);
+
g_scan_context_register_full_match(context, match);
g_object_unref(G_OBJECT(match));