summaryrefslogtreecommitdiff
path: root/src/analysis/scan/patterns
diff options
context:
space:
mode:
Diffstat (limited to 'src/analysis/scan/patterns')
-rw-r--r--src/analysis/scan/patterns/token-int.h17
-rw-r--r--src/analysis/scan/patterns/token.c140
-rw-r--r--src/analysis/scan/patterns/token.h6
-rw-r--r--src/analysis/scan/patterns/tokens/Makefile.am1
-rw-r--r--src/analysis/scan/patterns/tokens/atom.c63
-rw-r--r--src/analysis/scan/patterns/tokens/atom.h5
-rw-r--r--src/analysis/scan/patterns/tokens/hex-int.h2
-rw-r--r--src/analysis/scan/patterns/tokens/hex.c210
-rw-r--r--src/analysis/scan/patterns/tokens/hex.h2
-rw-r--r--src/analysis/scan/patterns/tokens/node-int.h47
-rw-r--r--src/analysis/scan/patterns/tokens/node.c407
-rw-r--r--src/analysis/scan/patterns/tokens/node.h34
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/Makefile.am14
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/any-int.h60
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/any.c425
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/any.h58
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/choice-int.h (renamed from src/analysis/scan/patterns/tokens/nodes/hub-int.h)21
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/choice.c486
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/choice.h61
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/hub.c150
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/hub.h55
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/masked-int.h63
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/masked.c814
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/masked.h72
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/not-int.h57
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/not.c364
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/not.h59
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/plain-int.h4
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/plain.c244
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/plain.h16
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/sequence-int.h58
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/sequence.c360
-rw-r--r--src/analysis/scan/patterns/tokens/nodes/sequence.h61
-rw-r--r--src/analysis/scan/patterns/tokens/offset.c352
-rw-r--r--src/analysis/scan/patterns/tokens/offset.h101
-rw-r--r--src/analysis/scan/patterns/tokens/plain-int.h10
-rw-r--r--src/analysis/scan/patterns/tokens/plain.c257
-rw-r--r--src/analysis/scan/patterns/tokens/plain.h15
38 files changed, 4380 insertions, 791 deletions
diff --git a/src/analysis/scan/patterns/token-int.h b/src/analysis/scan/patterns/token-int.h
index 294a3b1..f1d63f0 100644
--- a/src/analysis/scan/patterns/token-int.h
+++ b/src/analysis/scan/patterns/token-int.h
@@ -32,19 +32,17 @@
-/* Inscrit la définition d'un motif dans un moteur de recherche. */
-typedef bool (* enroll_token_fc) (GStringToken *, GScanContext *, GEngineBackend *, size_t);
-
-/* Transforme les correspondances locales en trouvailles. */
-typedef void (* check_token_fc) (const GStringToken *, GScanContext *, GBinContent *, pending_matches_t *);
-
-
/* Encadrement d'une bribe de recherche textuelle (instance) */
struct _GStringToken
{
GSearchPattern parent; /* A laisser en premier */
GScanTokenNode *root; /* Motif à rechercher */
+ size_t slow; /* Surcoût du motif */
+ bool need_backward; /* Besoin d'une seconde passe */
+
+ bool fullword; /* Cible de mots entiers ? */
+ bool private; /* Vocation privée ? */
};
@@ -53,14 +51,11 @@ struct _GStringTokenClass
{
GSearchPatternClass parent; /* A laisser en premier */
- enroll_token_fc enroll; /* Inscription d'un motif */
- check_token_fc check; /* Conversion en trouvailles */
-
};
/* Met en place un gestionnaire de recherche de binaire. */
-bool g_string_token_create(GStringToken *, GScanTokenNode *);
+bool g_string_token_create(GStringToken *, GScanTokenNode *, bool, bool);
diff --git a/src/analysis/scan/patterns/token.c b/src/analysis/scan/patterns/token.c
index cc2d87a..1b2ee8a 100644
--- a/src/analysis/scan/patterns/token.c
+++ b/src/analysis/scan/patterns/token.c
@@ -25,6 +25,7 @@
#include <assert.h>
+#include <ctype.h>
#include <stdio.h>
@@ -116,6 +117,11 @@ static void g_string_token_class_init(GStringTokenClass *klass)
static void g_string_token_init(GStringToken *token)
{
token->root = NULL;
+ token->slow = 0;
+ token->need_backward = false;
+
+ token->fullword = false;
+ token->private = false;
}
@@ -160,8 +166,10 @@ static void g_string_token_finalize(GStringToken *token)
/******************************************************************************
* *
-* Paramètres : token = encadrement de motif à initialiser pleinement. *
-* root = représentation du motif à recherche. *
+* Paramètres : token = encadrement de motif à initialiser pleinement. *
+* root = représentation du motif à recherche. *
+* fullword = limite les correspondances à des mots entiers. *
+* private = donne une vocation privée au motif de recherche. *
* *
* Description : Met en place un gestionnaire de recherche de binaire. *
* *
@@ -171,7 +179,7 @@ static void g_string_token_finalize(GStringToken *token)
* *
******************************************************************************/
-bool g_string_token_create(GStringToken *token, GScanTokenNode *root)
+bool g_string_token_create(GStringToken *token, GScanTokenNode *root, bool fullword, bool private)
{
bool result; /* Bilan à retourner */
@@ -180,6 +188,9 @@ bool g_string_token_create(GStringToken *token, GScanTokenNode *root)
token->root = root;
g_object_ref(G_OBJECT(root));
+ token->fullword = fullword;
+ token->private = private;
+
return result;
}
@@ -187,39 +198,74 @@ bool g_string_token_create(GStringToken *token, GScanTokenNode *root)
/******************************************************************************
* *
-* Paramètres : token = définition de la bribe à enregistrer. *
-* context = contexte de l'analyse à mener. *
-* backend = moteur de recherche à préchauffer. *
-* maxsize = taille max. des atomes (mise en commun optimisée). *
+* Paramètres : token = encadrement de motif à consulter. *
* *
-* Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+* Description : Indique si seuls des mots entiers sont retenus des analyses. *
* *
-* Retour : Bilan de l'opération à renvoyer. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool g_string_token_enroll__old(GStringToken *token, GScanContext *context, GEngineBackend *backend, size_t maxsize)
+bool g_string_token_target_fullword(const GStringToken *token)
{
- bool result; /* Statut à retourner */
- GStringTokenClass *class; /* Classe de l'instance */
+ bool result; /* Statut à renvoyer */
+
+ result = token->fullword;
- assert(g_engine_backend_get_atom_max_size(backend) == maxsize);
+ return result;
- class = G_STRING_TOKEN_GET_CLASS(token);
+}
- result = class->enroll(token, context, backend, maxsize);
+
+/******************************************************************************
+* *
+* Paramètres : token = encadrement de motif à consulter. *
+* *
+* Description : Détermine si le gestionnaire est à vocation privée. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_string_token_is_private(const GStringToken *token)
+{
+ bool result; /* Statut à renvoyer */
+
+ result = token->private;
return result;
}
+
+/******************************************************************************
+* *
+* Paramètres : token = définition de la bribe à enregistrer. *
+* context = contexte de l'analyse à mener. *
+* backend = moteur de recherche à préchauffer. *
+* maxsize = taille max. des atomes (mise en commun optimisée). *
+* *
+* Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
bool g_string_token_enroll(GStringToken *token, GScanContext *context, GEngineBackend *backend, size_t maxsize)
{
bool result; /* Statut à retourner */
- result = g_scan_token_node_enroll(token->root, context, backend, maxsize);
+ token->need_backward = g_scan_token_node_setup_tree(token->root);
+
+ result = g_scan_token_node_enroll(token->root, context, backend, maxsize, &token->slow);
+
+ printf("need backward? %d\n", token->need_backward);
return result;
@@ -241,19 +287,59 @@ bool g_string_token_enroll(GStringToken *token, GScanContext *context, GEngineBa
* *
******************************************************************************/
-void g_string_token_check__old(const GStringToken *token, GScanContext *context, GBinContent *content, pending_matches_t *matches)
+void g_string_token_check(const GStringToken *token, GScanContext *context, GBinContent *content, pending_matches_t *matches)
{
- GStringTokenClass *class; /* Classe de l'instance */
+ size_t p; /* Boucle de parcours #3 */
+ match_area_t *pending; /* Correspondance à traiter */
+ vmpa2t pos; /* Tête de lecture */
+ const bin_t *byte; /* Octet à valider */
- class = G_STRING_TOKEN_GET_CLASS(token);
+ g_scan_token_node_check_forward(token->root, context, content, matches);
- class->check(token, context, content, matches);
+ if (token->need_backward)
+ g_scan_token_node_check_backward(token->root, context, content, matches);
-}
+ sort_and_filter_pending_matches(matches);
-void g_string_token_check(const GStringToken *token, GScanContext *context, GBinContent *content, pending_matches_t *matches)
-{
- g_scan_token_node_check(token->root, context, content, matches, NULL);
+ if (token->fullword)
+ {
+ reset_pending_matches_ttl(matches);
+
+ for (p = 0; p < matches->used; p++)
+ {
+ pending = &matches->areas[p];
+
+ /* Validation de l'octet précédent, s'il existe */
+ if (pending->start > matches->content_start)
+ {
+ init_vmpa(&pos, pending->start - 1, VMPA_NO_VIRTUAL);
+
+ byte = g_binary_content_get_raw_access(content, &pos, 1);
+
+ if (isalnum(*byte))
+ continue;
+
+ }
+
+ /* Validation de l'octet suivant, s'il existe */
+ if (pending->end < matches->content_end)
+ {
+ init_vmpa(&pos, pending->end, VMPA_NO_VIRTUAL);
+
+ byte = g_binary_content_get_raw_access(content, &pos, 1);
+
+ if (isalnum(*byte))
+ continue;
+
+ }
+
+ keep_pending_match(pending);
+
+ }
+
+ purge_pending_matches(matches);
+
+ }
}
@@ -284,6 +370,9 @@ static void g_string_token_output_to_text(const GStringToken *pattern, GScanCont
size_t count; /* Quantité de cette liste */
size_t i; /* Boucle de parcours */
+ if (g_string_token_is_private(pattern))
+ return;
+
matches = g_scan_context_get_full_matches(context, G_SEARCH_PATTERN(pattern), &count);
for (i = 0; i < count; i++)
@@ -318,6 +407,9 @@ static void g_string_token_output_to_json(const GStringToken *pattern, GScanCont
size_t k; /* Boucle de parcours #2 */
bool trailing; /* Virgule finale */
+ if (g_string_token_is_private(pattern))
+ return;
+
matches = g_scan_context_get_full_matches(context, G_SEARCH_PATTERN(pattern), &count);
/* Nombre de correspondances */
diff --git a/src/analysis/scan/patterns/token.h b/src/analysis/scan/patterns/token.h
index 879d912..b361ecc 100644
--- a/src/analysis/scan/patterns/token.h
+++ b/src/analysis/scan/patterns/token.h
@@ -52,6 +52,12 @@ typedef struct _GStringTokenClass GStringTokenClass;
/* Indique le type défini pour une bribe de recherche textuelle. */
GType g_string_token_get_type(void);
+/* Indique si seuls des mots entiers sont retenus des analyses. */
+bool g_string_token_target_fullword(const GStringToken *);
+
+/* Détermine si le gestionnaire est à vocation privée. */
+bool g_string_token_is_private(const GStringToken *);
+
/* Inscrit la définition d'un motif dans un moteur de recherche. */
bool g_string_token_enroll(GStringToken *, GScanContext *, GEngineBackend *, size_t);
diff --git a/src/analysis/scan/patterns/tokens/Makefile.am b/src/analysis/scan/patterns/tokens/Makefile.am
index 7fb515f..f0ab3d5 100644
--- a/src/analysis/scan/patterns/tokens/Makefile.am
+++ b/src/analysis/scan/patterns/tokens/Makefile.am
@@ -8,6 +8,7 @@ libanalysisscanpatternstokens_la_SOURCES = \
hex.h hex.c \
node-int.h \
node.h node.c \
+ offset.h offset.c \
plain-int.h \
plain.h plain.c
diff --git a/src/analysis/scan/patterns/tokens/atom.c b/src/analysis/scan/patterns/tokens/atom.c
index fcb585d..52f239c 100644
--- a/src/analysis/scan/patterns/tokens/atom.c
+++ b/src/analysis/scan/patterns/tokens/atom.c
@@ -251,6 +251,7 @@ void find_best_atom(const sized_binary_t *raw, size_t maxsize, tracked_scan_atom
/******************************************************************************
* *
* Paramètres : src = chaîne ed référence à dupliquer. *
+* atom = préselection opérée en amont. *
* count = nombre de lettres présentes. *
* *
* Description : Etablit la liste des cas de figures ignorant la casse. *
@@ -261,7 +262,7 @@ void find_best_atom(const sized_binary_t *raw, size_t maxsize, tracked_scan_atom
* *
******************************************************************************/
-sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, size_t count)
+sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, const tracked_scan_atom_t *atom, size_t count)
{
sized_binary_t *result; /* Liste à retourner */
size_t i; /* Boucle de parcours #1 */
@@ -274,16 +275,20 @@ sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, size_t co
size_t divisor; /* Taille de la découpe */
size_t quotient; /* Reste de la position */
- count *= 2;
-
/* Création du réceptacle */
result = malloc(count * sizeof(tracked_scan_atom_t));
+ assert(src->len == (atom->pos + atom->len + atom->rem));
+
for (i = 0; i < count; i++)
{
result[i].data = malloc(src->len);
result[i].len = src->len;
+
+ memcpy(result[i].data, src->data, atom->pos);
+ memcpy(&result[i].data[atom->pos + atom->len], &src->data[atom->pos + atom->len], atom->rem);
+
}
/* Remplissage */
@@ -294,7 +299,7 @@ sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, size_t co
check = 1;
#endif
- for (i = 0; i < src->len; i++)
+ for (i = atom->pos; i < (atom->pos + atom->len); i++)
{
ch = src->data[i];
@@ -315,8 +320,8 @@ sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, size_t co
replaced *= 2;
#ifndef NDEBUG
- check++;
- assert((check - 1) <= count);
+ check *= 2;
+ assert(check <= count);
#endif
}
@@ -326,7 +331,51 @@ sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, size_t co
}
- assert((check - 1) == count);
+ assert(check == count);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : byte = octet partiel à interpréter. *
+* mask = valeur du masque à appliquer. *
+* produced = nombre de contenus générés. [OUT] *
+* *
+* Description : Etablit la liste des cas de figures avec un octet partiel. *
+* *
+* Retour : Liste de toutes les combinaisons possibles. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+sized_binary_t *make_atoms_from_masked_byte(bin_t value, bin_t mask, size_t *produced)
+{
+ sized_binary_t *result; /* Liste à retourner */
+ size_t i; /* Boucle de parcours #1 */
+
+ *produced = 16;
+
+ /* Création du réceptacle */
+
+ result = malloc(16 * sizeof(tracked_scan_atom_t));
+
+ /* Remplissage */
+
+ for (i = 0; i < 16; i++)
+ {
+ result[i].data = malloc(1);
+ result[i].len = 1;
+
+ if (mask == 0x0f)
+ result[i].data[0] = value | (i << 4);
+ else
+ result[i].data[0] = value | i;
+
+ }
return result;
diff --git a/src/analysis/scan/patterns/tokens/atom.h b/src/analysis/scan/patterns/tokens/atom.h
index daa1f16..2fbc19e 100644
--- a/src/analysis/scan/patterns/tokens/atom.h
+++ b/src/analysis/scan/patterns/tokens/atom.h
@@ -58,7 +58,10 @@ int finish_quality_rating(const bitfield_t *, size_t);
void find_best_atom(const sized_binary_t *, size_t , tracked_scan_atom_t *, size_t *);
/* Etablit la liste des cas de figures ignorant la casse. */
-sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *, size_t);
+sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *, const tracked_scan_atom_t *, size_t);
+
+/* Etablit la liste des cas de figures avec un octet partiel. */
+sized_binary_t *make_atoms_from_masked_byte(bin_t, bin_t, size_t *);
/* Enregistre l'atome déterminé d'une série d'octets. */
bool enroll_prepared_atom(const sized_binary_t *, GScanContext *, GEngineBackend *, tracked_scan_atom_t *);
diff --git a/src/analysis/scan/patterns/tokens/hex-int.h b/src/analysis/scan/patterns/tokens/hex-int.h
index f0460c8..440f693 100644
--- a/src/analysis/scan/patterns/tokens/hex-int.h
+++ b/src/analysis/scan/patterns/tokens/hex-int.h
@@ -49,7 +49,7 @@ struct _GScanHexBytesClass
/* Met en place un gestionnaire de recherche de binaire. */
-bool g_scan_hex_bytes_create(GScanHexBytes *, GScanTokenNode *);
+bool g_scan_hex_bytes_create(GScanHexBytes *, GScanTokenNode *, bool);
diff --git a/src/analysis/scan/patterns/tokens/hex.c b/src/analysis/scan/patterns/tokens/hex.c
index c1cdbdf..1fda597 100644
--- a/src/analysis/scan/patterns/tokens/hex.c
+++ b/src/analysis/scan/patterns/tokens/hex.c
@@ -58,12 +58,6 @@ static void g_scan_hex_bytes_output_to_text(const GScanHexBytes *, GScanContext
/* Affiche un motif de recherche au format JSON. */
static void g_scan_hex_bytes_output_to_json(const GScanHexBytes *, GScanContext *, const sized_string_t *, unsigned int, int);
-/* Inscrit la définition d'un motif dans un moteur de recherche. */
-//static bool g_scan_hex_bytes_enroll(GScanHexBytes *, GScanContext *, GEngineBackend *, size_t);
-
-/* Transforme les correspondances locales en trouvailles. */
-//static void g_scan_hex_bytes_check(const GScanHexBytes *, GScanContext *, GBinContent *, pending_matches_t *);
-
/* ---------------------------------------------------------------------------------- */
@@ -91,7 +85,6 @@ static void g_scan_hex_bytes_class_init(GScanHexBytesClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
GSearchPatternClass *pattern; /* Version de classe ancêtre */
- GStringTokenClass *token; /* Version de classe parente */
object = G_OBJECT_CLASS(klass);
@@ -103,11 +96,6 @@ static void g_scan_hex_bytes_class_init(GScanHexBytesClass *klass)
pattern->to_text = (output_pattern_to_text_fc)g_scan_hex_bytes_output_to_text;
pattern->to_json = (output_pattern_to_json_fc)g_scan_hex_bytes_output_to_json;
- token = G_STRING_TOKEN_CLASS(klass);
-
- //token->enroll = (enroll_token_fc)g_scan_hex_bytes_enroll;
- //token->check = (check_token_fc)g_scan_hex_bytes_check;
-
}
@@ -170,6 +158,7 @@ static void g_scan_hex_bytes_finalize(GScanHexBytes *bytes)
/******************************************************************************
* *
* Paramètres : root = représentation du motif à recherche. *
+* private = donne une vocation privée au motif de recherche. *
* *
* Description : Construit un gestionnaire de recherche de texte brut. *
* *
@@ -179,13 +168,13 @@ static void g_scan_hex_bytes_finalize(GScanHexBytes *bytes)
* *
******************************************************************************/
-GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *root)
+GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *root, bool private)
{
GSearchPattern *result; /* Structure à retourner */
result = g_object_new(G_TYPE_SCAN_HEX_BYTES, NULL);
- if (!g_scan_hex_bytes_create(G_SCAN_HEX_BYTES(result), root))
+ if (!g_scan_hex_bytes_create(G_SCAN_HEX_BYTES(result), root, private))
g_clear_object(&result);
return result;
@@ -197,6 +186,7 @@ GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *root)
* *
* Paramètres : bytes = encadrement de motif à initialiser pleinement. *
* root = représentation du motif à recherche. *
+* private = donne une vocation privée au motif de recherche. *
* *
* Description : Met en place un gestionnaire de recherche de binaire. *
* *
@@ -206,11 +196,11 @@ GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *root)
* *
******************************************************************************/
-bool g_scan_hex_bytes_create(GScanHexBytes *bytes, GScanTokenNode *root)
+bool g_scan_hex_bytes_create(GScanHexBytes *bytes, GScanTokenNode *root, bool private)
{
bool result; /* Bilan à retourner */
- result = g_string_token_create(G_STRING_TOKEN(bytes), root);
+ result = g_string_token_create(G_STRING_TOKEN(bytes), root, false, private);
return result;
@@ -267,191 +257,3 @@ static void g_scan_hex_bytes_output_to_json(const GScanHexBytes *pattern, GScanC
/* TODO */
}
-
-#if 0
-
-/******************************************************************************
-* *
-* Paramètres : bytes = définition de la bribe à enregistrer. *
-* context = contexte de l'analyse à mener. *
-* backend = moteur de recherche à préchauffer. *
-* maxsize = taille max. des atomes (mise en commun optimisée). *
-* *
-* 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_hex_bytes_enroll(GScanHexBytes *bytes, GScanContext *context, GEngineBackend *backend, size_t maxsize)
-{
- bool result; /* Statut à retourner */
- size_t i; /* Boucle de parcours #1 */
- tracked_scan_atom_t atom; /* Atome identifié */
- size_t letters; /* Nombre de lettres présentes */
- size_t k; /* Boucle de parcours #2 */
- size_t extra_count; /* Quantité pour l'exhaustivité*/
- sized_binary_t *extra; /* Couverture supplémntaire */
- size_t remaining; /* Quantité restant à traiter */
-
- /* Génération d'une base de chaînes à couvrir */
-
- if (bytes->modifier == NULL)
- {
- bytes->raw = malloc(sizeof(sized_binary_t));
- bytes->count = 1;
-
- szstrdup(&bytes[0].raw[0], &bytes->orig);
-
- result = true;
-
- }
- else
- result = g_scan_token_modifier_transform(bytes->modifier, &bytes->orig, &bytes->raw, &bytes->count);
-
- if (!result)
- goto exit;
-
- /* Préparation pour la mémorisation des atomes */
-
- bytes->atoms = malloc(bytes->count * sizeof(tracked_scan_atom_t));
-
- /* Recherche des atomes */
-
- for (i = 0; i < bytes->count; i++)
- {
- if (bytes->flags & SPBF_CASE_INSENSITIVE)
- {
- find_best_atom(&bytes->raw[i], maxsize, &atom, &letters);
-
- if (letters == 0)
- bytes->atoms[i] = atom;
-
- /* Insertion des combinaisons pour couvrir toutes les casses */
- else
- {
- for (k = 0, extra_count = 1; k < letters; k++, extra_count *= 2)
- ;
-
- extra = make_atoms_case_insensitive(&bytes->raw[i], extra_count);
-
- remaining = bytes->count - i - 1;
-
- bytes->count += (extra_count - 1);
-
- bytes->raw = realloc(bytes->raw, bytes->count * sizeof(sized_binary_t));
-
- memmove(&bytes->raw[i + extra_count], &bytes->raw[i + 1], remaining * sizeof(sized_binary_t));
-
- for (k = 0; k < extra_count; k++)
- bytes->raw[i + k] = extra[k];
-
- free(extra);
-
- bytes->atoms = realloc(bytes->raw, bytes->count * sizeof(tracked_scan_atom_t));
-
- for (k = 0; k < extra_count; k++)
- bytes->atoms[i + k] = atom;
-
- i += extra_count - 1;
-
- }
-
- }
-
- else
- find_best_atom(&bytes->raw[i], maxsize, &bytes->atoms[i], &letters);
-
- }
-
- /* Enregistrements en masse */
-
-
- for (i = 0; i < bytes->count && result; i++)
- result = enroll_prepared_atom(&bytes->raw[i], context, backend, &bytes->atoms[i]);
-
- exit:
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : bytes = définition de la bribe à manipuler. *
-* context = contexte de l'analyse à mener. *
-* content = accès au contenu brut pour vérifications (optim.) *
-* matches = suivi des correspondances à consolider. *
-* *
-* Description : Transforme les correspondances locales en trouvailles. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_scan_hex_bytes_check(const GScanHexBytes *bytes, GScanContext *context, GBinContent *content, pending_matches_t *matches)
-{
- size_t i; /* Boucle de parcours #1 */
- const sized_binary_t *raw; /* Données brutes d'origine */
- const tracked_scan_atom_t *atom; /* Atome correspondant */
- size_t count; /* Quantité de bribes trouvées */
- const phys_t *found; /* Localisations des bribes */
- size_t k; /* Boucle de parcours #2 */
- phys_t start; /* Point de départ */
- vmpa2t pos; /* Position dans les données */
- const bin_t *ptr; /* Accès aux données brutes */
- int ret; /* Bilan d'une comparaison */
-
- for (i = 0; i < bytes->count; i++)
- {
- raw = &bytes->raw[i];
- atom = &bytes->atoms[i];
-
- found = g_scan_context_get_atom_matches(context, atom->pid, &count);
-
- for (k = 0; k < count; k++)
- {
- start = found[k] - atom->pos;
-
- init_vmpa(&pos, start, VMPA_NO_VIRTUAL);
-
- /* Validation du contenu avant l'atome */
-
- if (atom->pos > 0)
- {
- ptr = g_binary_content_get_raw_access(content, &pos, atom->pos);
-
- ret = memcmp(raw->data, ptr, atom->pos);
- if (ret != 0) continue;
-
- }
-
- /* Validation du contenu après l'atome */
-
- if (atom->rem > 0)
- {
- advance_vmpa(&pos, atom->len);
-
- ptr = g_binary_content_get_raw_access(content, &pos, atom->rem);
-
- ret = memcmp(raw->data + atom->pos + atom->len, ptr, atom->rem);
- if (ret != 0) continue;
-
- }
-
- /* Mémorisation de la correspondance */
-
- add_pending_matches(matches, start, raw->len);
-
- }
-
- }
-
-}
-
-#endif
diff --git a/src/analysis/scan/patterns/tokens/hex.h b/src/analysis/scan/patterns/tokens/hex.h
index 1db8eb6..fe5268c 100644
--- a/src/analysis/scan/patterns/tokens/hex.h
+++ b/src/analysis/scan/patterns/tokens/hex.h
@@ -52,7 +52,7 @@ typedef struct _GScanHexBytesClass GScanHexBytesClass;
GType g_scan_hex_bytes_get_type(void);
/* Construit un gestionnaire de recherche de texte brut. */
-GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *);
+GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *, bool);
diff --git a/src/analysis/scan/patterns/tokens/node-int.h b/src/analysis/scan/patterns/tokens/node-int.h
index c543cbf..091a5be 100644
--- a/src/analysis/scan/patterns/tokens/node-int.h
+++ b/src/analysis/scan/patterns/tokens/node-int.h
@@ -28,12 +28,33 @@
#include "node.h"
+#include "offset.h"
+
+
+
+/* Prend acte d'une nouvelle propriété pour le noeud. */
+typedef void (* apply_scan_token_node_flags_fc) (GScanTokenNode *, ScanTokenNodeFlags);
+
+/* Noeuds clefs de l'arborescence mise en place */
+typedef struct _scan_tree_points_t
+{
+ GScanTokenNode *first_node; /* Premier noeud de traitement */
+ GScanTokenNode *last_node; /* Dernier noeud de traitement */
+
+ GScanTokenNode *first_plain; /* Premier noeud textuel */
+ GScanTokenNode *best_masked; /* Noeud masqué le plus long */
+
+} scan_tree_points_t;
+
+
+/* Parcourt une arborescence de noeuds et y relève des éléments. */
+typedef void (* visit_scan_token_node_fc) (GScanTokenNode *, scan_tree_points_t *);
/* Inscrit la définition d'un motif dans un moteur de recherche. */
-typedef bool (* enroll_scan_token_node_fc) (GScanTokenNode *, GScanContext *, GEngineBackend *, size_t);
+typedef bool (* enroll_scan_token_node_fc) (GScanTokenNode *, GScanContext *, GEngineBackend *, size_t, size_t *);
/* Transforme les correspondances locales en trouvailles. */
-typedef void (* check_scan_token_node_fc) (const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, const node_search_offset_t *);
+typedef void (* check_scan_token_node_fc) (const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
/* Décomposition d'un motif de recherche en atomes (instance) */
@@ -41,6 +62,8 @@ struct _GScanTokenNode
{
GObject parent; /* A laisser en premier */
+ ScanTokenNodeFlags flags; /* Propriétés particulières */
+
};
/* Décomposition d'un motif de recherche en atomes (classe) */
@@ -48,11 +71,29 @@ struct _GScanTokenNodeClass
{
GObjectClass parent; /* A laisser en premier */
+ apply_scan_token_node_flags_fc apply; /* Prise en compte de fanions */
+
+ visit_scan_token_node_fc visit; /* Phase de répérage initial */
enroll_scan_token_node_fc enroll; /* Inscription d'un motif */
- check_scan_token_node_fc check; /* Conversion en trouvailles */
+
+ check_scan_token_node_fc check_forward; /* Conversion en trouvailles */
+ check_scan_token_node_fc check_backward;/* Conversion en trouvailles */
};
+/* Parcourt une arborescence de noeuds et y relève des éléments. */
+void g_scan_token_node_visit(GScanTokenNode *, scan_tree_points_t *);
+
+/* Inscrit la définition d'un motif dans un moteur de recherche. */
+bool _g_scan_token_node_enroll(GScanTokenNode *, GScanContext *, GEngineBackend *, size_t, size_t *);
+
+/* Transforme les correspondances locales en trouvailles. */
+void _g_scan_token_node_check_forward(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+void _g_scan_token_node_check_backward(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+
#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/node.c b/src/analysis/scan/patterns/tokens/node.c
index 224328a..1354fff 100644
--- a/src/analysis/scan/patterns/tokens/node.c
+++ b/src/analysis/scan/patterns/tokens/node.c
@@ -28,6 +28,7 @@
#include "node-int.h"
+#include "nodes/any.h"
@@ -35,7 +36,7 @@
/* Initialise la classe des éléments de décomposition. */
-static void g_scan_token_node_class_init(GScanTokenNodeClass *klass);
+static void g_scan_token_node_class_init(GScanTokenNodeClass *);
/* Initialise une instance d'élément décomposant un motif. */
static void g_scan_token_node_init(GScanTokenNode *);
@@ -95,6 +96,7 @@ static void g_scan_token_node_class_init(GScanTokenNodeClass *klass)
static void g_scan_token_node_init(GScanTokenNode *node)
{
+ node->flags = STNF_NONE;
}
@@ -139,10 +141,148 @@ static void g_scan_token_node_finalize(GScanTokenNode *node)
/******************************************************************************
* *
+* Paramètres : node = noeud de motif à consulter. *
+* *
+* Description : Indique les propriétés particulières d'un noeud d'analyse. *
+* *
+* Retour : Propriétés particulières associées au noeud. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+ScanTokenNodeFlags g_scan_token_node_get_flags(const GScanTokenNode *node)
+{
+ ScanTokenNodeFlags result; /* Statut à retourner */
+
+ result = node->flags;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud de motif à mettre à jour. *
+* flags = propriétés particulières à associer au noeud. *
+* *
+* Description : Marque le noeud avec des propriétés particulières. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_set_flags(GScanTokenNode *node, ScanTokenNodeFlags flags)
+{
+ GScanTokenNodeClass *class; /* Classe de l'instance */
+
+ node->flags |= flags;
+
+ class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+
+ if (class->apply != NULL)
+ class->apply(node, flags);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = point de départ du parcours à effectuer. *
+* points = points capitaux de l'arborescence. [OUT] *
+* *
+* Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_visit(GScanTokenNode *node, scan_tree_points_t *points)
+{
+ GScanTokenNodeClass *class; /* Classe de l'instance */
+
+ if (node->flags & STNF_PROD)
+ {
+ if (points->first_node == NULL)
+ points->first_node = node;
+
+ points->last_node = node;
+
+ }
+
+ class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+
+ if (class->visit != NULL)
+ class->visit(node, points);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = point de départ du parcours à préparer. *
+* *
+* Description : Détermine et prépare les éléments clefs d'une arborescence. *
+* *
+* Retour : true si une analyse à rebourd complémentaire est requise. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_node_setup_tree(GScanTokenNode *node)
+{
+ bool result; /* Prévision à retourner */
+ scan_tree_points_t points; /* Repérage de points capitaux */
+ GScanTokenNode *main; /* Principal noeud d'opération */
+
+ /* Phase de localisation */
+
+ points.first_node = NULL;
+ points.last_node = NULL;
+
+ points.first_plain = NULL;
+ points.best_masked = NULL;
+
+ g_scan_token_node_visit(node, &points);
+
+ /* Phase d'application */
+
+ //g_scan_token_node_set_flags(points.first_node, STNF_FIRST);
+ //g_scan_token_node_set_flags(points.last_node, STNF_LAST);
+
+ if (points.first_plain != NULL)
+ main = points.first_plain;
+
+ else if (points.best_masked != NULL)
+ main = points.best_masked;
+
+ else
+ main = node;//points.first_node;
+
+ g_scan_token_node_set_flags(main, STNF_MAIN);
+
+ printf("main : %p (%s)\n", main, G_OBJECT_TYPE_NAME(main));
+
+ result = (main != node/*points.first_node*/);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : node = définition de la bribe à enregistrer. *
* context = contexte de l'analyse à mener. *
* 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.*
* *
@@ -152,16 +292,45 @@ static void g_scan_token_node_finalize(GScanTokenNode *node)
* *
******************************************************************************/
-bool g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngineBackend *backend, size_t maxsize)
+bool _g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
{
bool result; /* Statut à retourner */
GScanTokenNodeClass *class; /* Classe de l'instance */
+ class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+
+ result = class->enroll(node, context, backend, maxsize, slow);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à enregistrer. *
+* context = contexte de l'analyse à mener. *
+* 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 : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+ bool result; /* Statut à retourner */
+
assert(g_engine_backend_get_atom_max_size(backend) == maxsize);
- class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+ *slow = 0;
- result = class->enroll(node, context, backend, maxsize);
+ result = _g_scan_token_node_enroll(node, context, backend, maxsize, slow);
return result;
@@ -175,6 +344,8 @@ bool g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngi
* content = accès au contenu brut pour vérifications (optim.) *
* matches = suivi des correspondances à consolider. *
* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* skip = détermine si l'analyse est différée. [OUT] *
* *
* Description : Transforme les correspondances locales en trouvailles. *
* *
@@ -184,12 +355,236 @@ bool g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngi
* *
******************************************************************************/
-void g_scan_token_node_check(const GScanTokenNode *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, const node_search_offset_t *offset)
+void _g_scan_token_node_check_forward(const GScanTokenNode *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
{
GScanTokenNodeClass *class; /* Classe de l'instance */
+ if (node->flags & STNF_MAIN)
+ {
+ //assert(*skip); //REMME
+ *skip = false;
+ }
+
+ printf("Checking forward... node=%p / %s skip=%d main=%u\n",
+ node, G_OBJECT_TYPE_NAME(node), *skip, (node->flags & STNF_MAIN) == STNF_MAIN);
+
class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
- class->check(node, context, content, matches, offset);
+ class->check_forward(node, context, content, matches, offset, not, skip);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* context = contexte de l'analyse à mener. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* matches = suivi des correspondances à consolider. *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_check_forward(const GScanTokenNode *node, GScanContext *context, GBinContent *content, pending_matches_t *matches)
+{
+ node_search_offset_t offset; /* Espace des correspondances */
+ bool skip; /* Mise en attente des analyses*/
+ size_t ocount; /* Quantité de bornes présentes*/
+ node_offset_range_t * const *ranges_ptr;/* Bornes d'espace à parcourir */
+ size_t pcount; /* Nombre de correspondances */
+ match_area_t * const *pending_ptr; /* Correspondances actuelles */
+ size_t p; /* Boucle de parcours #2 */
+ match_area_t *pending; /* Correspondance à traiter */
+ phys_t old_end; /* Ancien point d'arrivée */
+ size_t o; /* Boucle de parcours #1 */
+ const node_offset_range_t *range; /* Bornes d'espace à parcourir */
+ phys_t new_end; /* Nouveau point d'arrivée */
+
+ init_node_search_offset(&offset);
+
+ skip = true;
+
+ _g_scan_token_node_check_forward(node, context, content, matches, &offset, false, &skip);
+
+ /**
+ * Si un décalage entre octets n'a pas été consommé,
+ * les résultats sont étendus à minima.
+ */
+
+ ranges_ptr = get_node_search_offset_ranges(&offset, &ocount);
+
+ if (ocount > 0)
+ {
+ reset_pending_matches_ttl(matches);
+
+ pending_ptr = get_all_pending_matches(matches, &pcount);
+
+ for (p = 0; p < pcount; p++)
+ {
+ pending = (*pending_ptr) + p;
+
+ old_end = pending->end;
+
+ for (o = 0; o < ocount; o++)
+ {
+ range = (*ranges_ptr) + o;
+
+ new_end = old_end + range->min;
+
+ if (new_end > matches->content_end)
+ new_end = matches->content_end;
+
+ extend_pending_match_ending(matches, p, new_end);
+
+ }
+
+ }
+
+ /**
+ * Pas besoin de purge ici puisque tous les résultats ont été traités
+ * au moins une fois, sans condition.
+ */
+ /* purge_pending_matches(matches); */
+
+ disable_all_ranges_in_node_search_offset(&offset);
+
+ }
+
+ assert(offset.used == 0);
+
+ exit_node_search_offset(&offset);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* context = contexte de l'analyse à mener. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* matches = suivi des correspondances à consolider. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* skip = détermine si l'analyse est différée. [OUT] *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void _g_scan_token_node_check_backward(const GScanTokenNode *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+ GScanTokenNodeClass *class; /* Classe de l'instance */
+
+ printf("Checking backward... node=%p / %s skip=%d main=%u\n",
+ node, G_OBJECT_TYPE_NAME(node), *skip, (node->flags & STNF_MAIN) == STNF_MAIN);
+
+ class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+
+ class->check_backward(node, context, content, matches, offset, not, skip);
+
+ if (node->flags & STNF_MAIN)
+ {
+ //assert(*skip); //REMME
+ *skip = false;
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* context = contexte de l'analyse à mener. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* matches = suivi des correspondances à consolider. *
+* *
+* Description : Transforme les correspondances locales en trouvailles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_check_backward(const GScanTokenNode *node, GScanContext *context, GBinContent *content, pending_matches_t *matches)
+{
+ node_search_offset_t offset; /* Espace des correspondances */
+ bool skip; /* Mise en attente des analyses*/
+ size_t ocount; /* Quantité de bornes présentes*/
+ node_offset_range_t * const *ranges_ptr;/* Bornes d'espace à parcourir */
+ size_t pcount; /* Nombre de correspondances */
+ match_area_t * const *pending_ptr; /* Correspondances actuelles */
+ size_t p; /* Boucle de parcours #2 */
+ match_area_t *pending; /* Correspondance à traiter */
+ phys_t old_start; /* Ancien point d'arrivée */
+ size_t o; /* Boucle de parcours #1 */
+ const node_offset_range_t *range; /* Bornes d'espace à parcourir */
+ phys_t new_start; /* Nouveau point d'arrivée */
+
+ init_node_search_offset(&offset);
+
+ skip = true;
+
+ _g_scan_token_node_check_backward(node, context, content, matches, &offset, false, &skip);
+
+ /**
+ * Si un décalage entre octets n'a pas été consommé,
+ * les résultats sont étendus à minima.
+ */
+
+ ranges_ptr = get_node_search_offset_ranges(&offset, &ocount);
+
+ if (ocount > 0)
+ {
+ reset_pending_matches_ttl(matches);
+
+ pending_ptr = get_all_pending_matches(matches, &pcount);
+
+ for (p = 0; p < pcount; p++)
+ {
+ pending = (*pending_ptr) + p;
+
+ old_start = pending->start;
+
+ for (o = 0; o < ocount; o++)
+ {
+ range = (*ranges_ptr) + o;
+
+ if (old_start < range->min)
+ new_start = 0;
+ else
+ new_start = old_start - range->min;
+
+ if (new_start < matches->content_start)
+ new_start = matches->content_start;
+
+ extend_pending_match_beginning(matches, p, new_start);
+
+ }
+
+ }
+
+ /**
+ * Pas besoin de purge ici puisque tous les résultats ont été traités
+ * au moins une fois, sans condition.
+ */
+ /* purge_pending_matches(matches); */
+
+ disable_all_ranges_in_node_search_offset(&offset);
+
+ }
+
+ assert(offset.used == 0);
+
+ exit_node_search_offset(&offset);
}
diff --git a/src/analysis/scan/patterns/tokens/node.h b/src/analysis/scan/patterns/tokens/node.h
index 4c9eb48..a2e3b0d 100644
--- a/src/analysis/scan/patterns/tokens/node.h
+++ b/src/analysis/scan/patterns/tokens/node.h
@@ -49,28 +49,38 @@ typedef struct _GScanTokenNode GScanTokenNode;
typedef struct _GScanTokenNodeClass GScanTokenNodeClass;
+/* Propriétés particulières pour noeud d'analyse */
+typedef enum _ScanTokenNodeFlags
+{
+ STNF_NONE = (0 << 0), /* Absence de singularité */
+ STNF_PROD = (1 << 0), /* Absence de singularité */
+ STNF_FIRST = (1 << 1), /* Premier noeud de traitement */ /* REMME ? */
+ STNF_LAST = (1 << 2), /* Dernier noeud de traitement */ /* REMME ? */
+ STNF_MAIN = (1 << 3), /* Point de départ d'analyse */
+
+} ScanTokenNodeFlags;
+
+
/* Indique le type défini pour un élément décomposant un motif d'octets à rechercher. */
GType g_scan_token_node_get_type(void);
+/* Indique les propriétés particulières d'un noeud d'analyse. */
+ScanTokenNodeFlags g_scan_token_node_get_flags(const GScanTokenNode *);
-// TODO
-// validate
-// force_plain_registration // set begin/end
+/* Marque le noeud avec des propriétés particulières. */
+void g_scan_token_node_set_flags(GScanTokenNode *, ScanTokenNodeFlags);
+/* Détermine et prépare les éléments clefs d'une arborescence. */
+bool g_scan_token_node_setup_tree(GScanTokenNode *);
/* Inscrit la définition d'un motif dans un moteur de recherche. */
-bool g_scan_token_node_enroll(GScanTokenNode *, GScanContext *, GEngineBackend *, size_t);
+bool g_scan_token_node_enroll(GScanTokenNode *, GScanContext *, GEngineBackend *, size_t, size_t *);
-/* Mémorisation d'une souplesse dans les positions visées */
-typedef struct _node_search_offset_t
-{
- phys_t min; /* Position minimale */
- phys_t max; /* Position maxnimale */
-
-} node_search_offset_t;
+/* Transforme les correspondances locales en trouvailles. */
+void g_scan_token_node_check_forward(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *);
/* Transforme les correspondances locales en trouvailles. */
-void g_scan_token_node_check(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, const node_search_offset_t *);
+void g_scan_token_node_check_backward(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *);
diff --git a/src/analysis/scan/patterns/tokens/nodes/Makefile.am b/src/analysis/scan/patterns/tokens/nodes/Makefile.am
index c20beaf..b5da1ee 100644
--- a/src/analysis/scan/patterns/tokens/nodes/Makefile.am
+++ b/src/analysis/scan/patterns/tokens/nodes/Makefile.am
@@ -3,10 +3,18 @@ noinst_LTLIBRARIES = libanalysisscanpatternstokensnodes.la
libanalysisscanpatternstokensnodes_la_SOURCES = \
- hub-int.h \
- hub.h hub.c \
+ any-int.h \
+ any.h any.c \
+ choice-int.h \
+ choice.h choice.c \
+ masked-int.h \
+ masked.h masked.c \
+ not-int.h \
+ not.h not.c \
plain-int.h \
- plain.h plain.c
+ plain.h plain.c \
+ sequence-int.h \
+ sequence.h sequence.c
libanalysisscanpatternstokensnodes_la_CFLAGS = $(LIBGOBJ_CFLAGS)
diff --git a/src/analysis/scan/patterns/tokens/nodes/any-int.h b/src/analysis/scan/patterns/tokens/nodes/any-int.h
new file mode 100644
index 0000000..705aab3
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/any-int.h
@@ -0,0 +1,60 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * any-int.h - prototypes internes pour une 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/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_INT_H
+
+
+#include "any.h"
+
+
+#include "../atom.h"
+#include "../node-int.h"
+
+
+
+/* Espace constitué d'un ou plusieurs octets quelconques (instance) */
+struct _GScanTokenNodeAny
+{
+ GScanTokenNode parent; /* A laisser en premier */
+
+ phys_t min; /* Quantité minimale */
+ phys_t max; /* Quantité maximale */
+ bool has_max; /* Quantité définie ? */
+
+};
+
+/* Espace constitué d'un ou plusieurs octets quelconques (classe) */
+struct _GScanTokenNodeAnyClass
+{
+ GScanTokenNodeClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un un noeud pointant une série d'octets. */
+bool g_scan_token_node_any_create(GScanTokenNodeAny *, const phys_t *, const phys_t *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_INT_H */
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..af2ae29
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/any.c
@@ -0,0 +1,425 @@
+
+/* 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 *, GScanContext *, GEngineBackend *, size_t, size_t *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_any_check_backward(const GScanTokenNodeAny *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, 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->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)
+{
+ g_scan_token_node_set_flags(G_SCAN_TOKEN_NODE(any), STNF_PROD);
+
+ 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 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);
+
+ }
+
+ any->has_max = (max != NULL);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à enregistrer. *
+* context = contexte de l'analyse à mener. *
+* 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, GScanContext *context, 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. *
+* context = contexte de l'analyse à mener. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* matches = suivi des correspondances à consolider. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+ bool initialized; /* Initialisation du suivi ? */
+ bool forced; /* Inclusion dans un scan ? */
+ phys_t size; /* Quantité d'octets considérés*/
+ const phys_t *datasize; /* Taille max. à communiquer */
+
+ if (*skip)
+ return;
+
+
+ // $a = { [1-3] 6f }
+ // pas d'initialisation, construction de résultats avec une taille nulle
+
+
+
+ initialized = are_pending_matches_initialized(matches);
+
+ forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
+
+ size = matches->content_end - matches->content_start;
+
+ datasize = (not ? &size : NULL);
+
+ if (forced)
+ {
+ assert(!initialized);
+
+ if (node->min > size)
+ /* TODO set abort in matches */;
+
+ else
+ add_range_to_node_search_offset(offset,
+ matches->content_start,
+ matches->content_end - matches->content_start,
+ datasize);
+
+ }
+ else
+ {
+ assert(initialized);
+
+
+ // TODO : compléter les intervales éventuels déjà en place
+
+
+ printf("[i] create hole: %llx <-> %llx\n",
+ (unsigned long long)node->min,
+ (unsigned long long)node->max);
+
+
+
+ if (node->has_max)
+ add_range_to_node_search_offset(offset, node->min, node->max, datasize);
+ else
+ add_range_to_node_search_offset(offset, node->min, matches->content_end - node->min, datasize);
+
+ // TODO : si dernier, virer les correspondances qui n'ont plus l'espace de fin requis
+ // -> au niveau du noeud, en fonction du flag _LAST
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* context = contexte de l'analyse à mener. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* matches = suivi des correspondances à consolider. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+#ifndef NDEBUG
+ bool forced; /* Inclusion dans un scan ? */
+#endif
+ phys_t size; /* Quantité d'octets considérés*/
+ const phys_t *datasize; /* Taille max. à communiquer */
+
+ if (*skip)
+ return;
+
+ /**
+ * En lecture à rebourd, au moins un noeud a été solicité pour analyse (lors
+ * du sens de lecteur normal). Donc l'initialisation a déjà dû avoir lieu.
+ */
+ assert(are_pending_matches_initialized(matches));
+
+ /**
+ * 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 = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
+ assert(!forced);
+#endif
+
+ size = matches->content_end - matches->content_start;
+
+ if (node->min > size)
+ /* TODO set abort in matches */;
+
+ else
+ {
+ datasize = (not ? &size : NULL);
+
+ /**
+ * Une tolérance basée sur des espaces (et non des positions) est déterminée
+ * ici.
+ *
+ * Charge au prochain noeud de traitement de filtrer les résultats courants
+ * avec, voire à la fonction _g_scan_token_node_check_backward() de
+ * réaliser une synthèse finale si le noeud courant est le dernier d'une
+ * lignée.
+ */
+
+ if (node->has_max)
+ add_range_to_node_search_offset(offset, node->min, node->max, datasize);
+ else
+ add_range_to_node_search_offset(offset, node->min, matches->content_end - node->min, datasize);
+
+ }
+
+}
diff --git a/src/analysis/scan/patterns/tokens/nodes/any.h b/src/analysis/scan/patterns/tokens/nodes/any.h
new file mode 100644
index 0000000..6a5628a
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/any.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * any.h - prototypes pour une 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/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_H
+
+
+#include <glib-object.h>
+
+
+#include "../node.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_NODE_ANY g_scan_token_node_any_get_type()
+#define G_SCAN_TOKEN_NODE_ANY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_ANY, GScanTokenNodeAny))
+#define G_IS_SCAN_TOKEN_NODE_ANY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_ANY))
+#define G_SCAN_TOKEN_NODE_ANY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_ANY, GScanTokenNodeAnyClass))
+#define G_IS_SCAN_TOKEN_NODE_ANY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_ANY))
+#define G_SCAN_TOKEN_NODE_ANY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_ANY, GScanTokenNodeAnyClass))
+
+
+/* Espace constitué d'un ou plusieurs octets quelconques (instance) */
+typedef struct _GScanTokenNodeAny GScanTokenNodeAny;
+
+/* Espace constitué d'un ou plusieurs octets quelconques (classe) */
+typedef struct _GScanTokenNodeAnyClass GScanTokenNodeAnyClass;
+
+
+/* Indique le type défini pour une série d'octets quelconque, vide ou non. */
+GType g_scan_token_node_any_get_type(void);
+
+/* Construit un noeud pointant une série d'octets quelconques. */
+GScanTokenNode *g_scan_token_node_any_new(const phys_t *, const phys_t *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/hub-int.h b/src/analysis/scan/patterns/tokens/nodes/choice-int.h
index df05112..77a4058 100644
--- a/src/analysis/scan/patterns/tokens/nodes/hub-int.h
+++ b/src/analysis/scan/patterns/tokens/nodes/choice-int.h
@@ -1,6 +1,6 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * hub-int.h - prototypes internes pour un groupe de décompositions de motif de recherche en atomes assemblés
+ * choice-int.h - prototypes internes pour des décompositions alternatives de motif de recherche
*
* Copyright (C) 2023 Cyrille Bagard
*
@@ -21,26 +21,29 @@
*/
-#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_INT_H
-#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_INT_H
+#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_INT_H
-#include "hub.h"
+#include "choice.h"
#include "../node-int.h"
-/* Groupe de décompositions de motif de recherche en atomes (instance) */
-struct _GScanTokenNodeHub
+/* Décompositions alternatives de motif de recherche (instance) */
+struct _GScanTokenNodeChoice
{
GScanTokenNode parent; /* A laisser en premier */
+ GScanTokenNode **children; /* Sous-noeuds à représenter */
+ size_t count; /* Taille de cette liste */
+
};
-/* Groupe de décompositions de motif de recherche en atomes (classe) */
-struct _GScanTokenNodeHubClass
+/* Décompositions alternatives de motif de recherche (classe) */
+struct _GScanTokenNodeChoiceClass
{
GScanTokenNodeClass parent; /* A laisser en premier */
@@ -48,4 +51,4 @@ struct _GScanTokenNodeHubClass
-#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_INT_H */
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/choice.c b/src/analysis/scan/patterns/tokens/nodes/choice.c
new file mode 100644
index 0000000..df6ae45
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/choice.c
@@ -0,0 +1,486 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * choice.c - décompositions alternatives de motif de recherche
+ *
+ * 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 "choice.h"
+
+
+#include "choice-int.h"
+
+
+
+/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
+
+
+/* Initialise la classe des décompositions alternatives. */
+static void g_scan_token_node_choice_class_init(GScanTokenNodeChoiceClass *);
+
+/* Initialise une instance de décompositions alternatives. */
+static void g_scan_token_node_choice_init(GScanTokenNodeChoice *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_node_choice_dispose(GScanTokenNodeChoice *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_node_choice_finalize(GScanTokenNodeChoice *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Prend acte d'une nouvelle propriété pour le noeud. */
+static void g_scan_token_node_choice_apply_flags(GScanTokenNodeChoice *, ScanTokenNodeFlags);
+
+/* Parcourt une arborescence de noeuds et y relève des éléments. */
+static void g_scan_token_node_choice_visit(GScanTokenNodeChoice *, scan_tree_points_t *);
+
+/* Inscrit la définition d'un motif dans un moteur de recherche. */
+static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *, GScanContext *, GEngineBackend *, size_t, size_t *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_choice_check_forward(const GScanTokenNodeChoice *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_choice_check_backward(const GScanTokenNodeChoice *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DECOMPOSITION DE MOTIF RECHERCHE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour des décompositions alternatives de motif de recherche. */
+G_DEFINE_TYPE(GScanTokenNodeChoice, g_scan_token_node_choice, G_TYPE_SCAN_TOKEN_NODE);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des décompositions alternatives. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_choice_class_init(GScanTokenNodeChoiceClass *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_choice_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_token_node_choice_finalize;
+
+ node = G_SCAN_TOKEN_NODE_CLASS(klass);
+
+ node->apply = (apply_scan_token_node_flags_fc)g_scan_token_node_choice_apply_flags;
+ node->visit = (visit_scan_token_node_fc)g_scan_token_node_choice_visit;
+ node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_choice_enroll;
+ node->check_forward = (check_scan_token_node_fc)g_scan_token_node_choice_check_forward;
+ node->check_backward = (check_scan_token_node_fc)g_scan_token_node_choice_check_backward;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : choice = instance à initialiser. *
+* *
+* Description : Initialise une instance de décompositions alternatives. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_choice_init(GScanTokenNodeChoice *choice)
+{
+ choice->children = NULL;
+ choice->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : choice = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_choice_dispose(GScanTokenNodeChoice *choice)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < choice->count; i++)
+ g_clear_object(&choice->children[i]);
+
+ G_OBJECT_CLASS(g_scan_token_node_choice_parent_class)->dispose(G_OBJECT(choice));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : choice = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_choice_finalize(GScanTokenNodeChoice *choice)
+{
+ if (choice->children != NULL)
+ free(choice->children);
+
+ G_OBJECT_CLASS(g_scan_token_node_choice_parent_class)->finalize(G_OBJECT(choice));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Construit une série de décompositions alternatives de motif. *
+* *
+* Retour : Mécanismes mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenNode *g_scan_token_node_choice_new(void)
+{
+ GScanTokenNode *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_CHOICE, NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : choice = ensemble de noeuds à compléter. *
+* node = nouveau noeud à intégrer. *
+* *
+* Description : Ajoute un noeud à aux décompositions alternatives de motif. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_choice_add(GScanTokenNodeChoice *choice, GScanTokenNode *node)
+{
+ choice->children = realloc(choice->children, ++choice->count * sizeof(GScanTokenNode *));
+
+ choice->children[choice->count - 1] = node;
+ g_object_ref(G_OBJECT(node));
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud de motif à mettre à jour. *
+* flags = propriétés particulières à associer au noeud. *
+* *
+* Description : Prend acte d'une nouvelle propriété pour le noeud. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_choice_apply_flags(GScanTokenNodeChoice *node, ScanTokenNodeFlags flags)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < node->count; i++)
+ g_scan_token_node_set_flags(node->children[i], flags);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = point de départ du parcours à effectuer. *
+* points = points capitaux de l'arborescence. [OUT] *
+* *
+* Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_choice_visit(GScanTokenNodeChoice *node, scan_tree_points_t *points)
+{
+ size_t first_plain_count; /* Décompte de noeuds textuels */
+ size_t i; /* Boucle de parcours */
+ scan_tree_points_t tmp_points; /* Synthèse d'analyse locale */
+
+ if (points->first_plain != NULL)
+ return;
+
+ first_plain_count = 0;
+
+ for (i = 0; i < node->count; i++)
+ {
+ tmp_points.first_node = NULL;
+ tmp_points.last_node = NULL;
+
+ tmp_points.first_plain = NULL;
+ tmp_points.best_masked = NULL;
+
+ g_scan_token_node_visit(node->children[i], &tmp_points);
+
+ if (tmp_points.first_plain != NULL)
+ first_plain_count++;
+
+ }
+
+ if (first_plain_count == node->count)
+ points->first_plain = G_SCAN_TOKEN_NODE(node);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à enregistrer. *
+* context = contexte de l'analyse à mener. *
+* 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_choice_enroll(GScanTokenNodeChoice *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+ bool result; /* Statut à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = true;
+
+ for (i = 0; i < node->count && result; i++)
+ result = _g_scan_token_node_enroll(node->children[i], context, backend, maxsize, slow);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* context = contexte de l'analyse à mener. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* matches = suivi des correspondances à consolider. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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_choice_check_forward(const GScanTokenNodeChoice *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+ pending_matches_t init_matches; /* Correspondances initiales */
+ node_search_offset_t init_offset; /* Intervales initiaux */
+ size_t new_offset; /* Décompte d'intervales */
+ size_t i; /* Boucle de parcours */
+ pending_matches_t tmp_matches; /* Copie locale de travail #1 */
+ node_search_offset_t tmp_offset; /* Copie locale de travail #2 */
+
+ if (*skip)
+ return;
+
+ /* Copie des contextes de départ */
+
+ copy_pending_matches(&init_matches, matches);
+
+ exit_pending_matches(matches);
+ init_pending_matches(matches, &init_matches.content_start, &init_matches.content_end);
+
+ copy_node_search_offset(&init_offset, offset);
+
+ exit_node_search_offset(offset);
+ init_node_search_offset(offset);
+
+ /* Lancement des sous-traitements */
+
+ new_offset = 0;
+
+ for (i = 0; i < node->count; i++)
+ {
+ copy_pending_matches(&tmp_matches, &init_matches);
+ copy_node_search_offset(&tmp_offset, &init_offset);
+
+ _g_scan_token_node_check_forward(node->children[i], context, content,
+ &tmp_matches, &tmp_offset, not, skip);
+
+ merge_pending_matches(matches, &tmp_matches);
+ merge_node_search_offset(offset, &tmp_offset);
+
+ if (tmp_offset.used > 0)
+ new_offset++;
+
+ exit_pending_matches(&tmp_matches);
+ exit_node_search_offset(&tmp_offset);
+
+ }
+
+ /* Sortie propre */
+
+ exit_pending_matches(&init_matches);
+ exit_node_search_offset(&init_offset);
+
+ /* "Alternative" directe en cas de motif(s) non terminé(s) par un intervale */
+
+ if (new_offset != node->count)
+ {
+ assert(node->count > 1);
+ add_range_to_node_search_offset(offset, 0, 0, NULL);
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* context = contexte de l'analyse à mener. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* matches = suivi des correspondances à consolider. *
+* offsets = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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_choice_check_backward(const GScanTokenNodeChoice *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+ pending_matches_t init_matches; /* Correspondances initiales */
+ node_search_offset_t init_offset; /* Intervales initiaux */
+ size_t new_offset; /* Décompte d'intervales */
+ size_t i; /* Boucle de parcours */
+ pending_matches_t tmp_matches; /* Copie locale de travail #1 */
+ node_search_offset_t tmp_offset; /* Copie locale de travail #2 */
+
+ if (*skip)
+ return;
+
+ /* Copie des contextes de départ */
+
+ copy_pending_matches(&init_matches, matches);
+
+ exit_pending_matches(matches);
+ init_pending_matches(matches, &init_matches.content_start, &init_matches.content_end);
+
+ copy_node_search_offset(&init_offset, offset);
+
+ exit_node_search_offset(offset);
+ init_node_search_offset(offset);
+
+ /* Lancement des sous-traitements */
+
+ new_offset = 0;
+
+ for (i = 0; i < node->count; i++)
+ {
+ copy_pending_matches(&tmp_matches, &init_matches);
+ copy_node_search_offset(&tmp_offset, &init_offset);
+
+ _g_scan_token_node_check_backward(node->children[i], context, content,
+ &tmp_matches, &tmp_offset, not, skip);
+
+ merge_pending_matches(matches, &tmp_matches);
+ merge_node_search_offset(offset, &tmp_offset);
+
+ if (tmp_offset.used > 0)
+ new_offset++;
+
+ exit_pending_matches(&tmp_matches);
+ exit_node_search_offset(&tmp_offset);
+
+ }
+
+ /* Sortie propre */
+
+ exit_pending_matches(&init_matches);
+ exit_node_search_offset(&init_offset);
+
+ /* "Alternative" directe en cas de motif(s) non terminé(s) par un intervale */
+
+ if (new_offset != node->count)
+ {
+ assert(node->count > 1);
+ add_range_to_node_search_offset(offset, 0, 0, NULL);
+ }
+
+}
diff --git a/src/analysis/scan/patterns/tokens/nodes/choice.h b/src/analysis/scan/patterns/tokens/nodes/choice.h
new file mode 100644
index 0000000..e793b1e
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/choice.h
@@ -0,0 +1,61 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * choice.h - prototypes pour des décompositions alternatives de motif de recherche
+ *
+ * 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_PATTERNS_TOKENS_NODES_CHOICE_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_H
+
+
+#include <glib-object.h>
+
+
+#include "../node.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_NODE_CHOICE g_scan_token_node_choice_get_type()
+#define G_SCAN_TOKEN_NODE_CHOICE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_CHOICE, GScanTokenNodeChoice))
+#define G_IS_SCAN_TOKEN_NODE_CHOICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_CHOICE))
+#define G_SCAN_TOKEN_NODE_CHOICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_CHOICE, GScanTokenNodeChoiceClass))
+#define G_IS_SCAN_TOKEN_NODE_CHOICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_CHOICE))
+#define G_SCAN_TOKEN_NODE_CHOICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_CHOICE, GScanTokenNodeChoiceClass))
+
+
+/* Décompositions alternatives de motif de recherche (instance) */
+typedef struct _GScanTokenNodeChoice GScanTokenNodeChoice;
+
+/* Décompositions alternatives de motif de recherche (classe) */
+typedef struct _GScanTokenNodeChoiceClass GScanTokenNodeChoiceClass;
+
+
+/* Indique le type défini pour des décompositions alternatives de motif de recherche. */
+GType g_scan_token_node_choice_get_type(void);
+
+/* Construit une série de décompositions alternatives de motif. */
+GScanTokenNode *g_scan_token_node_choice_new(void);
+
+/* Ajoute un noeud à aux décompositions alternatives de motif. */
+void g_scan_token_node_choice_add(GScanTokenNodeChoice *, GScanTokenNode *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/hub.c b/src/analysis/scan/patterns/tokens/nodes/hub.c
deleted file mode 100644
index a11531d..0000000
--- a/src/analysis/scan/patterns/tokens/nodes/hub.c
+++ /dev/null
@@ -1,150 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * hub.c - groupe de décompositions de motif de recherche en atomes assemblés
- *
- * 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 "hub.h"
-
-
-#include "hub-int.h"
-
-
-
-/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
-
-
-/* Initialise la classe des groupes de décompositions. */
-static void g_scan_token_node_hub_class_init(GScanTokenNodeHubClass *klass);
-
-/* Initialise une instance de groupe de décompositions. */
-static void g_scan_token_node_hub_init(GScanTokenNodeHub *);
-
-/* Supprime toutes les références externes. */
-static void g_scan_token_node_hub_dispose(GScanTokenNodeHub *);
-
-/* Procède à la libération totale de la mémoire. */
-static void g_scan_token_node_hub_finalize(GScanTokenNodeHub *);
-
-
-
-/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
-
-
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* DECOMPOSITION DE MOTIF RECHERCHE */
-/* ---------------------------------------------------------------------------------- */
-
-
-/* Indique le type défini pour un groupe de décompositions de motif d'octets à rechercher. */
-G_DEFINE_TYPE(GScanTokenNodeHub, g_scan_token_node_hub, G_TYPE_SCAN_TOKEN_NODE);
-
-
-/******************************************************************************
-* *
-* Paramètres : klass = classe à initialiser. *
-* *
-* Description : Initialise la classe des groupes de décompositions. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_scan_token_node_hub_class_init(GScanTokenNodeHubClass *klass)
-{
- GObjectClass *object; /* Autre version de la classe */
-
- object = G_OBJECT_CLASS(klass);
-
- object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_hub_dispose;
- object->finalize = (GObjectFinalizeFunc)g_scan_token_node_hub_finalize;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : hub = instance à initialiser. *
-* *
-* Description : Initialise une instance de groupe de décompositions. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_scan_token_node_hub_init(GScanTokenNodeHub *hub)
-{
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : hub = instance d'objet GLib à traiter. *
-* *
-* Description : Supprime toutes les références externes. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_scan_token_node_hub_dispose(GScanTokenNodeHub *hub)
-{
- G_OBJECT_CLASS(g_scan_token_node_hub_parent_class)->dispose(G_OBJECT(hub));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : hub = instance d'objet GLib à traiter. *
-* *
-* Description : Procède à la libération totale de la mémoire. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_scan_token_node_hub_finalize(GScanTokenNodeHub *hub)
-{
- G_OBJECT_CLASS(g_scan_token_node_hub_parent_class)->finalize(G_OBJECT(hub));
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
-/* ---------------------------------------------------------------------------------- */
-
-
-
-
diff --git a/src/analysis/scan/patterns/tokens/nodes/hub.h b/src/analysis/scan/patterns/tokens/nodes/hub.h
deleted file mode 100644
index b2cb0fc..0000000
--- a/src/analysis/scan/patterns/tokens/nodes/hub.h
+++ /dev/null
@@ -1,55 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * hub.h - prototypes pour un groupe de décompositions de motif de recherche en atomes assemblés
- *
- * 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_PATTERNS_TOKENS_NODES_HUB_H
-#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_H
-
-
-#include <glib-object.h>
-
-
-#include "../node.h"
-
-
-
-#define G_TYPE_SCAN_TOKEN_NODE_HUB g_scan_token_node_hub_get_type()
-#define G_SCAN_TOKEN_NODE_HUB(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_HUB, GScanTokenNodeHub))
-#define G_IS_SCAN_TOKEN_NODE_HUB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_HUB))
-#define G_SCAN_TOKEN_NODE_HUB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_HUB, GScanTokenNodeHubClass))
-#define G_IS_SCAN_TOKEN_NODE_HUB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_HUB))
-#define G_SCAN_TOKEN_NODE_HUB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_HUB, GScanTokenNodeHubClass))
-
-
-/* Groupe de décompositions de motif de recherche en atomes (instance) */
-typedef struct _GScanTokenNodeHub GScanTokenNodeHub;
-
-/* Groupe de décompositions de motif de recherche en atomes (classe) */
-typedef struct _GScanTokenNodeHubClass GScanTokenNodeHubClass;
-
-
-/* Indique le type défini pour un groupe de décompositions de motif d'octets à rechercher. */
-GType g_scan_token_node_hub_get_type(void);
-
-
-
-#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/masked-int.h b/src/analysis/scan/patterns/tokens/nodes/masked-int.h
new file mode 100644
index 0000000..9eb8712
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/masked-int.h
@@ -0,0 +1,63 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * masked-int.h - prototypes internes pour la gestion d'une recherche de motif partielle
+ *
+ * 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_PATTERNS_TOKENS_NODES_MASKED_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_INT_H
+
+
+#include "masked.h"
+
+
+#include "../node-int.h"
+
+
+
+/* Bribe de motif partielle pour recherches (instance) */
+struct _GScanTokenNodeMasked
+{
+ GScanTokenNode parent; /* A laisser en premier */
+
+ masked_byte_t *bytes; /* Série d'octets masqués */
+ size_t len; /* Taille de cette série */
+
+ sized_binary_t *raw; /* Liste de motifs à couvrir */
+ tracked_scan_atom_t *atoms; /* Atomes correspondants */
+ size_t count; /* Taille de cette liste */
+ size_t enrolled_count; /* Quantité avec identifiant */
+
+};
+
+/* Bribe de motif partielle pour recherches (classe) */
+struct _GScanTokenNodeMaskedClass
+{
+ GScanTokenNodeClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une bribe de motif partielle. */
+bool g_scan_token_node_masked_create(GScanTokenNodeMasked *, const masked_byte_t *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/masked.c b/src/analysis/scan/patterns/tokens/nodes/masked.c
new file mode 100644
index 0000000..25f0315
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/masked.c
@@ -0,0 +1,814 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * masked.c - gestion d'une recherche de motif partielle
+ *
+ * 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 "masked.h"
+
+
+#include <assert.h>
+
+
+#include "masked-int.h"
+#include "../../backends/bitap.h"
+
+
+
+/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
+
+
+/* Initialise la classe des bribes de motif partielles. */
+static void g_scan_token_node_masked_class_init(GScanTokenNodeMaskedClass *);
+
+/* Initialise une instance de bribe de motif partielle. */
+static void g_scan_token_node_masked_init(GScanTokenNodeMasked *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_node_masked_dispose(GScanTokenNodeMasked *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_node_masked_finalize(GScanTokenNodeMasked *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Parcourt une arborescence de noeuds et y relève des éléments. */
+static void g_scan_token_node_masked_visit(GScanTokenNodeMasked *, scan_tree_points_t *);
+
+/* Inscrit la définition d'un motif dans un moteur de recherche. */
+static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *, GScanContext *, GEngineBackend *, size_t, size_t *);
+
+/* Détermine si un contenu d'intérêt est présent à une position. */
+static bool check_scan_token_node_masked_content(const masked_byte_t *, size_t, phys_t, GBinContent *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DECOMPOSITION DE MOTIF RECHERCHE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un noeud représentant une bribe partielle à retrouver. */
+G_DEFINE_TYPE(GScanTokenNodeMasked, g_scan_token_node_masked, G_TYPE_SCAN_TOKEN_NODE);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des bribes de motif partielles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_masked_class_init(GScanTokenNodeMaskedClass *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_masked_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_token_node_masked_finalize;
+
+ node = G_SCAN_TOKEN_NODE_CLASS(klass);
+
+ node->visit = (visit_scan_token_node_fc)g_scan_token_node_masked_visit;
+ node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_masked_enroll;
+ node->check_forward = (check_scan_token_node_fc)g_scan_token_node_masked_check_forward;
+ node->check_backward = (check_scan_token_node_fc)g_scan_token_node_masked_check_backward;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : masked = instance à initialiser. *
+* *
+* Description : Initialise une instance de bribe de motif partielle. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_masked_init(GScanTokenNodeMasked *masked)
+{
+ g_scan_token_node_set_flags(G_SCAN_TOKEN_NODE(masked), STNF_PROD);
+
+ masked->bytes = NULL;
+ masked->len = 0;
+
+ masked->raw = NULL;
+ masked->atoms = NULL;
+ masked->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : masked = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_masked_dispose(GScanTokenNodeMasked *masked)
+{
+ G_OBJECT_CLASS(g_scan_token_node_masked_parent_class)->dispose(G_OBJECT(masked));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : masked = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_masked_finalize(GScanTokenNodeMasked *masked)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (masked->bytes != NULL)
+ free(masked->bytes);
+
+ for (i = 0; i < masked->count; i++)
+ exit_szstr(&masked->raw[i]);
+
+ if (masked->raw != NULL)
+ free(masked->raw);
+
+ if (masked->atoms != NULL)
+ free(masked->atoms);
+
+ G_OBJECT_CLASS(g_scan_token_node_masked_parent_class)->finalize(G_OBJECT(masked));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : byte = valeur masquée à intégrer. *
+* *
+* Description : Construit une bribe de motif partielle. *
+* *
+* Retour : Mécanismes mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenNode *g_scan_token_node_masked_new(const masked_byte_t *byte)
+{
+ GScanTokenNode *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_MASKED, NULL);
+
+ if (!g_scan_token_node_masked_create(G_SCAN_TOKEN_NODE_MASKED(result), byte))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : masked = bribe partielle à initialiser pleinement. *
+* byte = valeur masquée à intégrer. *
+* *
+* Description : Met en place une bribe de motif partielle. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_node_masked_create(GScanTokenNodeMasked *masked, const masked_byte_t *byte)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ g_scan_token_node_masked_add(masked, byte);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : masked = ensemble de noeuds à compléter. *
+* byte = valeur masquée à intégrer. *
+* *
+* Description : Enregistre la valeur d'octet à rechercher avec son masque. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_masked_add(GScanTokenNodeMasked *masked, const masked_byte_t *byte)
+{
+ assert((byte->value & 0x0f) == 0 || (byte->value & 0xf0) == 0);
+
+ masked->bytes = realloc(masked->bytes, ++masked->len * sizeof(masked_byte_t));
+
+ masked->bytes[masked->len - 1] = *byte;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : node = point de départ du parcours à effectuer. *
+* points = points capitaux de l'arborescence. [OUT] *
+* *
+* Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_masked_visit(GScanTokenNodeMasked *node, scan_tree_points_t *points)
+{
+ GScanTokenNodeMasked *other; /* Concurrence à mesurer */
+
+ if (points->best_masked == NULL)
+ points->best_masked = G_SCAN_TOKEN_NODE(node);
+
+ else
+ {
+ other = G_SCAN_TOKEN_NODE_MASKED(points->best_masked);
+
+ if (node->len > other->len)
+ points->best_masked = G_SCAN_TOKEN_NODE(node);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à enregistrer. *
+* context = contexte de l'analyse à mener. *
+* 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_masked_enroll(GScanTokenNodeMasked *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+ bool result; /* Statut à retourner */
+ bool forced; /* Inclusion dans un scan ? */
+ //size_t len_to_enroll; /* Taille à considérer */
+ size_t i; /* Boucle de parcours */
+
+ result = true;
+
+ forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
+
+ if (forced)
+ {
+ *slow += (maxsize * 2);
+
+ /**
+ * Dans le cas bien précis de l'usage de l'algorithme Bitap pour les recherches
+ * dans le contenu binaire à analyser, on tire parti du coût nul des recherches
+ * multiples pour une même position.
+ */
+
+ if (G_IS_BITAP_BACKEND(backend))
+ {
+ //len_to_enroll = (node->len < maxsize ? node->len : maxsize);
+
+ /* TODO */
+ assert(false);
+
+
+ node->enrolled_count = 1;
+
+ }
+
+ else
+ {
+ node->raw = make_atoms_from_masked_byte(node->bytes[0].value, node->bytes[0].mask, &node->count);
+
+ node->atoms = malloc(node->count * sizeof(tracked_scan_atom_t));
+
+ for (i = 0; i < node->count && result; i++)
+ {
+ find_best_atom(&node->raw[i], maxsize, &node->atoms[i], NULL);
+
+ result = enroll_prepared_atom(&node->raw[i], context, backend, &node->atoms[i]);
+
+ }
+
+ node->enrolled_count = node->count;
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : bytes = octets partiels avec leur masque à interpréter. *
+* len = quantité d'octets à interpréter. *
+* start = point d'analyse à respecter. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* *
+* Description : Détermine si un contenu d'intérêt est présent à une position.*
+* *
+* Retour : Bilan de l'analyse : true pour une correspondance. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool check_scan_token_node_masked_content(const masked_byte_t *bytes, size_t len, phys_t start, GBinContent *content)
+{
+ bool result; /* Bilan à retourner */
+ vmpa2t pos; /* Position dans les données */
+ const bin_t *ptr; /* Accès aux données brutes */
+ size_t i; /* Boucle de parcours */
+
+ result = false;
+
+ init_vmpa(&pos, start, VMPA_NO_VIRTUAL);
+
+ ptr = g_binary_content_get_raw_access(content, &pos, len);
+
+ for (i = 0; i < len; i++)
+ {
+ if ((ptr[i] & bytes[i].mask) != bytes[i].value)
+ break;
+ }
+
+ result = (i == len);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* context = contexte de l'analyse à mener. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* matches = suivi des correspondances à consolider. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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_masked_check_forward(const GScanTokenNodeMasked *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+ bool initialized; /* Initialisation du suivi ? */
+#ifndef NDEBUG
+ bool forced; /* Inclusion dans un scan ? */
+#endif
+ size_t ocount; /* Quantité de bornes présentes*/
+ node_offset_range_t * const *ranges_ptr;/* Bornes d'espace à parcourir */
+ size_t i; /* Boucle de parcours #1 */
+ const tracked_scan_atom_t *atom; /* Atome correspondant */
+ size_t count; /* Quantité de bribes trouvées */
+ const phys_t *found; /* Localisations des bribes */
+ size_t k; /* Boucle de parcours #2 */
+ phys_t new_begin; /* Nouveau départ à tester */
+ size_t o; /* Boucle de parcours #3 */
+ const node_offset_range_t *range; /* Bornes d'espace à parcourir */
+ bool status; /* Bilan d'une correspondance */
+ size_t pcount; /* Nombre de correspondances */
+ match_area_t * const *pending_ptr; /* Correspondances actuelles */
+ size_t p; /* Boucle de parcours #4 */
+ match_area_t *pending; /* Correspondance à traiter */
+ phys_t after; /* Espace disposible après */
+ phys_t min; /* Borne minimale déterminée */
+ phys_t max; /* Borne maximale déterminée */
+ phys_t j; /* Boucle de parcours #5 */
+
+ if (*skip)
+ return;
+
+ initialized = are_pending_matches_initialized(matches);
+
+ /**
+ * Si l'analyse arrive à un ou plusieurs octets masqués, soit il s'agit du
+ * premier noeud, et la génération d'atomes a été forcée pour obtenir des
+ * points de départ, soit des correspondances ont été établies au préalable,
+ * et il ne doit alors pas y avoir d'atome mis en place (si l'initialisation
+ * ne provient pas d'une mise en place artificielle par une inversion NOT).
+ */
+#ifndef NDEBUG
+ forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
+ assert((!initialized && forced) || (initialized && (!forced || not)));
+#endif
+
+ ranges_ptr = get_node_search_offset_ranges(offset, &ocount);
+
+ /* Si aucune correspondance n'a été établie */
+ if (!initialized)
+ {
+ for (i = 0; i < node->enrolled_count; i++)
+ {
+ atom = &node->atoms[i];
+
+ found = g_scan_context_get_atom_matches(context, atom->pid, &count);
+
+ for (k = 0; k < count; k++)
+ {
+ assert(atom->pos == 0);
+
+ new_begin = found[k];
+
+ /**
+ * Si des bornes sont spécifiées, la position de l'atome est testée.
+ *
+ * Dans la pratique, cette situation (non initialisée) ne peut provenir
+ * que d'un espace situé dans le vide, donc couvrant un large périmètre.
+ * La validation a ainsi de grandes chances de passer...
+ *
+ * Le motif pouvant amener à cette situation (pas d'initialisation,
+ * mais à décalage à considérer) est par exemple :
+ *
+ * ~( ?? ?1 )
+ *
+ */
+ if (ocount > 0)
+ {
+ if (!does_node_search_offset_include_pos_forward(offset, 0, new_begin))
+ continue;
+ }
+
+ /**
+ * Existe-t-il assez de place pour faire tenir le motif masqué ?
+ */
+ if ((new_begin + node->len) > matches->content_end)
+ continue;
+
+ status = check_scan_token_node_masked_content(node->bytes, node->len, 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 (start, len) enregistré est
+ * unique.
+ */
+ add_pending_match(matches, new_begin, node->len);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /* Si les correspondances en place sont à confirmer et compléter */
+ else
+ {
+ reset_pending_matches_ttl(matches);
+
+ pending_ptr = get_all_pending_matches(matches, &pcount);
+
+ for (p = 0; p < pcount; p++)
+ {
+ pending = (*pending_ptr) + p;
+
+ assert(pending->end <= matches->content_end);
+
+ after = matches->content_end - pending->end;
+
+ new_begin = pending->end;
+
+ if (ocount > 0)
+ {
+ for (o = 0; o < ocount; o++)
+ {
+ range = (*ranges_ptr) + o;
+
+ /**
+ * Si bornes de tolérance il y a, l'espace restant est validé en
+ * tenant compte de ces bornes.
+ */
+ if (!get_node_offset_range(range, node->len, after, &min, &max))
+ continue;
+
+ /**
+ * Une recherche des différentes correspondances amont est lancée.
+ */
+ for (j = min; j <= max; j++)
+ {
+ status = check_scan_token_node_masked_content(node->bytes, node->len,
+ new_begin + j, content);
+
+ if ((status && !not) || (!status && not))
+ {
+ /**
+ * S'il s'avère qu'il existe de multiples correspondances dans l'espace
+ * analysé, c'est la fonction extend_pending_match_ending() qui
+ * duplique cette correspondance, en s'appuyant sur le TTL pour
+ * repérer ce cas de figure.
+ *
+ * Par exemple, deux correspondances '?1 ?1 [1-3] ?2 ?2'
+ * sont valides pour un même contenu :
+ *
+ * aa.bbb -> correspondance 'aa.bb'
+ * ^
+ *
+ * aa.bbb -> correspondance 'aa..bb'
+ * ^
+ */
+ extend_pending_match_ending(matches, p, new_begin + j + node->len);
+
+ /**
+ * Comme l'extension a pu conduire à un ajout et donc à une
+ * réallocation de la liste, on recharge l'élément pour les
+ * itérations suivantes.
+ */
+ pending = (*pending_ptr) + p;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ else
+ {
+ /**
+ * Si la fin d'une correspondance potentielle est trop près de
+ * la fin du contenu binaire et ne peut contenir le motif
+ * représenté, alors la corresponance est écartée.
+ */
+ if (node->len > after)
+ continue;
+
+ new_begin = pending->end;
+
+ status = check_scan_token_node_masked_content(node->bytes, node->len, new_begin, content);
+
+ if ((status && !not) || (!status && not))
+ {
+ extend_pending_match_ending(matches, p, new_begin + node->len);
+
+ /**
+ * Comme il n'y a qu'une seule itération par correspondance,
+ * nul besoin de recharcher l'élément.
+ */
+
+ }
+
+ }
+
+ }
+
+ purge_pending_matches(matches);
+
+ }
+
+ set_pending_matches_initialized(matches);
+
+ disable_all_ranges_in_node_search_offset(offset);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* context = contexte de l'analyse à mener. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* matches = suivi des correspondances à consolider. *
+* offsets = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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_masked_check_backward(const GScanTokenNodeMasked *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+#ifndef NDEBUG
+ bool forced; /* Inclusion dans un scan ? */
+#endif
+ size_t pcount; /* Nombre de correspondances */
+ match_area_t * const *pending_ptr; /* Correspondances actuelles */
+ size_t ocount; /* Quantité de bornes présentes*/
+ node_offset_range_t * const *ranges_ptr;/* Bornes d'espace à parcourir */
+ size_t p; /* Boucle de parcours #1 */
+ const match_area_t *pending; /* Correspondance à traiter */
+ phys_t before; /* Espace disposible avant */
+ phys_t new_begin; /* Nouveau départ à tester */
+ size_t o; /* Boucle de parcours #2 */
+ const node_offset_range_t *range; /* Bornes d'espace à parcourir */
+ phys_t min; /* Borne minimale déterminée */
+ phys_t max; /* Borne maximale déterminée */
+ phys_t j; /* Boucle de parcours #3 */
+ bool status; /* Bilan d'une correspondance */
+
+ if (*skip)
+ return;
+
+ /**
+ * En lecture à rebourd, au moins un noeud a été solicité pour analyse (lors
+ * du sens de lecteur normal). Donc l'initialisation a déjà dû avoir lieu.
+ */
+ assert(are_pending_matches_initialized(matches));
+
+ /**
+ * 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 = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
+ assert(!forced);
+#endif
+
+ reset_pending_matches_ttl(matches);
+
+ pending_ptr = get_all_pending_matches(matches, &pcount);
+
+ ranges_ptr = get_node_search_offset_ranges(offset, &ocount);
+
+ for (p = 0; p < pcount; p++)
+ {
+ pending = (*pending_ptr) + p;
+
+ assert(matches->content_start <= pending->start);
+
+ before = pending->start - matches->content_start;
+
+ printf(" (masked) pending: %u - len=%u\n",
+ (unsigned int)pending->start, (unsigned int)node->len);
+
+ new_begin = pending->start - node->len;
+
+ if (ocount > 0)
+ {
+ for (o = 0; o < ocount; o++)
+ {
+ range = (*ranges_ptr) + o;
+
+ /**
+ * Si bornes de tolérance il y a, l'espace restant est validé en
+ * tenant compte de ces bornes.
+ */
+ if (!get_node_offset_range(range, node->len, before, &min, &max))
+ {
+ if (not)
+ extend_pending_match_beginning(matches, p, pending->start - node->len);
+
+ continue;
+
+ }
+
+ /**
+ * Une recherche des différentes correspondances amont est lancée.
+ */
+ for (j = min; j <= max; j++)
+ {
+ status = check_scan_token_node_masked_content(node->bytes, node->len,
+ new_begin - j, content);
+
+ if ((status && !not) || (!status && not))
+ {
+ /**
+ * S'il s'avère qu'il existe de multiples correspondances dans l'espace
+ * analysé, c'est la fonction extend_pending_match_beginning() qui
+ * duplique cette correspondance, en s'appuyant sur le TTL pour
+ * repérer ce cas de figure.
+ */
+ extend_pending_match_beginning(matches, p, new_begin);
+
+ /**
+ * Comme l'extension a pu conduire à un ajout et donc à une
+ * réallocation de la liste, on recharge l'élément pour les
+ * itérations suivantes.
+ */
+ pending = (*pending_ptr) + p;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ else
+ {
+ /**
+ * Si le début d'une correspondance potentielle est trop près du début
+ * du contenu binaire et ne peut contenir le motif représenté, alors
+ * la corresponance est écartée.
+ */
+ if (node->len > before)
+ {
+ if (not)
+ extend_pending_match_beginning(matches, p, new_begin);
+
+ continue;
+
+ }
+
+ status = check_scan_token_node_masked_content(node->bytes, node->len, new_begin, content);
+
+ printf(" (masked) found new @ %llx ? %d\n",
+ (unsigned long long)new_begin, status);
+
+
+ if ((status && !not) || (!status && not))
+ extend_pending_match_beginning(matches, p, new_begin);
+
+ }
+
+ }
+
+ purge_pending_matches(matches);
+
+ disable_all_ranges_in_node_search_offset(offset);
+
+}
diff --git a/src/analysis/scan/patterns/tokens/nodes/masked.h b/src/analysis/scan/patterns/tokens/nodes/masked.h
new file mode 100644
index 0000000..d1765fa
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/masked.h
@@ -0,0 +1,72 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * masked.h - prototypes pour la gestion d'une recherche de motif partielle
+ *
+ * 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_PATTERNS_TOKENS_NODES_MASKED_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_H
+
+
+#include <glib-object.h>
+
+
+#include "../atom.h"
+#include "../node.h"
+#include "../../../../../arch/archbase.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_NODE_MASKED g_scan_token_node_masked_get_type()
+#define G_SCAN_TOKEN_NODE_MASKED(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_MASKED, GScanTokenNodeMasked))
+#define G_IS_SCAN_TOKEN_NODE_MASKED(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_MASKED))
+#define G_SCAN_TOKEN_NODE_MASKED_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_MASKED, GScanTokenNodeMaskedClass))
+#define G_IS_SCAN_TOKEN_NODE_MASKED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_MASKED))
+#define G_SCAN_TOKEN_NODE_MASKED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_MASKED, GScanTokenNodeMaskedClass))
+
+
+/* Bribe de motif partielle pour recherches (instance) */
+typedef struct _GScanTokenNodeMasked GScanTokenNodeMasked;
+
+/* Bribe de motif partielle pour recherches (classe) */
+typedef struct _GScanTokenNodeMaskedClass GScanTokenNodeMaskedClass;
+
+
+/* Mémorisation d'un octet visé avec son masque */
+typedef struct _masked_byte_t
+{
+ bin_t value; /* Valeur de l'octet visé */
+ bin_t mask; /* Masque à appliquer */
+
+} masked_byte_t;
+
+
+/* Indique le type défini pour un noeud représentant une bribe partielle à retrouver. */
+GType g_scan_token_node_masked_get_type(void);
+
+/* Construit une bribe de motif partielle. */
+GScanTokenNode *g_scan_token_node_masked_new(const masked_byte_t *);
+
+/* Enregistre la valeur d'octet à rechercher avec son masque. */
+void g_scan_token_node_masked_add(GScanTokenNodeMasked *, const masked_byte_t *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/not-int.h b/src/analysis/scan/patterns/tokens/nodes/not-int.h
new file mode 100644
index 0000000..5f92afd
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/not-int.h
@@ -0,0 +1,57 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * not-int.h - prototypes internes pour l'inversion de résultats de correspondances établis
+ *
+ * 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_PATTERNS_TOKENS_NODES_NOT_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_INT_H
+
+
+#include "not.h"
+
+
+#include "../node-int.h"
+
+
+
+/* Inversion de résultats de correspondances établis (instance) */
+struct _GScanTokenNodeNot
+{
+ GScanTokenNode parent; /* A laisser en premier */
+
+ GScanTokenNode *child; /* Sous-noeud à considérer */
+
+};
+
+/* Inversion de résultats de correspondances établis (classe) */
+struct _GScanTokenNodeNotClass
+{
+ GScanTokenNodeClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une inversion de résultats de correspondances. */
+bool g_scan_token_node_not_create(GScanTokenNodeNot *, GScanTokenNode *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/not.c b/src/analysis/scan/patterns/tokens/nodes/not.c
new file mode 100644
index 0000000..c54a66f
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/not.c
@@ -0,0 +1,364 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * not.c - inversion de résultats de correspondances établis
+ *
+ * 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 "not.h"
+
+
+#include "not-int.h"
+
+
+
+/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
+
+
+/* Initialise la classe des inversions de correspondances. */
+static void g_scan_token_node_not_class_init(GScanTokenNodeNotClass *);
+
+/* Initialise une instance d'inversion de correspondances. */
+static void g_scan_token_node_not_init(GScanTokenNodeNot *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_node_not_dispose(GScanTokenNodeNot *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_node_not_finalize(GScanTokenNodeNot *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Parcourt une arborescence de noeuds et y relève des éléments. */
+static void g_scan_token_node_not_visit(GScanTokenNodeNot *, scan_tree_points_t *);
+
+/* Inscrit la définition d'un motif dans un moteur de recherche. */
+static bool g_scan_token_node_not_enroll(GScanTokenNodeNot *, GScanContext *, GEngineBackend *, size_t, size_t *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_not_check_backward(const GScanTokenNodeNot *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DECOMPOSITION DE MOTIF RECHERCHE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une inversion des résultats de correspondances. */
+G_DEFINE_TYPE(GScanTokenNodeNot, g_scan_token_node_not, G_TYPE_SCAN_TOKEN_NODE);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des inversions de correspondances. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_not_class_init(GScanTokenNodeNotClass *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_not_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_token_node_not_finalize;
+
+ node = G_SCAN_TOKEN_NODE_CLASS(klass);
+
+ node->visit = (visit_scan_token_node_fc)g_scan_token_node_not_visit;
+ node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_not_enroll;
+ node->check_forward = (check_scan_token_node_fc)g_scan_token_node_not_check_forward;
+ node->check_backward = (check_scan_token_node_fc)g_scan_token_node_not_check_backward;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : not = instance à initialiser. *
+* *
+* Description : Initialise une instance d'inversion de correspondances. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_not_init(GScanTokenNodeNot *not)
+{
+ not->child = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : not = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_not_dispose(GScanTokenNodeNot *not)
+{
+ g_clear_object(&not->child);
+
+ G_OBJECT_CLASS(g_scan_token_node_not_parent_class)->dispose(G_OBJECT(not));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : not = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_not_finalize(GScanTokenNodeNot *not)
+{
+ G_OBJECT_CLASS(g_scan_token_node_not_parent_class)->finalize(G_OBJECT(not));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : child = noeud dont les résultats sont à écarter. *
+* *
+* Description : Construit une inversion de résultats de correspondances. *
+* *
+* Retour : Mécanismes mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenNode *g_scan_token_node_not_new(GScanTokenNode *child)
+{
+ GScanTokenNode *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_NOT, NULL);
+
+ if (!g_scan_token_node_not_create(G_SCAN_TOKEN_NODE_NOT(result), child))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : not = encadrement d'inversion à initialiser pleinement. *
+* child = noeud dont les résultats sont à écarter. *
+* *
+* Description : Met en place une inversion de résultats de correspondances. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_node_not_create(GScanTokenNodeNot *not, GScanTokenNode *child)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ not->child = child;
+ g_object_ref(G_OBJECT(child));
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : node = point de départ du parcours à effectuer. *
+* points = points capitaux de l'arborescence. [OUT] *
+* *
+* Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_not_visit(GScanTokenNodeNot *node, scan_tree_points_t *points)
+{
+ g_scan_token_node_visit(node->child, points);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à enregistrer. *
+* context = contexte de l'analyse à mener. *
+* 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_not_enroll(GScanTokenNodeNot *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+ bool result; /* Statut à retourner */
+
+ result = _g_scan_token_node_enroll(node->child, context, backend, maxsize, slow);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* context = contexte de l'analyse à mener. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* matches = suivi des correspondances à consolider. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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_not_check_forward(const GScanTokenNodeNot *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+ bool initialized; /* Initialisation du suivi ? */
+ phys_t i; /* Boucle de parcours */
+
+
+ /*
+
+ ?????????????????????????
+
+
+ if (*skip)
+ return;
+ */
+
+
+
+ initialized = are_pending_matches_initialized(matches);
+
+
+ printf("TOTO......(init done? %d)\n", initialized);
+
+
+
+ if (!initialized)
+ {
+ for (i = matches->content_start; i < matches->content_end; i++)
+ add_pending_match(matches, i, 0);
+
+ set_pending_matches_initialized(matches);
+
+ }
+
+ _g_scan_token_node_check_forward(node->child, context, content, matches, offset, !not, skip);
+
+
+
+
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* context = contexte de l'analyse à mener. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* matches = suivi des correspondances à consolider. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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_not_check_backward(const GScanTokenNodeNot *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+
+
+
+ if (*skip)
+ return;
+
+
+
+ printf("TODO\n");
+ assert(0);
+
+
+
+}
diff --git a/src/analysis/scan/patterns/tokens/nodes/not.h b/src/analysis/scan/patterns/tokens/nodes/not.h
new file mode 100644
index 0000000..58630e8
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/not.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * not.h - prototypes pour l'inversion de résultats de correspondances établis
+ *
+ * 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_PATTERNS_TOKENS_NODES_NOT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_H
+
+
+#include <glib-object.h>
+
+
+#include "../node.h"
+#include "../../../../../arch/archbase.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_NODE_NOT g_scan_token_node_not_get_type()
+#define G_SCAN_TOKEN_NODE_NOT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_NOT, GScanTokenNodeNot))
+#define G_IS_SCAN_TOKEN_NODE_NOT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_NOT))
+#define G_SCAN_TOKEN_NODE_NOT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_NOT, GScanTokenNodeNotClass))
+#define G_IS_SCAN_TOKEN_NODE_NOT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_NOT))
+#define G_SCAN_TOKEN_NODE_NOT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_NOT, GScanTokenNodeNotClass))
+
+
+/* Inversion de résultats de correspondances établis (instance) */
+typedef struct _GScanTokenNodeNot GScanTokenNodeNot;
+
+/* Inversion de résultats de correspondances établis (classe) */
+typedef struct _GScanTokenNodeNotClass GScanTokenNodeNotClass;
+
+
+/* Indique le type défini pour une inversion des résultats de correspondances. */
+GType g_scan_token_node_not_get_type(void);
+
+/* Construit une inversion de résultats de correspondances. */
+GScanTokenNode *g_scan_token_node_not_new(GScanTokenNode *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/plain-int.h b/src/analysis/scan/patterns/tokens/nodes/plain-int.h
index a38359d..2077c6f 100644
--- a/src/analysis/scan/patterns/tokens/nodes/plain-int.h
+++ b/src/analysis/scan/patterns/tokens/nodes/plain-int.h
@@ -28,8 +28,8 @@
#include "plain.h"
-#include "../node-int.h"
#include "../atom.h"
+#include "../node-int.h"
@@ -56,7 +56,7 @@ struct _GScanTokenNodePlainClass
};
-/* Met en place un un noeud représentant un motif textuel. */
+/* Met en place un noeud représentant un motif textuel. */
bool g_scan_token_node_plain_create(GScanTokenNodePlain *, const sized_binary_t *, GScanTokenModifier *, ScanPlainNodeFlags);
diff --git a/src/analysis/scan/patterns/tokens/nodes/plain.c b/src/analysis/scan/patterns/tokens/nodes/plain.c
index ee87c73..5a7f976 100644
--- a/src/analysis/scan/patterns/tokens/nodes/plain.c
+++ b/src/analysis/scan/patterns/tokens/nodes/plain.c
@@ -24,7 +24,11 @@
#include "plain.h"
+#include <assert.h>
+
+
#include "plain-int.h"
+#include "../../../../../common/extstr.h"
@@ -32,7 +36,7 @@
/* Initialise la classe des noeuds pour motif textuel. */
-static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *klass);
+static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *);
/* Initialise une instance de noeud pour motif textuel. */
static void g_scan_token_node_plain_init(GScanTokenNodePlain *);
@@ -48,14 +52,20 @@ static void g_scan_token_node_plain_finalize(GScanTokenNodePlain *);
/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+/* Parcourt une arborescence de noeuds et y relève des éléments. */
+static void g_scan_token_node_plain_visit(GScanTokenNodePlain *, scan_tree_points_t *);
+
/* Inscrit la définition d'un motif dans un moteur de recherche. */
-static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *, GScanContext *, GEngineBackend *, size_t );
+static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *, GScanContext *, GEngineBackend *, size_t, size_t *);
/* Détermine si un contenu d'intérêt est présent à une position. */
-static bool check_scan_token_node_plain_content(const sized_binary_t *, const tracked_scan_atom_t *, phys_t, GBinContent *);
+static bool check_scan_token_node_plain_content(const sized_binary_t *, const tracked_scan_atom_t *, bool, phys_t, GBinContent *);
/* Transforme les correspondances locales en trouvailles. */
-static void g_scan_plain_bytes_check(const GScanTokenNodePlain *, GScanContext *, GBinContent *, pending_matches_t *, const node_search_offset_t *);
+static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_plain_check_backward(const GScanTokenNodePlain *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
@@ -92,8 +102,10 @@ static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *klass)
node = G_SCAN_TOKEN_NODE_CLASS(klass);
+ node->visit = (visit_scan_token_node_fc)g_scan_token_node_plain_visit;
node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_plain_enroll;
- node->check = (check_scan_token_node_fc)g_scan_plain_bytes_check;
+ node->check_forward = (check_scan_token_node_fc)g_scan_token_node_plain_check_forward;
+ node->check_backward = (check_scan_token_node_fc)g_scan_token_node_plain_check_backward;
}
@@ -112,6 +124,8 @@ static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *klass)
static void g_scan_token_node_plain_init(GScanTokenNodePlain *plain)
{
+ g_scan_token_node_set_flags(G_SCAN_TOKEN_NODE(plain), STNF_PROD);
+
init_szstr(&plain->orig);
plain->modifier = NULL;
plain->flags = SPNF_NONE;
@@ -203,6 +217,7 @@ GScanTokenNode *g_scan_token_node_plain_new(const sized_binary_t *text, GScanTok
}
+
/******************************************************************************
* *
* Paramètres : plain = encadrement de motif à initialiser pleinement. *
@@ -210,7 +225,7 @@ GScanTokenNode *g_scan_token_node_plain_new(const sized_binary_t *text, GScanTok
* modifier = transformateur éventuel à solliciter. *
* flags = particularités à prendre en considération. *
* *
-* Description : Met en place un un noeud représentant un motif textuel. *
+* Description : Met en place un noeud représentant un motif textuel. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -239,6 +254,29 @@ bool g_scan_token_node_plain_create(GScanTokenNodePlain *plain, const sized_bina
}
+/******************************************************************************
+* *
+* Paramètres : plain = noeud de motif textuel à consulter. *
+* *
+* Description : Indique les propriétés particulières d'un noeud de texte. *
+* *
+* Retour : Propriétés particulières associées au noeud. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+ScanPlainNodeFlags g_scan_token_node_plain_get_flags(const GScanTokenNodePlain *plain)
+{
+ ScanPlainNodeFlags result; /* Statut à retourner */
+
+ result = plain->flags;
+
+ return result;
+
+}
+
+
/* ---------------------------------------------------------------------------------- */
/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
@@ -247,10 +285,32 @@ bool g_scan_token_node_plain_create(GScanTokenNodePlain *plain, const sized_bina
/******************************************************************************
* *
+* Paramètres : node = point de départ du parcours à effectuer. *
+* points = points capitaux de l'arborescence. [OUT] *
+* *
+* Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_plain_visit(GScanTokenNodePlain *node, scan_tree_points_t *points)
+{
+ if (points->first_plain == NULL)
+ points->first_plain = G_SCAN_TOKEN_NODE(node);
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : node = définition de la bribe à enregistrer. *
* context = contexte de l'analyse à mener. *
* 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.*
* *
@@ -260,7 +320,7 @@ bool g_scan_token_node_plain_create(GScanTokenNodePlain *plain, const sized_bina
* *
******************************************************************************/
-static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanContext *context, GEngineBackend *backend, size_t maxsize)
+static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
{
bool result; /* Statut à retourner */
size_t i; /* Boucle de parcours #1 */
@@ -312,13 +372,14 @@ static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanConte
if (letters == 0)
node->atoms[i] = atom;
- /* Insertion des combinaisons pour couvrir toutes les casses */
+ /* Insertion des nouvelles combinaisons pour couvrir toutes les casses */
else
{
- for (k = 0, extra_count = 1; k < letters; k++, extra_count *= 2)
+ /* extra_count = 2^letters */
+ for (k = 1, extra_count = 2; k < letters; k++, extra_count *= 2)
;
- extra = make_atoms_case_insensitive(&node->raw[i], extra_count);
+ extra = make_atoms_case_insensitive(&node->raw[i], &atom, extra_count);
remaining = node->count - i - 1;
@@ -333,7 +394,7 @@ static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanConte
free(extra);
- node->atoms = realloc(node->raw, node->count * sizeof(tracked_scan_atom_t));
+ node->atoms = realloc(node->atoms, node->count * sizeof(tracked_scan_atom_t));
for (k = 0; k < extra_count; k++)
node->atoms[i + k] = atom;
@@ -365,6 +426,7 @@ static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanConte
* *
* Paramètres : raw = contneu brut à retrouver idéalement. *
* atom = contenu brut représentatif ciblé. *
+* nocase = marque un éventuel désintérêt pour la casse. *
* start = point d'analyse à respecter. *
* content = accès au contenu brut pour vérifications (optim.) *
* *
@@ -376,7 +438,7 @@ static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanConte
* *
******************************************************************************/
-static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const tracked_scan_atom_t *atom, phys_t start, GBinContent *content)
+static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const tracked_scan_atom_t *atom, bool nocase, phys_t start, GBinContent *content)
{
bool result; /* Bilan à retourner */
vmpa2t pos; /* Position dans les données */
@@ -393,7 +455,11 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const
{
ptr = g_binary_content_get_raw_access(content, &pos, atom->pos);
- ret = memcmp(raw->data, ptr, atom->pos);
+ if (nocase)
+ ret = memcasecmp(raw->data, ptr, atom->pos);
+ else
+ ret = memcmp(raw->data, ptr, atom->pos);
+
if (ret != 0) goto done;
}
@@ -406,7 +472,11 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const
ptr = g_binary_content_get_raw_access(content, &pos, atom->rem);
- ret = memcmp(raw->data + atom->pos + atom->len, ptr, atom->rem);
+ if (nocase)
+ ret = memcasecmp(raw->data + atom->pos + atom->len, ptr, atom->rem);
+ else
+ ret = memcmp(raw->data + atom->pos + atom->len, ptr, atom->rem);
+
if (ret != 0) goto done;
}
@@ -427,6 +497,8 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const
* content = accès au contenu brut pour vérifications (optim.) *
* matches = suivi des correspondances à consolider. *
* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* skip = détermine si l'analyse est différée. [OUT] *
* *
* Description : Transforme les correspondances locales en trouvailles. *
* *
@@ -436,22 +508,33 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const
* *
******************************************************************************/
-static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, const node_search_offset_t *offset)
+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 nocase; /* Pas d'intérêt pour la casse */
+ size_t ocount; /* Quantité de bornes présentes*/
size_t i; /* Boucle de parcours #1 */
const sized_binary_t *raw; /* Données brutes d'origine */
const tracked_scan_atom_t *atom; /* Atome correspondant */
size_t count; /* Quantité de bribes trouvées */
const phys_t *found; /* Localisations des bribes */
size_t k; /* Boucle de parcours #2 */
- phys_t start; /* Point de départ */
+ phys_t new_begin; /* Nouveau départ à tester */
bool status; /* Bilan d'une correspondance */
size_t pcount; /* Nombre de correspondances */
+ match_area_t * const *pending_ptr; /* Correspondances actuelles */
size_t p; /* Boucle de parcours #3 */
+ const match_area_t *pending; /* Correspondance à traiter */
+
+ if (*skip)
+ return;
initialized = are_pending_matches_initialized(matches);
+ nocase = (node->flags & SPNF_CASE_INSENSITIVE);
+
+ get_node_search_offset_ranges(offset, &ocount);
+
for (i = 0; i < node->count; i++)
{
raw = &node->raw[i];
@@ -463,28 +546,34 @@ static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanConte
{
for (k = 0; k < count; k++)
{
- start = found[k] - atom->pos;
+ new_begin = found[k] - atom->pos;
/**
* Si personne n'a manipulé les pré-résultats, mais qu'un décallage
* est spécifié par un noeud précédent, une validation sur la base
* d'une position 0 est menée.
*/
- if (offset != NULL)
+ if (ocount > 0)
{
- if (start < offset->min || start > offset->max)
+ if (!does_node_search_offset_include_pos_forward(offset, 0, new_begin))
+ {
+ if (not)
+ add_pending_match(matches, new_begin, raw->len);
+
continue;
+
+ }
}
- status = check_scan_token_node_plain_content(raw, atom, start, content);
+ status = check_scan_token_node_plain_content(raw, atom, nocase, new_begin, content);
- if (status)
+ if ((status && !not) || (!status && not))
/**
* Il ne peut y avoir qu'une seule séquence d'octets à un même
- * emplacement, donc le couple (start, len) enregistré est
+ * emplacement, donc le couple (new_begin, len) enregistré est
* unique.
*/
- add_pending_match(matches, start, raw->len);
+ add_pending_match(matches, new_begin, raw->len);
}
@@ -494,12 +583,17 @@ static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanConte
{
reset_pending_matches_ttl(matches);
- pcount = count_pending_matches(matches);
+ pending_ptr = get_all_pending_matches(matches, &pcount);
for (p = 0; p < pcount; p++)
+ {
+ pending = (*pending_ptr) + p;
+
+ assert(matches->content_start <= pending->start);
+
for (k = 0; k < count; k++)
{
- start = found[k] - atom->pos;
+ new_begin = found[k] - atom->pos;
/**
* Si bornes de tolérance il y a, on valide la position.
@@ -507,20 +601,52 @@ static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanConte
* Sinon les correspondances passées et actuelle doivent
* être jointes.
*/
- if (offset != NULL)
+ if (ocount > 0)
{
- if (!has_pending_match_ending_between(matches, p, start, offset->min, offset->max))
+ if (!does_node_search_offset_include_pos_forward(offset, pending->end, new_begin))
+ {
+ if (not)
+ {
+ extend_pending_match_ending(matches, p, pending->end + raw->len);
+
+ /**
+ * Comme l'extension a pu conduire à un ajout et donc à une
+ * réallocation de la liste, on recharge l'élément pour les
+ * itérations suivantes.
+ */
+ pending = (*pending_ptr) + p;
+
+ }
+
continue;
+
+ }
}
else
{
- if (!has_pending_match_ending_at(matches, p, start))
+ if (pending->end != new_begin)
+ {
+ if (not)
+ {
+ extend_pending_match_ending(matches, p, pending->end + raw->len);
+
+ /**
+ * Comme l'extension a pu conduire à un ajout et donc à une
+ * réallocation de la liste, on recharge l'élément pour les
+ * itérations suivantes.
+ */
+ pending = (*pending_ptr) + p;
+
+ }
+
continue;
+
+ }
}
- status = check_scan_token_node_plain_content(raw, atom, start, content);
+ status = check_scan_token_node_plain_content(raw, atom, nocase, new_begin, content);
- if (status)
+ if ((status && !not) || (!status && not))
{
/**
* Même si une base de couples uniques est assurée,
@@ -559,18 +685,28 @@ static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanConte
/**
* La seconde situation est prise en compte par la fonction
- * extend_pending_match() qui s'appuie sur le TTL pour dupliquer
- * la correspondance pending[x] initiale. Le nouvel élément est
- * placé en fin de liste, ce qui ne boulverse pas le parcours
- * de liste courant, la valeur de pcount n'étant pas actualisée.
+ * extend_pending_match_ending() qui s'appuie sur le TTL pour
+ * dupliquer la correspondance pending[x] initiale. Le nouvel
+ * élément est placé en fin de liste, ce qui ne boulverse pas
+ * le parcours de liste courant, la valeur de pcount n'étant
+ * pas actualisée.
*/
- extend_pending_match(matches, p, start + raw->len);
+ extend_pending_match_ending(matches, p, new_begin + raw->len);
+
+ /**
+ * Comme l'extension a pu conduire à un ajout et donc à une
+ * réallocation de la liste, on recharge l'élément pour les
+ * itérations suivantes.
+ */
+ pending = (*pending_ptr) + p;
}
}
+ }
+
purge_pending_matches(matches);
}
@@ -579,4 +715,42 @@ static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanConte
set_pending_matches_initialized(matches);
+ disable_all_ranges_in_node_search_offset(offset);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* context = contexte de l'analyse à mener. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* matches = suivi des correspondances à consolider. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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_plain_check_backward(const GScanTokenNodePlain *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+
+
+
+ if (*skip)
+ return;
+
+
+
+ printf("TODO\n");
+ assert(0);
+
+
+
}
diff --git a/src/analysis/scan/patterns/tokens/nodes/plain.h b/src/analysis/scan/patterns/tokens/nodes/plain.h
index 33e7feb..c8f3920 100644
--- a/src/analysis/scan/patterns/tokens/nodes/plain.h
+++ b/src/analysis/scan/patterns/tokens/nodes/plain.h
@@ -52,9 +52,16 @@ typedef struct _GScanTokenNodePlainClass GScanTokenNodePlainClass;
/* Propriétés d'un élément textuel à rechercher */
typedef enum _ScanPlainNodeFlags
{
- SPNF_NONE = 0x0, /* Aucune particularité */
- SPNF_CASE_INSENSITIVE = 0x1, /* Ignorance de la casse */
- SPNF_FULL_WORD = 0x2, /* Recherche de mot entier */
+ SPNF_NONE = (0 << 0), /* Aucune particularité */
+ SPNF_CASE_INSENSITIVE = (1 << 0), /* Ignorance de la casse */
+
+ /**
+ * Les deux propriétés suivantes sont récupérées et traitées
+ * au niveau du Token propriétaire.
+ */
+
+ SPNF_FULLWORD = (1 << 1), /* Recherche de mot entier */
+ SPNF_PRIVATE = (1 << 2), /* Marque privative */
} ScanPlainNodeFlags;
@@ -65,6 +72,9 @@ GType g_scan_token_node_plain_get_type(void);
/* Construit un noeud représentant un motif textuel. */
GScanTokenNode *g_scan_token_node_plain_new(const sized_binary_t *, GScanTokenModifier *, ScanPlainNodeFlags);
+/* Indique les propriétés particulières d'un noeud de texte. */
+ScanPlainNodeFlags g_scan_token_node_plain_get_flags(const GScanTokenNodePlain *);
+
#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/sequence-int.h b/src/analysis/scan/patterns/tokens/nodes/sequence-int.h
new file mode 100644
index 0000000..f0ea6ae
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/sequence-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sequence-int.h - prototypes internes pour des décompositions séquentielles de motif de recherche
+ *
+ * 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_PATTERNS_TOKENS_NODES_SEQUENCE_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_INT_H
+
+
+#include "sequence.h"
+
+
+#include "../node-int.h"
+
+
+
+/* Décompositions séquentielles de motif de recherche (instance) */
+struct _GScanTokenNodeSequence
+{
+ GScanTokenNode parent; /* A laisser en premier */
+
+ GScanTokenNode **children; /* Sous-noeuds à représenter */
+ size_t count; /* Taille de cette liste */
+
+};
+
+/* Décompositions séquentielles de motif de recherche (classe) */
+struct _GScanTokenNodeSequenceClass
+{
+ GScanTokenNodeClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une série de décompositions séquentielles. */
+bool g_scan_token_node_sequence_create(GScanTokenNodeSequence *, GScanTokenNode *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/sequence.c b/src/analysis/scan/patterns/tokens/nodes/sequence.c
new file mode 100644
index 0000000..ad332fc
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/sequence.c
@@ -0,0 +1,360 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sequence.c - décompositions séquentielles de motif de recherche
+ *
+ * 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 "sequence.h"
+
+
+#include "sequence-int.h"
+
+
+
+/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
+
+
+/* Initialise la classe des décompositions séquentielles. */
+static void g_scan_token_node_sequence_class_init(GScanTokenNodeSequenceClass *);
+
+/* Initialise une instance de décompositions séquentielles. */
+static void g_scan_token_node_sequence_init(GScanTokenNodeSequence *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_node_sequence_dispose(GScanTokenNodeSequence *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_node_sequence_finalize(GScanTokenNodeSequence *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Parcourt une arborescence de noeuds et y relève des éléments. */
+static void g_scan_token_node_sequence_visit(GScanTokenNodeSequence *node, scan_tree_points_t *);
+
+/* Inscrit la définition d'un motif dans un moteur de recherche. */
+static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *, GScanContext *, GEngineBackend *, size_t, size_t *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_sequence_check_forward(const GScanTokenNodeSequence *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+/* Transforme les correspondances locales en trouvailles. */
+static void g_scan_token_node_sequence_check_backward(const GScanTokenNodeSequence *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DECOMPOSITION DE MOTIF RECHERCHE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour des décompositions séquentielles de motif de recherche. */
+G_DEFINE_TYPE(GScanTokenNodeSequence, g_scan_token_node_sequence, G_TYPE_SCAN_TOKEN_NODE);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des décompositions séquentielles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_class_init(GScanTokenNodeSequenceClass *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_sequence_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_token_node_sequence_finalize;
+
+ node = G_SCAN_TOKEN_NODE_CLASS(klass);
+
+ node->visit = (visit_scan_token_node_fc)g_scan_token_node_sequence_visit;
+ node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_sequence_enroll;
+ node->check_forward = (check_scan_token_node_fc)g_scan_token_node_sequence_check_forward;
+ node->check_backward = (check_scan_token_node_fc)g_scan_token_node_sequence_check_backward;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : sequence = instance à initialiser. *
+* *
+* Description : Initialise une instance de décompositions séquentielles. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_init(GScanTokenNodeSequence *sequence)
+{
+ sequence->children = NULL;
+ sequence->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : sequence = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_dispose(GScanTokenNodeSequence *sequence)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < sequence->count; i++)
+ g_clear_object(&sequence->children[i]);
+
+ G_OBJECT_CLASS(g_scan_token_node_sequence_parent_class)->dispose(G_OBJECT(sequence));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : sequence = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_finalize(GScanTokenNodeSequence *sequence)
+{
+ if (sequence->children != NULL)
+ free(sequence->children);
+
+ G_OBJECT_CLASS(g_scan_token_node_sequence_parent_class)->finalize(G_OBJECT(sequence));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : child = noeud dont les résultats sont à écarter. *
+* *
+* Description : Construit une série de décompositions séquentielles de motif.*
+* *
+* Retour : Mécanismes mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanTokenNode *g_scan_token_node_sequence_new(GScanTokenNode *child)
+{
+ GScanTokenNode *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_SEQUENCE, NULL);
+
+ if (!g_scan_token_node_sequence_create(G_SCAN_TOKEN_NODE_SEQUENCE(result), child))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : sequence = décompositions à initialiser pleinement. *
+* child = noeud dont les résultats sont à écarter. *
+* *
+* Description : Met en place une série de décompositions séquentielles. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_token_node_sequence_create(GScanTokenNodeSequence *sequence, GScanTokenNode *child)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ g_scan_token_node_sequence_add(sequence, child);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : sequence = ensemble de noeuds à compléter. *
+* child = nouveau noeud à intégrer. *
+* *
+* Description : Ajoute un noeud à aux décompositions séquentielles de motif. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_token_node_sequence_add(GScanTokenNodeSequence *sequence, GScanTokenNode *child)
+{
+ sequence->children = realloc(sequence->children, ++sequence->count * sizeof(GScanTokenNode *));
+
+ sequence->children[sequence->count - 1] = child;
+ g_object_ref(G_OBJECT(child));
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : node = point de départ du parcours à effectuer. *
+* points = points capitaux de l'arborescence. [OUT] *
+* *
+* Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_visit(GScanTokenNodeSequence *node, scan_tree_points_t *points)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < node->count; i++)
+ g_scan_token_node_visit(node->children[i], points);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à enregistrer. *
+* context = contexte de l'analyse à mener. *
+* 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_sequence_enroll(GScanTokenNodeSequence *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+ bool result; /* Statut à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = true;
+
+ for (i = 0; i < node->count && result; i++)
+ result = _g_scan_token_node_enroll(node->children[i], context, backend, maxsize, slow);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* context = contexte de l'analyse à mener. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* matches = suivi des correspondances à consolider. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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_sequence_check_forward(const GScanTokenNodeSequence *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < node->count; i++)
+ _g_scan_token_node_check_forward(node->children[i], context, content, matches, offset, not, skip);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = définition de la bribe à manipuler. *
+* context = contexte de l'analyse à mener. *
+* content = accès au contenu brut pour vérifications (optim.) *
+* matches = suivi des correspondances à consolider. *
+* offset = tolérance dans les positions à appliquer. *
+* not = indique si les résultats doivent être inversés. *
+* 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_sequence_check_backward(const GScanTokenNodeSequence *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = node->count; i > 0 ; i--)
+ _g_scan_token_node_check_backward(node->children[i - 1], context, content, matches, offset, not, skip);
+
+}
diff --git a/src/analysis/scan/patterns/tokens/nodes/sequence.h b/src/analysis/scan/patterns/tokens/nodes/sequence.h
new file mode 100644
index 0000000..fc181c6
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/sequence.h
@@ -0,0 +1,61 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sequence.h - prototypes pour des décompositions séquentielles de motif de recherche
+ *
+ * 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_PATTERNS_TOKENS_NODES_SEQUENCE_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_H
+
+
+#include <glib-object.h>
+
+
+#include "../node.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_NODE_SEQUENCE g_scan_token_node_sequence_get_type()
+#define G_SCAN_TOKEN_NODE_SEQUENCE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE, GScanTokenNodeSequence))
+#define G_IS_SCAN_TOKEN_NODE_SEQUENCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE))
+#define G_SCAN_TOKEN_NODE_SEQUENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE, GScanTokenNodeSequenceClass))
+#define G_IS_SCAN_TOKEN_NODE_SEQUENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE))
+#define G_SCAN_TOKEN_NODE_SEQUENCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE, GScanTokenNodeSequenceClass))
+
+
+/* Décompositions séquentielles de motif de recherche (instance) */
+typedef struct _GScanTokenNodeSequence GScanTokenNodeSequence;
+
+/* Décompositions séquentielles de motif de recherche (classe) */
+typedef struct _GScanTokenNodeSequenceClass GScanTokenNodeSequenceClass;
+
+
+/* Indique le type défini pour des décompositions séquentielles de motif de recherche. */
+GType g_scan_token_node_sequence_get_type(void);
+
+/* Construit une série de décompositions séquentielles de motif. */
+GScanTokenNode *g_scan_token_node_sequence_new(GScanTokenNode *);
+
+/* Ajoute un noeud à aux décompositions séquentielles de motif. */
+void g_scan_token_node_sequence_add(GScanTokenNodeSequence *, GScanTokenNode *);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_H */
diff --git a/src/analysis/scan/patterns/tokens/offset.c b/src/analysis/scan/patterns/tokens/offset.c
new file mode 100644
index 0000000..010ec67
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/offset.c
@@ -0,0 +1,352 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * offset.c - décomposition d'un motif de recherche en atomes assemblés
+ *
+ * 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 "offset.h"
+
+
+#include <assert.h>
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : range = bornes décrivant un espace quelconque. *
+* available = espace restant disponible. *
+* min = point de départ pour parcourir une zone. [OUT] *
+* max = point d'arrivée pour parcourir une zone. [OUT] *
+* *
+* Description : Fournit les bornes d'une zone à analyser. *
+* *
+* Retour : true si assez d'espace est disponible, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool get_node_offset_range(const node_offset_range_t *range, phys_t len, phys_t available, phys_t *min, phys_t *max)
+{
+ bool result; /* Bilan à retourner */
+
+ if ((len + range->min) > available)
+ result = false;
+
+ else
+ {
+ result = true;
+
+ *min = range->min;
+ *max = range->max;
+
+ if ((len + *max) > available)
+ {
+ *max = available - len;
+ assert(*max >= *min);
+ }
+
+ }
+
+ return result;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : offset = suivi de tolérances bornées à initialiser. *
+* *
+* Description : Initialise une mémorisation d'intervales de tolérance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void init_node_search_offset(node_search_offset_t *offset)
+{
+ offset->ranges = NULL;
+ offset->allocated = 0;
+
+ offset->gen_ptr = NULL;
+
+ offset->used = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dest = suivi de tolérances bornées à initialiser. [OUT] *
+* src = suivi de tolérances bornées à copier. *
+* *
+* Description : Copie une mémorisation d'intervales entre positions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void copy_node_search_offset(node_search_offset_t *dest, const node_search_offset_t *src)
+{
+ init_node_search_offset(dest);
+
+ switch (src->used)
+ {
+ case 0:
+ dest->gen_ptr = NULL;
+ break;
+
+ case 1:
+ dest->range = src->range;
+ dest->gen_ptr = &dest->range;
+ break;
+
+ default:
+ dest->ranges = malloc(src->used * sizeof(node_offset_range_t));
+ memcpy(dest->ranges, src->ranges, src->used * sizeof(node_offset_range_t));
+ dest->gen_ptr = dest->ranges;;
+ break;
+
+ }
+
+ dest->used = src->used;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dest = suivi de tolérances bornées à initialiser. [OUT] *
+* src = suivi de tolérances bornées à copier. *
+* *
+* Description : Fusionne une mémorisation d'intervales entre positions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void merge_node_search_offset(node_search_offset_t *dest, const node_search_offset_t *src)
+{
+ node_offset_range_t * const *list; /* Liste d'intervales à copier */
+ size_t i; /* Boucle de parcours */
+
+ if ((dest->used + src->used) > 1 && (dest->used + src->used) > dest->allocated)
+ {
+ dest->allocated += src->used;
+
+ dest->ranges = realloc(dest->ranges, dest->allocated * sizeof(node_offset_range_t));
+
+ }
+
+ list = get_node_search_offset_ranges(src, (size_t []){ 0 });
+
+ for (i = 0; i < src->used; i++)
+ add_range_to_node_search_offset(dest, (*list)[i].min, (*list)[i].max, NULL);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : offset = suivi de tolérances bornées à terminer. *
+* *
+* Description : Met fin à une mémorisation d'intervales de tolérance. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void exit_node_search_offset(node_search_offset_t *offset)
+{
+ if (offset->ranges != NULL)
+ free(offset->ranges);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : offset = suivi de tolérances bornées à consulter. *
+* count = nombre de bornes enregistrées. [OUT] *
+* *
+* Description : Fournit la liste des tolérances bornées établies à présent. *
+* *
+* Retour : Liste d'intervales en lecture seule. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+node_offset_range_t * const *get_node_search_offset_ranges(const node_search_offset_t *offset, size_t *count)
+{
+ node_offset_range_t * const *result; /* Série à renvoyer */
+
+ result = &offset->gen_ptr;
+
+ *count = offset->used;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : offset = suivi de tolérances bornées à consulter. *
+* min = point de départ pour parcourir une zone. *
+* max = point d'arrivée pour parcourir une zone. *
+* datasize = taille maximale pour définir une inversion NOT. *
+* *
+* Description : Ajoute un nouvel espace borné aux décalages tolérés. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void add_range_to_node_search_offset(node_search_offset_t *offset, phys_t min, phys_t max, const phys_t *datasize)
+{
+ bool not; /* Traduction de la taille */
+ size_t needed; /* Nombre d'emplacements requis*/
+
+ not = (datasize != NULL);
+
+ /* Si le réceptacle unique peut être employé... */
+ if (offset->used == 0 && !not)
+ {
+ offset->range.min = min;
+ offset->range.max = max;
+
+ offset->used = 1;
+
+ offset->gen_ptr = &offset->range;
+
+ }
+
+ /* Sinon le groupe dynamique est sollicité */
+ else
+ {
+ needed = offset->used + (not ? 2 : 1);
+
+ if (needed > offset->allocated)
+ {
+ offset->ranges = realloc(offset->ranges, needed * sizeof(node_offset_range_t));
+ offset->allocated = needed;
+ }
+
+ /* Bascule d'un éventuel intervale courant */
+ if (offset->used == 1)
+ {
+ offset->ranges[0].min = offset->range.min;
+ offset->ranges[0].max = offset->range.max;
+ }
+
+ if (not)
+ {
+ if (min > 0)
+ {
+ offset->ranges[offset->used].min = 0;
+ offset->ranges[offset->used].max = min - 1;
+
+ offset->used++;
+
+ }
+
+ if ((max + 1) < *datasize)
+ {
+ offset->ranges[offset->used].min = max + 1;
+ offset->ranges[offset->used].max = *datasize - (max + 1);
+
+ offset->used++;
+
+ }
+
+ }
+ else
+ {
+ offset->ranges[offset->used].min = min;
+ offset->ranges[offset->used].max = max;
+
+ offset->used++;
+
+ }
+
+ offset->gen_ptr = offset->ranges;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : offset = suivi de tolérances bornées à consulter. *
+* last = dernière position validée. *
+* pos = nouvelle position potentielle. *
+* *
+* Description : Indique si une position est comprise dans un intervale. *
+* *
+* Retour : Bilan de la détermination. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool does_node_search_offset_include_pos_forward(const node_search_offset_t *offset, phys_t last, phys_t pos)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
+ const node_offset_range_t *range; /* Accès rapide aux infos. */
+
+ result = false;
+
+ for (i = 0; i < offset->used; i++)
+ {
+ range = &offset->gen_ptr[i];
+
+ result = ((last + range->min) <= pos && pos <= (last + range->max));
+ if (result) break;
+
+ }
+
+ return result;
+
+}
diff --git a/src/analysis/scan/patterns/tokens/offset.h b/src/analysis/scan/patterns/tokens/offset.h
new file mode 100644
index 0000000..b458717
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/offset.h
@@ -0,0 +1,101 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * offset.h - prototypes pour la prise en compte des espaces entre octets dans un motif de recherche
+ *
+ * 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_PATTERNS_TOKENS_OFFSET_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_OFFSET_H
+
+
+#include <stdbool.h>
+
+#include "../../../../arch/vmpa.h"
+
+
+
+/* Mémorisation d'une souplesse dans les positions visées */
+typedef struct _node_offset_range_t
+{
+ /**
+ * Les deux champs ci-après font bien référence à des positions absolues,
+ * et non à des bornes d'espace, lors que les résultats de correspondances
+ * sont encore non initialisés.
+ *
+ * Ensuite ces bornes représentent bien un espace séparant les résultats
+ * issus de deux noeuds.
+ */
+ phys_t min; /* Position minimale */
+ phys_t max; /* Position maximale */
+
+} node_offset_range_t;
+
+
+/* Fournit les bornes d'une zone à analyser. */
+bool get_node_offset_range(const node_offset_range_t *, phys_t, phys_t, phys_t *, phys_t *);
+
+
+
+
+
+
+/* Mémorisation d'une souplesse dans les positions visées */
+typedef struct _node_search_offset_t
+{
+ node_offset_range_t range; /* Bornes de décalage uniques */
+
+ node_offset_range_t *ranges; /* Bornes de décalage multiples*/
+ size_t allocated; /* Nombre d'allocations */
+
+ node_offset_range_t *gen_ptr; /* Accès générique à la liste */
+
+ size_t used; /* Nombre de bornes présentes */
+
+} node_search_offset_t;
+
+
+/* Initialise une mémorisation d'intervales de tolérance. */
+void init_node_search_offset(node_search_offset_t *);
+
+/* Copie une mémorisation d'intervales entre positions. */
+void copy_node_search_offset(node_search_offset_t *, const node_search_offset_t *);
+
+/* Fusionne une mémorisation d'intervales entre positions. */
+void merge_node_search_offset(node_search_offset_t *, const node_search_offset_t *);
+
+/* Met fin à une mémorisation d'intervales de tolérance. */
+void exit_node_search_offset(node_search_offset_t *);
+
+/* Fournit la liste des tolérances bornées établies à présent. */
+/* TODO : supprimer un niveau d'indirection */
+node_offset_range_t * const *get_node_search_offset_ranges(const node_search_offset_t *, size_t *);
+
+/* Ajoute un nouvel espace borné aux décalages tolérés. */
+void add_range_to_node_search_offset(node_search_offset_t *, phys_t, phys_t, const phys_t *);
+
+#define disable_all_ranges_in_node_search_offset(off) \
+ (off)->used = 0
+
+/* Indique si une position est comprise dans un intervale. */
+bool does_node_search_offset_include_pos_forward(const node_search_offset_t *, phys_t, phys_t);
+
+
+
+#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_OFFSET_H */
diff --git a/src/analysis/scan/patterns/tokens/plain-int.h b/src/analysis/scan/patterns/tokens/plain-int.h
index 40a71b5..5748160 100644
--- a/src/analysis/scan/patterns/tokens/plain-int.h
+++ b/src/analysis/scan/patterns/tokens/plain-int.h
@@ -38,14 +38,6 @@ struct _GScanPlainBytes
{
GStringToken parent; /* A laisser en premier */
- sized_binary_t orig; /* Motif d'origine avant modifs*/
- GScanTokenModifier *modifier; /* Transformateur pour le motif*/
- ScanPlainBytesFlags flags; /* Fanions associés au motif */
-
- sized_binary_t *raw; /* Liste de motifs à couvrir */
- tracked_scan_atom_t *atoms; /* Atomes correspondants */
- size_t count; /* Taille de cette liste */
-
};
/* Encadrement d'une recherche de texte brut (classe) */
@@ -57,7 +49,7 @@ struct _GScanPlainBytesClass
/* Met en place un gestionnaire de recherche de texte brut. */
-bool g_scan_plain_bytes_create(GScanPlainBytes *, const sized_binary_t *, GScanTokenModifier *, ScanPlainBytesFlags);
+bool g_scan_plain_bytes_create(GScanPlainBytes *, GScanTokenNode *);
diff --git a/src/analysis/scan/patterns/tokens/plain.c b/src/analysis/scan/patterns/tokens/plain.c
index 26e7dfa..2eb6bbc 100644
--- a/src/analysis/scan/patterns/tokens/plain.c
+++ b/src/analysis/scan/patterns/tokens/plain.c
@@ -29,6 +29,7 @@
#include "plain-int.h"
+#include "nodes/plain.h"
@@ -58,12 +59,6 @@ static void g_scan_plain_bytes_output_to_text(const GScanPlainBytes *, GScanCont
/* Affiche un motif de recherche au format JSON. */
static void g_scan_plain_bytes_output_to_json(const GScanPlainBytes *, GScanContext *, const sized_string_t *, unsigned int, int);
-/* Inscrit la définition d'un motif dans un moteur de recherche. */
-static bool g_scan_plain_bytes_enroll(GScanPlainBytes *, GScanContext *, GEngineBackend *, size_t);
-
-/* Transforme les correspondances locales en trouvailles. */
-static void g_scan_plain_bytes_check(const GScanPlainBytes *, GScanContext *, GBinContent *, pending_matches_t *);
-
/* ---------------------------------------------------------------------------------- */
@@ -91,7 +86,6 @@ static void g_scan_plain_bytes_class_init(GScanPlainBytesClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
GSearchPatternClass *pattern; /* Version de classe ancêtre */
- GStringTokenClass *token; /* Version de classe parente */
object = G_OBJECT_CLASS(klass);
@@ -103,11 +97,6 @@ static void g_scan_plain_bytes_class_init(GScanPlainBytesClass *klass)
pattern->to_text = (output_pattern_to_text_fc)g_scan_plain_bytes_output_to_text;
pattern->to_json = (output_pattern_to_json_fc)g_scan_plain_bytes_output_to_json;
- token = G_STRING_TOKEN_CLASS(klass);
-
- token->enroll = (enroll_token_fc)g_scan_plain_bytes_enroll;
- token->check = (check_token_fc)g_scan_plain_bytes_check;
-
}
@@ -125,13 +114,6 @@ static void g_scan_plain_bytes_class_init(GScanPlainBytesClass *klass)
static void g_scan_plain_bytes_init(GScanPlainBytes *bytes)
{
- init_szstr(&bytes->orig);
- bytes->modifier = NULL;
- bytes->flags = SPBF_NONE;
-
- bytes->raw = NULL;
- bytes->atoms = NULL;
- bytes->count = 0;
}
@@ -150,8 +132,6 @@ static void g_scan_plain_bytes_init(GScanPlainBytes *bytes)
static void g_scan_plain_bytes_dispose(GScanPlainBytes *bytes)
{
- g_clear_object(&bytes->modifier);
-
G_OBJECT_CLASS(g_scan_plain_bytes_parent_class)->dispose(G_OBJECT(bytes));
}
@@ -171,19 +151,6 @@ static void g_scan_plain_bytes_dispose(GScanPlainBytes *bytes)
static void g_scan_plain_bytes_finalize(GScanPlainBytes *bytes)
{
- size_t i; /* Boucle de parcours */
-
- exit_szstr(&bytes->orig);
-
- for (i = 0; i < bytes->count; i++)
- exit_szstr(&bytes->raw[i]);
-
- if (bytes->raw != NULL)
- free(bytes->raw);
-
- if (bytes->atoms != NULL)
- free(bytes->atoms);
-
G_OBJECT_CLASS(g_scan_plain_bytes_parent_class)->finalize(G_OBJECT(bytes));
}
@@ -191,9 +158,7 @@ static void g_scan_plain_bytes_finalize(GScanPlainBytes *bytes)
/******************************************************************************
* *
-* Paramètres : text = texte brut à rechercher. *
-* modifier = transformateur éventuel à solliciter. *
-* flags = particularités à prendre en considération. *
+* Paramètres : root = représentation du motif à recherche. *
* *
* Description : Construit un gestionnaire de recherche de texte brut. *
* *
@@ -203,25 +168,24 @@ static void g_scan_plain_bytes_finalize(GScanPlainBytes *bytes)
* *
******************************************************************************/
-GSearchPattern *g_scan_plain_bytes_new(const sized_binary_t *text, GScanTokenModifier *modifier, ScanPlainBytesFlags flags)
+GSearchPattern *g_scan_plain_bytes_new(GScanTokenNode *root)
{
GSearchPattern *result; /* Structure à retourner */
result = g_object_new(G_TYPE_SCAN_PLAIN_BYTES, NULL);
- if (!g_scan_plain_bytes_create(G_SCAN_PLAIN_BYTES(result), text, modifier, flags))
+ if (!g_scan_plain_bytes_create(G_SCAN_PLAIN_BYTES(result), root))
g_clear_object(&result);
return result;
}
+
/******************************************************************************
* *
-* Paramètres : bytes = encadrement de motif à initialiser pleinement. *
-* text = texte brut à rechercher. *
-* modifier = transformateur éventuel à solliciter. *
-* flags = particularités à prendre en considération. *
+* Paramètres : bytes = encadrement de motif à initialiser pleinement. *
+* root = représentation du motif à recherche. *
* *
* Description : Met en place un gestionnaire de recherche de texte brut. *
* *
@@ -231,21 +195,19 @@ GSearchPattern *g_scan_plain_bytes_new(const sized_binary_t *text, GScanTokenMod
* *
******************************************************************************/
-bool g_scan_plain_bytes_create(GScanPlainBytes *bytes, const sized_binary_t *text, GScanTokenModifier *modifier, ScanPlainBytesFlags flags)
+bool g_scan_plain_bytes_create(GScanPlainBytes *bytes, GScanTokenNode *root)
{
bool result; /* Bilan à retourner */
+ ScanPlainNodeFlags flags; /* Propriétés à interpréter */
+ bool fullword; /* Cible de mots entiers ? */
+ bool private; /* Vocation privée ? */
- result = true;
+ flags = g_scan_token_node_plain_get_flags(G_SCAN_TOKEN_NODE_PLAIN(root));
- szstrdup(&bytes->orig, text);
+ fullword = (flags & SPNF_FULLWORD);
+ private = (flags & SPNF_PRIVATE);
- if (modifier != NULL)
- {
- bytes->modifier = modifier;
- g_object_ref(G_OBJECT(modifier));
- }
-
- bytes->flags = flags;
+ result = g_string_token_create(G_STRING_TOKEN(bytes), root, fullword, private);
return result;
@@ -302,192 +264,3 @@ static void g_scan_plain_bytes_output_to_json(const GScanPlainBytes *pattern, GS
/* TODO */
}
-
-
-/******************************************************************************
-* *
-* Paramètres : bytes = définition de la bribe à enregistrer. *
-* context = contexte de l'analyse à mener. *
-* backend = moteur de recherche à préchauffer. *
-* maxsize = taille max. des atomes (mise en commun optimisée). *
-* *
-* 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_plain_bytes_enroll(GScanPlainBytes *bytes, GScanContext *context, GEngineBackend *backend, size_t maxsize)
-{
- return false;
-#if 0
- bool result; /* Statut à retourner */
- size_t i; /* Boucle de parcours #1 */
- tracked_scan_atom_t atom; /* Atome identifié */
- size_t letters; /* Nombre de lettres présentes */
- size_t k; /* Boucle de parcours #2 */
- size_t extra_count; /* Quantité pour l'exhaustivité*/
- sized_binary_t *extra; /* Couverture supplémntaire */
- size_t remaining; /* Quantité restant à traiter */
-
- /* Génération d'une base de chaînes à couvrir */
-
- if (bytes->modifier == NULL)
- {
- bytes->raw = malloc(sizeof(sized_binary_t));
- bytes->count = 1;
-
- szstrdup(&bytes[0].raw[0], &bytes->orig);
-
- result = true;
-
- }
- else
- result = g_scan_token_modifier_transform(bytes->modifier, &bytes->orig, &bytes->raw, &bytes->count);
-
- if (!result)
- goto exit;
-
- /* Préparation pour la mémorisation des atomes */
-
- bytes->atoms = malloc(bytes->count * sizeof(tracked_scan_atom_t));
-
- /* Recherche des atomes */
-
- for (i = 0; i < bytes->count; i++)
- {
- if (bytes->flags & SPBF_CASE_INSENSITIVE)
- {
- find_best_atom(&bytes->raw[i], maxsize, &atom, &letters);
-
- if (letters == 0)
- bytes->atoms[i] = atom;
-
- /* Insertion des combinaisons pour couvrir toutes les casses */
- else
- {
- for (k = 0, extra_count = 1; k < letters; k++, extra_count *= 2)
- ;
-
- extra = make_atoms_case_insensitive(&bytes->raw[i], extra_count);
-
- remaining = bytes->count - i - 1;
-
- bytes->count += (extra_count - 1);
-
- bytes->raw = realloc(bytes->raw, bytes->count * sizeof(sized_binary_t));
-
- memmove(&bytes->raw[i + extra_count], &bytes->raw[i + 1], remaining * sizeof(sized_binary_t));
-
- for (k = 0; k < extra_count; k++)
- bytes->raw[i + k] = extra[k];
-
- free(extra);
-
- bytes->atoms = realloc(bytes->raw, bytes->count * sizeof(tracked_scan_atom_t));
-
- for (k = 0; k < extra_count; k++)
- bytes->atoms[i + k] = atom;
-
- i += extra_count - 1;
-
- }
-
- }
-
- else
- find_best_atom(&bytes->raw[i], maxsize, &bytes->atoms[i], &letters);
-
- }
-
- /* Enregistrements en masse */
-
-
- for (i = 0; i < bytes->count && result; i++)
- result = enroll_prepared_atom(&bytes->raw[i], context, backend, &bytes->atoms[i]);
-
- exit:
-
- return result;
-#endif
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : bytes = définition de la bribe à manipuler. *
-* context = contexte de l'analyse à mener. *
-* content = accès au contenu brut pour vérifications (optim.) *
-* matches = suivi des correspondances à consolider. *
-* *
-* Description : Transforme les correspondances locales en trouvailles. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_scan_plain_bytes_check(const GScanPlainBytes *bytes, GScanContext *context, GBinContent *content, pending_matches_t *matches)
-{
-#if 0
-
- size_t i; /* Boucle de parcours #1 */
- const sized_binary_t *raw; /* Données brutes d'origine */
- const tracked_scan_atom_t *atom; /* Atome correspondant */
- size_t count; /* Quantité de bribes trouvées */
- const phys_t *found; /* Localisations des bribes */
- size_t k; /* Boucle de parcours #2 */
- phys_t start; /* Point de départ */
- vmpa2t pos; /* Position dans les données */
- const bin_t *ptr; /* Accès aux données brutes */
- int ret; /* Bilan d'une comparaison */
-
- for (i = 0; i < bytes->count; i++)
- {
- raw = &bytes->raw[i];
- atom = &bytes->atoms[i];
-
- found = g_scan_context_get_atom_matches(context, atom->pid, &count);
-
- for (k = 0; k < count; k++)
- {
- start = found[k] - atom->pos;
-
- init_vmpa(&pos, start, VMPA_NO_VIRTUAL);
-
- /* Validation du contenu avant l'atome */
-
- if (atom->pos > 0)
- {
- ptr = g_binary_content_get_raw_access(content, &pos, atom->pos);
-
- ret = memcmp(raw->data, ptr, atom->pos);
- if (ret != 0) continue;
-
- }
-
- /* Validation du contenu après l'atome */
-
- if (atom->rem > 0)
- {
- advance_vmpa(&pos, atom->len);
-
- ptr = g_binary_content_get_raw_access(content, &pos, atom->rem);
-
- ret = memcmp(raw->data + atom->pos + atom->len, ptr, atom->rem);
- if (ret != 0) continue;
-
- }
-
- /* Mémorisation de la correspondance */
-
- add_pending_matches(matches, start, raw->len);
-
- }
-
- }
-#endif
-}
diff --git a/src/analysis/scan/patterns/tokens/plain.h b/src/analysis/scan/patterns/tokens/plain.h
index 80a0b4d..6ff48d7 100644
--- a/src/analysis/scan/patterns/tokens/plain.h
+++ b/src/analysis/scan/patterns/tokens/plain.h
@@ -28,9 +28,8 @@
#include <glib-object.h>
-#include "../modifier.h"
+#include "node.h"
#include "../../pattern.h"
-#include "../../../../common/szstr.h"
@@ -49,21 +48,11 @@ typedef struct _GScanPlainBytes GScanPlainBytes;
typedef struct _GScanPlainBytesClass GScanPlainBytesClass;
-/* Propriétés d'un élément textuel à rechercher */
-typedef enum _ScanPlainBytesFlags
-{
- SPBF_NONE = 0x0, /* Aucune particularité */
- SPBF_CASE_INSENSITIVE = 0x1, /* Ignorance de la casse */
- SPBF_FULL_WORD = 0x2, /* Recherche de mot entier */
-
-} ScanPlainBytesFlags;
-
-
/* Indique le type défini pour une suite d'octets à retrouver dans un binaire. */
GType g_scan_plain_bytes_get_type(void);
/* Construit un gestionnaire de recherche de texte brut. */
-GSearchPattern *g_scan_plain_bytes_new(const sized_binary_t *, GScanTokenModifier *, ScanPlainBytesFlags);
+GSearchPattern *g_scan_plain_bytes_new(GScanTokenNode *);