diff options
Diffstat (limited to 'src/analysis/scan/rule.c')
| -rw-r--r-- | src/analysis/scan/rule.c | 352 |
1 files changed, 292 insertions, 60 deletions
diff --git a/src/analysis/scan/rule.c b/src/analysis/scan/rule.c index 68222dd..d3acbc2 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,20 @@ 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); + + if (rule->bytes_locals != NULL) + free(rule->bytes_locals); + G_OBJECT_CLASS(g_scan_rule_parent_class)->finalize(G_OBJECT(rule)); } @@ -270,6 +284,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. * * * @@ -283,7 +345,7 @@ const char *g_scan_rule_get_name(const GScanRule *rule, fnv64_t *hash) void g_scan_rule_add_local_variable(GScanRule *rule, GSearchPattern *pattern) { - if (G_IS_STRING_TOKEN(pattern)) + if (G_IS_BYTES_TOKEN(pattern)) { if (rule->bytes_used == rule->bytes_allocated) { @@ -308,13 +370,13 @@ void g_scan_rule_add_local_variable(GScanRule *rule, GSearchPattern *pattern) * * * Retour : Motif de détection retrouvé ou NULL en cas d'échec. * * * -* Remarques : - * +* Remarques : La propriétée de l'instance renvoyée est partagée ! * * * ******************************************************************************/ -GSearchPattern *g_scan_rule_get_local_variable(GScanRule *rule, const char *target) +const GSearchPattern *g_scan_rule_get_local_variable(GScanRule *rule, const char *target) { - GSearchPattern *result; /* Variable à retourner */ + const GSearchPattern *result; /* Variable à retourner */ size_t i; /* Boucle de parcours */ const char *name; /* Désignation d'un motif */ @@ -332,9 +394,6 @@ GSearchPattern *g_scan_rule_get_local_variable(GScanRule *rule, const char *targ } - if (result != NULL) - g_object_ref(G_OBJECT(result)); - return result; } @@ -350,13 +409,16 @@ GSearchPattern *g_scan_rule_get_local_variable(GScanRule *rule, const char *targ * * * Retour : Motifs de détection retrouvés ou NULL en cas d'échec. * * * -* Remarques : - * +* Remarques : La propriétée des instances renvoyées est partagée ! * * * ******************************************************************************/ -GSearchPattern **g_scan_rule_get_local_variables(GScanRule *rule, const char *target, size_t *count) +const GSearchPattern **g_scan_rule_get_local_variables(GScanRule *rule, const char *target, size_t *count) { - GSearchPattern **result; /* Variables à retourner */ + const GSearchPattern **result; /* Variables à retourner */ + size_t target_len; /* Nbre de caractères à évaluer*/ + size_t len_without_star; /* Taille sans masque */ + bool need_regex; /* Traitement complexe requis */ size_t i; /* Boucle de parcours */ char *regex; /* Définition complète */ regex_t preg; /* Expression compilée */ @@ -371,20 +433,68 @@ GSearchPattern **g_scan_rule_get_local_variables(GScanRule *rule, const char *ta if (target == NULL) { + need_all_of_them: + *count = rule->bytes_used; result = malloc(*count * sizeof(GSearchPattern *)); + memcpy(result, rule->bytes_locals, *count); + + } + + /* Second cas de figure : identification au cas par cas */ + + else + { + target_len = strlen(target); + + len_without_star = 0; + + need_regex = false; + + for (i = 0; i < target_len; i++) + if (target[i] == '*') + break; + else + len_without_star++; + + for (i++; i < target_len; i++) + if (target[i] != '*') + { + need_regex = true; + goto try_harder; + } + + if (len_without_star == 0) + goto need_all_of_them; + + result = malloc(rule->bytes_used * sizeof(GSearchPattern *)); + for (i = 0; i < rule->bytes_used; i++) { - result[i] = rule->bytes_locals[i]; - g_object_ref(G_OBJECT(result[i])); + name = g_search_pattern_get_name(rule->bytes_locals[i]); + + if (strncmp(name, target, len_without_star) == 0) + { + result[*count] = rule->bytes_locals[i]; + (*count)++; + } + + } + + if (*count == 0) + { + free(result); + result = NULL; } } - /* Second cas de figure : une expression régulière est vraisemblablement de mise */ + try_harder: - else + /* Dernier cas de figure : une expression régulière est vraisemblablement de mise */ + + if (need_regex) { regex = strdup(target); @@ -411,10 +521,7 @@ GSearchPattern **g_scan_rule_get_local_variables(GScanRule *rule, const char *ta if (ret != REG_NOMATCH) { result[*count] = rule->bytes_locals[i]; - g_object_ref(G_OBJECT(result[*count])); - (*count)++; - } } @@ -479,7 +586,6 @@ bool g_scan_rule_setup_backend(GScanRule *rule, GEngineBackend *backend, GScanCo bool result; /* Statut à retourner */ size_t maxsize; /* Taille maximale des atomes */ GSearchPattern *pattern; /* Motif à intégrer */ - GScanOptions *options; /* Options d'analyse */ size_t i; /* Boucle de parcours */ /* Suivi des conditions de correspondance */ @@ -494,22 +600,42 @@ bool g_scan_rule_setup_backend(GScanRule *rule, GEngineBackend *backend, GScanCo for (i = 0; i < rule->bytes_used && result; i++) { pattern = rule->bytes_locals[i]; - result = g_string_token_enroll(G_STRING_TOKEN(pattern), context, backend, maxsize); + result = g_bytes_token_enroll(G_BYTES_TOKEN(pattern), backend, maxsize); } - g_engine_backend_warm_up(backend); + exit: - /* Affichage éventuel de statistiques */ + return result; - options = g_scan_context_get_options(context); +} - if (g_scan_options_get_print_stats(options)) - g_engine_backend_output_stats(backend); +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à considérer. * +* backend = moteur d'analyse pour données brutes. * +* * +* Description : Récupère les identifiants finaux pour les motifs recherchés. * +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ - g_object_unref(G_OBJECT(options)); +bool g_scan_rule_define_pattern_ids(GScanRule *rule, GEngineBackend *backend) +{ + bool result; /* Statut à retourner */ + size_t i; /* Boucle de parcours */ + GSearchPattern *pattern; /* Motif à intégrer */ - exit: + result = true; + + for (i = 0; i < rule->bytes_used && result; i++) + { + pattern = rule->bytes_locals[i]; + result = g_bytes_token_build_id(G_BYTES_TOKEN(pattern), backend); + } return result; @@ -532,50 +658,43 @@ bool g_scan_rule_setup_backend(GScanRule *rule, GEngineBackend *backend, GScanCo void g_scan_rule_check(GScanRule *rule, GEngineBackend *backend, GScanContext *context) { - GBinContent *content; /* Contenu à manipuler */ + scan_node_check_params_t params; /* Rassemblement de paramètres */ vmpa2t start; /* Point de début du contenu */ vmpa2t end; /* Point de fin du contenu */ - pending_matches_t matches; /* Suivi de correspondances */ - size_t i; /* Boucle de parcours #1 */ + size_t i; /* Boucle de parcours */ GSearchPattern *pattern; /* Motif à intégrer */ - size_t k; /* Boucle de parcours #2 */ - match_area_t *area; /* Zone à initialiser */ - GScanMatch *match; /* Correspondance à mémoriser */ + GScanMatches *matches; /* Correspondances établies */ - content = g_scan_context_get_content(context); + /* Définition d'un contexte */ + + params.context = context; + params.content = g_scan_context_get_content(context); + params.allocator = g_umem_slice_new(sizeof(match_area_t)); + + g_binary_content_compute_start_pos(params.content, &start); + g_binary_content_compute_end_pos(params.content, &end); - g_binary_content_compute_start_pos(content, &start); - g_binary_content_compute_end_pos(content, &end); + params.content_start = start.physical; + params.content_end = end.physical; - /* Consolidation des résultats */ + /* Vérifications */ for (i = 0; i < rule->bytes_used; i++) { - init_pending_matches(&matches, &start.physical, &end.physical); - pattern = rule->bytes_locals[i]; - g_string_token_check(G_STRING_TOKEN(pattern), context, content, &matches); - - for (k = 0; k < matches.used; k++) - { - area = &matches.areas[k]; + matches = g_scan_bytes_matches_new(); - match = g_scan_bytes_match_new(G_SEARCH_PATTERN(pattern), content, - area->start, area->end - area->start); + g_bytes_token_check(G_BYTES_TOKEN(pattern), G_SCAN_BYTES_MATCHES(matches), ¶ms); - g_scan_context_register_full_match(context, match); - g_object_unref(G_OBJECT(match)); - - } + g_scan_context_register_full_matches(context, pattern, matches); - exit_pending_matches(&matches); + g_object_unref(G_OBJECT(matches)); } - /* Sortie propre */ - - g_object_unref(G_OBJECT(content)); + g_object_unref(G_OBJECT(params.content)); + //g_object_unref(G_OBJECT(params.allocator)); } @@ -597,19 +716,74 @@ 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 */ + GBinContent *content; /* Contenu binaire scanné */ + char *desc; /* Description de ce contenu */ - if (full) - for (i = 0; i < rule->bytes_used; i++) - g_search_pattern_output_to_text(rule->bytes_locals[i], context, fd); + /** + * Si la règle n'a pas fait mouche, rien n'est imprimé. + */ + if (!g_scan_context_has_match_for_rule(context, rule->name)) + return; - if (g_scan_context_has_match_for_rule(context, rule->name)) + options = g_scan_context_get_options(context); + + selected = g_scan_options_has_tag_as_selected(options, NULL); + + /** + * Si la règle comporte des étiquettes et que l'utilisateur en a spécifié + * également. + */ + if (rule->tags_count > 0 && !selected) + { + 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 (g_scan_options_get_print_tags(options)) + { + 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)); + } @@ -706,8 +880,11 @@ 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 */ + GBinContent *content; /* Contenu binaire scanné */ + char *desc; /* Description de ce contenu */ /* Introduction */ @@ -727,6 +904,61 @@ 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); + + /* Cible du scan */ + + for (i = 0; i < (level + 1); i++) + write(fd, padding->data, padding->len); + + write(fd, "\"target\": \"", 11); + + content = g_scan_context_get_content(context); + + desc = g_binary_content_describe(content, true); + + write(fd, desc, strlen(desc)); + + free(desc); + + g_object_unref(G_OBJECT(content)); + + write(fd, "\",\n", 3); + /* Affichage des correspondances d'octets */ for (i = 0; i < (level + 1); i++) |
