From 2424c52c4f3bc44ce5f36348442cfa103e0989c2 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Fri, 18 Aug 2023 02:07:39 +0200 Subject: Create some modifiers and handle match properties inside ROST. --- configure.ac | 3 + plugins/pychrysalide/analysis/scan/Makefile.am | 1 + plugins/pychrysalide/analysis/scan/context.c | 85 +++ plugins/pychrysalide/analysis/scan/core.c | 188 +++++++ plugins/pychrysalide/analysis/scan/core.h | 39 ++ plugins/pychrysalide/analysis/scan/module.c | 3 + plugins/pychrysalide/analysis/scan/options.c | 156 ++++++ .../analysis/scan/patterns/Makefile.am | 10 +- .../pychrysalide/analysis/scan/patterns/modifier.c | 324 ++++++++++++ .../pychrysalide/analysis/scan/patterns/modifier.h | 45 ++ .../analysis/scan/patterns/modifiers/Makefile.am | 17 + .../analysis/scan/patterns/modifiers/hex.c | 211 ++++++++ .../analysis/scan/patterns/modifiers/hex.h | 45 ++ .../analysis/scan/patterns/modifiers/list.c | 320 +++++++++++ .../analysis/scan/patterns/modifiers/list.h | 45 ++ .../analysis/scan/patterns/modifiers/module.c | 110 ++++ .../analysis/scan/patterns/modifiers/module.h | 42 ++ .../analysis/scan/patterns/modifiers/plain.c | 211 ++++++++ .../analysis/scan/patterns/modifiers/plain.h | 45 ++ .../analysis/scan/patterns/modifiers/rev.c | 211 ++++++++ .../analysis/scan/patterns/modifiers/rev.h | 45 ++ .../pychrysalide/analysis/scan/patterns/module.c | 5 + src/analysis/scan/context-int.h | 1 + src/analysis/scan/context.c | 93 ++-- src/analysis/scan/context.h | 11 +- src/analysis/scan/core.c | 162 ++++++ src/analysis/scan/core.h | 13 + src/analysis/scan/expr-int.h | 4 +- src/analysis/scan/expr.c | 20 +- src/analysis/scan/expr.h | 6 +- src/analysis/scan/exprs/Makefile.am | 4 + src/analysis/scan/exprs/counter.c | 22 +- src/analysis/scan/exprs/handler-int.h | 58 ++ src/analysis/scan/exprs/handler.c | 402 ++++++++++++++ src/analysis/scan/exprs/handler.h | 66 +++ src/analysis/scan/exprs/item-int.h | 58 ++ src/analysis/scan/exprs/item.c | 346 ++++++++++++ src/analysis/scan/exprs/item.h | 55 ++ src/analysis/scan/exprs/literal.c | 5 +- src/analysis/scan/exprs/set.c | 10 +- src/analysis/scan/grammar.y | 559 +++++++++++++++++--- src/analysis/scan/items/count.c | 2 +- src/analysis/scan/match-int.h | 10 +- src/analysis/scan/match.c | 92 +++- src/analysis/scan/match.h | 14 +- src/analysis/scan/matches/bytes-int.h | 6 +- src/analysis/scan/matches/bytes.c | 270 ++++++++-- src/analysis/scan/matches/bytes.h | 26 +- src/analysis/scan/matches/pending.c | 243 +++++++-- src/analysis/scan/matches/pending.h | 32 +- src/analysis/scan/options-int.h | 2 + src/analysis/scan/options.c | 86 +++ src/analysis/scan/options.h | 12 + src/analysis/scan/pattern-int.h | 13 +- src/analysis/scan/pattern.c | 111 +++- src/analysis/scan/pattern.h | 18 +- src/analysis/scan/patterns/Makefile.am | 7 +- src/analysis/scan/patterns/modifier-int.h | 59 +++ src/analysis/scan/patterns/modifier.c | 181 +++++++ src/analysis/scan/patterns/modifier.h | 62 +++ src/analysis/scan/patterns/modifiers/Makefile.am | 17 + src/analysis/scan/patterns/modifiers/hex.c | 252 +++++++++ src/analysis/scan/patterns/modifiers/hex.h | 58 ++ src/analysis/scan/patterns/modifiers/list-int.h | 54 ++ src/analysis/scan/patterns/modifiers/list.c | 405 ++++++++++++++ src/analysis/scan/patterns/modifiers/list.h | 68 +++ src/analysis/scan/patterns/modifiers/plain.c | 245 +++++++++ src/analysis/scan/patterns/modifiers/plain.h | 58 ++ src/analysis/scan/patterns/modifiers/rev.c | 247 +++++++++ src/analysis/scan/patterns/modifiers/rev.h | 58 ++ src/analysis/scan/patterns/token-int.h | 6 + src/analysis/scan/patterns/token.c | 180 ++++++- src/analysis/scan/patterns/token.h | 1 + src/analysis/scan/patterns/tokens/Makefile.am | 12 + src/analysis/scan/patterns/tokens/atom.c | 364 +++++++++++++ src/analysis/scan/patterns/tokens/atom.h | 68 +++ src/analysis/scan/patterns/tokens/hex-int.h | 56 ++ src/analysis/scan/patterns/tokens/hex.c | 457 ++++++++++++++++ src/analysis/scan/patterns/tokens/hex.h | 59 +++ src/analysis/scan/patterns/tokens/node-int.h | 58 ++ src/analysis/scan/patterns/tokens/node.c | 195 +++++++ src/analysis/scan/patterns/tokens/node.h | 77 +++ .../scan/patterns/tokens/nodes/Makefile.am | 16 + src/analysis/scan/patterns/tokens/nodes/hub-int.h | 51 ++ src/analysis/scan/patterns/tokens/nodes/hub.c | 150 ++++++ src/analysis/scan/patterns/tokens/nodes/hub.h | 55 ++ .../scan/patterns/tokens/nodes/plain-int.h | 64 +++ src/analysis/scan/patterns/tokens/nodes/plain.c | 582 +++++++++++++++++++++ src/analysis/scan/patterns/tokens/nodes/plain.h | 70 +++ src/analysis/scan/patterns/tokens/plain-int.h | 64 +++ src/analysis/scan/patterns/tokens/plain.c | 365 ++++++++----- src/analysis/scan/patterns/tokens/plain.h | 31 +- src/analysis/scan/rule-int.h | 6 +- src/analysis/scan/rule.c | 194 ++++++- src/analysis/scan/rule.h | 13 + src/analysis/scan/scanner.c | 116 ++++ src/analysis/scan/scanner.h | 13 + src/analysis/scan/tokens.l | 495 ++++++++++++++---- src/common/cpp.h | 2 + src/common/szstr.h | 6 + src/core/core.c | 8 +- src/rost.c | 26 +- tests/analysis/scan/pyapi.py | 33 ++ tests/analysis/scan/scanning_hex.py | 26 + 104 files changed, 10150 insertions(+), 533 deletions(-) create mode 100644 plugins/pychrysalide/analysis/scan/core.c create mode 100644 plugins/pychrysalide/analysis/scan/core.h create mode 100644 plugins/pychrysalide/analysis/scan/patterns/modifier.c create mode 100644 plugins/pychrysalide/analysis/scan/patterns/modifier.h create mode 100644 plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am create mode 100644 plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c create mode 100644 plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.h create mode 100644 plugins/pychrysalide/analysis/scan/patterns/modifiers/list.c create mode 100644 plugins/pychrysalide/analysis/scan/patterns/modifiers/list.h create mode 100644 plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c create mode 100644 plugins/pychrysalide/analysis/scan/patterns/modifiers/module.h create mode 100644 plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.c create mode 100644 plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.h create mode 100644 plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c create mode 100644 plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.h create mode 100644 src/analysis/scan/exprs/handler-int.h create mode 100644 src/analysis/scan/exprs/handler.c create mode 100644 src/analysis/scan/exprs/handler.h create mode 100644 src/analysis/scan/exprs/item-int.h create mode 100644 src/analysis/scan/exprs/item.c create mode 100644 src/analysis/scan/exprs/item.h create mode 100644 src/analysis/scan/patterns/modifier-int.h create mode 100644 src/analysis/scan/patterns/modifier.c create mode 100644 src/analysis/scan/patterns/modifier.h create mode 100644 src/analysis/scan/patterns/modifiers/Makefile.am create mode 100644 src/analysis/scan/patterns/modifiers/hex.c create mode 100644 src/analysis/scan/patterns/modifiers/hex.h create mode 100644 src/analysis/scan/patterns/modifiers/list-int.h create mode 100644 src/analysis/scan/patterns/modifiers/list.c create mode 100644 src/analysis/scan/patterns/modifiers/list.h create mode 100644 src/analysis/scan/patterns/modifiers/plain.c create mode 100644 src/analysis/scan/patterns/modifiers/plain.h create mode 100644 src/analysis/scan/patterns/modifiers/rev.c create mode 100644 src/analysis/scan/patterns/modifiers/rev.h create mode 100644 src/analysis/scan/patterns/tokens/atom.c create mode 100644 src/analysis/scan/patterns/tokens/atom.h create mode 100644 src/analysis/scan/patterns/tokens/hex-int.h create mode 100644 src/analysis/scan/patterns/tokens/hex.c create mode 100644 src/analysis/scan/patterns/tokens/hex.h create mode 100644 src/analysis/scan/patterns/tokens/node-int.h create mode 100644 src/analysis/scan/patterns/tokens/node.c create mode 100644 src/analysis/scan/patterns/tokens/node.h create mode 100644 src/analysis/scan/patterns/tokens/nodes/Makefile.am create mode 100644 src/analysis/scan/patterns/tokens/nodes/hub-int.h create mode 100644 src/analysis/scan/patterns/tokens/nodes/hub.c create mode 100644 src/analysis/scan/patterns/tokens/nodes/hub.h create mode 100644 src/analysis/scan/patterns/tokens/nodes/plain-int.h create mode 100644 src/analysis/scan/patterns/tokens/nodes/plain.c create mode 100644 src/analysis/scan/patterns/tokens/nodes/plain.h create mode 100644 src/analysis/scan/patterns/tokens/plain-int.h create mode 100644 tests/analysis/scan/scanning_hex.py diff --git a/configure.ac b/configure.ac index e9183a2..2f35cbe 100644 --- a/configure.ac +++ b/configure.ac @@ -684,6 +684,7 @@ AC_CONFIG_FILES([Makefile plugins/pychrysalide/analysis/scan/Makefile plugins/pychrysalide/analysis/scan/patterns/Makefile plugins/pychrysalide/analysis/scan/patterns/backends/Makefile + plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile plugins/pychrysalide/analysis/storage/Makefile plugins/pychrysalide/analysis/types/Makefile plugins/pychrysalide/arch/Makefile @@ -734,7 +735,9 @@ AC_CONFIG_FILES([Makefile src/analysis/scan/matches/Makefile src/analysis/scan/patterns/Makefile src/analysis/scan/patterns/backends/Makefile + src/analysis/scan/patterns/modifiers/Makefile src/analysis/scan/patterns/tokens/Makefile + src/analysis/scan/patterns/tokens/nodes/Makefile src/analysis/storage/Makefile src/analysis/types/Makefile src/arch/Makefile diff --git a/plugins/pychrysalide/analysis/scan/Makefile.am b/plugins/pychrysalide/analysis/scan/Makefile.am index 565ce82..32bf1e3 100644 --- a/plugins/pychrysalide/analysis/scan/Makefile.am +++ b/plugins/pychrysalide/analysis/scan/Makefile.am @@ -4,6 +4,7 @@ noinst_LTLIBRARIES = libpychrysaanalysisscan.la libpychrysaanalysisscan_la_SOURCES = \ constants.h constants.c \ context.h context.c \ + core.h core.c \ expr.h expr.c \ item.h item.c \ module.h module.c \ diff --git a/plugins/pychrysalide/analysis/scan/context.c b/plugins/pychrysalide/analysis/scan/context.c index 524ec46..8f29457 100644 --- a/plugins/pychrysalide/analysis/scan/context.c +++ b/plugins/pychrysalide/analysis/scan/context.c @@ -44,9 +44,15 @@ CREATE_DYN_CONSTRUCTOR(scan_context, G_TYPE_SCAN_CONTEXT); /* Initialise une instance sur la base du dérivé de GObject. */ static int py_scan_context_init(PyObject *, PyObject *, PyObject *); +/* Note que la phase d'analyse de contenu est terminée. */ +static PyObject *py_scan_context_mark_scan_as_done(PyObject *, PyObject *); + /* Indique si une correspondance globale a pu être établie. */ static PyObject *py_scan_context_has_match_for_rule(PyObject *, PyObject *); +/* Indique si la phase d'analyse de contenu est terminée. */ +static PyObject *py_scan_context_is_scan_done(PyObject *, void *); + /****************************************************************************** @@ -95,6 +101,43 @@ static int py_scan_context_init(PyObject *self, PyObject *args, PyObject *kwds) * Paramètres : self = classe représentant un format. * * args = arguments fournis à l'appel. * * * +* Description : Note que la phase d'analyse de contenu est terminée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_context_mark_scan_as_done(PyObject *self, PyObject *args) +{ + PyObject *result; /* Contexte de suivi à renvoyer*/ + GScanContext *context; /* Contexte de suivi d'analyse */ + +#define SCAN_CONTEXT_MARK_SCAN_AS_DONE_METHOD PYTHON_METHOD_DEF \ +( \ + mark_scan_as_done, "$self", \ + METH_NOARGS, py_scan_context, \ + "Note that the analysis operations are finished." \ +) + + context = G_SCAN_CONTEXT(pygobject_get(self)); + + g_scan_context_mark_scan_as_done(context); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format. * +* args = arguments fournis à l'appel. * +* * * Description : Indique si une correspondance globale a pu être établie. * * * * Retour : Bilan final d'une analyse (False par défaut). * @@ -140,6 +183,46 @@ static PyObject *py_scan_context_has_match_for_rule(PyObject *self, PyObject *ar /****************************************************************************** * * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique si la phase d'analyse de contenu est terminée. * +* * +* Retour : True si la phase de scan est terminée, False sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_context_is_scan_done(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GScanContext *context; /* Contexte de suivi d'analyse */ + bool status; /* Bilan de consultation */ + +#define SCAN_CONTEXT_IS_SCAN_DONE_ATTRIB PYTHON_IS_DEF_FULL \ +( \ + scan_done, py_scan_context, \ + "Tell if the analysis operations are finished.\n" \ + "\n" \ + "The result is a boolean: *True* if the scan is marked as" \ + " done, *False* otherwise." \ +) + + context = G_SCAN_CONTEXT(pygobject_get(self)); + + status = g_scan_context_is_scan_done(context); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : - * * * * Description : Fournit un accès à une définition de type à diffuser. * @@ -153,11 +236,13 @@ static PyObject *py_scan_context_has_match_for_rule(PyObject *self, PyObject *ar PyTypeObject *get_python_scan_context_type(void) { static PyMethodDef py_scan_context_methods[] = { + SCAN_CONTEXT_MARK_SCAN_AS_DONE_METHOD, SCAN_CONTEXT_HAS_MATCH_FOR_RULE_METHOD, { NULL } }; static PyGetSetDef py_scan_context_getseters[] = { + SCAN_CONTEXT_IS_SCAN_DONE_ATTRIB, { NULL } }; diff --git a/plugins/pychrysalide/analysis/scan/core.c b/plugins/pychrysalide/analysis/scan/core.c new file mode 100644 index 0000000..f609f7d --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/core.c @@ -0,0 +1,188 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.c - équivalent Python du fichier "analysis/scan/core.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 "core.h" + + +#include + + +#include + + +#include "patterns/modifier.h" +#include "../../access.h" +#include "../../helpers.h" + + + +/* #include */ + +/* #include */ +/* #include */ +/* #include */ + +/* #include "../core.h" */ + +/* #include "../arch/processor.h" */ + + + +/* Inscrit un modificateur dans la liste des disponibles. */ +static PyObject *py_scan_register_token_modifier(PyObject *, PyObject *); + +/* Fournit le modificateur correspondant à un nom. */ +static PyObject *py_scan_find_token_modifiers_for_name(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* args = arguments fournis à l'appel. * +* * +* Description : Inscrit un modificateur dans la liste des disponibles. * +* * +* Retour : Bilan des enregistrements effectués : True si nouveauté. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_register_token_modifier(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + PyObject *instance; /* Instance Python fournie */ + GScanTokenModifier *modifier; /* Version native */ + int ret; /* Bilan de lecture des args. */ + bool status; /* Bilan d'un enregistrement */ + +#define SCAN_REGISTER_TOKEN_MODIFIER_METHOD PYTHON_METHOD_DEF \ +( \ + register_token_modifier, "inst, /", \ + METH_VARARGS, py_scan, \ + "Register a token modifier for byte patterns to scan.\n" \ + "\n" \ + "This instance will be used as singleton and has to be a" \ + " subclass of pychrysalide.analysis.scan.patterns.TokenModifier." \ +) + + ret = PyArg_ParseTuple(args, "O!", get_python_scan_token_modifier_type(), &instance); + if (!ret) return NULL; + + modifier = G_SCAN_TOKEN_MODIFIER(pygobject_get(instance)); + + status = register_scan_token_modifier(modifier); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* args = arguments fournis à l'appel. * +* * +* Description : Fournit le modificateur correspondant à un nom. * +* * +* Retour : Instance du modificateur identifié ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_find_token_modifiers_for_name(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + const char *name; /* Nom d'appel à rechercher */ + int ret; /* Bilan de lecture des args. */ + GScanTokenModifier *modifier; /* Instance mise en place */ + +#define SCAN_FIND_TOKEN_MODIFIERS_FOR_NAME_METHOD PYTHON_METHOD_DEF \ +( \ + find_token_modifiers_for_name, "name, /", \ + METH_VARARGS, py_scan, \ + "Provide the registered instance of a pattern modifier linked" \ + " to a given *name* provided as a key string.\n" \ + "\n" \ + "The returned instance is an object inherited from" \ + " pychrysalide.analysis.scan.patterns.TokenModifier or *None*" \ + " if no instance was found for the provided name." \ +) + + ret = PyArg_ParseTuple(args, "s", &name); + if (!ret) return NULL; + + modifier = find_scan_token_modifiers_for_name(name); + + if (modifier != NULL) + { + result = pygobject_new(G_OBJECT(modifier)); + g_object_unref(G_OBJECT(modifier)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Définit une extension du module 'scan' à compléter. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_scan_module_with_core_methods(void) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Module à recompléter */ + + static PyMethodDef py_core_methods[] = { + SCAN_REGISTER_TOKEN_MODIFIER_METHOD, + SCAN_FIND_TOKEN_MODIFIERS_FOR_NAME_METHOD, + { NULL } + }; + + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + result = register_python_module_methods(module, py_core_methods); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/core.h b/plugins/pychrysalide/analysis/scan/core.h new file mode 100644 index 0000000..e283f91 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/core.h @@ -0,0 +1,39 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.h - prototypes pour l'équivalent Python du fichier "analysis/scan/core.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_CORE_CORE_H +#define _PLUGINS_PYCHRYSALIDE_CORE_CORE_H + + +#include +#include + + + +/* Définit une extension du module 'scan' à compléter. */ +bool populate_scan_module_with_core_methods(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_CORE_CORE_H */ diff --git a/plugins/pychrysalide/analysis/scan/module.c b/plugins/pychrysalide/analysis/scan/module.c index d56e44a..ff19d92 100644 --- a/plugins/pychrysalide/analysis/scan/module.c +++ b/plugins/pychrysalide/analysis/scan/module.c @@ -29,6 +29,7 @@ #include "context.h" +#include "core.h" #include "expr.h" #include "item.h" #include "options.h" @@ -110,6 +111,8 @@ bool populate_analysis_scan_module(void) if (result) result = ensure_python_scan_options_is_registered(); if (result) result = ensure_python_scan_namespace_is_registered(); + if (result) result = populate_scan_module_with_core_methods(); + if (result) result = populate_analysis_scan_patterns_module(); assert(result); diff --git a/plugins/pychrysalide/analysis/scan/options.c b/plugins/pychrysalide/analysis/scan/options.c index 30c3f18..84c1784 100644 --- a/plugins/pychrysalide/analysis/scan/options.c +++ b/plugins/pychrysalide/analysis/scan/options.c @@ -46,6 +46,18 @@ static PyObject *py_scan_options_get_backend_for_data(PyObject *, void *); /* Sélectionne un type de moteur d'analyse pour données brutes. */ static int py_scan_options_set_backend_for_data(PyObject *, PyObject *, void *); +/* Impose le format JSON comme type de sortie. */ +static PyObject *py_scan_options_get_print_json(PyObject *, void *); + +/* Mémorise le format JSON comme type de sortie. */ +static int py_scan_options_set_print_json(PyObject *, PyObject *, void *); + +/* Indique un besoin d'affichage des correspondances finales. */ +static PyObject *py_scan_options_get_print_strings(PyObject *, void *); + +/* Mémorise un besoin d'affichage des correspondances finales. */ +static int py_scan_options_set_print_strings(PyObject *, PyObject *, void *); + /* Indique un besoin de statistiques en fin de compilation. */ static PyObject *py_scan_options_get_print_stats(PyObject *, void *); @@ -161,6 +173,148 @@ static int py_scan_options_set_backend_for_data(PyObject *self, PyObject *value, * Paramètres : self = classe représentant un format Axml. * * closure = adresse non utilisée ici. * * * +* Description : Impose le format JSON comme type de sortie. * +* * +* Retour : Etat de l'option visée à conservé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_options_get_print_json(PyObject *self, void *closure) +{ + PyObject *result; /* Liste éventuelle à renvoyer */ + GScanOptions *options; /* Version native */ + bool state; /* Etat courant à consulter */ + +#define SCAN_OPTIONS_PRINT_JSON_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + print_json, py_scan_options, \ + "Define if the process summary is output into a JSON" \ + " format at the end of the scan or not." \ +) + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + state = g_scan_options_get_print_json(options); + + result = state ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = adresse non utilisée ici. * +* * +* Description : Mémorise le format JSON comme type de sortie. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_options_set_print_json(PyObject *self, PyObject *value, void *closure) +{ + bool state; /* Nouvel état à définir */ + GScanOptions *options; /* Version native */ + + if (value != Py_True && value != Py_False) + return -1; + + state = (value == Py_True); + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + g_scan_options_set_print_json(options, state); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format Axml. * +* closure = adresse non utilisée ici. * +* * +* Description : Indique un besoin d'affichage des correspondances finales. * +* * +* Retour : Etat de l'option visée à conservé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_options_get_print_strings(PyObject *self, void *closure) +{ + PyObject *result; /* Liste éventuelle à renvoyer */ + GScanOptions *options; /* Version native */ + bool state; /* Etat courant à consulter */ + +#define SCAN_OPTIONS_PRINT_STRINGS_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + print_strings, py_scan_options, \ + "Define if the matching patterns are printed with found" \ + " offset at the end of the scan or not." \ +) + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + state = g_scan_options_get_print_strings(options); + + result = state ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = adresse non utilisée ici. * +* * +* Description : Mémorise un besoin d'affichage des correspondances finales. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_options_set_print_strings(PyObject *self, PyObject *value, void *closure) +{ + bool state; /* Nouvel état à définir */ + GScanOptions *options; /* Version native */ + + if (value != Py_True && value != Py_False) + return -1; + + state = (value == Py_True); + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + g_scan_options_set_print_strings(options, state); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format Axml. * +* closure = adresse non utilisée ici. * +* * * Description : Indique un besoin de statistiques en fin de compilation. * * * * Retour : Etat de l'option visée à conservé. * @@ -246,6 +400,8 @@ PyTypeObject *get_python_scan_options_type(void) static PyGetSetDef py_scan_options_getseters[] = { SCAN_OPTIONS_BACKEND_FOR_DATA_ATTRIB, + SCAN_OPTIONS_PRINT_JSON_ATTRIB, + SCAN_OPTIONS_PRINT_STRINGS_ATTRIB, SCAN_OPTIONS_PRINT_STATS_ATTRIB, { NULL } }; diff --git a/plugins/pychrysalide/analysis/scan/patterns/Makefile.am b/plugins/pychrysalide/analysis/scan/patterns/Makefile.am index 612f34b..dd26fa5 100644 --- a/plugins/pychrysalide/analysis/scan/patterns/Makefile.am +++ b/plugins/pychrysalide/analysis/scan/patterns/Makefile.am @@ -3,13 +3,15 @@ noinst_LTLIBRARIES = libpychrysaanalysisscanpatterns.la libpychrysaanalysisscanpatterns_la_SOURCES = \ backend.h backend.c \ + modifier.h modifier.c \ module.h module.c libpychrysaanalysisscanpatterns_la_LIBADD = \ - backends/libpychrysaanalysisscanpatternsbackends.la + backends/libpychrysaanalysisscanpatternsbackends.la \ + modifiers/libpychrysaanalysisscanpatternsmodifiers.la -libpychrysaanalysisscanpatterns_la_CFLAGS = $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) \ - -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT +libpychrysaanalysisscanpatterns_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + $(TOOLKIT_CFLAGS) -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) @@ -17,4 +19,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaanalysisscanpatterns_la_SOURCES:%c=) -SUBDIRS = backends +SUBDIRS = backends modifiers diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifier.c b/plugins/pychrysalide/analysis/scan/patterns/modifier.c new file mode 100644 index 0000000..4cae011 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifier.c @@ -0,0 +1,324 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * modifier.c - équivalent Python du fichier "analysis/scan/modifier.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 "modifier.h" + + +#include + + +#include + + +#include "../../../access.h" +#include "../../../helpers.h" + + + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(scan_token_modifier, G_TYPE_SCAN_TOKEN_MODIFIER, NULL); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_token_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_token_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_TOKEN_MODIFIER_DOC \ + "An *TokenModifier* object is the root class of all modifiers" \ + " for byte patterns." + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = tampon de données à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Transforme une séquence d'octets pour motif de recherche. * +* * +* Retour : Liste des nouvelle(s) séquence(s) d'octets obtenue(s). * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_token_modifier_transform(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + const char *data; /* Séquence d'octets à traiter */ + 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é */ + GScanTokenModifier *modifier; /* Version native de l'instance*/ + sized_binary_t *dest; /* Liste des nouvelles chaînes */ + size_t count; /* Taille de cette liste */ + bool status; /* Bilan de l'opération */ + size_t i; /* Boucle de parcours */ + +#define SCAN_TOKEN_MODIFIER_TRANSFORM_METHOD PYTHON_METHOD_DEF \ +( \ + transform, "$self, data", \ + METH_VARARGS, py_scan_token_modifier, \ + "Transform data from a byte pattern for an incoming scan.\n" \ + "\n" \ + "The data has to be provided as bytes.\n" \ + "\n" \ + "The method returns a tuple of transformed data as bytes, or" \ + " *None* in case of error." \ +) + + ret = PyArg_ParseTuple(args, "s#", &data, &len); + if (!ret) return NULL; + + src.data = (char *)data; + src.len = len; + + modifier = G_SCAN_TOKEN_MODIFIER(pygobject_get(self)); + + status = g_scan_token_modifier_transform(modifier, &src, &dest, &count); + + if (status) + { + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + { + PyTuple_SetItem(result, i, PyBytes_FromStringAndSize(dest[i].data, dest[i].len)); + exit_szstr(&dest[i]); + } + + free(dest); + + } + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un composant nommé à manipuler.* +* closure = non utilisé ici. * +* * +* Description : Fournit le désignation associée à un composant nommé. * +* * +* Retour : Description courante. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_token_modifier_get_name(PyObject *self, void *closure) +{ + PyObject *result; /* Décompte à retourner */ + GScanTokenModifier *modifier; /* Version native */ + char *name; /* Désignation à convertir */ + +#define SCAN_TOKEN_MODIFIER_NAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + name, py_scan_token_modifier, \ + "Call name for the modifier.\n" \ + "\n" \ + "The result is a string." \ +) + + modifier = G_SCAN_TOKEN_MODIFIER(pygobject_get(self)); + + name = g_scan_token_modifier_get_name(modifier); + + if (name == NULL) + { + result = Py_None; + Py_INCREF(result); + } + else + { + result = PyUnicode_FromString(name); + free(name); + } + + return result; + +} + + +/****************************************************************************** +* * +* 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_token_modifier_type(void) +{ + static PyMethodDef py_scan_token_modifier_methods[] = { + SCAN_TOKEN_MODIFIER_TRANSFORM_METHOD, + { NULL } + }; + + static PyGetSetDef py_scan_token_modifier_getseters[] = { + SCAN_TOKEN_MODIFIER_NAME_ATTRIB, + { NULL } + }; + + static PyTypeObject py_scan_token_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.TokenModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = SCAN_TOKEN_MODIFIER_DOC, + + .tp_methods = py_scan_token_modifier_methods, + .tp_getset = py_scan_token_modifier_getseters, + + .tp_init = py_scan_token_modifier_init, + .tp_new = py_scan_token_modifier_new, + + }; + + return &py_scan_token_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....TokenModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_token_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'TokenModifier' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_token_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_TOKEN_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 de séquence d'octets. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_token_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_token_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 token modifier"); + break; + + case 1: + *((GScanTokenModifier **)dst) = G_SCAN_TOKEN_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifier.h b/plugins/pychrysalide/analysis/scan/patterns/modifier.h new file mode 100644 index 0000000..770b2c1 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifier.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * modifier.h - prototypes pour l'équivalent Python du fichier "analysis/scan/modifier.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_MODIFIER_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODIFIER_H + + +#include +#include + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_token_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.TokenModifier'. */ +bool ensure_python_scan_token_modifier_is_registered(void); + +/* Tente de convertir en transformation de séquence d'octets. */ +int convert_to_scan_token_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODIFIER_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am b/plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am new file mode 100644 index 0000000..baf7ed5 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am @@ -0,0 +1,17 @@ + +noinst_LTLIBRARIES = libpychrysaanalysisscanpatternsmodifiers.la + +libpychrysaanalysisscanpatternsmodifiers_la_SOURCES = \ + hex.h hex.c \ + list.h list.c \ + module.h module.c \ + plain.h plain.c \ + rev.h rev.c + +libpychrysaanalysisscanpatternsmodifiers_la_CFLAGS = $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libpychrysaanalysisscanpatternsmodifiers_la_SOURCES:%c=) diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c new file mode 100644 index 0000000..d0d1e1f --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c @@ -0,0 +1,211 @@ + +/* 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 "hex.h" + + +#include + + +#include +#include + + +#include "../modifier.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_hex_modifier, G_TYPE_SCAN_HEX_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_hex_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_hex_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_HEX_MODIFIER_DOC \ + "The *HexModifier* class transforms a byte pattern into its" \ + " corresponding byte sequence in lower case." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " HexModifier()" + + /* 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_hex_modifier_type(void) +{ + static PyMethodDef py_scan_hex_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_hex_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_hex_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.HexModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_HEX_MODIFIER_DOC, + + .tp_methods = py_scan_hex_modifier_methods, + .tp_getset = py_scan_hex_modifier_getseters, + + .tp_init = py_scan_hex_modifier_init, + .tp_new = py_scan_hex_modifier_new, + + }; + + return &py_scan_hex_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....HexModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_hex_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'HexModifier' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_hex_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_HEX_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 transmission d'octets à l'identique. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_hex_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_hex_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 hex modifier"); + break; + + case 1: + *((GScanHexModifier **)dst) = G_SCAN_HEX_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.h new file mode 100644 index 0000000..5d70a01 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hex.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/hex.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_HEX_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_HEX_H + + +#include +#include + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_hex_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.HexModifier'. */ +bool ensure_python_scan_hex_modifier_is_registered(void); + +/* Tente de convertir en transmission d'octets à l'identique. */ +int convert_to_scan_hex_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_HEX_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.c new file mode 100644 index 0000000..7c77d63 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.c @@ -0,0 +1,320 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * list.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/list.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 "list.h" + + +#include + + +#include +#include + + +#include "../modifier.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_modifier_list, G_TYPE_SCAN_MODIFIER_LIST); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_modifier_list_init(PyObject *, PyObject *, PyObject *); + +/* Intègre un nouveau transformateur dans une liste. */ +static PyObject *py_scan_modifier_list_add(PyObject *, PyObject *); + +/* Fournit les transformateurs associés à la liste. */ +static PyObject *py_scan_modifier_list_get_modifiers(PyObject *, void *); + + + +/****************************************************************************** +* * +* 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_modifier_list_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_MODIFIER_LIST_DOC \ + "The *ModifierList* class is a special modifier which groups a list of" \ + " modifiers for byte patterns." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ModifierList()" \ + "\n" \ + "The keyword for such a modifier is *(list)*." + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = projet d'étude à manipuler. * +* args = arguments accompagnant l'appel. * +* * +* Description : Intègre un nouveau transformateur dans une liste. * +* * +* Retour : Bilan de l'ajout : False si un élément similaire est déjà là.* +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_modifier_list_add(PyObject *self, PyObject *args) +{ + PyObject *result; /* Absence de retour Python */ + GScanTokenModifier *modifier; /* Modificateur à intégrer */ + int ret; /* Bilan de lecture des args. */ + GScanModifierList *list; /* Version GLib du type */ + bool status; /* Bilan de l'opération */ + +#define SCAN_MODIFIER_LIST_ADD_METHOD PYTHON_METHOD_DEF \ +( \ + add, "$self, modifier, /", \ + METH_VARARGS, py_scan_modifier_list, \ + "Add an extra modifier to the list.\n" \ + "\n" \ + "This *modifier* parameter has to be a" \ + " pychrysalide.analysis.scan.patterns.TokenModifier instance." \ + "\n" \ + "The function returns *True* if the provided modifier did not already" \ + " exist in the list, *False* otherwise." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_scan_token_modifier, &modifier); + if (!ret) return NULL; + + list = G_SCAN_MODIFIER_LIST(pygobject_get(self)); + + status = g_scan_modifier_list_add(list, modifier); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit les transformateurs associés à la liste. * +* * +* Retour : Liste de modificateurs de séquence d'octets. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_modifier_list_get_modifiers(PyObject *self, void *closure) +{ + PyObject *result; /* Résultat à retourner */ + GScanModifierList *list; /* Version GLib du type */ + size_t count; /* Nombre de transformateurs */ + size_t i; /* Boucle de parcours */ + GScanTokenModifier *modifier; /* Modificateur de la liste */ + +#define SCAN_MODIFIER_LIST_MODIFIERS_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + modifiers, py_scan_modifier_list, \ + "List of all modifiers contained in a list.\n" \ + "\n" \ + "The returned value is a tuple of pychrysalide.analysis.scan.patterns.TokenModifier" \ + " instances." \ +) + + list = G_SCAN_MODIFIER_LIST(pygobject_get(self)); + + count = g_scan_modifier_list_count(list); + + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + { + modifier = g_scan_modifier_list_get(list, i); + + PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(modifier))); + + g_object_unref(modifier); + + } + + return result; + +} + +/****************************************************************************** +* * +* 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_modifier_list_type(void) +{ + static PyMethodDef py_scan_modifier_list_methods[] = { + SCAN_MODIFIER_LIST_ADD_METHOD, + { NULL } + }; + + static PyGetSetDef py_scan_modifier_list_getseters[] = { + SCAN_MODIFIER_LIST_MODIFIERS_ATTRIB, + { NULL } + }; + + static PyTypeObject py_scan_modifier_list_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.ModifierList", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_MODIFIER_LIST_DOC, + + .tp_methods = py_scan_modifier_list_methods, + .tp_getset = py_scan_modifier_list_getseters, + + .tp_init = py_scan_modifier_list_init, + .tp_new = py_scan_modifier_list_new, + + }; + + return &py_scan_modifier_list_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....ModifierList'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_modifier_list_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ModifierList' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_modifier_list_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_MODIFIER_LIST, 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 liste de transormations d'octets. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_modifier_list(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_modifier_list_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 modifier list"); + break; + + case 1: + *((GScanModifierList **)dst) = G_SCAN_MODIFIER_LIST(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.h new file mode 100644 index 0000000..133de8d --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * list.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/list.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_LIST_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_LIST_H + + +#include +#include + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_modifier_list_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.ModifierList'. */ +bool ensure_python_scan_modifier_list_is_registered(void); + +/* Tente de convertir en liste de transormations d'octets. */ +int convert_to_scan_modifier_list(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_LIST_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c new file mode 100644 index 0000000..1e9bda7 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c @@ -0,0 +1,110 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire modifiers en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include + + +#include "hex.h" +#include "list.h" +#include "plain.h" +#include "rev.h" +#include "../../../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Ajoute le module 'analysis....modifiers' à un module Python. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_analysis_scan_patterns_modifiers_module(PyObject *super) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_DOC \ + "This module provide all the features useful for scanning" \ + " binary contents." + + static PyModuleDef py_chrysalide_analysis_scan_patterns_modifiers_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.analysis.scan.patterns.modifiers", + .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_DOC, + + .m_size = -1, + + }; + + module = build_python_module(super, &py_chrysalide_analysis_scan_patterns_modifiers_module); + + result = (module != NULL); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'analysis...patterns.modifiers'.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_analysis_scan_patterns_modifiers_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_scan_hex_modifier_is_registered(); + 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(); + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.h new file mode 100644 index 0000000..8094efc --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire modifiers en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 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_MODULE_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_H + + +#include +#include + + + +/* Ajoute le module 'analysis.scan.patterns.modifiers' à un module Python. */ +bool add_analysis_scan_patterns_modifiers_module(PyObject *); + +/* Intègre les objets du module 'analysis.scan.patterns.modifiers'. */ +bool populate_analysis_scan_patterns_modifiers_module(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.c new file mode 100644 index 0000000..7a260c1 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.c @@ -0,0 +1,211 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/plain.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 "plain.h" + + +#include + + +#include +#include + + +#include "../modifier.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_plain_modifier, G_TYPE_SCAN_PLAIN_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_plain_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_plain_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_PLAIN_MODIFIER_DOC \ + "The *PlainModifier* class provide an transmision of a byte pattern" \ + " without any modification." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " PlainModifier()" + + /* 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_plain_modifier_type(void) +{ + static PyMethodDef py_scan_plain_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_plain_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_plain_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.PlainModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_PLAIN_MODIFIER_DOC, + + .tp_methods = py_scan_plain_modifier_methods, + .tp_getset = py_scan_plain_modifier_getseters, + + .tp_init = py_scan_plain_modifier_init, + .tp_new = py_scan_plain_modifier_new, + + }; + + return &py_scan_plain_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....PlainModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_plain_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'PlainModifier' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_plain_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_PLAIN_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 transmission d'octets à l'identique. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_plain_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_plain_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 plain modifier"); + break; + + case 1: + *((GScanPlainModifier **)dst) = G_SCAN_PLAIN_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.h new file mode 100644 index 0000000..03949d8 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/plain.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_PLAIN_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_PLAIN_H + + +#include +#include + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_plain_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.PlainModifier'. */ +bool ensure_python_scan_plain_modifier_is_registered(void); + +/* Tente de convertir en transmission d'octets à l'identique. */ +int convert_to_scan_plain_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_PLAIN_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c new file mode 100644 index 0000000..6ee350c --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c @@ -0,0 +1,211 @@ + +/* 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 "rev.h" + + +#include + + +#include +#include + + +#include "../modifier.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_reverse_modifier, G_TYPE_SCAN_REVERSE_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_reverse_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_reverse_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_HEX_MODIFIER_DOC \ + "The *ReverseModifier* class transforms a byte pattern by reversing" \ + " the order of each bytes." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ReverseModifier()" + + /* 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_reverse_modifier_type(void) +{ + static PyMethodDef py_scan_reverse_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_reverse_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_reverse_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.ReverseModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_HEX_MODIFIER_DOC, + + .tp_methods = py_scan_reverse_modifier_methods, + .tp_getset = py_scan_reverse_modifier_getseters, + + .tp_init = py_scan_reverse_modifier_init, + .tp_new = py_scan_reverse_modifier_new, + + }; + + return &py_scan_reverse_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....ReverseModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_reverse_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'HexModifier' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_reverse_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_REVERSE_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_reverse_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_reverse_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 reverse modifier"); + break; + + case 1: + *((GScanReverseModifier **)dst) = G_SCAN_REVERSE_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.h new file mode 100644 index 0000000..fe10e1e --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * rev.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/rev.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_REV_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_REV_H + + +#include +#include + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_reverse_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.ReverseModifier'. */ +bool ensure_python_scan_reverse_modifier_is_registered(void); + +/* Tente de convertir en transformation d'octets par inverse. */ +int convert_to_scan_reverse_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_REV_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/module.c b/plugins/pychrysalide/analysis/scan/patterns/module.c index f8db49e..123b23a 100644 --- a/plugins/pychrysalide/analysis/scan/patterns/module.c +++ b/plugins/pychrysalide/analysis/scan/patterns/module.c @@ -29,7 +29,9 @@ #include "backend.h" +#include "modifier.h" #include "backends/module.h" +#include "modifiers/module.h" #include "../../../helpers.h" @@ -71,6 +73,7 @@ bool add_analysis_scan_patterns_module(PyObject *super) result = (module != NULL); if (result) result = add_analysis_scan_patterns_backends_module(module); + if (result) result = add_analysis_scan_patterns_modifiers_module(module); if (!result) Py_XDECREF(module); @@ -99,8 +102,10 @@ bool populate_analysis_scan_patterns_module(void) result = true; if (result) result = ensure_python_engine_backend_is_registered(); + if (result) result = ensure_python_scan_token_modifier_is_registered(); if (result) result = populate_analysis_scan_patterns_backends_module(); + if (result) result = populate_analysis_scan_patterns_modifiers_module(); assert(result); diff --git a/src/analysis/scan/context-int.h b/src/analysis/scan/context-int.h index 3a971b8..8a5fbaf 100644 --- a/src/analysis/scan/context-int.h +++ b/src/analysis/scan/context-int.h @@ -74,6 +74,7 @@ struct _GScanContext GScanOptions *options; /* Options d'analyses */ GBinContent *content; /* Contenu binaire traité */ + bool scan_done; /* Phase d'analyse terminée ? */ patid_t next_patid; /* Prochain indice utilisable */ diff --git a/src/analysis/scan/context.c b/src/analysis/scan/context.c index f108e93..a3be86b 100644 --- a/src/analysis/scan/context.c +++ b/src/analysis/scan/context.c @@ -55,7 +55,7 @@ static void add_match_to_full_match_tracker(full_match_tracker_t *, GScanMatch * - +/* --------------------- MEMORISATION DE PROGRESSIONS D'ANALYSE --------------------- */ /* Initialise la classe des contextes de suivi d'analyses. */ @@ -72,10 +72,6 @@ static void g_scan_context_finalize(GScanContext *); - - - - /* ---------------------------------------------------------------------------------- */ /* ADMINISTRATION DES CORRESPONDANCES TOTALES */ /* ---------------------------------------------------------------------------------- */ @@ -191,10 +187,9 @@ static void add_match_to_full_match_tracker(full_match_tracker_t *tracker, GScan - - - - +/* ---------------------------------------------------------------------------------- */ +/* MEMORISATION DE PROGRESSIONS D'ANALYSE */ +/* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour un contexte de suivi d'analyse. */ @@ -242,6 +237,7 @@ static void g_scan_context_init(GScanContext *context) context->options = NULL; context->content = NULL; + context->scan_done = false; context->next_patid = 0; @@ -378,7 +374,7 @@ GScanContext *g_scan_context_new(GScanOptions *options) * * ******************************************************************************/ -GScanOptions *g_scan_context_get_options(GScanContext *context) +GScanOptions *g_scan_context_get_options(const GScanContext *context) { GScanOptions *result; /* Ensemble à retourner */ @@ -467,6 +463,48 @@ GBinContent *g_scan_context_get_content(const GScanContext *context) /****************************************************************************** * * +* Paramètres : context = instance à consulter. * +* * +* Description : Indique si la phase d'analyse de contenu est terminée. * +* * +* Retour : true si la phase de scan est terminée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_context_is_scan_done(const GScanContext *context) +{ + bool result; /* Statut à retourner */ + + result = context->scan_done; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : context = instance à mettre à jour. * +* * +* Description : Note que la phase d'analyse de contenu est terminée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_context_mark_scan_as_done(GScanContext *context) +{ + context->scan_done = true; + +} + + +/****************************************************************************** +* * * Paramètres : context = instance à mettre à jour. * * id = identifiant du motif trouvé. * * offset = localisation du motif au sein d'un contenu. * @@ -615,41 +653,6 @@ const GScanMatch **g_scan_context_get_full_matches(const GScanContext *context, /****************************************************************************** * * -* Paramètres : context = mémoire de résultats d'analyse à consulter. * -* * -* Description : Affiche les correspondances identifiées. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_scan_context_display(GScanContext *context) -{ - size_t i; /* Boucle de parcours */ - const rule_condition_t *cond; /* Conditions de orrespondance */ - - /* - FIXME : ordre - for (i = 0; i < context->full_used; i++) - g_scan_match_display(context->full_matches[i]); - */ - - for (i = 0; i < context->cond_count; i++) - { - cond = &context->conditions[i]; - - if (g_scan_context_has_match_for_rule(context, cond->name)) - fprintf(stderr, "Rule '%s' has matched!\n", cond->name); - - } - -} - - -/****************************************************************************** -* * * Paramètres : context = mémoire de résultats d'analyse à compléter. * * name = désignation de la règle ciblée. * * expr = expression de condition à réduire. * diff --git a/src/analysis/scan/context.h b/src/analysis/scan/context.h index 563a53e..ff6b373 100644 --- a/src/analysis/scan/context.h +++ b/src/analysis/scan/context.h @@ -66,7 +66,7 @@ GType g_scan_context_get_type(void); GScanContext *g_scan_context_new(GScanOptions *); /* Fournit l'ensemble des options à respecter pour les analyses. */ -GScanOptions *g_scan_context_get_options(GScanContext *); +GScanOptions *g_scan_context_get_options(const GScanContext *); /* Fournit un identifiant unique pour un motif recherché. */ patid_t g_scan_context_get_new_pattern_id(GScanContext *); @@ -77,6 +77,12 @@ void g_scan_context_set_content(GScanContext *, GBinContent *); /* Fournit une référence au contenu principal analysé. */ GBinContent *g_scan_context_get_content(const GScanContext *); +/* Indique si la phase d'analyse de contenu est terminée. */ +bool g_scan_context_is_scan_done(const GScanContext *); + +/* Note que la phase d'analyse de contenu est terminée. */ +void g_scan_context_mark_scan_as_done(GScanContext *); + /* Enregistre une correspondance partielle dans un contenu. */ void g_scan_context_register_atom_match(GScanContext *, patid_t, phys_t); @@ -89,9 +95,6 @@ void g_scan_context_register_full_match(GScanContext *, GScanMatch *); /* Fournit la liste de toutes les correspondances d'un motif. */ const GScanMatch **g_scan_context_get_full_matches(const GScanContext *, const GSearchPattern *, size_t *); -/* Affiche les correspondances identifiées. */ -void g_scan_context_display(GScanContext *); - /* Intègre une condition de correspondance pour règle. */ bool g_scan_context_set_rule_condition(GScanContext *, const char *, const GScanExpression *); diff --git a/src/analysis/scan/core.c b/src/analysis/scan/core.c index d940ab5..d102d58 100644 --- a/src/analysis/scan/core.c +++ b/src/analysis/scan/core.c @@ -25,6 +25,8 @@ #include +#include +#include #include "items/count.h" @@ -38,8 +40,168 @@ #endif #include "items/time/make.h" #include "items/time/now.h" +#include "patterns/modifiers/hex.h" +#include "patterns/modifiers/plain.h" +#include "patterns/modifiers/rev.h" +/* Liste des modificateurs disponibles */ + +typedef struct _available_modifier_t +{ + char *name; /* Désignation humaine */ + GScanTokenModifier *instance; /* Mécanisme correspondant */ + +} available_modifier_t; + +static available_modifier_t *__modifiers = NULL; +static size_t __modifiers_count = 0; + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à rendre disponible. * +* * +* Description : Inscrit un modificateur dans la liste des disponibles. * +* * +* Retour : Bilan des enregistrements effectués : true si nouveauté. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_scan_token_modifier(GScanTokenModifier *modifier) +{ + bool result; /* Bilan à retourner */ + char *name; /* Nom donné au modificateur */ + GScanTokenModifier *found; /* Alternative présente */ + available_modifier_t *last; /* Emplacement disponible */ + + name = g_scan_token_modifier_get_name(modifier); + + found = find_scan_token_modifiers_for_name(name); + + result = (found == NULL); + + if (!result) + free(name); + + else + { + __modifiers_count++; + __modifiers = realloc(__modifiers, __modifiers_count * sizeof(available_modifier_t)); + + last = &__modifiers[__modifiers_count - 1]; + + last->name = name; + last->instance = modifier; + + g_object_ref(G_OBJECT(modifier)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Charge tous les modificateurs de base. * +* * +* Retour : Bilan des opérations d'enregistrement. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool load_all_known_scan_token_modifiers(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + +#define REGISTER_SCAN_MODIFIER(m) \ + ({ \ + bool __status; \ + __status = register_scan_token_modifier(m); \ + g_object_unref(G_OBJECT(m)); \ + __status; \ + }) + + 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()); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Décharge tous les modificateurs inscrits. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void unload_all_scan_token_modifiers(void) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < __modifiers_count; i++) + g_object_unref(G_OBJECT(__modifiers[i].instance)); + + if (__modifiers != NULL) + free(__modifiers); + +} + + +/****************************************************************************** +* * +* Paramètres : name = désignation du modificateur recherché. * +* * +* Description : Fournit le modificateur correspondant à un nom. * +* * +* Retour : Instance du modificateur identifié ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenModifier *find_scan_token_modifiers_for_name(const char *name) +{ + GScanTokenModifier *result; /* Instance à renvoyer */ + size_t i; /* Boucle de parcours */ + available_modifier_t *registered; /* Infos d'enregistrement */ + + result = NULL; + + for (i = 0; i < __modifiers_count; i++) + { + registered = __modifiers + i; + + if (strcmp(registered->name, name) == 0) + { + result = registered->instance; + g_object_ref(G_OBJECT(result)); + break; + } + + } + + return result; + +} + /****************************************************************************** * * diff --git a/src/analysis/scan/core.h b/src/analysis/scan/core.h index 21d6e7c..86a47da 100644 --- a/src/analysis/scan/core.h +++ b/src/analysis/scan/core.h @@ -26,9 +26,22 @@ #include "space.h" +#include "patterns/modifier.h" +/* Inscrit un modificateur dans la liste des disponibles. */ +bool register_scan_token_modifier(GScanTokenModifier *); + +/* Charge tous les modificateurs de base. */ +bool load_all_known_scan_token_modifiers(void); + +/* Décharge tous les modificateurs inscrits. */ +void unload_all_scan_token_modifiers(void); + +/* Fournit le modificateur correspondant à un nom. */ +GScanTokenModifier *find_scan_token_modifiers_for_name(const char *); + /* Inscrit les principales fonctions dans l'espace racine. */ bool populate_main_scan_namespace(GScanNamespace *); diff --git a/src/analysis/scan/expr-int.h b/src/analysis/scan/expr-int.h index 48668b5..30a32d0 100644 --- a/src/analysis/scan/expr-int.h +++ b/src/analysis/scan/expr-int.h @@ -54,10 +54,10 @@ typedef ScanReductionState (* reduce_expr_fc) (GScanExpression *, GScanContext * typedef bool (* reduce_expr_to_bool_fc) (GScanExpression *, GScanContext *, GScanScope *, GScanExpression **); /* Dénombre les éléments portés par une expression. */ -typedef bool (* count_scan_expr_fc) (const GScanExpression *, size_t *); +typedef bool (* count_scan_expr_fc) (const GScanExpression *, GScanContext *, size_t *); /* Fournit un élément donné issu d'un ensemble constitué. */ -typedef bool (* get_scan_expr_fc) (const GScanExpression *, size_t, GScanExpression **); +typedef bool (* get_scan_expr_fc) (const GScanExpression *, size_t, GScanContext *, GScanExpression **); /* Réalise l'intersection entre deux ensembles. */ typedef GScanExpression * (* intersect_scan_expr_fc) (GScanExpression *, const GScanExpression *, GScanContext *, GScanScope *); diff --git a/src/analysis/scan/expr.c b/src/analysis/scan/expr.c index 808b14f..2b00544 100644 --- a/src/analysis/scan/expr.c +++ b/src/analysis/scan/expr.c @@ -466,6 +466,7 @@ bool g_scan_expression_handle_set_features(const GScanExpression *expr) /****************************************************************************** * * * Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * * count = quantité d'éléments déterminée. [OUT] * * * * Description : Dénombre les éléments portés par une expression. * @@ -476,7 +477,7 @@ bool g_scan_expression_handle_set_features(const GScanExpression *expr) * * ******************************************************************************/ -bool g_scan_expression_count_items(const GScanExpression *expr, size_t *count) +bool g_scan_expression_count_items(const GScanExpression *expr, GScanContext *ctx, size_t *count) { bool result; /* Bilan à retourner */ GScanExpressionClass *class; /* Classe à activer */ @@ -486,7 +487,7 @@ bool g_scan_expression_count_items(const GScanExpression *expr, size_t *count) class = G_SCAN_EXPRESSION_GET_CLASS(expr); if (class->count != NULL) - result = class->count(expr, count); + result = class->count(expr, ctx, count); else result = false; @@ -504,6 +505,7 @@ bool g_scan_expression_count_items(const GScanExpression *expr, size_t *count) * * * Paramètres : expr = expression à consulter. * * index = indice de l'élément à transférer. * +* ctx = contexte de suivi de l'analyse courante. * * out = zone d'enregistrement de la réduction opérée. [OUT] * * * * Description : Fournit un élément donné issu d'un ensemble constitué. * @@ -514,7 +516,7 @@ bool g_scan_expression_count_items(const GScanExpression *expr, size_t *count) * * ******************************************************************************/ -bool g_scan_expression_get_item(const GScanExpression *expr, size_t index, GScanExpression **out) +bool g_scan_expression_get_item(const GScanExpression *expr, size_t index, GScanContext *ctx, GScanExpression **out) { bool result; /* Bilan à retourner */ GScanExpressionClass *class; /* Classe à activer */ @@ -525,7 +527,7 @@ bool g_scan_expression_get_item(const GScanExpression *expr, size_t index, GScan if (class->get != NULL) { - result = class->get(expr, index, out); + result = class->get(expr, index, ctx, out); if (*out != NULL) g_object_ref(G_OBJECT(*out)); @@ -574,27 +576,27 @@ static GScanExpression *_g_scan_expression_intersect(GScanExpression *expr, cons result = NULL; - valid = g_scan_expression_count_items(other, &other_count); + valid = g_scan_expression_count_items(other, ctx, &other_count); if (!valid) goto done; /* Intersection entre deux ensembles ? */ if (g_scan_expression_handle_set_features(expr)) { - valid = g_scan_expression_count_items(expr, &expr_count); + valid = g_scan_expression_count_items(expr, ctx, &expr_count); if (!valid) goto done; result = g_scan_generic_set_new(); for (k = 0; k < expr_count; k++) { - valid = g_scan_expression_get_item(expr, k, &item); + valid = g_scan_expression_get_item(expr, k, ctx, &item); if (!valid) break; comparable = G_COMPARABLE_ITEM(item); for (i = 0; i < other_count; i++) { - valid = g_scan_expression_get_item(other, i, &item); + valid = g_scan_expression_get_item(other, i, ctx, &item); if (!valid) break; valid = g_comparable_item_compare_rich(comparable, G_COMPARABLE_ITEM(item), RCO_EQ, &status); @@ -619,7 +621,7 @@ static GScanExpression *_g_scan_expression_intersect(GScanExpression *expr, cons for (i = 0; i < other_count && result == NULL; i++) { - valid = g_scan_expression_get_item(other, i, &item); + valid = g_scan_expression_get_item(other, i, ctx, &item); if (!valid) break; valid = g_comparable_item_compare_rich(comparable, G_COMPARABLE_ITEM(item), RCO_EQ, &status); diff --git a/src/analysis/scan/expr.h b/src/analysis/scan/expr.h index dd4bc3f..797abec 100644 --- a/src/analysis/scan/expr.h +++ b/src/analysis/scan/expr.h @@ -50,7 +50,7 @@ typedef struct _GScanExpressionClass GScanExpressionClass; /* Types naturel équivalant à l'expression */ -typedef enum _ExprValueType +typedef enum _ExprValueType /* REMME */ { EVT_BOOLEAN, /* Valeur booléenne */ EVT_INTEGER, /* Nombre entier 64 bits */ @@ -97,10 +97,10 @@ bool g_scan_expression_reduce_to_boolean(GScanExpression *, GScanContext *, GSca bool g_scan_expression_handle_set_features(const GScanExpression *); /* Dénombre les éléments portés par une expression. */ -bool g_scan_expression_count_items(const GScanExpression *, size_t *); +bool g_scan_expression_count_items(const GScanExpression *, GScanContext *, size_t *); /* Fournit un élément donné issu d'un ensemble constitué. */ -bool g_scan_expression_get_item(const GScanExpression *, size_t, GScanExpression **); +bool g_scan_expression_get_item(const GScanExpression *, size_t, GScanContext *, GScanExpression **); /* Réalise l'intersection entre deux ensembles. */ GScanExpression *g_scan_expression_intersect(GScanExpression *, const GScanExpression *, GScanContext *, GScanScope *); diff --git a/src/analysis/scan/exprs/Makefile.am b/src/analysis/scan/exprs/Makefile.am index 1266a63..d1a122a 100644 --- a/src/analysis/scan/exprs/Makefile.am +++ b/src/analysis/scan/exprs/Makefile.am @@ -11,8 +11,12 @@ libanalysisscanexprs_la_SOURCES = \ call.h call.c \ counter-int.h \ counter.h counter.c \ + handler-int.h \ + handler.h handler.c \ intersect-int.h \ intersect.h intersect.c \ + item-int.h \ + item.h item.c \ literal-int.h \ literal.h literal.c \ logical-int.h \ diff --git a/src/analysis/scan/exprs/counter.c b/src/analysis/scan/exprs/counter.c index 290fd02..bb4e523 100644 --- a/src/analysis/scan/exprs/counter.c +++ b/src/analysis/scan/exprs/counter.c @@ -50,7 +50,7 @@ static void g_scan_match_counter_finalize(GScanMatchCounter *); /* Réduit une expression à une forme plus simple. */ -static bool g_scan_match_counter_reduce(GScanMatchCounter *, GScanContext *, GScanScope *, GScanExpression **); +static ScanReductionState g_scan_match_counter_reduce(GScanMatchCounter *, GScanContext *, GScanScope *, GScanExpression **); @@ -226,22 +226,22 @@ bool g_scan_match_counter_create(GScanMatchCounter *counter, GSearchPattern *pat * * ******************************************************************************/ -static bool g_scan_match_counter_reduce(GScanMatchCounter *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +static ScanReductionState g_scan_match_counter_reduce(GScanMatchCounter *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) { - bool result; /* Bilan à retourner */ + ScanReductionState result; /* Etat synthétisé à retourner */ size_t count; /* Quantité de correspondances */ - const GScanMatch **matches; /* Correspondances établies */ - - - matches = g_scan_context_get_full_matches(ctx, expr->pattern, &count); + if (g_scan_context_is_scan_done(ctx)) + { + g_scan_context_get_full_matches(ctx, expr->pattern, &count); - printf("matches: %zu\n", count); + *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ count }); + result = SRS_REDUCED; - *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ count }); - result = true; - + } + else + result = SRS_WAIT_FOR_SCAN; return result; diff --git a/src/analysis/scan/exprs/handler-int.h b/src/analysis/scan/exprs/handler-int.h new file mode 100644 index 0000000..f707fdb --- /dev/null +++ b/src/analysis/scan/exprs/handler-int.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * handler-int.h - prototypes internes pour la manipulation des correspondances établies lors d'un scan + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_HANDLER_INT_H +#define _ANALYSIS_SCAN_EXPRS_HANDLER_INT_H + + +#include "handler.h" + + +#include "../expr-int.h" + + + +/* Manipulation des correspondances établies lors d'un scan de binaire (instance) */ +struct _GScanPatternHandler +{ + GScanExpression parent; /* A laisser en premier */ + + GSearchPattern *pattern; /* Motif associé */ + ScanHandlerType type; /* Manipulation attendue */ + +}; + +/* Manipulation des correspondances établies lors d'un scan de binaire (classe) */ +struct _GScanPatternHandlerClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une manipulation de correspondances établies. */ +bool g_scan_pattern_handler_create(GScanPatternHandler *, GSearchPattern *, ScanHandlerType); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_HANDLER_INT_H */ diff --git a/src/analysis/scan/exprs/handler.c b/src/analysis/scan/exprs/handler.c new file mode 100644 index 0000000..a14140a --- /dev/null +++ b/src/analysis/scan/exprs/handler.c @@ -0,0 +1,402 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * handler.c - manipulation des correspondances établies lors d'un scan + * + * 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 . + */ + + +#include "handler.h" + + +#include + + +#include "literal.h" +#include "handler-int.h" +#include "../matches/bytes.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des manipulations de correspondances. */ +static void g_scan_pattern_handler_class_init(GScanPatternHandlerClass *); + +/* Initialise une instance de manipulation de correspondances. */ +static void g_scan_pattern_handler_init(GScanPatternHandler *); + +/* Supprime toutes les références externes. */ +static void g_scan_pattern_handler_dispose(GScanPatternHandler *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_pattern_handler_finalize(GScanPatternHandler *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réduit une expression à une forme plus simple. */ +static ScanReductionState g_scan_pattern_handler_reduce(GScanPatternHandler *, GScanContext *, GScanScope *, GScanExpression **); + +/* Réduit une expression à une forme booléenne. */ +static bool g_scan_pattern_handler_reduce_to_boolean(GScanPatternHandler *, GScanContext *, GScanScope *, GScanExpression **); + +/* Dénombre les éléments portés par une expression. */ +static bool g_scan_pattern_handler_count_items(const GScanPatternHandler *, GScanContext *, size_t *); + +/* Fournit un élément donné issu d'un ensemble constitué. */ +static bool g_scan_pattern_handler_get_item(const GScanPatternHandler *, size_t, GScanContext *, GScanExpression **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une manipulation de correspondances établies lors d'un scan. */ +G_DEFINE_TYPE(GScanPatternHandler, g_scan_pattern_handler, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des manipulations de correspondances. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pattern_handler_class_init(GScanPatternHandlerClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_pattern_handler_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_pattern_handler_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->reduce = (reduce_expr_fc)g_scan_pattern_handler_reduce; + expr->reduce_to_bool = (reduce_expr_to_bool_fc)g_scan_pattern_handler_reduce_to_boolean; + expr->count = (count_scan_expr_fc)g_scan_pattern_handler_count_items; + expr->get = (get_scan_expr_fc)g_scan_pattern_handler_get_item; + +} + + +/****************************************************************************** +* * +* Paramètres : handler = instance à initialiser. * +* * +* Description : Initialise une instance de manipulation de correspondances. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pattern_handler_init(GScanPatternHandler *handler) +{ + handler->pattern = NULL; + handler->type = SHT_RAW; + +} + + +/****************************************************************************** +* * +* Paramètres : handler = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pattern_handler_dispose(GScanPatternHandler *handler) +{ + g_clear_object(&handler->pattern); + + G_OBJECT_CLASS(g_scan_pattern_handler_parent_class)->dispose(G_OBJECT(handler)); + +} + + +/****************************************************************************** +* * +* Paramètres : handler = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_pattern_handler_finalize(GScanPatternHandler *handler) +{ + G_OBJECT_CLASS(g_scan_pattern_handler_parent_class)->finalize(G_OBJECT(handler)); + +} + + +/****************************************************************************** +* * +* Paramètres : pattern = motif à impliquer. * +* type = type de manipulation attendue. * +* * +* Description : Met en place une manipulation de correspondances établies. * +* * +* Retour : Expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_pattern_handler_new(GSearchPattern *pattern, ScanHandlerType type) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_PATTERN_HANDLER, NULL); + + if (!g_scan_pattern_handler_create(G_SCAN_PATTERN_HANDLER(result), pattern, type)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : handler = instance à initialiser pleinement. * +* pattern = motif à impliquer. * +* type = type de manipulation attendue. * +* * +* Description : Met en place une manipulation de correspondances établies. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_pattern_handler_create(GScanPatternHandler *handler, GSearchPattern *pattern, ScanHandlerType type) +{ + bool result; /* Bilan à retourner */ + + result = true; + + handler->pattern = pattern; + g_object_ref(G_OBJECT(pattern)); + + handler->type = type; + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static ScanReductionState g_scan_pattern_handler_reduce(GScanPatternHandler *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + ScanReductionState result; /* Etat synthétisé à retourner */ + + if (g_scan_context_is_scan_done(ctx)) + result = SRS_REDUCED; + + else + result = SRS_WAIT_FOR_SCAN; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * +* * +* Description : Réduit une expression à une forme booléenne. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_pattern_handler_reduce_to_boolean(GScanPatternHandler *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + bool result; /* Bilan à retourner */ + size_t count; /* Quantité de correspondances */ + + result = true; + + g_scan_context_get_full_matches(ctx, expr->pattern, &count); + + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ count > 0 }); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* count = quantité d'éléments déterminée. [OUT] * +* * +* Description : Dénombre les éléments portés par une expression. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_pattern_handler_count_items(const GScanPatternHandler *expr, GScanContext *ctx, size_t *count) +{ + bool result; /* Bilan à retourner */ + + result = true; + + assert(g_scan_context_is_scan_done(ctx)); + + g_scan_context_get_full_matches(ctx, expr->pattern, count); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* index = indice de l'élément à transférer. * +* ctx = contexte de suivi de l'analyse courante. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * +* * +* Description : Fournit un élément donné issu d'un ensemble constitué. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_pattern_handler_get_item(const GScanPatternHandler *expr, size_t index, GScanContext *ctx, GScanExpression **out) +{ + bool result; /* Bilan à retourner */ + size_t count; /* Quantité de correspondances */ + const GScanMatch **matches; /* Correspondances en place */ + const GScanBytesMatch *match; /* Correspondance ciblée */ + phys_t start; /* Point de départ du motif */ + phys_t end; /* Point d'arrivée du motif */ + phys_t len; /* Taille du motif */ + GBinContent *content; /* Contenu binaire à relire */ + vmpa2t pos; /* Tête de lecture */ + const bin_t *data; /* Accès aux données brutes */ + sized_string_t binary; /* Conversion de formats */ + + assert(g_scan_context_is_scan_done(ctx)); + + matches = g_scan_context_get_full_matches(ctx, expr->pattern, &count); + + result = (index < count); + if (!result) goto done; + + result = G_IS_SCAN_BYTES_MATCH(matches[index]); + if (!result) goto done; + + match = G_SCAN_BYTES_MATCH(matches[index]); + + len = g_scan_bytes_match_get_location(match, &start, &end); + + switch (expr->type) + { + case SHT_RAW: + content = g_scan_bytes_match_get_content(match); + + init_vmpa(&pos, start, VMPA_NO_VIRTUAL); + + data = g_binary_content_get_raw_access(content, &pos, len); + + binary.data = data; + binary.len = len; + + *out = g_scan_literal_expression_new(LVT_STRING, &binary); + + g_object_unref(G_OBJECT(content)); + break; + + case SHT_START: + *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ start }); + break; + + case SHT_LENGTH: + *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ len }); + break; + + case SHT_END: + *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ end }); + break; + + } + + done: + + return result; + +} diff --git a/src/analysis/scan/exprs/handler.h b/src/analysis/scan/exprs/handler.h new file mode 100644 index 0000000..8ad700a --- /dev/null +++ b/src/analysis/scan/exprs/handler.h @@ -0,0 +1,66 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * handler.h - prototypes pour la manipulation des correspondances établies lors d'un scan + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_HANDLER_H +#define _ANALYSIS_SCAN_EXPRS_HANDLER_H + + +#include "../expr.h" + + + +#define G_TYPE_SCAN_PATTERN_HANDLER g_scan_pattern_handler_get_type() +#define G_SCAN_PATTERN_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_PATTERN_HANDLER, GScanPatternHandler)) +#define G_IS_SCAN_PATTERN_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_PATTERN_HANDLER)) +#define G_SCAN_PATTERN_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_PATTERN_HANDLER, GScanPatternHandlerClass)) +#define G_IS_SCAN_PATTERN_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_PATTERN_HANDLER)) +#define G_SCAN_PATTERN_HANDLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_PATTERN_HANDLER, GScanPatternHandlerClass)) + + +/* Manipulation des correspondances établies lors d'un scan de binaire (instance) */ +typedef struct _GScanPatternHandler GScanPatternHandler; + +/* Manipulation des correspondances établies lors d'un scan de binaire (classe) */ +typedef struct _GScanPatternHandlerClass GScanPatternHandlerClass; + + +/* Type de manipulation représentée */ +typedef enum _ScanHandlerType +{ + SHT_RAW, /* Correspondances brutes */ + SHT_START, /* Départs de correspondances */ + SHT_LENGTH, /* Taille de correspondances */ + SHT_END, /* Fins de correspondances */ + +} ScanHandlerType; + + +/* Indique le type défini pour une manipulation de correspondances établies lors d'un scan. */ +GType g_scan_pattern_handler_get_type(void); + +/* Met en place une manipulation de correspondances établies. */ +GScanExpression *g_scan_pattern_handler_new(GSearchPattern *, ScanHandlerType); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_HANDLER_H */ diff --git a/src/analysis/scan/exprs/item-int.h b/src/analysis/scan/exprs/item-int.h new file mode 100644 index 0000000..56b159a --- /dev/null +++ b/src/analysis/scan/exprs/item-int.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item-int.h - prototypes internes pour la récupération d'un élément à partir d'une série + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_ITEM_INT_H +#define _ANALYSIS_SCAN_EXPRS_ITEM_INT_H + + +#include "item.h" + + +#include "../expr-int.h" + + + +/* Accès à un élément donné d'une série établie (instance) */ +struct _GScanSetItem +{ + GScanExpression parent; /* A laisser en premier */ + + GScanExpression *set; /* Série d'éléments à consulter*/ + GScanExpression *index; /* Indice de l'élément visé */ + +}; + +/* Accès à un élément donné d'une série établie (classe) */ +struct _GScanSetItemClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un accès à un élément donné d'une série. */ +bool g_scan_set_item_create(GScanSetItem *, GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_ITEM_INT_H */ diff --git a/src/analysis/scan/exprs/item.c b/src/analysis/scan/exprs/item.c new file mode 100644 index 0000000..a6b22f0 --- /dev/null +++ b/src/analysis/scan/exprs/item.c @@ -0,0 +1,346 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item.c - récupération d'un élément à partir d'une série + * + * 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 . + */ + + +#include "set.h" + + +#include + + +#include "literal.h" +#include "item-int.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des accès à un élément de série. */ +static void g_scan_set_item_class_init(GScanSetItemClass *); + +/* Initialise une instance d'accès à un élément de série. */ +static void g_scan_set_item_init(GScanSetItem *); + +/* Supprime toutes les références externes. */ +static void g_scan_set_item_dispose(GScanSetItem *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_set_item_finalize(GScanSetItem *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réduit une expression à une forme plus simple. */ +static ScanReductionState g_scan_set_item_reduce(GScanSetItem *, GScanContext *, GScanScope *, GScanExpression **); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour la récupération d'un élément à partir d'une série. */ +G_DEFINE_TYPE(GScanSetItem, g_scan_set_item, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des accès à un élément de série. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_set_item_class_init(GScanSetItemClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_set_item_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_set_item_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->reduce = (reduce_expr_fc)g_scan_set_item_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : item = instance à initialiser. * +* * +* Description : Initialise une instance d'accès à un élément de série. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_set_item_init(GScanSetItem *item) +{ + item->set = NULL; + item->index = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : item = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_set_item_dispose(GScanSetItem *item) +{ + g_clear_object(&item->set); + g_clear_object(&item->index); + + G_OBJECT_CLASS(g_scan_set_item_parent_class)->dispose(G_OBJECT(item)); + +} + + +/****************************************************************************** +* * +* Paramètres : item = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_set_item_finalize(GScanSetItem *item) +{ + G_OBJECT_CLASS(g_scan_set_item_parent_class)->finalize(G_OBJECT(item)); + +} + + +/****************************************************************************** +* * +* Paramètres : set = ensemble d'éléments à considérer. * +* index = indice de l'élément à viser. * +* * +* Description : Met en place un accès à un élément donné d'une série. * +* * +* Retour : Expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_set_item_new(GScanExpression *set, GScanExpression *index) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_SET_ITEM, NULL); + + if (!g_scan_set_item_create(G_SCAN_SET_ITEM(result), set, index)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = instance à initialiser pleinement. * +* set = ensemble d'éléments à considérer. * +* index = indice de l'élément à viser. * +* * +* Description : Met en place un accès à un élément donné d'une série. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_set_item_create(GScanSetItem *item, GScanExpression *set, GScanExpression *index) +{ + bool result; /* Bilan à retourner */ + + result = true; + + item->set = set; + g_object_ref(G_OBJECT(set)); + + item->index = index; + g_object_ref(G_OBJECT(index)); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static ScanReductionState g_scan_set_item_reduce(GScanSetItem *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + ScanReductionState result; /* Etat synthétisé à retourner */ + GScanExpression *new_set; /* Expression réduite (série) */ + GScanExpression *new_index; /* Expression réduite (indice) */ + ScanReductionState state_set; /* Etat synthétisé #1 */ + ScanReductionState state_index; /* Etat synthétisé #2 */ + GScanLiteralExpression *op_index; /* Indice d'accès final */ + LiteralValueType vtype; /* Type de valeur portée */ + long long val_s; /* Valeur de l'indice (signée) */ + unsigned long long val_u; /* Valeur de l'indice (!signée)*/ + bool status; /* Statut final de récupération*/ + + /* Réduction des éléments considérés */ + + new_set = NULL; + new_index = NULL; + + state_set = g_scan_expression_reduce(expr->set, ctx, scope, &new_set); + if (state_set == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + state_index = g_scan_expression_reduce(expr->index, ctx, scope, &new_index); + if (state_index == SRS_UNRESOLVABLE) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + /* Validation de la nature des éléments en jeu */ + + if (state_set == SRS_REDUCED && !g_scan_expression_handle_set_features(new_set)) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + if (state_index == SRS_REDUCED && !G_IS_SCAN_LITERAL_EXPRESSION(new_index)) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + /* Tentative d'accès à un élément de série */ + + if (state_set == SRS_REDUCED && state_index == SRS_REDUCED) + { + op_index = G_SCAN_LITERAL_EXPRESSION(new_index); + vtype = g_scan_literal_expression_get_value_type(op_index); + + if (vtype == LVT_SIGNED_INTEGER) + { + if (!g_scan_literal_expression_get_signed_integer_value(op_index, &val_s)) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + if (val_s < 0) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + status = g_scan_expression_get_item(expr->set, val_s, ctx, out); + + } + else if (vtype == LVT_UNSIGNED_INTEGER) + { + if (!g_scan_literal_expression_get_unsigned_integer_value(op_index, &val_u)) + { + result = SRS_UNRESOLVABLE; + goto exit; + } + + status = g_scan_expression_get_item(expr->set, val_u, ctx, out); + + } + + result = (status ? SRS_REDUCED : SRS_UNRESOLVABLE); + + } + + /* Mise à jour de la progression ? */ + + else + { + assert(state_set == SRS_WAIT_FOR_SCAN || state_index == SRS_WAIT_FOR_SCAN); + + if (new_set != expr->set || new_index != expr->index) + *out = g_scan_set_item_new(new_set, new_index); + + result = SRS_WAIT_FOR_SCAN; + + } + + /* Sortie propre */ + + exit: + + g_clear_object(&new_set); + g_clear_object(&new_index); + + return result; + +} diff --git a/src/analysis/scan/exprs/item.h b/src/analysis/scan/exprs/item.h new file mode 100644 index 0000000..9d3cdfb --- /dev/null +++ b/src/analysis/scan/exprs/item.h @@ -0,0 +1,55 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item.h - prototypes pour la récupération d'un élément à partir d'une série + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_ITEM_H +#define _ANALYSIS_SCAN_EXPRS_ITEM_H + + +#include "../expr.h" + + + +#define G_TYPE_SCAN_SET_ITEM g_scan_set_item_get_type() +#define G_SCAN_SET_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_SET_ITEM, GScanSetItem)) +#define G_IS_SCAN_SET_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_SET_ITEM)) +#define G_SCAN_SET_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_SET_ITEM, GScanSetItemClass)) +#define G_IS_SCAN_SET_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_SET_ITEM)) +#define G_SCAN_SET_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_SET_ITEM, GScanSetItemClass)) + + +/* Accès à un élément donné d'une série établie (instance) */ +typedef struct _GScanSetItem GScanSetItem; + +/* Accès à un élément donné d'une série établie (classe) */ +typedef struct _GScanSetItemClass GScanSetItemClass; + + +/* Indique le type défini pour la récupération d'un élément à partir d'une série. */ +GType g_scan_set_item_get_type(void); + +/* Met en place un accès à un élément donné d'une série. */ +GScanExpression *g_scan_set_item_new(GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_ITEM_H */ diff --git a/src/analysis/scan/exprs/literal.c b/src/analysis/scan/exprs/literal.c index e468382..070c177 100644 --- a/src/analysis/scan/exprs/literal.c +++ b/src/analysis/scan/exprs/literal.c @@ -60,7 +60,7 @@ static bool g_scan_literal_expression_compare_rich(const GScanLiteralExpression static bool g_scan_literal_expression_reduce_to_boolean(GScanLiteralExpression *, GScanContext *, GScanScope *, GScanExpression **); /* Dénombre les éléments portés par une expression. */ -static bool g_scan_literal_expression_count(const GScanLiteralExpression *, size_t *); +static bool g_scan_literal_expression_count(const GScanLiteralExpression *, GScanContext *, size_t *); @@ -623,6 +623,7 @@ static bool g_scan_literal_expression_reduce_to_boolean(GScanLiteralExpression * /****************************************************************************** * * * Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * * count = quantité d'éléments déterminée. [OUT] * * * * Description : Dénombre les éléments portés par une expression. * @@ -633,7 +634,7 @@ static bool g_scan_literal_expression_reduce_to_boolean(GScanLiteralExpression * * * ******************************************************************************/ -static bool g_scan_literal_expression_count(const GScanLiteralExpression *expr, size_t *count) +static bool g_scan_literal_expression_count(const GScanLiteralExpression *expr, GScanContext *ctx, size_t *count) { bool result; /* Bilan à retourner */ diff --git a/src/analysis/scan/exprs/set.c b/src/analysis/scan/exprs/set.c index 0a93ced..d76af4d 100644 --- a/src/analysis/scan/exprs/set.c +++ b/src/analysis/scan/exprs/set.c @@ -60,10 +60,10 @@ static ScanReductionState g_scan_generic_set_reduce(GScanGenericSet *, GScanCont static bool g_scan_generic_set_reduce_to_boolean(GScanGenericSet *, GScanContext *, GScanScope *, GScanExpression **); /* Dénombre les éléments portés par une expression. */ -static bool g_scan_generic_set_count_items(const GScanGenericSet *, size_t *); +static bool g_scan_generic_set_count_items(const GScanGenericSet *, GScanContext *, size_t *); /* Fournit un élément donné issu d'un ensemble constitué. */ -static bool g_scan_generic_set_get_item(const GScanGenericSet *, size_t, GScanExpression **); +static bool g_scan_generic_set_get_item(const GScanGenericSet *, size_t, GScanContext *, GScanExpression **); @@ -328,6 +328,7 @@ static bool g_scan_generic_set_reduce_to_boolean(GScanGenericSet *expr, GScanCon /****************************************************************************** * * * Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * * count = quantité d'éléments déterminée. [OUT] * * * * Description : Dénombre les éléments portés par une expression. * @@ -338,7 +339,7 @@ static bool g_scan_generic_set_reduce_to_boolean(GScanGenericSet *expr, GScanCon * * ******************************************************************************/ -static bool g_scan_generic_set_count_items(const GScanGenericSet *expr, size_t *count) +static bool g_scan_generic_set_count_items(const GScanGenericSet *expr, GScanContext *ctx, size_t *count) { bool result; /* Bilan à retourner */ @@ -355,6 +356,7 @@ static bool g_scan_generic_set_count_items(const GScanGenericSet *expr, size_t * * * * Paramètres : expr = expression à consulter. * * index = indice de l'élément à transférer. * +* ctx = contexte de suivi de l'analyse courante. * * out = zone d'enregistrement de la réduction opérée. [OUT] * * * * Description : Fournit un élément donné issu d'un ensemble constitué. * @@ -365,7 +367,7 @@ static bool g_scan_generic_set_count_items(const GScanGenericSet *expr, size_t * * * ******************************************************************************/ -static bool g_scan_generic_set_get_item(const GScanGenericSet *expr, size_t index, GScanExpression **out) +static bool g_scan_generic_set_get_item(const GScanGenericSet *expr, size_t index, GScanContext *ctx, GScanExpression **out) { bool result; /* Bilan à retourner */ diff --git a/src/analysis/scan/grammar.y b/src/analysis/scan/grammar.y index 10e1d42..c0aa52d 100644 --- a/src/analysis/scan/grammar.y +++ b/src/analysis/scan/grammar.y @@ -6,7 +6,7 @@ /* Affiche un message d'erreur suite à l'analyse en échec. */ -static int yyerror(GContentScanner *, yyscan_t, GScanRule **, void/*GBytesPattern*/ **, char **, size_t *, size_t *, char *); +static int yyerror(GContentScanner *, yyscan_t, GScanRule **, sized_string_t *, sized_string_t *, void/*GBytesPattern*/ **, char **, size_t *, size_t *, char *); %} @@ -16,34 +16,26 @@ static int yyerror(GContentScanner *, yyscan_t, GScanRule **, void/*GBytesPatter #define YY_TYPEDEF_YY_SCANNER_T typedef void *yyscan_t; +#include "core.h" #include "scanner.h" #include "exprs/access.h" #include "exprs/arithmetic.h" #include "exprs/call.h" #include "exprs/counter.h" +#include "exprs/handler.h" #include "exprs/intersect.h" +#include "exprs/item.h" #include "exprs/literal.h" #include "exprs/logical.h" #include "exprs/set.h" #include "exprs/relational.h" #include "exprs/strop.h" +#include "patterns/modifier.h" +#include "patterns/modifiers/list.h" +#include "patterns/tokens/hex.h" #include "patterns/tokens/plain.h" - - -#if 0 /////////////////////////////////////////////////////////////////////////:: -#define handle_coder_conversions(c, r) \ - ({ \ - encoding_spec *__spec; \ - encoding_syntax *__syntax; \ - conv_list *__list; \ - bool __status; \ - __spec = get_current_encoding_spec(c); \ - __syntax = get_current_encoding_syntax(__spec); \ - __list = get_conversions_in_encoding_syntax(__syntax); \ - __status = load_convs_from_raw_block(__list, r); \ - if (!__status) YYABORT; \ - }) -#endif /////////////////////////////////////////////////////////////////////////// +#include "patterns/tokens/nodes/plain.h" +#include "../../core/logs.h" } @@ -58,9 +50,25 @@ typedef void *yyscan_t; + sized_string_t *tmp_cstring; /* Série d'octets reconstituée */ + + struct { + bin_t byte; /* Valeur partielle recherchée */ + uint8_t mask; /* Masque associé */ + } semi_mask; + + GScanRule *rule; /* Nouvelle règle à intégrer */ - void/*GBytesPattern*/ *pattern; /* Nouveau motif à considérer */ + + + + GScanTokenNode *node; /* Bribe de motif à intégrer */ + GSearchPattern *pattern; /* Nouveau motif à considérer */ + + GScanTokenModifier *modifier; + + GScanExpression *expr; /* Expression de condition */ struct { @@ -78,13 +86,13 @@ typedef void *yyscan_t; %define api.pure full -%parse-param { GContentScanner *scanner } { yyscan_t yyscanner } { GScanRule **built_rule } { void /*GBytesPattern*/ **built_pattern } { char **buf } { size_t *allocated } { size_t *used } -%lex-param { yyscan_t yyscanner } { void/*GBytesPattern*/ **built_pattern } { char **buf } { size_t *allocated } { size_t *used } +%parse-param { GContentScanner *scanner } { yyscan_t yyscanner } { GScanRule **built_rule } { sized_string_t *tmp_0} { sized_string_t *tmp_1} { void /*GBytesPattern*/ **built_pattern } { char **buf } { size_t *allocated } { size_t *used } +%lex-param { yyscan_t yyscanner } { sized_string_t *tmp_0} { sized_string_t *tmp_1} { void/*GBytesPattern*/ **built_pattern } { char **buf } { size_t *allocated } { size_t *used } %code provides { #define YY_DECL \ - int rost_lex(YYSTYPE *yylval_param, yyscan_t yyscanner, void/*GBytesPattern*/ **built_pattern, char **buf, size_t *allocated, size_t *used) + int rost_lex(YYSTYPE *yylval_param, yyscan_t yyscanner, sized_string_t *tmp_0, sized_string_t *tmp_1, void/*GBytesPattern*/ **built_pattern, char **buf, size_t *allocated, size_t *used) YY_DECL; @@ -97,13 +105,26 @@ YY_DECL; %token RULE_NAME %token STRINGS CONDITION -%token IDENTIFIER + %token BYTES_ID %token BYTES_ID_COUNTER -%token BYTES_ID_LOCATION +%token BYTES_ID_START %token BYTES_ID_LENGTH +%token BYTES_ID_END %token NAME + +%token HEX_BYTES +%token FULL_MASK +%token SEMI_MASK + + +%token REGEX_BYTES +%token REGEX_CLASSES +%token REGEX_RANGE + + + %token BRACE_IN BRACE_OUT ASSIGN COLON @@ -143,11 +164,20 @@ YY_DECL; %token MUL "*" %token DIV "/" %token MOD "%" +%token TILDE "~" + +%token HOOK_O "[" +%token HOOK_C "]" + +%token BRACKET_O "{" +%token BRACKET_C "}" +%token QUESTION "?" %token PAREN_O "(" %token PAREN_C ")" %token COMMA "," %token DOT "." +%token PIPE "|" %token NONE "none" %token ANY "any" @@ -160,7 +190,11 @@ YY_DECL; %type RULE_NAME -%type IDENTIFIER BYTES_ID_COUNTER +%type BYTES_ID +%type BYTES_ID_COUNTER +%type BYTES_ID_START +%type BYTES_ID_LENGTH +%type BYTES_ID_END %type NAME @@ -173,8 +207,27 @@ YY_DECL; %type PLAIN_STRING %type MASKED_STRING +%type HEX_BYTES +%type FULL_MASK +%type SEMI_MASK + +%type REGEX_BYTES + + +%type modifiers +%type _modifiers +%type chained_modifiers +%type mod_stage +%type modifier + +%type hex_pattern +%type hex_tokens +%type hex_token + + + %type cexpression _cexpression -%type pattern_match + %type literal %type item_chain %type call_args @@ -185,7 +238,16 @@ YY_DECL; %type set_counter %type set %type set_items +%type set_access %type intersection +%type pattern_handler + + + + + +%left PIPE + %left OR @@ -200,6 +262,11 @@ YY_DECL; +%left HOOK_O HOOK_C + + + + %destructor { printf("-------- Discarding symbol %p.\n", $$); } @@ -257,14 +324,28 @@ strings : /* empty */ ; -string_decls : string_decl - | string_decls string_decl - ; + string_decls : string_decl + | hex_pattern + { + if ($1 == NULL) YYERROR; + g_scan_rule_add_local_variable(*built_rule, $1); + g_object_unref(G_OBJECT($1)); + } + | regex_pattern + | string_decls string_decl + | string_decls hex_pattern + { + if ($2 == NULL) YYERROR; + g_scan_rule_add_local_variable(*built_rule, $2); + g_object_unref(G_OBJECT($2)); + } + | string_decls regex_pattern + ; -string_decl : IDENTIFIER ASSIGN PLAIN_STRING +string_decl : BYTES_ID ASSIGN PLAIN_STRING modifiers { GSearchPattern *__pat; - __pat = g_plain_bytes_new((uint8_t *)$3.data, $3.len); + __pat = g_scan_plain_bytes_new(&$3, NULL, SPBF_NONE); g_search_pattern_set_name(__pat, $1.data, $1.len); g_scan_rule_add_local_variable(*built_rule, __pat); g_object_unref(G_OBJECT(__pat)); @@ -281,7 +362,7 @@ string_decl : IDENTIFIER ASSIGN PLAIN_STRING g_object_unref(G_OBJECT(__pat)); */ } - | IDENTIFIER ASSIGN MASKED_STRING + | BYTES_ID ASSIGN MASKED_STRING { printf("built %p\n", $3); /* @@ -301,6 +382,267 @@ string_decl : IDENTIFIER ASSIGN PLAIN_STRING } ; + +/** + * Prise en charge des modificateurs. + */ + + modifiers : /* empty */ + { + $$ = NULL; + } + | _modifiers + { + + // if (...) useless + + } + ; + + _modifiers : mod_stage + { + $$ = $1; + } + | chained_modifiers + { + $$ = $1; + } + ; + + chained_modifiers : _modifiers "|" _modifiers + ; + + mod_stage : modifier + { + $$ = $1; + } + | mod_stage modifier + { + bool status; + + if (G_IS_SCAN_MODIFIER_LIST($1)) + $$ = $1; + else + { + $$ = g_scan_modifier_list_new(); + g_scan_modifier_list_add(G_SCAN_MODIFIER_LIST($$), $1); + } + + status = g_scan_modifier_list_add(G_SCAN_MODIFIER_LIST($$), $2); + if (!status) + { + if (1) + log_simple_message(LMT_WARNING, "modifier already taken into account!"); + g_object_unref(G_OBJECT($2)); + } + + } + ; + + modifier : NAME + { + $$ = find_scan_token_modifiers_for_name($1.data); + if ($$ == NULL) YYERROR; + } + | "(" chained_modifiers ")" + { + $$ = $2; + } + ; + +/** + * Définition de motif en hexadécimal. + */ + + hex_pattern : BYTES_ID ASSIGN hex_tokens + { + $$ = g_scan_hex_bytes_new($3); + g_search_pattern_set_name($$, $1.data, $1.len); + } + ; + + hex_tokens : hex_token + { + $$ = $1; + } + | hex_tokens hex_token + { + + } + ; + + hex_token : HEX_BYTES + { + $$ = g_scan_token_node_plain_new($1, NULL, SPNF_NONE); + } + | FULL_MASK + { + printf("mask len: %llu\n", $1); + } + | SEMI_MASK + { + printf("semi mask: %hhx / %hhx \n", $1.byte, $1.mask); + } + | hex_range + { + printf("...range...\n"); + } + | "~" hex_token + { + + printf("hex -- NOT --\n"); + + } + | "(" hex_token "|" hex_token ")" + { + + printf("hex -- OR --\n"); + + } + ; + + hex_range : "[" "-" "]" + { + + printf("got inf range\n"); + + } + | "[" UNSIGNED_INTEGER "]" + { + + printf("got range [%llu]\n", $2); + + } + | "[" UNSIGNED_INTEGER "-" "]" + { + + printf("got range [%llu -> ]\n", $2); + + } + | "[" "-" UNSIGNED_INTEGER "]" + { + + printf("got range [ -> %llu]\n", $3); + + } + | "[" UNSIGNED_INTEGER "-" UNSIGNED_INTEGER "]" + { + + printf("got range [%llu -> %llu]\n", $2, $4); + + } + ; + +/** + * Définition de motif sous forme d'expression régulière + */ + + regex_pattern : BYTES_ID ASSIGN regex_tokens + { + + } + ; + + regex_tokens : regex_token + { + + } + | regex_tokens regex_token + { + + } + | "(" regex_tokens_list ")" + { + + printf("regex -- OR --\n"); + + } + | regex_tokens "(" regex_tokens_list ")" + { + + printf("regex -- OR --\n"); + + } + ; + + + regex_tokens_list : regex_tokens + | regex_tokens_list "|" regex_tokens + ; + + + regex_token : _regex_token + { + + } + | _regex_token regex_repeat + { + + } + ; + + _regex_token : DOT + { + printf("reg dot!\n"); + } + | REGEX_BYTES + { + printf("reg bytes: '%s' (l=%zu)\n", $1->data, $1->len); + } + | REGEX_CLASSES + { + printf("reg class!\n"); + } + | "[" REGEX_RANGE "]" + { + printf("reg range!\n"); + } + ; + + regex_repeat : "*" + { + printf(" .. repeat: *\n"); + } + | "+" + { + printf(" .. repeat: +\n"); + } + | "?" + { + printf(" .. repeat: ?\n"); + } + | "{" UNSIGNED_INTEGER "}" + { + + printf(" .. repeat {%llu}\n", $2); + + } + | "{" UNSIGNED_INTEGER "," "}" + { + + printf(" .. repeat {%llu,}\n", $2); + + } + | "{" "," UNSIGNED_INTEGER "}" + { + + printf(" .. repeat {,%llu}\n", $3); + + } + | "{" UNSIGNED_INTEGER "," UNSIGNED_INTEGER "}" + { + + printf(" .. repeat {%llu,%llu}\n", $2, $4); + + } + ; + + + +/** + * Définition des conditions. + */ + condition : CONDITION COLON cexpression { g_scan_rule_set_match_condition(*built_rule, $3); @@ -310,49 +652,19 @@ string_decl : IDENTIFIER ASSIGN PLAIN_STRING cexpression : _cexpression { $$ = $1; if ($$ == NULL) { printf("ERROR !!!\n"); YYERROR; } } - _cexpression : IDENTIFIER - { - printf("named var: %s\n", "$1"); - $$ = NULL; - /* - GSearchPattern *__pat; - GMatchCounter *__counter; - __pat = g_scan_rule_get_local_variable(*built_rule, $1); - if (__pat != NULL) - { - __counter = g_match_counter_new(__pat); - g_scan_rule_add_condition(*built_rule, G_MATCH_CONDITION(__counter)); - g_object_unref(G_OBJECT(__counter)); - g_object_unref(G_OBJECT(__pat)); - } - */ - } - | literal { $$ = $1; } - | pattern_match { $$ = $1; } - | item_chain { $$ = $1; } - | logical_expr { $$ = $1; } - | relational_expr { $$ = $1; } - | string_op { $$ = $1; } - | arithm_expr { $$ = $1; } - | set_counter { $$ = $1; } - | set { $$ = $1; } - | intersection { $$ = $1; } - | "(" cexpression ")" { $$ = $2; } - ; - - pattern_match : BYTES_ID_COUNTER - { - GSearchPattern *__pat; - __pat = g_scan_rule_get_local_variable(*built_rule, $1.data); - if (__pat == NULL) - $$ = NULL; - else - { - $$ = g_scan_match_counter_new(__pat); - g_object_unref(G_OBJECT(__pat)); - } - } - ; + _cexpression : literal { $$ = $1; } + | item_chain { $$ = $1; } + | logical_expr { $$ = $1; } + | relational_expr { $$ = $1; } + | string_op { $$ = $1; } + | arithm_expr { $$ = $1; } + | set_counter { $$ = $1; } + | set { $$ = $1; } + | set_access { $$ = $1; } + | intersection { $$ = $1; } + | pattern_handler { $$ = $1; } + | "(" cexpression ")" { $$ = $2; } + ; literal : "true" { @@ -538,16 +850,83 @@ set_counter : "none" "of" "them" { $$ = g_scan_literal_expression_new(LVT_BOOLEA } ; - intersection : cexpression "in" cexpression - { - $$ = g_scan_sets_intersection_new($1, $3); - g_object_unref(G_OBJECT($1)); - g_object_unref(G_OBJECT($3)); - } - ; - + set_access : cexpression "[" cexpression "]" + { + $$ = g_scan_set_item_new($1, $3); + g_object_unref(G_OBJECT($1)); + g_object_unref(G_OBJECT($3)); + } + ; + intersection : cexpression "in" cexpression + { + $$ = g_scan_sets_intersection_new($1, $3); + g_object_unref(G_OBJECT($1)); + g_object_unref(G_OBJECT($3)); + } + ; + pattern_handler : BYTES_ID + { + GSearchPattern *__pat; + __pat = g_scan_rule_get_local_variable(*built_rule, $1.data); + if (__pat == NULL) + $$ = NULL; + else + { + $$ = g_scan_pattern_handler_new(__pat, SHT_RAW); + g_object_unref(G_OBJECT(__pat)); + } + } + | BYTES_ID_COUNTER + { + GSearchPattern *__pat; + __pat = g_scan_rule_get_local_variable(*built_rule, $1.data); + if (__pat == NULL) + $$ = NULL; + else + { + $$ = g_scan_match_counter_new(__pat); + g_object_unref(G_OBJECT(__pat)); + } + } + | BYTES_ID_START + { + GSearchPattern *__pat; + __pat = g_scan_rule_get_local_variable(*built_rule, $1.data); + if (__pat == NULL) + $$ = NULL; + else + { + $$ = g_scan_pattern_handler_new(__pat, SHT_START); + g_object_unref(G_OBJECT(__pat)); + } + } + | BYTES_ID_LENGTH + { + GSearchPattern *__pat; + __pat = g_scan_rule_get_local_variable(*built_rule, $1.data); + if (__pat == NULL) + $$ = NULL; + else + { + $$ = g_scan_pattern_handler_new(__pat, SHT_LENGTH); + g_object_unref(G_OBJECT(__pat)); + } + } + | BYTES_ID_END + { + GSearchPattern *__pat; + __pat = g_scan_rule_get_local_variable(*built_rule, $1.data); + if (__pat == NULL) + $$ = NULL; + else + { + $$ = g_scan_pattern_handler_new(__pat, SHT_END); + g_object_unref(G_OBJECT(__pat)); + } + } + ; %% @@ -566,7 +945,7 @@ set_counter : "none" "of" "them" { $$ = g_scan_literal_expression_new(LVT_BOOLEA * * ******************************************************************************/ -static int yyerror(GContentScanner *scanner, yyscan_t yyscanner, GScanRule **built_rule, void/*GBytesPattern*/ **built_pattern, char **buf, size_t *allocated, size_t *used, char *msg) +static int yyerror(GContentScanner *scanner, yyscan_t yyscanner, GScanRule **built_rule, sized_string_t *tmp_0, sized_string_t *tmp_1, void/*GBytesPattern*/ **built_pattern, char **buf, size_t *allocated, size_t *used, char *msg) { printf("YYERROR line %d: %s\n", yyget_lineno(yyscanner), msg); @@ -593,6 +972,8 @@ bool process_rules_definitions(GContentScanner *scanner, const char *text, size_ { bool result; /* Bilan à renvoyer */ GScanRule *built_rule; /* Règle en construction */ + sized_string_t tmp_0; /* Zone tampon #1 */ + sized_string_t tmp_1; /* Zone tampon #2 */ void /*GBytesPattern*/ *built_pattern; /* Motif en construction */ char *buf; /* Zone de travail temporaire */ size_t allocated; /* Taille de mémoire allouée */ @@ -604,6 +985,13 @@ bool process_rules_definitions(GContentScanner *scanner, const char *text, size_ result = false; built_rule = NULL; + + tmp_0.data = malloc((length + 1) * sizeof(bin_t)); + tmp_0.len = 0; + + tmp_1.data = malloc((length + 1) * sizeof(bin_t)); + tmp_1.len = 0; + built_pattern = NULL; allocated = 256; @@ -616,7 +1004,7 @@ bool process_rules_definitions(GContentScanner *scanner, const char *text, size_ state = rost__scan_bytes(text, length, lexstate); - status = yyparse(scanner, lexstate, &built_rule, &built_pattern, &buf, &allocated, &used); + status = yyparse(scanner, lexstate, &built_rule, &tmp_0, &tmp_1, &built_pattern, &buf, &allocated, &used); result = (status == EXIT_SUCCESS); @@ -624,6 +1012,9 @@ bool process_rules_definitions(GContentScanner *scanner, const char *text, size_ rost_lex_destroy(lexstate); + exit_szstr(&tmp_0); + exit_szstr(&tmp_1); + free(buf); return result; diff --git a/src/analysis/scan/items/count.c b/src/analysis/scan/items/count.c index d87d33b..9040ec4 100644 --- a/src/analysis/scan/items/count.c +++ b/src/analysis/scan/items/count.c @@ -232,7 +232,7 @@ static bool g_scan_count_function_run_call(GScanCountFunction *item, GScanExpres else { - result = g_scan_expression_count_items(args[0], &value); + result = g_scan_expression_count_items(args[0], ctx, &value); if (result) *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ value })); diff --git a/src/analysis/scan/match-int.h b/src/analysis/scan/match-int.h index 9030d75..cf774c4 100644 --- a/src/analysis/scan/match-int.h +++ b/src/analysis/scan/match-int.h @@ -29,8 +29,11 @@ -/* Affiche une correspondance sur la sortie standard. */ -typedef void (* display_scan_match_fc) (const GScanMatch *); +/* Affiche une correspondance au format texte. */ +typedef void (* output_scan_match_to_text_fc) (const GScanMatch *, int); + +/* Affiche une correspondance au format JSON. */ +typedef void (* output_scan_match_to_json_fc) (const GScanMatch *, const sized_string_t *, unsigned int, int); /* Correspondance trouvée avec un motif (instance) */ @@ -47,7 +50,8 @@ struct _GScanMatchClass { GObjectClass parent; /* A laisser en premier */ - display_scan_match_fc display; /* Impression des résultats */ + output_scan_match_to_text_fc to_text; /* Impression au format texte */ + output_scan_match_to_json_fc to_json; /* Impression au format JSON */ }; diff --git a/src/analysis/scan/match.c b/src/analysis/scan/match.c index c7e2a78..b0b4320 100644 --- a/src/analysis/scan/match.c +++ b/src/analysis/scan/match.c @@ -157,8 +157,9 @@ GSearchPattern *g_scan_match_get_source(const GScanMatch *match) /****************************************************************************** * * * Paramètres : match = définition de correspondance à manipuler. * +* fd = canal d'écriture. * * * -* Description : Affiche une correspondance sur la sortie standard. * +* Description : Affiche une correspondance au format texte. * * * * Retour : - * * * @@ -166,12 +167,97 @@ GSearchPattern *g_scan_match_get_source(const GScanMatch *match) * * ******************************************************************************/ -void g_scan_match_display(const GScanMatch *match) +void g_scan_match_output_to_text(const GScanMatch *match, int fd) { GScanMatchClass *class; /* Classe à activer */ class = G_SCAN_MATCH_GET_CLASS(match); - class->display(match); + class->to_text(match, fd); + +} + + +/****************************************************************************** +* * +* Paramètres : match = définition de correspondance à manipuler. * +* * +* Description : Convertit une correspondance en texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_match_convert_as_text(const GScanMatch *match) +{ + /* TODO */ + +} + + +/****************************************************************************** +* * +* Paramètres : match = définition de correspondance à manipuler. * +* padding = éventuel bourrage initial à placer ou NULL. * +* level = profondeur actuelle. * +* fd = canal d'écriture. * +* trailing = impose une virgule finale ? * +* * +* Description : Affiche une correspondance au format JSON. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_match_output_to_json(const GScanMatch *match, const sized_string_t *padding, unsigned int level, int fd, bool trailing) +{ + unsigned int i; /* Boucle de parcours */ + GScanMatchClass *class; /* Classe à activer */ + + /* Introduction */ + + for (i = 0; i < level; i++) + write(fd, padding->data, padding->len); + + write(fd, "{\n", 2); + + /* Affichage du contenu */ + + class = G_SCAN_MATCH_GET_CLASS(match); + + class->to_json(match, padding, level + 1, fd); + + /* Conclusion */ + + for (i = 0; i < level; i++) + write(fd, padding->data, padding->len); + + if (trailing) + write(fd, "},\n", 3); + else + write(fd, "}\n", 2); + +} + + +/****************************************************************************** +* * +* Paramètres : match = définition de correspondance à manipuler. * +* * +* Description : Convertit une correspondance en JSON. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_match_convert_as_json(const GScanMatch *match) +{ + /* TODO */ } diff --git a/src/analysis/scan/match.h b/src/analysis/scan/match.h index 0990ae0..e713b5d 100644 --- a/src/analysis/scan/match.h +++ b/src/analysis/scan/match.h @@ -29,6 +29,7 @@ #include "pattern.h" +#include "../../common/szstr.h" @@ -53,8 +54,17 @@ GType g_scan_match_get_type(void); /* Indique la source du motif d'origine recherché. */ GSearchPattern *g_scan_match_get_source(const GScanMatch *); -/* Affiche une correspondance sur la sortie standard. */ -void g_scan_match_display(const GScanMatch *); +/* Affiche une correspondance au format texte. */ +void g_scan_match_output_to_text(const GScanMatch *, int); + +/* Convertit une correspondance en texte. */ +void g_scan_match_convert_as_text(const GScanMatch *); + +/* Affiche une correspondance au format JSON. */ +void g_scan_match_output_to_json(const GScanMatch *, const sized_string_t *, unsigned int, int, bool); + +/* Convertit une correspondance en JSON. */ +void g_scan_match_convert_as_json(const GScanMatch *); diff --git a/src/analysis/scan/matches/bytes-int.h b/src/analysis/scan/matches/bytes-int.h index c983aa3..6f7e60b 100644 --- a/src/analysis/scan/matches/bytes-int.h +++ b/src/analysis/scan/matches/bytes-int.h @@ -33,7 +33,7 @@ /* Correspondance trouvée avec une chaîne (instance) */ -struct _GBytesMatch +struct _GScanBytesMatch { GScanMatch parent; /* A laisser en premier */ @@ -45,7 +45,7 @@ struct _GBytesMatch }; /* Correspondance trouvée avec une chaîne (classe) */ -struct _GBytesMatchClass +struct _GScanBytesMatchClass { GScanMatchClass parent; /* A laisser en premier */ @@ -53,7 +53,7 @@ struct _GBytesMatchClass /* Met en place une correspondance trouvée avec un motif. */ -bool g_bytes_match_create(GBytesMatch *, GSearchPattern *, GBinContent *, phys_t, phys_t); +bool g_scan_bytes_match_create(GScanBytesMatch *, GSearchPattern *, GBinContent *, phys_t, phys_t); diff --git a/src/analysis/scan/matches/bytes.c b/src/analysis/scan/matches/bytes.c index 90fa27d..043170e 100644 --- a/src/analysis/scan/matches/bytes.c +++ b/src/analysis/scan/matches/bytes.c @@ -24,10 +24,14 @@ #include "bytes.h" +#include #include +#include #include "bytes-int.h" +#include "../../../common/cpp.h" +#include "../../../core/logs.h" @@ -35,24 +39,27 @@ /* Initialise la classe des correspondances de chaînes. */ -static void g_bytes_match_class_init(GBytesMatchClass *); +static void g_scan_bytes_match_class_init(GScanBytesMatchClass *); /* Initialise une instance de correspondance de chaîne trouvée. */ -static void g_bytes_match_init(GBytesMatch *); +static void g_scan_bytes_match_init(GScanBytesMatch *); /* Supprime toutes les références externes. */ -static void g_bytes_match_dispose(GBytesMatch *); +static void g_scan_bytes_match_dispose(GScanBytesMatch *); /* Procède à la libération totale de la mémoire. */ -static void g_bytes_match_finalize(GBytesMatch *); +static void g_scan_bytes_match_finalize(GScanBytesMatch *); /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ -/* Affiche une correspondance sur la sortie standard. */ -static void g_bytes_match_display(const GBytesMatch *); +/* Affiche une correspondance au format texte. */ +static void g_scan_bytes_match_output_to_text(const GScanBytesMatch *, int); + +/* Affiche une correspondance au format JSON. */ +static void g_scan_bytes_match_output_to_json(const GScanBytesMatch *, const sized_string_t *, unsigned int, int); @@ -62,7 +69,7 @@ static void g_bytes_match_display(const GBytesMatch *); /* Indique le type défini pour un correspondance de chaîne identifiée. */ -G_DEFINE_TYPE(GBytesMatch, g_bytes_match, G_TYPE_SCAN_MATCH); +G_DEFINE_TYPE(GScanBytesMatch, g_scan_bytes_match, G_TYPE_SCAN_MATCH); /****************************************************************************** @@ -77,19 +84,20 @@ G_DEFINE_TYPE(GBytesMatch, g_bytes_match, G_TYPE_SCAN_MATCH); * * ******************************************************************************/ -static void g_bytes_match_class_init(GBytesMatchClass *klass) +static void g_scan_bytes_match_class_init(GScanBytesMatchClass *klass) { GObjectClass *object; /* Autre version de la classe */ GScanMatchClass *match; /* Version parente de la classe*/ object = G_OBJECT_CLASS(klass); - object->dispose = (GObjectFinalizeFunc/* ! */)g_bytes_match_dispose; - object->finalize = (GObjectFinalizeFunc)g_bytes_match_finalize; + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_bytes_match_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_bytes_match_finalize; match = G_SCAN_MATCH_CLASS(klass); - match->display = (display_scan_match_fc)g_bytes_match_display; + match->to_text = (output_scan_match_to_text_fc)g_scan_bytes_match_output_to_text; + match->to_json = (output_scan_match_to_json_fc)g_scan_bytes_match_output_to_json; } @@ -106,7 +114,7 @@ static void g_bytes_match_class_init(GBytesMatchClass *klass) * * ******************************************************************************/ -static void g_bytes_match_init(GBytesMatch *match) +static void g_scan_bytes_match_init(GScanBytesMatch *match) { match->content = NULL; @@ -128,11 +136,11 @@ static void g_bytes_match_init(GBytesMatch *match) * * ******************************************************************************/ -static void g_bytes_match_dispose(GBytesMatch *match) +static void g_scan_bytes_match_dispose(GScanBytesMatch *match) { g_clear_object(&match->content); - G_OBJECT_CLASS(g_bytes_match_parent_class)->dispose(G_OBJECT(match)); + G_OBJECT_CLASS(g_scan_bytes_match_parent_class)->dispose(G_OBJECT(match)); } @@ -149,9 +157,9 @@ static void g_bytes_match_dispose(GBytesMatch *match) * * ******************************************************************************/ -static void g_bytes_match_finalize(GBytesMatch *match) +static void g_scan_bytes_match_finalize(GScanBytesMatch *match) { - G_OBJECT_CLASS(g_bytes_match_parent_class)->finalize(G_OBJECT(match)); + G_OBJECT_CLASS(g_scan_bytes_match_parent_class)->finalize(G_OBJECT(match)); } @@ -171,13 +179,13 @@ static void g_bytes_match_finalize(GBytesMatch *match) * * ******************************************************************************/ -GScanMatch *g_bytes_match_new(GSearchPattern *source, GBinContent *content, phys_t start, phys_t len) +GScanMatch *g_scan_bytes_match_new(GSearchPattern *source, GBinContent *content, phys_t start, phys_t len) { GScanMatch *result; /* Structure à retourner */ - result = g_object_new(G_TYPE_BYTES_MATCH, NULL); + result = g_object_new(G_TYPE_SCAN_BYTES_MATCH, NULL); - if (!g_bytes_match_create(G_BYTES_MATCH(result), source, content, start, len)) + if (!g_scan_bytes_match_create(G_SCAN_BYTES_MATCH(result), source, content, start, len)) g_clear_object(&result); return result; @@ -201,7 +209,7 @@ GScanMatch *g_bytes_match_new(GSearchPattern *source, GBinContent *content, phys * * ******************************************************************************/ -bool g_bytes_match_create(GBytesMatch *match, GSearchPattern *source, GBinContent *content, phys_t start, phys_t len) +bool g_scan_bytes_match_create(GScanBytesMatch *match, GSearchPattern *source, GBinContent *content, phys_t start, phys_t len) { bool result; /* Bilan à retourner */ GScanMatch *base; /* Lien vers les infos de base */ @@ -224,6 +232,58 @@ bool g_bytes_match_create(GBytesMatch *match, GSearchPattern *source, GBinConten } +/****************************************************************************** +* * +* Paramètres : match = informations de correspondance à consulter. * +* * +* Description : Fournit une référence au contenu lié à la correspondance. * +* * +* Retour : Content binaire associé au context. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBinContent *g_scan_bytes_match_get_content(const GScanBytesMatch *match) +{ + GBinContent *result; /* Instance à retourner */ + + result = match->content; + + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : match = informations de correspondance à consulter. * +* start = position de départ d'un motif détecté. [OUT] * +* end = position d'arrivée d'un motif détecté. [OUT] * +* * +* Description : Indique la localisation d'une correspondance établie. * +* * +* Retour : Taille mesurée de la correspondance. * +* * +* Remarques : - * +* * +******************************************************************************/ + +phys_t g_scan_bytes_match_get_location(const GScanBytesMatch *match, phys_t *start, phys_t *end) +{ + phys_t result; /* Taille à retourner */ + + result = match->len; + + *start = match->start; + *end = match->start + result; + + return result; + +} + /* ---------------------------------------------------------------------------------- */ /* IMPLEMENTATION DES FONCTIONS DE CLASSE */ @@ -233,8 +293,9 @@ bool g_bytes_match_create(GBytesMatch *match, GSearchPattern *source, GBinConten /****************************************************************************** * * * Paramètres : match = définition de correspondance à manipuler. * +* fd = canal d'écriture. * * * -* Description : Affiche une correspondance sur la sortie standard. * +* Description : Affiche une correspondance au format texte. * * * * Retour : - * * * @@ -242,15 +303,34 @@ bool g_bytes_match_create(GBytesMatch *match, GSearchPattern *source, GBinConten * * ******************************************************************************/ -static void g_bytes_match_display(const GBytesMatch *match) +static void g_scan_bytes_match_output_to_text(const GScanBytesMatch *match, int fd) { + char value[2 + ULLONG_MAXLEN]; /* Impression de la position */ + int ret; /* Bilan d'une conversion */ GScanMatch *base; /* Lien vers les infos de base */ const char *name; /* Désignation du motif ciblé */ vmpa2t pos; /* Tête de lecture */ const bin_t *data; /* Accès aux données brutes */ - phys_t i; /* Boucle de parcours */ + phys_t k; /* Boucle de parcours #2 */ + + /* Position dans le binaire (hexadécimal) */ + + ret = snprintf(value, ULLONG_MAXLEN, "0x%llx", (unsigned long long)match->start); + + if (ret > 0) + write(fd, value, ret); - /* Affichage d'un repère */ + else + { + log_simple_message(LMT_EXT_ERROR, "Error while converting offset to hex!"); + write(fd, "\"\"", 9); + } + + write(fd, ":", 1); + + /* Affichage de la désignation */ + + write(fd, "$", 1); base = G_SCAN_MATCH(match); @@ -262,25 +342,151 @@ static void g_bytes_match_display(const GBytesMatch *match) * Cette absence de nom est supportée ici. */ - if (name == NULL) - name = ""; + if (name != NULL) + write(fd, name, strlen(name)); + + write(fd, ": ", 2); + + /* Affichage du contenu */ + + init_vmpa(&pos, match->start, VMPA_NO_VIRTUAL); + + data = g_binary_content_get_raw_access(match->content, &pos, match->len); + + for (k = 0; k < match->len; k++) + { + if (isprint(data[k])) + write(fd, &data[k], 1); + + else + { + write(fd, "\\x", 2); + + ret = snprintf(value, ULLONG_MAXLEN, "%02hhx", data[k]); + + if (ret > 0) + { + assert(ret == 2); + write(fd, value, ret); + } + + else + { + log_simple_message(LMT_EXT_ERROR, "Error while converting data!"); + write(fd, "??", 2); + } + + } + + } + + write(fd, "\n", 1); + +} + + +/****************************************************************************** +* * +* Paramètres : match = définition de correspondance à manipuler. * +* padding = éventuel bourrage initial à placer ou NULL. * +* level = profondeur actuelle. * +* fd = canal d'écriture. * +* * +* Description : Affiche une correspondance au format JSON. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_bytes_match_output_to_json(const GScanBytesMatch *match, const sized_string_t *padding, unsigned int level, int fd) +{ + unsigned int i; /* Boucle de parcours #1 */ + vmpa2t pos; /* Tête de lecture */ + char value[4 + ULLONG_MAXLEN]; /* Impression de la position */ + int ret; /* Bilan d'une conversion */ + const bin_t *data; /* Accès aux données brutes */ + phys_t k; /* Boucle de parcours #2 */ + + /* Position dans le binaire (décimal) */ + + for (i = 0; i < level; i++) + write(fd, padding->data, padding->len); + + write(fd, "\"offset\": ", 10); + + ret = snprintf(value, ULLONG_MAXLEN, "%llu", (unsigned long long)match->start); + + if (ret > 0) + write(fd, value, ret); + + else + { + log_simple_message(LMT_EXT_ERROR, "Error while converting offset!"); + write(fd, "null", 4); + } + + write(fd, ",\n", 2); + + /* Position dans le binaire (hexadécimal) */ + + for (i = 0; i < level; i++) + write(fd, padding->data, padding->len); + + write(fd, "\"offset_hex\": ", 14); - printf("0x%llx:$%s: ", (unsigned long long)match->start, name); + ret = snprintf(value, ULLONG_MAXLEN, "\"0x%llx\"", (unsigned long long)match->start); + + if (ret > 0) + write(fd, value, ret); + + else + { + log_simple_message(LMT_EXT_ERROR, "Error while converting offset to hex!"); + write(fd, "null", 4); + } + + write(fd, ",\n", 2); /* Affichage du contenu */ + for (i = 0; i < level; i++) + write(fd, padding->data, padding->len); + + write(fd, "\"content\": \"", 12); + init_vmpa(&pos, match->start, VMPA_NO_VIRTUAL); data = g_binary_content_get_raw_access(match->content, &pos, match->len); - for (i = 0; i < match->len; i++) + for (k = 0; k < match->len; k++) { - if (isprint(data[i])) - printf("%c", data[i]); + if (isprint(data[k])) + write(fd, &data[k], 1); + else - printf("\\x%02hhx", data[i]); + { + write(fd, "\\x", 2); + + ret = snprintf(value, ULLONG_MAXLEN, "%02hhx", data[k]); + + if (ret > 0) + { + assert(ret == 2); + write(fd, value, ret); + } + + else + { + log_simple_message(LMT_EXT_ERROR, "Error while converting data!"); + write(fd, "??", 2); + } + + } + } - printf("\n"); + write(fd, "\"\n", 2); } diff --git a/src/analysis/scan/matches/bytes.h b/src/analysis/scan/matches/bytes.h index 22e76a6..e599ee4 100644 --- a/src/analysis/scan/matches/bytes.h +++ b/src/analysis/scan/matches/bytes.h @@ -33,26 +33,32 @@ -#define G_TYPE_BYTES_MATCH g_bytes_match_get_type() -#define G_BYTES_MATCH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BYTES_MATCH, GBytesMatch)) -#define G_IS_BYTES_MATCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BYTES_MATCH)) -#define G_BYTES_MATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BYTES_MATCH, GBytesMatchClass)) -#define G_IS_BYTES_MATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BYTES_MATCH)) -#define G_BYTES_MATCH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BYTES_MATCH, GBytesMatchClass)) +#define G_TYPE_SCAN_BYTES_MATCH g_scan_bytes_match_get_type() +#define G_SCAN_BYTES_MATCH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_BYTES_MATCH, GScanBytesMatch)) +#define G_IS_SCAN_BYTES_MATCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_BYTES_MATCH)) +#define G_SCAN_BYTES_MATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_BYTES_MATCH, GScanBytesMatchClass)) +#define G_IS_SCAN_BYTES_MATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_BYTES_MATCH)) +#define G_SCAN_BYTES_MATCH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_BYTES_MATCH, GScanBytesMatchClass)) /* Correspondance trouvée avec une chaîne (instance) */ -typedef struct _GBytesMatch GBytesMatch; +typedef struct _GScanBytesMatch GScanBytesMatch; /* Correspondance trouvée avec une chaîne (classe) */ -typedef struct _GBytesMatchClass GBytesMatchClass; +typedef struct _GScanBytesMatchClass GScanBytesMatchClass; /* Indique le type défini pour un correspondance de chaîne identifiée. */ -GType g_bytes_match_get_type(void); +GType g_scan_bytes_match_get_type(void); /* Prend note d'une correspondance trouvée avec un motif. */ -GScanMatch *g_bytes_match_new(GSearchPattern *, GBinContent *, phys_t, phys_t); +GScanMatch *g_scan_bytes_match_new(GSearchPattern *, GBinContent *, phys_t, phys_t); + +/* Fournit une référence au contenu lié à la correspondance. */ +GBinContent *g_scan_bytes_match_get_content(const GScanBytesMatch *); + +/* Indique la localisation d'une correspondance établie. */ +phys_t g_scan_bytes_match_get_location(const GScanBytesMatch *, phys_t *, phys_t *); diff --git a/src/analysis/scan/matches/pending.c b/src/analysis/scan/matches/pending.c index 73b7a06..9d1037d 100644 --- a/src/analysis/scan/matches/pending.c +++ b/src/analysis/scan/matches/pending.c @@ -79,46 +79,52 @@ void exit_pending_matches(pending_matches_t *matches) /****************************************************************************** * * * Paramètres : matches = suivi de correspondances à consulter. * -* start = point de départ d'une suite pour de correspondance.* -* mindex = indice de départ et d'arrivée. [OUT] * * * -* Description : Détermine la zone de correspondance idéale pour complément. * +* Description : Dénombre les correspondances établies jusque là. * * * -* Retour : Bilan de l'opération : true en cas de succès des recherches. * +* Retour : Quantité de correspondances complètes jusqu'à présent. * * * * Remarques : - * * * ******************************************************************************/ -bool find_target_in_pending_matches(pending_matches_t *matches, phys_t start, size_t *target) +size_t count_pending_matches(const pending_matches_t *matches) { - bool result; /* Bilan à retourner */ - size_t i; /* Boucle de parcours */ - match_area_t *area; /* Zone à initialiser */ + size_t result; /* Quantité à renvoyer */ - assert(*target <= matches->used); + result = matches->used; - result = false; + return result; - for (i = *target; i < matches->used; i++) - { - area = &matches->areas[i]; +} - if ((area->start + area->length) == start) - { - *target = i; - result = true; - break; - } - } +/****************************************************************************** +* * +* Paramètres : matches = suivi de correspondances à consulter. * +* count = nombre de correspondances en attente. [OUT] * +* * +* Description : Fournit la liste des correspondances établies à présent. * +* * +* Retour : Liste de correspondances en lecture seule. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const match_area_t *get_all_pending_matches(const pending_matches_t *matches, size_t *count) +{ + match_area_t *result; /* Série à renvoyer */ + + result = matches->areas; + + *count = matches->used; return result; } - /****************************************************************************** * * * Paramètres : matches = suivi de correspondances à compléter. * @@ -133,7 +139,7 @@ bool find_target_in_pending_matches(pending_matches_t *matches, phys_t start, si * * ******************************************************************************/ -void add_pending_matches(pending_matches_t *matches, phys_t start, phys_t length) +void add_pending_match(pending_matches_t *matches, phys_t start, phys_t length) { match_area_t *area; /* Zone à initialiser */ @@ -148,7 +154,9 @@ void add_pending_matches(pending_matches_t *matches, phys_t start, phys_t length area = &matches->areas[matches->used++]; area->start = start; - area->length = length; + area->end = start + length; + + area->ttl = 1; } @@ -167,21 +175,71 @@ void add_pending_matches(pending_matches_t *matches, phys_t start, phys_t length * * ******************************************************************************/ -void extend_pending_matches(pending_matches_t *matches, size_t target, phys_t length) +void extend_pending_match(pending_matches_t *matches, size_t target, phys_t end) +{ + match_area_t *area; /* Zone à actualiser */ + + assert(target < matches->used); + + area = &matches->areas[matches->used++]; + + if (area->ttl == 0) + { + area->end = end; + + area->ttl = 1; + + } + else + { + assert(area->ttl == 1); + + add_pending_match(matches, area->start, end - area->start); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : matches = suivi de correspondances à consulter. * +* target = indice de la zone de correspondance concernée. * +* pos = position à tester. * +* * +* Description : Détermine si une correspondance se termine à une position. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool has_pending_match_ending_at(const pending_matches_t *matches, size_t target, phys_t pos) { + bool result; /* Statut à retourner */ + match_area_t *area; /* Couverture visée */ + assert(target < matches->used); - matches->areas[target].length += length; + area = &matches->areas[target]; + + result = (area->end == pos); + + return result; } /****************************************************************************** * * -* Paramètres : matches = suivi de correspondances à modifier. * +* Paramètres : matches = suivi de correspondances à consulter. * * target = indice de la zone de correspondance concernée. * +* pos = position à tester. * +* min = borne inférieure de l'espace à considérer. * +* max = borne supérieure de l'espace à considérer. * * * -* Description : Retire une correspondance finalement non établie du suivi. * +* Description : Détermine si une correspondance se situe dans une plage. * * * * Retour : - * * * @@ -189,14 +247,135 @@ void extend_pending_matches(pending_matches_t *matches, size_t target, phys_t le * * ******************************************************************************/ -void remove_pending_matches(pending_matches_t *matches, size_t target) +bool has_pending_match_ending_between(const pending_matches_t *matches, size_t target, phys_t pos, phys_t min, phys_t max) { + bool result; /* Statut à retourner */ + match_area_t *area; /* Couverture visée */ + assert(target < matches->used); - if ((target + 1) < matches->used) - memmove(&matches->areas[target], &matches->areas[target + 1], - (matches->used - target - 1) * sizeof(match_area_t)); + area = &matches->areas[target]; + + result = ((area->end + min) <= pos && pos <= (area->end + max)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : matches = suivi de correspondances à modifier. * +* * +* Description : Réinitialisation à 0 tous les TTL de correspondances. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void reset_pending_matches_ttl(pending_matches_t *matches) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < matches->used; i++) + matches->areas[i].ttl = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : matches = suivi de correspondances à modifier. * +* * +* Description : Retire toutes les correspondances sans issue pour l'analyse. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void purge_pending_matches(pending_matches_t *matches) +{ + match_area_t *del_start; /* Départ d'une zone morte */ + match_area_t *del_end; /* Fin d'une zone morte */ + size_t del_remaining; /* Nombre de valides ensuite */ + size_t del_count; /* Nombre d'éléments à effacer */ + size_t i; /* Boucle de parcours */ + + /** + * Note : le code original était le suivant : + * + + * for (i = matches->used; i > 0; i--) + * if (matches->areas[i - 1].ttl == 0) + * { + * memmove(&matches->areas[i - 1], &matches->areas[i], (matches->used - i) * sizeof(match_area_t)); + * matches->used--; + * } + * + * Pour éviter les appels à memmove(), un déplacement par blocs est désormais visée. + */ + + del_start = NULL; + del_end = NULL; + del_count = 0; + del_remaining = 0; - matches->used--; + /* Suppression en bloc si possible */ + + for (i = matches->used; i > 0; i--) + { + if (matches->areas[i - 1].ttl == 0) + { + del_start = &matches->areas[i - 1]; + + if (del_end == NULL) + { + del_end = del_start; + del_remaining = matches->used - i; + } + + del_count++; + + } + else + { + if (del_start != NULL) + { + assert(&matches->areas[i] == del_start); + + if (del_remaining > 0) + memmove(del_start, del_end + 1, del_remaining * sizeof(match_area_t)); + + assert(matches->used > del_count); + matches->used -= del_count; + + del_start = NULL; + del_end = NULL; + del_count = 0; + del_remaining = 0; + + } + + } + + } + + /* Dernier traitement au besoin */ + + if (del_start != NULL) + { + assert(&matches->areas[0] == del_start); + + if (del_remaining > 0) + memmove(del_start, del_end + 1, del_remaining * sizeof(match_area_t)); + + assert(matches->used >= del_count); + matches->used -= del_count; + + } } diff --git a/src/analysis/scan/matches/pending.h b/src/analysis/scan/matches/pending.h index de2fd5f..0a1fe5c 100644 --- a/src/analysis/scan/matches/pending.h +++ b/src/analysis/scan/matches/pending.h @@ -25,6 +25,9 @@ #define _ANALYSIS_SCAN_MATCHES_PENDING_H +#include + + #include "../../content.h" @@ -33,7 +36,9 @@ typedef struct _match_area_t { phys_t start; /* Point de départ */ - phys_t length; /* Taille de la zone couverte */ + phys_t end; /* Point d'arrivée (exclus) */ + + unsigned long ttl; /* Durée de vie pour analyse */ } match_area_t; @@ -55,21 +60,34 @@ void init_pending_matches(pending_matches_t *); /* Libère la mémoire utilisée par une consolidation. */ void exit_pending_matches(pending_matches_t *); +// TODO ajouter un assert(used == 0) si !initialized */ #define are_pending_matches_initialized(pm) pm->initialized #define set_pending_matches_initialized(pm) pm->initialized = true -/* Détermine la zone de correspondance idéale pour complément. */ -bool find_target_in_pending_matches(pending_matches_t *, phys_t, size_t *); +/* Dénombre les correspondances établies jusque là. */ +size_t count_pending_matches(const pending_matches_t *); + +/* Fournit la liste des correspondances établies à présent. */ +const match_area_t *get_all_pending_matches(const pending_matches_t *, size_t *); /* Ajoute au suivi la définition d'une nouvelle correspondance. */ -void add_pending_matches(pending_matches_t *, phys_t, phys_t); +void add_pending_match(pending_matches_t *, phys_t, phys_t); /* Etend une zone couverte dans le suivi des correspondances. */ -void extend_pending_matches(pending_matches_t *, size_t, phys_t); +void extend_pending_match(pending_matches_t *, size_t, phys_t); + +/* Détermine si une correspondance se situe dans une plage. */ +bool has_pending_match_ending_between(const pending_matches_t *, size_t, phys_t, phys_t, phys_t); + +/* Détermine si une correspondance se termine à une position. */ +bool has_pending_match_ending_at(const pending_matches_t *, size_t, phys_t); + +/* Réinitialisation à 0 tous les TTL de correspondances. */ +void reset_pending_matches_ttl(pending_matches_t *); -/* Retire une correspondance finalement non établie du suivi. */ -void remove_pending_matches(pending_matches_t *, size_t); +/* Retire toutes les correspondances sans issue pour l'analyse. */ +void purge_pending_matches(pending_matches_t *); diff --git a/src/analysis/scan/options-int.h b/src/analysis/scan/options-int.h index a7772ed..4e85974 100644 --- a/src/analysis/scan/options-int.h +++ b/src/analysis/scan/options-int.h @@ -36,6 +36,8 @@ struct _GScanOptions GType data_backend; /* Choix du moteur d'analyse */ + bool print_json; /* Sortie au format json ? */ + bool print_strings; /* Affichage de correspondances*/ bool print_stats; /* Affichage de statistiques ? */ }; diff --git a/src/analysis/scan/options.c b/src/analysis/scan/options.c index 89e411e..cb56c2b 100644 --- a/src/analysis/scan/options.c +++ b/src/analysis/scan/options.c @@ -199,6 +199,92 @@ void g_scan_options_set_backend_for_data(GScanOptions *options, GType backend) * * * Paramètres : options = ensemble d'options d'analyses à consulter. * * * +* Description : Impose le format JSON comme type de sortie. * +* * +* Retour : Etat de l'option visée à conservé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_options_get_print_json(const GScanOptions *options) +{ + bool result; /* Statut à retourner */ + + result = options->print_json; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : options = ensemble d'options d'analyses à modifier. * +* state = état de l'option visée à conserver. * +* * +* Description : Mémorise le format JSON comme type de sortie. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_options_set_print_json(GScanOptions *options, bool state) +{ + options->print_json = state; + +} + + +/****************************************************************************** +* * +* Paramètres : options = ensemble d'options d'analyses à consulter. * +* * +* Description : Indique un besoin d'affichage des correspondances finales. * +* * +* Retour : Etat de l'option visée à conservé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_options_get_print_strings(const GScanOptions *options) +{ + bool result; /* Statut à retourner */ + + result = options->print_strings; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : options = ensemble d'options d'analyses à modifier. * +* state = état de l'option visée à conserver. * +* * +* Description : Mémorise un besoin d'affichage des correspondances finales. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_options_set_print_strings(GScanOptions *options, bool state) +{ + options->print_strings = state; + +} + + +/****************************************************************************** +* * +* Paramètres : options = ensemble d'options d'analyses à consulter. * +* * * Description : Indique un besoin de statistiques en fin de compilation. * * * * Retour : Etat de l'option visée à conservé. * diff --git a/src/analysis/scan/options.h b/src/analysis/scan/options.h index a7931c5..6b027e3 100644 --- a/src/analysis/scan/options.h +++ b/src/analysis/scan/options.h @@ -57,6 +57,18 @@ GType g_scan_options_get_backend_for_data(const GScanOptions *); /* Sélectionne un type de moteur d'analyse pour données brutes. */ void g_scan_options_set_backend_for_data(GScanOptions *, GType); +/* Impose le format JSON comme type de sortie. */ +bool g_scan_options_get_print_json(const GScanOptions *); + +/* Mémorise le format JSON comme type de sortie. */ +void g_scan_options_set_print_json(GScanOptions *, bool); + +/* Indique un besoin d'affichage des correspondances finales. */ +bool g_scan_options_get_print_strings(const GScanOptions *); + +/* Mémorise un besoin d'affichage des correspondances finales. */ +void g_scan_options_set_print_strings(GScanOptions *, bool); + /* Indique un besoin de statistiques en fin de compilation. */ bool g_scan_options_get_print_stats(const GScanOptions *); diff --git a/src/analysis/scan/pattern-int.h b/src/analysis/scan/pattern-int.h index 03af30f..b510c75 100644 --- a/src/analysis/scan/pattern-int.h +++ b/src/analysis/scan/pattern-int.h @@ -28,9 +28,15 @@ #include "pattern.h" +#include "context.h" -/* Décompte le nombre de correspondances identifiées. */ -typedef size_t (* count_pattern_matchs_fc) (const GSearchPattern *); + + +/* Affiche un motif de recherche au format texte. */ +typedef void (* output_pattern_to_text_fc) (const GSearchPattern *, GScanContext *, int); + +/* Affiche un motif de recherche au format JSON. */ +typedef void (* output_pattern_to_json_fc) (const GSearchPattern *, GScanContext *, const sized_string_t *, unsigned int, int); /* Motif à rechercher au sein d'un contenu (instance) */ @@ -47,7 +53,8 @@ struct _GSearchPatternClass { GObjectClass parent; /* A laisser en premier */ - count_pattern_matchs_fc count; /* Décompte des résultats */ + output_pattern_to_text_fc to_text; /* Impression au format texte */ + output_pattern_to_json_fc to_json; /* Impression au format JSON */ }; diff --git a/src/analysis/scan/pattern.c b/src/analysis/scan/pattern.c index 53a2662..5b966d2 100644 --- a/src/analysis/scan/pattern.c +++ b/src/analysis/scan/pattern.c @@ -186,25 +186,122 @@ void g_search_pattern_set_name(GSearchPattern *pattern, const char *name, size_t /****************************************************************************** * * -* Paramètres : pattern = définition de motif à consulter. * +* Paramètres : pattern = définition de motif à considérer. * +* context = contexte de l'analyse à mener. * +* fd = canal d'écriture. * * * -* Description : Décompte le nombre de correspondances identifiées. * +* Description : Affiche un motif de recherche au format texte. * * * -* Retour : Quantité d'identifications réalisées. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -size_t g_search_pattern_count_matchs(const GSearchPattern *pattern) +void g_search_pattern_output_to_text(const GSearchPattern *pattern, GScanContext *context, int fd) { - size_t result; /* Décompte à retourner */ GSearchPatternClass *class; /* Classe à activer */ class = G_SEARCH_PATTERN_GET_CLASS(pattern); - result = 0;//class->count(pattern); + class->to_text(pattern, context, fd); - return result; +} + + +/****************************************************************************** +* * +* Paramètres : pattern = définition de motif à considérer. * +* context = contexte de l'analyse à mener. * +* * +* Description : Convertit un motif de recherche en texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_search_pattern_convert_as_text(const GSearchPattern *pattern, GScanContext *context) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : pattern = définition de motif à considérer. * +* context = contexte de l'analyse à mener. * +* padding = éventuel bourrage initial à placer ou NULL. * +* level = profondeur actuelle. * +* fd = canal d'écriture. * +* trailing = impose une virgule finale ? * +* * +* Description : Affiche un motif de recherche au format JSON. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_search_pattern_output_to_json(const GSearchPattern *pattern, GScanContext *context, const sized_string_t *padding, unsigned int level, int fd, bool trailing) +{ + unsigned int i; /* Boucle de parcours */ + GSearchPatternClass *class; /* Classe à activer */ + + /* Introduction */ + + for (i = 0; i < level; i++) + write(fd, padding->data, padding->len); + + write(fd, "{\n", 2); + + /* Désignation du motif */ + + for (i = 0; i < (level + 1); i++) + write(fd, padding->data, padding->len); + + write(fd, "\"name\": \"$", 10); + + write(fd, pattern->name, strlen(pattern->name)); + + write(fd, "\",\n", 3); + + /* Affichage du contenu */ + + class = G_SEARCH_PATTERN_GET_CLASS(pattern); + + class->to_json(pattern, context, padding, level + 1, fd); + + /* Conclusion */ + + for (i = 0; i < level; i++) + write(fd, padding->data, padding->len); + + if (trailing) + write(fd, "},\n", 3); + else + write(fd, "}\n", 2); + +} + + +/****************************************************************************** +* * +* Paramètres : pattern = définition de motif à considérer. * +* context = contexte de l'analyse à mener. * +* * +* Description : Convertit un motif de recherche en JSON. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_search_pattern_convert_as_json(const GSearchPattern *pattern, GScanContext *context) +{ + /* TODO */ } diff --git a/src/analysis/scan/pattern.h b/src/analysis/scan/pattern.h index 9ea66d3..0e4327d 100644 --- a/src/analysis/scan/pattern.h +++ b/src/analysis/scan/pattern.h @@ -30,9 +30,14 @@ #include "../../arch/archbase.h" #include "../../arch/vmpa.h" +#include "../../common/szstr.h" +/* Depuis context.h: contexte de suivi d'une analyse en cours (instance) */ +typedef struct _GScanContext GScanContext; +; + #define G_TYPE_SEARCH_PATTERN g_search_pattern_get_type() #define G_SEARCH_PATTERN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SEARCH_PATTERN, GSearchPattern)) #define G_IS_SEARCH_PATTERN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SEARCH_PATTERN)) @@ -57,8 +62,17 @@ const char *g_search_pattern_get_name(const GSearchPattern *); /* Inscrit la désignation attribuée à un motif de recherche. */ void g_search_pattern_set_name(GSearchPattern *, const char *, size_t); -/* Décompte le nombre de correspondances identifiées. */ -size_t g_search_pattern_count_matchs(const GSearchPattern *); +/* Affiche un motif de recherche au format texte. */ +void g_search_pattern_output_to_text(const GSearchPattern *, GScanContext *, int); + +/* Convertit un motif de recherche en texte. */ +void g_search_pattern_convert_as_text(const GSearchPattern *, GScanContext *); + +/* Affiche un motif de recherche au format JSON. */ +void g_search_pattern_output_to_json(const GSearchPattern *, GScanContext *, const sized_string_t *, unsigned int, int, bool); + +/* Convertit un motif de recherche en JSON. */ +void g_search_pattern_convert_as_json(const GSearchPattern *, GScanContext *); diff --git a/src/analysis/scan/patterns/Makefile.am b/src/analysis/scan/patterns/Makefile.am index 4082275..c3d0994 100644 --- a/src/analysis/scan/patterns/Makefile.am +++ b/src/analysis/scan/patterns/Makefile.am @@ -5,14 +5,17 @@ noinst_LTLIBRARIES = libanalysisscanpatterns.la libanalysisscanpatterns_la_SOURCES = \ backend-int.h \ backend.h backend.c \ + modifier-int.h \ + modifier.h modifier.c \ token-int.h \ token.h token.c libanalysisscanpatterns_la_LIBADD = \ backends/libanalysisscanpatternsbackends.la \ + modifiers/libanalysisscanpatternsmodifiers.la \ tokens/libanalysisscanpatternstokens.la -libanalysisscanpatterns_la_CFLAGS = $(LIBGOBJ_CFLAGS) +libanalysisscanpatterns_la_CFLAGS = $(LIBGOBJ_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) @@ -20,4 +23,4 @@ devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) dev_HEADERS = $(libanalysisscanpatterns_la_SOURCES:%c=) -SUBDIRS = backends tokens +SUBDIRS = backends modifiers tokens diff --git a/src/analysis/scan/patterns/modifier-int.h b/src/analysis/scan/patterns/modifier-int.h new file mode 100644 index 0000000..246c139 --- /dev/null +++ b/src/analysis/scan/patterns/modifier-int.h @@ -0,0 +1,59 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * modifier-int.h - prototypes internes pour la modification d'une séquence d'octets pour un motif recherché + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_MODIFIER_INT_H +#define _ANALYSIS_SCAN_MODIFIER_INT_H + + +#include "modifier.h" + + + +/* Fournit le nom d'appel d'un modificateur pour motif. */ +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 *); + + +/* Transformation d'une séquence d'octets en une ou plusieurs autres formes (instance) */ +struct _GScanTokenModifier +{ + GObject parent; /* A laisser en premier */ + +}; + +/* Transformation d'une séquence d'octets en une ou plusieurs autres formes (classe) */ +struct _GScanTokenModifierClass +{ + GObjectClass parent; /* A laisser en premier */ + + get_scan_modifier_name_fc get_name; /* Fourniture du nom d'appel */ + + transform_scan_token_fc transform; /* Opération de transformation */ + +}; + + + +#endif /* _ANALYSIS_SCAN_MODIFIER_INT_H */ diff --git a/src/analysis/scan/patterns/modifier.c b/src/analysis/scan/patterns/modifier.c new file mode 100644 index 0000000..77d8bfd --- /dev/null +++ b/src/analysis/scan/patterns/modifier.c @@ -0,0 +1,181 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * modifier.c - modification d'une séquence d'octets pour un motif recherché + * + * 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 . + */ + + +#include "modifier.h" + + +#include "modifier-int.h" + + + +/* Initialise la classe des transformations d'octets. */ +static void g_scan_token_modifier_class_init(GScanTokenModifierClass *); + +/* Initialise une instance de transformation d'octets. */ +static void g_scan_token_modifier_init(GScanTokenModifier *); + +/* Supprime toutes les références externes. */ +static void g_scan_token_modifier_dispose(GScanTokenModifier *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_token_modifier_finalize(GScanTokenModifier *); + + + +/* Indique le type défini pour une transformation d'une séquence d'octets. */ +G_DEFINE_TYPE(GScanTokenModifier, g_scan_token_modifier, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des transformations d'octets. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_modifier_class_init(GScanTokenModifierClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_modifier_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_token_modifier_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance à initialiser. * +* * +* Description : Initialise une instance de transformation d'octets. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_modifier_init(GScanTokenModifier *modifier) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_modifier_dispose(GScanTokenModifier *modifier) +{ + G_OBJECT_CLASS(g_scan_token_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_token_modifier_finalize(GScanTokenModifier *modifier) +{ + G_OBJECT_CLASS(g_scan_token_modifier_parent_class)->finalize(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* * +* Description : Fournit le nom d'appel d'un modificateur pour motif. * +* * +* Retour : Désignation humaine. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *g_scan_token_modifier_get_name(const GScanTokenModifier *modifier) +{ + char *result; /* Désignation à retourner */ + GScanTokenModifierClass *class; /* Classe à activer */ + + class = G_SCAN_TOKEN_MODIFIER_GET_CLASS(modifier); + + result = class->get_name(modifier); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* src = séquence d'octets à traiter. * +* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] * +* count = 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(const GScanTokenModifier *modifier, const sized_binary_t *src, sized_binary_t **dest, size_t *count) +{ + 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); + + return result; + +} diff --git a/src/analysis/scan/patterns/modifier.h b/src/analysis/scan/patterns/modifier.h new file mode 100644 index 0000000..a195ca8 --- /dev/null +++ b/src/analysis/scan/patterns/modifier.h @@ -0,0 +1,62 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * modifier.h - prototypes pour la modification d'une séquence d'octets pour un motif recherché + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_MODIFIER_H +#define _ANALYSIS_SCAN_MODIFIER_H + + +#include +#include + + +#include "../../../common/szstr.h" + + + +#define G_TYPE_SCAN_TOKEN_MODIFIER g_scan_token_modifier_get_type() +#define G_SCAN_TOKEN_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_MODIFIER, GScanTokenModifier)) +#define G_IS_SCAN_TOKEN_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_MODIFIER)) +#define G_SCAN_TOKEN_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_MODIFIER, GScanTokenModifierClass)) +#define G_IS_SCAN_TOKEN_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_MODIFIER)) +#define G_SCAN_TOKEN_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_MODIFIER, GScanTokenModifierClass)) + + +/* Transformation d'une séquence d'octets en une ou plusieurs autres formes (instance) */ +typedef struct _GScanTokenModifier GScanTokenModifier; + +/* Transformation d'une séquence d'octets en une ou plusieurs autres formes (classe) */ +typedef struct _GScanTokenModifierClass GScanTokenModifierClass; + + +/* Indique le type défini pour une transformation d'une séquence d'octets. */ +GType g_scan_token_modifier_get_type(void); + +/* Fournit le nom d'appel d'un modificateur pour motif. */ +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 *); + + + +#endif /* _ANALYSIS_SCAN_MODIFIER_H */ diff --git a/src/analysis/scan/patterns/modifiers/Makefile.am b/src/analysis/scan/patterns/modifiers/Makefile.am new file mode 100644 index 0000000..fe5263c --- /dev/null +++ b/src/analysis/scan/patterns/modifiers/Makefile.am @@ -0,0 +1,17 @@ + +noinst_LTLIBRARIES = libanalysisscanpatternsmodifiers.la + + +libanalysisscanpatternsmodifiers_la_SOURCES = \ + hex.h hex.c \ + list-int.h \ + list.h list.c \ + plain.h plain.c \ + rev.h rev.c + +libanalysisscanpatternsmodifiers_la_CFLAGS = $(LIBGOBJ_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libanalysisscanpatternsmodifiers_la_SOURCES:%c=) diff --git a/src/analysis/scan/patterns/modifiers/hex.c b/src/analysis/scan/patterns/modifiers/hex.c new file mode 100644 index 0000000..cf1583c --- /dev/null +++ b/src/analysis/scan/patterns/modifiers/hex.c @@ -0,0 +1,252 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hex.c - transformation en version hexadécimale 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 . + */ + + +#include "hex.h" + + +#include +#include + + +#include "../modifier-int.h" + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des transformations en hexadécimal. */ +static void g_scan_hex_modifier_class_init(GScanHexModifierClass *klass); + +/* Initialise une instance de transformation en hexadécimal. */ +static void g_scan_hex_modifier_init(GScanHexModifier *); + +/* Supprime toutes les références externes. */ +static void g_scan_hex_modifier_dispose(GScanHexModifier *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_hex_modifier_finalize(GScanHexModifier *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit le nom d'appel d'un modificateur pour motif. */ +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 *); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une transformation d'une séquence d'octets dans sa version hexadécimale. */ +G_DEFINE_TYPE(GScanHexModifier, g_scan_hex_modifier, G_TYPE_SCAN_TOKEN_MODIFIER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des transformations en hexadécimal. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_hex_modifier_class_init(GScanHexModifierClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenModifierClass *modifier; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_hex_modifier_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_hex_modifier_finalize; + + modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass); + + modifier->get_name = (get_scan_modifier_name_fc)g_scan_hex_modifier_get_name; + + modifier->transform = (transform_scan_token_fc)g_scan_hex_modifier_transform; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance à initialiser. * +* * +* Description : Initialise une instance de transformation en hexadécimal. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_hex_modifier_init(GScanHexModifier *modifier) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_hex_modifier_dispose(GScanHexModifier *modifier) +{ + G_OBJECT_CLASS(g_scan_hex_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_hex_modifier_finalize(GScanHexModifier *modifier) +{ + G_OBJECT_CLASS(g_scan_hex_modifier_parent_class)->finalize(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit un modificateur fournistant une vue hexadécimale. * +* * +* Retour : Mécanisme mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenModifier *g_scan_hex_modifier_new(void) +{ + GScanTokenModifier *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_HEX_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_hex_modifier_get_name(const GScanHexModifier *modifier) +{ + char *result; /* Désignation à retourner */ + + result = strdup("hex"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* src = séquence d'octets à traiter. * +* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] * +* count = 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_hex_modifier_transform(const GScanHexModifier *modifier, const sized_binary_t *src, sized_binary_t **dest, size_t *count) +{ + bool result; /* Bilan d'opération à renvoyer*/ + sized_binary_t *binary; /* Raccourci vers le stockage */ + size_t i; /* Boucle de parcours */ + + static char *alphabet = "0123456789abcdef"; + + result = true; + + *dest = malloc(1 * sizeof(sized_binary_t)); + *count = 1; + + binary = &(*dest)[0]; + + binary->len = src->len * 2; + binary->data = malloc(binary->len); + + for (i = 0; i < src->len; i++) + { + binary->data[i * 2 + 0] = alphabet[src->data[i] >> 4]; + binary->data[i * 2 + 1] = alphabet[src->data[i] & 0xf]; + } + + return result; + +} diff --git a/src/analysis/scan/patterns/modifiers/hex.h b/src/analysis/scan/patterns/modifiers/hex.h new file mode 100644 index 0000000..1a9b410 --- /dev/null +++ b/src/analysis/scan/patterns/modifiers/hex.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hex.h - prototypes pour la transformation en version hexadécimale 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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_MODIFIERS_HEX_H +#define _ANALYSIS_SCAN_PATTERNS_MODIFIERS_HEX_H + + +#include + + +#include "../modifier.h" + + + +#define G_TYPE_SCAN_HEX_MODIFIER g_scan_hex_modifier_get_type() +#define G_SCAN_HEX_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_HEX_MODIFIER, GScanHexModifier)) +#define G_IS_SCAN_HEX_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_HEX_MODIFIER)) +#define G_SCAN_HEX_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_HEX_MODIFIER, GScanHexModifierClass)) +#define G_IS_SCAN_HEX_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_HEX_MODIFIER)) +#define G_SCAN_HEX_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_HEX_MODIFIER, GScanHexModifierClass)) + + +/* Transformation d'une séquence d'octets dans sa version hexadécimale (instance) */ +typedef GScanTokenModifier GScanHexModifier; + +/* Transformation d'une séquence d'octets dans sa version hexadécimale (classe) */ +typedef GScanTokenModifierClass GScanHexModifierClass; + + +/* Indique le type défini pour une transformation d'une séquence d'octets dans sa version hexadécimale. */ +GType g_scan_hex_modifier_get_type(void); + +/* Construit un modificateur fournistant une vue hexadécimale. */ +GScanTokenModifier *g_scan_hex_modifier_new(void); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_MODIFIERS_HEX_H */ diff --git a/src/analysis/scan/patterns/modifiers/list-int.h b/src/analysis/scan/patterns/modifiers/list-int.h new file mode 100644 index 0000000..c8ed64b --- /dev/null +++ b/src/analysis/scan/patterns/modifiers/list-int.h @@ -0,0 +1,54 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * list-int.h - prototypes internes pour la gestion d'une liste de transformateurs + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_MODIFIERS_LIST_INT_H +#define _ANALYSIS_SCAN_MODIFIERS_LIST_INT_H + + +#include "list.h" + + +#include "../modifier-int.h" + + + +/* Liste de transformations d'une séquence d'octets (instance) */ +struct _GScanModifierList +{ + GObject parent; /* A laisser en premier */ + + GScanTokenModifier **modifiers; /* Liste de transformateurs */ + size_t count; /* Taille de cette liste */ + +}; + +/* Liste de transformations d'une séquence d'octets (classe) */ +struct _GScanModifierListClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _ANALYSIS_SCAN_MODIFIERS_LIST_INT_H */ diff --git a/src/analysis/scan/patterns/modifiers/list.c b/src/analysis/scan/patterns/modifiers/list.c new file mode 100644 index 0000000..e08d509 --- /dev/null +++ b/src/analysis/scan/patterns/modifiers/list.c @@ -0,0 +1,405 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * list.c - gestion d'une liste de transformateurs + * + * 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 . + */ + + +#include "list.h" + + +#include +#include + + +#include "list-int.h" + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des liste de transformations d'octets. */ +static void g_scan_modifier_list_class_init(GScanModifierListClass *); + +/* Initialise une instance de liste de transformations d'octets. */ +static void g_scan_modifier_list_init(GScanModifierList *); + +/* Supprime toutes les références externes. */ +static void g_scan_modifier_list_dispose(GScanModifierList *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_modifier_list_finalize(GScanModifierList *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit le nom d'appel d'un modificateur pour motif. */ +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 *); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une série de transformations d'octets. */ +G_DEFINE_TYPE(GScanModifierList, g_scan_modifier_list, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des liste de transformations d'octets. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_modifier_list_class_init(GScanModifierListClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenModifierClass *modifier; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_modifier_list_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_modifier_list_finalize; + + modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass); + + modifier->get_name = (get_scan_modifier_name_fc)g_scan_modifier_list_get_name; + + modifier->transform = (transform_scan_token_fc)g_scan_modifier_list_transform; + +} + + +/****************************************************************************** +* * +* Paramètres : list = instance à initialiser. * +* * +* Description : Initialise une instance de liste de transformations d'octets.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_modifier_list_init(GScanModifierList *list) +{ + list->modifiers = NULL; + list->count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : list = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_modifier_list_dispose(GScanModifierList *list) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < list->count; i++) + g_clear_object(&list->modifiers[i]); + + G_OBJECT_CLASS(g_scan_modifier_list_parent_class)->dispose(G_OBJECT(list)); + +} + + +/****************************************************************************** +* * +* Paramètres : list = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_modifier_list_finalize(GScanModifierList *list) +{ + if (list->modifiers != NULL) + free(list->modifiers); + + G_OBJECT_CLASS(g_scan_modifier_list_parent_class)->finalize(G_OBJECT(list)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit une liste de modificateurs d'octets. * +* * +* Retour : Mécanisme mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenModifier *g_scan_modifier_list_new(void) +{ + GScanTokenModifier *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_MODIFIER_LIST, NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : list = liste de modificateurs à étendre. * +* modifier = modificateur à intégrer. * +* * +* Description : Intègre un nouveau transformateur dans une liste. * +* * +* Retour : Bilan de l'ajout : false si un élément similaire est déjà là.* +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_modifier_list_add(GScanModifierList *list, GScanTokenModifier *modifier) +{ + bool result; /* Bilan à retourner */ + char *name; /* Désignation du modificateur */ + size_t i; /* Boucle de parcours */ + char *other; /* Désignation de ses collègues*/ + + /* Recherche d'une redondance */ + + /** + * Note : deux listes identiques passent sans soucis. + * TODO : comparer les transformateurs ? + */ + + result = true; + + if (!G_IS_SCAN_MODIFIER_LIST(modifier)) + { + name = g_scan_token_modifier_get_name(modifier); + + for (i = 0; i < list->count && result; i++) + { + if (G_IS_SCAN_MODIFIER_LIST(list->modifiers[i])) + continue; + + other = g_scan_token_modifier_get_name(list->modifiers[i]); + + result = (strcmp(name, other) != 0); + + free(other); + + } + + } + + free(name); + + if (!result) + goto done; + + /* Inclusion dans la liste */ + + list->modifiers = realloc(list->modifiers, ++list->count * sizeof(GScanTokenModifier *)); + + list->modifiers[list->count - 1] = modifier; + g_object_ref(G_OBJECT(modifier)); + + done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : list = série à consulter. * +* * +* Description : Indique le nombre de transformateurs intégrés dans la liste. * +* * +* Retour : Nombre de modificateurs représentés. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_scan_modifier_list_count(const GScanModifierList *list) +{ + size_t result; /* Quantité à retourner */ + + result = list->count; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : list = série à consulter. * +* index = indice du paramètre à retourner. * +* * +* Description : Fournit un transformateur donné de la liste. * +* * +* Retour : Modificateur inclus dans la liste ou NULL si mauvais indice. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenModifier *g_scan_modifier_list_get(const GScanModifierList *list, size_t index) +{ + GScanTokenModifier *result; /* Instance à retourner */ + + assert(index < list->count); + + if (index < list->count) + { + result = list->modifiers[index]; + g_object_ref(G_OBJECT(result)); + } + + else + result = 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_modifier_list_get_name(const GScanModifierList *modifier) +{ + char *result; /* Désignation à retourner */ + + result = strdup("(list)"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* src = séquence d'octets à traiter. * +* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] * +* count = 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_modifier_list_transform(const GScanModifierList *modifier, const sized_binary_t *src, sized_binary_t **dest, size_t *count) +{ + 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; + *count = 0; + + for (i = 0; i < modifier->count; i++) + { + result = g_scan_token_modifier_transform(modifier->modifiers[i], src, &extra, &extra_count); + if (!result) goto exit; + + new = (*dest) + *count; + + *count += extra_count; + *dest = realloc(*dest, *count * 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 < *count; i++) + exit_szstr(dest[i]); + + if (*dest != NULL) + free(*dest); + + *dest = NULL; + *count = 0; + + } + + return result; + +} diff --git a/src/analysis/scan/patterns/modifiers/list.h b/src/analysis/scan/patterns/modifiers/list.h new file mode 100644 index 0000000..abd1eae --- /dev/null +++ b/src/analysis/scan/patterns/modifiers/list.h @@ -0,0 +1,68 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * list.h - prototypes pour la gestion d'une liste de transformateurs + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_MODIFIERS_LIST_H +#define _ANALYSIS_SCAN_MODIFIERS_LIST_H + + +#include +#include + + +#include "../modifier.h" + + + +#define G_TYPE_SCAN_MODIFIER_LIST g_scan_modifier_list_get_type() +#define G_SCAN_MODIFIER_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MODIFIER_LIST, GScanModifierList)) +#define G_IS_SCAN_MODIFIER_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MODIFIER_LIST)) +#define G_SCAN_MODIFIER_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MODIFIER_LIST, GScanModifierListClass)) +#define G_IS_SCAN_MODIFIER_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MODIFIER_LIST)) +#define G_SCAN_MODIFIER_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MODIFIER_LIST, GScanModifierListClass)) + + +/* Liste de transformations d'une séquence d'octets (instance) */ +typedef struct _GScanModifierList GScanModifierList; + +/* Liste de transformations d'une séquence d'octets (classe) */ +typedef struct _GScanModifierListClass GScanModifierListClass; + + +/* Indique le type défini pour une série de transformations d'octets. */ +GType g_scan_modifier_list_get_type(void); + +/* Construit une liste de modificateurs d'octets. */ +GScanTokenModifier *g_scan_modifier_list_new(void); + +/* Intègre un nouveau transformateur dans une liste. */ +bool g_scan_modifier_list_add(GScanModifierList *, GScanTokenModifier *); + +/* Indique le nombre de transformateurs intégrés dans la liste. */ +size_t g_scan_modifier_list_count(const GScanModifierList *); + +/* Fournit un transformateur donné de la liste. */ +GScanTokenModifier *g_scan_modifier_list_get(const GScanModifierList *, size_t); + + + +#endif /* _ANALYSIS_SCAN_MODIFIERS_LIST_H */ diff --git a/src/analysis/scan/patterns/modifiers/plain.c b/src/analysis/scan/patterns/modifiers/plain.c new file mode 100644 index 0000000..5837d46 --- /dev/null +++ b/src/analysis/scan/patterns/modifiers/plain.c @@ -0,0 +1,245 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain.c - transmission à l'identique 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 . + */ + + +#include "plain.h" + + +#include +#include + + +#include "../modifier-int.h" + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des transmissions à l'identique. */ +static void g_scan_plain_modifier_class_init(GScanPlainModifierClass *klass); + +/* Initialise une instance de transmission à l'identique. */ +static void g_scan_plain_modifier_init(GScanPlainModifier *); + +/* Supprime toutes les références externes. */ +static void g_scan_plain_modifier_dispose(GScanPlainModifier *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_plain_modifier_finalize(GScanPlainModifier *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit le nom d'appel d'un modificateur pour motif. */ +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 *); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une transmission à l'identique d'une séquence d'octets. */ +G_DEFINE_TYPE(GScanPlainModifier, g_scan_plain_modifier, G_TYPE_SCAN_TOKEN_MODIFIER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des transmissions à l'identique. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_plain_modifier_class_init(GScanPlainModifierClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenModifierClass *modifier; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_plain_modifier_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_plain_modifier_finalize; + + modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass); + + modifier->get_name = (get_scan_modifier_name_fc)g_scan_plain_modifier_get_name; + + modifier->transform = (transform_scan_token_fc)g_scan_plain_modifier_transform; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance à initialiser. * +* * +* Description : Initialise une instance de transmission à l'identique. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_plain_modifier_init(GScanPlainModifier *modifier) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_plain_modifier_dispose(GScanPlainModifier *modifier) +{ + G_OBJECT_CLASS(g_scan_plain_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_plain_modifier_finalize(GScanPlainModifier *modifier) +{ + G_OBJECT_CLASS(g_scan_plain_modifier_parent_class)->finalize(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit un modificateur livrant des octets à l'identique. * +* * +* Retour : Mécanisme mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenModifier *g_scan_plain_modifier_new(void) +{ + GScanTokenModifier *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_PLAIN_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_plain_modifier_get_name(const GScanPlainModifier *modifier) +{ + char *result; /* Désignation à retourner */ + + result = strdup("plain"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* src = séquence d'octets à traiter. * +* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] * +* count = 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_plain_modifier_transform(const GScanPlainModifier *modifier, const sized_binary_t *src, sized_binary_t **dest, size_t *count) +{ + bool result; /* Bilan d'opération à renvoyer*/ + sized_binary_t *binary; /* Raccourci vers le stockage */ + + result = true; + + *dest = malloc(1 * sizeof(sized_binary_t)); + *count = 1; + + binary = &(*dest)[0]; + + 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/plain.h b/src/analysis/scan/patterns/modifiers/plain.h new file mode 100644 index 0000000..ecabefd --- /dev/null +++ b/src/analysis/scan/patterns/modifiers/plain.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain.h - prototypes pour la transmission à l'identique 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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_MODIFIERS_PLAIN_H +#define _ANALYSIS_SCAN_PATTERNS_MODIFIERS_PLAIN_H + + +#include + + +#include "../modifier.h" + + + +#define G_TYPE_SCAN_PLAIN_MODIFIER g_scan_plain_modifier_get_type() +#define G_SCAN_PLAIN_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_PLAIN_MODIFIER, GScanPlainModifier)) +#define G_IS_SCAN_PLAIN_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_PLAIN_MODIFIER)) +#define G_SCAN_PLAIN_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_PLAIN_MODIFIER, GScanPlainModifierClass)) +#define G_IS_SCAN_PLAIN_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_PLAIN_MODIFIER)) +#define G_SCAN_PLAIN_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_PLAIN_MODIFIER, GScanPlainModifierClass)) + + +/* Transmission à l'identique d'une séquence d'octets (instance) */ +typedef GScanTokenModifier GScanPlainModifier; + +/* Transmission à l'identique d'une séquence d'octets (classe) */ +typedef GScanTokenModifierClass GScanPlainModifierClass; + + +/* Indique le type défini pour une transmission à l'identique d'une séquence d'octets. */ +GType g_scan_plain_modifier_get_type(void); + +/* Construit un modificateur livrant des octets à l'identique. */ +GScanTokenModifier *g_scan_plain_modifier_new(void); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_MODIFIERS_PLAIN_H */ diff --git a/src/analysis/scan/patterns/modifiers/rev.c b/src/analysis/scan/patterns/modifiers/rev.c new file mode 100644 index 0000000..d22b549 --- /dev/null +++ b/src/analysis/scan/patterns/modifiers/rev.c @@ -0,0 +1,247 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * rev.c - transormation via inversement 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 . + */ + + +#include "rev.h" + + +#include +#include + + +#include "../modifier-int.h" + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des transmissions via inversement. */ +static void g_scan_reverse_modifier_class_init(GScanReverseModifierClass *klass); + +/* Initialise une instance de transmission via inversement. */ +static void g_scan_reverse_modifier_init(GScanReverseModifier *); + +/* Supprime toutes les références externes. */ +static void g_scan_reverse_modifier_dispose(GScanReverseModifier *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_reverse_modifier_finalize(GScanReverseModifier *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit le nom d'appel d'un modificateur pour motif. */ +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 *); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une transormation via inversement d'une séquence d'octets. */ +G_DEFINE_TYPE(GScanReverseModifier, g_scan_reverse_modifier, G_TYPE_SCAN_TOKEN_MODIFIER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des transmissions via inversement. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_reverse_modifier_class_init(GScanReverseModifierClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenModifierClass *modifier; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_reverse_modifier_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_reverse_modifier_finalize; + + modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass); + + modifier->get_name = (get_scan_modifier_name_fc)g_scan_reverse_modifier_get_name; + + modifier->transform = (transform_scan_token_fc)g_scan_reverse_modifier_transform; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance à initialiser. * +* * +* Description : Initialise une instance de transmission via inversement. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_reverse_modifier_init(GScanReverseModifier *modifier) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_reverse_modifier_dispose(GScanReverseModifier *modifier) +{ + G_OBJECT_CLASS(g_scan_reverse_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_reverse_modifier_finalize(GScanReverseModifier *modifier) +{ + G_OBJECT_CLASS(g_scan_reverse_modifier_parent_class)->finalize(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit un modificateur livrant des octets inversés. * +* * +* Retour : Mécanisme mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenModifier *g_scan_reverse_modifier_new(void) +{ + GScanTokenModifier *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_REVERSE_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_reverse_modifier_get_name(const GScanReverseModifier *modifier) +{ + char *result; /* Désignation à retourner */ + + result = strdup("rev"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* src = séquence d'octets à traiter. * +* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] * +* count = 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_reverse_modifier_transform(const GScanReverseModifier *modifier, const sized_binary_t *src, sized_binary_t **dest, size_t *count) +{ + bool result; /* Bilan d'opération à renvoyer*/ + sized_binary_t *binary; /* Raccourci vers le stockage */ + size_t i; /* Boucle de parcours */ + + result = true; + + *dest = malloc(1 * sizeof(sized_binary_t)); + *count = 1; + + binary = &(*dest)[0]; + + binary->len = src->len; + binary->data = malloc(binary->len); + + for (i = 0; i < src->len; i++) + binary->data[src->len - i - 1] = src->data[i]; + + return result; + +} diff --git a/src/analysis/scan/patterns/modifiers/rev.h b/src/analysis/scan/patterns/modifiers/rev.h new file mode 100644 index 0000000..5b4e398 --- /dev/null +++ b/src/analysis/scan/patterns/modifiers/rev.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * rev.h - prototypes pour la transormation via inversement 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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_MODIFIERS_REV_H +#define _ANALYSIS_SCAN_PATTERNS_MODIFIERS_REV_H + + +#include + + +#include "../modifier.h" + + + +#define G_TYPE_SCAN_REVERSE_MODIFIER g_scan_reverse_modifier_get_type() +#define G_SCAN_REVERSE_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_REVERSE_MODIFIER, GScanReverseModifier)) +#define G_IS_SCAN_REVERSE_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_REVERSE_MODIFIER)) +#define G_SCAN_REVERSE_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_REVERSE_MODIFIER, GScanReverseModifierClass)) +#define G_IS_SCAN_REVERSE_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_REVERSE_MODIFIER)) +#define G_SCAN_REVERSE_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_REVERSE_MODIFIER, GScanReverseModifierClass)) + + +/* Transormation via inversement d'une séquence d'octets (instance) */ +typedef GScanTokenModifier GScanReverseModifier; + +/* Transormation via inversement d'une séquence d'octets (classe) */ +typedef GScanTokenModifierClass GScanReverseModifierClass; + + +/* Indique le type défini pour une transormation via inversement d'une séquence d'octets. */ +GType g_scan_reverse_modifier_get_type(void); + +/* Construit un modificateur livrant des octets inversés. */ +GScanTokenModifier *g_scan_reverse_modifier_new(void); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_MODIFIERS_REV_H */ diff --git a/src/analysis/scan/patterns/token-int.h b/src/analysis/scan/patterns/token-int.h index a9667c9..294a3b1 100644 --- a/src/analysis/scan/patterns/token-int.h +++ b/src/analysis/scan/patterns/token-int.h @@ -44,6 +44,8 @@ struct _GStringToken { GSearchPattern parent; /* A laisser en premier */ + GScanTokenNode *root; /* Motif à rechercher */ + }; /* Encadrement d'une bribe de recherche textuelle (classe) */ @@ -57,5 +59,9 @@ struct _GStringTokenClass }; +/* Met en place un gestionnaire de recherche de binaire. */ +bool g_string_token_create(GStringToken *, GScanTokenNode *); + + #endif /* _ANALYSIS_SCAN_PATTERNS_TOKEN_INT_H */ diff --git a/src/analysis/scan/patterns/token.c b/src/analysis/scan/patterns/token.c index d8a5cbc..cc2d87a 100644 --- a/src/analysis/scan/patterns/token.c +++ b/src/analysis/scan/patterns/token.c @@ -25,12 +25,18 @@ #include +#include #include "token-int.h" +#include "../../../common/cpp.h" +#include "../../../core/logs.h" +/* ------------------------- CIBLAGE DES SEQUENCES D'OCTETS ------------------------- */ + + /* Initialise la classe des bribes de recherche textuelle. */ static void g_string_token_class_init(GStringTokenClass *); @@ -45,6 +51,22 @@ static void g_string_token_finalize(GStringToken *); +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Affiche un motif de recherche au format texte. */ +static void g_string_token_output_to_text(const GStringToken *, GScanContext *, int); + +/* Affiche un motif de recherche au format JSON. */ +static void g_string_token_output_to_json(const GStringToken *, GScanContext *, const sized_string_t *, unsigned int, int); + + + +/* ---------------------------------------------------------------------------------- */ +/* CIBLAGE DES SEQUENCES D'OCTETS */ +/* ---------------------------------------------------------------------------------- */ + + /* Indique le type défini pour une bribe de recherche textuelle. */ G_DEFINE_TYPE(GStringToken, g_string_token, G_TYPE_SEARCH_PATTERN); @@ -73,9 +95,8 @@ static void g_string_token_class_init(GStringTokenClass *klass) pattern = G_SEARCH_PATTERN_CLASS(klass); - //pattern->prepare = (prepare_pattern_fc)g_string_token_prepare; - //pattern->analyze = (analyze_pattern_fc)g_string_token_analyze; - //pattern->count = (count_pattern_matchs_fc); + pattern->to_text = (output_pattern_to_text_fc)g_string_token_output_to_text; + pattern->to_json = (output_pattern_to_json_fc)g_string_token_output_to_json; } @@ -94,6 +115,7 @@ static void g_string_token_class_init(GStringTokenClass *klass) static void g_string_token_init(GStringToken *token) { + token->root = NULL; } @@ -138,6 +160,33 @@ static void g_string_token_finalize(GStringToken *token) /****************************************************************************** * * +* Paramètres : token = encadrement de motif à initialiser pleinement. * +* root = représentation du motif à recherche. * +* * +* Description : Met en place un gestionnaire de recherche de binaire. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_string_token_create(GStringToken *token, GScanTokenNode *root) +{ + bool result; /* Bilan à retourner */ + + result = true; + + token->root = root; + g_object_ref(G_OBJECT(root)); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : token = définition de la bribe à enregistrer. * * context = contexte de l'analyse à mener. * * backend = moteur de recherche à préchauffer. * @@ -151,7 +200,7 @@ static void g_string_token_finalize(GStringToken *token) * * ******************************************************************************/ -bool g_string_token_enroll(GStringToken *token, GScanContext *context, GEngineBackend *backend, size_t maxsize) +bool g_string_token_enroll__old(GStringToken *token, GScanContext *context, GEngineBackend *backend, size_t maxsize) { bool result; /* Statut à retourner */ GStringTokenClass *class; /* Classe de l'instance */ @@ -166,6 +215,16 @@ bool g_string_token_enroll(GStringToken *token, GScanContext *context, GEngineBa } +bool g_string_token_enroll(GStringToken *token, GScanContext *context, GEngineBackend *backend, size_t maxsize) +{ + bool result; /* Statut à retourner */ + + result = g_scan_token_node_enroll(token->root, context, backend, maxsize); + + return result; + +} + /****************************************************************************** * * @@ -182,7 +241,7 @@ bool g_string_token_enroll(GStringToken *token, GScanContext *context, GEngineBa * * ******************************************************************************/ -void g_string_token_check(const GStringToken *token, GScanContext *context, GBinContent *content, pending_matches_t *matches) +void g_string_token_check__old(const GStringToken *token, GScanContext *context, GBinContent *content, pending_matches_t *matches) { GStringTokenClass *class; /* Classe de l'instance */ @@ -191,3 +250,114 @@ void g_string_token_check(const GStringToken *token, GScanContext *context, GBin class->check(token, context, content, matches); } + +void g_string_token_check(const GStringToken *token, GScanContext *context, GBinContent *content, pending_matches_t *matches) +{ + g_scan_token_node_check(token->root, context, content, matches, NULL); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : pattern = définition de motif à considérer. * +* context = contexte de l'analyse à mener. * +* fd = canal d'écriture. * +* * +* Description : Affiche un motif de recherche au format texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_string_token_output_to_text(const GStringToken *pattern, GScanContext *context, int fd) +{ + const GScanMatch **matches; /* Correspondances établies */ + size_t count; /* Quantité de cette liste */ + size_t i; /* Boucle de parcours */ + + matches = g_scan_context_get_full_matches(context, G_SEARCH_PATTERN(pattern), &count); + + for (i = 0; i < count; i++) + g_scan_match_output_to_text(matches[i], fd); + +} + + +/****************************************************************************** +* * +* Paramètres : pattern = définition de motif à considérer. * +* context = contexte de l'analyse à mener. * +* padding = éventuel bourrage initial à placer ou NULL. * +* level = profondeur actuelle. * +* fd = canal d'écriture. * +* * +* Description : Affiche un motif de recherche au format JSON. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_string_token_output_to_json(const GStringToken *pattern, GScanContext *context, const sized_string_t *padding, unsigned int level, int fd) +{ + unsigned int i; /* Boucle de parcours #1 */ + const GScanMatch **matches; /* Correspondances établies */ + size_t count; /* Quantité de cette liste */ + char value[ULLONG_MAXLEN]; /* Impression de la position */ + int ret; /* Bilan d'une conversion */ + size_t k; /* Boucle de parcours #2 */ + bool trailing; /* Virgule finale */ + + matches = g_scan_context_get_full_matches(context, G_SEARCH_PATTERN(pattern), &count); + + /* Nombre de correspondances */ + + for (i = 0; i < level; i++) + write(fd, padding->data, padding->len); + + write(fd, "\"match_count\": ", 15); + + ret = snprintf(value, ULLONG_MAXLEN, "%zu", count); + + if (ret > 0) + write(fd, value, ret); + + else + { + log_simple_message(LMT_EXT_ERROR, "Error while converting value!"); + write(fd, "null", 4); + } + + write(fd, ",\n", 2); + + /* Détail des correspondances */ + + for (i = 0; i < level; i++) + write(fd, padding->data, padding->len); + + write(fd, "\"matches\": [\n", 13); + + for (k = 0; k < count; k++) + { + trailing = ((k + 1) < count); + + g_scan_match_output_to_json(matches[k], padding, level + 1, fd, trailing); + + } + + for (i = 0; i < level; i++) + write(fd, padding->data, padding->len); + + write(fd, "]\n", 2); + +} diff --git a/src/analysis/scan/patterns/token.h b/src/analysis/scan/patterns/token.h index c1cb173..879d912 100644 --- a/src/analysis/scan/patterns/token.h +++ b/src/analysis/scan/patterns/token.h @@ -29,6 +29,7 @@ #include "backend.h" +#include "tokens/node.h" #include "../matches/pending.h" diff --git a/src/analysis/scan/patterns/tokens/Makefile.am b/src/analysis/scan/patterns/tokens/Makefile.am index 00cff2a..7fb515f 100644 --- a/src/analysis/scan/patterns/tokens/Makefile.am +++ b/src/analysis/scan/patterns/tokens/Makefile.am @@ -3,11 +3,23 @@ noinst_LTLIBRARIES = libanalysisscanpatternstokens.la libanalysisscanpatternstokens_la_SOURCES = \ + atom.h atom.c \ + hex-int.h \ + hex.h hex.c \ + node-int.h \ + node.h node.c \ + plain-int.h \ plain.h plain.c +libanalysisscanpatternstokens_la_LIBADD = \ + nodes/libanalysisscanpatternstokensnodes.la + libanalysisscanpatternstokens_la_CFLAGS = $(LIBGOBJ_CFLAGS) devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) dev_HEADERS = $(libanalysisscanpatternstokens_la_SOURCES:%c=) + + +SUBDIRS = nodes diff --git a/src/analysis/scan/patterns/tokens/atom.c b/src/analysis/scan/patterns/tokens/atom.c new file mode 100644 index 0000000..fcb585d --- /dev/null +++ b/src/analysis/scan/patterns/tokens/atom.c @@ -0,0 +1,364 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * atom.c - détermination d'atomes à partir de motifs + * + * 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 . + */ + + +#include "atom.h" + + +#include +#include + + + +/** + * Remplacement des fonctions de dans support des locales. + */ + +#define IS_CH_LETTER(ch) (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z')) + +#define MAKE_CH_UPPER(ch) (ch & 0xdf) +#define MAKE_CH_LOWER(ch) (ch | 0x20) + + + +/****************************************************************************** +* * +* Paramètres : ch = octet dont la valeur est à analyser. * +* seen = suivi des octets déjà rencontrés. [OUT] * +* letters = nombre de lettres rencontrées. [OUT] * +* * +* Description : Note l'intêret de rechercher un octet particulier. * +* * +* Retour : Note positive ou négative. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int rate_byte_quality(bin_t ch, bitfield_t *seen, size_t *letters) +{ + int result; /* Note à retourner */ + + switch (ch) + { + case 0x00: + case 0x20: + case 0x90: + case 0xcc: + case 0xff: + result = 12; + break; + + case 'A' ... 'Z': + case 'z' ... 'z': + if (letters == NULL) + result = 20; + else + { + result = 18; + (*letters)++; + } + break; + + default: + result = 20; + break; + + } + + set_in_bit_field(seen, ch, 1); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : seen = suivi des octets déjà rencontrés. * +* max = nombre d'octets considérés à la base. * +* * +* Description : Termine la notation d'un ensemble d'octets. * +* * +* Retour : Note positive ou négative. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int finish_quality_rating(const bitfield_t *seen, size_t max) +{ + int result; /* Note à retourner */ + size_t uniq; /* Quantié d'octets uniques */ + bool bad; /* Indice de mauvaise qualité */ + + uniq = popcount_for_bit_field(seen); + + if (uniq == 1) + { + bad = test_in_bit_field(seen, 0x00) + || test_in_bit_field(seen, 0x20) + || test_in_bit_field(seen, 0x90) + || test_in_bit_field(seen, 0xcc) + || test_in_bit_field(seen, 0xff); + + result = (bad ? -10 * max : 2); + + } + + else + result = uniq * 2; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : raw = définition de la bribe à enregistrer. * +* maxsize = taille max. des atomes (mise en commun optimisée). * +* atom = informations de suivi constituées. [OUT] * +* letters = nombre de lettres rencontrées. [OUT] * +* * +* Description : Détermine la portion idéale de recherche. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void find_best_atom(const sized_binary_t *raw, size_t maxsize, tracked_scan_atom_t *atom, size_t *letters) +{ + size_t i; /* Boucle de parcours #1 */ + bin_t ch; /* Octets à étudier */ + size_t best_letters; /* Mémorisation de décompte */ + size_t *ptr_letters; /* Pointeur vers le décompte */ + int best_rating; /* Meilleur notation obtenue */ + bitfield_t *seen; /* Mémorise les octets déjà vus*/ + size_t max_loop; /* Limitation des itérations */ + size_t k; /* Boucle de parcours #2 */ + size_t local_letters; /* Décompte courant des lettres*/ + int local_rating; /* Notation courante */ + + /* Si la chaîne fournie est plus petite que la taille d'un atome... */ + if (raw->len <= maxsize) + { + atom->pos = 0; + atom->len = raw->len; + atom->rem = 0; + + if (letters != NULL) + { + *letters = 0; + + for (i = 0; i < raw->len; i++) + { + ch = raw->data[i]; + + if (IS_CH_LETTER(ch)) + (*letters)++; + + } + + } + + } + + /* ... ou si une sélection doit s'opérer */ + else + { + /* Etablissement d'une mesure de référence à la position 0 */ + + atom->pos = 0; + atom->len = maxsize; + + ptr_letters = (letters != NULL ? &best_letters : NULL); + + best_letters = 0; + best_rating = 0; + + seen = create_bit_field(256, false); + + for (k = 0; k < maxsize; k++) + best_rating += rate_byte_quality(raw->data[k], seen, ptr_letters); + + best_rating += finish_quality_rating(seen, maxsize); + + /* Parcours du reste du contenu */ + + max_loop = (raw->len - maxsize); + + ptr_letters = (letters != NULL ? &local_letters : NULL); + + for (i = 1; i < max_loop; i++) + { + local_letters = 0; + local_rating = 0; + + reset_all_in_bit_field(seen); + + for (k = 0; k < maxsize; k++) + local_rating += rate_byte_quality(raw->data[i + k], seen, ptr_letters); + + local_rating += finish_quality_rating(seen, maxsize); + + if (local_rating > best_rating) + { + atom->pos = i; + + best_letters = local_letters; + best_rating = local_rating; + + } + + } + + /* Conclusion */ + + delete_bit_field(seen); + + atom->rem = raw->len - atom->pos - maxsize; + + if (letters != NULL) + *letters = best_letters; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : src = chaîne ed référence à dupliquer. * +* count = nombre de lettres présentes. * +* * +* Description : Etablit la liste des cas de figures ignorant la casse. * +* * +* Retour : Liste de toutes les combinaisons possibles. * +* * +* Remarques : - * +* * +******************************************************************************/ + +sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, size_t count) +{ + sized_binary_t *result; /* Liste à retourner */ + size_t i; /* Boucle de parcours #1 */ + size_t replaced; /* 2^(alternatives créées) */ +#ifndef NDEBUG + size_t check; /* Validation du compte max. */ +#endif + bin_t ch; /* Octet à recopier */ + size_t k; /* Boucle de parcours #2 */ + size_t divisor; /* Taille de la découpe */ + size_t quotient; /* Reste de la position */ + + count *= 2; + + /* Création du réceptacle */ + + result = malloc(count * sizeof(tracked_scan_atom_t)); + + for (i = 0; i < count; i++) + { + result[i].data = malloc(src->len); + result[i].len = src->len; + } + + /* Remplissage */ + + replaced = 2; + +#ifndef NDEBUG + check = 1; +#endif + + for (i = 0; i < src->len; i++) + { + ch = src->data[i]; + + if (IS_CH_LETTER(ch)) + { + for (k = 0; k < count; k++) + { + divisor = count / replaced; + quotient = k / divisor; + + if ((quotient % 2) == 0) + result[k].data[i] = MAKE_CH_UPPER(ch); + else + result[k].data[i] = MAKE_CH_LOWER(ch); + + } + + replaced *= 2; + +#ifndef NDEBUG + check++; + assert((check - 1) <= count); +#endif + + } + else + for (k = 0; k < count; k++) + result[k].data[i] = ch; + + } + + assert((check - 1) == count); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : raw = définition de la bribe à enregistrer. * +* context = contexte de l'analyse à mener. * +* backend = moteur de recherche à préchauffer. * +* atom = informations de suivi constituées. [OUT] * +* * +* Description : Enregistre l'atome déterminé d'une série d'octets. * +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool enroll_prepared_atom(const sized_binary_t *raw, GScanContext *context, GEngineBackend *backend, tracked_scan_atom_t *atom) +{ + bool result; /* Statut à retourner */ + const bin_t *data; /* Données à rechercher */ + + data = raw->data + atom->pos; + + atom->pid = g_engine_backend_enroll_plain_pattern(backend, context, data, atom->len); + + result = (atom->pid != INVALID_PATTERN_ID); + + return result; + +} diff --git a/src/analysis/scan/patterns/tokens/atom.h b/src/analysis/scan/patterns/tokens/atom.h new file mode 100644 index 0000000..daa1f16 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/atom.h @@ -0,0 +1,68 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * atom.h - prototypes pour la détermination d'atomes à partir de motifs + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_ATOM_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_ATOM_H + + +#include + + +#include "../backend.h" +#include "../../context.h" +#include "../../../../arch/vmpa.h" +#include "../../../../common/bits.h" +#include "../../../../common/szstr.h" + + + +/* Suivi des motifs réellement recherchés */ +typedef struct _tracked_scan_atom_t +{ + phys_t pos; /* Début de sélection atomique */ + phys_t len; /* Taille de ladite sélection */ + phys_t rem; /* Reste après l'atome */ + + patid_t pid; /* Identifiant de la bribe */ + +} tracked_scan_atom_t; + + +/* Note l'intêret de rechercher un octet particulier. */ +int rate_byte_quality(bin_t, bitfield_t *, size_t *); + +/* Termine la notation d'un ensemble d'octets. */ +int finish_quality_rating(const bitfield_t *, size_t); + +/* Détermine la portion idéale de recherche. */ +void find_best_atom(const sized_binary_t *, size_t , tracked_scan_atom_t *, size_t *); + +/* Etablit la liste des cas de figures ignorant la casse. */ +sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *, size_t); + +/* Enregistre l'atome déterminé d'une série d'octets. */ +bool enroll_prepared_atom(const sized_binary_t *, GScanContext *, GEngineBackend *, tracked_scan_atom_t *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_ATOM_H */ diff --git a/src/analysis/scan/patterns/tokens/hex-int.h b/src/analysis/scan/patterns/tokens/hex-int.h new file mode 100644 index 0000000..f0460c8 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/hex-int.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hex-int.h - prototypes internes pour la recherche de morceaux de binaire + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_INT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_INT_H + + +#include "hex.h" + + +#include "atom.h" +#include "../token-int.h" + + + +/* Encadrement d'une recherche de morceaux de binaire (instance) */ +struct _GScanHexBytes +{ + GStringToken parent; /* A laisser en premier */ + +}; + +/* Encadrement d'une recherche de morceaux de binaire (classe) */ +struct _GScanHexBytesClass +{ + GStringTokenClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un gestionnaire de recherche de binaire. */ +bool g_scan_hex_bytes_create(GScanHexBytes *, GScanTokenNode *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_INT_H */ diff --git a/src/analysis/scan/patterns/tokens/hex.c b/src/analysis/scan/patterns/tokens/hex.c new file mode 100644 index 0000000..c1cdbdf --- /dev/null +++ b/src/analysis/scan/patterns/tokens/hex.c @@ -0,0 +1,457 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hex.c - recherche de morceaux de binaire + * + * 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 . + */ + + +#include "hex.h" + + +#include +#include + + +#include "hex-int.h" + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des recherches de texte brut. */ +static void g_scan_hex_bytes_class_init(GScanHexBytesClass *klass); + +/* Initialise une instance de recherche de texte brut. */ +static void g_scan_hex_bytes_init(GScanHexBytes *); + +/* Supprime toutes les références externes. */ +static void g_scan_hex_bytes_dispose(GScanHexBytes *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_hex_bytes_finalize(GScanHexBytes *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Affiche un motif de recherche au format texte. */ +static void g_scan_hex_bytes_output_to_text(const GScanHexBytes *, GScanContext *, int); + +/* Affiche un motif de recherche au format JSON. */ +static void g_scan_hex_bytes_output_to_json(const GScanHexBytes *, GScanContext *, const sized_string_t *, unsigned int, int); + +/* Inscrit la définition d'un motif dans un moteur de recherche. */ +//static bool g_scan_hex_bytes_enroll(GScanHexBytes *, GScanContext *, GEngineBackend *, size_t); + +/* Transforme les correspondances locales en trouvailles. */ +//static void g_scan_hex_bytes_check(const GScanHexBytes *, GScanContext *, GBinContent *, pending_matches_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une suite d'octets à retrouver dans un binaire. */ +G_DEFINE_TYPE(GScanHexBytes, g_scan_hex_bytes, G_TYPE_STRING_TOKEN); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des recherches de texte brut. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_hex_bytes_class_init(GScanHexBytesClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GSearchPatternClass *pattern; /* Version de classe ancêtre */ + GStringTokenClass *token; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_hex_bytes_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_hex_bytes_finalize; + + pattern = G_SEARCH_PATTERN_CLASS(klass); + + pattern->to_text = (output_pattern_to_text_fc)g_scan_hex_bytes_output_to_text; + pattern->to_json = (output_pattern_to_json_fc)g_scan_hex_bytes_output_to_json; + + token = G_STRING_TOKEN_CLASS(klass); + + //token->enroll = (enroll_token_fc)g_scan_hex_bytes_enroll; + //token->check = (check_token_fc)g_scan_hex_bytes_check; + +} + + +/****************************************************************************** +* * +* Paramètres : bytes = instance à initialiser. * +* * +* Description : Initialise une instance de recherche de texte brut. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_hex_bytes_init(GScanHexBytes *bytes) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : bytes = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_hex_bytes_dispose(GScanHexBytes *bytes) +{ + G_OBJECT_CLASS(g_scan_hex_bytes_parent_class)->dispose(G_OBJECT(bytes)); + +} + + +/****************************************************************************** +* * +* Paramètres : bytes = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_hex_bytes_finalize(GScanHexBytes *bytes) +{ + G_OBJECT_CLASS(g_scan_hex_bytes_parent_class)->finalize(G_OBJECT(bytes)); + +} + + +/****************************************************************************** +* * +* Paramètres : root = représentation du motif à recherche. * +* * +* Description : Construit un gestionnaire de recherche de texte brut. * +* * +* Retour : Mécanismes mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *root) +{ + GSearchPattern *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_HEX_BYTES, NULL); + + if (!g_scan_hex_bytes_create(G_SCAN_HEX_BYTES(result), root)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : bytes = encadrement de motif à initialiser pleinement. * +* root = représentation du motif à recherche. * +* * +* Description : Met en place un gestionnaire de recherche de binaire. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_hex_bytes_create(GScanHexBytes *bytes, GScanTokenNode *root) +{ + bool result; /* Bilan à retourner */ + + result = g_string_token_create(G_STRING_TOKEN(bytes), root); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : pattern = définition de motif à considérer. * +* context = contexte de l'analyse à mener. * +* fd = canal d'écriture. * +* * +* Description : Affiche un motif de recherche au format texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_hex_bytes_output_to_text(const GScanHexBytes *pattern, GScanContext *context, int fd) +{ + G_SEARCH_PATTERN_CLASS(g_scan_hex_bytes_parent_class)->to_text(G_SEARCH_PATTERN(pattern), context, fd); + +} + + +/****************************************************************************** +* * +* Paramètres : pattern = définition de motif à considérer. * +* context = contexte de l'analyse à mener. * +* padding = éventuel bourrage initial à placer ou NULL. * +* level = profondeur actuelle. * +* fd = canal d'écriture. * +* * +* Description : Affiche un motif de recherche au format JSON. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_hex_bytes_output_to_json(const GScanHexBytes *pattern, GScanContext *context, const sized_string_t *padding, unsigned int level, int fd) +{ + G_SEARCH_PATTERN_CLASS(g_scan_hex_bytes_parent_class)->to_json(G_SEARCH_PATTERN(pattern), context, padding, level, fd); + + /* TODO */ + +} + +#if 0 + +/****************************************************************************** +* * +* Paramètres : bytes = définition de la bribe à enregistrer. * +* context = contexte de l'analyse à mener. * +* backend = moteur de recherche à préchauffer. * +* maxsize = taille max. des atomes (mise en commun optimisée). * +* * +* Description : Inscrit la définition d'un motif dans un moteur de recherche.* +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_hex_bytes_enroll(GScanHexBytes *bytes, GScanContext *context, GEngineBackend *backend, size_t maxsize) +{ + bool result; /* Statut à retourner */ + size_t i; /* Boucle de parcours #1 */ + tracked_scan_atom_t atom; /* Atome identifié */ + size_t letters; /* Nombre de lettres présentes */ + size_t k; /* Boucle de parcours #2 */ + size_t extra_count; /* Quantité pour l'exhaustivité*/ + sized_binary_t *extra; /* Couverture supplémntaire */ + size_t remaining; /* Quantité restant à traiter */ + + /* Génération d'une base de chaînes à couvrir */ + + if (bytes->modifier == NULL) + { + bytes->raw = malloc(sizeof(sized_binary_t)); + bytes->count = 1; + + szstrdup(&bytes[0].raw[0], &bytes->orig); + + result = true; + + } + else + result = g_scan_token_modifier_transform(bytes->modifier, &bytes->orig, &bytes->raw, &bytes->count); + + if (!result) + goto exit; + + /* Préparation pour la mémorisation des atomes */ + + bytes->atoms = malloc(bytes->count * sizeof(tracked_scan_atom_t)); + + /* Recherche des atomes */ + + for (i = 0; i < bytes->count; i++) + { + if (bytes->flags & SPBF_CASE_INSENSITIVE) + { + find_best_atom(&bytes->raw[i], maxsize, &atom, &letters); + + if (letters == 0) + bytes->atoms[i] = atom; + + /* Insertion des combinaisons pour couvrir toutes les casses */ + else + { + for (k = 0, extra_count = 1; k < letters; k++, extra_count *= 2) + ; + + extra = make_atoms_case_insensitive(&bytes->raw[i], extra_count); + + remaining = bytes->count - i - 1; + + bytes->count += (extra_count - 1); + + bytes->raw = realloc(bytes->raw, bytes->count * sizeof(sized_binary_t)); + + memmove(&bytes->raw[i + extra_count], &bytes->raw[i + 1], remaining * sizeof(sized_binary_t)); + + for (k = 0; k < extra_count; k++) + bytes->raw[i + k] = extra[k]; + + free(extra); + + bytes->atoms = realloc(bytes->raw, bytes->count * sizeof(tracked_scan_atom_t)); + + for (k = 0; k < extra_count; k++) + bytes->atoms[i + k] = atom; + + i += extra_count - 1; + + } + + } + + else + find_best_atom(&bytes->raw[i], maxsize, &bytes->atoms[i], &letters); + + } + + /* Enregistrements en masse */ + + + for (i = 0; i < bytes->count && result; i++) + result = enroll_prepared_atom(&bytes->raw[i], context, backend, &bytes->atoms[i]); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : bytes = définition de la bribe à manipuler. * +* context = contexte de l'analyse à mener. * +* content = accès au contenu brut pour vérifications (optim.) * +* matches = suivi des correspondances à consolider. * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_hex_bytes_check(const GScanHexBytes *bytes, GScanContext *context, GBinContent *content, pending_matches_t *matches) +{ + size_t i; /* Boucle de parcours #1 */ + const sized_binary_t *raw; /* Données brutes d'origine */ + const tracked_scan_atom_t *atom; /* Atome correspondant */ + size_t count; /* Quantité de bribes trouvées */ + const phys_t *found; /* Localisations des bribes */ + size_t k; /* Boucle de parcours #2 */ + phys_t start; /* Point de départ */ + vmpa2t pos; /* Position dans les données */ + const bin_t *ptr; /* Accès aux données brutes */ + int ret; /* Bilan d'une comparaison */ + + for (i = 0; i < bytes->count; i++) + { + raw = &bytes->raw[i]; + atom = &bytes->atoms[i]; + + found = g_scan_context_get_atom_matches(context, atom->pid, &count); + + for (k = 0; k < count; k++) + { + start = found[k] - atom->pos; + + init_vmpa(&pos, start, VMPA_NO_VIRTUAL); + + /* Validation du contenu avant l'atome */ + + if (atom->pos > 0) + { + ptr = g_binary_content_get_raw_access(content, &pos, atom->pos); + + ret = memcmp(raw->data, ptr, atom->pos); + if (ret != 0) continue; + + } + + /* Validation du contenu après l'atome */ + + if (atom->rem > 0) + { + advance_vmpa(&pos, atom->len); + + ptr = g_binary_content_get_raw_access(content, &pos, atom->rem); + + ret = memcmp(raw->data + atom->pos + atom->len, ptr, atom->rem); + if (ret != 0) continue; + + } + + /* Mémorisation de la correspondance */ + + add_pending_matches(matches, start, raw->len); + + } + + } + +} + +#endif diff --git a/src/analysis/scan/patterns/tokens/hex.h b/src/analysis/scan/patterns/tokens/hex.h new file mode 100644 index 0000000..1db8eb6 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/hex.h @@ -0,0 +1,59 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hex.h - prototypes pour la recherche de morceaux de binaire + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_H + + +#include + + +#include "node.h" +#include "../../pattern.h" + + + +#define G_TYPE_SCAN_HEX_BYTES g_scan_hex_bytes_get_type() +#define G_SCAN_HEX_BYTES(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_HEX_BYTES, GScanHexBytes)) +#define G_IS_SCAN_HEX_BYTES(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_HEX_BYTES)) +#define G_SCAN_HEX_BYTES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_HEX_BYTES, GScanHexBytesClass)) +#define G_IS_SCAN_HEX_BYTES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_HEX_BYTES)) +#define G_SCAN_HEX_BYTES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_HEX_BYTES, GScanHexBytesClass)) + + +/* Encadrement d'une recherche de morceaux de binaire (instance) */ +typedef struct _GScanHexBytes GScanHexBytes; + +/* Encadrement d'une recherche de morceaux de binaire (classe) */ +typedef struct _GScanHexBytesClass GScanHexBytesClass; + + +/* Indique le type défini pour une suite d'octets à retrouver dans un binaire. */ +GType g_scan_hex_bytes_get_type(void); + +/* Construit un gestionnaire de recherche de texte brut. */ +GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_HEX_H */ diff --git a/src/analysis/scan/patterns/tokens/node-int.h b/src/analysis/scan/patterns/tokens/node-int.h new file mode 100644 index 0000000..c543cbf --- /dev/null +++ b/src/analysis/scan/patterns/tokens/node-int.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * node-int.h - prototypes internes pour la décomposition d'un motif de recherche en atomes assemblés + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_INT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_INT_H + + +#include "node.h" + + + +/* Inscrit la définition d'un motif dans un moteur de recherche. */ +typedef bool (* enroll_scan_token_node_fc) (GScanTokenNode *, GScanContext *, GEngineBackend *, size_t); + +/* Transforme les correspondances locales en trouvailles. */ +typedef void (* check_scan_token_node_fc) (const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, const node_search_offset_t *); + + +/* Décomposition d'un motif de recherche en atomes (instance) */ +struct _GScanTokenNode +{ + GObject parent; /* A laisser en premier */ + +}; + +/* Décomposition d'un motif de recherche en atomes (classe) */ +struct _GScanTokenNodeClass +{ + GObjectClass parent; /* A laisser en premier */ + + enroll_scan_token_node_fc enroll; /* Inscription d'un motif */ + check_scan_token_node_fc check; /* Conversion en trouvailles */ + +}; + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_INT_H */ diff --git a/src/analysis/scan/patterns/tokens/node.c b/src/analysis/scan/patterns/tokens/node.c new file mode 100644 index 0000000..224328a --- /dev/null +++ b/src/analysis/scan/patterns/tokens/node.c @@ -0,0 +1,195 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * node.c - décomposition d'un motif de recherche en atomes assemblés + * + * 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 . + */ + + +#include "node.h" + + +#include + + +#include "node-int.h" + + + +/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */ + + +/* Initialise la classe des éléments de décomposition. */ +static void g_scan_token_node_class_init(GScanTokenNodeClass *klass); + +/* Initialise une instance d'élément décomposant un motif. */ +static void g_scan_token_node_init(GScanTokenNode *); + +/* Supprime toutes les références externes. */ +static void g_scan_token_node_dispose(GScanTokenNode *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_token_node_finalize(GScanTokenNode *); + + + +/* ---------------------------------------------------------------------------------- */ +/* DECOMPOSITION DE MOTIF RECHERCHE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un élément décomposant un motif d'octets à rechercher. */ +G_DEFINE_TYPE(GScanTokenNode, g_scan_token_node, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des éléments de décomposition. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_class_init(GScanTokenNodeClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_token_node_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : node = instance à initialiser. * +* * +* Description : Initialise une instance d'élément décomposant un motif. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_init(GScanTokenNode *node) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : node = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_dispose(GScanTokenNode *node) +{ + G_OBJECT_CLASS(g_scan_token_node_parent_class)->dispose(G_OBJECT(node)); + +} + + +/****************************************************************************** +* * +* Paramètres : node = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_finalize(GScanTokenNode *node) +{ + G_OBJECT_CLASS(g_scan_token_node_parent_class)->finalize(G_OBJECT(node)); + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à enregistrer. * +* context = contexte de l'analyse à mener. * +* backend = moteur de recherche à préchauffer. * +* maxsize = taille max. des atomes (mise en commun optimisée). * +* * +* Description : Inscrit la définition d'un motif dans un moteur de recherche.* +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngineBackend *backend, size_t maxsize) +{ + bool result; /* Statut à retourner */ + GScanTokenNodeClass *class; /* Classe de l'instance */ + + assert(g_engine_backend_get_atom_max_size(backend) == maxsize); + + class = G_SCAN_TOKEN_NODE_GET_CLASS(node); + + result = class->enroll(node, context, backend, maxsize); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* context = contexte de l'analyse à mener. * +* content = accès au contenu brut pour vérifications (optim.) * +* matches = suivi des correspondances à consolider. * +* offset = tolérance dans les positions à appliquer. * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_token_node_check(const GScanTokenNode *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, const node_search_offset_t *offset) +{ + GScanTokenNodeClass *class; /* Classe de l'instance */ + + class = G_SCAN_TOKEN_NODE_GET_CLASS(node); + + class->check(node, context, content, matches, offset); + +} diff --git a/src/analysis/scan/patterns/tokens/node.h b/src/analysis/scan/patterns/tokens/node.h new file mode 100644 index 0000000..4c9eb48 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/node.h @@ -0,0 +1,77 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * node.h - prototypes pour la décomposition d'un motif de recherche en atomes assemblés + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_H + + +#include +#include + + +#include "../backend.h" +#include "../../context.h" +#include "../../matches/pending.h" + + +#define G_TYPE_SCAN_TOKEN_NODE g_scan_token_node_get_type() +#define G_SCAN_TOKEN_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE, GScanTokenNode)) +#define G_IS_SCAN_TOKEN_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE)) +#define G_SCAN_TOKEN_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE, GScanTokenNodeClass)) +#define G_IS_SCAN_TOKEN_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE)) +#define G_SCAN_TOKEN_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE, GScanTokenNodeClass)) + + +/* Décomposition d'un motif de recherche en atomes (instance) */ +typedef struct _GScanTokenNode GScanTokenNode; + +/* Décomposition d'un motif de recherche en atomes (classe) */ +typedef struct _GScanTokenNodeClass GScanTokenNodeClass; + + +/* Indique le type défini pour un élément décomposant un motif d'octets à rechercher. */ +GType g_scan_token_node_get_type(void); + + +// TODO +// validate +// force_plain_registration // set begin/end + + +/* Inscrit la définition d'un motif dans un moteur de recherche. */ +bool g_scan_token_node_enroll(GScanTokenNode *, GScanContext *, GEngineBackend *, size_t); + +/* Mémorisation d'une souplesse dans les positions visées */ +typedef struct _node_search_offset_t +{ + phys_t min; /* Position minimale */ + phys_t max; /* Position maxnimale */ + +} node_search_offset_t; + +/* Transforme les correspondances locales en trouvailles. */ +void g_scan_token_node_check(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, const node_search_offset_t *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_H */ diff --git a/src/analysis/scan/patterns/tokens/nodes/Makefile.am b/src/analysis/scan/patterns/tokens/nodes/Makefile.am new file mode 100644 index 0000000..c20beaf --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/Makefile.am @@ -0,0 +1,16 @@ + +noinst_LTLIBRARIES = libanalysisscanpatternstokensnodes.la + + +libanalysisscanpatternstokensnodes_la_SOURCES = \ + hub-int.h \ + hub.h hub.c \ + plain-int.h \ + plain.h plain.c + +libanalysisscanpatternstokensnodes_la_CFLAGS = $(LIBGOBJ_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libanalysisscanpatternstokensnodes_la_SOURCES:%c=) diff --git a/src/analysis/scan/patterns/tokens/nodes/hub-int.h b/src/analysis/scan/patterns/tokens/nodes/hub-int.h new file mode 100644 index 0000000..df05112 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/hub-int.h @@ -0,0 +1,51 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hub-int.h - prototypes internes pour un groupe de décompositions de motif de recherche en atomes assemblés + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_INT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_INT_H + + +#include "hub.h" + + +#include "../node-int.h" + + + +/* Groupe de décompositions de motif de recherche en atomes (instance) */ +struct _GScanTokenNodeHub +{ + GScanTokenNode parent; /* A laisser en premier */ + +}; + +/* Groupe de décompositions de motif de recherche en atomes (classe) */ +struct _GScanTokenNodeHubClass +{ + GScanTokenNodeClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_INT_H */ diff --git a/src/analysis/scan/patterns/tokens/nodes/hub.c b/src/analysis/scan/patterns/tokens/nodes/hub.c new file mode 100644 index 0000000..a11531d --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/hub.c @@ -0,0 +1,150 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hub.c - groupe de décompositions de motif de recherche en atomes assemblés + * + * 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 . + */ + + +#include "hub.h" + + +#include "hub-int.h" + + + +/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */ + + +/* Initialise la classe des groupes de décompositions. */ +static void g_scan_token_node_hub_class_init(GScanTokenNodeHubClass *klass); + +/* Initialise une instance de groupe de décompositions. */ +static void g_scan_token_node_hub_init(GScanTokenNodeHub *); + +/* Supprime toutes les références externes. */ +static void g_scan_token_node_hub_dispose(GScanTokenNodeHub *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_token_node_hub_finalize(GScanTokenNodeHub *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + + + + +/* ---------------------------------------------------------------------------------- */ +/* DECOMPOSITION DE MOTIF RECHERCHE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un groupe de décompositions de motif d'octets à rechercher. */ +G_DEFINE_TYPE(GScanTokenNodeHub, g_scan_token_node_hub, G_TYPE_SCAN_TOKEN_NODE); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des groupes de décompositions. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_hub_class_init(GScanTokenNodeHubClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_hub_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_token_node_hub_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : hub = instance à initialiser. * +* * +* Description : Initialise une instance de groupe de décompositions. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_hub_init(GScanTokenNodeHub *hub) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : hub = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_hub_dispose(GScanTokenNodeHub *hub) +{ + G_OBJECT_CLASS(g_scan_token_node_hub_parent_class)->dispose(G_OBJECT(hub)); + +} + + +/****************************************************************************** +* * +* Paramètres : hub = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_hub_finalize(GScanTokenNodeHub *hub) +{ + G_OBJECT_CLASS(g_scan_token_node_hub_parent_class)->finalize(G_OBJECT(hub)); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + + + diff --git a/src/analysis/scan/patterns/tokens/nodes/hub.h b/src/analysis/scan/patterns/tokens/nodes/hub.h new file mode 100644 index 0000000..b2cb0fc --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/hub.h @@ -0,0 +1,55 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hub.h - prototypes pour un groupe de décompositions de motif de recherche en atomes assemblés + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_H + + +#include + + +#include "../node.h" + + + +#define G_TYPE_SCAN_TOKEN_NODE_HUB g_scan_token_node_hub_get_type() +#define G_SCAN_TOKEN_NODE_HUB(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_HUB, GScanTokenNodeHub)) +#define G_IS_SCAN_TOKEN_NODE_HUB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_HUB)) +#define G_SCAN_TOKEN_NODE_HUB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_HUB, GScanTokenNodeHubClass)) +#define G_IS_SCAN_TOKEN_NODE_HUB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_HUB)) +#define G_SCAN_TOKEN_NODE_HUB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_HUB, GScanTokenNodeHubClass)) + + +/* Groupe de décompositions de motif de recherche en atomes (instance) */ +typedef struct _GScanTokenNodeHub GScanTokenNodeHub; + +/* Groupe de décompositions de motif de recherche en atomes (classe) */ +typedef struct _GScanTokenNodeHubClass GScanTokenNodeHubClass; + + +/* Indique le type défini pour un groupe de décompositions de motif d'octets à rechercher. */ +GType g_scan_token_node_hub_get_type(void); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_H */ diff --git a/src/analysis/scan/patterns/tokens/nodes/plain-int.h b/src/analysis/scan/patterns/tokens/nodes/plain-int.h new file mode 100644 index 0000000..a38359d --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/plain-int.h @@ -0,0 +1,64 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain-int.h - prototypes internes pour la gestion d'une recherche de motif textuel + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_INT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_INT_H + + +#include "plain.h" + + +#include "../node-int.h" +#include "../atom.h" + + + +/* Bribe de motif textuelle pour recherches (instance) */ +struct _GScanTokenNodePlain +{ + GScanTokenNode parent; /* A laisser en premier */ + + sized_binary_t orig; /* Motif d'origine avant modifs*/ + GScanTokenModifier *modifier; /* Transformateur pour le motif*/ + ScanPlainNodeFlags flags; /* Fanions associés au motif */ + + sized_binary_t *raw; /* Liste de motifs à couvrir */ + tracked_scan_atom_t *atoms; /* Atomes correspondants */ + size_t count; /* Taille de cette liste */ + +}; + +/* Bribe de motif textuelle pour recherches (instance) */ +struct _GScanTokenNodePlainClass +{ + GScanTokenNodeClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un un noeud représentant un motif textuel. */ +bool g_scan_token_node_plain_create(GScanTokenNodePlain *, const sized_binary_t *, GScanTokenModifier *, ScanPlainNodeFlags); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_INT_H */ diff --git a/src/analysis/scan/patterns/tokens/nodes/plain.c b/src/analysis/scan/patterns/tokens/nodes/plain.c new file mode 100644 index 0000000..ee87c73 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/plain.c @@ -0,0 +1,582 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain.c - gestion d'une recherche de motif textuel + * + * 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 . + */ + + +#include "plain.h" + + +#include "plain-int.h" + + + +/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */ + + +/* Initialise la classe des noeuds pour motif textuel. */ +static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *klass); + +/* Initialise une instance de noeud pour motif textuel. */ +static void g_scan_token_node_plain_init(GScanTokenNodePlain *); + +/* Supprime toutes les références externes. */ +static void g_scan_token_node_plain_dispose(GScanTokenNodePlain *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_token_node_plain_finalize(GScanTokenNodePlain *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Inscrit la définition d'un motif dans un moteur de recherche. */ +static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *, GScanContext *, GEngineBackend *, size_t ); + +/* Détermine si un contenu d'intérêt est présent à une position. */ +static bool check_scan_token_node_plain_content(const sized_binary_t *, const tracked_scan_atom_t *, phys_t, GBinContent *); + +/* Transforme les correspondances locales en trouvailles. */ +static void g_scan_plain_bytes_check(const GScanTokenNodePlain *, GScanContext *, GBinContent *, pending_matches_t *, const node_search_offset_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* DECOMPOSITION DE MOTIF RECHERCHE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un noeud représentant une bribe de texte à retrouver. */ +G_DEFINE_TYPE(GScanTokenNodePlain, g_scan_token_node_plain, G_TYPE_SCAN_TOKEN_NODE); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des noeuds pour motif textuel. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenNodeClass *node; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_plain_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_token_node_plain_finalize; + + node = G_SCAN_TOKEN_NODE_CLASS(klass); + + node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_plain_enroll; + node->check = (check_scan_token_node_fc)g_scan_plain_bytes_check; + +} + + +/****************************************************************************** +* * +* Paramètres : plain = instance à initialiser. * +* * +* Description : Initialise une instance de noeud pour motif textuel. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_plain_init(GScanTokenNodePlain *plain) +{ + init_szstr(&plain->orig); + plain->modifier = NULL; + plain->flags = SPNF_NONE; + + plain->raw = NULL; + plain->atoms = NULL; + plain->count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : plain = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_plain_dispose(GScanTokenNodePlain *plain) +{ + g_clear_object(&plain->modifier); + + G_OBJECT_CLASS(g_scan_token_node_plain_parent_class)->dispose(G_OBJECT(plain)); + +} + + +/****************************************************************************** +* * +* Paramètres : plain = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_token_node_plain_finalize(GScanTokenNodePlain *plain) +{ + size_t i; /* Boucle de parcours */ + + exit_szstr(&plain->orig); + + for (i = 0; i < plain->count; i++) + exit_szstr(&plain->raw[i]); + + if (plain->raw != NULL) + free(plain->raw); + + if (plain->atoms != NULL) + free(plain->atoms); + + G_OBJECT_CLASS(g_scan_token_node_plain_parent_class)->finalize(G_OBJECT(plain)); + +} + + +/****************************************************************************** +* * +* Paramètres : text = texte brut à rechercher. * +* modifier = transformateur éventuel à solliciter. * +* flags = particularités à prendre en considération. * +* * +* Description : Construit un noeud représentant un motif textuel. * +* * +* Retour : Mécanismes mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenNode *g_scan_token_node_plain_new(const sized_binary_t *text, GScanTokenModifier *modifier, ScanPlainNodeFlags flags) +{ + GScanTokenNode *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_PLAIN, NULL); + + if (!g_scan_token_node_plain_create(G_SCAN_TOKEN_NODE_PLAIN(result), text, modifier, flags)) + g_clear_object(&result); + + return result; + +} + +/****************************************************************************** +* * +* Paramètres : plain = encadrement de motif à initialiser pleinement. * +* text = texte brut à rechercher. * +* modifier = transformateur éventuel à solliciter. * +* flags = particularités à prendre en considération. * +* * +* Description : Met en place un un noeud représentant un motif textuel. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_token_node_plain_create(GScanTokenNodePlain *plain, const sized_binary_t *text, GScanTokenModifier *modifier, ScanPlainNodeFlags flags) +{ + bool result; /* Bilan à retourner */ + + result = true; + + szstrdup(&plain->orig, text); + + if (modifier != NULL) + { + plain->modifier = modifier; + g_object_ref(G_OBJECT(modifier)); + } + + plain->flags = flags; + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à enregistrer. * +* context = contexte de l'analyse à mener. * +* backend = moteur de recherche à préchauffer. * +* maxsize = taille max. des atomes (mise en commun optimisée). * +* * +* Description : Inscrit la définition d'un motif dans un moteur de recherche.* +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanContext *context, GEngineBackend *backend, size_t maxsize) +{ + bool result; /* Statut à retourner */ + size_t i; /* Boucle de parcours #1 */ + tracked_scan_atom_t atom; /* Atome identifié */ + size_t letters; /* Nombre de lettres présentes */ + size_t k; /* Boucle de parcours #2 */ + size_t extra_count; /* Quantité pour l'exhaustivité*/ + sized_binary_t *extra; /* Couverture supplémntaire */ + size_t remaining; /* Quantité restant à traiter */ + + /* Génération d'une base de chaînes à couvrir */ + + if (node->modifier == NULL) + { + node->raw = malloc(sizeof(sized_binary_t)); + node->count = 1; + + szstrdup(&node->raw[0], &node->orig); + + result = true; + + } + else + result = g_scan_token_modifier_transform(node->modifier, &node->orig, &node->raw, &node->count); + + if (!result) + goto exit; + + /* Préparation pour la mémorisation des atomes */ + + node->atoms = malloc(node->count * sizeof(tracked_scan_atom_t)); + + /* Validation du besoin effectif dans les cas extrèmes */ + + + + // TODO : if (orig.len < ...) + + + + /* Recherche des atomes */ + + for (i = 0; i < node->count; i++) + { + if (node->flags & SPNF_CASE_INSENSITIVE) + { + find_best_atom(&node->raw[i], maxsize, &atom, &letters); + + if (letters == 0) + node->atoms[i] = atom; + + /* Insertion des combinaisons pour couvrir toutes les casses */ + else + { + for (k = 0, extra_count = 1; k < letters; k++, extra_count *= 2) + ; + + extra = make_atoms_case_insensitive(&node->raw[i], extra_count); + + remaining = node->count - i - 1; + + node->count += (extra_count - 1); + + node->raw = realloc(node->raw, node->count * sizeof(sized_binary_t)); + + memmove(&node->raw[i + extra_count], &node->raw[i + 1], remaining * sizeof(sized_binary_t)); + + for (k = 0; k < extra_count; k++) + node->raw[i + k] = extra[k]; + + free(extra); + + node->atoms = realloc(node->raw, node->count * sizeof(tracked_scan_atom_t)); + + for (k = 0; k < extra_count; k++) + node->atoms[i + k] = atom; + + i += extra_count - 1; + + } + + } + + else + find_best_atom(&node->raw[i], maxsize, &node->atoms[i], &letters); + + } + + /* Enregistrements en masse */ + + for (i = 0; i < node->count && result; i++) + result = enroll_prepared_atom(&node->raw[i], context, backend, &node->atoms[i]); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : raw = contneu brut à retrouver idéalement. * +* atom = contenu brut représentatif ciblé. * +* start = point d'analyse à respecter. * +* content = accès au contenu brut pour vérifications (optim.) * +* * +* Description : Détermine si un contenu d'intérêt est présent à une position.* +* * +* Retour : Bilan de l'analyse : true pour une correspondance. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const tracked_scan_atom_t *atom, phys_t start, GBinContent *content) +{ + bool result; /* Bilan à retourner */ + vmpa2t pos; /* Position dans les données */ + const bin_t *ptr; /* Accès aux données brutes */ + int ret; /* Bilan d'une comparaison */ + + result = false; + + init_vmpa(&pos, start, VMPA_NO_VIRTUAL); + + /* Validation du contenu avant l'atome */ + + if (atom->pos > 0) + { + ptr = g_binary_content_get_raw_access(content, &pos, atom->pos); + + ret = memcmp(raw->data, ptr, atom->pos); + if (ret != 0) goto done; + + } + + /* Validation du contenu après l'atome */ + + if (atom->rem > 0) + { + advance_vmpa(&pos, atom->len); + + ptr = g_binary_content_get_raw_access(content, &pos, atom->rem); + + ret = memcmp(raw->data + atom->pos + atom->len, ptr, atom->rem); + if (ret != 0) goto done; + + } + + result = true; + + done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = définition de la bribe à manipuler. * +* context = contexte de l'analyse à mener. * +* content = accès au contenu brut pour vérifications (optim.) * +* matches = suivi des correspondances à consolider. * +* offset = tolérance dans les positions à appliquer. * +* * +* Description : Transforme les correspondances locales en trouvailles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, const node_search_offset_t *offset) +{ + bool initialized; /* Initialisation du suivi ? */ + size_t i; /* Boucle de parcours #1 */ + const sized_binary_t *raw; /* Données brutes d'origine */ + const tracked_scan_atom_t *atom; /* Atome correspondant */ + size_t count; /* Quantité de bribes trouvées */ + const phys_t *found; /* Localisations des bribes */ + size_t k; /* Boucle de parcours #2 */ + phys_t start; /* Point de départ */ + bool status; /* Bilan d'une correspondance */ + size_t pcount; /* Nombre de correspondances */ + size_t p; /* Boucle de parcours #3 */ + + initialized = are_pending_matches_initialized(matches); + + for (i = 0; i < node->count; i++) + { + raw = &node->raw[i]; + atom = &node->atoms[i]; + + found = g_scan_context_get_atom_matches(context, atom->pid, &count); + + if (!initialized) + { + for (k = 0; k < count; k++) + { + start = found[k] - atom->pos; + + /** + * Si personne n'a manipulé les pré-résultats, mais qu'un décallage + * est spécifié par un noeud précédent, une validation sur la base + * d'une position 0 est menée. + */ + if (offset != NULL) + { + if (start < offset->min || start > offset->max) + continue; + } + + status = check_scan_token_node_plain_content(raw, atom, start, content); + + if (status) + /** + * Il ne peut y avoir qu'une seule séquence d'octets à un même + * emplacement, donc le couple (start, len) enregistré est + * unique. + */ + add_pending_match(matches, start, raw->len); + + } + + } + + else + { + reset_pending_matches_ttl(matches); + + pcount = count_pending_matches(matches); + + for (p = 0; p < pcount; p++) + for (k = 0; k < count; k++) + { + start = found[k] - atom->pos; + + /** + * Si bornes de tolérance il y a, on valide la position. + * + * Sinon les correspondances passées et actuelle doivent + * être jointes. + */ + if (offset != NULL) + { + if (!has_pending_match_ending_between(matches, p, start, offset->min, offset->max)) + continue; + } + else + { + if (!has_pending_match_ending_at(matches, p, start)) + continue; + } + + status = check_scan_token_node_plain_content(raw, atom, start, content); + + if (status) + { + /** + * Même si une base de couples uniques est assurée, + * la constitution d'un ensemble de noeuds peut amener une + * redondance dans les emplacements de correspondances. + * + * Par exemple, pour la séquence d'octets analysés suivante : + * + * aaa....bbb + * + * La définition { (61 61 | 61 61 61) [4-5] 62 62 62 } peut établir + * les correspondances suivantes : + * + * aa.....bbb -> couple pending[x] (0;2) puis (0;10) + * ^ + * aa....bbb -> couple pending[y] (1;3) puis (1;10) + * ^ + * aaa....bbb -> couple pending[z] (0;3) puis (0;10) + * ^ + * + * Par ailleurs, une même base de départ peut conduire + * à plusieurs zone de correspondances. + * + * Par exemple, pour la séquence d'octets analysés suivante : + * + * aa..bb..bb + * + * La définition { 61 61 [2-6] 62 62 } peut établir + * les correspondances suivantes : + * + * aa..bb..bb -> couple pending[x] (0;2) puis (0;6) + * ^ + * aa..bb..bb -> couple pending[x] (0;2) puis (0;10) + * ^ + */ + + /** + * La seconde situation est prise en compte par la fonction + * extend_pending_match() qui s'appuie sur le TTL pour dupliquer + * la correspondance pending[x] initiale. Le nouvel élément est + * placé en fin de liste, ce qui ne boulverse pas le parcours + * de liste courant, la valeur de pcount n'étant pas actualisée. + */ + + extend_pending_match(matches, p, start + raw->len); + + } + + } + + purge_pending_matches(matches); + + } + + } + + set_pending_matches_initialized(matches); + +} diff --git a/src/analysis/scan/patterns/tokens/nodes/plain.h b/src/analysis/scan/patterns/tokens/nodes/plain.h new file mode 100644 index 0000000..33e7feb --- /dev/null +++ b/src/analysis/scan/patterns/tokens/nodes/plain.h @@ -0,0 +1,70 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain.h - prototypes pour la gestion d'une recherche de motif textuel + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_H + + +#include + + +#include "../node.h" +#include "../../modifier.h" +#include "../../../../../common/szstr.h" + + + +#define G_TYPE_SCAN_TOKEN_NODE_PLAIN g_scan_token_node_plain_get_type() +#define G_SCAN_TOKEN_NODE_PLAIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_PLAIN, GScanTokenNodePlain)) +#define G_IS_SCAN_TOKEN_NODE_PLAIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_PLAIN)) +#define G_SCAN_TOKEN_NODE_PLAIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_PLAIN, GScanTokenNodePlainClass)) +#define G_IS_SCAN_TOKEN_NODE_PLAIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_PLAIN)) +#define G_SCAN_TOKEN_NODE_PLAIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_PLAIN, GScanTokenNodePlainClass)) + + +/* Bribe de motif textuelle pour recherches (instance) */ +typedef struct _GScanTokenNodePlain GScanTokenNodePlain; + +/* Bribe de motif textuelle pour recherches (classe) */ +typedef struct _GScanTokenNodePlainClass GScanTokenNodePlainClass; + + +/* Propriétés d'un élément textuel à rechercher */ +typedef enum _ScanPlainNodeFlags +{ + SPNF_NONE = 0x0, /* Aucune particularité */ + SPNF_CASE_INSENSITIVE = 0x1, /* Ignorance de la casse */ + SPNF_FULL_WORD = 0x2, /* Recherche de mot entier */ + +} ScanPlainNodeFlags; + + +/* Indique le type défini pour un noeud représentant une bribe de texte à retrouver. */ +GType g_scan_token_node_plain_get_type(void); + +/* Construit un noeud représentant un motif textuel. */ +GScanTokenNode *g_scan_token_node_plain_new(const sized_binary_t *, GScanTokenModifier *, ScanPlainNodeFlags); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_H */ diff --git a/src/analysis/scan/patterns/tokens/plain-int.h b/src/analysis/scan/patterns/tokens/plain-int.h new file mode 100644 index 0000000..40a71b5 --- /dev/null +++ b/src/analysis/scan/patterns/tokens/plain-int.h @@ -0,0 +1,64 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain-int.h - prototypes internes pour la recherche d'une chaîne de caractères brute + * + * 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 . + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_INT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_INT_H + + +#include "plain.h" + + +#include "atom.h" +#include "../token-int.h" + + + +/* Encadrement d'une recherche de texte brut (instance) */ +struct _GScanPlainBytes +{ + GStringToken parent; /* A laisser en premier */ + + sized_binary_t orig; /* Motif d'origine avant modifs*/ + GScanTokenModifier *modifier; /* Transformateur pour le motif*/ + ScanPlainBytesFlags flags; /* Fanions associés au motif */ + + sized_binary_t *raw; /* Liste de motifs à couvrir */ + tracked_scan_atom_t *atoms; /* Atomes correspondants */ + size_t count; /* Taille de cette liste */ + +}; + +/* Encadrement d'une recherche de texte brut (classe) */ +struct _GScanPlainBytesClass +{ + GStringTokenClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un gestionnaire de recherche de texte brut. */ +bool g_scan_plain_bytes_create(GScanPlainBytes *, const sized_binary_t *, GScanTokenModifier *, ScanPlainBytesFlags); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_INT_H */ diff --git a/src/analysis/scan/patterns/tokens/plain.c b/src/analysis/scan/patterns/tokens/plain.c index 9eb731e..26e7dfa 100644 --- a/src/analysis/scan/patterns/tokens/plain.c +++ b/src/analysis/scan/patterns/tokens/plain.c @@ -28,59 +28,41 @@ #include -#include "../token-int.h" +#include "plain-int.h" /* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ -/* Encadrement d'une recherche de texte brut (instance) */ -struct _GPlainBytes -{ - GStringToken parent; /* A laisser en premier */ - - uint8_t *raw; /* Octets recherchés */ - size_t allocated; /* Taille allouée */ - size_t used; /* Quantité d'octets utilisée */ - - phys_t atom_pos; /* Début de sélection atomique */ - phys_t atom_len; /* Taille de ladite sélection */ - phys_t atom_rem; /* Reste après l'atome */ - patid_t pid; /* Identifiant de la bribe */ - -}; - -/* Encadrement d'une recherche de texte brut (classe) */ -struct _GPlainBytesClass -{ - GStringTokenClass parent; /* A laisser en premier */ - -}; - - /* Initialise la classe des recherches de texte brut. */ -static void g_plain_bytes_class_init(GPlainBytesClass *klass); +static void g_scan_plain_bytes_class_init(GScanPlainBytesClass *klass); /* Initialise une instance de recherche de texte brut. */ -static void g_plain_bytes_init(GPlainBytes *); +static void g_scan_plain_bytes_init(GScanPlainBytes *); /* Supprime toutes les références externes. */ -static void g_plain_bytes_dispose(GPlainBytes *); +static void g_scan_plain_bytes_dispose(GScanPlainBytes *); /* Procède à la libération totale de la mémoire. */ -static void g_plain_bytes_finalize(GPlainBytes *); +static void g_scan_plain_bytes_finalize(GScanPlainBytes *); /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ +/* Affiche un motif de recherche au format texte. */ +static void g_scan_plain_bytes_output_to_text(const GScanPlainBytes *, GScanContext *, int); + +/* Affiche un motif de recherche au format JSON. */ +static void g_scan_plain_bytes_output_to_json(const GScanPlainBytes *, GScanContext *, const sized_string_t *, unsigned int, int); + /* Inscrit la définition d'un motif dans un moteur de recherche. */ -static bool g_plain_bytes_enroll(GPlainBytes *, GScanContext *, GEngineBackend *, size_t); +static bool g_scan_plain_bytes_enroll(GScanPlainBytes *, GScanContext *, GEngineBackend *, size_t); /* Transforme les correspondances locales en trouvailles. */ -static void g_plain_bytes_check(const GPlainBytes *, GScanContext *, GBinContent *, pending_matches_t *); +static void g_scan_plain_bytes_check(const GScanPlainBytes *, GScanContext *, GBinContent *, pending_matches_t *); @@ -90,7 +72,7 @@ static void g_plain_bytes_check(const GPlainBytes *, GScanContext *, GBinContent /* Indique le type défini pour une suite d'octets à retrouver dans un binaire. */ -G_DEFINE_TYPE(GPlainBytes, g_plain_bytes, G_TYPE_STRING_TOKEN); +G_DEFINE_TYPE(GScanPlainBytes, g_scan_plain_bytes, G_TYPE_STRING_TOKEN); /****************************************************************************** @@ -105,7 +87,7 @@ G_DEFINE_TYPE(GPlainBytes, g_plain_bytes, G_TYPE_STRING_TOKEN); * * ******************************************************************************/ -static void g_plain_bytes_class_init(GPlainBytesClass *klass) +static void g_scan_plain_bytes_class_init(GScanPlainBytesClass *klass) { GObjectClass *object; /* Autre version de la classe */ GSearchPatternClass *pattern; /* Version de classe ancêtre */ @@ -113,26 +95,25 @@ static void g_plain_bytes_class_init(GPlainBytesClass *klass) object = G_OBJECT_CLASS(klass); - object->dispose = (GObjectFinalizeFunc/* ! */)g_plain_bytes_dispose; - object->finalize = (GObjectFinalizeFunc)g_plain_bytes_finalize; + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_plain_bytes_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_plain_bytes_finalize; pattern = G_SEARCH_PATTERN_CLASS(klass); - //pattern->prepare = (prepare_pattern_fc)g_plain_bytes_prepare; - //pattern->analyze = (analyze_pattern_fc)g_plain_bytes_analyze; - //pattern->count = (count_pattern_matchs_fc); + pattern->to_text = (output_pattern_to_text_fc)g_scan_plain_bytes_output_to_text; + pattern->to_json = (output_pattern_to_json_fc)g_scan_plain_bytes_output_to_json; token = G_STRING_TOKEN_CLASS(klass); - token->enroll = (enroll_token_fc)g_plain_bytes_enroll; - token->check = (check_token_fc)g_plain_bytes_check; + token->enroll = (enroll_token_fc)g_scan_plain_bytes_enroll; + token->check = (check_token_fc)g_scan_plain_bytes_check; } /****************************************************************************** * * -* Paramètres : pattern = instance à initialiser. * +* Paramètres : bytes = instance à initialiser. * * * * Description : Initialise une instance de recherche de texte brut. * * * @@ -142,16 +123,15 @@ static void g_plain_bytes_class_init(GPlainBytesClass *klass) * * ******************************************************************************/ -static void g_plain_bytes_init(GPlainBytes *bytes) +static void g_scan_plain_bytes_init(GScanPlainBytes *bytes) { - bytes->raw = NULL; - bytes->allocated = 0; - bytes->used = 0; + init_szstr(&bytes->orig); + bytes->modifier = NULL; + bytes->flags = SPBF_NONE; - bytes->atom_pos = 0; - bytes->atom_len = 0; - bytes->atom_rem = 0; - bytes->pid = INVALID_PATTERN_ID; + bytes->raw = NULL; + bytes->atoms = NULL; + bytes->count = 0; } @@ -168,9 +148,11 @@ static void g_plain_bytes_init(GPlainBytes *bytes) * * ******************************************************************************/ -static void g_plain_bytes_dispose(GPlainBytes *bytes) +static void g_scan_plain_bytes_dispose(GScanPlainBytes *bytes) { - G_OBJECT_CLASS(g_plain_bytes_parent_class)->dispose(G_OBJECT(bytes)); + g_clear_object(&bytes->modifier); + + G_OBJECT_CLASS(g_scan_plain_bytes_parent_class)->dispose(G_OBJECT(bytes)); } @@ -187,20 +169,31 @@ static void g_plain_bytes_dispose(GPlainBytes *bytes) * * ******************************************************************************/ -static void g_plain_bytes_finalize(GPlainBytes *bytes) +static void g_scan_plain_bytes_finalize(GScanPlainBytes *bytes) { + size_t i; /* Boucle de parcours */ + + exit_szstr(&bytes->orig); + + for (i = 0; i < bytes->count; i++) + exit_szstr(&bytes->raw[i]); + if (bytes->raw != NULL) free(bytes->raw); - G_OBJECT_CLASS(g_plain_bytes_parent_class)->finalize(G_OBJECT(bytes)); + if (bytes->atoms != NULL) + free(bytes->atoms); + + G_OBJECT_CLASS(g_scan_plain_bytes_parent_class)->finalize(G_OBJECT(bytes)); } /****************************************************************************** * * -* Paramètres : text = texte brut à rechercher. * -* len = longueur de ce texte. * +* Paramètres : text = texte brut à rechercher. * +* modifier = transformateur éventuel à solliciter. * +* flags = particularités à prendre en considération. * * * * Description : Construit un gestionnaire de recherche de texte brut. * * * @@ -210,19 +203,51 @@ static void g_plain_bytes_finalize(GPlainBytes *bytes) * * ******************************************************************************/ -GSearchPattern *g_plain_bytes_new(const uint8_t *raw, size_t len) +GSearchPattern *g_scan_plain_bytes_new(const sized_binary_t *text, GScanTokenModifier *modifier, ScanPlainBytesFlags flags) { - GPlainBytes *result; /* Structure à retourner */ + GSearchPattern *result; /* Structure à retourner */ - result = g_object_new(G_TYPE_PLAIN_BYTES, NULL); + result = g_object_new(G_TYPE_SCAN_PLAIN_BYTES, NULL); - result->raw = malloc(len); - result->allocated = len; - result->used = len; + if (!g_scan_plain_bytes_create(G_SCAN_PLAIN_BYTES(result), text, modifier, flags)) + g_clear_object(&result); - memcpy(result->raw, raw, len); + return result; + +} - return G_SEARCH_PATTERN(result); +/****************************************************************************** +* * +* Paramètres : bytes = encadrement de motif à initialiser pleinement. * +* text = texte brut à rechercher. * +* modifier = transformateur éventuel à solliciter. * +* flags = particularités à prendre en considération. * +* * +* Description : Met en place un gestionnaire de recherche de texte brut. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_plain_bytes_create(GScanPlainBytes *bytes, const sized_binary_t *text, GScanTokenModifier *modifier, ScanPlainBytesFlags flags) +{ + bool result; /* Bilan à retourner */ + + result = true; + + szstrdup(&bytes->orig, text); + + if (modifier != NULL) + { + bytes->modifier = modifier; + g_object_ref(G_OBJECT(modifier)); + } + + bytes->flags = flags; + + return result; } @@ -235,6 +260,52 @@ GSearchPattern *g_plain_bytes_new(const uint8_t *raw, size_t len) /****************************************************************************** * * +* Paramètres : pattern = définition de motif à considérer. * +* context = contexte de l'analyse à mener. * +* fd = canal d'écriture. * +* * +* Description : Affiche un motif de recherche au format texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_plain_bytes_output_to_text(const GScanPlainBytes *pattern, GScanContext *context, int fd) +{ + G_SEARCH_PATTERN_CLASS(g_scan_plain_bytes_parent_class)->to_text(G_SEARCH_PATTERN(pattern), context, fd); + +} + + +/****************************************************************************** +* * +* Paramètres : pattern = définition de motif à considérer. * +* context = contexte de l'analyse à mener. * +* padding = éventuel bourrage initial à placer ou NULL. * +* level = profondeur actuelle. * +* fd = canal d'écriture. * +* * +* Description : Affiche un motif de recherche au format JSON. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_plain_bytes_output_to_json(const GScanPlainBytes *pattern, GScanContext *context, const sized_string_t *padding, unsigned int level, int fd) +{ + G_SEARCH_PATTERN_CLASS(g_scan_plain_bytes_parent_class)->to_json(G_SEARCH_PATTERN(pattern), context, padding, level, fd); + + /* TODO */ + +} + + +/****************************************************************************** +* * * Paramètres : bytes = définition de la bribe à enregistrer. * * context = contexte de l'analyse à mener. * * backend = moteur de recherche à préchauffer. * @@ -248,39 +319,99 @@ GSearchPattern *g_plain_bytes_new(const uint8_t *raw, size_t len) * * ******************************************************************************/ -static bool g_plain_bytes_enroll(GPlainBytes *bytes, GScanContext *context, GEngineBackend *backend, size_t maxsize) +static bool g_scan_plain_bytes_enroll(GScanPlainBytes *bytes, GScanContext *context, GEngineBackend *backend, size_t maxsize) { + return false; +#if 0 bool result; /* Statut à retourner */ + size_t i; /* Boucle de parcours #1 */ + tracked_scan_atom_t atom; /* Atome identifié */ + size_t letters; /* Nombre de lettres présentes */ + size_t k; /* Boucle de parcours #2 */ + size_t extra_count; /* Quantité pour l'exhaustivité*/ + sized_binary_t *extra; /* Couverture supplémntaire */ + size_t remaining; /* Quantité restant à traiter */ + /* Génération d'une base de chaînes à couvrir */ - result = true; - + if (bytes->modifier == NULL) + { + bytes->raw = malloc(sizeof(sized_binary_t)); + bytes->count = 1; + szstrdup(&bytes[0].raw[0], &bytes->orig); - bytes->atom_pos = 0; + result = true; - if (bytes->used > maxsize) // Attention à la position de départ (à retrancher) ! - { - bytes->atom_len = maxsize; - bytes->atom_rem = bytes->used - maxsize; } else + result = g_scan_token_modifier_transform(bytes->modifier, &bytes->orig, &bytes->raw, &bytes->count); + + if (!result) + goto exit; + + /* Préparation pour la mémorisation des atomes */ + + bytes->atoms = malloc(bytes->count * sizeof(tracked_scan_atom_t)); + + /* Recherche des atomes */ + + for (i = 0; i < bytes->count; i++) { - bytes->atom_len = bytes->used; - bytes->atom_rem = 0; - } + if (bytes->flags & SPBF_CASE_INSENSITIVE) + { + find_best_atom(&bytes->raw[i], maxsize, &atom, &letters); + if (letters == 0) + bytes->atoms[i] = atom; - bytes->pid = g_engine_backend_enroll_plain_pattern(backend, context, bytes->raw, bytes->atom_len); + /* Insertion des combinaisons pour couvrir toutes les casses */ + else + { + for (k = 0, extra_count = 1; k < letters; k++, extra_count *= 2) + ; + extra = make_atoms_case_insensitive(&bytes->raw[i], extra_count); + remaining = bytes->count - i - 1; - result = (bytes->pid != INVALID_PATTERN_ID); + bytes->count += (extra_count - 1); + bytes->raw = realloc(bytes->raw, bytes->count * sizeof(sized_binary_t)); + memmove(&bytes->raw[i + extra_count], &bytes->raw[i + 1], remaining * sizeof(sized_binary_t)); - return result; + for (k = 0; k < extra_count; k++) + bytes->raw[i + k] = extra[k]; + + free(extra); + + bytes->atoms = realloc(bytes->raw, bytes->count * sizeof(tracked_scan_atom_t)); + + for (k = 0; k < extra_count; k++) + bytes->atoms[i + k] = atom; + i += extra_count - 1; + + } + + } + + else + find_best_atom(&bytes->raw[i], maxsize, &bytes->atoms[i], &letters); + + } + + /* Enregistrements en masse */ + + + for (i = 0; i < bytes->count && result; i++) + result = enroll_prepared_atom(&bytes->raw[i], context, backend, &bytes->atoms[i]); + + exit: + + return result; +#endif } @@ -299,76 +430,64 @@ static bool g_plain_bytes_enroll(GPlainBytes *bytes, GScanContext *context, GEng * * ******************************************************************************/ -static void g_plain_bytes_check(const GPlainBytes *bytes, GScanContext *context, GBinContent *content, pending_matches_t *matches) +static void g_scan_plain_bytes_check(const GScanPlainBytes *bytes, GScanContext *context, GBinContent *content, pending_matches_t *matches) { - bool initialized; /* Initialisation du suivi ? */ +#if 0 + + size_t i; /* Boucle de parcours #1 */ + const sized_binary_t *raw; /* Données brutes d'origine */ + const tracked_scan_atom_t *atom; /* Atome correspondant */ size_t count; /* Quantité de bribes trouvées */ const phys_t *found; /* Localisations des bribes */ - size_t mindex; /* Indice d'élément à compléter*/ - size_t i; /* Boucle de parcours */ + size_t k; /* Boucle de parcours #2 */ phys_t start; /* Point de départ */ vmpa2t pos; /* Position dans les données */ const bin_t *ptr; /* Accès aux données brutes */ int ret; /* Bilan d'une comparaison */ - initialized = are_pending_matches_initialized(matches); - - found = g_scan_context_get_atom_matches(context, bytes->pid, &count); - - mindex = 0; - - for (i = 0; i < count; i++) + for (i = 0; i < bytes->count; i++) { - start = found[i] - bytes->atom_pos; - - /* Recherche d'un point de départ attendu et conforme ? */ + raw = &bytes->raw[i]; + atom = &bytes->atoms[i]; - if (initialized) - if (!find_target_in_pending_matches(matches, start, &mindex)) - continue; + found = g_scan_context_get_atom_matches(context, atom->pid, &count); - init_vmpa(&pos, start, VMPA_NO_VIRTUAL); - - /* Validation du contenu avant l'atome */ - - if (bytes->atom_pos > 0) + for (k = 0; k < count; k++) { - ptr = g_binary_content_get_raw_access(content, &pos, bytes->atom_len); - - ret = memcmp(bytes->raw + bytes->atom_pos, ptr, bytes->atom_len); - if (ret != 0) goto exclude_false_positive; + start = found[k] - atom->pos; - } + init_vmpa(&pos, start, VMPA_NO_VIRTUAL); - /* Validation du contenu après l'atome */ + /* Validation du contenu avant l'atome */ - if (bytes->atom_rem > 0) - { - advance_vmpa(&pos, bytes->atom_len); + if (atom->pos > 0) + { + ptr = g_binary_content_get_raw_access(content, &pos, atom->pos); - ptr = g_binary_content_get_raw_access(content, &pos, bytes->atom_rem); + ret = memcmp(raw->data, ptr, atom->pos); + if (ret != 0) continue; - ret = memcmp(bytes->raw + bytes->atom_pos + bytes->atom_len, ptr, bytes->atom_rem); - if (ret != 0) goto exclude_false_positive; + } - } + /* Validation du contenu après l'atome */ - /* Mémorisation de la correspondance */ + if (atom->rem > 0) + { + advance_vmpa(&pos, atom->len); - if (initialized) - extend_pending_matches(matches, mindex, bytes->used); - else - add_pending_matches(matches, start, bytes->used); + ptr = g_binary_content_get_raw_access(content, &pos, atom->rem); - continue; + ret = memcmp(raw->data + atom->pos + atom->len, ptr, atom->rem); + if (ret != 0) continue; - exclude_false_positive: + } - if (initialized) - remove_pending_matches(matches, mindex); + /* Mémorisation de la correspondance */ - } + add_pending_matches(matches, start, raw->len); - set_pending_matches_initialized(matches); + } + } +#endif } diff --git a/src/analysis/scan/patterns/tokens/plain.h b/src/analysis/scan/patterns/tokens/plain.h index de1d4ec..80a0b4d 100644 --- a/src/analysis/scan/patterns/tokens/plain.h +++ b/src/analysis/scan/patterns/tokens/plain.h @@ -26,41 +26,44 @@ #include -#include +#include "../modifier.h" #include "../../pattern.h" +#include "../../../../common/szstr.h" -#define G_TYPE_PLAIN_BYTES g_plain_bytes_get_type() -#define G_PLAIN_BYTES(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PLAIN_BYTES, GPlainBytes)) -#define G_IS_PLAIN_BYTES(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PLAIN_BYTES)) -#define G_PLAIN_BYTES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PLAIN_BYTES, GPlainBytesClass)) -#define G_IS_PLAIN_BYTES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PLAIN_BYTES)) -#define G_PLAIN_BYTES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PLAIN_BYTES, GPlainBytesClass)) +#define G_TYPE_SCAN_PLAIN_BYTES g_scan_plain_bytes_get_type() +#define G_SCAN_PLAIN_BYTES(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_PLAIN_BYTES, GScanPlainBytes)) +#define G_IS_SCAN_PLAIN_BYTES(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_PLAIN_BYTES)) +#define G_SCAN_PLAIN_BYTES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_PLAIN_BYTES, GScanPlainBytesClass)) +#define G_IS_SCAN_PLAIN_BYTES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_PLAIN_BYTES)) +#define G_SCAN_PLAIN_BYTES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_PLAIN_BYTES, GScanPlainBytesClass)) /* Représentation d'une suite d'octets à retrouver (instance) */ -typedef struct _GPlainBytes GPlainBytes; +typedef struct _GScanPlainBytes GScanPlainBytes; /* Représentation d'une suite d'octets à retrouver (classe) */ -typedef struct _GPlainBytesClass GPlainBytesClass; +typedef struct _GScanPlainBytesClass GScanPlainBytesClass; /* Propriétés d'un élément textuel à rechercher */ -typedef enum _StringTokenAttrib +typedef enum _ScanPlainBytesFlags { - STP_CASE_INSENSITIVE, + SPBF_NONE = 0x0, /* Aucune particularité */ + SPBF_CASE_INSENSITIVE = 0x1, /* Ignorance de la casse */ + SPBF_FULL_WORD = 0x2, /* Recherche de mot entier */ -} StringTokenAttrib; +} ScanPlainBytesFlags; /* Indique le type défini pour une suite d'octets à retrouver dans un binaire. */ -GType g_plain_bytes_get_type(void); +GType g_scan_plain_bytes_get_type(void); /* Construit un gestionnaire de recherche de texte brut. */ -GSearchPattern *g_plain_bytes_new(const uint8_t *, size_t); +GSearchPattern *g_scan_plain_bytes_new(const sized_binary_t *, GScanTokenModifier *, ScanPlainBytesFlags); diff --git a/src/analysis/scan/rule-int.h b/src/analysis/scan/rule-int.h index cc10b08..b43cba9 100644 --- a/src/analysis/scan/rule-int.h +++ b/src/analysis/scan/rule-int.h @@ -40,9 +40,9 @@ struct _GScanRule char *name; /* Désignation de la règle */ fnv64_t name_hash; /* Empreinte de la désignation */ - GSearchPattern **data_locals; /* Variables de données */ - size_t data_allocated; /* Taille allouée du tableau */ - size_t data_used; /* Nombre d'éléments présents */ + GSearchPattern **bytes_locals; /* Variables de données */ + size_t bytes_allocated; /* Taille allouée du tableau */ + size_t bytes_used; /* Nombre d'éléments présents */ GScanExpression *condition; /* Condition de correspondance */ diff --git a/src/analysis/scan/rule.c b/src/analysis/scan/rule.c index 6ca97ab..4727c9d 100644 --- a/src/analysis/scan/rule.c +++ b/src/analysis/scan/rule.c @@ -93,9 +93,9 @@ static void g_scan_rule_init(GScanRule *rule) rule->name = NULL; rule->name_hash = 0; - rule->data_locals = NULL; - rule->data_allocated = 0; - rule->data_used = 0; + rule->bytes_locals = NULL; + rule->bytes_allocated = 0; + rule->bytes_used = 0; rule->condition = NULL; @@ -118,8 +118,8 @@ static void g_scan_rule_dispose(GScanRule *rule) { size_t i; /* Boucle de parcours */ - for (i = 0; i < rule->data_used; i++) - g_clear_object(&rule->data_locals[i]); + for (i = 0; i < rule->bytes_used; i++) + g_clear_object(&rule->bytes_locals[i]); g_clear_object(&rule->condition); @@ -219,13 +219,13 @@ void g_scan_rule_add_local_variable(GScanRule *rule, GSearchPattern *pattern) { if (G_IS_STRING_TOKEN(pattern)) { - if (rule->data_used == rule->data_allocated) + if (rule->bytes_used == rule->bytes_allocated) { - rule->data_allocated += PATTERN_ALLOC_SIZE; - rule->data_locals = realloc(rule->data_locals, rule->data_allocated * sizeof(GSearchPattern *)); + rule->bytes_allocated += PATTERN_ALLOC_SIZE; + rule->bytes_locals = realloc(rule->bytes_locals, rule->bytes_allocated * sizeof(GSearchPattern *)); } - rule->data_locals[rule->data_used++] = pattern; + rule->bytes_locals[rule->bytes_used++] = pattern; g_object_ref(G_OBJECT(pattern)); } @@ -254,13 +254,13 @@ GSearchPattern *g_scan_rule_get_local_variable(GScanRule *rule, const char *targ result = NULL; - for (i = 0; i < rule->data_used; i++) + for (i = 0; i < rule->bytes_used; i++) { - name = g_search_pattern_get_name(rule->data_locals[i]); + name = g_search_pattern_get_name(rule->bytes_locals[i]); if (strcmp(name, target) == 0) { - result = rule->data_locals[i]; + result = rule->bytes_locals[i]; break; } @@ -327,9 +327,9 @@ bool g_scan_rule_setup_backend(GScanRule *rule, GEngineBackend *backend, GScanCo maxsize = g_engine_backend_get_atom_max_size(backend); - for (i = 0; i < rule->data_used && result; i++) + for (i = 0; i < rule->bytes_used && result; i++) { - pattern = rule->data_locals[i]; + pattern = rule->bytes_locals[i]; result = g_string_token_enroll(G_STRING_TOKEN(pattern), context, backend, maxsize); } @@ -380,11 +380,11 @@ void g_scan_rule_check(GScanRule *rule, GEngineBackend *backend, GScanContext *c /* Consolidation des résultats */ - for (i = 0; i < rule->data_used; i++) + for (i = 0; i < rule->bytes_used; i++) { init_pending_matches(&matches); - pattern = rule->data_locals[i]; + pattern = rule->bytes_locals[i]; g_string_token_check(G_STRING_TOKEN(pattern), context, content, &matches); @@ -392,7 +392,9 @@ void g_scan_rule_check(GScanRule *rule, GEngineBackend *backend, GScanContext *c { area = &matches.areas[k]; - match = g_bytes_match_new(G_SEARCH_PATTERN(pattern), content, area->start, area->length); + match = g_scan_bytes_match_new(G_SEARCH_PATTERN(pattern), content, + area->start, area->end - area->start); + g_scan_context_register_full_match(context, match); g_object_unref(G_OBJECT(match)); @@ -407,3 +409,161 @@ void g_scan_rule_check(GScanRule *rule, GEngineBackend *backend, GScanContext *c g_object_unref(G_OBJECT(content)); } + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à considérer. * +* context = contexte de l'analyse à mener. * +* fd = canal d'écriture. * +* * +* Description : Affiche une règle au format texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_rule_output_to_text(const GScanRule *rule, GScanContext *context, int fd) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < rule->bytes_used; i++) + g_search_pattern_output_to_text(rule->bytes_locals[i], context, fd); + + if (g_scan_context_has_match_for_rule(context, rule->name)) + { + write(fd, "Rule '", 6); + write(fd, rule->name, strlen(rule->name)); + write(fd, "' has matched!\n", 15); + } + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à considérer. * +* context = contexte de l'analyse à mener. * +* * +* Description : Convertit une règle en texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_rule_convert_as_text(const GScanRule *rule, GScanContext *context) +{ + /* TODO */ + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à considérer. * +* context = contexte de l'analyse à mener. * +* padding = éventuel bourrage initial à placer ou NULL. * +* level = profondeur actuelle. * +* fd = canal d'écriture. * +* trailing = impose une virgule finale ? * +* * +* Description : Affiche une règle au format JSON. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_rule_output_to_json(const GScanRule *rule, GScanContext *context, const sized_string_t *padding, unsigned int level, int fd, bool trailing) +{ + size_t i; /* Boucle de parcours */ + bool sub_trailing; /* Virgule finale */ + + /* Introduction */ + + for (i = 0; i < level; i++) + write(fd, padding->data, padding->len); + + write(fd, "{\n", 2); + + /* Désignation de la règle */ + + for (i = 0; i < (level + 1); i++) + write(fd, padding->data, padding->len); + + write(fd, "\"name\": \"", 9); + + write(fd, rule->name, strlen(rule->name)); + + write(fd, "\",\n", 3); + + /* Affichage des correspondances d'octets */ + + for (i = 0; i < (level + 1); i++) + write(fd, padding->data, padding->len); + + write(fd, "\"bytes_patterns\": [\n", 20); + + for (i = 0; i < rule->bytes_used; i++) + { + sub_trailing = ((i + 1) < rule->bytes_used); + + g_search_pattern_output_to_json(rule->bytes_locals[i], context, padding, level + 2, fd, sub_trailing); + + } + + for (i = 0; i < (level + 1); i++) + write(fd, padding->data, padding->len); + + write(fd, "],\n", 3); + + /* Bilan du filtrage */ + + for (i = 0; i < (level + 1); i++) + write(fd, padding->data, padding->len); + + write(fd, "\"matched\": ", 11); + + if (g_scan_context_has_match_for_rule(context, rule->name)) + write(fd, "true", 4); + else + write(fd, "false", 5); + + write(fd, "\n", 1); + + /* Conclusion */ + + for (i = 0; i < level; i++) + write(fd, padding->data, padding->len); + + if (trailing) + write(fd, "},\n", 3); + else + write(fd, "}\n", 2); + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à considérer. * +* context = contexte de l'analyse à mener. * +* * +* Description : Convertit une règle en JSON. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_rule_convert_as_json(const GScanRule *rule, GScanContext *context) +{ + /* TODO */ + +} diff --git a/src/analysis/scan/rule.h b/src/analysis/scan/rule.h index 12a435c..cb2c287 100644 --- a/src/analysis/scan/rule.h +++ b/src/analysis/scan/rule.h @@ -34,6 +34,7 @@ #include "expr.h" #include "patterns/backend.h" #include "../../common/fnv1a.h" +#include "../../common/szstr.h" @@ -76,6 +77,18 @@ bool g_scan_rule_setup_backend(GScanRule *, GEngineBackend *, GScanContext *); /* Lance une analyse d'un contenu binaire selon une règle. */ void g_scan_rule_check(GScanRule *, GEngineBackend *, GScanContext *); +/* Affiche une règle au format texte. */ +void g_scan_rule_output_to_text(const GScanRule *, GScanContext *, int); + +/* Convertit une règle en texte. */ +void g_scan_rule_convert_as_text(const GScanRule *, GScanContext *); + +/* Affiche une règle au format JSON. */ +void g_scan_rule_output_to_json(const GScanRule *, GScanContext *, const sized_string_t *, unsigned int, int, bool); + +/* Convertit une règle en JSON. */ +void g_scan_rule_convert_as_json(const GScanRule *, GScanContext *); + #endif /* _ANALYSIS_SCAN_RULE_H */ diff --git a/src/analysis/scan/scanner.c b/src/analysis/scan/scanner.c index ce8d677..b550b1f 100644 --- a/src/analysis/scan/scanner.c +++ b/src/analysis/scan/scanner.c @@ -510,6 +510,8 @@ GScanContext *g_content_scanner_analyze(GContentScanner *scanner, GScanOptions * g_engine_backend_run_scan(scanner->data_backend, result); + g_scan_context_mark_scan_as_done(result); + for (i = 0; i < scanner->rule_count; i++) g_scan_rule_check(scanner->rules[i], scanner->data_backend, result); @@ -518,3 +520,117 @@ GScanContext *g_content_scanner_analyze(GContentScanner *scanner, GScanOptions * return result; } + + +/****************************************************************************** +* * +* Paramètres : scanner = gestionnaire de recherche à consulter. * +* context = contexte de l'analyse à mener. * +* fd = canal d'écriture. * +* * +* Description : Affiche un gestionnaire de recherches au format texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_content_scanner_output_to_text(const GContentScanner *scanner, GScanContext *context, int fd) +{ + size_t i; /* Boucle de parcours */ + + /* Sous-traitance aux règles */ + + for (i = 0; i < scanner->rule_count; i++) + g_scan_rule_output_to_text(scanner->rules[i], context, fd); + +} + + +/****************************************************************************** +* * +* Paramètres : scanner = gestionnaire de recherche à consulter. * +* context = contexte de l'analyse à mener. * +* * +* Description : Convertit un gestionnaire de recherches en texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_content_scanner_convert_as_text(const GContentScanner *scanner, GScanContext *context) +{ + /* TODO */ + +} + + +/****************************************************************************** +* * +* Paramètres : scanner = gestionnaire de recherche à consulter. * +* context = contexte de l'analyse à mener. * +* padding = éventuel bourrage initial à placer ou NULL. * +* level = profondeur actuelle. * +* fd = canal d'écriture. * +* * +* Description : Affiche un gestionnaire de recherches au format JSON. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_content_scanner_output_to_json(const GContentScanner *scanner, GScanContext *context, const sized_string_t *padding, unsigned int level, int fd) +{ + size_t i; /* Boucle de parcours */ + bool trailing; /* Virgule finale */ + + /* Introduction */ + + for (i = 0; i < level; i++) + write(fd, padding->data, padding->len); + + write(fd, "[\n", 2); + + /* Sous-traitance aux règles */ + + for (i = 0; i < scanner->rule_count; i++) + { + trailing = ((i + 1) < scanner->rule_count); + + g_scan_rule_output_to_json(scanner->rules[i], context, padding, level + 1, fd, trailing); + + } + + /* Conclusion */ + + for (i = 0; i < level; i++) + write(fd, padding->data, padding->len); + + write(fd, "]\n", 2); + +} + + +/****************************************************************************** +* * +* Paramètres : scanner = gestionnaire de recherche à consulter. * +* context = contexte de l'analyse à mener. * +* * +* Description : Convertit un gestionnaire de recherches en JSON. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_content_scanner_convert_as_json(const GContentScanner *scanner, GScanContext *context) +{ + /* TODO */ + +} diff --git a/src/analysis/scan/scanner.h b/src/analysis/scan/scanner.h index f838344..58dbe19 100644 --- a/src/analysis/scan/scanner.h +++ b/src/analysis/scan/scanner.h @@ -32,6 +32,7 @@ #include "expr.h" #include "options.h" #include "rule.h" +#include "../../common/szstr.h" @@ -71,6 +72,18 @@ bool g_content_scanner_add_rule(GContentScanner *, GScanRule *); /* Définit l'expression d'une correspondance recherchée. */ GScanContext *g_content_scanner_analyze(GContentScanner *, GScanOptions *, GBinContent *); +/* Affiche un gestionnaire de recherches au format texte. */ +void g_content_scanner_output_to_text(const GContentScanner *, GScanContext *, int); + +/* Convertit un gestionnaire de recherches en texte. */ +void g_content_scanner_convert_as_text(const GContentScanner *, GScanContext *); + +/* Affiche un gestionnaire de recherches au format JSON. */ +void g_content_scanner_output_to_json(const GContentScanner *, GScanContext *, const sized_string_t *, unsigned int, int); + +/* Convertit un gestionnaire de recherches en JSON. */ +void g_content_scanner_convert_as_json(const GContentScanner *, GScanContext *); + #endif /* _ANALYSIS_SCAN_SCANNER_H */ diff --git a/src/analysis/scan/tokens.l b/src/analysis/scan/tokens.l index f3dbc79..18594c4 100644 --- a/src/analysis/scan/tokens.l +++ b/src/analysis/scan/tokens.l @@ -15,47 +15,140 @@ #include -#define read_block(tmp) \ - ({ \ - unsigned int __depth; \ - bool __is_string; \ - char *__iter; \ - \ - __depth = 1; \ - __is_string = false; \ - \ - for (__iter = temp; __depth > 0; __iter += (__depth > 0 ? 1 : 0)) \ - { \ - *__iter = input(); \ - \ - switch (*__iter) \ - { \ - case '"': \ - __is_string = !__is_string; \ - break; \ - \ - case '{': \ - if (!__is_string) __depth++; \ - break; \ - \ - case '}': \ - if (!__is_string) \ - { \ - __depth--; \ - if (__depth == 0) unput('}'); \ - } \ - break; \ - \ - } \ - \ - } \ - \ - *__iter = '\0'; \ - \ - }) +/****************************************************************************** +* * +* Paramètres : src = liste d'octets à traiter. * +* len = taille de cette liste. * +* out = série d'octets bruts obtenue. [OUT] * +* * +* Description : Transcrit une série d'octets en en remplaçant certains. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void rost_unescape_bytes(const char *src, size_t len, sized_string_t *out) +{ + size_t i; /* Boucle de parcours */ + bin_t byte; /* Octet à analyser */ + bin_t next; /* Octet suivant */ + + out->len = 0; + + for (i = 0; i < len; i++) + { + byte = src[i]; + + switch (byte) + { + case '\\': + + next = src[i + 1]; + + switch (next) + { + case '\a': + out->data[out->len++] = '\\'; + break; + + case '\t': + out->data[out->len++] = '\t'; + break; + + case '\n': + out->data[out->len++] = '\n'; + break; + + case '\v': + out->data[out->len++] = '\v'; + break; + + case '\f': + out->data[out->len++] = '\f'; + break; + + case '\r': + out->data[out->len++] = '\r'; + break; + + case '\\': + out->data[out->len++] = '\\'; + break; + + case 'x': + + next = src[i + 2]; + + switch (next) + { + case '0' ... '9': + out->data[out->len] = (next - '0'); + break; + + case 'A' ... 'F': + out->data[out->len] = 0x10 + (next - 'A'); + break; + + case 'a' ... 'f': + out->data[out->len] = 0x10 + (next - 'a'); + break; + + } + + out->data[out->len] <<= 4; + + next = src[i + 3]; + + switch (next) + { + case '0' ... '9': + out->data[out->len] |= (next - '0'); + break; + + case 'A' ... 'F': + out->data[out->len] |= 0x10 + (next - 'A'); + break; + + case 'a' ... 'f': + out->data[out->len] |= 0x10 + (next - 'a'); + break; + + } + + out->len++; + + i += 2; + break; + + case '{': + out->data[out->len++] = '{'; + break; + + case '}': + out->data[out->len++] = '}'; + break; + + } + + i++; + break; + + default: + out->data[out->len++] = byte; + break; + + } + + } + +} + + #define PUSH_STATE(s) yy_push_state(s, yyscanner) #define POP_STATE yy_pop_state(yyscanner) @@ -88,9 +181,15 @@ %x raw_block %x strings -%x strval -%x strval_raw -%x strval_hex +%x bytes_value +%x bytes_value_raw + +%x bytes_hex +%x bytes_hex_range + +%x bytes_regex +%x bytes_regex_quantifier +%x bytes_regex_range %x condition %x strlit @@ -101,6 +200,22 @@ %x comment + +hbyte [0-9a-fA-F]{2} + +reg_allowed [^^$.|/{}()\[\]*+?\\] +reg_allowed_escaped \\^|\\$|\\\.|\\\||\\\/|\\\{|\\\}|\\\(|\\\)|\\\[|\\\]|\\\*|\\\+|\\\?|\\\\ +reg_escaped \\a|\\t|\\n|\\v|\\f|\\r +reg_byte \\x[0-9a-fA-F]{2} + +regular_chars {reg_allowed}|{reg_allowed_escaped}|{reg_escaped}|{reg_byte} + +reg_classes \\w|\\W|\\s|\\S|\\d|\\D|\\b|\\B + + +bytes_id [A-Za-z_][A-Za-z0-9_]* + + %% @@ -139,8 +254,8 @@ -(0|[1-9][0-9]*) { yylval->signed_integer = strtoll(yytext, NULL, 10); return SIGNED_INTEGER; } -0x[0-9a-f]+ { yylval->signed_integer = strtoll(yytext, NULL, 16); return SIGNED_INTEGER; } -(0|[1-9][0-9]*) { yylval->unsigned_integer = strtoull(yytext, NULL, 10); return UNSIGNED_INTEGER; } -0x[0-9a-f]+ { yylval->unsigned_integer = strtoull(yytext, NULL, 16); return UNSIGNED_INTEGER; } +(0|[1-9][0-9]*) { yylval->unsigned_integer = strtoull(yytext, NULL, 10); return UNSIGNED_INTEGER; } +0x[0-9a-f]+ { yylval->unsigned_integer = strtoull(yytext, NULL, 16); return UNSIGNED_INTEGER; } [kK][bB] { return KB; } [mM][bB] { return MB; } @@ -181,6 +296,195 @@ +%{ /* Définition de motif en hexadécimal */ %} + + "{" { + POP_STATE; + PUSH_STATE(bytes_hex); + } + + "}" { POP_STATE; } + + "[" { + PUSH_STATE(bytes_hex_range); + return HOOK_O; + } + + "-" { return MINUS; } + + "]" { + POP_STATE; + return HOOK_C; + } + + "(" { return PAREN_O; } + + ")" { return PAREN_C; } + + "|" { return PIPE; } + + "~" { return TILDE; } + + {hbyte}([ ]*{hbyte})* { + bool even; + size_t i; + bin_t byte; + bin_t value; + + tmp_0->len = 0; + + even = true; + + for (i = 0; i < yyleng; i++) + { + byte = yytext[i]; + + switch (byte) + { + case ' ': + continue; + break; + + case '0' ... '9': + value = (byte - '0'); + break; + + case 'A' ... 'F': + value = 0x10 + (byte - 'A'); + break; + + case 'a' ... 'f': + value = 0x10 + (byte - 'a'); + break; + + } + + if (even) + { + tmp_0->data[tmp_0->len] = (value << 4); + even = false; + } + + else + { + tmp_0->data[tmp_0->len++] |= value; + even = true; + } + + } + + assert(even); + +#ifndef NDEBUG + /* Pour rendre plus lisibles les impressions de débogage */ + tmp_0->data[tmp_0->len] = '\0'; +#endif + + yylval->tmp_cstring = tmp_0; + return HEX_BYTES; + + } + + [\?]{2}([ ]*[\?]{2})* { + unsigned long long counter; + size_t i; + + counter = 0; + + for (i = 0; i < yyleng; i++) + if (yytext[i] == '?') + counter++; + + assert(counter % 2 == 0); + + yylval->unsigned_integer = counter / 2; + return FULL_MASK; + + } + + +%{ /* Définition d'expressions régulières */ %} + + "/" { + POP_STATE; + printf(" -- regex\n"); + PUSH_STATE(bytes_regex); + } + + "/" { printf("exit regex\n"); POP_STATE; } + + "." { return DOT; } + + ({regular_chars})+ { + rost_unescape_bytes(yytext, yyleng, tmp_0); + + printf(" regular: '%s'\n", yytext); + +#ifndef NDEBUG + /* Pour rendre plus lisibles les impressions de débogage */ + tmp_0->data[tmp_0->len] = '\0'; +#endif + + yylval->tmp_cstring = tmp_0; + return REGEX_BYTES; + + } + + ({reg_classes})+ { + + return REGEX_CLASSES; + + } + +%{ /* \[({regular_chars}|({regular_chars})-z|{reg_classes})+\] { */ %} + + + "[" { + PUSH_STATE(bytes_regex_range); + printf(" !! entering range\n"); + return HOOK_O; + } + + "]" { + POP_STATE; + printf(" !! exiting range\n"); + return HOOK_C; + } + + + + +({regular_chars}|({regular_chars}-{regular_chars})|{reg_classes})+ { + + printf("range: '%s'\n", yytext); + return REGEX_RANGE; + + } + + "(" { return PAREN_O; } + + ")" { return PAREN_C; } + + "|" { return PIPE; } + + "*" { return MUL; } + "+" { return PLUS; } + "?" { return QUESTION; } + + "{" { + PUSH_STATE(bytes_regex_quantifier); + return BRACKET_O; + } + + "," { return COMMA; } + + "}" { + POP_STATE; + return BRACKET_C; + } + + +%{ /* Condition de correspondance */ %} "and" { return AND; } "or" { return OR; } @@ -208,10 +512,17 @@ "/" { return DIV; } "%" { return MOD; } -"(" { return PAREN_O; } -")" { return PAREN_C; } -"," { return COMMA; } +"(" { return PAREN_O; } +")" { return PAREN_C; } +"," { return COMMA; } + + +"[" { return HOOK_O; } +"]" { return HOOK_C; } + + "." { return DOT; } +"|" { return PIPE; } "none" { return NONE; } "any" { return ANY; } @@ -221,36 +532,51 @@ "in" { return IN; } -$[A-Za-z0-9_]* { - yylval->sized_cstring.data = yytext + 1; - yylval->sized_cstring.len = yyleng - 1; - return IDENTIFIER; - } + ${bytes_id} { + yylval->sized_cstring.data = yytext + 1; + yylval->sized_cstring.len = yyleng - 1; + return BYTES_ID; + } + + #{bytes_id} { + yylval->sized_cstring.data = yytext + 1; + yylval->sized_cstring.len = yyleng - 1; + return BYTES_ID_COUNTER; + } + + @{bytes_id} { + yylval->sized_cstring.data = yytext + 1; + yylval->sized_cstring.len = yyleng - 1; + return BYTES_ID_START; + } + + !{bytes_id} { + yylval->sized_cstring.data = yytext + 1; + yylval->sized_cstring.len = yyleng - 1; + return BYTES_ID_LENGTH; + } + + ~{bytes_id} { + yylval->sized_cstring.data = yytext + 1; + yylval->sized_cstring.len = yyleng - 1; + return BYTES_ID_END; + } -$[A-Za-z_][A-Za-z0-9_]* { - yylval->sized_cstring.data = yytext + 1; - yylval->sized_cstring.len = yyleng - 1; - return BYTES_ID; - } -#[A-Za-z_][A-Za-z0-9_]* { - yylval->sized_cstring.data = yytext + 1; - yylval->sized_cstring.len = yyleng - 1; - return BYTES_ID_COUNTER; - } -[A-Za-z_][A-Za-z0-9_]* { + +[A-Za-z_][A-Za-z0-9_]* { yylval->sized_cstring.data = yytext; yylval->sized_cstring.len = yyleng; return NAME; } -"=" { PUSH_STATE(strval); return ASSIGN; } +"=" { PUSH_STATE(bytes_value); return ASSIGN; } -\"[^\"\\]+\" { +\"[^\"\\]+\" { POP_STATE; yylval->sized_cstring.data = yytext + 1; yylval->sized_cstring.len = yyleng - 2; @@ -260,43 +586,28 @@ -"\"" { +"\"" { POP_STATE; // *built_pattern = g_bytes_pattern_new(); - PUSH_STATE(strval_raw); - } -"{" { - POP_STATE; - // *built_pattern = g_bytes_pattern_new(); - PUSH_STATE(strval_hex); + PUSH_STATE(bytes_value_raw); } -"\"" { POP_STATE; /*yylval->pattern = *built_pattern*/; return MASKED_STRING; } +"\"" { POP_STATE; /*yylval->pattern = *built_pattern*/; return MASKED_STRING; } -"\\\"" { }//g_bytes_pattern_append_data(*built_pattern, '"', 0xff); } -"\\t" { }//g_bytes_pattern_append_data(*built_pattern, '\t', 0xff); } -"\\r" { }//g_bytes_pattern_append_data(*built_pattern, '\r', 0xff); } -"\\n" { }//g_bytes_pattern_append_data(*built_pattern, '\n', 0xff); } -"\\\\" { }//g_bytes_pattern_append_data(*built_pattern, '\\', 0xff); } +"\\\"" { }//g_bytes_pattern_append_data(*built_pattern, '"', 0xff); } +"\\t" { }//g_bytes_pattern_append_data(*built_pattern, '\t', 0xff); } +"\\r" { }//g_bytes_pattern_append_data(*built_pattern, '\r', 0xff); } +"\\n" { }//g_bytes_pattern_append_data(*built_pattern, '\n', 0xff); } +"\\\\" { }//g_bytes_pattern_append_data(*built_pattern, '\\', 0xff); } -\\x[0-9a-fA-F]{2} { +\\x[0-9a-fA-F]{2} { uint8_t __ch; __ch = strtol(yytext + 2, NULL, 16); + printf("__ch: %hhx\n", __ch); //g_bytes_pattern_append_data(*built_pattern, __ch, 0xff); } -. { }//g_bytes_pattern_append_data(*built_pattern, *yytext, 0xff); } - -"}" { POP_STATE; /*yylval->pattern = *built_pattern;*/ return MASKED_STRING; } - -[0-9a-fA-F]{2} { - uint8_t __ch; - __ch = strtol(yytext, NULL, 16); - //g_bytes_pattern_append_data(*built_pattern, __ch, 0xff); - } - -"??" { /*g_bytes_pattern_insert_space(*built_pattern, 1, 1);*/ } - +. { }//g_bytes_pattern_append_data(*built_pattern, *yytext, 0xff); } @@ -318,7 +629,9 @@ %{ /* Actions par défaut */ %} -<*>[ \t\n]+ { } +<*>[ \t]+ { } + +<*>[\n] { static int ln = 1; if (0) printf("----------- %%< -------------- %%< ---- %d\n", ln++); } <*>. { char *msg; diff --git a/src/common/cpp.h b/src/common/cpp.h index b1606ed..39e7676 100644 --- a/src/common/cpp.h +++ b/src/common/cpp.h @@ -46,6 +46,8 @@ #define SIZE_T_MAXLEN strlen(XSTR(LONG_MAX)) +#define ULLONG_MAXLEN (sizeof(XSTR(ULLONG_MAX)) + 1) + /** * Emprunt au noyau Linux (cf. include/linux/bug.h) pour les vérifications à la compilation. diff --git a/src/common/szstr.h b/src/common/szstr.h index d73e489..0091482 100644 --- a/src/common/szstr.h +++ b/src/common/szstr.h @@ -30,6 +30,7 @@ #include "sort.h" +#include "../arch/archbase.h" @@ -42,6 +43,9 @@ typedef struct _sized_string_t } sized_string_t; +typedef sized_string_t sized_binary_t; + + #define init_szstr(s) \ do \ { \ @@ -59,6 +63,8 @@ typedef struct _sized_string_t } \ while (0) +#define copy_szstr(d, s) (d) = (s); + #define exit_szstr(s) \ do \ { \ diff --git a/src/core/core.c b/src/core/core.c index 26469ff..626d58b 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -105,17 +105,18 @@ bool load_all_core_components(bool cs) explorer = g_content_explorer_new(); set_current_content_explorer(explorer); + resolver = g_content_resolver_new(); + set_current_content_resolver(resolver); + #ifdef HAVE_MAGIC_SUPPORT if (result) result = init_magic_cookie(); #endif - resolver = g_content_resolver_new(); - set_current_content_resolver(resolver); - root_ns = g_scan_namespace_new(NULL); set_rost_root_namespace(root_ns); if (result) result = populate_main_scan_namespace(root_ns); + if (result) result = load_all_known_scan_token_modifiers(); if (result) result = init_segment_content_hash_table(); @@ -157,6 +158,7 @@ void unload_all_core_components(bool cs) unload_processors_definitions(); + unload_all_scan_token_modifiers(); set_rost_root_namespace(NULL); #ifdef HAVE_MAGIC_SUPPORT diff --git a/src/rost.c b/src/rost.c index 40fe587..66f2ba6 100644 --- a/src/rost.c +++ b/src/rost.c @@ -87,6 +87,8 @@ static void show_rost_help(const char *name) printf("\n"); printf("\t-A --algorithm=name\tSelect one of the available algorithms for data: bitmap, acism (default: acsim).\n"); + printf("\t-j --print-json\t\tPrint matching strings in JSON format.\n"); + printf("\t-s --print-strings\tPrint matching strings.\n"); printf("\t-S --print-stats\tPrint rules' statistics.\n"); printf("\t-V --verbosity=level\tSet the log level (0 for all messages, %u for none).\n", LMT_COUNT); @@ -165,11 +167,14 @@ int main(int argc, char **argv) GContentScanner *scanner; /* Encadrement d'une recherche */ GBinContent *content; /* Contenu à analyser */ GScanContext *context; /* Contexte des trouvailles */ + sized_string_t padding; /* Bourrage pour le JSON */ static struct option long_options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { "algorithm", required_argument, NULL, 'A' }, + { "print-json", no_argument, NULL, 'j' }, + { "print-strings", no_argument, NULL, 's' }, { "print-stats", no_argument, NULL, 'S' }, { "verbosity", required_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } @@ -190,7 +195,7 @@ int main(int argc, char **argv) while (true) { - ret = getopt_long(argc, argv, "hvA:SV:", long_options, &index); + ret = getopt_long(argc, argv, "hvA:jsSV:", long_options, &index); if (ret == -1) break; switch (ret) @@ -212,6 +217,14 @@ int main(int argc, char **argv) g_scan_options_set_backend_for_data(options, G_TYPE_INVALID); break; + case 'j': + g_scan_options_set_print_json(options, true); + break; + + case 's': + g_scan_options_set_print_strings(options, true); + break; + case 'S': g_scan_options_set_print_stats(options, true); break; @@ -288,7 +301,16 @@ int main(int argc, char **argv) context = g_content_scanner_analyze(scanner, options, content); - g_scan_context_display(context); + if (g_scan_options_get_print_json(options)) + { + padding.data = " "; + padding.len = 3; + + g_content_scanner_output_to_json(scanner, context, &padding, 0, STDOUT_FILENO); + + } + else + g_content_scanner_output_to_text(scanner, context, STDOUT_FILENO); g_object_unref(G_OBJECT(context)); g_object_unref(G_OBJECT(content)); diff --git a/tests/analysis/scan/pyapi.py b/tests/analysis/scan/pyapi.py index 1bba44e..b5b2453 100644 --- a/tests/analysis/scan/pyapi.py +++ b/tests/analysis/scan/pyapi.py @@ -1,8 +1,12 @@ +import binascii + from chrysacase import ChrysalideTestCase from gi._constants import TYPE_INVALID from pychrysalide.analysis.scan import ScanExpression from pychrysalide.analysis.scan import ScanOptions +from pychrysalide.analysis.scan import find_token_modifiers_for_name +from pychrysalide.analysis.scan.patterns.modifiers import PlainModifier from pychrysalide.glibext import ComparableItem @@ -24,6 +28,7 @@ class TestRostPythonAPI(ChrysalideTestCase): e = ScanExpression() + def testBooleanComparison(self): """Compare custom scan expressions.""" @@ -56,3 +61,31 @@ class TestRostPythonAPI(ChrysalideTestCase): # TypeError: '<' not supported between instances of 'StrLenExpr' and 'StrLenExpr' with self.assertRaisesRegex(TypeError, '\'<\' not supported between instances'): self.assertTrue(e0 < e1) + + + def testBytePatternModifiers(self): + """Validate the bytes produced by modifiers.""" + + mod = find_token_modifiers_for_name('plain') + self.assertIsNotNone(mod) + + source = b'ABC' + transformed = mod.transform(source) + + self.assertEqual(source, transformed[0]) + + mod = find_token_modifiers_for_name('hex') + self.assertIsNotNone(mod) + + source = b'ABC' + transformed = mod.transform(source) + + self.assertEqual(binascii.hexlify(source), transformed[0]) + + mod = find_token_modifiers_for_name('rev') + self.assertIsNotNone(mod) + + source = b'ABC' + transformed = mod.transform(source) + + self.assertEqual(source[::-1], transformed[0]) diff --git a/tests/analysis/scan/scanning_hex.py b/tests/analysis/scan/scanning_hex.py new file mode 100644 index 0000000..e009b79 --- /dev/null +++ b/tests/analysis/scan/scanning_hex.py @@ -0,0 +1,26 @@ + +from common import RostTestClass +from pychrysalide.analysis.contents import MemoryContent + + +class TestRostScanning(RostTestClass): + """TestCases for the bytes section syntax.""" + + def testSimpleHexPattern(self): + """Test a simple hex pattern.""" + + cnt = MemoryContent(b'123-Abc-456') + + rule = ''' +rule test { + + strings: + $a = { 41 62 63 } + + condition: + #a == 1 and @a[0] == 4 + +} +''' + + self.check_rule_success(rule, content=cnt) -- cgit v0.11.2-87-g4458