diff options
Diffstat (limited to 'src/analysis/scan/patterns/tokens/nodes/plain.c')
-rw-r--r-- | src/analysis/scan/patterns/tokens/nodes/plain.c | 902 |
1 files changed, 713 insertions, 189 deletions
diff --git a/src/analysis/scan/patterns/tokens/nodes/plain.c b/src/analysis/scan/patterns/tokens/nodes/plain.c index 71f5f17..166ce74 100644 --- a/src/analysis/scan/patterns/tokens/nodes/plain.c +++ b/src/analysis/scan/patterns/tokens/nodes/plain.c @@ -52,20 +52,26 @@ static void g_scan_token_node_plain_finalize(GScanTokenNodePlain *); /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ +/* Communique l'intérêt d'un noeud au sein d'une analyse. */ +static float g_scan_token_node_plain_compute_weight_for_scan(const GScanTokenNodePlain *); + /* 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, size_t *); +static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *, GEngineBackend *, size_t, size_t *); + +/* Récupère un identifiant final pour un atome d'octets. */ +static bool g_scan_token_node_plain_build_id(GScanTokenNodePlain *, GEngineBackend *); /* 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 *, bool, phys_t, GBinContent *); /* Transforme les correspondances locales en trouvailles. */ -static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *); +static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *, scan_node_check_params_t *, TokenNodeCheckFlags, 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 *); +static void g_scan_token_node_plain_check_backward(const GScanTokenNodePlain *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); @@ -102,8 +108,11 @@ static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *klass) node = G_SCAN_TOKEN_NODE_CLASS(klass); + node->compute_weight = (compute_scan_token_node_weight_fc)g_scan_token_node_plain_compute_weight_for_scan; + node->apply = (apply_scan_token_node_flags_fc)NULL; 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->build_id = (build_scan_token_node_id_fc)g_scan_token_node_plain_build_id; 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; @@ -124,8 +133,6 @@ 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; @@ -314,6 +321,29 @@ char *g_scan_token_node_plain_get_modifier_path(const GScanTokenNodePlain *node, /****************************************************************************** * * +* Paramètres : node = noeud de motif à consulter. * +* * +* Description : Communique l'intérêt d'un noeud au sein d'une analyse. * +* * +* Retour : Poids de l'importance pour un départ de scan. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static float g_scan_token_node_plain_compute_weight_for_scan(const GScanTokenNodePlain *node) +{ + float result; /* Valeur à retourner */ + + result = node->orig.len; + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : node = point de départ du parcours à effectuer. * * points = points capitaux de l'arborescence. [OUT] * * * @@ -327,9 +357,25 @@ char *g_scan_token_node_plain_get_modifier_path(const GScanTokenNodePlain *node, static void g_scan_token_node_plain_visit(GScanTokenNodePlain *node, scan_tree_points_t *points) { + GScanTokenNode *candidate; /* Autre version du noeud */ + float node_weight; /* Poids du noeud courant */ + float other_weight; /* Poids de l'autre noeud */ + if (points->first_plain == NULL) points->first_plain = G_SCAN_TOKEN_NODE(node); + else + { + candidate = G_SCAN_TOKEN_NODE(node); + + node_weight = g_scan_token_node_compute_weight_for_scan(candidate); + other_weight = g_scan_token_node_compute_weight_for_scan(points->first_plain); + + if (node_weight >= other_weight) + points->first_plain = candidate; + + } + } @@ -349,7 +395,7 @@ static void g_scan_token_node_plain_visit(GScanTokenNodePlain *node, scan_tree_p * * ******************************************************************************/ -static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow) +static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GEngineBackend *backend, size_t maxsize, size_t *slow) { bool result; /* Statut à retourner */ size_t i; /* Boucle de parcours #1 */ @@ -442,7 +488,7 @@ static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanConte /* Enregistrements en masse */ for (i = 0; i < node->count && result; i++) - result = enroll_prepared_atom(&node->raw[i], context, backend, &node->atoms[i]); + result = enroll_prepared_atom(&node->raw[i], backend, &node->atoms[i]); exit: @@ -453,6 +499,34 @@ static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanConte /****************************************************************************** * * +* Paramètres : node = définition de la bribe à peaufiner. * +* backend = moteur de recherche à préchauffer. * +* * +* Description : Récupère un identifiant final pour un atome d'octets. * +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_token_node_plain_build_id(GScanTokenNodePlain *node, GEngineBackend *backend) +{ + bool result; /* Statut à retourner */ + size_t i; /* Boucle de parcours #1 */ + + result = true; + + for (i = 0; i < node->count && result; i++) + result = build_atom_pattern_id(&node->atoms[i], backend); + + return result; + +} + + +/****************************************************************************** +* * * 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. * @@ -478,11 +552,11 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const init_vmpa(&pos, start, VMPA_NO_VIRTUAL); - /* Validation du contenu avant l'atome */ + /* Validation du motif intégral */ - if (atom->pos > 0) + if (atom == NULL) { - ptr = g_binary_content_get_raw_access(content, &pos, atom->pos); + ptr = g_binary_content_get_raw_access(content, &pos, raw->len); /** * Si la partion atomique recherchée est trouvée en début de contenu, @@ -492,39 +566,67 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const if (ptr == NULL) goto done; if (nocase) - ret = memcasecmp(raw->data, ptr, atom->pos); + ret = memcasecmp(raw->data, ptr, raw->len); else - ret = memcmp(raw->data, ptr, atom->pos); + ret = memcmp(raw->data, ptr, raw->len); - if (ret != 0) goto done; + result = (ret == 0); } - /* Validation du contenu après l'atome */ + /* Validation des extrémités */ - if (atom->rem > 0) + else { - advance_vmpa(&pos, atom->len); + /* Validation du contenu avant l'atome */ - ptr = g_binary_content_get_raw_access(content, &pos, atom->rem); + if (atom->pos > 0) + { + ptr = g_binary_content_get_raw_access(content, &pos, atom->pos); - /** - * Si la partion atomique recherchée est trouvée en fin de contenu, - * le reste du motif de recherche va déborder. L'accès correspondant - * est donc refusé, et cette situation est prise en compte ici. - */ - if (ptr == NULL) goto done; + /** + * Si la partion atomique recherchée est trouvée en début de contenu, + * le reste du motif de recherche va déborder. L'accès correspondant + * est donc refusé, et cette situation est prise en compte ici. + */ + if (ptr == NULL) goto done; - 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 (nocase) + ret = memcasecmp(raw->data, ptr, atom->pos); + else + ret = memcmp(raw->data, ptr, atom->pos); - if (ret != 0) goto done; + if (ret != 0) goto done; - } + } - result = true; + /* 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); + + /** + * Si la partion atomique recherchée est trouvée en fin de contenu, + * le reste du motif de recherche va déborder. L'accès correspondant + * est donc refusé, et cette situation est prise en compte ici. + */ + if (ptr == NULL) goto done; + + 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; + + } + + result = true; + + } done: @@ -535,13 +637,10 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const /****************************************************************************** * * -* 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] * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* cflags = altérations de traitement à respecter. * +* skip = détermine si l'analyse est différée. [OUT] * * * * Description : Transforme les correspondances locales en trouvailles. * * * @@ -551,236 +650,408 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const * * ******************************************************************************/ -static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip) +static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip) { - bool initialized; /* Initialisation du suivi ? */ bool track_path; /* Conservation du chemin */ bool nocase; /* Pas d'intérêt pour la casse */ - size_t ocount; /* Quantité de bornes présentes*/ size_t i; /* Boucle de parcours #1 */ 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 new_begin; /* Nouveau départ à tester */ + GUMemSlice *atoms; /* Localisations des bribes */ + const umem_slice_iter_t *aiter; /* Boucle de parcours #2 */ + match_area_t *end; /* Borne de fin de parcours */ + match_area_t *pos; /* Position courante */ 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 */ + match_area_t *area; /* Correspondance à valider */ + match_area_t *next; /* Correspondance suivante */ + phys_t after; /* Espace disposible après */ + phys_t min_end; /* Fin la plus proche possible */ + phys_t max_end; /* Fin la plus éloignée trouvée*/ + bool updated; /* Existence de correspondance */ + size_t rcount; /* Quantité de bornes présentes*/ + const node_offset_range_t *ranges; /* Bornes d'espace à parcourir */ + size_t r; /* Boucle de parcours #xxxxxxxxxxxx*/ + phys_t p; /* Boucle de parcours #xxxxxxxxxxxx*/ + phys_t updated_edge; /* Nouvelle bordure de motif */ + match_area_t *new_area; /* Copie de correspondance */ + + if (0x1) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip); if (*skip) return; - initialized = are_pending_matches_initialized(matches); - track_path = (G_SCAN_TOKEN_NODE(node)->flags & STNF_MAIN); nocase = (node->flags & SPNF_CASE_INSENSITIVE); - get_node_search_offset_ranges(offset, &ocount); - - for (i = 0; i < node->count; i++) + /** + * Création de premières marques de correspondances. + */ + if (!params->initialized) { - raw = &node->raw[i]; - atom = &node->atoms[i]; + for (i = 0; i < node->count; i++) + { + raw = &node->raw[i]; + atom = &node->atoms[i]; - found = g_scan_context_get_atom_matches(context, atom->pid, &count); + atoms = g_scan_context_get_atom_matches(params->context, atom->pid); - if (!initialized) - { - for (k = 0; k < count; k++) + if (atom->fast_check) { - 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 (ocount > 0) + for (aiter = g_umem_slice_get_iter(atoms); aiter != NULL; aiter = aiter->next) { - if (!does_node_search_offset_include_pos_forward(offset, 0, new_begin)) + end = aiter->data_end; + + for (pos = aiter->data; pos < end; pos++) { - if (not) - add_pending_match(matches, new_begin, raw->len); + /** + * La modification de la zone d'origine est possible dans tous les cas + * car cette zone a été allouée de façon dédiée à un type de correspondances + * et ne sera pas réutilisée comme autre source de correspondance ailleurs. + */ + pos->end = pos->start + atom->len; - continue; + if (cflags & TNCF_KEEP_DISCARDED) + { + add_tail_match_area(pos, ¶ms->kept_areas); + params->kept_count++; + } + + else if (cflags & TNCF_CREATE_NEW) + { + add_tail_match_area(pos, ¶ms->created_areas); + params->created_count++; + } + + else + { + assert(cflags & TNCF_UPDATE_IN_PLACE); + + add_tail_match_area(pos, ¶ms->main_areas); + params->main_count++; + + } } + } - status = check_scan_token_node_plain_content(raw, atom, nocase, new_begin, content); + } - if ((status && !not) || (!status && not)) + else + { + for (aiter = g_umem_slice_get_iter(atoms); aiter != NULL; aiter = aiter->next) { - /** - * Il ne peut y avoir qu'une seule séquence d'octets à un même - * emplacement, donc le couple (new_begin, len) enregistré est - * unique. - */ - if (track_path) - add_pending_match_with_path(matches, new_begin, raw->len, i); - else - add_pending_match(matches, new_begin, raw->len); + end = aiter->data_end; + + for (pos = aiter->data; pos < end; pos++) + { + status = check_scan_token_node_plain_content(raw, atom, nocase, + pos->start - atom->pos, params->content); + + if (status) + { + /** + * La modification de la zone d'origine est possible dans tous les cas + * car cette zone a été allouée de façon dédiée à un type de correspondances + * et ne sera pas réutilisée comme autre source de correspondance ailleurs. + */ + pos->start -= atom->pos; + pos->end = pos->start + raw->len; + + if (cflags & TNCF_KEEP_DISCARDED) + { + add_tail_match_area(pos, ¶ms->kept_areas); + params->kept_count++; + } + + else if (cflags & TNCF_CREATE_NEW) + { + add_tail_match_area(pos, ¶ms->created_areas); + params->created_count++; + } + + else + { + assert(cflags & TNCF_UPDATE_IN_PLACE); + + add_tail_match_area(pos, ¶ms->main_areas); + params->main_count++; + + } + + } + + } } + } } - else - { - reset_pending_matches_ttl(matches); + } - pending_ptr = get_all_pending_matches(matches, &pcount); + /** + * Poursuite des traitements sur des correspondances déjà amorcées, impliquant + * des comparaisons entières de motifs. + */ + else + { + if (0x1) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count); - for (p = 0; p < pcount; p++) + for_each_match_area_safe(area, ¶ms->main_areas, next) + { + assert(area->end <= params->content_end); + + after = params->content_end - area->end; + + if (0x1) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end); + + /** + * Il ne peut y avoir qu'une seule séquence d'octets à un même + * emplacement. En revanche, des modificateurs peuvent construire + * possédant une même base, mais offrant des suffixes différents + * (par exemple, un marqueur nul UTF-16 final en complément). + * + * L'ensemble des combinaisons produites doit ainsi être exploré. + */ + + /** + * Par ailleurs, même si une base de couples uniques est assurée, + * la constitution d'un ensemble de noeuds peut amener une redondance + * dans les emplacements de correspondances ; ces doublons éventuels + * sont alors filtrés par un appel à sort_match_areas_no_dup(). + * + * Par exemple, pour la séquence d'octets analysés suivante : + * + * aaa....bbb + * + * La définition { (61 61 | 61 61 61) [4-5] 62 62 62 } peut établir + * les correspondances suivantes : + * + * aa.....bbb -> couple pending[x] (0;2) puis (0;10) + * ^ + * aa....bbb -> couple pending[y] (1;3) puis (1;10) + * ^ + * aaa....bbb -> couple pending[z] (0;3) puis (0;10) + * ^ + * + * Par ailleurs, une même base de départ peut conduire à plusieurs + * zones de correspondances. + * + * Par exemple, pour la séquence d'octets analysés suivante : + * + * aa..bb..bb + * + * La définition { 61 61 [2-6] 62 62 } peut établir + * les correspondances suivantes : + * + * aa..bb..bb -> couple pending[x] (0;2) puis (0;6) + * ^ + * aa..bb..bb -> couple pending[x] (0;2) puis (0;10) + * ^ + */ + + /** + * Dans la première situation, c'est la bribe 62 62 62 qui fait l'objet + * d'une recherche de motifs. Les autres bribes sont recherchées + * manuellement ici, car l'espace de séparation est léger (inférieur à + * MAX_RANGE_FOR_MANUAL_CHECK). + * + * La seconde situation bénéficie de recherches automatisées pour + * l'ensemble des motifs, du fait d'une valeur de séparation plus + * importante. + * + * Dans les deux cas, l'espace de séparation est entièrement considéré. + * La sélection de la correspondance à retour s'établit selon un + * paramètre de configuation : doit-on être avare sur les distances + * consommées ou non ? + */ + + min_end = params->content_end; + max_end = params->content_start; + + updated = false; + + for (i = 0; i < node->count; i++) { - pending = (*pending_ptr) + p; + raw = &node->raw[i]; - assert(matches->content_start <= pending->start); - - for (k = 0; k < count; k++) + /* Souplesse dans les positions ? */ + if (offsets_exist(¶ms->offset)) { - new_begin = found[k] - atom->pos; + ranges = get_node_search_offset_ranges_2(¶ms->offset, &rcount); - /** - * Si bornes de tolérance il y a, on valide la position. - * - * Sinon les correspondances passées et actuelle doivent - * être jointes. - */ - if (ocount > 0) + for (r = 0; r < rcount; r++) { - if (!does_node_search_offset_include_pos_forward(offset, pending->end, new_begin)) + assert(ranges[r].has_max); + assert((ranges[r].max - ranges[r].min) <= MAX_RANGE_FOR_MANUAL_CHECK); + + for (p = ranges[r].min; p <= ranges[r].max; p++) { - if (not) + /** + * 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 sans appel. + */ + if ((p + raw->len) > after) + break; + + status = check_scan_token_node_plain_content(raw, NULL, nocase, + area->end + p, params->content); + + if (status) { - extend_pending_match_ending(matches, p, pending->end + raw->len); + updated_edge = area->end + p + 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; + if (updated_edge < min_end) + min_end = updated_edge; - } + if (updated_edge > max_end) + max_end = updated_edge; - continue; + updated = true; + + } } + } - else + + } + + /* Position immédiatement attendue */ + 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 sans appel. + */ + if (raw->len > after) + continue; + + status = check_scan_token_node_plain_content(raw, NULL, nocase, area->end, params->content); + + if (status) { - if (pending->end != new_begin) - { - if (not) - { - extend_pending_match_ending(matches, p, pending->end + raw->len); + updated_edge = area->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; + if (updated_edge < min_end) + min_end = updated_edge; - } + if (updated_edge > max_end) + max_end = updated_edge; - continue; + updated = true; - } } - status = check_scan_token_node_plain_content(raw, atom, nocase, new_begin, content); + } - if ((status && !not) || (!status && not)) + } + + if (updated) + { + /** + * Si seuls les rejets sont d'intérêt, les correspondances établies + * ne se voient pas mises à jours ni retirées. + */ + + if ((cflags & TNCF_KEEP_DISCARDED) == 0) + { + if (cflags & TNCF_UPDATE_IN_PLACE) + area->end = (1 /* greedy */ ? min_end : max_end); + + else if (cflags & TNCF_CREATE_NEW) { - /** - * Même si une base de couples uniques est assurée, - * la constitution d'un ensemble de noeuds peut amener une - * redondance dans les emplacements de correspondances. - * - * Par exemple, pour la séquence d'octets analysés suivante : - * - * aaa....bbb - * - * La définition { (61 61 | 61 61 61) [4-5] 62 62 62 } peut établir - * les correspondances suivantes : - * - * aa.....bbb -> couple pending[x] (0;2) puis (0;10) - * ^ - * aa....bbb -> couple pending[y] (1;3) puis (1;10) - * ^ - * aaa....bbb -> couple pending[z] (0;3) puis (0;10) - * ^ - * - * Par ailleurs, une même base de départ peut conduire - * à plusieurs zone de correspondances. - * - * Par exemple, pour la séquence d'octets analysés suivante : - * - * aa..bb..bb - * - * La définition { 61 61 [2-6] 62 62 } peut établir - * les correspondances suivantes : - * - * aa..bb..bb -> couple pending[x] (0;2) puis (0;6) - * ^ - * aa..bb..bb -> couple pending[x] (0;2) puis (0;10) - * ^ - */ + new_area = g_umem_slice_alloc(params->allocator); - /** - * La seconde situation est prise en compte par la fonction - * 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. - */ + *new_area = *area; - extend_pending_match_ending(matches, p, new_begin + raw->len); + new_area->end = (1 /* greedy */ ? min_end : max_end); - /** - * 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; + add_tail_match_area(new_area, ¶ms->created_areas); + params->created_count++; } +#ifndef NDEBUG + else + assert(false); +#endif + } } - purge_pending_matches(matches); + else + { + /** + * Si la liste principale doit être mise à jour... + */ + + if (cflags & TNCF_UPDATE_IN_PLACE) + { + del_match_area(area, ¶ms->main_areas); + assert(params->main_count > 0); + params->main_count--; + } + + /** + * Au cas où le rejet est d'intérêt, l'absence de correspondance + * est conservée dans une liste dédiée. + */ + + if (cflags & TNCF_KEEP_DISCARDED) + { + if (cflags & TNCF_UPDATE_IN_PLACE) + { + add_tail_match_area(area, ¶ms->kept_areas); + params->kept_count++; + } + + else if (cflags & TNCF_CREATE_NEW) + { + new_area = g_umem_slice_alloc(params->allocator); + + *new_area = *area; + + new_area->end = (1 /* greedy */ ? min_end : max_end); + + add_tail_match_area(new_area, ¶ms->kept_areas); + params->kept_count++; + + } + +#ifndef NDEBUG + else + assert(false); +#endif + + } + + } } } - set_pending_matches_initialized(matches); + params->initialized = true; - disable_all_ranges_in_node_search_offset(offset); + disable_all_ranges_in_node_search_offset(¶ms->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] * +* Paramètres : node = définition de la bribe à manipuler. * +* params = accès direct aux éléments utiles aux validations. * +* cflags = altérations de traitement à respecter. * +* skip = détermine si l'analyse est différée. [OUT] * * * * Description : Transforme les correspondances locales en trouvailles. * * * @@ -790,19 +1061,272 @@ static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *nod * * ******************************************************************************/ -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) +static void g_scan_token_node_plain_check_backward(const GScanTokenNodePlain *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip) { + + + bool track_path; /* Conservation du chemin */ + bool nocase; /* Pas d'intérêt pour la casse */ + + + + + size_t i; /* Boucle de parcours #1 */ + + + const sized_binary_t *raw; /* Données brutes d'origine */ + + + bool status; /* Bilan d'une correspondance */ + + + + + + match_area_t *area; /* Correspondance à valider */ + match_area_t *next; /* Correspondance suivante */ + phys_t before; /* Espace disposible avant */ + phys_t min_start; /* Début le plus proche trouvé */ + phys_t max_start; /* Début le plus distant trouvé*/ + bool updated; /* Existence de correspondance */ + size_t rcount; /* Quantité de bornes présentes*/ + const node_offset_range_t *ranges; /* Bornes d'espace à parcourir */ + size_t r; /* Boucle de parcours #xxxxxxxxxxxx*/ + phys_t p; /* Boucle de parcours #xxxxxxxxxxxx*/ + phys_t updated_edge; /* Nouvelle bordure de motif */ + match_area_t *new_area; /* Copie de correspondance */ + + if (0x1) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip); + if (*skip) return; + /** + * En lecture à rebourd, au moins un noeud a été solicité pour analyse (lors + * du sens de lecture normal). Donc l'initialisation a déjà dû avoir lieu. + */ + + assert(params->initialized); + + track_path = (G_SCAN_TOKEN_NODE(node)->flags & STNF_MAIN); + + nocase = (node->flags & SPNF_CASE_INSENSITIVE); + - printf("TODO\n"); - assert(0); + /** + * ............. + */ + if (0) + { + + + ; + + + + } + + /** + * Poursuite des traitements sur des correspondances déjà amorcées, impliquant + * des comparaisons entières de motifs. + */ + else + { + if (0x1) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count); + + for_each_match_area_safe(area, ¶ms->main_areas, next) + { + assert(params->content_start <= area->start); + + before = area->start - params->content_start; + + if (0x1) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end); + + /** + * Il ne peut y avoir qu'une seule séquence d'octets à un même + * emplacement. En revanche, des modificateurs peuvent construire + * possédant une même base, mais offrant des suffixes différents + * (par exemple, un marqueur nul UTF-16 final en complément). + * + * L'ensemble des combinaisons produites doit ainsi être exploré. + */ + + min_start = params->content_start; + max_start = params->content_end; + + updated = false; + + for (i = 0; i < node->count; i++) + { + raw = &node->raw[i]; + + /* Souplesse dans les positions ? */ + if (offsets_exist(¶ms->offset)) + { + ranges = get_node_search_offset_ranges_2(¶ms->offset, &rcount); + for (r = 0; r < rcount; r++) + { + assert(ranges[r].has_max); + assert((ranges[r].max - ranges[r].min) <= MAX_RANGE_FOR_MANUAL_CHECK); + + for (p = ranges[r].min; p <= ranges[r].max; p++) + { + /** + * 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 sans appel. + */ + if ((p + raw->len) > before) + break; + + status = check_scan_token_node_plain_content(raw, NULL, nocase, + area->start - raw->len - p, + params->content); + + if (status) + { + updated_edge = area->start - raw->len - p; + + if (updated_edge > min_start) + min_start = updated_edge; + + if (updated_edge < max_start) + max_start = updated_edge; + + updated = true; + + } + + } + + } + + } + + /* Position immédiatement attendue */ + else + { + /** + * Si la fin 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 sans appel. + */ + if (raw->len > before) + continue; + + status = check_scan_token_node_plain_content(raw, NULL, nocase, + area->start - raw->len, + params->content); + + if (status) + { + updated_edge = area->start - raw->len; + + if (updated_edge > min_start) + min_start = updated_edge; + + if (updated_edge < max_start) + max_start = updated_edge; + + updated = true; + + } + + } + + } + + if (updated) + { + /** + * Si seuls les rejets sont d'intérêt, les correspondances établies + * ne se voient pas mises à jours ni retirées. + */ + + if ((cflags & TNCF_KEEP_DISCARDED) == 0) + { + if (cflags & TNCF_UPDATE_IN_PLACE) + area->start = (1 /* greedy */ ? min_start : max_start); + + else if (cflags & TNCF_CREATE_NEW) + { + new_area = g_umem_slice_alloc(params->allocator); + + *new_area = *area; + + new_area->start = (1 /* greedy */ ? min_start : max_start); + + add_tail_match_area(new_area, ¶ms->created_areas); + params->created_count++; + + } + +#ifndef NDEBUG + else + assert(false); +#endif + + } + + } + + else + { + /** + * Si la liste principale doit être mise à jour... + */ + + if (cflags & TNCF_UPDATE_IN_PLACE) + { + del_match_area(area, ¶ms->main_areas); + assert(params->main_count > 0); + params->main_count--; + } + + /** + * Au cas où le rejet est d'intérêt, l'absence de correspondance + * est conservée dans une liste dédiée. + */ + + if (cflags & TNCF_KEEP_DISCARDED) + { + if (cflags & TNCF_UPDATE_IN_PLACE) + { + add_tail_match_area(area, ¶ms->kept_areas); + params->kept_count++; + } + + else if (cflags & TNCF_CREATE_NEW) + { + new_area = g_umem_slice_alloc(params->allocator); + + *new_area = *area; + + new_area->start = (1 /* greedy */ ? min_start : max_start); + + add_tail_match_area(new_area, ¶ms->kept_areas); + params->kept_count++; + + } + +#ifndef NDEBUG + else + assert(false); +#endif + + } + + } + + } + + } + disable_all_ranges_in_node_search_offset(¶ms->offset); } |