diff options
Diffstat (limited to 'src/analysis/scan/patterns/tokens/nodes')
| -rw-r--r-- | src/analysis/scan/patterns/tokens/nodes/any.c | 461 | ||||
| -rw-r--r-- | src/analysis/scan/patterns/tokens/nodes/choice.c | 342 | ||||
| -rw-r--r-- | src/analysis/scan/patterns/tokens/nodes/masked-int.h | 5 | ||||
| -rw-r--r-- | src/analysis/scan/patterns/tokens/nodes/masked.c | 735 | ||||
| -rw-r--r-- | src/analysis/scan/patterns/tokens/nodes/masked.h | 9 | ||||
| -rw-r--r-- | src/analysis/scan/patterns/tokens/nodes/not.c | 98 | ||||
| -rw-r--r-- | src/analysis/scan/patterns/tokens/nodes/plain.c | 902 | ||||
| -rw-r--r-- | src/analysis/scan/patterns/tokens/nodes/sequence.c | 116 | 
8 files changed, 2028 insertions, 640 deletions
| diff --git a/src/analysis/scan/patterns/tokens/nodes/any.c b/src/analysis/scan/patterns/tokens/nodes/any.c index 6233cb4..10a01cd 100644 --- a/src/analysis/scan/patterns/tokens/nodes/any.c +++ b/src/analysis/scan/patterns/tokens/nodes/any.c @@ -55,10 +55,10 @@ static void g_scan_token_node_any_finalize(GScanTokenNodeAny *);  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 *); +static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);  /* Transforme les correspondances locales en trouvailles. */ -static void g_scan_token_node_any_check_backward(const GScanTokenNodeAny *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *); +static void g_scan_token_node_any_check_backward(const GScanTokenNodeAny *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); @@ -95,6 +95,7 @@ static void g_scan_token_node_any_class_init(GScanTokenNodeAnyClass *klass)      node = G_SCAN_TOKEN_NODE_CLASS(klass); +    node->apply = (apply_scan_token_node_flags_fc)NULL;      node->visit = (visit_scan_token_node_fc)NULL;      node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_any_enroll;      node->check_forward = (check_scan_token_node_fc)g_scan_token_node_any_check_forward; @@ -117,8 +118,6 @@ static void g_scan_token_node_any_class_init(GScanTokenNodeAnyClass *klass)  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; @@ -297,13 +296,10 @@ static bool g_scan_token_node_any_enroll(GScanTokenNodeAny *node, GScanContext *  /******************************************************************************  *                                                                             * -*  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.       *  *                                                                             * @@ -313,66 +309,250 @@ static bool g_scan_token_node_any_enroll(GScanTokenNodeAny *node, GScanContext *  *                                                                             *  ******************************************************************************/ -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) +static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)  { -    bool initialized;                       /* Initialisation du suivi ?   */ +    ScanTokenNodeFlags flags;               /* Particularités du noeud     */      bool forced;                            /* Inclusion dans un scan ?    */      phys_t size;                            /* Quantité d'octets considérés*/ -    const phys_t *datasize;                 /* Taille max. à communiquer   */ +    phys_t match_size;                      /* Taille de correspondance    */ +    phys_t i;                               /* Boucle de parcours #1       */ +    match_area_t *space;                    /* Nouvelle zone à intégrer    */ +    match_area_t *area;                     /* Correspondance à valider    */ +    match_area_t *next;                     /* Correspondance suivante     */ +    phys_t after;                           /* Espace disposible après     */ +    phys_t min_end;                         /* Fin la plus proche possible */ +    phys_t max_end;                         /* Fin la plus éloignée trouvée*/ +    bool updated;                           /* Existence de correspondance */ +    size_t rcount;                          /* Quantité de bornes présentes*/ +    const node_offset_range_t *ranges;      /* Bornes d'espace à parcourir */ +    size_t r;                               /* Boucle de parcours #2       */ +    phys_t updated_edge;                    /* Nouvelle bordure de motif   */ +    match_area_t *new_area;                 /* Copie de correspondance     */ + +    if (0x1) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);      if (*skip)          return; +    flags = g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)); -    //         $a = { [1-3] 6f } -    // pas d'initialisation, construction de résultats avec une taille nulle +    forced = (flags & STNF_MAIN); +    assert((!params->initialized && forced) || (params->initialized & !forced)); + +    /** +     * La situation forcée correspond au cas particulier d'une définition +     * complètement abstraite : ??, ?? ??, etc. +     */ +    if (forced) +    { +        size = params->content_end - params->content_start; +        if (node->has_max && 0 /* greedy ? */) +        { +            match_size = node->max; -    initialized = are_pending_matches_initialized(matches); +            if (match_size > size) +                match_size = node->min; -    forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN); +        } +        else +            match_size = node->min; + +        /** +         * Si le contenu binaire est trop petit pour contenir au moins un enregistrement, +         * aucune correspondance n'est enregistrée. Comme le noeud est le principale, ie. +         * seul et unique, l'analyse s'arrête ensuite d'elle même. +         * +         * Si le contenu binaire est suffisamment large, des espaces sont créés et l'analyse +         * se termine ensuite. La conservation des espaces n'est donc pas utile, ni réalisée. +         */ -    size = matches->content_end - matches->content_start; +        if (match_size <= size) +        { +            size -= match_size; -    datasize = (not ? &size : NULL); +            assert(cflags & TNCF_UPDATE_IN_PLACE); -    if (forced) -    { -        assert(!initialized); +            for (i = 0; i < size; i++) +            { +                space = g_umem_slice_alloc(params->allocator); -        if (node->min > size) -            /* TODO set abort in matches */; +                space->start = params->content_start + i; +                space->end = space->start + match_size; -        else -            add_range_to_node_search_offset(offset, -                                            matches->content_start, -                                            matches->content_end - matches->content_start, -                                            datasize); +                add_tail_match_area(space, ¶ms->main_areas); +                params->main_count++; + +            } + +        }      } + +    /** +     * Situation usuelle : des espaces séparent deux noeuds. +     */      else      { -        assert(initialized); +        assert(params->initialized); + +        /** +         * Les espaces existants sont à compléter. La présence de tels espaces +         * restant à traiter peut provenir d'un aiguillage imposé par un motif +         * tel que : +         * +         *    ( aa ?? ?? | bb cc dd ) [0-5] ee ee +         * +         * Deux espaces sont à considérer avant de rechercher des octets ee : +         * [2-7] et [0-5]. +         * +         * Note : ces espaces peuvent être disjoints. +         * +         * Si aucun espace n'est en place, un est créé. +         */ +        extend_node_search_offset(¶ms->offset, node->min, node->max, node->has_max); -        // TODO : compléter les intervales éventuels déjà en place +        /** +         * Si un décalage enregistré ne peut être consommé par un noeud, les +         * résultats sont étendus ici à minima ou maxima. +         */ +        if (flags & STNF_LAST) +        { +            assert(offsets_exist(¶ms->offset)); -        /* -        printf("[i] create hole: %llx <-> %llx\n", -               (unsigned long long)node->min, -               (unsigned long long)node->max); -        */ +            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(area->end <= params->content_end); -        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); +                after = params->content_end - area->end; + +                if (0x1) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end); -        // TODO : si dernier, virer les correspondances qui n'ont plus l'espace de fin requis -        // -> au niveau du noeud, en fonction du flag _LAST +                min_end = params->content_end; +                max_end = params->content_start; + +                updated = false; + +                ranges = get_node_search_offset_ranges_2(¶ms->offset, &rcount); + +                for (r = 0; r < rcount; r++) +                { +                    if (ranges[r].min > after) +                        continue; + +                    updated_edge = area->end + ranges[r].min; + +                    if (updated_edge < min_end) +                        min_end = updated_edge; + +                    if (ranges[r].has_max) +                    { +                        if (ranges[r].max > after) +                            updated_edge = params->content_end; +                        else +                            updated_edge = area->end + ranges[r].max; + +                        if (updated_edge > max_end) +                            max_end = updated_edge; + +                    } + +                    updated = true; + +                } + +                if (updated) +                { +                    /** +                     * Si seuls les rejets sont d'intérêt, les correspondances établies +                     * ne se voient pas mises à jours ni retirées. +                     */ + +                    if ((cflags & TNCF_KEEP_DISCARDED) == 0) +                    { +                        if (cflags & TNCF_UPDATE_IN_PLACE) +                            area->end = (1 /* greedy */ ? min_end : max_end); + +                        else if (cflags & TNCF_CREATE_NEW) +                        { +                            new_area = g_umem_slice_alloc(params->allocator); + +                            *new_area = *area; + +                            new_area->end = (1 /* greedy */ ? min_end : max_end); + +                            add_tail_match_area(new_area, ¶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->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 + +                    } + +                } + +            } + +            disable_all_ranges_in_node_search_offset(¶ms->offset); + +        }      } @@ -381,13 +561,10 @@ static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *node, G  /******************************************************************************  *                                                                             * -*  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.       *  *                                                                             * @@ -397,55 +574,191 @@ static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *node, G  *                                                                             *  ******************************************************************************/ -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) +static void g_scan_token_node_any_check_backward(const GScanTokenNodeAny *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)  { +    ScanTokenNodeFlags flags;               /* Particularités du noeud     */  #ifndef NDEBUG      bool forced;                            /* Inclusion dans un scan ?    */  #endif -    phys_t size;                            /* Quantité d'octets considérés*/ -    const phys_t *datasize;                 /* Taille max. à communiquer   */ +    match_area_t *area;                     /* Correspondance à valider    */ +    match_area_t *next;                     /* Correspondance suivante     */ +    phys_t before;                          /* Espace disposible avant     */ +    phys_t min_start;                       /* Début le plus proche trouvé */ +    phys_t max_start;                       /* Début le plus distant trouvé*/ +    bool updated;                           /* Existence de correspondance */ +    size_t rcount;                          /* Quantité de bornes présentes*/ +    const node_offset_range_t *ranges;      /* Bornes d'espace à parcourir */ +    size_t r;                               /* Boucle de parcours          */ +    phys_t updated_edge;                    /* Nouvelle bordure de motif   */ +    match_area_t *new_area;                 /* Copie de correspondance     */ + +    if (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 lecteur normal). Donc l'initialisation a déjà dû avoir lieu. +     * du sens de lecture normal). Donc l'initialisation a déjà dû avoir lieu.       */ -    assert(are_pending_matches_initialized(matches)); + +    assert(params->initialized); + +    flags = g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node));      /**       * Si les recherches associées au noeud ont été forcées, alors les traitements       * liés ont déjà été effectués, et l'appel de cette fonction aurait dû être sauté.       */  #ifndef NDEBUG -    forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN); +    forced = (flags & STNF_MAIN);      assert(!forced);  #endif -    size = matches->content_end - matches->content_start; +    /** +     * Les considérations pour l'extension des espaces en place sont identiques +     * à celles formulées dans la fonction g_scan_token_node_any_check_forward(). +     */ -    if (node->min > size) -        /* TODO set abort in matches */; +    extend_node_search_offset(¶ms->offset, node->min, node->max, node->has_max); -    else +    /** +     * Si un décalage enregistré ne peut être consommé par un noeud, les +     * résultats sont étendus ici à minima ou maxima. +     */ + +    if (flags & STNF_FIRST)      { -        datasize = (not ? &size : NULL); +        assert(offsets_exist(¶ms->offset)); -        /** -         * 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 (0x1) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count); -        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); +        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); + +            min_start = params->content_start; +            max_start = params->content_end; + +            updated = false; + +            ranges = get_node_search_offset_ranges_2(¶ms->offset, &rcount); + +            for (r = 0; r < rcount; r++) +            { +                if (ranges[r].min > before) +                    continue; + +                updated_edge = area->start - ranges[r].min; + +                if (updated_edge > min_start) +                    min_start = updated_edge; + +                if (ranges[r].has_max) +                { +                    if (ranges[r].max > before) +                        updated_edge = params->content_start; +                    else +                        updated_edge = area->start - ranges[r].max; + +                    if (updated_edge < max_start) +                        max_start = updated_edge; + +                } + +                updated = true; + +            } + +            if (updated) +            { +                /** +                 * Si seuls les rejets sont d'intérêt, les correspondances établies +                 * ne se voient pas mises à jours ni retirées. +                 */ + +                if ((cflags & TNCF_KEEP_DISCARDED) == 0) +                { +                    if (cflags & TNCF_UPDATE_IN_PLACE) +                        area->start = (1 /* greedy */ ? min_start : max_start); + +                    else if (cflags & TNCF_CREATE_NEW) +                    { +                        new_area = g_umem_slice_alloc(params->allocator); + +                        *new_area = *area; + +                        new_area->start = (1 /* greedy */ ? min_start : max_start); + +                        add_tail_match_area(new_area, ¶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);      } diff --git a/src/analysis/scan/patterns/tokens/nodes/choice.c b/src/analysis/scan/patterns/tokens/nodes/choice.c index df6ae45..102c7de 100644 --- a/src/analysis/scan/patterns/tokens/nodes/choice.c +++ b/src/analysis/scan/patterns/tokens/nodes/choice.c @@ -24,6 +24,9 @@  #include "choice.h" +#include <assert.h> + +  #include "choice-int.h" @@ -48,6 +51,9 @@ static void g_scan_token_node_choice_finalize(GScanTokenNodeChoice *);  /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ +/* Communique l'intérêt d'un noeud au sein d'une analyse. */ +static float g_scan_token_node_choice_compute_weight_for_scan(const GScanTokenNodeChoice *); +  /* Prend acte d'une nouvelle propriété pour le noeud. */  static void g_scan_token_node_choice_apply_flags(GScanTokenNodeChoice *, ScanTokenNodeFlags); @@ -55,13 +61,16 @@ static void g_scan_token_node_choice_apply_flags(GScanTokenNodeChoice *, ScanTok  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 *); +static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *, GEngineBackend *, size_t, size_t *); + +/* Récupère un identifiant final pour un atome d'octets. */ +static bool g_scan_token_node_choice_build_id(GScanTokenNodeChoice *, GEngineBackend *);  /* 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 *); +static void g_scan_token_node_choice_check_forward(const GScanTokenNodeChoice *, scan_node_check_params_t *, TokenNodeCheckFlags, 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 *); +static void g_scan_token_node_choice_check_backward(const GScanTokenNodeChoice *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); @@ -98,9 +107,11 @@ static void g_scan_token_node_choice_class_init(GScanTokenNodeChoiceClass *klass      node = G_SCAN_TOKEN_NODE_CLASS(klass); +    node->compute_weight = (compute_scan_token_node_weight_fc)g_scan_token_node_choice_compute_weight_for_scan;      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->build_id = (build_scan_token_node_id_fc)g_scan_token_node_choice_build_id;      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; @@ -227,6 +238,51 @@ void g_scan_token_node_choice_add(GScanTokenNodeChoice *choice, GScanTokenNode *  /******************************************************************************  *                                                                             * +*  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_choice_compute_weight_for_scan(const GScanTokenNodeChoice *node) +{ +    float result;                           /* Valeur à retourner          */ +    size_t weight_count;                    /* Nombre de comptabilisations */ +    size_t i;                               /* Boucle de parcours          */ +    float weight;                           /* Nouveau poids à intégrer    */ + +    result = 0; + +    weight_count = 0; + +    for (i = 0; i < node->count; i++) +    { +        weight = g_scan_token_node_compute_weight_for_scan(node->children[i]); + +        if (weight > 0) +        { +            result += weight; +            weight_count++; +        } + +    } + +    if (weight_count != node->count) +        result = 0; +    else +        result /= weight_count; + +    return result; + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : node  = noeud de motif à mettre à jour.                      *  *                flags = propriétés particulières à associer au noeud.        *  *                                                                             * @@ -274,9 +330,6 @@ static void g_scan_token_node_choice_visit(GScanTokenNodeChoice *node, scan_tree      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; @@ -296,7 +349,6 @@ static void g_scan_token_node_choice_visit(GScanTokenNodeChoice *node, scan_tree  /******************************************************************************  *                                                                             *  *  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] * @@ -309,7 +361,7 @@ static void g_scan_token_node_choice_visit(GScanTokenNodeChoice *node, scan_tree  *                                                                             *  ******************************************************************************/ -static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow) +static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *node, GEngineBackend *backend, size_t maxsize, size_t *slow)  {      bool result;                            /* Statut à retourner          */      size_t i;                               /* Boucle de parcours          */ @@ -317,7 +369,7 @@ static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *node, GScanCon      result = true;      for (i = 0; i < node->count && result; i++) -        result = _g_scan_token_node_enroll(node->children[i], context, backend, maxsize, slow); +        result = _g_scan_token_node_enroll(node->children[i], backend, maxsize, slow);      return result; @@ -326,13 +378,38 @@ static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *node, GScanCon  /******************************************************************************  *                                                                             * -*  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 à 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_choice_build_id(GScanTokenNodeChoice *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 = g_scan_token_node_build_id(node->children[i], backend); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : node   = définition de la bribe à manipuler.                 * +*                params = accès direct aux éléments utiles aux validations.   * +*                cflags = altérations de traitement à respecter.              * +*                skip   = détermine si l'analyse est différée. [OUT]          *  *                                                                             *  *  Description : Transforme les correspondances locales en trouvailles.       *  *                                                                             * @@ -342,78 +419,117 @@ static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *node, GScanCon  *                                                                             *  ******************************************************************************/ -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) +static void g_scan_token_node_choice_check_forward(const GScanTokenNodeChoice *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, 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       */ +    bool initialized;                       /* Initialisation du suivi ?   */ +    match_area_t *collected_areas;          /* Zones mises en place ici    */ +    size_t collected_count;                 /* Quantité de ces zones       */ +    TokenNodeCheckFlags local_cflags;       /* Particularités nouvelles    */      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  */ +    scan_node_check_params_t local_params;  /* Rassemblement de paramètres */ + +    if (0x1) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);      if (*skip)          return; -    /* Copie des contextes de départ */ +    /* Lancement des sous-traitements */ -    copy_pending_matches(&init_matches, matches); +    initialized = false; -    exit_pending_matches(matches); -    init_pending_matches(matches, &init_matches.content_start, &init_matches.content_end); +    collected_areas = NULL; +    collected_count = 0; -    copy_node_search_offset(&init_offset, offset); +    local_cflags = (cflags & ~TNCF_UPDATE_IN_PLACE) | TNCF_CREATE_NEW; -    exit_node_search_offset(offset); -    init_node_search_offset(offset); +    for (i = 0; i < node->count; i++) +    { +        local_params = *params; -    /* Lancement des sous-traitements */ +        local_params.created_areas = NULL; +        local_params.created_count = 0; -    new_offset = 0; +        local_params.kept_areas = NULL; +        local_params.kept_count = 0; -    for (i = 0; i < node->count; i++) -    { -        copy_pending_matches(&tmp_matches, &init_matches); -        copy_node_search_offset(&tmp_offset, &init_offset); +        if ((cflags & TNCF_CREATE_NEW) == 0 && (i + 1) == node->count) +            local_cflags = cflags; + +        _g_scan_token_node_check_forward(node->children[i], &local_params, local_cflags, skip); -        _g_scan_token_node_check_forward(node->children[i], context, content, -                                         &tmp_matches, &tmp_offset, not, skip); +        initialized |= local_params.initialized; -        merge_pending_matches(matches, &tmp_matches); -        merge_node_search_offset(offset, &tmp_offset); +        if (local_cflags & TNCF_KEEP_DISCARDED) +        { +            merge_match_areas(&collected_areas, &local_params.kept_areas); +            collected_count += local_params.kept_count; +        } -        if (tmp_offset.used > 0) -            new_offset++; +        else if (local_cflags & TNCF_CREATE_NEW) +        { +            merge_match_areas(&collected_areas, &local_params.created_areas); +            collected_count += local_params.created_count; +        } -        exit_pending_matches(&tmp_matches); -        exit_node_search_offset(&tmp_offset); +        else +        { +            assert(local_cflags & TNCF_UPDATE_IN_PLACE); + +            merge_match_areas(&collected_areas, &local_params.main_areas); +            collected_count += local_params.main_count; + +        }      } -    /* Sortie propre */ +    /* Enregistrement des résultats finaux */ -    exit_pending_matches(&init_matches); -    exit_node_search_offset(&init_offset); +    if (collected_count > 1) +        sort_match_areas_no_dup(&collected_areas, &collected_count, compare_match_area_as_dl_item, NULL); -    /* "Alternative" directe en cas de motif(s) non terminé(s) par un intervale */ +    if (0x1) printf("[%s] collected: #%zu (bis)\n", __FUNCTION__, collected_count); -    if (new_offset != node->count) +    params->initialized = initialized; + +    if (cflags & TNCF_KEEP_DISCARDED)      { -        assert(node->count > 1); -        add_range_to_node_search_offset(offset, 0, 0, NULL); +        params->kept_areas = collected_areas; +        params->kept_count = collected_count;      } +    else if (cflags & TNCF_CREATE_NEW) +    { +        params->created_areas = collected_areas; +        params->created_count = collected_count; +    } + +    else +    { +        assert(cflags & TNCF_UPDATE_IN_PLACE); + +        params->main_areas = collected_areas; +        params->main_count = collected_count; + +    } + + + + + +    /// TODO : gestion des offets en sortie : ajout (+ ajout d'un test en Python) + + + +  }  /******************************************************************************  *                                                                             * -*  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]         * +*  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.       *  *                                                                             * @@ -423,64 +539,108 @@ static void g_scan_token_node_choice_check_forward(const GScanTokenNodeChoice *n  *                                                                             *  ******************************************************************************/ -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) +static void g_scan_token_node_choice_check_backward(const GScanTokenNodeChoice *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, 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       */ +    match_area_t *collected_areas;          /* Zones mises en place ici    */ +    size_t collected_count;                 /* Quantité de ces zones       */ +    TokenNodeCheckFlags local_cflags;       /* Particularités nouvelles    */      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  */ +    scan_node_check_params_t local_params;  /* Rassemblement de paramètres */ + +    if (0x1) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);      if (*skip)          return; -    /* Copie des contextes de départ */ +    /** +     * 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. +     */ -    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); +    assert(params->initialized);      /* Lancement des sous-traitements */ -    new_offset = 0; +    collected_areas = NULL; +    collected_count = 0; + +    local_cflags = (cflags & ~TNCF_UPDATE_IN_PLACE) | TNCF_CREATE_NEW;      for (i = 0; i < node->count; i++)      { -        copy_pending_matches(&tmp_matches, &init_matches); -        copy_node_search_offset(&tmp_offset, &init_offset); +        local_params = *params; + +        local_params.created_areas = NULL; +        local_params.created_count = 0; + +        local_params.kept_areas = NULL; +        local_params.kept_count = 0; + +        if ((cflags & TNCF_CREATE_NEW) == 0 && (i + 1) == node->count) +            local_cflags = cflags; -        _g_scan_token_node_check_backward(node->children[i], context, content, -                                          &tmp_matches, &tmp_offset, not, skip); +        _g_scan_token_node_check_backward(node->children[i], &local_params, local_cflags, skip); -        merge_pending_matches(matches, &tmp_matches); -        merge_node_search_offset(offset, &tmp_offset); +        if (local_cflags & TNCF_KEEP_DISCARDED) +        { +            merge_match_areas(&collected_areas, &local_params.kept_areas); +            collected_count += local_params.kept_count; +        } -        if (tmp_offset.used > 0) -            new_offset++; +        else if (local_cflags & TNCF_CREATE_NEW) +        { +            merge_match_areas(&collected_areas, &local_params.created_areas); +            collected_count += local_params.created_count; +        } -        exit_pending_matches(&tmp_matches); -        exit_node_search_offset(&tmp_offset); +        else +        { +            assert(local_cflags & TNCF_UPDATE_IN_PLACE); + +            merge_match_areas(&collected_areas, &local_params.main_areas); +            collected_count += local_params.main_count; + +        }      } -    /* Sortie propre */ +    /* Enregistrement des résultats finaux */ -    exit_pending_matches(&init_matches); -    exit_node_search_offset(&init_offset); +    if (collected_count > 1) +        sort_match_areas_no_dup(&collected_areas, &collected_count, compare_match_area_as_dl_item, NULL); -    /* "Alternative" directe en cas de motif(s) non terminé(s) par un intervale */ +    if (0x1) printf("[%s] collected: #%zu (bis)\n", __FUNCTION__, collected_count); -    if (new_offset != node->count) +    if (cflags & TNCF_KEEP_DISCARDED)      { -        assert(node->count > 1); -        add_range_to_node_search_offset(offset, 0, 0, NULL); +        params->kept_areas = collected_areas; +        params->kept_count = collected_count;      } +    else if (cflags & TNCF_CREATE_NEW) +    { +        params->created_areas = collected_areas; +        params->created_count = collected_count; +    } + +    else +    { +        assert(cflags & TNCF_UPDATE_IN_PLACE); + +        params->main_areas = collected_areas; +        params->main_count = collected_count; + +    } + + + + + +    /// TODO : gestion des offets en sortie : ajout (+ ajout d'un test en Python) + + + + + +  } diff --git a/src/analysis/scan/patterns/tokens/nodes/masked-int.h b/src/analysis/scan/patterns/tokens/nodes/masked-int.h index 9eb8712..5fcc330 100644 --- a/src/analysis/scan/patterns/tokens/nodes/masked-int.h +++ b/src/analysis/scan/patterns/tokens/nodes/masked-int.h @@ -41,8 +41,9 @@ struct _GScanTokenNodeMasked      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 raw_count;                       /* Taille de cette liste       */ + +    tracked_scan_atom_t *enrolled_atoms;    /* Atomes correspondants       */      size_t enrolled_count;                  /* Quantité avec identifiant   */  }; diff --git a/src/analysis/scan/patterns/tokens/nodes/masked.c b/src/analysis/scan/patterns/tokens/nodes/masked.c index 8765b1d..2dbdb08 100644 --- a/src/analysis/scan/patterns/tokens/nodes/masked.c +++ b/src/analysis/scan/patterns/tokens/nodes/masked.c @@ -56,16 +56,19 @@ static void g_scan_token_node_masked_finalize(GScanTokenNodeMasked *);  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 *); +static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *, GEngineBackend *, size_t, size_t *); + +/* Récupère un identifiant final pour un atome d'octets. */ +static bool g_scan_token_node_masked_build_id(GScanTokenNodeMasked *, GEngineBackend *);  /* 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 *); +static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *, scan_node_check_params_t *, TokenNodeCheckFlags, 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 *); +static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); @@ -102,8 +105,10 @@ static void g_scan_token_node_masked_class_init(GScanTokenNodeMaskedClass *klass      node = G_SCAN_TOKEN_NODE_CLASS(klass); +    node->apply = (apply_scan_token_node_flags_fc)NULL;      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->build_id = (build_scan_token_node_id_fc)g_scan_token_node_masked_build_id;      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; @@ -124,14 +129,14 @@ static void g_scan_token_node_masked_class_init(GScanTokenNodeMaskedClass *klass  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; +    masked->raw_count = 0; + +    masked->enrolled_atoms = NULL; +    masked->enrolled_count = 0;  } @@ -174,14 +179,14 @@ static void g_scan_token_node_masked_finalize(GScanTokenNodeMasked *masked)      if (masked->bytes != NULL)          free(masked->bytes); -    for (i = 0; i < masked->count; i++) +    for (i = 0; i < masked->raw_count; i++)          exit_szstr(&masked->raw[i]);      if (masked->raw != NULL)          free(masked->raw); -    if (masked->atoms != NULL) -        free(masked->atoms); +    if (masked->enrolled_atoms != NULL) +        free(masked->enrolled_atoms);      G_OBJECT_CLASS(g_scan_token_node_masked_parent_class)->finalize(G_OBJECT(masked)); @@ -305,7 +310,6 @@ static void g_scan_token_node_masked_visit(GScanTokenNodeMasked *node, scan_tree  /******************************************************************************  *                                                                             *  *  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] * @@ -318,7 +322,7 @@ static void g_scan_token_node_masked_visit(GScanTokenNodeMasked *node, scan_tree  *                                                                             *  ******************************************************************************/ -static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow) +static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *node, GEngineBackend *backend, size_t maxsize, size_t *slow)  {      bool result;                            /* Statut à retourner          */      bool forced;                            /* Inclusion dans un scan ?    */ @@ -333,6 +337,8 @@ static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *node, GScanCon      {          *slow += (maxsize * 2); +        node->raw = make_atoms_from_masked_bytes(node->bytes, node->len, &node->raw_count); +          /**           * 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 @@ -353,19 +359,23 @@ static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *node, GScanCon          else          { -            node->raw = make_atoms_from_masked_byte(node->bytes[0].value, node->bytes[0].mask, &node->count); +            node->enrolled_atoms = malloc(node->raw_count * sizeof(tracked_scan_atom_t)); +            node->enrolled_count = node->raw_count; -            node->atoms = malloc(node->count * sizeof(tracked_scan_atom_t)); - -            for (i = 0; i < node->count && result; i++) +            for (i = 0; i < node->enrolled_count && result; i++)              { -                find_best_atom(&node->raw[i], maxsize, &node->atoms[i], NULL); +                find_best_atom(&node->raw[i], maxsize, &node->enrolled_atoms[i], NULL); -                result = enroll_prepared_atom(&node->raw[i], context, backend, &node->atoms[i]); +                /** +                 * Correction : si l'atome ne représente qu'une vue partielle, +                 * la validation rapide ne peut s'appliquer. +                 */ +                if (node->enrolled_atoms[i].fast_check) +                    node->enrolled_atoms[i].fast_check = (node->enrolled_atoms[i].len == node->len); -            } +                result = enroll_prepared_atom(&node->raw[i], backend, &node->enrolled_atoms[i]); -            node->enrolled_count = node->count; +            }          } @@ -378,6 +388,34 @@ static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *node, GScanCon  /******************************************************************************  *                                                                             * +*  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_masked_build_id(GScanTokenNodeMasked *node, GEngineBackend *backend) +{ +    bool result;                            /* Statut à retourner          */ +    size_t i;                               /* Boucle de parcours #1       */ + +    result = true; + +    for (i = 0; i < node->enrolled_count && result; i++) +        result = build_atom_pattern_id(&node->enrolled_atoms[i], backend); + +    return result; + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : bytes   = octets partiels avec leur masque à interpréter.    *  *                len     = quantité d'octets à interpréter.                   *  *                start   = point d'analyse à respecter.                       * @@ -419,13 +457,10 @@ static bool check_scan_token_node_masked_content(const masked_byte_t *bytes, siz  /******************************************************************************  *                                                                             * -*  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.       *  *                                                                             * @@ -435,37 +470,36 @@ static bool check_scan_token_node_masked_content(const masked_byte_t *bytes, siz  *                                                                             *  ******************************************************************************/ -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) +static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, 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 */ +    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 #4       */ -    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;                             /* Borne minimale déterminée   */ -    phys_t max;                             /* Borne maximale déterminée   */ -    phys_t j;                               /* Boucle de parcours #5       */ +    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); -      /**       * 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 @@ -475,61 +509,103 @@ static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *n       */  #ifndef NDEBUG      forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN); -    assert((!initialized && forced) || (initialized && (!forced || not))); +    assert((!params->initialized && forced) || (params->initialized && (!forced || cflags & TNCF_KEEP_DISCARDED)));  #endif -    ranges_ptr = get_node_search_offset_ranges(offset, &ocount); - -    /* Si aucune correspondance n'a été établie */ -    if (!initialized) +    if (!params->initialized)      {          for (i = 0; i < node->enrolled_count; i++)          { -            atom = &node->atoms[i]; +            atom = &node->enrolled_atoms[i]; -            found = g_scan_context_get_atom_matches(context, atom->pid, &count); +            atoms = g_scan_context_get_atom_matches(params->context, atom->pid); -            for (k = 0; k < count; k++) +            if (atom->fast_check)              { -                assert(atom->pos == 0); +                for (aiter = g_umem_slice_get_iter(atoms); aiter != NULL; aiter = aiter->next) +                { +                    end = aiter->data_end; -                new_begin = found[k]; +                    for (pos = aiter->data; pos < end; pos++) +                    { +                        /** +                         * 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; -                /** -                 * 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; -                } +                        if (cflags & TNCF_KEEP_DISCARDED) +                        { +                            add_tail_match_area(pos, ¶ms->kept_areas); +                            params->kept_count++; +                        } -                /** -                 * Existe-t-il assez de place pour faire tenir le motif masqué ? -                 */ -                if ((new_begin + node->len) > matches->content_end) -                    continue; +                        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_masked_content(node->bytes, node->len, 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 (start, len) enregistré est -                     * unique. -                     */ -                    add_pending_match(matches, new_begin, node->len); +                    end = aiter->data_end; + +                    for (pos = aiter->data; pos < end; pos++) +                    { +                        status = check_scan_token_node_masked_content(node->bytes, node->len, +                                                                      pos->start, 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->end = pos->start + node->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++; + +                            } + +                        } + +                    }                  } @@ -539,69 +615,77 @@ static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *n      } -    /* Si les correspondances en place sont à confirmer et compléter */ +    /** +     * Poursuite des traitements sur des correspondances déjà amorcées, impliquant +     * des comparaisons entières de motifs. +     */      else      { -        reset_pending_matches_ttl(matches); +        if (0x1) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count); -        pending_ptr = get_all_pending_matches(matches, &pcount); - -        for (p = 0; p < pcount; p++) +        for_each_match_area_safe(area, ¶ms->main_areas, next)          { -            pending = (*pending_ptr) + p; +            assert(area->end <= params->content_end); + +            after = params->content_end - area->end; -            assert(pending->end <= matches->content_end); +            if (0x1) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end); + +            /** +             * S'il s'avère qu'il existe de multiples correspondances dans l'espace +             * analysé, c'est la prise en compte d'une éventuelle avarice quant aux +             * distances consommées qui va sélectionner la position d'une bribe de +             * correspondance retenue. +             * +             * Par exemple, deux correspondances '?1 ?1 [1-3] ?2 ?2' peuvent être +             * valides pour un même contenu : +             * +             *    aa.bbb -> correspondance 'aa.bb' +             *      ^ +             * +             *    aa.bbb -> correspondance 'aa..bb' +             *      ^ +             */ -            after = matches->content_end - pending->end; +            min_end = params->content_end; +            max_end = params->content_start; -            new_begin = pending->end; +            updated = false; -            if (ocount > 0) +            /* Souplesse dans les positions ? */ +            if (offsets_exist(¶ms->offset))              { -                for (o = 0; o < ocount; o++) +                ranges = get_node_search_offset_ranges_2(¶ms->offset, &rcount); + +                for (r = 0; r < rcount; r++)                  { -                    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++) +                    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 + node->len) > after) +                            break; +                          status = check_scan_token_node_masked_content(node->bytes, node->len, -                                                                      new_begin + j, content); +                                                                      area->end + p, params->content); -                        if ((status && !not) || (!status && not)) +                        if (status)                          { -                            /** -                             * 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); +                            updated_edge = area->end + p + 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; +                            if (updated_edge < min_end) +                                min_end = updated_edge; + +                            if (updated_edge > max_end) +                                max_end = updated_edge; + +                            updated = true;                          } @@ -611,55 +695,133 @@ static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *n              } +            /* 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. +                 * représenté, alors la corresponance est écartée sans appel.                   */ -                if (node->len > after) -                    continue; +                if (node->len <= after) +                { +                    status = check_scan_token_node_masked_content(node->bytes, node->len, +                                                                  area->end, params->content); + +                    if (status) +                    { +                        updated_edge = area->end + node->len; + +                        min_end = updated_edge; +                        max_end = updated_edge; + +                        updated = true; + +                    } + +                } -                new_begin = pending->end; +            } -                status = check_scan_token_node_masked_content(node->bytes, node->len, new_begin, content); +            if (updated) +            { +                /** +                 * Si seuls les rejets sont d'intérêt, les correspondances établies +                 * ne se voient pas mises à jours ni retirées. +                 */ -                if ((status && !not) || (!status && not)) +                if ((cflags & TNCF_KEEP_DISCARDED) == 0)                  { -                    extend_pending_match_ending(matches, p, new_begin + node->len); +                    if (cflags & TNCF_UPDATE_IN_PLACE) +                        area->end = (1 /* greedy */ ? min_end : max_end); -                    /** -                     * Comme il n'y a qu'une seule itération par correspondance, -                     * nul besoin de recharcher l'élément. -                     */ +                    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->created_areas); +                        params->created_count++; + +                    } + +#ifndef NDEBUG +                    else +                        assert(false); +#endif                  }              } -        } +            else +            { +                /** +                 * Si la liste principale doit être mise à jour... +                 */ -        purge_pending_matches(matches); +                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.            * -*                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]         * +*  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.       *  *                                                                             * @@ -669,26 +831,32 @@ static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *n  *                                                                             *  ******************************************************************************/ -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) +static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, 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  */ + +    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; @@ -696,7 +864,7 @@ static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *       * 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)); +    assert(params->initialized);      /**       * Si les recherches associées au noeud ont été forcées, alors les traitements @@ -707,65 +875,121 @@ static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *      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++) +    /** +     * ............. +     */ +    if (0)      { -        pending = (*pending_ptr) + p; -        assert(matches->content_start <= pending->start); -        before = pending->start - matches->content_start; +        ; + + -        new_begin = pending->start - node->len; +    } + +    /** +     * 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); -        if (ocount > 0) +        for_each_match_area_safe(area, ¶ms->main_areas, next)          { -            for (o = 0; o < ocount; o++) +            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; + +            /* Souplesse dans les positions ? */ +            if (offsets_exist(¶ms->offset))              { -                range = (*ranges_ptr) + o; +                ranges = get_node_search_offset_ranges_2(¶ms->offset, &rcount); -                /** -                 * 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)) +                for (r = 0; r < rcount; r++)                  { -                    if (not) -                        extend_pending_match_beginning(matches, p, pending->start - node->len); +                    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 + node->len) > before) +                            break; + +                        status = check_scan_token_node_masked_content(node->bytes, node->len, +                                                                      area->start - node->len - p, +                                                                      params->content); + +                        if (status) +                        { +                            updated_edge = area->start - node->len - p; + +                            if (updated_edge > min_start) +                                min_start = updated_edge; + +                            if (updated_edge < max_start) +                                max_start = updated_edge; + +                            updated = true; -                    continue; +                        } + +                    }                  } +            } + +            /* Position immédiatement attendue */ +            else +            {                  /** -                 * Une recherche des différentes correspondances amont est lancée. +                 * 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.                   */ -                for (j = min; j <= max; j++) +                if (node->len <= before)                  {                      status = check_scan_token_node_masked_content(node->bytes, node->len, -                                                                  new_begin - j, content); +                                                                  area->start - node->len, +                                                                  params->content); -                    if ((status && !not) || (!status && not)) +                    if (status)                      { -                        /** -                         * 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); +                        updated_edge = area->start - 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; +                        if (updated_edge > min_start) +                            min_start = updated_edge; + +                        if (updated_edge < max_start) +                            max_start = updated_edge; + +                        updated = true;                      } @@ -773,35 +997,92 @@ static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *              } -        } - -        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 (updated)              { -                if (not) -                    extend_pending_match_beginning(matches, p, new_begin); +                /** +                 * 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 -                continue; +                }              } -            status = check_scan_token_node_masked_content(node->bytes, node->len, new_begin, content); +            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 ((status && !not) || (!status && not)) -                extend_pending_match_beginning(matches, p, new_begin); +                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 + +                } + +            }          }      } -    purge_pending_matches(matches); - -    disable_all_ranges_in_node_search_offset(offset); +    disable_all_ranges_in_node_search_offset(¶ms->offset);  } diff --git a/src/analysis/scan/patterns/tokens/nodes/masked.h b/src/analysis/scan/patterns/tokens/nodes/masked.h index d1765fa..04a05bc 100644 --- a/src/analysis/scan/patterns/tokens/nodes/masked.h +++ b/src/analysis/scan/patterns/tokens/nodes/masked.h @@ -49,15 +49,6 @@ typedef struct _GScanTokenNodeMasked GScanTokenNodeMasked;  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); diff --git a/src/analysis/scan/patterns/tokens/nodes/not.c b/src/analysis/scan/patterns/tokens/nodes/not.c index 645a1c8..81fce28 100644 --- a/src/analysis/scan/patterns/tokens/nodes/not.c +++ b/src/analysis/scan/patterns/tokens/nodes/not.c @@ -24,6 +24,9 @@  #include "not.h" +#include <assert.h> + +  #include "not-int.h" @@ -48,17 +51,23 @@ static void g_scan_token_node_not_finalize(GScanTokenNodeNot *);  /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ +/* Prend acte d'une nouvelle propriété pour le noeud. */ +static void g_scan_token_node_not_apply_flags(GScanTokenNodeNot *, ScanTokenNodeFlags); +  /* 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 *); +static bool g_scan_token_node_not_enroll(GScanTokenNodeNot *, GEngineBackend *, size_t, size_t *); + +/* Récupère un identifiant final pour un atome d'octets. */ +static bool g_scan_token_node_not_build_id(GScanTokenNodeNot *, GEngineBackend *);  /* 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 *); +static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *, scan_node_check_params_t *, TokenNodeCheckFlags, 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 *); +static void g_scan_token_node_not_check_backward(const GScanTokenNodeNot *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); @@ -95,8 +104,10 @@ static void g_scan_token_node_not_class_init(GScanTokenNodeNotClass *klass)      node = G_SCAN_TOKEN_NODE_CLASS(klass); +    node->apply = (apply_scan_token_node_flags_fc)g_scan_token_node_not_apply_flags;      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->build_id = (build_scan_token_node_id_fc)g_scan_token_node_not_build_id;      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; @@ -223,6 +234,26 @@ bool g_scan_token_node_not_create(GScanTokenNodeNot *not, GScanTokenNode *child)  /******************************************************************************  *                                                                             * +*  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_not_apply_flags(GScanTokenNodeNot *node, ScanTokenNodeFlags flags) +{ +    g_scan_token_node_set_flags(node->child, flags); + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : node   = point de départ du parcours à effectuer.            *  *                points = points capitaux de l'arborescence. [OUT]            *  *                                                                             * @@ -244,7 +275,6 @@ static void g_scan_token_node_not_visit(GScanTokenNodeNot *node, scan_tree_point  /******************************************************************************  *                                                                             *  *  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] * @@ -257,11 +287,11 @@ static void g_scan_token_node_not_visit(GScanTokenNodeNot *node, scan_tree_point  *                                                                             *  ******************************************************************************/ -static bool g_scan_token_node_not_enroll(GScanTokenNodeNot *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow) +static bool g_scan_token_node_not_enroll(GScanTokenNodeNot *node, GEngineBackend *backend, size_t maxsize, size_t *slow)  {      bool result;                            /* Statut à retourner          */ -    result = _g_scan_token_node_enroll(node->child, context, backend, maxsize, slow); +    result = _g_scan_token_node_enroll(node->child, backend, maxsize, slow);      return result; @@ -270,13 +300,34 @@ static bool g_scan_token_node_not_enroll(GScanTokenNodeNot *node, GScanContext *  /******************************************************************************  *                                                                             * -*  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 à 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_not_build_id(GScanTokenNodeNot *node, GEngineBackend *backend) +{ +    bool result;                            /* Statut à retourner          */ + +    result = g_scan_token_node_build_id(node->child, backend); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : node   = définition de la bribe à manipuler.                 * +*                params = accès direct aux éléments utiles aux validations.   * +*                cflags = altérations de traitement à respecter.              * +*                skip   = détermine si l'analyse est différée. [OUT]          *  *                                                                             *  *  Description : Transforme les correspondances locales en trouvailles.       *  *                                                                             * @@ -286,8 +337,12 @@ static bool g_scan_token_node_not_enroll(GScanTokenNodeNot *node, GScanContext *  *                                                                             *  ******************************************************************************/ -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) +static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)  { + +#if 0 + +      bool initialized;                       /* Initialisation du suivi ?   */      phys_t i;                               /* Boucle de parcours          */ @@ -322,7 +377,7 @@ static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *node, G      _g_scan_token_node_check_forward(node->child, context, content, matches, offset, !not, skip); - +#endif  } @@ -330,13 +385,10 @@ static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *node, G  /******************************************************************************  *                                                                             * -*  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.       *  *                                                                             * @@ -346,7 +398,7 @@ static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *node, G  *                                                                             *  ******************************************************************************/ -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) +static void g_scan_token_node_not_check_backward(const GScanTokenNodeNot *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)  { 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);  } diff --git a/src/analysis/scan/patterns/tokens/nodes/sequence.c b/src/analysis/scan/patterns/tokens/nodes/sequence.c index 91307bf..394c877 100644 --- a/src/analysis/scan/patterns/tokens/nodes/sequence.c +++ b/src/analysis/scan/patterns/tokens/nodes/sequence.c @@ -24,6 +24,9 @@  #include "sequence.h" +#include <assert.h> + +  #include "any.h"  #include "sequence-int.h" @@ -49,17 +52,23 @@ static void g_scan_token_node_sequence_finalize(GScanTokenNodeSequence *);  /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ +/* Prend acte d'une nouvelle propriété pour le noeud. */ +static void g_scan_token_node_sequence_apply_flags(GScanTokenNodeSequence *, ScanTokenNodeFlags); +  /* 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 *); +static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *, GEngineBackend *, size_t, size_t *); + +/* Récupère un identifiant final pour un atome d'octets. */ +static bool g_scan_token_node_sequence_build_id(GScanTokenNodeSequence *, GEngineBackend *);  /* 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 *); +static void g_scan_token_node_sequence_check_forward(const GScanTokenNodeSequence *, scan_node_check_params_t *, TokenNodeCheckFlags, 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 *); +static void g_scan_token_node_sequence_check_backward(const GScanTokenNodeSequence *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *); @@ -76,7 +85,7 @@ G_DEFINE_TYPE(GScanTokenNodeSequence, g_scan_token_node_sequence, G_TYPE_SCAN_TO  *                                                                             *  *  Paramètres  : klass = classe à initialiser.                                *  *                                                                             * -*  Description : Initialise la classe des décompositions séquentielles.        * +*  Description : Initialise la classe des décompositions séquentielles.       *  *                                                                             *  *  Retour      : -                                                            *  *                                                                             * @@ -96,8 +105,10 @@ static void g_scan_token_node_sequence_class_init(GScanTokenNodeSequenceClass *k      node = G_SCAN_TOKEN_NODE_CLASS(klass); +    node->apply = (apply_scan_token_node_flags_fc)g_scan_token_node_sequence_apply_flags;      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->build_id = (build_scan_token_node_id_fc)g_scan_token_node_sequence_build_id;      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; @@ -330,6 +341,40 @@ GScanTokenNode *g_scan_token_node_sequence_get(const GScanTokenNodeSequence *seq  /******************************************************************************  *                                                                             * +*  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_sequence_apply_flags(GScanTokenNodeSequence *node, ScanTokenNodeFlags flags) +{ +    size_t i;                               /* Boucle de parcours          */ + +    if (node->count == 1) +        g_scan_token_node_set_flags(node->children[0], flags); + +    else if (node->count > 1) +    { +        g_scan_token_node_set_flags(node->children[0], flags & ~STNF_LAST); + +        for (i = 1; i < (node->count - 1); i++) +            g_scan_token_node_set_flags(node->children[i], flags & ~(STNF_FIRST | STNF_LAST)); + +        g_scan_token_node_set_flags(node->children[node->count - 1], flags & ~STNF_FIRST); + +    } + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : node   = point de départ du parcours à effectuer.            *  *                points = points capitaux de l'arborescence. [OUT]            *  *                                                                             * @@ -354,7 +399,6 @@ static void g_scan_token_node_sequence_visit(GScanTokenNodeSequence *node, scan_  /******************************************************************************  *                                                                             *  *  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] * @@ -367,7 +411,7 @@ static void g_scan_token_node_sequence_visit(GScanTokenNodeSequence *node, scan_  *                                                                             *  ******************************************************************************/ -static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow) +static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *node, GEngineBackend *backend, size_t maxsize, size_t *slow)  {      bool result;                            /* Statut à retourner          */      size_t i;                               /* Boucle de parcours          */ @@ -375,7 +419,35 @@ static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *node, GSca      result = true;      for (i = 0; i < node->count && result; i++) -        result = _g_scan_token_node_enroll(node->children[i], context, backend, maxsize, slow); +        result = _g_scan_token_node_enroll(node->children[i], backend, maxsize, slow); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  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_sequence_build_id(GScanTokenNodeSequence *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 = g_scan_token_node_build_id(node->children[i], backend);      return result; @@ -384,13 +456,10 @@ static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *node, GSca  /******************************************************************************  *                                                                             * -*  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.       *  *                                                                             * @@ -400,25 +469,22 @@ static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *node, GSca  *                                                                             *  ******************************************************************************/ -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) +static void g_scan_token_node_sequence_check_forward(const GScanTokenNodeSequence *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, 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); +        _g_scan_token_node_check_forward(node->children[i], params, cflags, 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]         * +*  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.       *  *                                                                             * @@ -428,11 +494,11 @@ static void g_scan_token_node_sequence_check_forward(const GScanTokenNodeSequenc  *                                                                             *  ******************************************************************************/ -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) +static void g_scan_token_node_sequence_check_backward(const GScanTokenNodeSequence *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, 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); +        _g_scan_token_node_check_backward(node->children[i - 1], params, cflags, skip);  } | 
