From 3ab6c0c0072ae0e2abde48d60d7eac18f084a764 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 1 Oct 2023 20:08:26 +0200
Subject: Introduce parameters for scan pattern modifiers.

---
 plugins/pychrysalide/analysis/scan/Makefile.am     |   2 +-
 plugins/pychrysalide/analysis/scan/core.c          |   9 +-
 .../pychrysalide/analysis/scan/patterns/modifier.c | 114 +++++-
 .../analysis/scan/patterns/modifiers/Makefile.am   |   3 +-
 .../analysis/scan/patterns/modifiers/hex.c         |   4 +-
 .../analysis/scan/patterns/modifiers/module.c      |   2 +
 .../analysis/scan/patterns/modifiers/rev.c         |   2 +-
 .../analysis/scan/patterns/modifiers/xor.c         | 210 +++++++++++
 .../analysis/scan/patterns/modifiers/xor.h         |  45 +++
 src/analysis/scan/core.c                           |  23 +-
 src/analysis/scan/core.h                           |   2 +-
 src/analysis/scan/grammar.y                        |  76 +++-
 src/analysis/scan/patterns/Makefile.am             |   3 +
 src/analysis/scan/patterns/customizer-int.h        |  58 +++
 src/analysis/scan/patterns/customizer.c            | 374 +++++++++++++++++++
 src/analysis/scan/patterns/customizer.h            |  65 ++++
 src/analysis/scan/patterns/modarg.h                |  91 +++++
 src/analysis/scan/patterns/modifier-int.h          |  10 +-
 src/analysis/scan/patterns/modifier.c              |  76 +++-
 src/analysis/scan/patterns/modifier.h              |  10 +-
 src/analysis/scan/patterns/modifiers/Makefile.am   |   3 +-
 src/analysis/scan/patterns/modifiers/hex.c         |  33 +-
 src/analysis/scan/patterns/modifiers/list.c        |  21 +-
 src/analysis/scan/patterns/modifiers/plain.c       |  25 +-
 src/analysis/scan/patterns/modifiers/rev.c         |  29 +-
 src/analysis/scan/patterns/modifiers/xor.c         | 395 +++++++++++++++++++++
 src/analysis/scan/patterns/modifiers/xor.h         |  58 +++
 src/analysis/scan/patterns/tokens/nodes/plain.c    |   2 +-
 src/analysis/scan/tokens.l                         |  34 +-
 tests/analysis/scan/pyapi.py                       |  25 +-
 30 files changed, 1720 insertions(+), 84 deletions(-)
 create mode 100644 plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.c
 create mode 100644 plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.h
 create mode 100644 src/analysis/scan/patterns/customizer-int.h
 create mode 100644 src/analysis/scan/patterns/customizer.c
 create mode 100644 src/analysis/scan/patterns/customizer.h
 create mode 100644 src/analysis/scan/patterns/modarg.h
 create mode 100644 src/analysis/scan/patterns/modifiers/xor.c
 create mode 100644 src/analysis/scan/patterns/modifiers/xor.h

diff --git a/plugins/pychrysalide/analysis/scan/Makefile.am b/plugins/pychrysalide/analysis/scan/Makefile.am
index 32bf1e3..0b20ca5 100644
--- a/plugins/pychrysalide/analysis/scan/Makefile.am
+++ b/plugins/pychrysalide/analysis/scan/Makefile.am
@@ -15,7 +15,7 @@ libpychrysaanalysisscan_la_SOURCES =		\
 libpychrysaanalysisscan_la_LIBADD =			\
 	patterns/libpychrysaanalysisscanpatterns.la
 
-libpychrysaanalysisscan_la_CFLAGS = $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) \
+libpychrysaanalysisscan_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) \
 	-I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
 
 
diff --git a/plugins/pychrysalide/analysis/scan/core.c b/plugins/pychrysalide/analysis/scan/core.c
index f609f7d..dcf5bf8 100644
--- a/plugins/pychrysalide/analysis/scan/core.c
+++ b/plugins/pychrysalide/analysis/scan/core.c
@@ -119,7 +119,8 @@ static PyObject *py_scan_register_token_modifier(PyObject *self, PyObject *args)
 static PyObject *py_scan_find_token_modifiers_for_name(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Bilan à retourner           */
-    const char *name;                       /* Nom d'appel à rechercher    */
+    sized_string_t name;                    /* Nom d'appel à rechercher    */
+    Py_ssize_t len;                         /* Taille de ce nom            */
     int ret;                                /* Bilan de lecture des args.  */
     GScanTokenModifier *modifier;           /* Instance mise en place      */
 
@@ -135,10 +136,12 @@ static PyObject *py_scan_find_token_modifiers_for_name(PyObject *self, PyObject
     " if no instance was found for the provided name."              \
 )
 
-    ret = PyArg_ParseTuple(args, "s", &name);
+    ret = PyArg_ParseTuple(args, "s#", &name.static_data, &len);
     if (!ret) return NULL;
 
-    modifier = find_scan_token_modifiers_for_name(name);
+    name.len = len;
+
+    modifier = find_scan_token_modifiers_for_name(&name);
 
     if (modifier != NULL)
     {
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifier.c b/plugins/pychrysalide/analysis/scan/patterns/modifier.c
index 4cae011..0fec60c 100644
--- a/plugins/pychrysalide/analysis/scan/patterns/modifier.c
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifier.c
@@ -91,19 +91,27 @@ static int py_scan_token_modifier_init(PyObject *self, PyObject *args, PyObject
 static PyObject *py_scan_token_modifier_transform(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Bilan à faire remonter      */
-    const char *data;                       /* Séquence d'octets à traiter */
+    PyObject *py_src;                       /* Motifs Python en entrée     */
+    PyObject *py_arg;                       /* Eventuel paramètre de config*/
+    sized_binary_t src;                     /* Entrée au format adapté     */
     Py_ssize_t len;                         /* Quantité de ces données     */
     int ret;                                /* Bilan de lecture des args.  */
-    sized_binary_t src;                     /* Entrée au format adapté     */
+    sized_binary_t *src_list;               /* Entrées au format adapté    */
+    size_t scount;                          /* Taille de cette liste       */
+    bool dyn_src;                           /* Allocation dynamique ?      */
+    Py_ssize_t size;                        /* Taille d'une séquence       */
+    Py_ssize_t k;                           /* Boucle de parcours #1       */
+    PyObject *item;                         /* Elément de liste de motifs  */
+    modifier_arg_t arg;                     /* Eventuelle précision        */
     GScanTokenModifier *modifier;           /* Version native de l'instance*/
     sized_binary_t *dest;                   /* Liste des nouvelles chaînes */
-    size_t count;                           /* Taille de cette liste       */
+    size_t dcount;                          /* Taille de cette liste       */
     bool status;                            /* Bilan de l'opération        */
-    size_t i;                               /* Boucle de parcours          */
+    size_t i;                               /* Boucle de parcours #2       */
 
 #define SCAN_TOKEN_MODIFIER_TRANSFORM_METHOD PYTHON_METHOD_DEF      \
 (                                                                   \
-    transform, "$self, data",                                       \
+    transform, "$self, data, /, arg",                               \
     METH_VARARGS, py_scan_token_modifier,                           \
     "Transform data from a byte pattern for an incoming scan.\n"    \
     "\n"                                                            \
@@ -113,21 +121,105 @@ static PyObject *py_scan_token_modifier_transform(PyObject *self, PyObject *args
     " *None* in case of error."                                     \
 )
 
-    ret = PyArg_ParseTuple(args, "s#", &data, &len);
+    py_arg = NULL;
+
+    ret = PyArg_ParseTuple(args, "O|O", &py_src, &py_arg);
     if (!ret) return NULL;
 
-    src.data = (char *)data;
-    src.len = len;
+    /* Constitution des motifs d'entrée */
+
+    if (PyBytes_Check(py_src))
+    {
+        ret = PyBytes_AsStringAndSize(py_src, &src.data, &len);
+        if (ret == -1) return NULL;
+
+        src.len = len;
+
+        src_list = &src;
+        scount = 1;
+
+        dyn_src = false;
+
+    }
+
+    else if (PySequence_Check(py_src))
+    {
+        size = PySequence_Size(py_src);
+
+        src_list = malloc(size * sizeof(sized_binary_t));
+        scount = size;
+
+        dyn_src = true;
+
+        for (k = 0; k < size; k++)
+        {
+            item = PySequence_ITEM(py_src, k);
+
+            if (PyBytes_Check(item))
+            {
+                ret = PyBytes_AsStringAndSize(item, &src_list[k].data, &len);
+                if (ret == -1) return NULL;
+
+                src_list[k].len = len;
+
+            }
+            else
+            {
+                free(src_list);
+
+                PyErr_SetString(PyExc_TypeError, "lists of items other than bytes are not supported");
+                return NULL;
+            }
+
+        }
+
+    }
+
+    else
+    {
+        PyErr_SetString(PyExc_TypeError, "only bytes and lists of bytes are expected as input for modifiers");
+        return NULL;
+    }
+
+    /* Récupération d'une éventuelle précision opérationnelle */
+
+    if (py_arg != NULL)
+    {
+        if (PyLong_Check(py_arg))
+        {
+            arg.type = MAT_UNSIGNED_INTEGER;
+            arg.value.u_integer = PyLong_AsUnsignedLongLong(py_arg);
+        }
+
+        else
+        {
+            if (dyn_src)
+                free(src_list);
+
+            PyErr_SetString(PyExc_TypeError, "unable to handle the argument type for calling a modifier");
+            return NULL;
+
+        }
+
+    }
+
+    /* Création des nouveaux motifs */
 
     modifier = G_SCAN_TOKEN_MODIFIER(pygobject_get(self));
 
-    status = g_scan_token_modifier_transform(modifier, &src, &dest, &count);
+    if (py_arg == NULL)
+        status = g_scan_token_modifier_transform(modifier, src_list, scount, &dest, &dcount);
+    else
+        status = g_scan_token_modifier_transform_with_arg(modifier, src_list, scount, &arg, &dest, &dcount);
+
+    if (dyn_src)
+        free(src_list);
 
     if (status)
     {
-        result = PyTuple_New(count);
+        result = PyTuple_New(dcount);
 
-        for (i = 0; i < count; i++)
+        for (i = 0; i < dcount; i++)
         {
             PyTuple_SetItem(result, i, PyBytes_FromStringAndSize(dest[i].data, dest[i].len));
             exit_szstr(&dest[i]);
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am b/plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am
index baf7ed5..ae53e45 100644
--- a/plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am
@@ -6,7 +6,8 @@ libpychrysaanalysisscanpatternsmodifiers_la_SOURCES = \
 	list.h list.c							\
 	module.h module.c						\
 	plain.h plain.c							\
-	rev.h rev.c
+	rev.h rev.c								\
+	xor.h xor.c
 
 libpychrysaanalysisscanpatternsmodifiers_la_CFLAGS = $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) \
 	-I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c
index d0d1e1f..503580d 100644
--- a/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c
@@ -131,7 +131,7 @@ PyTypeObject *get_python_scan_hex_modifier_type(void)
 *                                                                             *
 *  Paramètres  : -                                                            *
 *                                                                             *
-*  Description : Prend en charge l'objet 'pychrysalide....HexModifier'.     *
+*  Description : Prend en charge l'objet 'pychrysalide....HexModifier'.       *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -141,7 +141,7 @@ PyTypeObject *get_python_scan_hex_modifier_type(void)
 
 bool ensure_python_scan_hex_modifier_is_registered(void)
 {
-    PyTypeObject *type;                     /* Type Python 'HexModifier' */
+    PyTypeObject *type;                     /* Type Python 'HexModifier'   */
     PyObject *module;                       /* Module à recompléter        */
     PyObject *dict;                         /* Dictionnaire du module      */
 
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c
index 1e9bda7..ae450dc 100644
--- a/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c
@@ -32,6 +32,7 @@
 #include "list.h"
 #include "plain.h"
 #include "rev.h"
+#include "xor.h"
 #include "../../../../helpers.h"
 
 
@@ -102,6 +103,7 @@ bool populate_analysis_scan_patterns_modifiers_module(void)
     if (result) result = ensure_python_scan_modifier_list_is_registered();
     if (result) result = ensure_python_scan_plain_modifier_is_registered();
     if (result) result = ensure_python_scan_reverse_modifier_is_registered();
+    if (result) result = ensure_python_scan_xor_modifier_is_registered();
 
     assert(result);
 
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c
index 6ee350c..841e929 100644
--- a/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c
@@ -141,7 +141,7 @@ PyTypeObject *get_python_scan_reverse_modifier_type(void)
 
 bool ensure_python_scan_reverse_modifier_is_registered(void)
 {
-    PyTypeObject *type;                     /* Type Python 'HexModifier' */
+    PyTypeObject *type;                     /* Type Python ReverseModifier */
     PyObject *module;                       /* Module à recompléter        */
     PyObject *dict;                         /* Dictionnaire du module      */
 
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.c
new file mode 100644
index 0000000..1280f2f
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.c
@@ -0,0 +1,210 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hex.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/hex.c"
+ *
+ * Copyright (C) 2023 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "xor.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <analysis/scan/patterns/modifiers/xor.h>
+
+
+#include "../modifier.h"
+#include "../../../../access.h"
+#include "../../../../helpers.h"
+
+
+
+CREATE_DYN_CONSTRUCTOR(scan_xor_modifier, G_TYPE_SCAN_XOR_MODIFIER);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_scan_xor_modifier_init(PyObject *, PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = objet à initialiser (théoriquement).                  *
+*                args = arguments fournis à l'appel.                          *
+*                kwds = arguments de type key=val fournis.                    *
+*                                                                             *
+*  Description : Initialise une instance sur la base du dérivé de GObject.    *
+*                                                                             *
+*  Retour      : 0.                                                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static int py_scan_xor_modifier_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    int ret;                                /* Bilan de lecture des args.  */
+
+#define SCAN_HEX_MODIFIER_DOC                                               \
+    "The *XorModifier* class transforms a byte pattern by XORing bytes.\n"  \
+    "\n"                                                                    \
+    "Instances can be created using the following constructor:\n"           \
+    "\n"                                                                    \
+    "    XorModifier()"
+
+    /* Initialisation d'un objet GLib */
+
+    ret = forward_pygobjet_init(self);
+    if (ret == -1) return -1;
+
+    return 0;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Fournit un accès à une définition de type à diffuser.        *
+*                                                                             *
+*  Retour      : Définition d'objet pour Python.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+PyTypeObject *get_python_scan_xor_modifier_type(void)
+{
+    static PyMethodDef py_scan_xor_modifier_methods[] = {
+        { NULL }
+    };
+
+    static PyGetSetDef py_scan_xor_modifier_getseters[] = {
+        { NULL }
+    };
+
+    static PyTypeObject py_scan_xor_modifier_type = {
+
+        PyVarObject_HEAD_INIT(NULL, 0)
+
+        .tp_name        = "pychrysalide.analysis.scan.patterns.modifiers.XorModifier",
+        .tp_basicsize   = sizeof(PyGObject),
+
+        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+        .tp_doc         = SCAN_HEX_MODIFIER_DOC,
+
+        .tp_methods     = py_scan_xor_modifier_methods,
+        .tp_getset      = py_scan_xor_modifier_getseters,
+
+        .tp_init        = py_scan_xor_modifier_init,
+        .tp_new         = py_scan_xor_modifier_new,
+
+    };
+
+    return &py_scan_xor_modifier_type;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Prend en charge l'objet 'pychrysalide....XorModifier'.   *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool ensure_python_scan_xor_modifier_is_registered(void)
+{
+    PyTypeObject *type;                     /* Type Python XorModifier */
+    PyObject *module;                       /* Module à recompléter        */
+    PyObject *dict;                         /* Dictionnaire du module      */
+
+    type = get_python_scan_xor_modifier_type();
+
+    if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+    {
+        module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers");
+
+        dict = PyModule_GetDict(module);
+
+        if (!ensure_python_scan_token_modifier_is_registered())
+            return false;
+
+        if (!register_class_for_pygobject(dict, G_TYPE_SCAN_XOR_MODIFIER, type))
+            return false;
+
+    }
+
+    return true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : arg = argument quelconque à tenter de convertir.             *
+*                dst = destination des valeurs récupérées en cas de succès.   *
+*                                                                             *
+*  Description : Tente de convertir en transformation d'octets par inverse.   *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_scan_xor_modifier(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+
+    result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_xor_modifier_type());
+
+    switch (result)
+    {
+        case -1:
+            /* L'exception est déjà fixée par Python */
+            result = 0;
+            break;
+
+        case 0:
+            PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to XOR modifier");
+            break;
+
+        case 1:
+            *((GScanXorModifier **)dst) = G_SCAN_XOR_MODIFIER(pygobject_get(arg));
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.h
new file mode 100644
index 0000000..7b9bb69
--- /dev/null
+++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * xor.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/xor.h"
+ *
+ * Copyright (C) 2023 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_XOR_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_XOR_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_scan_xor_modifier_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.XorModifier'. */
+bool ensure_python_scan_xor_modifier_is_registered(void);
+
+/* Tente de convertir en transformation d'octets par inverse. */
+int convert_to_scan_xor_modifier(PyObject *, void *);
+
+
+
+#endif  /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_XOR_H */
diff --git a/src/analysis/scan/core.c b/src/analysis/scan/core.c
index da3cf00..6316a53 100644
--- a/src/analysis/scan/core.c
+++ b/src/analysis/scan/core.c
@@ -46,13 +46,14 @@
 #include "patterns/modifiers/hex.h"
 #include "patterns/modifiers/plain.h"
 #include "patterns/modifiers/rev.h"
+#include "patterns/modifiers/xor.h"
 
 
 /* Liste des modificateurs disponibles */
 
 typedef struct _available_modifier_t
 {
-    char *name;                             /* Désignation humaine         */
+    sized_string_t name;                    /* Désignation humaine         */
     GScanTokenModifier *instance;           /* Mécanisme correspondant     */
 
 } available_modifier_t;
@@ -76,18 +77,19 @@ static size_t __modifiers_count = 0;
 bool register_scan_token_modifier(GScanTokenModifier *modifier)
 {
     bool result;                            /* Bilan à retourner           */
-    char *name;                             /* Nom donné au modificateur   */
+    sized_string_t name;                    /* Nom donné au modificateur   */
     GScanTokenModifier *found;              /* Alternative présente        */
     available_modifier_t *last;             /* Emplacement disponible      */
 
-    name = g_scan_token_modifier_get_name(modifier);
+    name.data = g_scan_token_modifier_get_name(modifier);
+    name.len = strlen(name.data);
 
-    found = find_scan_token_modifiers_for_name(name);
+    found = find_scan_token_modifiers_for_name(&name);
 
     result = (found == NULL);
 
     if (!result)
-        free(name);
+        exit_szstr(&name);
 
     else
     {
@@ -137,6 +139,7 @@ bool load_all_known_scan_token_modifiers(void)
     if (result) result = REGISTER_SCAN_MODIFIER(g_scan_hex_modifier_new());
     if (result) result = REGISTER_SCAN_MODIFIER(g_scan_plain_modifier_new());
     if (result) result = REGISTER_SCAN_MODIFIER(g_scan_reverse_modifier_new());
+    if (result) result = REGISTER_SCAN_MODIFIER(g_scan_xor_modifier_new());
 
     return result;
 
@@ -160,7 +163,10 @@ void unload_all_scan_token_modifiers(void)
     size_t i;                               /* Boucle de parcours          */
 
     for (i = 0; i < __modifiers_count; i++)
+    {
+        exit_szstr(&__modifiers[i].name);
         g_object_unref(G_OBJECT(__modifiers[i].instance));
+    }
 
     if (__modifiers != NULL)
         free(__modifiers);
@@ -180,7 +186,7 @@ void unload_all_scan_token_modifiers(void)
 *                                                                             *
 ******************************************************************************/
 
-GScanTokenModifier *find_scan_token_modifiers_for_name(const char *name)
+GScanTokenModifier *find_scan_token_modifiers_for_name(const sized_string_t *name)
 {
     GScanTokenModifier *result;             /* Instance à renvoyer         */
     size_t i;                               /* Boucle de parcours          */
@@ -192,7 +198,10 @@ GScanTokenModifier *find_scan_token_modifiers_for_name(const char *name)
     {
         registered = __modifiers + i;
 
-        if (strcmp(registered->name, name) == 0)
+        if (registered->name.len != name->len)
+            continue;
+
+        if (strncmp(registered->name.data, name->data, name->len) == 0)
         {
             result = registered->instance;
             g_object_ref(G_OBJECT(result));
diff --git a/src/analysis/scan/core.h b/src/analysis/scan/core.h
index 86a47da..8a18a75 100644
--- a/src/analysis/scan/core.h
+++ b/src/analysis/scan/core.h
@@ -40,7 +40,7 @@ bool load_all_known_scan_token_modifiers(void);
 void unload_all_scan_token_modifiers(void);
 
 /* Fournit le modificateur correspondant à un nom. */
-GScanTokenModifier *find_scan_token_modifiers_for_name(const char *);
+GScanTokenModifier *find_scan_token_modifiers_for_name(const sized_string_t *);
 
 /* Inscrit les principales fonctions dans l'espace racine. */
 bool populate_main_scan_namespace(GScanNamespace *);
diff --git a/src/analysis/scan/grammar.y b/src/analysis/scan/grammar.y
index 741b394..c63dda7 100644
--- a/src/analysis/scan/grammar.y
+++ b/src/analysis/scan/grammar.y
@@ -40,6 +40,7 @@ typedef void *yyscan_t;
 #include "exprs/setcounter.h"
 #include "exprs/relational.h"
 #include "exprs/strop.h"
+#include "patterns/customizer.h"
 #include "patterns/modifier.h"
 #include "patterns/modifiers/list.h"
 #include "patterns/tokens/hex.h"
@@ -80,6 +81,7 @@ typedef void *yyscan_t;
     GSearchPattern *pattern;                /* Nouveau motif à considérer  */
 
     GScanTokenModifier *modifier;           /* Modificateur pour texte     */
+    modifier_arg_t mod_arg;                 /* Argument pour modificateur  */
     ScanPlainNodeFlags str_flags;           /* Fanions pour texte          */
 
 
@@ -255,6 +257,8 @@ YY_DECL;
 %type <modifier> chained_modifiers
 %type <modifier> mod_stage
 %type <modifier> modifier
+%type <modifier> modifier_args
+%type <mod_arg> modifier_arg
 
 %type <str_flags> str_flags
 
@@ -512,9 +516,9 @@ YY_DECL;
                    {
                        $$ = $1;
                    }
-                   | chained_modifiers
+                   | "(" chained_modifiers ")"
                    {
-                       $$ = $1;
+                       $$ = $2;
                    }
                    ;
 
@@ -550,7 +554,7 @@ YY_DECL;
 
           modifier : NAME
                    {
-                       $$ = find_scan_token_modifiers_for_name($1.data);
+                       $$ = find_scan_token_modifiers_for_name(&$1);
                        if ($$ == NULL)
                        {
                            char *_msg;
@@ -567,9 +571,71 @@ YY_DECL;
                            YYERROR;
                        }
                    }
-                   | "(" chained_modifiers ")"
+                   | NAME "(" modifier_args ")"
                    {
-                       $$ = $2;
+                       GScanTokenModifier *_mod;
+                       bool _status;
+
+                       $$ = $3;
+
+                       _mod = find_scan_token_modifiers_for_name(&$1);
+                       if (_mod == NULL)
+                       {
+                           char *_msg;
+                           int _ret;
+
+                           _ret = asprintf(&_msg, _("Unknown modifier: \"%.*s\""), (int)$1.len, $1.data);
+
+                           if (_ret != -1)
+                           {
+                               raise_error(_msg);
+                               free(_msg);
+                           }
+
+                           g_object_unref(G_OBJECT($$));
+
+                           YYERROR;
+                       }
+
+                       _status = g_scan_token_customizer_attach_modifier(G_SCAN_TOKEN_CUSTOMIZER($$), _mod);
+                       if (!_status)
+                       {
+                           char *_msg;
+                           int _ret;
+
+                           _ret = asprintf(&_msg,
+                                           _("Unsupported argument for modifier: \"%.*s\""),
+                                           (int)$1.len, $1.data);
+                           if (_ret != -1)
+                           {
+                               raise_error(_msg);
+                               free(_msg);
+                           }
+
+                           g_object_unref(G_OBJECT($$));
+
+                           YYERROR;
+                       }
+
+                   }
+                   ;
+
+
+     modifier_args : modifier_arg
+                   {
+                       $$ = g_scan_token_customizer_new(&$1);
+                   }
+                   | modifier_args "," modifier_arg
+                   {
+                       $$ = $1;
+                       g_scan_token_customizer_add_extra_arg(G_SCAN_TOKEN_CUSTOMIZER($$), &$3);
+                   }
+                   ;
+
+      modifier_arg : PLAIN_TEXT
+                   {
+                       $$.type = MAT_STRING;
+                       $$.value.string = $1;
                    }
                    ;
 
diff --git a/src/analysis/scan/patterns/Makefile.am b/src/analysis/scan/patterns/Makefile.am
index c3d0994..c520321 100644
--- a/src/analysis/scan/patterns/Makefile.am
+++ b/src/analysis/scan/patterns/Makefile.am
@@ -5,6 +5,9 @@ noinst_LTLIBRARIES  = libanalysisscanpatterns.la
 libanalysisscanpatterns_la_SOURCES =		\
 	backend-int.h							\
 	backend.h backend.c						\
+	customizer-int.h						\
+	customizer.h customizer.c				\
+	modarg.h								\
 	modifier-int.h							\
 	modifier.h modifier.c					\
 	token-int.h								\
diff --git a/src/analysis/scan/patterns/customizer-int.h b/src/analysis/scan/patterns/customizer-int.h
new file mode 100644
index 0000000..9d49ab6
--- /dev/null
+++ b/src/analysis/scan/patterns/customizer-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * customizer-int.h - prototypes internes pour la modification paramétrée d'une séquence d'octets
+ *
+ * Copyright (C) 2023 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_CUSTOMIZER_INT_H
+#define _ANALYSIS_SCAN_CUSTOMIZER_INT_H
+
+
+#include "customizer.h"
+#include "modifier-int.h"
+
+
+
+/* Encadrement de transformation paramétrée d'une séquence d'octets (instance) */
+struct _GScanTokenCustomizer
+{
+    GScanTokenModifier parent;              /* A laisser en premier        */
+
+    GScanTokenModifier *effective;          /* Modificateur effectif       */
+
+    modifier_arg_t *args;                   /* Paramètres de transformation*/
+    size_t count;                           /* Quantité de ces paramètres  */
+
+};
+
+/* Encadrement de transformation paramétrée d'une séquence d'octets (classe) */
+struct _GScanTokenCustomizerClass
+{
+    GScanTokenModifierClass parent;         /* A laisser en premier        */
+
+};
+
+
+/* Met en place un encadrement de transformation de motifs. */
+bool g_scan_token_customizer_create(GScanTokenCustomizer *, const modifier_arg_t *);
+
+
+
+#endif  /* _ANALYSIS_SCAN_CUSTOMIZER_INT_H */
diff --git a/src/analysis/scan/patterns/customizer.c b/src/analysis/scan/patterns/customizer.c
new file mode 100644
index 0000000..59065aa
--- /dev/null
+++ b/src/analysis/scan/patterns/customizer.c
@@ -0,0 +1,374 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * customizer.c - modification paramétrée d'une séquence d'octets
+ *
+ * Copyright (C) 2023 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 "customizer.h"
+
+
+#include <malloc.h>
+
+
+#include "customizer-int.h"
+
+
+
+/* --------------------- TRANSFORMATION PERSONNALISEE DE MOTIFS --------------------- */
+
+
+/* Initialise la classe des transformations paramétrée. */
+static void g_scan_token_customizer_class_init(GScanTokenCustomizerClass *);
+
+/* Initialise une instance de transformation paramétrée. */
+static void g_scan_token_customizer_init(GScanTokenCustomizer *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_customizer_dispose(GScanTokenCustomizer *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_customizer_finalize(GScanTokenCustomizer *);
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_token_customizer_get_name(const GScanTokenCustomizer *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_token_customizer_transform(const GScanTokenCustomizer *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       TRANSFORMATION PERSONNALISEE DE MOTIFS                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transformation personnalisée d'une séquence d'octets. */
+G_DEFINE_TYPE(GScanTokenCustomizer, g_scan_token_customizer, G_TYPE_SCAN_TOKEN_MODIFIER);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des transformations paramétrée.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_customizer_class_init(GScanTokenCustomizerClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GScanTokenModifierClass *modifier;      /* Version de classe parente   */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_customizer_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_scan_token_customizer_finalize;
+
+    modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+    modifier->get_name = (get_scan_modifier_name_fc)g_scan_token_customizer_get_name;
+
+    modifier->transform = (transform_scan_token_fc)g_scan_token_customizer_transform;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : customizer = instance à initialiser.                         *
+*                                                                             *
+*  Description : Initialise une instance de transformation paramétrée.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_customizer_init(GScanTokenCustomizer *customizer)
+{
+    customizer->effective = NULL;
+
+    customizer->args = NULL;
+    customizer->count = 0;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : customizer = instance d'objet GLib à traiter.                *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_customizer_dispose(GScanTokenCustomizer *customizer)
+{
+    g_clear_object(&customizer->effective);
+
+    G_OBJECT_CLASS(g_scan_token_customizer_parent_class)->dispose(G_OBJECT(customizer));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : customizer = instance d'objet GLib à traiter.                *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_customizer_finalize(GScanTokenCustomizer *customizer)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    for (i = 0; i < customizer->count; i++)
+        exit_mod_arg(&customizer->args[i]);
+
+    if (customizer->args != NULL)
+        free(customizer->args);
+
+    G_OBJECT_CLASS(g_scan_token_customizer_parent_class)->finalize(G_OBJECT(customizer));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : arg = premier argument pour personnaliser l'opération.       *
+*                                                                             *
+*  Description : Construit un encadrement de transformation de motifs.        *
+*                                                                             *
+*  Retour      : Mécanisme mis en place.                                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_token_customizer_new(const modifier_arg_t *arg)
+{
+    GScanTokenModifier *result;             /* Structure à retourner       */
+
+    result = g_object_new(G_TYPE_SCAN_TOKEN_CUSTOMIZER, NULL);
+
+    if (!g_scan_token_customizer_create(G_SCAN_TOKEN_CUSTOMIZER(result), arg))
+        g_clear_object(&result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : customizer = encadrement de motif à initialiser pleinement.  *
+*                arg        = premier argument pour personnaliser l'opération.*
+*                                                                             *
+*  Description : Met en place un encadrement de transformation de motifs.     *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_scan_token_customizer_create(GScanTokenCustomizer *customizer, const modifier_arg_t *arg)
+{
+    g_scan_token_customizer_add_extra_arg(customizer, arg);
+
+    return true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : customizer = encadrement de motif à compléter.               *
+*                arg        = nouvel argument pour personnaliser l'opération. *
+*                                                                             *
+*  Description : Ajoute un argument à l'encadrement de transformation.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_scan_token_customizer_add_extra_arg(GScanTokenCustomizer *customizer, const modifier_arg_t *arg)
+{
+    customizer->args = realloc(customizer->args, ++customizer->count * sizeof(modifier_arg_t));
+
+    copy_mod_arg(&customizer->args[customizer->count - 1], arg);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : customizer = encadrement de motif à compléter.               *
+*                modifier   = modificateur de motifs à employer en sous-main. *
+*                                                                             *
+*  Description : Définit le transformateur effectif pour les motifs.          *
+*                                                                             *
+*  Retour      : true si le motificateur accepte les arguments courants.      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_scan_token_customizer_attach_modifier(GScanTokenCustomizer *customizer, GScanTokenModifier *modifier)
+{
+    bool result;                            /* Validation à retourner      */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = true;
+
+    for (i = 0; i < customizer->count && result; i++)
+        result = g_scan_token_modifier_can_handle_arg(modifier, &customizer->args[i]);
+
+    if (!result) goto exit;
+
+    customizer->effective = modifier;
+    g_object_ref(G_OBJECT(modifier));
+
+ exit:
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : modifier = modificateur à consulter.                         *
+*                                                                             *
+*  Description : Fournit le nom d'appel d'un modificateur pour motif.         *
+*                                                                             *
+*  Retour      : Désignation humaine.                                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *g_scan_token_customizer_get_name(const GScanTokenCustomizer *modifier)
+{
+    char *result;                           /* Désignation à retourner     */
+
+    if (modifier->effective == NULL)
+        result = NULL;
+
+    else
+        result = g_scan_token_modifier_get_name(modifier->effective);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : modifier = modificateur à solliciter.                        *
+*                src      = séquence d'octets à traiter.                      *
+*                scount   = quantité de ces séquences.                        *
+*                dest     = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+*                dcount   = quantité de ces séquences.                        *
+*                                                                             *
+*  Description : Transforme une séquence d'octets pour motif de recherche.    *
+*                                                                             *
+*  Retour      : Bilan de l'opération : succès ou échec.                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_token_customizer_transform(const GScanTokenCustomizer *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+    bool result;                            /* Bilan d'opération à renvoyer*/
+    size_t i;                               /* Boucle de parcours #1       */
+    sized_binary_t *extra;                  /* Motifs supplémentaires      */
+    size_t extra_count;                     /* Quantité de ces motifs      */
+    sized_binary_t *new;                    /* Nouvel emplacement libre    */
+    size_t k;                               /* Boucle de parcours #2       */
+
+    *dest = NULL;
+    *dcount = 0;
+
+    for (i = 0; i < modifier->count; i++)
+    {
+        result = g_scan_token_modifier_transform_with_arg(modifier->effective,
+                                                          src, scount,
+                                                          &modifier->args[i],
+                                                          &extra, &extra_count);
+        if (!result) goto exit;
+
+        new = (*dest) + *dcount;
+
+        *dcount += extra_count;
+        *dest = realloc(*dest, *dcount * sizeof(sized_binary_t));
+
+        for (k = 0; k < extra_count; k++, new++)
+            copy_szstr(*new, extra[k]);
+
+        free(extra);
+
+    }
+
+ exit:
+
+    if (!result)
+    {
+        for (i = 0; i < *dcount; i++)
+            exit_szstr(dest[i]);
+
+        if (*dest != NULL)
+            free(*dest);
+
+        *dest = NULL;
+        *dcount = 0;
+
+    }
+
+    return result;
+
+}
diff --git a/src/analysis/scan/patterns/customizer.h b/src/analysis/scan/patterns/customizer.h
new file mode 100644
index 0000000..845d9ff
--- /dev/null
+++ b/src/analysis/scan/patterns/customizer.h
@@ -0,0 +1,65 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * customizer.h - prototypes pour la modification paramétrée d'une séquence d'octets
+ *
+ * Copyright (C) 2023 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_CUSTOMIZER_H
+#define _ANALYSIS_SCAN_CUSTOMIZER_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "modifier.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_CUSTOMIZER            g_scan_token_customizer_get_type()
+#define G_SCAN_TOKEN_CUSTOMIZER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_CUSTOMIZER, GScanTokenCustomizer))
+#define G_IS_SCAN_TOKEN_CUSTOMIZER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_CUSTOMIZER))
+#define G_SCAN_TOKEN_CUSTOMIZER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_CUSTOMIZER, GScanTokenCustomizerClass))
+#define G_IS_SCAN_TOKEN_CUSTOMIZER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_CUSTOMIZER))
+#define G_SCAN_TOKEN_CUSTOMIZER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_CUSTOMIZER, GScanTokenCustomizerClass))
+
+
+/* Encadrement de transformation paramétrée d'une séquence d'octets (instance) */
+typedef struct _GScanTokenCustomizer GScanTokenCustomizer;
+
+/* Encadrement de transformation paramétrée d'une séquence d'octets (classe) */
+typedef struct _GScanTokenCustomizerClass GScanTokenCustomizerClass;
+
+
+/* Indique le type défini pour une transformation personnalisée d'une séquence d'octets. */
+GType g_scan_token_customizer_get_type(void);
+
+/* Construit un encadrement de transformation de motifs. */
+GScanTokenModifier *g_scan_token_customizer_new(const modifier_arg_t *);
+
+/* Ajoute un argument à l'encadrement de transformation. */
+void g_scan_token_customizer_add_extra_arg(GScanTokenCustomizer *, const modifier_arg_t *);
+
+/* Définit le transformateur effectif pour les motifs. */
+bool g_scan_token_customizer_attach_modifier(GScanTokenCustomizer *, GScanTokenModifier *);
+
+
+
+#endif  /* _ANALYSIS_SCAN_CUSTOMIZER_H */
diff --git a/src/analysis/scan/patterns/modarg.h b/src/analysis/scan/patterns/modarg.h
new file mode 100644
index 0000000..d96e137
--- /dev/null
+++ b/src/analysis/scan/patterns/modarg.h
@@ -0,0 +1,91 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * modarg.h - prototypes pour la conservation d'arguments pour modificateurs
+ *
+ * Copyright (C) 2023 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_MODARG_H
+#define _ANALYSIS_SCAN_MODARG_H
+
+
+#include <stdbool.h>
+
+
+#include "../../../common/szstr.h"
+
+
+
+/* Types d'arguments pris en charge */
+typedef enum _ModifierArgType
+{
+    MAT_BOOLEAN,                            /* Valeur booléenne            */
+    MAT_SIGNED_INTEGER,                     /* Nombre entier 64 bits #1    */
+    MAT_UNSIGNED_INTEGER,                   /* Nombre entier 64 bits #2    */
+    MAT_STRING,                             /* Chaîne de caractères        */
+    MAT_RANGE,                              /* Séquence d'entiers          */
+
+} ModifierArgType;
+
+/* Argument pour modificateur de motif */
+typedef struct _modifier_arg_t
+{
+    ModifierArgType type;                   /* Type de valeur portée       */
+
+    union
+    {
+        bool boolean;                       /* Valeur booléenne            */
+        long long s_integer;                /* Valeur entière 64 bits      */
+        unsigned long long u_integer;       /* Valeur entière 64 bits      */
+        sized_string_t string;              /* Chaîne de caractères        */
+
+        struct
+        {
+            long long start;                /* Point de départ             */
+            long long end;                  /* Point d'arrivée             */
+
+        } range;
+
+    } value;
+
+} modifier_arg_t;
+
+
+#define exit_mod_arg(a)                                         \
+    do                                                          \
+    {                                                           \
+        if ((a)->type == MAT_STRING)                            \
+            exit_szstr(&(a)->value.string);                     \
+    }                                                           \
+    while (0)
+
+#define copy_mod_arg(d, s)                                      \
+    do                                                          \
+    {                                                           \
+        (d)->type = (s)->type;                                  \
+        if ((s)->type == MAT_STRING)                            \
+            szstrdup(&(d)->value.string, &(s)->value.string);   \
+        else                                                    \
+            *(d) = *(s);                                        \
+    }                                                           \
+    while (0)
+
+
+
+#endif  /* _ANALYSIS_SCAN_MODARG_H */
diff --git a/src/analysis/scan/patterns/modifier-int.h b/src/analysis/scan/patterns/modifier-int.h
index 246c139..e1de2d8 100644
--- a/src/analysis/scan/patterns/modifier-int.h
+++ b/src/analysis/scan/patterns/modifier-int.h
@@ -33,7 +33,13 @@
 typedef char * (* get_scan_modifier_name_fc) (const GScanTokenModifier *);
 
 /* Transforme une séquence d'octets pour motif de recherche. */
-typedef bool (* transform_scan_token_fc) (const GScanTokenModifier *, const sized_binary_t *, sized_binary_t **, size_t *);
+typedef bool (* transform_scan_token_fc) (const GScanTokenModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Détermine si un argument est bien toléré par un modificateur. */
+typedef bool (* can_token_modifier_handle_arg) (const GScanTokenModifier *, const modifier_arg_t *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+typedef bool (* transform_scan_token_with_fc) (const GScanTokenModifier *, const sized_binary_t *, size_t, const modifier_arg_t *, sized_binary_t **, size_t *);
 
 
 /* Transformation d'une séquence d'octets en une ou plusieurs autres formes (instance) */
@@ -51,6 +57,8 @@ struct _GScanTokenModifierClass
     get_scan_modifier_name_fc get_name;     /* Fourniture du nom d'appel   */
 
     transform_scan_token_fc transform;      /* Opération de transformation */
+    can_token_modifier_handle_arg can_handle; /* Support d'argument donné  */
+    transform_scan_token_with_fc transform_with; /* Opération encadrée     */
 
 };
 
diff --git a/src/analysis/scan/patterns/modifier.c b/src/analysis/scan/patterns/modifier.c
index 77d8bfd..4f041b1 100644
--- a/src/analysis/scan/patterns/modifier.c
+++ b/src/analysis/scan/patterns/modifier.c
@@ -156,8 +156,9 @@ char *g_scan_token_modifier_get_name(const GScanTokenModifier *modifier)
 *                                                                             *
 *  Paramètres  : modifier = modificateur à solliciter.                        *
 *                src      = séquence d'octets à traiter.                      *
+*                scount   = quantité de ces séquences.                        *
 *                dest     = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
-*                count    = quantité de ces séquences.                        *
+*                dcount   = quantité de ces séquences.                        *
 *                                                                             *
 *  Description : Transforme une séquence d'octets pour motif de recherche.    *
 *                                                                             *
@@ -167,14 +168,83 @@ char *g_scan_token_modifier_get_name(const GScanTokenModifier *modifier)
 *                                                                             *
 ******************************************************************************/
 
-bool g_scan_token_modifier_transform(const GScanTokenModifier *modifier, const sized_binary_t *src, sized_binary_t **dest, size_t *count)
+bool g_scan_token_modifier_transform(const GScanTokenModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
 {
     bool result;                            /* Bilan d'opération à renvoyer*/
     GScanTokenModifierClass *class;         /* Classe à activer            */
 
     class = G_SCAN_TOKEN_MODIFIER_GET_CLASS(modifier);
 
-    result = class->transform(modifier, src, dest, count);
+    result = class->transform(modifier, src, scount, dest, dcount);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : modifier = modificateur à solliciter.                        *
+*                arg      = argument de personnalisation.                     *
+*                                                                             *
+*  Description : Détermine si un argument est bien toléré par un modificateur.*
+*                                                                             *
+*  Retour      : Bilan de la consultation : support ou non.                   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_scan_token_modifier_can_handle_arg(const GScanTokenModifier *modifier, const modifier_arg_t *arg)
+{
+    bool result;                            /* Bilan d'opération à renvoyer*/
+    GScanTokenModifierClass *class;         /* Classe à activer            */
+
+    class = G_SCAN_TOKEN_MODIFIER_GET_CLASS(modifier);
+
+    if (class->can_handle == NULL)
+        result = false;
+    else
+        result = class->can_handle(modifier, arg);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : modifier = modificateur à solliciter.                        *
+*                src      = séquence d'octets à traiter.                      *
+*                scount   = quantité de ces séquences.                        *
+*                arg      = argument de personnalisation.                     *
+*                dest     = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+*                dcount   = quantité de ces séquences.                        *
+*                                                                             *
+*  Description : Transforme une séquence d'octets pour motif de recherche.    *
+*                                                                             *
+*  Retour      : Bilan de l'opération : succès ou échec.                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_scan_token_modifier_transform_with_arg(const GScanTokenModifier *modifier, const sized_binary_t *src, size_t scount, const modifier_arg_t *arg, sized_binary_t **dest, size_t *dcount)
+{
+    bool result;                            /* Bilan d'opération à renvoyer*/
+    GScanTokenModifierClass *class;         /* Classe à activer            */
+
+    result = false;
+
+    if (!g_scan_token_modifier_can_handle_arg(modifier, arg))
+        goto exit;
+
+    class = G_SCAN_TOKEN_MODIFIER_GET_CLASS(modifier);
+
+    if (class->transform_with != NULL)
+        result = class->transform_with(modifier, src, scount, arg, dest, dcount);
+
+ exit:
 
     return result;
 
diff --git a/src/analysis/scan/patterns/modifier.h b/src/analysis/scan/patterns/modifier.h
index a195ca8..ce2589a 100644
--- a/src/analysis/scan/patterns/modifier.h
+++ b/src/analysis/scan/patterns/modifier.h
@@ -29,6 +29,8 @@
 #include <stdbool.h>
 
 
+
+#include "modarg.h"
 #include "../../../common/szstr.h"
 
 
@@ -55,7 +57,13 @@ GType g_scan_token_modifier_get_type(void);
 char *g_scan_token_modifier_get_name(const GScanTokenModifier *);
 
 /* Transforme une séquence d'octets pour motif de recherche. */
-bool g_scan_token_modifier_transform(const GScanTokenModifier *, const sized_binary_t *, sized_binary_t **, size_t *);
+bool g_scan_token_modifier_transform(const GScanTokenModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Détermine si un argument est bien toléré par un modificateur. */
+bool g_scan_token_modifier_can_handle_arg(const GScanTokenModifier *, const modifier_arg_t *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+bool g_scan_token_modifier_transform_with_arg(const GScanTokenModifier *, const sized_binary_t *, size_t, const modifier_arg_t *, sized_binary_t **, size_t *);
 
 
 
diff --git a/src/analysis/scan/patterns/modifiers/Makefile.am b/src/analysis/scan/patterns/modifiers/Makefile.am
index fe5263c..f66393e 100644
--- a/src/analysis/scan/patterns/modifiers/Makefile.am
+++ b/src/analysis/scan/patterns/modifiers/Makefile.am
@@ -7,7 +7,8 @@ libanalysisscanpatternsmodifiers_la_SOURCES = \
 	list-int.h								\
 	list.h list.c							\
 	plain.h plain.c							\
-	rev.h rev.c
+	rev.h rev.c								\
+	xor.h xor.c
 
 libanalysisscanpatternsmodifiers_la_CFLAGS = $(LIBGOBJ_CFLAGS)
 
diff --git a/src/analysis/scan/patterns/modifiers/hex.c b/src/analysis/scan/patterns/modifiers/hex.c
index cf1583c..da992df 100644
--- a/src/analysis/scan/patterns/modifiers/hex.c
+++ b/src/analysis/scan/patterns/modifiers/hex.c
@@ -56,7 +56,7 @@ static void g_scan_hex_modifier_finalize(GScanHexModifier *);
 static char *g_scan_hex_modifier_get_name(const GScanHexModifier *);
 
 /* Transforme une séquence d'octets pour motif de recherche. */
-static bool g_scan_hex_modifier_transform(const GScanHexModifier *, const sized_binary_t *, sized_binary_t **, size_t *);
+static bool g_scan_hex_modifier_transform(const GScanHexModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
 
 
 
@@ -212,8 +212,9 @@ static char *g_scan_hex_modifier_get_name(const GScanHexModifier *modifier)
 *                                                                             *
 *  Paramètres  : modifier = modificateur à solliciter.                        *
 *                src      = séquence d'octets à traiter.                      *
+*                scount   = quantité de ces séquences.                        *
 *                dest     = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
-*                count    = quantité de ces séquences.                        *
+*                dcount   = quantité de ces séquences.                        *
 *                                                                             *
 *  Description : Transforme une séquence d'octets pour motif de recherche.    *
 *                                                                             *
@@ -223,28 +224,36 @@ static char *g_scan_hex_modifier_get_name(const GScanHexModifier *modifier)
 *                                                                             *
 ******************************************************************************/
 
-static bool g_scan_hex_modifier_transform(const GScanHexModifier *modifier, const sized_binary_t *src, sized_binary_t **dest, size_t *count)
+static bool g_scan_hex_modifier_transform(const GScanHexModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
 {
     bool result;                            /* Bilan d'opération à renvoyer*/
     sized_binary_t *binary;                 /* Raccourci vers le stockage  */
-    size_t i;                               /* Boucle de parcours          */
+    size_t i;                               /* Boucle de parcours #1       */
+    const sized_binary_t *_src;             /* SOurce courante             */
+    size_t k;                               /* Boucle de parcours #2       */
 
     static char *alphabet = "0123456789abcdef";
 
     result = true;
 
-    *dest = malloc(1 * sizeof(sized_binary_t));
-    *count = 1;
+    *dcount = scount;
+    *dest = malloc(*dcount * sizeof(sized_binary_t));
 
     binary = &(*dest)[0];
 
-    binary->len = src->len * 2;
-    binary->data = malloc(binary->len);
-
-    for (i = 0; i < src->len; i++)
+    for (i = 0; i < scount; i++, binary++)
     {
-        binary->data[i * 2 + 0] = alphabet[src->data[i] >> 4];
-        binary->data[i * 2 + 1] = alphabet[src->data[i] & 0xf];
+        _src = src + i;
+
+        binary->len = _src->len * 2;
+        binary->data = malloc(binary->len);
+
+        for (k = 0; k < _src->len; k++)
+        {
+            binary->data[k * 2 + 0] = alphabet[_src->data[k] >> 4];
+            binary->data[k * 2 + 1] = alphabet[_src->data[k] & 0xf];
+        }
+
     }
 
     return result;
diff --git a/src/analysis/scan/patterns/modifiers/list.c b/src/analysis/scan/patterns/modifiers/list.c
index 141fa54..5bf0faa 100644
--- a/src/analysis/scan/patterns/modifiers/list.c
+++ b/src/analysis/scan/patterns/modifiers/list.c
@@ -56,7 +56,7 @@ static void g_scan_modifier_list_finalize(GScanModifierList *);
 static char *g_scan_modifier_list_get_name(const GScanModifierList *);
 
 /* Transforme une séquence d'octets pour motif de recherche. */
-static bool g_scan_modifier_list_transform(const GScanModifierList *, const sized_binary_t *, sized_binary_t **, size_t *);
+static bool g_scan_modifier_list_transform(const GScanModifierList *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
 
 
 
@@ -345,8 +345,9 @@ static char *g_scan_modifier_list_get_name(const GScanModifierList *modifier)
 *                                                                             *
 *  Paramètres  : modifier = modificateur à solliciter.                        *
 *                src      = séquence d'octets à traiter.                      *
+*                scount   = quantité de ces séquences.                        *
 *                dest     = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
-*                count    = quantité de ces séquences.                        *
+*                dcount   = quantité de ces séquences.                        *
 *                                                                             *
 *  Description : Transforme une séquence d'octets pour motif de recherche.    *
 *                                                                             *
@@ -356,7 +357,7 @@ static char *g_scan_modifier_list_get_name(const GScanModifierList *modifier)
 *                                                                             *
 ******************************************************************************/
 
-static bool g_scan_modifier_list_transform(const GScanModifierList *modifier, const sized_binary_t *src, sized_binary_t **dest, size_t *count)
+static bool g_scan_modifier_list_transform(const GScanModifierList *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
 {
     bool result;                            /* Bilan d'opération à renvoyer*/
     size_t i;                               /* Boucle de parcours #1       */
@@ -366,17 +367,17 @@ static bool g_scan_modifier_list_transform(const GScanModifierList *modifier, co
     size_t k;                               /* Boucle de parcours #2       */
 
     *dest = NULL;
-    *count = 0;
+    *dcount = 0;
 
     for (i = 0; i < modifier->count; i++)
     {
-        result = g_scan_token_modifier_transform(modifier->modifiers[i], src, &extra, &extra_count);
+        result = g_scan_token_modifier_transform(modifier->modifiers[i], src, scount, &extra, &extra_count);
         if (!result) goto exit;
 
-        new = (*dest) + *count;
+        new = (*dest) + *dcount;
 
-        *count += extra_count;
-        *dest = realloc(*dest, *count * sizeof(sized_binary_t)); 
+        *dcount += extra_count;
+        *dest = realloc(*dest, *dcount * sizeof(sized_binary_t));
 
         for (k = 0; k < extra_count; k++, new++)
             copy_szstr(*new, extra[k]);
@@ -389,14 +390,14 @@ static bool g_scan_modifier_list_transform(const GScanModifierList *modifier, co
 
     if (!result)
     {
-        for (i = 0; i < *count; i++)
+        for (i = 0; i < *dcount; i++)
             exit_szstr(dest[i]);
 
         if (*dest != NULL)
             free(*dest);
 
         *dest = NULL;
-        *count = 0;
+        *dcount = 0;
 
     }
 
diff --git a/src/analysis/scan/patterns/modifiers/plain.c b/src/analysis/scan/patterns/modifiers/plain.c
index 5837d46..485bb23 100644
--- a/src/analysis/scan/patterns/modifiers/plain.c
+++ b/src/analysis/scan/patterns/modifiers/plain.c
@@ -56,7 +56,7 @@ static void g_scan_plain_modifier_finalize(GScanPlainModifier *);
 static char *g_scan_plain_modifier_get_name(const GScanPlainModifier *);
 
 /* Transforme une séquence d'octets pour motif de recherche. */
-static bool g_scan_plain_modifier_transform(const GScanPlainModifier *, const sized_binary_t *, sized_binary_t **, size_t *);
+static bool g_scan_plain_modifier_transform(const GScanPlainModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
 
 
 
@@ -212,8 +212,9 @@ static char *g_scan_plain_modifier_get_name(const GScanPlainModifier *modifier)
 *                                                                             *
 *  Paramètres  : modifier = modificateur à solliciter.                        *
 *                src      = séquence d'octets à traiter.                      *
+*                scount   = quantité de ces séquences.                        *
 *                dest     = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
-*                count    = quantité de ces séquences.                        *
+*                dcount   = quantité de ces séquences.                        *
 *                                                                             *
 *  Description : Transforme une séquence d'octets pour motif de recherche.    *
 *                                                                             *
@@ -223,22 +224,30 @@ static char *g_scan_plain_modifier_get_name(const GScanPlainModifier *modifier)
 *                                                                             *
 ******************************************************************************/
 
-static bool g_scan_plain_modifier_transform(const GScanPlainModifier *modifier, const sized_binary_t *src, sized_binary_t **dest, size_t *count)
+static bool g_scan_plain_modifier_transform(const GScanPlainModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
 {
     bool result;                            /* Bilan d'opération à renvoyer*/
     sized_binary_t *binary;                 /* Raccourci vers le stockage  */
+    size_t i;                               /* Boucle de parcours          */
+    const sized_binary_t *_src;             /* SOurce courante             */
 
     result = true;
 
-    *dest = malloc(1 * sizeof(sized_binary_t));
-    *count = 1;
+    *dcount = scount;
+    *dest = malloc(*dcount * sizeof(sized_binary_t));
 
     binary = &(*dest)[0];
 
-    binary->len = src->len;
-    binary->data = malloc(binary->len);
+    for (i = 0; i < scount; i++, binary++)
+    {
+        _src = src + i;
 
-    memcpy(binary->data, src->data, src->len);
+        binary->len = _src->len;
+        binary->data = malloc(binary->len);
+
+        memcpy(binary->data, _src->data, _src->len);
+
+    }
 
     return result;
 
diff --git a/src/analysis/scan/patterns/modifiers/rev.c b/src/analysis/scan/patterns/modifiers/rev.c
index d22b549..8b931bd 100644
--- a/src/analysis/scan/patterns/modifiers/rev.c
+++ b/src/analysis/scan/patterns/modifiers/rev.c
@@ -56,7 +56,7 @@ static void g_scan_reverse_modifier_finalize(GScanReverseModifier *);
 static char *g_scan_reverse_modifier_get_name(const GScanReverseModifier *);
 
 /* Transforme une séquence d'octets pour motif de recherche. */
-static bool g_scan_reverse_modifier_transform(const GScanReverseModifier *, const sized_binary_t *, sized_binary_t **, size_t *);
+static bool g_scan_reverse_modifier_transform(const GScanReverseModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
 
 
 
@@ -212,8 +212,9 @@ static char *g_scan_reverse_modifier_get_name(const GScanReverseModifier *modifi
 *                                                                             *
 *  Paramètres  : modifier = modificateur à solliciter.                        *
 *                src      = séquence d'octets à traiter.                      *
+*                scount   = quantité de ces séquences.                        *
 *                dest     = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
-*                count    = quantité de ces séquences.                        *
+*                dcount   = quantité de ces séquences.                        *
 *                                                                             *
 *  Description : Transforme une séquence d'octets pour motif de recherche.    *
 *                                                                             *
@@ -223,24 +224,32 @@ static char *g_scan_reverse_modifier_get_name(const GScanReverseModifier *modifi
 *                                                                             *
 ******************************************************************************/
 
-static bool g_scan_reverse_modifier_transform(const GScanReverseModifier *modifier, const sized_binary_t *src, sized_binary_t **dest, size_t *count)
+static bool g_scan_reverse_modifier_transform(const GScanReverseModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
 {
     bool result;                            /* Bilan d'opération à renvoyer*/
     sized_binary_t *binary;                 /* Raccourci vers le stockage  */
-    size_t i;                               /* Boucle de parcours          */
+    size_t i;                               /* Boucle de parcours #1       */
+    const sized_binary_t *_src;             /* SOurce courante             */
+    size_t k;                               /* Boucle de parcours #2       */
 
     result = true;
 
-    *dest = malloc(1 * sizeof(sized_binary_t));
-    *count = 1;
+    *dcount = scount;
+    *dest = malloc(*dcount * sizeof(sized_binary_t));
 
     binary = &(*dest)[0];
 
-    binary->len = src->len;
-    binary->data = malloc(binary->len);
+    for (i = 0; i < scount; i++, binary++)
+    {
+        _src = src + i;
 
-    for (i = 0; i < src->len; i++)
-        binary->data[src->len - i - 1] = src->data[i];
+        binary->len = _src->len;
+        binary->data = malloc(binary->len);
+
+        for (k = 0; k < _src->len; k++)
+            binary->data[_src->len - k - 1] = _src->data[k];
+
+    }
 
     return result;
 
diff --git a/src/analysis/scan/patterns/modifiers/xor.c b/src/analysis/scan/patterns/modifiers/xor.c
new file mode 100644
index 0000000..65194ab
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/xor.c
@@ -0,0 +1,395 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * xor.c - transormation via opération XOR
+ *
+ * Copyright (C) 2023 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 "xor.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <stdint.h>
+#include <string.h>
+
+
+#include "../modifier-int.h"
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des transmissions via opération XOR. */
+static void g_scan_xor_modifier_class_init(GScanXorModifierClass *klass);
+
+/* Initialise une instance de transmission via opération XOR. */
+static void g_scan_xor_modifier_init(GScanXorModifier *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_xor_modifier_dispose(GScanXorModifier *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_xor_modifier_finalize(GScanXorModifier *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_xor_modifier_get_name(const GScanXorModifier *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_xor_modifier_transform(const GScanXorModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Détermine si un argument est bien toléré par un modificateur. */
+static bool g_scan_xor_modifier_can_handle_arg(const GScanXorModifier *, const modifier_arg_t *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_xor_modifier_transform_with_arg(const GScanXorModifier *, const sized_binary_t *, size_t, const modifier_arg_t *, sized_binary_t **, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                         RECHERCHE D'UN MOTIF DE TEXTE BRUT                         */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une transormation via une opération XOR. */
+G_DEFINE_TYPE(GScanXorModifier, g_scan_xor_modifier, G_TYPE_SCAN_TOKEN_MODIFIER);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des transmissions via opération XOR.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_xor_modifier_class_init(GScanXorModifierClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GScanTokenModifierClass *modifier;      /* Version de classe parente   */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_xor_modifier_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_scan_xor_modifier_finalize;
+
+    modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+    modifier->get_name = (get_scan_modifier_name_fc)g_scan_xor_modifier_get_name;
+
+    modifier->transform = (transform_scan_token_fc)g_scan_xor_modifier_transform;
+    modifier->can_handle = (can_token_modifier_handle_arg)g_scan_xor_modifier_can_handle_arg;
+    modifier->transform_with = (transform_scan_token_with_fc)g_scan_xor_modifier_transform_with_arg;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : modifier = instance à initialiser.                           *
+*                                                                             *
+*  Description : Initialise une instance de transmission via opération XOR.   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_xor_modifier_init(GScanXorModifier *modifier)
+{
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : modifier = instance d'objet GLib à traiter.                  *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_xor_modifier_dispose(GScanXorModifier *modifier)
+{
+    G_OBJECT_CLASS(g_scan_xor_modifier_parent_class)->dispose(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : modifier = instance d'objet GLib à traiter.                  *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_xor_modifier_finalize(GScanXorModifier *modifier)
+{
+    G_OBJECT_CLASS(g_scan_xor_modifier_parent_class)->finalize(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Construit un modificateur livrant des octets traités par XOR.*
+*                                                                             *
+*  Retour      : Mécanisme mis en place.                                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_xor_modifier_new(void)
+{
+    GScanTokenModifier *result;                    /* Structure à retourner       */
+
+    result = g_object_new(G_TYPE_SCAN_XOR_MODIFIER, NULL);
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : modifier = modificateur à consulter.                         *
+*                                                                             *
+*  Description : Fournit le nom d'appel d'un modificateur pour motif.         *
+*                                                                             *
+*  Retour      : Désignation humaine.                                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *g_scan_xor_modifier_get_name(const GScanXorModifier *modifier)
+{
+    char *result;                           /* Désignation à retourner     */
+
+    result = strdup("xor");
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : modifier = modificateur à solliciter.                        *
+*                src      = séquence d'octets à traiter.                      *
+*                scount   = quantité de ces séquences.                        *
+*                dest     = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+*                dcount   = quantité de ces séquences.                        *
+*                                                                             *
+*  Description : Transforme une séquence d'octets pour motif de recherche.    *
+*                                                                             *
+*  Retour      : Bilan de l'opération : succès ou échec.                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_xor_modifier_transform(const GScanXorModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+    bool result;                            /* Bilan d'opération à renvoyer*/
+    sized_binary_t *binary;                 /* Raccourci vers le stockage  */
+    size_t i;                               /* Boucle de parcours #1       */
+    const sized_binary_t *_src;             /* SOurce courante             */
+    long long x;                            /* Boucle de parcours #2       */
+    size_t k;                               /* Boucle de parcours #3       */
+
+    result = true;
+
+    *dcount = scount * 256;
+    *dest = malloc(*dcount * sizeof(sized_binary_t));
+
+    binary = &(*dest)[0];
+
+    for (i = 0; i < scount; i++)
+    {
+        _src = src + i;
+
+        for (x = 0; x <= 0xff; x++, binary++)
+        {
+            binary->len = _src->len;
+            binary->data = malloc(binary->len);
+
+            for (k = 0; k < _src->len; k++)
+                binary->data[k] = _src->data[k] ^ x;
+
+        }
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : modifier = modificateur à solliciter.                        *
+*                arg      = argument de personnalisation.                     *
+*                                                                             *
+*  Description : Détermine si un argument est bien toléré par un modificateur.*
+*                                                                             *
+*  Retour      : Bilan de la consultation : support ou non.                   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_xor_modifier_can_handle_arg(const GScanXorModifier *modifier, const modifier_arg_t *arg)
+{
+    bool result;                            /* Bilan d'opération à renvoyer*/
+
+    switch (arg->type)
+    {
+        case MAT_UNSIGNED_INTEGER:
+            result = (arg->value.u_integer <= UINT8_MAX);
+            break;
+
+        case MAT_RANGE:
+            result = (INT8_MIN <= arg->value.range.start && arg->value.range.end <= INT8_MAX);
+            break;
+
+        default:
+            result = false;
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : modifier = modificateur à solliciter.                        *
+*                src      = séquence d'octets à traiter.                      *
+*                scount   = quantité de ces séquences.                        *
+*                arg      = argument de personnalisation.                     *
+*                dest     = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+*                dcount   = quantité de ces séquences.                        *
+*                                                                             *
+*  Description : Transforme une séquence d'octets pour motif de recherche.    *
+*                                                                             *
+*  Retour      : Bilan de l'opération : succès ou échec.                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_xor_modifier_transform_with_arg(const GScanXorModifier *modifier, const sized_binary_t *src, size_t scount, const modifier_arg_t *arg, sized_binary_t **dest, size_t *dcount)
+{
+    bool result;                            /* Bilan d'opération à renvoyer*/
+    sized_binary_t *binary;                 /* Raccourci vers le stockage  */
+    size_t i;                               /* Boucle de parcours #1       */
+    const sized_binary_t *_src;             /* SOurce courante             */
+    long long x;                            /* Boucle de parcours #2       */
+    size_t k;                               /* Boucle de parcours #3       */
+
+    result = true;
+
+    switch (arg->type)
+    {
+        case MAT_UNSIGNED_INTEGER:
+
+            *dcount = scount;
+            *dest = malloc(*dcount * sizeof(sized_binary_t));
+
+            binary = &(*dest)[0];
+
+            for (i = 0; i < scount; i++)
+            {
+                _src = src + i;
+
+                binary->len = _src->len;
+                binary->data = malloc(binary->len);
+
+                for (k = 0; k < _src->len; k++)
+                    binary->data[k] = _src->data[k] ^ arg->value.u_integer;
+
+            }
+
+            break;
+
+        case MAT_RANGE:
+
+            *dcount = scount * (arg->value.range.end - arg->value.range.start + 1);
+            *dest = malloc(*dcount * sizeof(sized_binary_t));
+
+            binary = &(*dest)[0];
+
+            for (i = 0; i < scount; i++)
+            {
+                _src = src + i;
+
+                for (x = arg->value.range.start; x <= arg->value.range.end; x++, binary++)
+                {
+                    binary->len = _src->len;
+                    binary->data = malloc(binary->len);
+
+                    for (k = 0; k < _src->len; k++)
+                        binary->data[k] = _src->data[k] ^ x;
+
+                }
+
+            }
+
+            break;
+
+        default:
+            assert(false);
+            result = false;
+
+    }
+
+    return result;
+
+}
diff --git a/src/analysis/scan/patterns/modifiers/xor.h b/src/analysis/scan/patterns/modifiers/xor.h
new file mode 100644
index 0000000..1a3e7e6
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/xor.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * xor.h - prototypes pour la transormation via opération XOR
+ *
+ * Copyright (C) 2023 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_MODIFIERS_XOR_H
+#define _ANALYSIS_SCAN_PATTERNS_MODIFIERS_XOR_H
+
+
+#include <glib-object.h>
+
+
+#include "../modifier.h"
+
+
+
+#define G_TYPE_SCAN_XOR_MODIFIER            g_scan_xor_modifier_get_type()
+#define G_SCAN_XOR_MODIFIER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_XOR_MODIFIER, GScanXorModifier))
+#define G_IS_SCAN_XOR_MODIFIER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_XOR_MODIFIER))
+#define G_SCAN_XOR_MODIFIER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_XOR_MODIFIER, GScanXorModifierClass))
+#define G_IS_SCAN_XOR_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_XOR_MODIFIER))
+#define G_SCAN_XOR_MODIFIER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_XOR_MODIFIER, GScanXorModifierClass))
+
+
+/* Transormation via inversement d'une séquence d'octets (instance) */
+typedef GScanTokenModifier GScanXorModifier;
+
+/* Transormation via inversement d'une séquence d'octets (classe) */
+typedef GScanTokenModifierClass GScanXorModifierClass;
+
+
+/* Indique le type défini pour une transormation via une opération XOR. */
+GType g_scan_xor_modifier_get_type(void);
+
+/* Construit un modificateur livrant des octets traités par XOR. */
+GScanTokenModifier *g_scan_xor_modifier_new(void);
+
+
+
+#endif  /* _ANALYSIS_SCAN_PATTERNS_MODIFIERS_XOR_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/plain.c b/src/analysis/scan/patterns/tokens/nodes/plain.c
index 5a7f976..5d89cf8 100644
--- a/src/analysis/scan/patterns/tokens/nodes/plain.c
+++ b/src/analysis/scan/patterns/tokens/nodes/plain.c
@@ -344,7 +344,7 @@ static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanConte
 
     }
     else
-        result = g_scan_token_modifier_transform(node->modifier, &node->orig, &node->raw, &node->count);
+        result = g_scan_token_modifier_transform(node->modifier, &node->orig, 1, &node->raw, &node->count);
 
     if (!result)
         goto exit;
diff --git a/src/analysis/scan/tokens.l b/src/analysis/scan/tokens.l
index b284128..6633975 100644
--- a/src/analysis/scan/tokens.l
+++ b/src/analysis/scan/tokens.l
@@ -607,6 +607,32 @@ bytes_fuzzy_id [\*A-Za-z_][\*A-Za-z0-9_]*
                                     }
 
 
+
+<bytes>[A-Za-z_][A-Za-z0-9_]* {
+                                    yylval->sized_cstring.data = yytext;
+                                    yylval->sized_cstring.len = yyleng;
+                                    return NAME;
+                                }
+
+
+                         <bytes>"(" { return PAREN_O; }
+
+                         <bytes>")" { return PAREN_C; }
+
+                         <bytes>"," { return COMMA; }
+
+
+<bytes>\"{str_not_escaped}+\" {
+                                        yylval->sized_cstring.data = yytext + 1;
+                                        yylval->sized_cstring.len = yyleng - 2;
+
+                                        return PLAIN_TEXT;
+                                    }
+
+
+
+
+
 %{ /* Définition de motif en hexadécimal */ %}
 
                    <bytes_value>"{" {
@@ -885,9 +911,9 @@ bytes_fuzzy_id [\*A-Za-z_][\*A-Za-z0-9_]*
 <condition>"/"                  { return DIV; }
 <condition>"%"                  { return MOD; }
 
-<bytes,condition>"("            { return PAREN_O; }
-<bytes,condition>")"            { return PAREN_C; }
-<bytes,condition>","            { return COMMA; }
+<condition>"("                  { return PAREN_O; }
+<condition>")"                  { return PAREN_C; }
+<condition>","                  { return COMMA; }
 
 
 <condition>"["                  { return HOOK_O; }
@@ -946,7 +972,7 @@ bytes_fuzzy_id [\*A-Za-z_][\*A-Za-z0-9_]*
 
 
 
-<bytes,condition>[A-Za-z_][A-Za-z0-9_]* {
+<condition>[A-Za-z_][A-Za-z0-9_]* {
                                     yylval->sized_cstring.data = yytext;
                                     yylval->sized_cstring.len = yyleng;
                                     return NAME;
diff --git a/tests/analysis/scan/pyapi.py b/tests/analysis/scan/pyapi.py
index 4b066f3..ff3143f 100644
--- a/tests/analysis/scan/pyapi.py
+++ b/tests/analysis/scan/pyapi.py
@@ -28,7 +28,7 @@ class TestRostPythonAPI(ChrysalideTestCase):
             e = ScanExpression()
 
 
-    def testBooleanComparison(self):
+    def __TODO__testBooleanComparison(self):
         """Compare custom scan expressions."""
 
         class StrLenExpr(ScanExpression):
@@ -88,3 +88,26 @@ class TestRostPythonAPI(ChrysalideTestCase):
         transformed = mod.transform(source)
 
         self.assertEqual(source[::-1], transformed[0])
+
+
+    def testBytePatternModifiersAPI(self):
+        """Validate the API for pattern modifiers."""
+
+        mod = find_token_modifiers_for_name('plain')
+        self.assertIsNotNone(mod)
+
+        source = [ b'ABC', b'01234' ]
+        transformed = mod.transform(source)
+
+        self.assertEqual(len(source), len(transformed))
+        self.assertEqual(source[0], transformed[0])
+        self.assertEqual(source[1], transformed[1])
+
+
+        mod = find_token_modifiers_for_name('xor')
+        self.assertIsNotNone(mod)
+
+        source = [ b'ABC' ]
+        transformed = mod.transform(source, 0x20)
+
+        self.assertEqual(transformed[0], b'abc')
-- 
cgit v0.11.2-87-g4458