From a5cd93644fbb16dfc181f630b1c8d739fdc685fb Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Tue, 26 Sep 2023 21:59:37 +0200
Subject: Display tags on demand with ROST.

---
 src/analysis/scan/options-int.h |  1 +
 src/analysis/scan/options.c     | 43 +++++++++++++++++++
 src/analysis/scan/options.h     |  6 +++
 src/analysis/scan/rule.c        | 92 ++++++++++++++++++++++++++++++++++-------
 src/rost.c                      | 10 ++++-
 5 files changed, 136 insertions(+), 16 deletions(-)

diff --git a/src/analysis/scan/options-int.h b/src/analysis/scan/options-int.h
index 9e1c7d8..975fb6c 100644
--- a/src/analysis/scan/options-int.h
+++ b/src/analysis/scan/options-int.h
@@ -41,6 +41,7 @@ struct _GScanOptions
     bool print_json;                        /* Sortie au format json ?     */
     bool print_strings;                     /* Affichage de correspondances*/
     bool print_stats;                       /* Affichage de statistiques ? */
+    bool print_tags;                        /* Affichage des étiquttes ?   */
 
     char **selected_tags;                   /* Etiquettes sélectionnées    */
     size_t selected_count;                  /* Nombre de ces étiquettes    */
diff --git a/src/analysis/scan/options.c b/src/analysis/scan/options.c
index 0b50495..ecff9f1 100644
--- a/src/analysis/scan/options.c
+++ b/src/analysis/scan/options.c
@@ -388,6 +388,49 @@ void g_scan_options_set_print_stats(GScanOptions *options, bool state)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : options = ensemble d'options d'analyses à consulter.         *
+*                                                                             *
+*  Description : Indique un besoin d'affichage des étiquettes avec résultats. *
+*                                                                             *
+*  Retour      : Etat de l'option visée à conservé.                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_scan_options_get_print_tags(const GScanOptions *options)
+{
+    bool result;                            /* Statut à retourner          */
+
+    result = options->print_tags;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : options = ensemble d'options d'analyses à modifier.          *
+*                state   = état de l'option visée à conserver.                *
+*                                                                             *
+*  Description : Mémorise un besoin d'affichage des étiquettes avec résultats.*
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_scan_options_set_print_tags(GScanOptions *options, bool state)
+{
+    options->print_tags = state;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : options = ensemble d'options d'analyses à compléter.         *
 *                tag     = étiquette de règle à sélectionner.                 *
 *                                                                             *
diff --git a/src/analysis/scan/options.h b/src/analysis/scan/options.h
index fc1b7d3..059c57e 100644
--- a/src/analysis/scan/options.h
+++ b/src/analysis/scan/options.h
@@ -81,6 +81,12 @@ bool g_scan_options_get_print_stats(const GScanOptions *);
 /* Mémorise un besoin de statistiques en fin de compilation. */
 void g_scan_options_set_print_stats(GScanOptions *, bool);
 
+/* Indique un besoin d'affichage des étiquettes avec résultats. */
+bool g_scan_options_get_print_tags(const GScanOptions *);
+
+/* Mémorise un besoin d'affichage des étiquettes avec résultats. */
+void g_scan_options_set_print_tags(GScanOptions *, bool);
+
 /* Inscrit une étiquette comme sélection de règles à afficher. */
 void g_scan_options_select_tag(GScanOptions *, const char *);
 
diff --git a/src/analysis/scan/rule.c b/src/analysis/scan/rule.c
index 29ae826..650b824 100644
--- a/src/analysis/scan/rule.c
+++ b/src/analysis/scan/rule.c
@@ -659,34 +659,61 @@ void g_scan_rule_output_to_text(const GScanRule *rule, GScanContext *context, bo
     GScanOptions *options;                  /* Options de l'utilisateur    */
     bool selected;                          /* Affichage attendu ?         */
     size_t i;                               /* Boucle de parcours          */
+    GBinContent *content;                   /* Contenu binaire scanné      */
+    char *desc;                             /* Description de ce contenu   */
 
     options = g_scan_context_get_options(context);
 
-    if (rule->tags_count == 0)
-        selected = g_scan_options_has_tag_as_selected(options, NULL);
+    selected = g_scan_options_has_tag_as_selected(options, NULL);
 
-    else
+    /**
+     * Si la règle comporte des étiquettes et que l'utilisateur en a spécifié
+     * également.
+     */
+    if (rule->tags_count > 0 && !selected)
     {
-        selected = false;
-
         for (i = 0; i < rule->tags_count && !selected; i++)
             selected = g_scan_options_has_tag_as_selected(options, rule->tags[i]);
-
     }
 
     if (selected)
     {
-        if (full)
-            for (i = 0; i < rule->bytes_used; i++)
-                g_search_pattern_output_to_text(rule->bytes_locals[i], context, fd);
+        write(fd, rule->name, strlen(rule->name));
 
-        if (g_scan_context_has_match_for_rule(context, rule->name))
+        if (g_scan_options_get_print_tags(options))
         {
-            write(fd, "Rule '", 6);
-            write(fd, rule->name, strlen(rule->name));
-            write(fd, "' has matched!\n", 15);
+            write(fd, " [", 2);
+
+            for (i = 0; i < rule->tags_count; i++)
+            {
+                if (i > 0)
+                    write(fd, ",", 1);
+
+                write(fd, rule->tags[i], strlen(rule->tags[i]));
+
+            }
+
+            write(fd, "]", 1);
+
         }
 
+        write(fd, " ", 1);
+
+        content = g_scan_context_get_content(context);
+
+        desc = g_binary_content_describe(content, true);
+
+        write(fd, desc, strlen(desc));
+        write(fd, "\n", 1);
+
+        free(desc);
+
+        g_object_unref(G_OBJECT(content));
+
+        if (full)
+            for (i = 0; i < rule->bytes_used; i++)
+                g_search_pattern_output_to_text(rule->bytes_locals[i], context, fd);
+
     }
 
     g_object_unref(G_OBJECT(options));
@@ -787,8 +814,9 @@ char *g_scan_rule_convert_as_text(const GScanRule *rule, GScanContext *context)
 
 void g_scan_rule_output_to_json(const GScanRule *rule, GScanContext *context, const sized_string_t *padding, unsigned int level, int fd, bool tail)
 {
-    size_t i;                               /* Boucle de parcours          */
+    size_t i;                               /* Boucle de parcours #1       */
     bool sub_tail;                          /* Saut de la virgule finale ? */
+    size_t k;                               /* Boucle de parcours #2       */
 
     /* Introduction */
 
@@ -808,6 +836,42 @@ void g_scan_rule_output_to_json(const GScanRule *rule, GScanContext *context, co
 
     write(fd, "\",\n", 3);
 
+    /* Etiquettes ? */
+
+    for (i = 0; i < (level + 1); i++)
+        write(fd, padding->data, padding->len);
+
+    write(fd, "\"tags\": [", 9);
+
+    if (rule->tags_count > 0)
+    {
+        write(fd, "\n", 1);
+
+        for (k = 0; k < rule->tags_count; k++)
+        {
+            for (i = 0; i < (level + 2); i++)
+                write(fd, padding->data, padding->len);
+
+            write(fd, "\"", 1);
+
+            write(fd, rule->tags[k], strlen(rule->tags[k]));
+
+            write(fd, "\"", 1);
+
+            if ((k + 1) < rule->tags_count)
+                write(fd, ",", 1);
+
+            write(fd, "\n", 1);
+
+        }
+
+        for (i = 0; i < (level + 1); i++)
+            write(fd, padding->data, padding->len);
+
+    }
+
+    write(fd, "],\n", 3);
+
     /* Affichage des correspondances d'octets */
 
     for (i = 0; i < (level + 1); i++)
diff --git a/src/rost.c b/src/rost.c
index 8a7e806..1d4929f 100644
--- a/src/rost.c
+++ b/src/rost.c
@@ -96,7 +96,8 @@ static void show_rost_help(const char *name)
     printf("\t-j --print-json\t\tPrint matching strings in JSON format instead of simple text.\n");
     printf("\t-s --print-strings\tPrint matching strings (default text format only).\n");
     printf("\t-S --print-stats\tPrint rules' statistics.\n");
-    printf("\t-t --tag=TAG\t\tprint only matching rules tagged as TAG (default text format only).\n");
+    printf("\t-g --print-tags\t\tPrint tags linked to rules on match (default text format only).\n");
+    printf("\t-t --tag=TAG\t\tPrint only matching rules tagged as TAG (default text format only).\n");
     printf("\t-V --verbosity=level\tSet the log level (0 for all messages, %u for none).\n", LMT_COUNT);
 
     printf("\n");
@@ -241,6 +242,7 @@ int main(int argc, char **argv)
         { "print-json",     no_argument,        NULL,   'j' },
         { "print-strings",  no_argument,        NULL,   's' },
         { "print-stats",    no_argument,        NULL,   'S' },
+        { "print-tags",     no_argument,        NULL,   'g' },
         { "tag",            required_argument,  NULL,   't' },
         { "verbosity",      required_argument,  NULL,   'V' },
         { NULL,             0,                  NULL,   0 }
@@ -262,7 +264,7 @@ int main(int argc, char **argv)
 
     while (true)
     {
-        ret = getopt_long(argc, argv, "hvA:CjsSt:V:", long_options, &index);
+        ret = getopt_long(argc, argv, "hvA:CjsSgt:V:", long_options, &index);
         if (ret == -1) break;
 
         switch (ret)
@@ -301,6 +303,10 @@ int main(int argc, char **argv)
                 g_scan_options_set_print_stats(options, true);
                 break;
 
+            case 'g':
+                g_scan_options_set_print_tags(options, true);
+                break;
+
             case 't':
                 g_scan_options_select_tag(options, optarg);
                 break;
-- 
cgit v0.11.2-87-g4458