summaryrefslogtreecommitdiff
path: root/src/analysis/scan/rule.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/analysis/scan/rule.c')
-rw-r--r--src/analysis/scan/rule.c1084
1 files changed, 1084 insertions, 0 deletions
diff --git a/src/analysis/scan/rule.c b/src/analysis/scan/rule.c
new file mode 100644
index 0000000..d3acbc2
--- /dev/null
+++ b/src/analysis/scan/rule.c
@@ -0,0 +1,1084 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * rule.c - parcours de contenus à la recherche de motifs
+ *
+ * Copyright (C) 2022 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "rule.h"
+
+
+#include <assert.h>
+#include <regex.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+
+#include "rule-int.h"
+#include "matches/bytes.h"
+#include "patterns/token.h"
+#include "../../common/extstr.h"
+#include "../../core/logs.h"
+
+
+
+/* Initialise la classe des règles de détection statique. */
+static void g_scan_rule_class_init(GScanRuleClass *);
+
+/* Initialise une instance de règle de détection statique. */
+static void g_scan_rule_init(GScanRule *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_rule_dispose(GScanRule *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_rule_finalize(GScanRule *);
+
+
+
+/* Indique le type défini pour une règle de détection par motifs. */
+G_DEFINE_TYPE(GScanRule, g_scan_rule, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des règles de détection statique. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_rule_class_init(GScanRuleClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_rule_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_scan_rule_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = instance à initialiser. *
+* *
+* Description : Initialise une instance de règle de détection statique. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_rule_init(GScanRule *rule)
+{
+ rule->flags = SRF_NONE;
+
+ 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;
+
+ rule->condition = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_scan_rule_dispose(GScanRule *rule)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < rule->bytes_used; i++)
+ g_clear_object(&rule->bytes_locals[i]);
+
+ g_clear_object(&rule->condition);
+
+ G_OBJECT_CLASS(g_scan_rule_parent_class)->dispose(G_OBJECT(rule));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+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));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : flags = propriétés particulières à conférer à la règle. *
+* name = désignation à associer à la future règle. *
+* *
+* Description : Crée une règle de détection statique à l'aide de motifs. *
+* *
+* Retour : Règle de détection mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GScanRule *g_scan_rule_new(ScanRuleFlags flags, const char *name)
+{
+ GScanRule *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_RULE, NULL);
+
+ result->flags = flags;
+
+ result->name = strdup(name);
+ result->name_hash = fnv_64a_hash(name);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à initialiser pleinement. *
+* flags = propriétés particulières à conférer à la règle. *
+* name = désignation à associer à la future règle. *
+* *
+* Description : Met en place une règle de détection statique avec motifs. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_rule_create(GScanRule *rule, ScanRuleFlags flags, const char *name)
+{
+ GScanRule *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_SCAN_RULE, NULL);
+
+ result->flags = flags;
+
+ result->name = strdup(name);
+ result->name_hash = fnv_64a_hash(name);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à consulter. *
+* *
+* Description : Indique les particularités liées à une règle de détection. *
+* *
+* Retour : Propriétés particulières attachées à la règle. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+ScanRuleFlags g_scan_rule_get_flags(const GScanRule *rule)
+{
+ ScanRuleFlags result; /* Fanions à retourner */
+
+ result = rule->flags;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à consulter. *
+* hash = empreinte précalculée associée au nom. [OUT] *
+* *
+* Description : Indique le nom associé à une règle de détection. *
+* *
+* Retour : Désignation humaine associée à la règle. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_scan_rule_get_name(const GScanRule *rule, fnv64_t *hash)
+{
+ const char *result; /* Désignation à retourner */
+
+ result = rule->name;
+
+ if (hash != NULL)
+ *hash = rule->name_hash;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* 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. *
+* *
+* Description : Intègre une nouvelle variable locale à une règle. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_rule_add_local_variable(GScanRule *rule, GSearchPattern *pattern)
+{
+ if (G_IS_BYTES_TOKEN(pattern))
+ {
+ if (rule->bytes_used == rule->bytes_allocated)
+ {
+ rule->bytes_allocated += PATTERN_ALLOC_SIZE;
+ rule->bytes_locals = realloc(rule->bytes_locals, rule->bytes_allocated * sizeof(GSearchPattern *));
+ }
+
+ rule->bytes_locals[rule->bytes_used++] = pattern;
+ g_object_ref(G_OBJECT(pattern));
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à consulter. *
+* target = nom d'une variable locale à retrouver. *
+* *
+* Description : Fournit une variable locale à une règle selon un nom. *
+* *
+* Retour : Motif de détection retrouvé ou NULL en cas d'échec. *
+* *
+* Remarques : La propriétée de l'instance renvoyée est partagée ! *
+* *
+******************************************************************************/
+
+const GSearchPattern *g_scan_rule_get_local_variable(GScanRule *rule, const char *target)
+{
+ const GSearchPattern *result; /* Variable à retourner */
+ size_t i; /* Boucle de parcours */
+ const char *name; /* Désignation d'un motif */
+
+ result = NULL;
+
+ for (i = 0; i < rule->bytes_used; i++)
+ {
+ name = g_search_pattern_get_name(rule->bytes_locals[i]);
+
+ if (strcmp(name, target) == 0)
+ {
+ result = rule->bytes_locals[i];
+ break;
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à consulter. *
+* target = nom d'une variable locale à retrouver. *
+* count = quantité de motifs renvoyés. [OUT] *
+* *
+* Description : Fournit une liste de variables locales à partir d'un nom. *
+* *
+* Retour : Motifs de détection retrouvés ou NULL en cas d'échec. *
+* *
+* Remarques : La propriétée des instances renvoyées est partagée ! *
+* *
+******************************************************************************/
+
+const GSearchPattern **g_scan_rule_get_local_variables(GScanRule *rule, const char *target, size_t *count)
+{
+ 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 */
+ int ret; /* Bilan d'un appel */
+ const char *name; /* Désignation d'un motif */
+
+ result = NULL;
+
+ *count = 0;
+
+ /* Premier cas de figure : la liste complète est attendue */
+
+ 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++)
+ {
+ 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;
+ }
+
+ }
+
+ try_harder:
+
+ /* Dernier cas de figure : une expression régulière est vraisemblablement de mise */
+
+ if (need_regex)
+ {
+ regex = strdup(target);
+
+ regex = strrpl(regex, "*", ".*");
+ regex = strprep(regex, "^");
+ regex = stradd(regex, "$");
+
+ ret = regcomp(&preg, regex, REG_NOSUB);
+
+ if (ret != 0)
+ {
+ LOG_ERROR_REGCOMP(&preg, ret);
+ goto done;
+ }
+
+ result = malloc(rule->bytes_used * sizeof(GSearchPattern *));
+
+ for (i = 0; i < rule->bytes_used; i++)
+ {
+ name = g_search_pattern_get_name(rule->bytes_locals[i]);
+
+ ret = regexec(&preg, name, 0, NULL, 0);
+
+ if (ret != REG_NOMATCH)
+ {
+ result[*count] = rule->bytes_locals[i];
+ (*count)++;
+ }
+
+ }
+
+ if (*count == 0)
+ {
+ free(result);
+ result = NULL;
+ }
+
+ regfree(&preg);
+
+ done:
+
+ free(regex);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à compléter. *
+* expr = expression de condition à satisfaire. *
+* *
+* Description : Définit l'expression d'une correspondance recherchée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_rule_set_match_condition(GScanRule *rule, GScanExpression *expr)
+{
+ rule->condition = expr;
+
+ g_object_ref(G_OBJECT(expr));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à considérer. *
+* backend = moteur d'analyse pour données brutes. *
+* context = contexte de l'analyse à mener. *
+* *
+* Description : Prépare le suivi de recherche de motifs pour une règle. *
+* *
+* Retour : Bilan de l'opération à renvoyer. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_scan_rule_setup_backend(GScanRule *rule, GEngineBackend *backend, GScanContext *context)
+{
+ bool result; /* Statut à retourner */
+ size_t maxsize; /* Taille maximale des atomes */
+ GSearchPattern *pattern; /* Motif à intégrer */
+ size_t i; /* Boucle de parcours */
+
+ /* Suivi des conditions de correspondance */
+
+ result = g_scan_context_set_rule_condition(context, rule->name, rule->condition);
+ if (!result) goto exit;
+
+ /* Programmation des motifs recherchés */
+
+ maxsize = g_engine_backend_get_atom_max_size(backend);
+
+ for (i = 0; i < rule->bytes_used && result; i++)
+ {
+ pattern = rule->bytes_locals[i];
+ result = g_bytes_token_enroll(G_BYTES_TOKEN(pattern), backend, maxsize);
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* 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 : - *
+* *
+******************************************************************************/
+
+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 */
+
+ 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;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à considérer. *
+* backend = moteur d'analyse pour données brutes. *
+* context = contexte de l'analyse à mener. *
+* *
+* Description : Lance une analyse d'un contenu binaire selon une règle. *
+* *
+* Retour : Contexte de suivi pour l'analyse menée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_scan_rule_check(GScanRule *rule, GEngineBackend *backend, GScanContext *context)
+{
+ 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 */
+ size_t i; /* Boucle de parcours */
+ GSearchPattern *pattern; /* Motif à intégrer */
+ GScanMatches *matches; /* Correspondances établies */
+
+ /* 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);
+
+ params.content_start = start.physical;
+ params.content_end = end.physical;
+
+ /* Vérifications */
+
+ for (i = 0; i < rule->bytes_used; i++)
+ {
+ pattern = rule->bytes_locals[i];
+
+ matches = g_scan_bytes_matches_new();
+
+ g_bytes_token_check(G_BYTES_TOKEN(pattern), G_SCAN_BYTES_MATCHES(matches), &params);
+
+ g_scan_context_register_full_matches(context, pattern, matches);
+
+ g_object_unref(G_OBJECT(matches));
+
+ }
+
+ g_object_unref(G_OBJECT(params.content));
+ //g_object_unref(G_OBJECT(params.allocator));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à considérer. *
+* context = contexte de l'analyse à mener. *
+* full = force un affichage complet des résultats. *
+* fd = canal d'écriture. *
+* *
+* Description : Affiche une règle au format texte. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+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 */
+
+ /**
+ * 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;
+
+ 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->name, strlen(rule->name));
+
+ 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));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à considérer. *
+* context = contexte de l'analyse à mener. *
+* *
+* Description : Convertit une règle en texte. *
+* *
+* Retour : Données textuelles ou NULL en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_scan_rule_convert_as_text(const GScanRule *rule, GScanContext *context)
+{
+ char *result; /* Données à retourner */
+ char *name; /* Nom "unique" pour le canal */
+ int ret; /* Bilan de création de nom */
+ int fd; /* Canal d'écriture */
+ struct stat info; /* Infos. incluant une taille */
+ ssize_t got; /* Données effectivement relues*/
+
+ static unsigned long long counter = 0;
+
+ result = NULL;
+
+ ret = asprintf(&name, "rost-rule2text-%llu", counter++);
+ if (ret == -1) goto exit;
+
+ fd = memfd_create(name, MFD_CLOEXEC);
+ if (fd == -1)
+ {
+ LOG_ERROR_N("memfd_create");
+ goto exit_with_name;
+ }
+
+ g_scan_rule_output_to_text(rule, context, true, fd);
+
+ ret = fstat(fd, &info);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("fstat");
+ goto exit_with_name_and_fd;
+ }
+
+ result = malloc((info.st_size + 1) * sizeof(char));
+
+ lseek(fd, SEEK_SET, 0);
+
+ got = read(fd, result, info.st_size);
+ if (got != info.st_size)
+ {
+ LOG_ERROR_N("read");
+ free(result);
+ goto exit_with_name_and_fd;
+ }
+
+ result[info.st_size] = '\0';
+
+ exit_with_name_and_fd:
+
+ close(fd);
+
+ exit_with_name:
+
+ free(name);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à considérer. *
+* context = contexte de l'analyse à mener. *
+* padding = éventuel bourrage initial à placer ou NULL. *
+* level = profondeur actuelle. *
+* fd = canal d'écriture. *
+* tail = décline la pose d'une virgule finale ? *
+* *
+* Description : Affiche une règle au format JSON. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+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 #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 */
+
+ for (i = 0; i < level; i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "{\n", 2);
+
+ /* Désignation de la règle */
+
+ for (i = 0; i < (level + 1); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"name\": \"", 9);
+
+ write(fd, rule->name, strlen(rule->name));
+
+ 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++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"bytes_patterns\": [\n", 20);
+
+ for (i = 0; i < rule->bytes_used; i++)
+ {
+ sub_tail = ((i + 1) == rule->bytes_used);
+
+ g_search_pattern_output_to_json(rule->bytes_locals[i], context, padding, level + 2, fd, sub_tail);
+
+ }
+
+ for (i = 0; i < (level + 1); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "],\n", 3);
+
+ /* Bilan du filtrage */
+
+ for (i = 0; i < (level + 1); i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"matched\": ", 11);
+
+ if (g_scan_context_has_match_for_rule(context, rule->name))
+ write(fd, "true", 4);
+ else
+ write(fd, "false", 5);
+
+ write(fd, "\n", 1);
+
+ /* Conclusion */
+
+ for (i = 0; i < level; i++)
+ write(fd, padding->data, padding->len);
+
+ if (tail)
+ write(fd, "}\n", 2);
+ else
+ write(fd, "},\n", 3);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : rule = règle de détection à considérer. *
+* context = contexte de l'analyse à mener. *
+* *
+* Description : Convertit une règle en JSON. *
+* *
+* Retour : Données textuelles au format JSON ou NULL en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_scan_rule_convert_as_json(const GScanRule *rule, GScanContext *context)
+{
+ char *result; /* Données à retourner */
+ char *name; /* Nom "unique" pour le canal */
+ int ret; /* Bilan de création de nom */
+ int fd; /* Canal d'écriture */
+ sized_string_t padding; /* Bourrage pour le JSON */
+ struct stat info; /* Infos. incluant une taille */
+ ssize_t got; /* Données effectivement relues*/
+
+ static unsigned long long counter = 0;
+
+ result = NULL;
+
+ ret = asprintf(&name, "rost-rule2json-%llu", counter++);
+ if (ret == -1) goto exit;
+
+ fd = memfd_create(name, MFD_CLOEXEC);
+ if (fd == -1)
+ {
+ LOG_ERROR_N("memfd_create");
+ goto exit_with_name;
+ }
+
+ padding.data = " ";
+ padding.len = 3;
+
+ g_scan_rule_output_to_json(rule, context, &padding, 0, fd, false);
+
+ ret = fstat(fd, &info);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("fstat");
+ goto exit_with_name_and_fd;
+ }
+
+ result = malloc((info.st_size + 1) * sizeof(char));
+
+ lseek(fd, SEEK_SET, 0);
+
+ got = read(fd, result, info.st_size);
+ if (got != info.st_size)
+ {
+ LOG_ERROR_N("read");
+ free(result);
+ goto exit_with_name_and_fd;
+ }
+
+ result[info.st_size] = '\0';
+
+ exit_with_name_and_fd:
+
+ close(fd);
+
+ exit_with_name:
+
+ free(name);
+
+ exit:
+
+ return result;
+
+}