diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2023-09-12 04:43:02 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2023-09-12 04:45:25 (GMT) |
commit | fed4c10b9bb1c6f99440dba3839a1e7b56b40359 (patch) | |
tree | d544bde345c16a5eff19c0f9a074c09b366f7dbe /src/analysis/scan/patterns/tokens | |
parent | 155c500b8933d2c7269215ea1d141d341de0a44f (diff) |
Save current state with some ROST extra features.
Diffstat (limited to 'src/analysis/scan/patterns/tokens')
35 files changed, 4252 insertions, 756 deletions
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(¬->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 *); |