From 24945cea340b7b0ca0fe2ccad7b67519dda1c1bd Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 28 Jan 2024 22:27:09 +0100
Subject: Implement a basic support for Hyperscan.

---
 configure.ac                                       |  15 +
 src/Makefile.am                                    |   2 +-
 src/analysis/scan/patterns/backends/Makefile.am    |   6 +-
 .../scan/patterns/backends/hyperscan-int.h         |  67 +++
 src/analysis/scan/patterns/backends/hyperscan.c    | 648 +++++++++++++++++++++
 src/analysis/scan/patterns/backends/hyperscan.h    |  59 ++
 src/rost.c                                         |  13 +-
 7 files changed, 802 insertions(+), 8 deletions(-)
 create mode 100644 src/analysis/scan/patterns/backends/hyperscan-int.h
 create mode 100644 src/analysis/scan/patterns/backends/hyperscan.c
 create mode 100644 src/analysis/scan/patterns/backends/hyperscan.h

diff --git a/configure.ac b/configure.ac
index 55e8f65..cfb94bd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -541,6 +541,20 @@ if test "x$enable_magic_support" = "xyes"; then
 fi
 
 
+#--- Checks for Hyperscan
+
+PKG_CHECK_MODULES(LIBHS,libhs >= 5.4.9,[libhs_found=yes],[libhs_found=no])
+
+if test "$libhs_found" = "yes"; then
+   libhs_version=`pkg-config libhs --modversion`
+else
+   libhs_version='-'
+fi
+
+AC_SUBST(LIBHS_CFLAGS)
+AC_SUBST(LIBHS_LIBS)
+
+
 #--- Checks for Python
 
 if test "x$enable_debug" = "xyes"; then
@@ -822,6 +836,7 @@ echo The cryptography and SSL/TLS toolkit......... : $libssl_version
 echo The client URL library....................... : $libcurl_version
 echo The YAML support library..................... : $libyaml_version
 echo The magic number recognition library......... : $libmagic_version
+echo The high-performance matching library........ : $libhs_version
 
 echo
 echo Available Python programming language........ : $python3_version
diff --git a/src/Makefile.am b/src/Makefile.am
index e7aa395..9dc053e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -59,7 +59,7 @@ libchrysacore_la_LDFLAGS =					\
 	-avoid-version -ldl -lm					\
 	$(TOOLKIT_LIBS) $(LIBXML_LIBS)			\
 	$(LIBSQLITE_LIBS) $(LIBARCHIVE_LIBS)	\
-	$(LIBSSL_LIBS)
+	$(LIBSSL_LIBS)  $(LIBHS_LIBS)
 
 if BUILD_CURL_SUPPORT
 
diff --git a/src/analysis/scan/patterns/backends/Makefile.am b/src/analysis/scan/patterns/backends/Makefile.am
index 672b7ff..23b0163 100644
--- a/src/analysis/scan/patterns/backends/Makefile.am
+++ b/src/analysis/scan/patterns/backends/Makefile.am
@@ -6,11 +6,13 @@ libanalysisscanpatternsbackends_la_SOURCES =	\
 	acism-int.h								\
 	acism.h acism.c							\
 	bitap-int.h								\
-	bitap.h bitap.c
+	bitap.h bitap.c							\
+	hyperscan-int.h							\
+	hyperscan.h hyperscan.c
 
 # Cf. https://www.gnu.org/software/automake/manual/html_node/Per_002dObject-Flags.html
 
-AM_CFLAGS = $(LIBGOBJ_CFLAGS)
+AM_CFLAGS = $(LIBGOBJ_CFLAGS) $(LIBHS_CFLAGS)
 
 
 
diff --git a/src/analysis/scan/patterns/backends/hyperscan-int.h b/src/analysis/scan/patterns/backends/hyperscan-int.h
new file mode 100644
index 0000000..31d271b
--- /dev/null
+++ b/src/analysis/scan/patterns/backends/hyperscan-int.h
@@ -0,0 +1,67 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hyperscan-int.h - prototypes internes pour la méthode de recherche basée sur la bibliothèque Hyperscan d'Intel
+ *
+ * Copyright (C) 2024 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/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_BACKENDS_HYPERSCAN_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_BACKENDS_HYPERSCAN_INT_H
+
+
+#include "hyperscan.h"
+
+
+#include "../backend-int.h"
+
+
+
+#define EXPR_COVERAGE_START   0
+#define EXPR_COVERAGE_COUNT   1
+#define EXPR_COVERAGE_END     1
+
+
+/* Méthode de recherche basée sur une bibliothèque d'Intel : Hyperscan (instance) */
+struct _GHyperscanBackend
+{
+    GEngineBackend parent;                  /* A laisser en premier        */
+
+    const uint8_t **atoms;                  /* Motif remarquable           */
+    size_t *lengths;                        /* Nombre d'octets considérés  */
+    uint32_t *coverages;                    /* Départ et quantité de suivis*/
+    size_t allocated;                       /* Nombre d'éléments alloués   */
+    size_t used;                            /* Nombre d'éléments utiles    */
+
+    unsigned int *lit_ids;                  /* Identifiants internes       */
+
+    hs_database_t *database;                /* Compilation d'éléments      */
+    hs_scratch_t *scratch;                  /* Espace de travail           */
+
+};
+
+/* Méthode de recherche basée sur une bibliothèque d'Intel : Hyperscan (classe) */
+struct _GHyperscanBackendClass
+{
+    GEngineBackendClass parent;             /* A laisser en premier        */
+
+};
+
+
+
+#endif  /* _ANALYSIS_SCAN_PATTERNS_BACKENDS_HYPERSCAN_INT_H */
diff --git a/src/analysis/scan/patterns/backends/hyperscan.c b/src/analysis/scan/patterns/backends/hyperscan.c
new file mode 100644
index 0000000..5d535e3
--- /dev/null
+++ b/src/analysis/scan/patterns/backends/hyperscan.c
@@ -0,0 +1,648 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hyperscan.c - méthode de recherche basée sur la bibliothèque Hyperscan d'Intel
+ *
+ * Copyright (C) 2024 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 "hyperscan.h"
+
+
+#include <hs.h>
+#include <string.h>
+
+
+#include <i18n.h>
+
+
+#include "hyperscan-int.h"
+#include "../../../../core/logs.h"
+
+
+
+/* ---------------------- IMPLANTATION D'UNE NOUVELLE APPROCHE ---------------------- */
+
+
+/* Initialise la classe des méthodes basée sur Hyperscan. */
+static void g_hyperscan_backend_class_init(GHyperscanBackendClass *);
+
+/* Initialise une instance de méthodes basée sur Hyperscan. */
+static void g_hyperscan_backend_init(GHyperscanBackend *);
+
+/* Supprime toutes les références externes. */
+static void g_hyperscan_backend_dispose(GHyperscanBackend *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_hyperscan_backend_finalize(GHyperscanBackend *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique la taille maximale des suites d'octets recherchées. */
+size_t g_hyperscan_backend_get_atom_max_size(const GHyperscanBackend *);
+
+/* Inscrit dans le moteur une chaîne de caractères à rechercher. */
+static bool g_hyperscan_backend_enroll_plain_pattern(GHyperscanBackend *, const uint8_t *, size_t, uint32_t [2]);
+
+/* Met en ordre les derniers détails avant un premier scan. */
+static bool g_hyperscan_backend_warm_up(GHyperscanBackend *);
+
+/* Récupère les identifiants finaux pour un motif recherché. */
+static patid_t g_hyperscan_backend_build_plain_pattern_id(const GHyperscanBackend *, const uint32_t [2]);
+
+/* Détermine le nombre d'identifiants constitués. */
+static size_t g_hyperscan_backend_count_plain_pattern_ids(const GHyperscanBackend *);
+
+/* Informations utiles au traitement d'un événement */
+typedef struct _hyperscan_context_t
+{
+    const size_t *lengths;                  /* Nombre d'octets considérés  */
+    const uint32_t *coverages;              /* Départ et quantité de suivis*/
+
+#ifndef NDEBUG
+    size_t used;                            /* Nombre d'éléments utiles    */
+    const unsigned int *lit_ids;            /* Identifiants internes       */
+#endif
+
+    GUMemSlice **matches;                   /* Zones d'enregistrements     */
+
+} hyperscan_context_t;
+
+/* Prend note d'une correspondance trouvée par Hyperscan. */
+static int handle_hyperscan_match_event(unsigned int, unsigned long long, unsigned long long, unsigned int, const hyperscan_context_t *);
+
+/* Parcours un contenu binaire à la recherche de motifs. */
+static void g_hyperscan_backend_run_scan(const GHyperscanBackend *, GScanContext *);
+
+/* Imprime quelques faits quant aux éléments mis en place. */
+static void g_hyperscan_backend_output_stats(const GHyperscanBackend *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                        IMPLANTATION D'UNE NOUVELLE APPROCHE                        */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un moteur de recherche pour données. */
+G_DEFINE_TYPE(GHyperscanBackend, g_hyperscan_backend, G_TYPE_ENGINE_BACKEND);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des méthodes basée sur Hyperscan.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_hyperscan_backend_class_init(GHyperscanBackendClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GEngineBackendClass *backend;           /* Version de classe parente   */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_hyperscan_backend_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_hyperscan_backend_finalize;
+
+    backend = G_ENGINE_BACKEND_CLASS(klass);
+
+    backend->get_max_size = (get_backend_atom_max_size_fc)g_hyperscan_backend_get_atom_max_size;
+    backend->enroll_plain = (enroll_plain_into_backend_fc)g_hyperscan_backend_enroll_plain_pattern;
+    backend->warm_up = (warm_up_backend_fc)g_hyperscan_backend_warm_up;
+    backend->build_id = (build_backend_plain_pattern_id_fc)g_hyperscan_backend_build_plain_pattern_id;
+    backend->count_ids = (count_backend_plain_pattern_ids_fc)g_hyperscan_backend_count_plain_pattern_ids;
+    backend->run_scan = (run_backend_scan_fc)g_hyperscan_backend_run_scan;
+    backend->output = (output_backend_stats_fc)g_hyperscan_backend_output_stats;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : backend = instance à initialiser.                            *
+*                                                                             *
+*  Description : Initialise une instance de méthodes basée sur Hyperscan.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_hyperscan_backend_init(GHyperscanBackend *backend)
+{
+    backend->atoms = NULL;
+    backend->lengths = NULL;
+    backend->coverages = NULL;
+    backend->allocated = 0;
+    backend->used = 0;
+
+    backend->database = NULL;
+    backend->scratch = NULL;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : backend = instance d'objet GLib à traiter.                   *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_hyperscan_backend_dispose(GHyperscanBackend *backend)
+{
+    G_OBJECT_CLASS(g_hyperscan_backend_parent_class)->dispose(G_OBJECT(backend));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : backend = instance d'objet GLib à traiter.                   *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_hyperscan_backend_finalize(GHyperscanBackend *backend)
+{
+    if (backend->atoms != NULL)
+        free(backend->atoms);
+
+    if (backend->lengths != NULL)
+        free(backend->lengths);
+
+    if (backend->coverages != NULL)
+        free(backend->coverages);
+
+    if (backend->scratch != NULL)
+        hs_free_scratch(backend->scratch);
+
+    if (backend->database != NULL)
+        hs_free_database(backend->database);
+
+    G_OBJECT_CLASS(g_hyperscan_backend_parent_class)->finalize(G_OBJECT(backend));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Crée une méthode de recherche avec la bibliothèque Hyperscan.*
+*                                                                             *
+*  Retour      : Méthode mise en place.                                       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GEngineBackend *g_hyperscan_backend_new(void)
+{
+    GHyperscanBackend *result;                  /* Structure à retourner       */
+
+    result = g_object_new(G_TYPE_HYPERSCAN_BACKEND, NULL);
+
+    return G_ENGINE_BACKEND(result);
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : backend = moteur de recherche à consulter.                   *
+*                                                                             *
+*  Description : Indique la taille maximale des suites d'octets recherchées.  *
+*                                                                             *
+*  Retour      : Valeur strictement positive.                                 *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+size_t g_hyperscan_backend_get_atom_max_size(const GHyperscanBackend *backend)
+{
+    size_t result;                          /* Taille à faire connaître    */
+
+    result = ~0;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : backend = moteur de recherche à manipuler.                   *
+*                plain   = chaîne de caractères classique à intégrer.         *
+*                len     = taille de cette chaîne.                            *
+*                tmp_id  = identifiants temporaires vers le motif. [OUT]      *
+*                                                                             *
+*  Description : Inscrit dans le moteur une chaîne de caractères à rechercher.*
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_hyperscan_backend_enroll_plain_pattern(GHyperscanBackend *backend, const uint8_t *plain, size_t len, uint32_t tmp_id[2])
+{
+    bool result;                            /* Bilan à retourner           */
+    size_t i;                               /* Boucle de parcours          */
+    int ret;                                /* Bilan d'une comparaison     */
+
+    result = true;
+
+    /*Recherche d'un motif déjà sollicité */
+
+    for (i = 0; i < backend->used; i++)
+    {
+        if (backend->lengths[i] != len)
+            continue;
+
+        ret = memcmp(backend->atoms[i], plain, backend->lengths[i]);
+
+        if (ret == 0)
+        {
+            tmp_id[0] = i;
+            tmp_id[1] = backend->coverages[i * 2 + EXPR_COVERAGE_COUNT];
+
+            backend->coverages[i * 2 + EXPR_COVERAGE_COUNT]++;
+            break;
+
+        }
+
+    }
+
+    /* Introduction d'un nouveau motif au besoin */
+
+    if (i == backend->used)
+    {
+        if (backend->used == backend->allocated)
+        {
+            if (backend->allocated == 0)
+                backend->allocated = 64;
+            else
+                backend->allocated *= 2;
+
+            backend->atoms = realloc(backend->atoms, backend->allocated * sizeof(const uint8_t *));
+            backend->lengths = realloc(backend->lengths, backend->allocated * sizeof(size_t));
+            backend->coverages = realloc(backend->coverages, backend->allocated * 2 * sizeof(uint32_t));
+
+        }
+
+        backend->atoms[i] = plain;
+        backend->lengths[i] = len;
+        backend->coverages[i * 2 + EXPR_COVERAGE_COUNT] = 1;
+
+        backend->used++;
+
+        tmp_id[0] = i;
+        tmp_id[1] = 0;
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : backend = moteur de recherche à préparer.                    *
+*                                                                             *
+*  Description : Met en ordre les derniers détails avant un premier scan.     *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_hyperscan_backend_warm_up(GHyperscanBackend *backend)
+{
+    bool result;                            /* Bilan à retourner           */
+    uint32_t current_start;                 /* Indice de gestionnaire      */
+    size_t i;                               /* Boucle de parcours          */
+    hs_compile_error_t *error;              /* Compléments d'information   */
+    hs_error_t ret;                         /* Code de retour              */
+
+    hs_platform_info_t platform;
+
+    result = false;
+
+    /* Mise à jour de la couverture des gestionnaires de suivi */
+
+    current_start = 0;
+
+    for (i = 0; i < backend->used; i++)
+    {
+        backend->coverages[i * 2 + EXPR_COVERAGE_START] = current_start;
+        backend->coverages[i * 2 + EXPR_COVERAGE_END] += current_start;
+
+        current_start = backend->coverages[i * 2 + EXPR_COVERAGE_END];
+
+    }
+
+    /* Enregistrement des expressions à prendre en compte */
+
+    backend->lit_ids = malloc(backend->used * sizeof(unsigned));
+
+    for (i = 0; i < backend->used; i++)
+        backend->lit_ids[i] = i;
+
+    //hs_populate_platform(&platform);
+
+    //platform.tune = 1;
+
+    //platform.cpu_features = HS_CPU_FEATURES_AVX512;
+
+    ret = hs_compile_lit_multi((const char *const *)backend->atoms, NULL, backend->lit_ids, backend->lengths,
+                               backend->used, HS_MODE_BLOCK, NULL, &backend->database, &error);
+
+
+    //printf("ret: %d -vs- %d\n", ret, HS_SUCCESS);
+
+    if (ret != HS_SUCCESS)
+    {
+        log_variadic_message(LMT_EXT_ERROR, _("Unable to compile %zu patterns: \"%s\""),
+                             backend->used, error->message);
+        printf("FAILED: %s\n", error->message);
+        hs_free_compile_error(error);
+        goto exit;
+    }
+
+#if 0
+    do
+    {
+        //hs_platform_info_t platform;
+        char *__info;
+
+        //hs_populate_platform(&platform);
+
+        printf("TUNE: %u\n", platform.tune);
+
+        printf("CPU: %llx  -  AVX2? %d  -  AVX512? %d\n", platform.cpu_features,
+               platform.cpu_features & HS_CPU_FEATURES_AVX2,
+               platform.cpu_features & HS_CPU_FEATURES_AVX512);
+
+        hs_database_info(backend->database, &__info);
+
+        printf("INFO: %s\n", __info);
+
+    }
+    while (0);
+#endif
+
+    /* Création d'un espace de travail */
+
+    ret = hs_alloc_scratch(backend->database, &backend->scratch);
+
+    //printf("ret: %d -vs- %d\n", ret, HS_SUCCESS);
+
+    if (ret != HS_SUCCESS)
+    {
+        log_variadic_message(LMT_EXT_ERROR, _("Unable to allocate scratch space"));
+        goto exit;
+    }
+
+    result = true;
+
+ exit:
+
+    //printf("result: %d\n", result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : backend = moteur de recherche à manipuler.                   *
+*                tmp_id  = identifiants temporaires vers le motif. [OUT]      *
+*                                                                             *
+*  Description : Récupère les identifiants finaux pour un motif recherché.    *
+*                                                                             *
+*  Retour      : Identifiant constitué ou INVALID_PATTERN_ID en cas d'échec.  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static patid_t g_hyperscan_backend_build_plain_pattern_id(const GHyperscanBackend *backend, const uint32_t tmp_id[2])
+{
+    patid_t result;                         /* Identifiant à retourner     */
+    size_t index;                           /* Indice reconstitué          */
+
+    assert(tmp_id[0] < backend->used);
+
+    index = tmp_id[0] * 2;
+
+    result = backend->coverages[index + EXPR_COVERAGE_START] + tmp_id[1];
+
+    assert(result < backend->coverages[index + EXPR_COVERAGE_END]);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : backend = moteur de recherche à manipuler.                   *
+*                                                                             *
+*  Description : Détermine le nombre d'identifiants constitués.               *
+*                                                                             *
+*  Retour      : Quantité de gestionnaires de suivi à prévoir.                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static size_t g_hyperscan_backend_count_plain_pattern_ids(const GHyperscanBackend *backend)
+{
+    size_t result;                          /* Quantité à retourner        */
+
+    if (backend->used == 0)
+        result = 0;
+    else
+        result = backend->coverages[(backend->used - 1) * 2 + EXPR_COVERAGE_END];
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : backend = moteur de recherche à manipuler.                   *
+*                context = lieu d'enregistrement des résultats.               *
+*                                                                             *
+*  Description : Prend note d'une correspondance trouvée par Hyperscan.       *
+*                                                                             *
+*  Retour      : 0 afin de poursuivre les recherches.                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static int handle_hyperscan_match_event(unsigned int id, unsigned long long from, unsigned long long to, unsigned int flags, const hyperscan_context_t *context)
+{
+    phys_t offset;                          /* Point de départ établi      */
+    const uint32_t *coverage_base;          /* Base des suivis             */
+    uint32_t k;                             /* Boucle de parcours          */
+    uint32_t final_k;                       /* Dernier indice à traiter    */
+
+    //return 0;
+
+#ifndef NDEBUG
+    assert(id < context->used);
+    assert(id == context->lit_ids[id]);
+#endif
+
+    offset = to - context->lengths[id];
+
+    coverage_base = context->coverages + id * 2;
+
+    k = coverage_base[EXPR_COVERAGE_START];
+    final_k = coverage_base[EXPR_COVERAGE_END];
+
+    for (; k < final_k; k++)
+        g_umem_slice_put_uint64(context->matches[k], offset);
+
+    return 0;
+
+}
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : backend = moteur de recherche à manipuler.                   *
+*                context = lieu d'enregistrement des résultats.               *
+*                                                                             *
+*  Description : Parcours un contenu binaire à la recherche de motifs.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_hyperscan_backend_run_scan(const GHyperscanBackend *backend, GScanContext *context)
+{
+    GBinContent *content;                   /* Contenu binaire manipulé    */
+    phys_t dlen;                            /* Quantité de données         */
+    vmpa2t pos;                             /* Point de départ ciblé       */
+    const bin_t *data;                      /* Données à analyser          */
+#ifndef NDEBUG
+    siez_t count;                           /* Nombre de zones prévues     */
+#endif
+    hyperscan_context_t hcontext;           /* Rassemblement d'informations*/
+    GUMemSlice **matches;                   /* Zones d'enregistrements     */
+    hs_error_t ret;                         /* Code de retour              */
+
+    /* Récupération d'un accès aux données */
+
+    content = g_scan_context_get_content(context);
+
+    dlen = g_binary_content_compute_size(content);
+
+    g_binary_content_compute_start_pos(content, &pos);
+    data = g_binary_content_get_raw_access(content, &pos, dlen);
+
+    /* Préparation de l'accès aux éléments utiles */
+
+    hcontext.lengths = backend->lengths;
+    hcontext.coverages = backend->coverages;
+
+#ifndef NDEBUG
+    hcontext.used = backend->used;
+    hcontext.lit_ids = backend->lit_ids;
+#endif
+
+#ifndef NDEBUG
+    matches = g_scan_context_get_match_storages(context, &count);
+    assert(count == backend->used);
+#else
+    matches = g_scan_context_get_match_storages(context, (size_t []){ 0 });
+#endif
+
+    hcontext.matches = matches;
+
+    /* Lancement de l'analyse */
+
+    ret = hs_scan(backend->database, (const char *)data, dlen,
+                  0 /* Arg. inutilisé */, backend->scratch,
+                  (match_event_handler)handle_hyperscan_match_event, &hcontext);
+
+
+    //printf("ret ok? %d\n", ret == HS_SUCCESS);
+
+
+
+    g_object_unref(G_OBJECT(content));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : backend = moteur de recherche à consulter.                   *
+*                                                                             *
+*  Description : Imprime quelques faits quant aux éléments mis en place.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_hyperscan_backend_output_stats(const GHyperscanBackend *backend)
+{
+    printf("TODO: %s\n", __FUNCTION__);
+
+}
diff --git a/src/analysis/scan/patterns/backends/hyperscan.h b/src/analysis/scan/patterns/backends/hyperscan.h
new file mode 100644
index 0000000..d8c0f92
--- /dev/null
+++ b/src/analysis/scan/patterns/backends/hyperscan.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hyperscan.h - prototypes pour la méthode de recherche basée sur la bibliothèque Hyperscan d'Intel
+ *
+ * Copyright (C) 2024 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/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_BACKENDS_HYPERSCAN_H
+#define _ANALYSIS_SCAN_PATTERNS_BACKENDS_HYPERSCAN_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "../backend.h"
+
+
+
+#define G_TYPE_HYPERSCAN_BACKEND            g_hyperscan_backend_get_type()
+#define G_HYPERSCAN_BACKEND(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_HYPERSCAN_BACKEND, GHyperscanBackend))
+#define G_IS_HYPERSCAN_BACKEND(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_HYPERSCAN_BACKEND))
+#define G_HYPERSCAN_BACKEND_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_HYPERSCAN_BACKEND, GHyperscanBackendClass))
+#define G_IS_HYPERSCAN_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_HYPERSCAN_BACKEND))
+#define G_HYPERSCAN_BACKEND_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_HYPERSCAN_BACKEND, GHyperscanBackendClass))
+
+
+/* Méthode de recherche basée sur une bibliothèque d'Intel : Hyperscan (instance) */
+typedef struct _GHyperscanBackend GHyperscanBackend;
+
+/* Méthode de recherche basée sur une bibliothèque d'Intel : Hyperscan (classe) */
+typedef struct _GHyperscanBackendClass GHyperscanBackendClass;
+
+
+/* Indique le type défini pour un moteur de recherche pour données. */
+GType g_hyperscan_backend_get_type(void);
+
+/* Crée une méthode de recherche avec la bibliothèque Hyperscan. */
+GEngineBackend *g_hyperscan_backend_new(void);
+
+
+
+#endif  /* _ANALYSIS_SCAN_PATTERNS_BACKENDS_HYPERSCAN_H */
diff --git a/src/rost.c b/src/rost.c
index d397a2c..4a052c3 100644
--- a/src/rost.c
+++ b/src/rost.c
@@ -39,8 +39,9 @@
 #include "analysis/scan/core.h"
 #include "analysis/scan/options.h"
 #include "analysis/scan/scanner.h"
-#include "analysis/scan/patterns/backends/bitap.h"
 #include "analysis/scan/patterns/backends/acism.h"
+#include "analysis/scan/patterns/backends/bitap.h"
+#include "analysis/scan/patterns/backends/hyperscan.h"
 #include "core/core.h"
 #include "core/global.h"
 #include "core/logs.h"
@@ -92,7 +93,7 @@ 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: acism, bitmap, hyperscan (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 instead of simple text.\n");
     printf("\t-s --print-strings\tPrint matching strings (default text format only).\n");
@@ -298,10 +299,12 @@ int main(int argc, char **argv)
                 break;
 
             case 'A':
-                if (strcmp(optarg, "bitmap") == 0)
-                    g_scan_options_set_backend_for_data(options, G_TYPE_BITAP_BACKEND);
-                else if (strcmp(optarg, "acism") == 0)
+                if (strcmp(optarg, "acism") == 0)
                     g_scan_options_set_backend_for_data(options, G_TYPE_ACISM_BACKEND);
+                else if (strcmp(optarg, "bitmap") == 0)
+                    g_scan_options_set_backend_for_data(options, G_TYPE_BITAP_BACKEND);
+                else if (strcmp(optarg, "hyperscan") == 0)
+                    g_scan_options_set_backend_for_data(options, G_TYPE_HYPERSCAN_BACKEND);
                 else
                     g_scan_options_set_backend_for_data(options, G_TYPE_INVALID);
                 break;
-- 
cgit v0.11.2-87-g4458