From 2f740fc8aa705df046a6d32fc98e2787df0e47e1 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Tue, 26 Sep 2023 01:50:02 +0200 Subject: Handle tags linked to ROST rules. --- src/analysis/scan/grammar.y | 23 ++++++++-- src/analysis/scan/options-int.h | 3 ++ src/analysis/scan/options.c | 76 +++++++++++++++++++++++++++++++++ src/analysis/scan/options.h | 6 +++ src/analysis/scan/rule-int.h | 3 ++ src/analysis/scan/rule.c | 95 ++++++++++++++++++++++++++++++++++++++--- src/analysis/scan/rule.h | 6 +++ src/analysis/scan/tokens.l | 6 ++- src/rost.c | 15 ++++--- 9 files changed, 215 insertions(+), 18 deletions(-) diff --git a/src/analysis/scan/grammar.y b/src/analysis/scan/grammar.y index e1f0e9e..741b394 100644 --- a/src/analysis/scan/grammar.y +++ b/src/analysis/scan/grammar.y @@ -116,7 +116,7 @@ YY_DECL; %token INCLUDE "include" %token RAW_RULE -%token RULE_NAME +%token RULE_IDENTIFIER %token META "meta" %token BYTES "bytes" @@ -216,7 +216,7 @@ YY_DECL; %token IN "in" -%type RULE_NAME +%type RULE_IDENTIFIER %type INFO_KEY @@ -346,12 +346,12 @@ YY_DECL; * Définition de règle. */ - rule : rule_flags RAW_RULE RULE_NAME + rule : rule_flags RAW_RULE RULE_IDENTIFIER { *built_rule = g_scan_rule_new($1, $3.data); $$ = *built_rule; } - BRACE_IN meta bytes condition BRACE_OUT + tags BRACE_IN meta bytes condition BRACE_OUT { $$ = $4; } @@ -379,6 +379,21 @@ YY_DECL; ; + tags : /* empty */ + | ":" tag_list + ; + + tag_list : RULE_IDENTIFIER + { + g_scan_rule_add_tag(*built_rule, $1.data); + } + | tag_list RULE_IDENTIFIER + { + g_scan_rule_add_tag(*built_rule, $2.data); + } + ; + + /** * Section "meta:" d'une définition de règle. */ diff --git a/src/analysis/scan/options-int.h b/src/analysis/scan/options-int.h index e8ae428..9e1c7d8 100644 --- a/src/analysis/scan/options-int.h +++ b/src/analysis/scan/options-int.h @@ -42,6 +42,9 @@ struct _GScanOptions bool print_strings; /* Affichage de correspondances*/ bool print_stats; /* Affichage de statistiques ? */ + char **selected_tags; /* Etiquettes sélectionnées */ + size_t selected_count; /* Nombre de ces étiquettes */ + }; /* Rassemblement d'options d'analyses (classe) */ diff --git a/src/analysis/scan/options.c b/src/analysis/scan/options.c index 637c821..0b50495 100644 --- a/src/analysis/scan/options.c +++ b/src/analysis/scan/options.c @@ -24,6 +24,10 @@ #include "options.h" +#include +#include + + #include "options-int.h" @@ -92,6 +96,9 @@ static void g_scan_options_init(GScanOptions *options) options->print_strings = false; options->print_stats = false; + options->selected_tags = NULL; + options->selected_count = 0; + } @@ -128,6 +135,14 @@ static void g_scan_options_dispose(GScanOptions *options) static void g_scan_options_finalize(GScanOptions *options) { + size_t i; /* Boucle de parcours */ + + for (i = 0; i < options->selected_count; i++) + free(options->selected_tags[i]); + + if (options->selected_tags != NULL) + free(options->selected_tags); + G_OBJECT_CLASS(g_scan_options_parent_class)->finalize(G_OBJECT(options)); } @@ -369,3 +384,64 @@ void g_scan_options_set_print_stats(GScanOptions *options, bool state) options->print_stats = state; } + + +/****************************************************************************** +* * +* Paramètres : options = ensemble d'options d'analyses à compléter. * +* tag = étiquette de règle à sélectionner. * +* * +* Description : Inscrit une étiquette comme sélection de règles à afficher. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_options_select_tag(GScanOptions *options, const char *tag) +{ + options->selected_tags = realloc(options->selected_tags, ++options->selected_count * sizeof(char *)); + + options->selected_tags[options->selected_count - 1] = strdup(tag); + +} + + +/****************************************************************************** +* * +* Paramètres : options = ensemble d'options d'analyses à compléter. * +* tag = étiquette de règle à auditionner. * +* * +* Description : Détermine si une étiquette donnée conduit à un affichage. * +* * +* Retour : true si une règle portant l'étiquette doit être affichée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_options_has_tag_as_selected(const GScanOptions *options, const char *tag) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + + if (tag == NULL) + result = (options->selected_count == 0); + + else + { + result = false; + + for (i = 0; i < options->selected_count; i++) + if (strcmp(options->selected_tags[i], tag) == 0) + { + result = true; + break; + } + + } + + return result; + +} diff --git a/src/analysis/scan/options.h b/src/analysis/scan/options.h index c6db838..fc1b7d3 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); +/* Inscrit une étiquette comme sélection de règles à afficher. */ +void g_scan_options_select_tag(GScanOptions *, const char *); + +/* Détermine si une étiquette donnée conduit à un affichage. */ +bool g_scan_options_has_tag_as_selected(const GScanOptions *, const char *); + #endif /* _ANALYSIS_SCAN_OPTIONS_H */ diff --git a/src/analysis/scan/rule-int.h b/src/analysis/scan/rule-int.h index 1ca2b7f..17d4dc2 100644 --- a/src/analysis/scan/rule-int.h +++ b/src/analysis/scan/rule-int.h @@ -42,6 +42,9 @@ struct _GScanRule char *name; /* Désignation de la règle */ fnv64_t name_hash; /* Empreinte de la désignation */ + char **tags; /* Etiquettes associées */ + char tags_count; /* Quantité de ces étiquettes */ + GSearchPattern **bytes_locals; /* Variables de données */ size_t bytes_allocated; /* Taille allouée du tableau */ size_t bytes_used; /* Nombre d'éléments présents */ diff --git a/src/analysis/scan/rule.c b/src/analysis/scan/rule.c index 68222dd..29ae826 100644 --- a/src/analysis/scan/rule.c +++ b/src/analysis/scan/rule.c @@ -102,6 +102,9 @@ static void g_scan_rule_init(GScanRule *rule) rule->name = NULL; rule->name_hash = 0; + rule->tags = NULL; + rule->tags_count = 0; + rule->bytes_locals = NULL; rule->bytes_allocated = 0; rule->bytes_used = 0; @@ -151,9 +154,17 @@ static void g_scan_rule_dispose(GScanRule *rule) static void g_scan_rule_finalize(GScanRule *rule) { + size_t i; /* Boucle de parcours */ + if (rule->name != NULL) free(rule->name); + for (i = 0; i < rule->tags_count; i++) + free(rule->tags[i]); + + if (rule->tags != NULL) + free(rule->tags); + G_OBJECT_CLASS(g_scan_rule_parent_class)->finalize(G_OBJECT(rule)); } @@ -270,6 +281,54 @@ const char *g_scan_rule_get_name(const GScanRule *rule, fnv64_t *hash) /****************************************************************************** * * +* Paramètres : rule = règle de détection à compléter. * +* tag = étiquette à associer à la règle. * +* * +* Description : Lie une règle à une nouvelle étiquette. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_rule_add_tag(GScanRule *rule, const char *tag) +{ + rule->tags = realloc(rule->tags, ++rule->tags_count * sizeof(char *)); + + rule->tags[rule->tags_count - 1] = strdup(tag); + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à consulter. * +* count = quantité d'éléments retournés. [OUT] * +* * +* Description : Indique les éventuelles étiquettes associées à une règle. * +* * +* Retour : Liste d'étiquettes associées à la règle consultée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char * const *g_scan_rule_list_tags(const GScanRule *rule, size_t *count) +{ + const char * const *result; /* Liste à retourner */ + + result = rule->tags; + + *count = rule->tags_count; + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : rule = règle de détection à compléter. * * pattern = nouveau motif de détection. * * * @@ -597,19 +656,41 @@ void g_scan_rule_check(GScanRule *rule, GEngineBackend *backend, GScanContext *c void g_scan_rule_output_to_text(const GScanRule *rule, GScanContext *context, bool full, int fd) { + GScanOptions *options; /* Options de l'utilisateur */ + bool selected; /* Affichage attendu ? */ size_t i; /* Boucle de parcours */ - if (full) - for (i = 0; i < rule->bytes_used; i++) - g_search_pattern_output_to_text(rule->bytes_locals[i], context, fd); + options = g_scan_context_get_options(context); - if (g_scan_context_has_match_for_rule(context, rule->name)) + if (rule->tags_count == 0) + selected = g_scan_options_has_tag_as_selected(options, NULL); + + else + { + 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) { - write(fd, "Rule '", 6); - write(fd, rule->name, strlen(rule->name)); - write(fd, "' has matched!\n", 15); + if (full) + for (i = 0; i < rule->bytes_used; i++) + g_search_pattern_output_to_text(rule->bytes_locals[i], context, fd); + + if (g_scan_context_has_match_for_rule(context, rule->name)) + { + write(fd, "Rule '", 6); + write(fd, rule->name, strlen(rule->name)); + write(fd, "' has matched!\n", 15); + } + } + g_object_unref(G_OBJECT(options)); + } diff --git a/src/analysis/scan/rule.h b/src/analysis/scan/rule.h index 3e6fe9d..b73ee1a 100644 --- a/src/analysis/scan/rule.h +++ b/src/analysis/scan/rule.h @@ -75,6 +75,12 @@ ScanRuleFlags g_scan_rule_get_flags(const GScanRule *); /* Indique le nom associé à une règle de détection. */ const char *g_scan_rule_get_name(const GScanRule *, fnv64_t *); +/* Lie une règle à une nouvelle étiquette. */ +void g_scan_rule_add_tag(GScanRule *, const char *); + +/* Indique les éventuelles étiquettes associées à une règle. */ +const char * const *g_scan_rule_list_tags(const GScanRule *, size_t *); + /* Intègre une nouvelle variable locale à une règle. */ void g_scan_rule_add_local_variable(GScanRule *, GSearchPattern *); diff --git a/src/analysis/scan/tokens.l b/src/analysis/scan/tokens.l index 1a17344..b284128 100644 --- a/src/analysis/scan/tokens.l +++ b/src/analysis/scan/tokens.l @@ -411,12 +411,14 @@ bytes_fuzzy_id [\*A-Za-z_][\*A-Za-z0-9_]* return RAW_RULE; } - [A-Za-z0-9_]+ { + {bytes_id} { yylval->sized_cstring.data = yytext; yylval->sized_cstring.len = yyleng; - return RULE_NAME; + return RULE_IDENTIFIER; } + ":" { return COLON; } + [ \t]* { } "{" { diff --git a/src/rost.c b/src/rost.c index efe18e5..8a7e806 100644 --- a/src/rost.c +++ b/src/rost.c @@ -91,11 +91,12 @@ static void show_rost_help(const char *name) printf("\n"); - printf("\t-A --algorithm=name\tSelect one of the available algorithms for data: bitmap, acism (default: acsim).\n"); + printf("\t-A --algorithm=NAME\tSelect one of the available algorithms for data: bitmap, acism (default: acsim).\n"); printf("\t-C --check-only\t\tValidate the rule syntax without performing a scan (discard the file/dir argument).\n"); - printf("\t-j --print-json\t\tPrint matching strings in JSON format.\n"); - printf("\t-s --print-strings\tPrint matching strings.\n"); + 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-V --verbosity=level\tSet the log level (0 for all messages, %u for none).\n", LMT_COUNT); printf("\n"); @@ -240,6 +241,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' }, + { "tag", required_argument, NULL, 't' }, { "verbosity", required_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; @@ -260,7 +262,7 @@ int main(int argc, char **argv) while (true) { - ret = getopt_long(argc, argv, "hvA:CjsSV:", long_options, &index); + ret = getopt_long(argc, argv, "hvA:CjsSt:V:", long_options, &index); if (ret == -1) break; switch (ret) @@ -299,6 +301,10 @@ int main(int argc, char **argv) g_scan_options_set_print_stats(options, true); break; + case 't': + g_scan_options_select_tag(options, optarg); + break; + case 'V': verbosity = strtoul(optarg, NULL, 10); break; @@ -310,7 +316,6 @@ int main(int argc, char **argv) if ((check_only && (optind + 0) != argc && (optind + 1) != argc) || (!check_only && (optind + 1) != argc && (optind + 2) != argc)) { - printf("failed: check=%d optind=%d argc=%d\n", check_only, optind, argc); show_rost_help(argv[0]); goto done; } -- cgit v0.11.2-87-g4458