diff options
137 files changed, 21392 insertions, 26 deletions
@@ -69,6 +69,7 @@ resources.[ch] # Binaries src/chrysalide src/chrysalide-hub +src/rost tools/d2c/d2c # Misc diff --git a/configure.ac b/configure.ac index 492634b..9e4375c 100644 --- a/configure.ac +++ b/configure.ac @@ -6,8 +6,8 @@ m4_include([gitrev.m4]) -AC_PREREQ(2.59) -AC_INIT([chrysalide], [gitversion], [nocbos@gmail.com]) +AC_PREREQ([2.71]) +AC_INIT([chrysalide],[gitversion],[nocbos@gmail.com]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) @@ -33,7 +33,9 @@ AC_PROG_LEX AC_PROG_YACC AC_PROG_INSTALL AC_PROG_MAKE_SET -AC_PROG_LIBTOOL +LT_INIT + +CFLAGS="" AC_EGREP_CPP(yes, [#ifdef __PIE__ @@ -58,7 +60,15 @@ AC_CHECK_LIB([dl], [dlopen]) AC_HEADER_DIRENT AC_HEADER_STDBOOL -AC_HEADER_STDC +m4_warn([obsolete], +[The preprocessor macro `STDC_HEADERS' is obsolete. + Except in unusual embedded environments, you can safely include all + ISO C90 headers unconditionally.])dnl +# Autoupdate added the next two lines to ensure that your configure +# script's behavior did not change. They are probably safe to remove. +AC_CHECK_INCLUDES_DEFAULT +AC_PROG_EGREP + AC_CHECK_HEADERS([malloc.h]) AC_CHECK_HEADERS([netdb.h]) AC_CHECK_HEADERS([stdlib.h]) @@ -292,7 +302,7 @@ if test "x$enable_debug" = "xyes"; then DEBUG_CPPFLAGS="-DDEBUG" DEBUG_CFLAGS="-O0 -ggdb -gdwarf-2" else - DEBUG_CPPFLAGS="-DNDEBUG" + DEBUG_CPPFLAGS="-Ofast -DNDEBUG" fi @@ -305,6 +315,7 @@ WARNING_CFLAGS="-Wall -Wimplicit -Wreturn-type -Wunused -Wswitch -Wcomment -Wuni # _BSD_SOURCE: htobe64, be64toh # _XOPEN_SOURCE: strdup, snprintf # _ISOC99_SOURCE: INFINITY; NAN +# _GNU_SOURCE: strcasestr # GTK_DISABLE_DEPRECATED: on reste conforme au C99 #COMPLIANCE_FLAGS="-D_BSD_SOURCE -D_GNU_SOURCE -DGTK_DISABLE_DEPRECATED" COMPLIANCE_CPPFLAGS="-D_DEFAULT_SOURCE -D_GNU_SOURCE" @@ -617,6 +628,9 @@ AC_CONFIG_FILES([Makefile plugins/pychrysalide/analysis/db/Makefile plugins/pychrysalide/analysis/db/items/Makefile plugins/pychrysalide/analysis/disass/Makefile + plugins/pychrysalide/analysis/scan/Makefile + plugins/pychrysalide/analysis/scan/patterns/Makefile + plugins/pychrysalide/analysis/scan/patterns/backends/Makefile plugins/pychrysalide/analysis/storage/Makefile plugins/pychrysalide/analysis/types/Makefile plugins/pychrysalide/arch/Makefile @@ -658,6 +672,14 @@ AC_CONFIG_FILES([Makefile src/analysis/disass/Makefile src/analysis/human/Makefile src/analysis/human/asm/Makefile + src/analysis/scan/Makefile + src/analysis/scan/conds/Makefile + src/analysis/scan/exprs/Makefile + src/analysis/scan/funcs/Makefile + src/analysis/scan/matches/Makefile + src/analysis/scan/patterns/Makefile + src/analysis/scan/patterns/backends/Makefile + src/analysis/scan/patterns/tokens/Makefile src/analysis/storage/Makefile src/analysis/types/Makefile src/arch/Makefile @@ -709,7 +731,7 @@ echo -n $PACKAGE r echo AC_PACKAGE_VERSION echo -echo The GLib and object library.................. : $libgobj_version +echo The GLib type, object and signal library..... : $libgobj_version echo The thread support for GLib.................. : $libgthread_version echo The dynamic module loader for GLib........... : $libgmod_version echo The GNU Image Manipulation Program Toolkit... : $libgtk_version @@ -733,6 +755,12 @@ else disable_gtk_support="yes" fi +if test "x$enable_curl_support" = "xyes"; then + disable_curl_support="no" +else + disable_curl_support="yes" +fi + if test "x$enable_python_bindings" = "xyes"; then disable_python_bindings="no" else diff --git a/plugins/pychrysalide/analysis/Makefile.am b/plugins/pychrysalide/analysis/Makefile.am index 67cf373..43e8ed2 100644 --- a/plugins/pychrysalide/analysis/Makefile.am +++ b/plugins/pychrysalide/analysis/Makefile.am @@ -19,6 +19,7 @@ libpychrysaanalysis_la_LIBADD = \ contents/libpychrysaanalysiscontents.la \ db/libpychrysaanalysisdb.la \ disass/libpychrysaanalysisdisass.la \ + scan/libpychrysaanalysisscan.la \ storage/libpychrysaanalysisstorage.la \ types/libpychrysaanalysistypes.la @@ -31,4 +32,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaanalysis_la_SOURCES:%c=) -SUBDIRS = contents db disass storage types +SUBDIRS = contents db disass scan storage types diff --git a/plugins/pychrysalide/analysis/scan/Makefile.am b/plugins/pychrysalide/analysis/scan/Makefile.am new file mode 100644 index 0000000..80cfa8c --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/Makefile.am @@ -0,0 +1,26 @@ + +noinst_LTLIBRARIES = libpychrysaanalysisscan.la + +libpychrysaanalysisscan_la_SOURCES = \ + constants.h constants.c \ + context.h context.c \ + expr.h expr.c \ + func.h func.c \ + module.h module.c \ + options.h options.c \ + scanner.h scanner.c \ + space.h space.c + +libpychrysaanalysisscan_la_LIBADD = \ + patterns/libpychrysaanalysisscanpatterns.la + +libpychrysaanalysisscan_la_CFLAGS = $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libpychrysaanalysisscan_la_SOURCES:%c=) + + +SUBDIRS = patterns diff --git a/plugins/pychrysalide/analysis/scan/constants.c b/plugins/pychrysalide/analysis/scan/constants.c new file mode 100644 index 0000000..87f3ae8 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/constants.c @@ -0,0 +1,131 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.c - ajout des constantes de base pour les types + * + * Copyright (C) 2020 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 "constants.h" + + +#include <analysis/scan/expr.h> + + +#include "../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes relatives aux expressions de scan. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool define_expression_value_type_constants(PyTypeObject *type) +{ + bool result; /* Bilan à retourner */ + PyObject *values; /* Groupe de valeurs à établir */ + + values = PyDict_New(); + + result = add_const_to_group(values, "BOOLEAN", EVT_BOOLEAN); + if (result) result = add_const_to_group(values, "INTEGER", EVT_INTEGER); + if (result) result = add_const_to_group(values, "STRING", EVT_STRING); + if (result) result = add_const_to_group(values, "REG_EXPR", EVT_REG_EXPR); + if (result) result = add_const_to_group(values, "COUNT", EVT_COUNT); + if (result) result = add_const_to_group(values, "PENDING", EVT_PENDING); + if (result) result = add_const_to_group(values, "UNRESOLVABLE", EVT_UNRESOLVABLE); + + if (!result) + { + Py_DECREF(values); + goto exit; + } + + result = attach_constants_group_to_type(type, false, "ExprValueType", values, + "Natural type equivalent to a given scan expression."); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* 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 constante ExprValueType. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_expression_value_type(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + unsigned long value; /* Valeur transcrite */ + + result = PyObject_IsInstance(arg, (PyObject *)&PyLong_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 ExprValueType"); + break; + + case 1: + value = PyLong_AsUnsignedLong(arg); + + if (value > EVT_COUNT) + { + PyErr_SetString(PyExc_TypeError, "invalid value for ExprValueType"); + result = 0; + } + + else + *((ExprValueType *)dst) = value; + + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/constants.h b/plugins/pychrysalide/analysis/scan/constants.h new file mode 100644 index 0000000..65eb7bc --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/constants.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.h - prototypes pour l'ajout des constantes de base pour les types + * + * Copyright (C) 2020 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_TYPES_CONSTANTS_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_TYPES_CONSTANTS_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Définit les constantes relatives aux expressions de scan. */ +bool define_expression_value_type_constants(PyTypeObject *); + +/* Tente de convertir en constante ExprValueType. */ +int convert_to_expression_value_type(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_TYPES_CONSTANTS_H */ diff --git a/plugins/pychrysalide/analysis/scan/context.c b/plugins/pychrysalide/analysis/scan/context.c new file mode 100644 index 0000000..1b418ea --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/context.c @@ -0,0 +1,266 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * context.c - équivalent Python du fichier "analysis/scan/context.c" + * + * 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 "context.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/content.h> +#include <analysis/scan/context-int.h> +#include <analysis/scan/expr.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/pychrysalide/analysis/scan/expr.h> + + + +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 *); + +/* Indique si une correspondance globale a pu être établie. */ +static PyObject *py_scan_context_has_match_for_rule(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_context_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_CONTEXT_DOC \ + "A ScanContext object tracks results of a run analysis process" \ + " against binary contents.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ScanContext()" + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, ""); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* 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). * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_context_has_match_for_rule(PyObject *self, PyObject *args) +{ + PyObject *result; /* Contexte de suivi à renvoyer*/ + const char *name; /* Désignation de règle */ + int ret; /* Bilan de lecture des args. */ + GScanContext *context; /* Contexte de suivi d'analyse */ + bool matched; /* Bilan d'analyse à renvoyer */ + +#define SCAN_CONTEXT_HAS_MATCH_FOR_RULE_METHOD PYTHON_METHOD_DEF \ +( \ + has_match_for_rule, "$self, name, /", \ + METH_VARARGS, py_scan_context, \ + "Provide the match status for a given scan rule.\n" \ + "\n" \ + "The *name* argument points to the registered rule to query.\n" \ + "\n" \ + "The method returns the scan final status as a boolean: *True*" \ + " in case of match, *False* otherwise." \ +) + + ret = PyArg_ParseTuple(args, "s", &name); + if (!ret) return NULL; + + context = G_SCAN_CONTEXT(pygobject_get(self)); + + matched = g_scan_context_has_match_for_rule(context, name); + + result = matched ? Py_True : Py_False; + Py_INCREF(result); + + 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_context_type(void) +{ + static PyMethodDef py_scan_context_methods[] = { + SCAN_CONTEXT_HAS_MATCH_FOR_RULE_METHOD, + { NULL } + }; + + static PyGetSetDef py_scan_context_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_context_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ScanContext", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_CONTEXT_DOC, + + .tp_methods = py_scan_context_methods, + .tp_getset = py_scan_context_getseters, + + .tp_init = py_scan_context_init, + .tp_new = py_scan_context_new, + + }; + + return &py_scan_context_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.....scan.ScanContext. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_context_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ScanContext' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_context_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_CONTEXT, type, &PyGObject_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 contexte de suivi d'analyse. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_context(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_context_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 scan context"); + break; + + case 1: + *((GScanContext **)dst) = G_SCAN_CONTEXT(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/context.h b/plugins/pychrysalide/analysis/scan/context.h new file mode 100644 index 0000000..477205b --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/context.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * context.h - prototypes pour l'équivalent Python du fichier "analysis/scan/context.h" + * + * 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_CONTEXT_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_CONTEXT_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_context_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanContext'. */ +bool ensure_python_scan_context_is_registered(void); + +/* Tente de convertir en contexte de suivi d'analyse. */ +int convert_to_scan_context(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_CONTEXT_H */ diff --git a/plugins/pychrysalide/analysis/scan/expr.c b/plugins/pychrysalide/analysis/scan/expr.c new file mode 100644 index 0000000..14d536f --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/expr.c @@ -0,0 +1,349 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * expr.c - équivalent Python du fichier "analysis/scan/expr.c" + * + * 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 "expr.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/content.h> +#include <analysis/scan/expr-int.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/pychrysalide/glibext/comparison.h> + + +#include "constants.h" + + + +/* Initialise la classe générique des expressions d'évaluation. */ +static void py_scan_expression_init_gclass(GScanExpressionClass *, gpointer); + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(scan_expression, G_TYPE_SCAN_EXPRESSION, py_scan_expression_init_gclass); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_expression_init(PyObject *, PyObject *, PyObject *); + +/* Réalise une comparaison entre objets selon un critère précis. */ +static bool py_scan_expression_compare_rich_wrapper(const GScanExpression *, const GScanExpression *, RichCmpOperation, bool *); + + + +/****************************************************************************** +* * +* Paramètres : class = classe à initialiser. * +* unused = données non utilisées ici. * +* * +* Description : Initialise la classe générique des expressions d'évaluation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_scan_expression_init_gclass(GScanExpressionClass *class, gpointer unused) +{ + class->cmp_rich = py_scan_expression_compare_rich_wrapper; + +} + + +/****************************************************************************** +* * +* 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_expression_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + ExprValueType vtype; /* Type de valeur représentée */ + int ret; /* Bilan de lecture des args. */ + GScanExpression *expr; /* Création GLib à transmettre */ + + static char *kwlist[] = { "vtype", NULL }; + +#define SCAN_EXPRESSION_DOC \ + "A ScanExpression is an abstract object which defines an expression"\ + " involved in data matching when running a scan.\n" \ + "\n" \ + "Calls to the *__init__* constructor of this abstract object expect"\ + " the following arguments as keyword parameters:\n" \ + "* *vtype*: type of the value carried by the expression, as a" \ + " pychrysalide.analysis.scan.ScanExpression.ExprValueType value." \ + "\n" \ + "The following methods have to be defined for new classes:\n" \ + "* pychrysalide.analysis.scan.ScanExpression._cmp_rich().\n" + + /* Récupération des paramètres */ + + ret = PyArg_ParseTupleAndKeywords(args, kwds, "O&", kwlist, convert_to_expression_value_type, &vtype); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + expr = G_SCAN_EXPRESSION(pygobject_get(self)); + + if (!g_scan_expression_create(expr, vtype)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create scan expression.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : item = premier objet à cnsulter pour une comparaison. * +* other = second objet à cnsulter pour une comparaison. * +* op = opération de comparaison à réaliser. * +* status = bilan des opérations de comparaison. [OUT] * +* * +* Description : Réalise une comparaison entre objets selon un critère précis.* +* * +* Retour : true si la comparaison a pu être effectuée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_scan_expression_compare_rich_wrapper(const GScanExpression *item, const GScanExpression *other, RichCmpOperation op, bool *status) +{ + bool result; /* Etat à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + int ret; /* Bilan d'une conversion */ + +#define SCAN_EXPRESSION_CMP_RICH_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _cmp_rich, "$self, other, op, /", \ + METH_VARARGS, \ + "Abstract method used to compare the expression against another" \ + " one.\n" \ + "\n" \ + "The second *other* instance is built from the same type as *self*."\ + " The *op* argument points to a" \ + " pychrysalide.glibext.ComparableItem.RichCmpOperation mode" \ + " describing the expected comparison.\n" \ + "\n" \ + "The result is a boolean status or *None* if the comparison" \ + " process is undefined." \ +) + + result = false; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(item)); + + if (has_python_method(pyobj, "_cmp_rich")) + { + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(other))); + PyTuple_SetItem(args, 1, cast_with_constants_group_from_type(get_python_comparable_item_type(), + "RichCmpOperation", op)); + + pyret = run_python_method(pyobj, "_cmp_rich", args); + + if (pyret != NULL) + { + ret = PyBool_Check(pyret); + + if (ret) + { + *status = (pyret == Py_True); + result = true; + } + + Py_DECREF(pyret); + + } + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + 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_expression_type(void) +{ + static PyMethodDef py_scan_expression_methods[] = { + SCAN_EXPRESSION_CMP_RICH_WRAPPER, + { NULL } + }; + + static PyGetSetDef py_scan_expression_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_expression_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ScanExpression", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_EXPRESSION_DOC, + + .tp_methods = py_scan_expression_methods, + .tp_getset = py_scan_expression_getseters, + + .tp_init = py_scan_expression_init, + .tp_new = py_scan_expression_new, + + }; + + return &py_scan_expression_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...scan.ScanExpression'.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_expression_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ScanExpression'*/ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_expression_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_comparable_item_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_EXPRESSION, type, &PyGObject_Type)) + return false; + + if (!define_expression_value_type_constants(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 expression d'évaluation généraliste. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_expression(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_expression_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 match expression"); + break; + + case 1: + *((GScanExpression **)dst) = G_SCAN_EXPRESSION(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/expr.h b/plugins/pychrysalide/analysis/scan/expr.h new file mode 100644 index 0000000..00ab28d --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/expr.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * expr.h - prototypes pour l'équivalent Python du fichier "analysis/scan/expr.h" + * + * 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_EXPR_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPR_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_expression_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanExpression'. */ +bool ensure_python_scan_expression_is_registered(void); + +/* Tente de convertir en fonction d'analyse pour scan. */ +int convert_to_scan_expression(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPR_H */ diff --git a/plugins/pychrysalide/analysis/scan/func.c b/plugins/pychrysalide/analysis/scan/func.c new file mode 100644 index 0000000..61731ec --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/func.c @@ -0,0 +1,207 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * func.c - équivalent Python du fichier "analysis/scan/func.c" + * + * 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 "func.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/content.h> +#include <analysis/scan/func-int.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> + + + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(scan_function, G_TYPE_SCAN_FUNCTION, NULL); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_function_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_function_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_FUNCTION_DOC \ + "A ScanFunction instance introduces a new method to analyze data" \ + " while scanning binary content.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ScanFunction()" + + /* 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_function_type(void) +{ + static PyMethodDef py_scan_function_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_function_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_function_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ScanFunction", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = SCAN_FUNCTION_DOC, + + .tp_methods = py_scan_function_methods, + .tp_getset = py_scan_function_getseters, + + .tp_init = py_scan_function_init, + .tp_new = py_scan_function_new, + + }; + + return &py_scan_function_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....scan.ScanFunction'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_function_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ScanFunction' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_function_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_FUNCTION, type, &PyGObject_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 fonction d'analyse pour scan. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_function(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_function_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 scan function"); + break; + + case 1: + *((GScanFunction **)dst) = G_SCAN_FUNCTION(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/func.h b/plugins/pychrysalide/analysis/scan/func.h new file mode 100644 index 0000000..d5d59f0 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/func.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * func.h - prototypes pour l'équivalent Python du fichier "analysis/scan/func.h" + * + * 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_FUNC_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_FUNC_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_function_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanFunction'. */ +bool ensure_python_scan_function_is_registered(void); + +/* Tente de convertir en fonction d'analyse pour scan. */ +int convert_to_scan_function(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_FUNC_H */ diff --git a/plugins/pychrysalide/analysis/scan/module.c b/plugins/pychrysalide/analysis/scan/module.c new file mode 100644 index 0000000..48b7100 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/module.c @@ -0,0 +1,119 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire scan 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 <assert.h> + + +#include "context.h" +#include "expr.h" +#include "func.h" +#include "options.h" +#include "scanner.h" +#include "space.h" +#include "patterns/module.h" +#include "../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Ajoute le module 'analysis.scan' à un module Python. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_analysis_scan_module(PyObject *super) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_DOC \ + "This module provide all the features useful for scanning" \ + " binary contents." + + static PyModuleDef py_chrysalide_analysis_scan_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.analysis.scan", + .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_DOC, + + .m_size = -1, + + }; + + module = build_python_module(super, &py_chrysalide_analysis_scan_module); + + result = (module != NULL); + + if (result) result = add_analysis_scan_patterns_module(module); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'analysis.scan'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_analysis_scan_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_content_scanner_is_registered(); + if (result) result = ensure_python_scan_context_is_registered(); + if (result) result = ensure_python_scan_expression_is_registered(); + if (result) result = ensure_python_scan_function_is_registered(); + if (result) result = ensure_python_scan_options_is_registered(); + if (result) result = ensure_python_scan_namespace_is_registered(); + + if (result) result = populate_analysis_scan_patterns_module(); + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/module.h b/plugins/pychrysalide/analysis/scan/module.h new file mode 100644 index 0000000..a5e84b5 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/module.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire scan 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_MODULE_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Ajoute le module 'analysis.scan' à un module Python. */ +bool add_analysis_scan_module(PyObject *); + +/* Intègre les objets du module 'analysis.scan'. */ +bool populate_analysis_scan_module(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_H */ diff --git a/plugins/pychrysalide/analysis/scan/options.c b/plugins/pychrysalide/analysis/scan/options.c new file mode 100644 index 0000000..c3b29e9 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/options.c @@ -0,0 +1,355 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * options.c - équivalent Python du fichier "analysis/scan/options.c" + * + * 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 "options.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/options-int.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + + +CREATE_DYN_CONSTRUCTOR(scan_options, G_TYPE_SCAN_OPTIONS); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_options_init(PyObject *, PyObject *, PyObject *); + +/* Indique le type d'un moteur d'analyse de données sélectionné. */ +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 *); + +/* Indique un besoin de statistiques en fin de compilation. */ +static PyObject *py_scan_options_get_print_stats(PyObject *, void *); + +/* Mémorise un besoin de statistiques en fin de compilation. */ +static int py_scan_options_set_print_stats(PyObject *, 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_options_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_OPTIONS_DOC \ + "The *ScanOptions* class stores all parameters used to tune" \ + " a scanning process..\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ScanOptions()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format Axml. * +* closure = adresse non utilisée ici. * +* * +* Description : Indique le type d'un moteur d'analyse de données sélectionné.* +* * +* Retour : Type d'objet, idéalement valide. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_options_get_backend_for_data(PyObject *self, void *closure) +{ + PyObject *result; /* Liste éventuelle à renvoyer */ + GScanOptions *options; /* Version native */ + GType type; /* Type à transcrire */ + +#define SCAN_OPTIONS_BACKEND_FOR_DATA_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + backend_for_data, py_scan_options, \ + "Type of the selected scan algorithm." \ +) + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + type = g_scan_options_get_backend_for_data(options); + + result = pyg_type_wrapper_new(type); + + 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 : Sélectionne un type de moteur d'analyse pour données brutes. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_options_set_backend_for_data(PyObject *self, PyObject *value, void *closure) +{ + GType type; /* Type à transcrit */ + GScanOptions *options; /* Version native */ + + type = pyg_type_from_object(value); + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + g_scan_options_set_backend_for_data(options, type); + + 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é. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_options_get_print_stats(PyObject *self, void *closure) +{ + PyObject *result; /* Liste éventuelle à renvoyer */ + GScanOptions *options; /* Version native */ + bool state; /* Etat courant à consulter */ + +#define SCAN_OPTIONS_PRINT_STATS_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + print_stats, py_scan_options, \ + "Control the output of final statistics afer a scan." \ +) + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + state = g_scan_options_get_print_stats(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 de statistiques en fin de compilation. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_options_set_print_stats(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_stats(options, state); + + 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_options_type(void) +{ + static PyMethodDef py_scan_options_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_options_getseters[] = { + SCAN_OPTIONS_BACKEND_FOR_DATA_ATTRIB, + SCAN_OPTIONS_PRINT_STATS_ATTRIB, + { NULL } + }; + + static PyTypeObject py_scan_options_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ScanOptions", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = SCAN_OPTIONS_DOC, + + .tp_methods = py_scan_options_methods, + .tp_getset = py_scan_options_getseters, + + .tp_init = py_scan_options_init, + .tp_new = py_scan_options_new, + + }; + + return &py_scan_options_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...scan.ScanOptions'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_options_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ScanOptions' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_options_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_OPTIONS, type, &PyGObject_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 ensemble d'options d'analyses. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_options(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_options_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 scan options"); + break; + + case 1: + *((GScanOptions **)dst) = G_SCAN_OPTIONS(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/options.h b/plugins/pychrysalide/analysis/scan/options.h new file mode 100644 index 0000000..3e83880 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/options.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * options.h - prototypes pour l'équivalent Python du fichier "analysis/scan/options.h" + * + * 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_OPTIONS_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_OPTIONS_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_options_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanOptions'. */ +bool ensure_python_scan_options_is_registered(void); + +/* Tente de convertir en ensemble d'options d'analyses. */ +int convert_to_scan_options(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_OPTIONS_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/Makefile.am b/plugins/pychrysalide/analysis/scan/patterns/Makefile.am new file mode 100644 index 0000000..612f34b --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/Makefile.am @@ -0,0 +1,20 @@ + +noinst_LTLIBRARIES = libpychrysaanalysisscanpatterns.la + +libpychrysaanalysisscanpatterns_la_SOURCES = \ + backend.h backend.c \ + module.h module.c + +libpychrysaanalysisscanpatterns_la_LIBADD = \ + backends/libpychrysaanalysisscanpatternsbackends.la + +libpychrysaanalysisscanpatterns_la_CFLAGS = $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libpychrysaanalysisscanpatterns_la_SOURCES:%c=) + + +SUBDIRS = backends diff --git a/plugins/pychrysalide/analysis/scan/patterns/backend.c b/plugins/pychrysalide/analysis/scan/patterns/backend.c new file mode 100644 index 0000000..6d668f4 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backend.c @@ -0,0 +1,202 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * backend.c - équivalent Python du fichier "analysis/scan/backend.c" + * + * 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 "backend.h" + + +#include <pygobject.h> + + +#include <analysis/scan/patterns/backend-int.h> + + +#include "../../../access.h" +#include "../../../helpers.h" + + + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(engine_backend, G_TYPE_ENGINE_BACKEND, NULL); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_engine_backend_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_engine_backend_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define ENGINE_BACKEND_DOC \ + "An *EngineBackend* object is the root class of all scan algorithm" \ + " looking for data patterns." + + /* 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_engine_backend_type(void) +{ + static PyMethodDef py_engine_backend_methods[] = { + { NULL } + }; + + static PyGetSetDef py_engine_backend_getseters[] = { + { NULL } + }; + + static PyTypeObject py_engine_backend_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.EngineBackend", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = ENGINE_BACKEND_DOC, + + .tp_methods = py_engine_backend_methods, + .tp_getset = py_engine_backend_getseters, + + .tp_init = py_engine_backend_init, + .tp_new = py_engine_backend_new, + + }; + + return &py_engine_backend_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....EngineBackend'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_engine_backend_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ScanNamespace' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_engine_backend_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_ENGINE_BACKEND, type, &PyGObject_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 méthode de recherches. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_engine_backend(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_engine_backend_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 engine backend"); + break; + + case 1: + *((GEngineBackend **)dst) = G_ENGINE_BACKEND(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/backend.h b/plugins/pychrysalide/analysis/scan/patterns/backend.h new file mode 100644 index 0000000..6b1f4cd --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backend.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * backend.h - prototypes pour l'équivalent Python du fichier "analysis/scan/backend.h" + * + * 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_BACKEND_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_BACKEND_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_engine_backend_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.EngineBackend'. */ +bool ensure_python_engine_backend_is_registered(void); + +/* Tente de convertir en méthode de recherches. */ +int convert_to_engine_backend(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_BACKEND_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/Makefile.am b/plugins/pychrysalide/analysis/scan/patterns/backends/Makefile.am new file mode 100644 index 0000000..cccfc2d --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/Makefile.am @@ -0,0 +1,15 @@ + +noinst_LTLIBRARIES = libpychrysaanalysisscanpatternsbackends.la + +libpychrysaanalysisscanpatternsbackends_la_SOURCES = \ + acism.h acism.c \ + bitap.h bitap.c \ + module.h module.c + +libpychrysaanalysisscanpatternsbackends_la_CFLAGS = $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libpychrysaanalysisscanpatternsbackends_la_SOURCES:%c=) diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/acism.c b/plugins/pychrysalide/analysis/scan/patterns/backends/acism.c new file mode 100644 index 0000000..63e653a --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/acism.c @@ -0,0 +1,214 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * acism.c - équivalent Python du fichier "analysis/scan/patterns/backends/acism.c" + * + * 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 "acism.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/patterns/backends/acism-int.h> + + +#include "../backend.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(acism_backend, G_TYPE_ACISM_BACKEND); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_acism_backend_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_acism_backend_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define ACISM_BACKEND_DOC \ + "A *AcismBackend* class provide an implementation of the Aho-Corasick" \ + " search algorithm with Interleaved State-transition Matrix (ACISM)." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " AcismBackend()" \ + "\n" \ + "See the relative white paper for more information:" \ + " https://docs.google.com/document/d/1e9Qbn22__togYgQ7PNyCz3YzIIVPKvrf8PCrFa74IFM" + + /* 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_acism_backend_type(void) +{ + static PyMethodDef py_acism_backend_methods[] = { + { NULL } + }; + + static PyGetSetDef py_acism_backend_getseters[] = { + { NULL } + }; + + static PyTypeObject py_acism_backend_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.backends.AcismBackend", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = ACISM_BACKEND_DOC, + + .tp_methods = py_acism_backend_methods, + .tp_getset = py_acism_backend_getseters, + + .tp_init = py_acism_backend_init, + .tp_new = py_acism_backend_new, + + }; + + return &py_acism_backend_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....AcismBackend'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_acism_backend_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'AcismBackend'*/ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_acism_backend_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.backends"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_engine_backend_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_ACISM_BACKEND, type, &PyGObject_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 méthode de recherche ACISM. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_acism_backend(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_acism_backend_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 ACISM backend"); + break; + + case 1: + *((GAcismBackend **)dst) = G_ACISM_BACKEND(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/acism.h b/plugins/pychrysalide/analysis/scan/patterns/backends/acism.h new file mode 100644 index 0000000..9ed61fa --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/acism.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * acism.h - prototypes pour l'équivalent Python du fichier "analysis/scan/patterns/backends/acism.h" + * + * 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_BACKENDS_ACISM_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_acism_backend_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.backends.AcismBackend'. */ +bool ensure_python_acism_backend_is_registered(void); + +/* Tente de convertir en méthode de recherche ACISM. */ +int convert_to_acism_backend(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.c b/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.c new file mode 100644 index 0000000..f961bf7 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.c @@ -0,0 +1,214 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bitap.c - équivalent Python du fichier "analysis/scan/patterns/backends/bitap.c" + * + * 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 "bitap.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/patterns/backends/bitap-int.h> + + +#include "../backend.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(bitap_backend, G_TYPE_BITAP_BACKEND); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_bitap_backend_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_bitap_backend_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define BITAP_BACKEND_DOC \ + "A *BitapBackend* class provide an implementation of the Bitap" \ + " search algorithm." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " BitapBackend()" \ + "\n" \ + "See the relative white paper for more information:" \ + " https://en.wikipedia.org/wiki/Bitap_algorithm" + + /* 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_bitap_backend_type(void) +{ + static PyMethodDef py_bitap_backend_methods[] = { + { NULL } + }; + + static PyGetSetDef py_bitap_backend_getseters[] = { + { NULL } + }; + + static PyTypeObject py_bitap_backend_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.backends.BitapBackend", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = BITAP_BACKEND_DOC, + + .tp_methods = py_bitap_backend_methods, + .tp_getset = py_bitap_backend_getseters, + + .tp_init = py_bitap_backend_init, + .tp_new = py_bitap_backend_new, + + }; + + return &py_bitap_backend_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....BitapBackend'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_bitap_backend_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'BitapBackend'*/ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_bitap_backend_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.backends"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_engine_backend_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_BITAP_BACKEND, type, &PyGObject_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 méthode de recherche BITAP. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_bitap_backend(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_bitap_backend_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 Bitap backend"); + break; + + case 1: + *((GBitapBackend **)dst) = G_BITAP_BACKEND(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.h b/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.h new file mode 100644 index 0000000..f7853d4 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bitap.h - prototypes pour l'équivalent Python du fichier "analysis/scan/patterns/backends/bitap.h" + * + * 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_BACKENDS_BITAP_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_bitap_backend_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.backends.BitapBackend'. */ +bool ensure_python_bitap_backend_is_registered(void); + +/* Tente de convertir en méthode de recherche Bitap. */ +int convert_to_bitap_backend(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/module.c b/plugins/pychrysalide/analysis/scan/patterns/backends/module.c new file mode 100644 index 0000000..f4a0293 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/module.c @@ -0,0 +1,106 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire backends 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 <assert.h> + + +#include "acism.h" +#include "bitap.h" +#include "../../../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Ajoute le module 'analysis.....backends' à un module Python. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_analysis_scan_patterns_backends_module(PyObject *super) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_DOC \ + "This module provide all the features useful for scanning" \ + " binary contents." + + static PyModuleDef py_chrysalide_analysis_scan_patterns_backends_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.analysis.scan.patterns.backends", + .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_DOC, + + .m_size = -1, + + }; + + module = build_python_module(super, &py_chrysalide_analysis_scan_patterns_backends_module); + + result = (module != NULL); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'analysis....patterns.backends'.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_analysis_scan_patterns_backends_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_acism_backend_is_registered(); + if (result) result = ensure_python_bitap_backend_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/module.h b/plugins/pychrysalide/analysis/scan/patterns/backends/module.h new file mode 100644 index 0000000..ab1aad5 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/module.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire backends 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_BACKENDS_MODULE_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Ajoute le module 'analysis.scan.patterns.backends' à un module Python. */ +bool add_analysis_scan_patterns_backends_module(PyObject *); + +/* Intègre les objets du module 'analysis.scan.patterns.backends'. */ +bool populate_analysis_scan_patterns_backends_module(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/module.c b/plugins/pychrysalide/analysis/scan/patterns/module.c new file mode 100644 index 0000000..f8db49e --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/module.c @@ -0,0 +1,109 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire patterns 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 <assert.h> + + +#include "backend.h" +#include "backends/module.h" +#include "../../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Ajoute le module 'analysis.scan.patterns' à un module Python.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_analysis_scan_patterns_module(PyObject *super) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_DOC \ + "This module provide all the features useful for scanning" \ + " binary contents." + + static PyModuleDef py_chrysalide_analysis_scan_patterns_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.analysis.scan.patterns", + .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_DOC, + + .m_size = -1, + + }; + + module = build_python_module(super, &py_chrysalide_analysis_scan_patterns_module); + + result = (module != NULL); + + if (result) result = add_analysis_scan_patterns_backends_module(module); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'analysis.scan.patterns'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_analysis_scan_patterns_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_engine_backend_is_registered(); + + if (result) result = populate_analysis_scan_patterns_backends_module(); + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/module.h b/plugins/pychrysalide/analysis/scan/patterns/module.h new file mode 100644 index 0000000..bc25129 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/module.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire patterns 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_MODULE_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Ajoute le module 'analysis.scan.patterns' à un module Python. */ +bool add_analysis_scan_patterns_module(PyObject *); + +/* Intègre les objets du module 'analysis.scan.patterns'. */ +bool populate_analysis_scan_patterns_module(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_H */ diff --git a/plugins/pychrysalide/analysis/scan/scanner.c b/plugins/pychrysalide/analysis/scan/scanner.c new file mode 100644 index 0000000..8eb36a7 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/scanner.c @@ -0,0 +1,313 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scanner.c - équivalent Python du fichier "analysis/scan/scanner.c" + * + * 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 "scanner.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/content.h> +#include <analysis/scan/context.h> +#include <analysis/scan/scanner-int.h> + + +#include "options.h" +#include "../content.h" +#include "../../access.h" +#include "../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(content_scanner, G_TYPE_CONTENT_SCANNER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_content_scanner_init(PyObject *, PyObject *, PyObject *); + +/* Lance une analyse d'un contenu binaire. */ +static PyObject *py_content_scanner_analyze(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_content_scanner_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + const char *text; /* Contenu de règles à traiter */ + const char *filename; /* Fichier de définitions */ + int ret; /* Bilan de lecture des args. */ + GContentScanner *scanner; /* Création GLib à transmettre */ + + static char *kwlist[] = { "text", "filename", NULL }; + +#define CONTENT_SCANNER_DOC \ + "A ContentScanner object provides support for rules processing" \ + " against binary contents.\n" \ + "\n" \ + "Instances can be created using one of the following" \ + " constructors:\n" \ + "\n" \ + " ContentScanner(text=str)" \ + " ContentScanner(filename=str)" \ + "\n" \ + "Where *text* is a string for the rules definitions and" \ + " *filename* an alternative string for a path pointing to a" \ + " definition file." + + /* Récupération des paramètres */ + + text = NULL; + filename = NULL; + + ret = PyArg_ParseTupleAndKeywords(args, kwds, "|ss", kwlist, &text, &filename); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + scanner = G_CONTENT_SCANNER(pygobject_get(self)); + + if (text != NULL) + { + if (!g_content_scanner_create_from_text(scanner, text)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create content scanner.")); + return -1; + } + + } + + else if (filename != NULL) + { + if (!g_content_scanner_create_from_file(scanner, filename)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create content scanner.")); + return -1; + } + + } + + else + { + PyErr_SetString(PyExc_ValueError, _("Unable to create empty content scanner.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format. * +* args = arguments fournis à l'appel. * +* * +* Description : Lance une analyse d'un contenu binaire. * +* * +* Retour : Contexte de suivi pour l'analyse menée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_content_scanner_analyze(PyObject *self, PyObject *args) +{ + PyObject *result; /* Contexte de suivi à renvoyer*/ + GScanOptions *options; /* Paramètres d'analyse */ + GBinContent *content; /* Contenu binaire à traiter */ + int ret; /* Bilan de lecture des args. */ + GContentScanner *scanner; /* Encadrement de recherche */ + GScanContext *context; /* Contexte de suivi */ + +#define CONTENT_SCANNER_ANALYZE_METHOD PYTHON_METHOD_DEF \ +( \ + analyze, "$self, options, content, /", \ + METH_VARARGS, py_content_scanner, \ + "Run a scan against a binary content.\n" \ + "\n" \ + "The *content* argument is a pychrysalide.analysis.BinContent" \ + " object pointing to data to analyze.\n" \ + "\n" \ + "The method returns a pychrysalide.analysis.scan.ScanContext" \ + " object tracking all the scan results." \ +) + + ret = PyArg_ParseTuple(args, "O&O&", convert_to_scan_options, &options, convert_to_binary_content, &content); + if (!ret) return NULL; + + scanner = G_CONTENT_SCANNER(pygobject_get(self)); + + context = g_content_scanner_analyze(scanner, options, content); + + result = pygobject_new(G_OBJECT(context)); + + 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_content_scanner_type(void) +{ + static PyMethodDef py_content_scanner_methods[] = { + CONTENT_SCANNER_ANALYZE_METHOD, + { NULL } + }; + + static PyGetSetDef py_content_scanner_getseters[] = { + { NULL } + }; + + static PyTypeObject py_content_scanner_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ContentScanner", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = CONTENT_SCANNER_DOC, + + .tp_methods = py_content_scanner_methods, + .tp_getset = py_content_scanner_getseters, + + .tp_init = py_content_scanner_init, + .tp_new = py_content_scanner_new, + + }; + + return &py_content_scanner_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...scan.ContentScanner. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_content_scanner_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ContentScanner'*/ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_content_scanner_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_CONTENT_SCANNER, type, &PyGObject_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 scanner de contenus binaires. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_content_scanner(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_content_scanner_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 content scanner"); + break; + + case 1: + *((GContentScanner **)dst) = G_CONTENT_SCANNER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/scanner.h b/plugins/pychrysalide/analysis/scan/scanner.h new file mode 100644 index 0000000..b3b1baf --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/scanner.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scanner.h - prototypes pour l'équivalent Python du fichier "analysis/scan/scanner.h" + * + * 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_SCANNER_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SCANNER_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_content_scanner_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ContentScanner'. */ +bool ensure_python_content_scanner_is_registered(void); + +/* Tente de convertir en scanner de contenus binaires. */ +int convert_to_content_scanner(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SCANNER_H */ diff --git a/plugins/pychrysalide/analysis/scan/space.c b/plugins/pychrysalide/analysis/scan/space.c new file mode 100644 index 0000000..9f29829 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/space.c @@ -0,0 +1,297 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * space.c - équivalent Python du fichier "analysis/scan/space.c" + * + * 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 "space.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/content.h> +#include <analysis/scan/space-int.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> + + + +CREATE_DYN_CONSTRUCTOR(scan_namespace, G_TYPE_SCAN_NAMESPACE); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_namespace_init(PyObject *, PyObject *, PyObject *); + +/* Indique le nom attribué à un espace de noms. */ +static PyObject *py_scan_namespace_get_name(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_namespace_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_NAMESPACE_DOC \ + "ScanNamespace defines a group of properties and functions for a" \ + " given scan theme.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ScanNamespace()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + +#if 0 +/****************************************************************************** +* * +* Paramètres : self = objet représentant une table de chaînes. * +* args = arguments fournis pour l'opération. * +* * +* Description : Remplace les propriétés renvoyant à des ressources. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_namespace_resolve(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + GResourceTable *table; /* Table de ressources */ + int ret; /* Bilan de lecture des args. */ + GScanNamespace *format; /* Version native */ + +#define SCAN_NAMESPACE_RESOLVE_METHOD PYTHON_METHOD_DEF \ +( \ + resolve, "$self, table, /", \ + METH_VARARGS, py_scan_namespace, \ + "Resolve all XML node attribute values pointing to" \ + " resource entries. Such values are identifiers" \ + " of the forme '@0x...'.\n" \ + "\n" \ + "The *table* argument has to be a loaded" \ + " pychrysalide.format.androidfw.ResourceTable" \ + " instance.\n" \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_resource_table, &table); + if (!ret) return NULL; + + format = G_SCAN_NAMESPACE(pygobject_get(self)); + + g_scan_namespace_resvolve(format, table); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format Axml. * +* closure = adresse non utilisée ici. * +* * +* Description : Indique le nom attribué à un espace de noms. * +* * +* Retour : Désignation associée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_namespace_get_name(PyObject *self, void *closure) +{ + PyObject *result; /* Liste éventuelle à renvoyer */ + GScanNamespace *space; /* Version native */ + const char *name; /* Désignation à exporter */ + +#define SCAN_NAMESPACE_NAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + name, py_scan_namespace, \ + "Name provided for the namespace." \ +) + + space = G_SCAN_NAMESPACE(pygobject_get(self)); + + name = g_scan_namespace_get_name(space); + + result = PyUnicode_FromString(name); + + return result; + +} +#endif + + +/****************************************************************************** +* * +* 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_namespace_type(void) +{ + static PyMethodDef py_scan_namespace_methods[] = { + //SCAN_NAMESPACE_RESOLVE_METHOD, + { NULL } + }; + + static PyGetSetDef py_scan_namespace_getseters[] = { + //SCAN_NAMESPACE_NAME_ATTRIB, + { NULL } + }; + + static PyTypeObject py_scan_namespace_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ScanNamespace", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = SCAN_NAMESPACE_DOC, + + .tp_methods = py_scan_namespace_methods, + .tp_getset = py_scan_namespace_getseters, + + .tp_init = py_scan_namespace_init, + .tp_new = py_scan_namespace_new, + + }; + + return &py_scan_namespace_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...scan.ScanNamespace'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_namespace_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ScanNamespace' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_namespace_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_NAMESPACE, type, &PyGObject_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 espace de noms pour scan. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_namespace(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_namespace_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 scan namespace"); + break; + + case 1: + *((GScanNamespace **)dst) = G_SCAN_NAMESPACE(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/space.h b/plugins/pychrysalide/analysis/scan/space.h new file mode 100644 index 0000000..0166c04 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/space.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * space.h - prototypes pour l'équivalent Python du fichier "analysis/scan/space.h" + * + * 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_SPACE_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SPACE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_namespace_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanNamespace'. */ +bool ensure_python_scan_namespace_is_registered(void); + +/* Tente de convertir en espace de noms pour scan. */ +int convert_to_scan_namespace(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SPACE_H */ diff --git a/src/Makefile.am b/src/Makefile.am index 8f746d6..1fe76bc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ lib_LTLIBRARIES = libchrysacore.la -bin_PROGRAMS = chrysalide chrysalide-hub +bin_PROGRAMS = chrysalide chrysalide-hub rost AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/intl @@ -20,6 +20,7 @@ GOBJECT_LEAKS_SOURCES = gleak.h gleak.c endif +libchrysacore_la_SOURCES = if BUILD_GTK_SUPPORT @@ -38,8 +39,19 @@ if BUILD_GTK_SUPPORT endif -libchrysacore_la_SOURCES = \ - $(GOBJECT_LEAKS_SOURCES) +libchrysacore_la_LIBADD = \ + analysis/libanalysis.la \ + arch/libarch.la \ + common/libcommon.la \ + core/libcore.la \ + debug/libdebug.la \ + format/libformat.la \ + glibext/libglibext.la \ + $(GTKEXT_LIBADD) \ + $(GUI_LIBADD) \ + mangling/libmangling.la \ + plugins/libplugins.la + # -ldl: dladdr(), dlerror() libchrysacore_la_LDFLAGS = \ @@ -54,28 +66,16 @@ libchrysacore_la_LDFLAGS += $(LIBCURL_LIBS) endif -libchrysacore_la_LIBADD = \ - analysis/libanalysis.la \ - arch/libarch.la \ - common/libcommon.la \ - core/libcore.la \ - debug/libdebug.la \ - format/libformat.la \ - glibext/libglibext.la \ - $(GTKEXT_LIBADD) \ - $(GUI_LIBADD) \ - mangling/libmangling.la \ - plugins/libplugins.la - ############################################################ # Programme principal ############################################################ -EXTRA_chrysalide_DEPENDENCIES = $(lib_LTLIBRARIES) +EXTRA_chrysalide_DEPENDENCIES = libchrysacore.la chrysalide_SOURCES = \ + $(GOBJECT_LEAKS_SOURCES) \ main.c @@ -92,9 +92,10 @@ chrysalide_LDADD = $(LIBINTL) # Gestionnaire de serveurs distants ############################################################ -EXTRA_chrysalide_hub_DEPENDENCIES = $(lib_LTLIBRARIES) +EXTRA_chrysalide_hub_DEPENDENCIES = libchrysacore.la chrysalide_hub_SOURCES = \ + $(GOBJECT_LEAKS_SOURCES) \ hub.c chrysalide_hub_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) @@ -104,6 +105,22 @@ chrysalide_hub_LDFLAGS = $(TOOLKIT_LIBS) $(LIBXML_LIBS) -L.libs -lchrysacore ############################################################ +# Détecteur de motifs +############################################################ + +EXTRA_rost_DEPENDENCIES = libchrysacore.la + +rost_SOURCES = \ + $(GOBJECT_LEAKS_SOURCES) \ + rost.c + +rost_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) + +rost_LDFLAGS = $(LIBGOBJ_LIBS) -L.libs -lchrysacore + + + +############################################################ # Le reste du monde ############################################################ diff --git a/src/analysis/Makefile.am b/src/analysis/Makefile.am index 39dd2dd..909ced9 100644 --- a/src/analysis/Makefile.am +++ b/src/analysis/Makefile.am @@ -25,6 +25,7 @@ libanalysis_la_LIBADD = \ db/libanalysisdb.la \ disass/libanalysisdisass.la \ human/libanalysishuman.la \ + scan/libanalysisscan.la \ storage/libanalysisstorage.la \ types/libanalysistypes.la @@ -34,4 +35,4 @@ devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) dev_HEADERS = $(libanalysis_la_SOURCES:%c=) -SUBDIRS = contents db disass human storage types +SUBDIRS = contents db disass human scan storage types diff --git a/src/analysis/scan/Makefile.am b/src/analysis/scan/Makefile.am new file mode 100644 index 0000000..bcec986 --- /dev/null +++ b/src/analysis/scan/Makefile.am @@ -0,0 +1,67 @@ + +BUILT_SOURCES = grammar.h + + +# On évite d'utiliser les variables personnalisées de type *_la_[YL]FLAGS +# afin de conserver des noms de fichiers simples, ie sans le nom de la +# bibliothèque de sortie en préfixe. + +AM_YFLAGS = -v -d -p rost_ -Wno-yacc -Wcounterexamples + +AM_LFLAGS = -P rost_ -o lex.yy.c --header-file=tokens.h \ + -Dyyget_lineno=rost_get_lineno \ + -Dyy_scan_bytes=rost__scan_bytes \ + -Dyy_delete_buffer=rost__delete_buffer + +noinst_LTLIBRARIES = libanalysisscan.la + + +libanalysisscan_la_SOURCES = \ + cond-int.h \ + cond.h cond.c \ + context-int.h \ + context.h context.c \ + core.h core.c \ + expr-int.h \ + expr.h expr.c \ + func-int.h \ + func.h func.c \ + item-int.h \ + item.h item.c \ + match-int.h \ + match.h match.c \ + options-int.h \ + options.h options.c \ + pattern-int.h \ + pattern.h pattern.c \ + rule-int.h \ + rule.h rule.c \ + scanner-int.h \ + scanner.h scanner.c \ + space-int.h \ + space.h space.c \ + tokens.l \ + grammar.y + +libanalysisscan_la_LIBADD = \ + exprs/libanalysisscanexprs.la \ + funcs/libanalysisscanfuncs.la \ + matches/libanalysisscanmatches.la \ + patterns/libanalysisscanpatterns.la + +libanalysisscan_la_CFLAGS = $(LIBGOBJ_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libanalysisscan_la_SOURCES:%c=) + + +# Automake fait les choses à moitié +CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h + +# Pareil : de tous les fichiers générés, seule la sortie de Flex saute pour les distributions ! +EXTRA_DIST = tokens.h + + +SUBDIRS = exprs funcs matches patterns diff --git a/src/analysis/scan/cond-int.h b/src/analysis/scan/cond-int.h new file mode 100644 index 0000000..aeb3fc9 --- /dev/null +++ b/src/analysis/scan/cond-int.h @@ -0,0 +1,63 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * cond-int.h - prototypes internes pour le parcours de contenus à la recherche de motifs + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_COND_INT_H +#define _ANALYSIS_SCAN_COND_INT_H + + +#include "cond.h" + + + +/* Indique le statut d'une condition de validation. */ +typedef bool (* resolve_cond_fc) (const GMatchCondition *); + +/* Indique le statut d'une condition de validation. */ +typedef unsigned long long (* resolve_cond_as_number_fc) (const GMatchCondition *); + +/* Avance vers la validation d'une condition, si besoin est. */ +typedef void (* analyze_cond_fc) (const GMatchCondition *, const bin_t *, phys_t, phys_t, bool); + + + +/* Expression conditionnelle manipulant des motifs (instance) */ +struct _GMatchCondition +{ + GObject parent; /* A laisser en premier */ + +}; + +/* Expression conditionnelle manipulant des motifs (classe) */ +struct _GMatchConditionClass +{ + GObjectClass parent; /* A laisser en premier */ + + resolve_cond_fc resolve; /* Réduction en booléen */ + resolve_cond_as_number_fc resolve_as_num; /* Réduction en nombre */ + analyze_cond_fc analyze; /* Analyse selon une position */ + +}; + + + +#endif /* _ANALYSIS_SCAN_COND_INT_H */ diff --git a/src/analysis/scan/cond.c b/src/analysis/scan/cond.c new file mode 100644 index 0000000..be5b3cb --- /dev/null +++ b/src/analysis/scan/cond.c @@ -0,0 +1,220 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * cond.c - expression conditionnelle validant la présence de motifs donnés + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "cond.h" + + +#include "cond-int.h" + + + +/* Initialise la classe des recherches dans du binaire. */ +static void g_match_condition_class_init(GMatchConditionClass *); + +/* Initialise une instance de recherche dans du binaire. */ +static void g_match_condition_init(GMatchCondition *); + +/* Supprime toutes les références externes. */ +static void g_match_condition_dispose(GMatchCondition *); + +/* Procède à la libération totale de la mémoire. */ +static void g_match_condition_finalize(GMatchCondition *); + + + +/* Indique le type défini pour une expression de validation. */ +G_DEFINE_TYPE(GMatchCondition, g_match_condition, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des recherches dans du binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_match_condition_class_init(GMatchConditionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + klass->resolve = NULL; + klass->resolve_as_num = NULL; + klass->analyze = NULL; + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_match_condition_dispose; + object->finalize = (GObjectFinalizeFunc)g_match_condition_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : cond = instance à initialiser. * +* * +* Description : Initialise une instance de recherche dans du binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_match_condition_init(GMatchCondition *cond) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : cond = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_match_condition_dispose(GMatchCondition *cond) +{ + G_OBJECT_CLASS(g_match_condition_parent_class)->dispose(G_OBJECT(cond)); + +} + + +/****************************************************************************** +* * +* Paramètres : cond = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_match_condition_finalize(GMatchCondition *cond) +{ + G_OBJECT_CLASS(g_match_condition_parent_class)->finalize(G_OBJECT(cond)); + +} + + +/****************************************************************************** +* * +* Paramètres : cond = condition à consulter. * +* * +* Description : Indique le statut d'une condition de validation. * +* * +* Retour : Validation de la condition considérée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_match_condition_resolve(const GMatchCondition *cond) +{ + bool result; /* Bilan à retourner */ + GMatchConditionClass *class; /* Classe à activer */ + unsigned long long number; /* Valeur à considérer */ + + class = G_MATCH_CONDITION_GET_CLASS(cond); + + if (class->resolve != NULL) + result = class->resolve(cond); + + else if (class->resolve_as_num != NULL) + { + number = class->resolve_as_num(cond); + result = (number > 0); + } + + else + result = false; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : cond = condition à consulter. * +* * +* Description : Indique le statut d'une condition de validation. * +* * +* Retour : Forme numérique de la condition considérée pour validation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +unsigned long long g_match_condition_resolve_as_number(const GMatchCondition *cond) +{ + unsigned long long result; /* Valeur à retourner */ + GMatchConditionClass *class; /* Classe à activer */ + + class = G_MATCH_CONDITION_GET_CLASS(cond); + + result = class->resolve_as_num(cond); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : cond = condition à considérer. * +* data = données binaires brutes à considérer. * +* size = quantité de ces données. * +* pos = position du point d'étude courant. * +* full = force une recherche pleine et entière. * +* * +* Description : Avance vers la validation d'une condition, si besoin est. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_match_condition_analyze(const GMatchCondition *cond, const bin_t *data, phys_t size, phys_t pos, bool full) +{ + GMatchConditionClass *class; /* Classe à activer */ + + class = G_MATCH_CONDITION_GET_CLASS(cond); + + class->analyze(cond, data, size, pos, full); + +} diff --git a/src/analysis/scan/cond.h b/src/analysis/scan/cond.h new file mode 100644 index 0000000..7a5d3c4 --- /dev/null +++ b/src/analysis/scan/cond.h @@ -0,0 +1,65 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * cond.h - prototypes pour l'expression conditionnelle validant la présence de motifs donnés + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_COND_H +#define _ANALYSIS_SCAN_COND_H + + +#include <glib-object.h> + + +#include "../../arch/archbase.h" +#include "../../arch/vmpa.h" + + + +#define G_TYPE_MATCH_CONDITION g_match_condition_get_type() +#define G_MATCH_CONDITION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_MATCH_CONDITION, GMatchCondition)) +#define G_IS_MATCH_CONDITION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_MATCH_CONDITION)) +#define G_MATCH_CONDITION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_MATCH_CONDITION, GMatchConditionClass)) +#define G_IS_MATCH_CONDITION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_MATCH_CONDITION)) +#define G_MATCH_CONDITION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_MATCH_CONDITION, GMatchConditionClass)) + + +/* Expression conditionnelle manipulant des motifs (instance) */ +typedef struct _GMatchCondition GMatchCondition; + +/* Expression conditionnelle manipulant des motifs (classe) */ +typedef struct _GMatchConditionClass GMatchConditionClass; + + +/* Indique le type défini pour une expression de validation. */ +GType g_match_condition_get_type(void); + +/* Indique le statut d'une condition de validation. */ +bool g_match_condition_resolve(const GMatchCondition *); + +/* Indique le statut d'une condition de validation. */ +unsigned long long g_match_condition_resolve_as_number(const GMatchCondition *); + +/* Avance vers la validation d'une condition, si besoin est. */ +void g_match_condition_analyze(const GMatchCondition *, const bin_t *, phys_t, phys_t, bool); + + + +#endif /* _ANALYSIS_SCAN_COND_H */ diff --git a/src/analysis/scan/conds/Makefile.am b/src/analysis/scan/conds/Makefile.am new file mode 100644 index 0000000..402deac --- /dev/null +++ b/src/analysis/scan/conds/Makefile.am @@ -0,0 +1,16 @@ + +noinst_LTLIBRARIES = libanalysisscanconds.la + + +libanalysisscanconds_la_SOURCES = \ + binop-int.h \ + binop.h binop.c \ + counter-int.h \ + counter.h counter.c + +libanalysisscanconds_la_CFLAGS = $(LIBGOBJ_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libanalysisscanconds_la_SOURCES:%c=) diff --git a/src/analysis/scan/conds/binop-int.h b/src/analysis/scan/conds/binop-int.h new file mode 100644 index 0000000..0fc5940 --- /dev/null +++ b/src/analysis/scan/conds/binop-int.h @@ -0,0 +1,54 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * binop-int.h - prototypes internes pour les opérations booléennes impliquant deux opérandes + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_CONDS_BINOP_INT_H +#define _ANALYSIS_SCAN_CONDS_BINOP_INT_H + + +#include "binop.h" + + +#include "../cond-int.h" + + + +/* Opération booléenne impliquant deux opérandes (instance) */ +struct _GBinaryOperation +{ + GMatchCondition parent; /* A laisser en premier */ + + GMatchCondition *conds[2]; /* Opérandes à manipuler */ + BinOpType type; /* Type de manipulation */ + +}; + +/* Opération booléenne impliquant deux opérandes (classe) */ +struct _GBinaryOperationClass +{ + GMatchConditionClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _ANALYSIS_SCAN_CONDS_BINOP_INT_H */ diff --git a/src/analysis/scan/conds/binop.c b/src/analysis/scan/conds/binop.c new file mode 100644 index 0000000..01e99d9 --- /dev/null +++ b/src/analysis/scan/conds/binop.c @@ -0,0 +1,265 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * binop.c - opérations booléennes impliquant deux opérandes + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "binop.h" + + +#include "binop-int.h" + + + +/* --------------------- INSTANCIATION D'UNE FORME DE CONDITION --------------------- */ + + +/* Initialise la classe des opérations booléennes. */ +static void g_binary_operation_class_init(GBinaryOperationClass *); + +/* Initialise une instance d'opération booléenne. */ +static void g_binary_operation_init(GBinaryOperation *); + +/* Supprime toutes les références externes. */ +static void g_binary_operation_dispose(GBinaryOperation *); + +/* Procède à la libération totale de la mémoire. */ +static void g_binary_operation_finalize(GBinaryOperation *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Indique le statut d'une condition de validation. */ +static bool g_binary_operation_resolve(const GBinaryOperation *); + +/* Lance l'analyse de contenu binaire selon un motif donné. */ +static void g_binary_operation_analyze(const GBinaryOperation *, const bin_t *, phys_t, phys_t, bool); + + + +/* ---------------------------------------------------------------------------------- */ +/* INSTANCIATION D'UNE FORME DE CONDITION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une opération booléenne de validation. */ +G_DEFINE_TYPE(GBinaryOperation, g_binary_operation, G_TYPE_MATCH_CONDITION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des opérations booléennes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_binary_operation_class_init(GBinaryOperationClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GMatchConditionClass *cond; /* Classe parente directe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_binary_operation_dispose; + object->finalize = (GObjectFinalizeFunc)g_binary_operation_finalize; + + cond = G_MATCH_CONDITION_CLASS(klass); + + cond->resolve = (resolve_cond_fc)g_binary_operation_resolve; + cond->analyze = (analyze_cond_fc)g_binary_operation_analyze; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser. * +* * +* Description : Initialise une instance d'opération booléenne. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_binary_operation_init(GBinaryOperation *op) +{ + op->conds[0] = NULL; + op->conds[1] = NULL; + + op->type = BOT_AND; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_binary_operation_dispose(GBinaryOperation *op) +{ + g_clear_object(&op->conds[0]); + g_clear_object(&op->conds[1]); + + G_OBJECT_CLASS(g_binary_operation_parent_class)->dispose(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_binary_operation_finalize(GBinaryOperation *op) +{ + G_OBJECT_CLASS(g_binary_operation_parent_class)->finalize(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : op1 = premier opérande à intégrer. * +* op2 = second opérande à intégrer. * +* type = type d'opération à prendre en compte. * +* * +* Description : Met en place une représentation d'opération booléenne. * +* * +* Retour : Condition mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBinaryOperation *g_binary_operation_new(GMatchCondition *op1, GMatchCondition *op2, BinOpType type) +{ + GBinaryOperation *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_BINARY_OPERATION, NULL); + + result->conds[0] = op1; + g_object_ref(G_OBJECT(op1)); + + result->conds[1] = op2; + g_object_ref(G_OBJECT(op2)); + + result->type = type; + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : op = condition à consulter. * +* * +* Description : Indique le statut d'une condition de validation. * +* * +* Retour : Validation de la condition considérée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_binary_operation_resolve(const GBinaryOperation *op) +{ + bool result; /* Bilan à retourner */ + + result = g_match_condition_resolve(op->conds[0]); + + switch (op->type) + { + case BOT_AND: + default: + if (result) + result = g_match_condition_resolve(op->conds[1]); + break; + + case BOT_OR: + if (!result) + result = g_match_condition_resolve(op->conds[1]); + break; + + case BOT_XOR: + result ^= g_match_condition_resolve(op->conds[1]); + break; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : op = condition à considérer. * +* data = données binaires brutes à considérer. * +* size = quantité de ces données. * +* pos = position du point d'étude courant. * +* full = force une recherche pleine et entière. * +* * +* Description : Lance l'analyse de contenu binaire selon un motif donné. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_binary_operation_analyze(const GBinaryOperation *op, const bin_t *data, phys_t size, phys_t pos, bool full) +{ + g_match_condition_analyze(op->conds[0], data, size, pos, full); + + if (full || !g_binary_operation_resolve(op)) + g_match_condition_analyze(op->conds[1], data, size, pos, full); + +} diff --git a/src/analysis/scan/conds/binop.h b/src/analysis/scan/conds/binop.h new file mode 100644 index 0000000..55cb515 --- /dev/null +++ b/src/analysis/scan/conds/binop.h @@ -0,0 +1,68 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * binop.h - prototypes pour les opérations booléennes impliquant deux opérandes + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_CONDS_BINOP_H +#define _ANALYSIS_SCAN_CONDS_BINOP_H + + +#include <glib-object.h> + + +#include "../cond.h" + + + +#define G_TYPE_BINARY_OPERATION g_binary_operation_get_type() +#define G_BINARY_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BINARY_OPERATION, GBinaryOperation)) +#define G_IS_BINARY_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BINARY_OPERATION)) +#define G_BINARY_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BINARY_OPERATION, GBinaryOperationClass)) +#define G_IS_BINARY_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BINARY_OPERATION)) +#define G_BINARY_OPERATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BINARY_OPERATION, GBinaryOperationClass)) + + +/* Opération booléenne impliquant deux opérandes (instance) */ +typedef struct _GBinaryOperation GBinaryOperation; + +/* Opération booléenne impliquant deux opérandes (classe) */ +typedef struct _GBinaryOperationClass GBinaryOperationClass; + + +/* Types d'opérations booléennes disponibles */ +typedef enum _BinOpType +{ + BOT_AND, + BOT_OR, + BOT_XOR, + +} BinOpType; + + +/* Indique le type défini pour une opération booléenne de validation. */ +GType g_binary_operation_get_type(void); + +/* Met en place une représentation d'opération booléenne. */ +GBinaryOperation *g_binary_operation_new(GMatchCondition *, GMatchCondition *, BinOpType); + + + +#endif /* _ANALYSIS_SCAN_CONDS_BINOP_H */ diff --git a/src/analysis/scan/conds/counter-int.h b/src/analysis/scan/conds/counter-int.h new file mode 100644 index 0000000..a706fca --- /dev/null +++ b/src/analysis/scan/conds/counter-int.h @@ -0,0 +1,53 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * counter-int.h - prototypes internes pour le décompte de correspondances identifiées dans du contenu binaire + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_CONDS_COUNTER_INT_H +#define _ANALYSIS_SCAN_CONDS_COUNTER_INT_H + + +#include "counter.h" + + +#include "../cond-int.h" + + + +/* Décompte des identifications de motifs (instance) */ +struct _GMatchCounter +{ + GMatchCondition parent; /* A laisser en premier */ + + GSearchPattern *pattern; /* Motif associé */ + +}; + +/* Décompte des identifications de motifs (classe) */ +struct _GMatchCounterClass +{ + GMatchConditionClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _ANALYSIS_SCAN_CONDS_COUNTER_INT_H */ diff --git a/src/analysis/scan/conds/counter.c b/src/analysis/scan/conds/counter.c new file mode 100644 index 0000000..7cf36b8 --- /dev/null +++ b/src/analysis/scan/conds/counter.c @@ -0,0 +1,232 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * counter.c - décompte de correspondances identifiées dans du contenu binaire + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "counter.h" + + +#include "counter-int.h" + + + +/* --------------------- INSTANCIATION D'UNE FORME DE CONDITION --------------------- */ + + +/* Initialise la classe des opérations booléennes. */ +static void g_match_counter_class_init(GMatchCounterClass *); + +/* Initialise une instance d'opération booléenne. */ +static void g_match_counter_init(GMatchCounter *); + +/* Supprime toutes les références externes. */ +static void g_match_counter_dispose(GMatchCounter *); + +/* Procède à la libération totale de la mémoire. */ +static void g_match_counter_finalize(GMatchCounter *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Indique le statut d'une condition de validation. */ +static unsigned long long g_match_counter_resolve_as_number(const GMatchCounter *); + +/* Lance l'analyse de contenu binaire selon un motif donné. */ +static void g_match_counter_analyze(const GMatchCounter *, const bin_t *, phys_t, phys_t, bool); + + + +/* ---------------------------------------------------------------------------------- */ +/* INSTANCIATION D'UNE FORME DE CONDITION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un décompte de résultats lors d'une recherche de motifs. */ +G_DEFINE_TYPE(GMatchCounter, g_match_counter, G_TYPE_MATCH_CONDITION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des opérations booléennes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_match_counter_class_init(GMatchCounterClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GMatchConditionClass *cond; /* Classe parente directe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_match_counter_dispose; + object->finalize = (GObjectFinalizeFunc)g_match_counter_finalize; + + cond = G_MATCH_CONDITION_CLASS(klass); + + cond->resolve_as_num = (resolve_cond_as_number_fc)g_match_counter_resolve_as_number; + cond->analyze = (analyze_cond_fc)g_match_counter_analyze; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser. * +* * +* Description : Initialise une instance d'opération booléenne. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_match_counter_init(GMatchCounter *counter) +{ + counter->pattern = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_match_counter_dispose(GMatchCounter *counter) +{ + g_clear_object(&counter->pattern); + + G_OBJECT_CLASS(g_match_counter_parent_class)->dispose(G_OBJECT(counter)); + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_match_counter_finalize(GMatchCounter *counter) +{ + G_OBJECT_CLASS(g_match_counter_parent_class)->finalize(G_OBJECT(counter)); + +} + + +/****************************************************************************** +* * +* Paramètres : pattern = motif à impliquer. * +* * +* Description : Met en place un décompte de correspondances obtenues. * +* * +* Retour : Condition mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GMatchCounter *g_match_counter_new(GSearchPattern *pattern) +{ + GMatchCounter *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_MATCH_COUNTER, NULL); + + result->pattern = pattern; + g_object_ref(G_OBJECT(pattern)); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : op = condition à consulter. * +* * +* Description : Indique le statut d'une condition de validation. * +* * +* Retour : Forme numérique de la condition considérée pour validation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static unsigned long long g_match_counter_resolve_as_number(const GMatchCounter *counter) +{ + unsigned long long result; /* Valeur à retourner */ + + result = g_search_pattern_count_matchs(counter->pattern); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : counter = condition à considérer. * +* data = données binaires brutes à considérer. * +* size = quantité de ces données. * +* pos = position du point d'étude courant. * +* full = force une recherche pleine et entière. * +* * +* Description : Lance l'analyse de contenu binaire selon un motif donné. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_match_counter_analyze(const GMatchCounter *counter, const bin_t *data, phys_t size, phys_t pos, bool full) +{ + //g_search_pattern_analyze(counter->pattern, data, size, pos); + +} diff --git a/src/analysis/scan/conds/counter.h b/src/analysis/scan/conds/counter.h new file mode 100644 index 0000000..033ac99 --- /dev/null +++ b/src/analysis/scan/conds/counter.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * counter.h - prototypes pour le décompte de correspondances identifiées dans du contenu binaire + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_CONDS_COUNTER_H +#define _ANALYSIS_SCAN_CONDS_COUNTER_H + + +#include <glib-object.h> + + +#include "../pattern.h" + + + +#define G_TYPE_MATCH_COUNTER g_match_counter_get_type() +#define G_MATCH_COUNTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_MATCH_COUNTER, GMatchCounter)) +#define G_IS_MATCH_COUNTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_MATCH_COUNTER)) +#define G_MATCH_COUNTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_MATCH_COUNTER, GMatchCounterClass)) +#define G_IS_MATCH_COUNTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_MATCH_COUNTER)) +#define G_MATCH_COUNTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_MATCH_COUNTER, GMatchCounterClass)) + + +/* Décompte des identifications de motifs (instance) */ +typedef struct _GMatchCounter GMatchCounter; + +/* Décompte des identifications de motifs (classe) */ +typedef struct _GMatchCounterClass GMatchCounterClass; + + +/* Indique le type défini pour un décompte de résultats lors d'une recherche de motifs. */ +GType g_match_counter_get_type(void); + +/* Met en place une représentation d'opération booléenne. */ +GMatchCounter *g_match_counter_new(GSearchPattern *); + + + +#endif /* _ANALYSIS_SCAN_CONDS_COUNTER_H */ diff --git a/src/analysis/scan/context-int.h b/src/analysis/scan/context-int.h new file mode 100644 index 0000000..94302bf --- /dev/null +++ b/src/analysis/scan/context-int.h @@ -0,0 +1,87 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * context-int.h - prototypes internes pour un suivi d'analyses via contextes + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_CONTEXT_INT_H +#define _ANALYSIS_SCAN_CONTEXT_INT_H + + +#include "context.h" + + +#include "expr.h" + + + +/* Mémorisation des correspondances partielles */ +typedef struct _atom_match_tracker_t +{ + phys_t *matches; /* Correspondances à confirmer */ + size_t allocated; /* Taille du talbeau préparé */ + size_t used; /* Nombre d'éléments présents */ + +} atom_match_tracker_t; + +#define ALLOCATION_STEP 10 + +/* Condition définissant une règle de correspondance */ +typedef struct _rule_condition_t +{ + char *name; /* Désignation de la règle */ + + GScanExpression *expr; /* Condition de correspondance */ + bool final_reduced; /* Réduction finale tentée ? */ + +} rule_condition_t; + +/* Contexte de suivi d'une analyse en cours (instance) */ +struct _GScanContext +{ + GObject parent; /* A laisser en premier */ + + GScanOptions *options; /* Options d'analyses */ + + GBinContent *content; /* Contenu binaire traité */ + + patid_t next_patid; /* Prochain indice utilisable */ + + atom_match_tracker_t *atom_trackers; /* Correspondances partielles */ + + GScanMatch **full_matches; /* Correspondances confirmées */ + size_t full_allocated; /* Taille du talbeau préparé */ + size_t full_used; /* Nombre d'éléments présents */ + + rule_condition_t *conditions; /* Ensemble de règles suivies */ + size_t cond_count; /* Quantité de ces conditions */ + +}; + +/* Contexte de suivi d'une analyse en cours (classe) */ +struct _GScanContextClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _ANALYSIS_SCAN_CONTEXT_INT_H */ diff --git a/src/analysis/scan/context.c b/src/analysis/scan/context.c new file mode 100644 index 0000000..aec654a --- /dev/null +++ b/src/analysis/scan/context.c @@ -0,0 +1,546 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * context.c - suivi d'analyses via contextes + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "context.h" + + +#include <assert.h> +#include <string.h> + + +#include "context-int.h" +#include "exprs/literal.h" + + + +/* Initialise la classe des contextes de suivi d'analyses. */ +static void g_scan_context_class_init(GScanContextClass *); + +/* Initialise une instance de contexte de suivi d'analyse. */ +static void g_scan_context_init(GScanContext *); + +/* Supprime toutes les références externes. */ +static void g_scan_context_dispose(GScanContext *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_context_finalize(GScanContext *); + + + +/* Indique le type défini pour un contexte de suivi d'analyse. */ +G_DEFINE_TYPE(GScanContext, g_scan_context, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des contextes de suivi d'analyses. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_context_class_init(GScanContextClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_context_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_context_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : context = instance à initialiser. * +* * +* Description : Initialise une instance de contexte de suivi d'analyse. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_context_init(GScanContext *context) +{ + context->options = NULL; + + context->content = NULL; + + context->next_patid = 0; + + context->atom_trackers = NULL; + + context->full_matches = NULL; + context->full_allocated = 0; + context->full_used = 0; + + context->conditions = NULL; + context->cond_count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : context = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_context_dispose(GScanContext *context) +{ + size_t i; /* Boucle de parcours */ + + g_clear_object(&context->options); + + g_clear_object(&context->content); + + for (i = 0; i < context->full_used; i++) + g_clear_object(&context->full_matches[i]); + + for (i = 0; i < context->cond_count; i++) + g_clear_object(&context->conditions[i].expr); + + G_OBJECT_CLASS(g_scan_context_parent_class)->dispose(G_OBJECT(context)); + +} + + +/****************************************************************************** +* * +* Paramètres : context = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_context_finalize(GScanContext *context) +{ + size_t i; /* Boucle de parcours */ + atom_match_tracker_t *atracker; /* Conservateur à manipuler #1 */ + + if (context->atom_trackers != NULL) + { + for (i = 0; i < context->next_patid; i++) + { + atracker = context->atom_trackers + i; + + if (atracker->matches != NULL) + free(atracker->matches); + + } + + free(context->atom_trackers); + + } + + if (context->full_matches != NULL) + free(context->full_matches); + + if (context->conditions != NULL) + { + for (i = 0; i < context->cond_count; i++) + free(context->conditions[i].name); + + free(context->conditions); + + } + + G_OBJECT_CLASS(g_scan_context_parent_class)->finalize(G_OBJECT(context)); + +} + + +/****************************************************************************** +* * +* Paramètres : options = ensemble d'options d'analyses à respecter. * +* * +* Description : Définit un contexte pour suivi d'analyse. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanContext *g_scan_context_new(GScanOptions *options) +{ + GScanContext *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_CONTEXT, NULL); + + result->options = options; + g_object_ref(G_OBJECT(options)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : context = instance à consulter. * +* * +* Description : Fournit l'ensemble des options à respecter pour les analyses.* +* * +* Retour : Ensemble d'options en vigueur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanOptions *g_scan_context_get_options(GScanContext *context) +{ + GScanOptions *result; /* Ensemble à retourner */ + + result = context->options; + + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : context = instance à consulter. * +* * +* Description : Fournit un identifiant unique pour un motif recherché. * +* * +* Retour : Identifiant nouveau à utiliser. * +* * +* Remarques : - * +* * +******************************************************************************/ + +patid_t g_scan_context_get_new_pattern_id(GScanContext *context) +{ + patid_t result; /* Identifiant à retourner */ + + result = context->next_patid++; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : context = instance à consulter. * +* content = contenu binaire en cours d'analyse. * +* * +* Description : Définit le contenu principal à analyser. * +* * +* Retour : Content binaire associé au context. * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_context_set_content(GScanContext *context, GBinContent *content) +{ + g_clear_object(&context->content); + + context->content = content; + + g_object_ref(G_OBJECT(content)); + + context->atom_trackers = calloc(context->next_patid, sizeof(atom_match_tracker_t)); + +} + + +/****************************************************************************** +* * +* Paramètres : context = instance à consulter. * +* * +* Description : Fournit une référence au contenu principal analysé. * +* * +* Retour : Content binaire associé au context. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBinContent *g_scan_context_get_content(const GScanContext *context) +{ + GBinContent *result; /* Instance à retourner */ + + result = context->content; + + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : context = instance à mettre à jour. * +* id = identifiant du motif trouvé. * +* offset = localisation du motif au sein d'un contenu. * +* * +* Description : Enregistre une correspondance partielle dans un contenu. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_context_register_atom_match(GScanContext *context, patid_t id, phys_t offset) +{ + atom_match_tracker_t *tracker; /* Gestionnaire concerné */ + + tracker = &context->atom_trackers[id]; + + if (tracker->used == tracker->allocated) + { + tracker->allocated += ALLOCATION_STEP; + tracker->matches = realloc(tracker->matches, tracker->allocated * sizeof(phys_t)); + } + + tracker->matches[tracker->used++] = offset; + +} + + +/****************************************************************************** +* * +* Paramètres : context = instance à mettre à jour. * +* id = identifiant du motif trouvé. * +* count = nombre de localisations renvoyées. [OUT] * +* * +* Description : Retourne tous les correspondances partielles notées. * +* * +* Retour : Liste interne des localisations conservées. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const phys_t *g_scan_context_get_atom_matches(const GScanContext *context, patid_t id, size_t *count) +{ + const phys_t *result; /* Liste constituée à renvoyer */ + atom_match_tracker_t *tracker; /* Gestionnaire concerné */ + + tracker = &context->atom_trackers[id]; + + result = tracker->matches; + *count = tracker->used; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : context = instance à mettre à jour. * +* match = représentation d'une plein ecorrespondance. * +* * +* Description : Enregistre une correspondance complète avec un contenu. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_context_register_full_match(GScanContext *context, GScanMatch *match) +{ + if (context->full_used == context->full_allocated) + { + context->full_allocated += ALLOCATION_STEP; + context->full_matches = realloc(context->full_matches, context->full_allocated * sizeof(GScanMatch *)); + } + + context->full_matches[context->full_used++] = match; + g_object_ref(G_OBJECT(match)); + +} + + +/****************************************************************************** +* * +* Paramètres : context = mémoire de résultats d'analyse à consulter. * +* * +* Description : Affiche les correspondances identifiées. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_context_display(const GScanContext *context) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < context->full_used; i++) + g_scan_match_display(context->full_matches[i]); + +} + + +/****************************************************************************** +* * +* 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. * +* * +* Description : Intègre une condition de correspondance pour règle. * +* * +* Retour : Bilan final d'une intégration (false si nom déjà présent). * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_context_set_rule_condition(GScanContext *context, const char *name, const GScanExpression *expr) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + rule_condition_t *new; /* Nouvel élément à intégrer */ + + result = true; + + /* Recherche d'antécédent */ + + for (i = 0; context->cond_count; i++) + if (strcmp(name, context->conditions[i].name) == 0) + { + result = false; + break; + } + + /* Ajout d'un nouvel élément ? */ + + if (result) + { + context->conditions = realloc(context->conditions, ++context->cond_count * sizeof(rule_condition_t)); + + new = &context->conditions[context->cond_count - 1]; + + new->name = strdup(name); + + new->expr = g_scan_expression_duplicate(expr); + new->final_reduced = false; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : context = mémoire de résultats d'analyse à consulter. * +* name = désignation de la règle ciblée. * +* * +* Description : Indique si une correspondance globale a pu être établie. * +* * +* Retour : Bilan final d'une analyse (false par défaut). * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_context_has_match_for_rule(GScanContext *context, const char *name) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + rule_condition_t *cond; /* Condition à considérer */ + GScanExpression *new; /* Nouvelle expression réduite */ + bool valid; /* Validité d'une récupération */ + + result = false; + + /* Recherche de la règle visée */ + + cond = NULL; + + for (i = 0; context->cond_count; i++) + if (strcmp(name, context->conditions[i].name) == 0) + { + cond = &context->conditions[i]; + break; + } + + if (cond == NULL) + goto exit; + + /* Tentative de réduction finale */ + + if (!cond->final_reduced) + { + new = g_scan_expression_reduce(cond->expr, context, false); + + if (new != NULL) + { + g_object_unref(G_OBJECT(cond->expr)); + cond->expr = new; + } + + cond->final_reduced = true; + + } + + /* Tentative de récupération d'un bilan final */ + + if (G_IS_LITERAL_EXPRESSION(cond->expr)) + { + valid = g_literal_expression_get_boolean_value(G_LITERAL_EXPRESSION(cond->expr), &result); + + if (!valid) + { + assert(!result); + result = false; + } + + } + + exit: + + return result; + +} diff --git a/src/analysis/scan/context.h b/src/analysis/scan/context.h new file mode 100644 index 0000000..92522f8 --- /dev/null +++ b/src/analysis/scan/context.h @@ -0,0 +1,100 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * context.h - prototypes pour le suivi d'analyses via contextes + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_CONTEXT_H +#define _ANALYSIS_SCAN_CONTEXT_H + + +#include <glib-object.h> + + +#include "match.h" +#include "options.h" +#include "../content.h" + + + +/* Depuis expr.h : expression d'évaluation généraliste (instance) */ +typedef struct _GScanExpression GScanExpression; + + +#define G_TYPE_SCAN_CONTEXT g_scan_context_get_type() +#define G_SCAN_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_CONTEXT, GScanContext)) +#define G_IS_SCAN_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_CONTEXT)) +#define G_SCAN_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_CONTEXT, GScanContextClass)) +#define G_IS_SCAN_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_CONTEXT)) +#define G_SCAN_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_CONTEXT, GScanContextClass)) + + +/* Contexte de suivi d'une analyse en cours (instance) */ +typedef struct _GScanContext GScanContext; + +/* Contexte de suivi d'une analyse en cours (classe) */ +typedef struct _GScanContextClass GScanContextClass; + + +/* Identifiant de motif intégré */ +typedef uint64_t patid_t; + +#define INVALID_PATTERN_ID 0xffffffffffffffff + + +/* Indique le type défini pour un contexte de suivi d'analyse. */ +GType g_scan_context_get_type(void); + +/* Définit un contexte pour suivi d'analyse. */ +GScanContext *g_scan_context_new(GScanOptions *); + +/* Fournit l'ensemble des options à respecter pour les analyses. */ +GScanOptions *g_scan_context_get_options(GScanContext *); + +/* Fournit un identifiant unique pour un motif recherché. */ +patid_t g_scan_context_get_new_pattern_id(GScanContext *); + +/* Définit le contenu principal à analyser. */ +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 *); + +/* Enregistre une correspondance partielle dans un contenu. */ +void g_scan_context_register_atom_match(GScanContext *, patid_t, phys_t); + +/* Retourne tous les correspondances partielles notées. */ +const phys_t *g_scan_context_get_atom_matches(const GScanContext *, patid_t, size_t *); + +/* Enregistre une correspondance complète avec un contenu. */ +void g_scan_context_register_full_match(GScanContext *, GScanMatch *); + +/* Affiche les correspondances identifiées. */ +void g_scan_context_display(const GScanContext *); + +/* Intègre une condition de correspondance pour règle. */ +bool g_scan_context_set_rule_condition(GScanContext *, const char *, const GScanExpression *); + +/* Indique si une correspondance globale a pu être établie. */ +bool g_scan_context_has_match_for_rule(GScanContext *, const char *); + + + +#endif /* _ANALYSIS_SCAN_CONTEXT_H */ diff --git a/src/analysis/scan/core.c b/src/analysis/scan/core.c new file mode 100644 index 0000000..3b6c2c9 --- /dev/null +++ b/src/analysis/scan/core.c @@ -0,0 +1,67 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.c - enregistrement des fonctions principales + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "core.h" + + +#include "funcs/datasize.h" +#include "funcs/uint.h" + + + +/****************************************************************************** +* * +* Paramètres : space = espace de noms à composer. * +* * +* Description : Inscrit les principales fonctions dans l'espace racine. * +* * +* Retour : Bilan des enregistrements effectués. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_main_scan_namespace(GScanNamespace *space) +{ + bool result; + + result = true; + +#define REGISTER_FUNC(s, f, n) \ + ({ \ + bool __result; \ + __result = g_scan_namespace_register(s, G_REGISTERED_ITEM(f), n); \ + __result; \ + }) + + if (result) result = REGISTER_FUNC(space, g_datasize_function_new(), "datasize"); + if (result) result = REGISTER_FUNC(space, g_datasize_function_new(), "filesize"); /* Alias */ + + if (result) result = REGISTER_FUNC(space, g_uint_function_new(MDS_8_BITS_UNSIGNED), "uint8"); + if (result) result = REGISTER_FUNC(space, g_uint_function_new(MDS_16_BITS_UNSIGNED), "uint16"); + if (result) result = REGISTER_FUNC(space, g_uint_function_new(MDS_32_BITS_UNSIGNED), "uint32"); + if (result) result = REGISTER_FUNC(space, g_uint_function_new(MDS_64_BITS_UNSIGNED), "uint64"); + + return result; + +} diff --git a/src/analysis/scan/core.h b/src/analysis/scan/core.h new file mode 100644 index 0000000..21d6e7c --- /dev/null +++ b/src/analysis/scan/core.h @@ -0,0 +1,37 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.h - prototypes pour l'enregistrement des fonctions principales + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_CORE_H +#define _ANALYSIS_SCAN_CORE_H + + +#include "space.h" + + + +/* Inscrit les principales fonctions dans l'espace racine. */ +bool populate_main_scan_namespace(GScanNamespace *); + + + +#endif /* _ANALYSIS_SCAN_CORE_H */ diff --git a/src/analysis/scan/decl.h b/src/analysis/scan/decl.h new file mode 100644 index 0000000..ab70368 --- /dev/null +++ b/src/analysis/scan/decl.h @@ -0,0 +1,40 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * decl.h - déclarations de prototypes utiles + * + * 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_DECL_H +#define _ANALYSIS_SCAN_DECL_H + + +#include <stdbool.h> + + +#include "scanner.h" + + + +/* Complète une recherche de motifs avec des règles. */ +bool process_rules_definitions(GContentScanner *, const char *, size_t); + + + +#endif /* _ANALYSIS_SCAN_DECL_H */ diff --git a/src/analysis/scan/expr-int.h b/src/analysis/scan/expr-int.h new file mode 100644 index 0000000..4323693 --- /dev/null +++ b/src/analysis/scan/expr-int.h @@ -0,0 +1,78 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * expr-int.h - prototypes internes pour la définition d'une expression servant aux conditions de correspondance + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPR_INT_H +#define _ANALYSIS_SCAN_EXPR_INT_H + + +#include "expr.h" + + +#include <stdbool.h> + + +#include "../../glibext/comparison-int.h" + + + +/* Réalise une comparaison entre objets selon un critère précis. */ +typedef bool (* compare_expr_rich_fc) (const GScanExpression *, const GScanExpression *, RichCmpOperation, bool *); + +/* Vérifie la validité d'une expression. */ +typedef bool (* check_expr_validity_fc) (const GScanExpression *); + +/* Reproduit une expression en place dans une nouvelle instance. */ +typedef GScanExpression * (* dup_expr_fc) (const GScanExpression *); + +/* Réduit une expression à une forme plus simple. */ +typedef GScanExpression * (* reduce_expr_fc) (GScanExpression *, GScanContext *, bool); + + +/* Expression d'évaluation généraliste (instance) */ +struct _GScanExpression +{ + GObject parent; /* A laisser en premier */ + + ExprValueType value_type; /* Type de valeur portée */ + +}; + +/* Expression d'évaluation généraliste (classe) */ +struct _GScanExpressionClass +{ + GObjectClass parent; /* A laisser en premier */ + + compare_expr_rich_fc cmp_rich; /* Comparaison de façon précise*/ + check_expr_validity_fc check; /* Validation de la cohérence */ + dup_expr_fc dup; /* Reproduction d'expression */ + reduce_expr_fc reduce; /* Simplification d'expression */ + +}; + + +/* Met en place une expression d'évaluation pour analyse. */ +bool g_scan_expression_create(GScanExpression *, ExprValueType); + + + +#endif /* _ANALYSIS_SCAN_EXPR_INT_H */ diff --git a/src/analysis/scan/expr.c b/src/analysis/scan/expr.c new file mode 100644 index 0000000..0b81e01 --- /dev/null +++ b/src/analysis/scan/expr.c @@ -0,0 +1,331 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * expr.c - définition d'une expression servant aux conditions de correspondance + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "expr.h" + + +#include "expr-int.h" + + + +/* ----------------------- BASES D'OBJET POUR LE SYSTEME GLIB ----------------------- */ + + +/* Initialise la classe des expressions de validation. */ +static void g_scan_expression_class_init(GScanExpressionClass *); + +/* Initialise une instance d'expression de validation. */ +static void g_scan_expression_init(GScanExpression *); + +/* Procède à l'initialisation de l'interface de comparaison. */ +static void g_scan_expression_cmp_interface_init(GComparableItemInterface *); + +/* Supprime toutes les références externes. */ +static void g_scan_expression_dispose(GScanExpression *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_expression_finalize(GScanExpression *); + + +/* ----------------------- INTERFACE OFFRANT DES COMPARAISONS ----------------------- */ + + +/* Réalise une comparaison entre objets selon un critère précis. */ +static bool g_scan_expression_compare_rich(const GScanExpression *, const GScanExpression *, RichCmpOperation, bool *); + + + +/* ---------------------------------------------------------------------------------- */ +/* BASES D'OBJET POUR LE SYSTEME GLIB */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une expression de validation. */ +G_DEFINE_TYPE_WITH_CODE(GScanExpression, g_scan_expression, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(G_TYPE_COMPARABLE_ITEM, g_scan_expression_cmp_interface_init)); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des expressions de validation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_expression_class_init(GScanExpressionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_expression_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_expression_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = instance à initialiser. * +* * +* Description : Initialise une instance d'expression de validation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_expression_init(GScanExpression *expr) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : iface = interface GLib à initialiser. * +* * +* Description : Procède à l'initialisation de l'interface de comparaison. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_expression_cmp_interface_init(GComparableItemInterface *iface) +{ + iface->cmp_rich = (compare_rich_fc)g_scan_expression_compare_rich; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_expression_dispose(GScanExpression *expr) +{ + G_OBJECT_CLASS(g_scan_expression_parent_class)->dispose(G_OBJECT(expr)); + +} + + +/****************************************************************************** +* * +* Paramètres : expr = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_expression_finalize(GScanExpression *expr) +{ + G_OBJECT_CLASS(g_scan_expression_parent_class)->finalize(G_OBJECT(expr)); + +} + + +/****************************************************************************** +* * +* Paramètres : expr = instance à initialiser pleinement. * +* vtype = type de valeur associée par l'expression. * +* * +* Description : Met en place une expression d'évaluation pour analyse. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_expression_create(GScanExpression *expr, ExprValueType vtype) +{ + bool result; /* Bilan à retourner */ + + result = true; + + expr->value_type = vtype; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* * +* Description : Indique le type de valeur portée par une expression. * +* * +* Retour : Type de valeur associée à l'expression. * +* * +* Remarques : - * +* * +******************************************************************************/ + +ExprValueType g_scan_expression_get_value_type(const GScanExpression *expr) +{ + ExprValueType result; /* Type à retourner */ + + result = expr->value_type; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* * +* Description : Vérifie la validité d'une expression. * +* * +* Retour : Validation de l'usage de l'expression. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_expression_check_validity(const GScanExpression *expr) +{ + bool result; /* Bilan à retourner */ + GScanExpressionClass *class; /* Classe à activer */ + + class = G_SCAN_EXPRESSION_GET_CLASS(expr); + + result = class->check(expr); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à copier. * +* * +* Description : Reproduit une expression en place dans une nouvelle instance.* +* * +* Retour : Nouvelle instance d'expression. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_expression_duplicate(const GScanExpression *expr) +{ + GScanExpression *result; /* Instance copiée à retourner */ + GScanExpressionClass *class; /* Classe à activer */ + + class = G_SCAN_EXPRESSION_GET_CLASS(expr); + + result = class->dup(expr); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* final = indique une ultime conversion dans le cycle en cours.* +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_expression_reduce(GScanExpression *expr, GScanContext *ctx, bool final) +{ + GScanExpression *result; /* Instance à renvoyer */ + GScanExpressionClass *class; /* Classe à activer */ + + class = G_SCAN_EXPRESSION_GET_CLASS(expr); + + result = class->reduce(expr, ctx, final); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* INTERFACE OFFRANT DES COMPARAISONS */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = premier objet à cnsulter pour une comparaison. * +* other = second objet à cnsulter pour une comparaison. * +* op = opération de comparaison à réaliser. * +* status = bilan des opérations de comparaison. [OUT] * +* * +* Description : Réalise une comparaison entre objets selon un critère précis.* +* * +* Retour : true si la comparaison a pu être effectuée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_expression_compare_rich(const GScanExpression *item, const GScanExpression *other, RichCmpOperation op, bool *status) +{ + bool result; /* Etat à retourner */ + GScanExpressionClass *class; /* Classe à activer */ + + class = G_SCAN_EXPRESSION_GET_CLASS(item); + + if (class->cmp_rich != NULL) + result = class->cmp_rich(item, other, op, status); + else + result = false; + + return result; + +} diff --git a/src/analysis/scan/expr.h b/src/analysis/scan/expr.h new file mode 100644 index 0000000..98e7f7d --- /dev/null +++ b/src/analysis/scan/expr.h @@ -0,0 +1,84 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * expr.h - prototypes pour la définition d'une expression servant aux conditions de correspondance + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPR_H +#define _ANALYSIS_SCAN_EXPR_H + + +#include <glib-object.h> +#include <stdbool.h> + + +#include "context.h" + + + +#define G_TYPE_SCAN_EXPRESSION g_scan_expression_get_type() +#define G_SCAN_EXPRESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_EXPRESSION, GScanExpression)) +#define G_IS_SCAN_EXPRESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_EXPRESSION)) +#define G_SCAN_EXPRESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_EXPRESSION, GScanExpressionClass)) +#define G_IS_SCAN_EXPRESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_EXPRESSION)) +#define G_SCAN_EXPRESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_EXPRESSION, GScanExpressionClass)) + + +/* Expression d'évaluation généraliste (instance) */ +typedef struct _GScanExpression GScanExpression; + +/* Expression d'évaluation généraliste (classe) */ +typedef struct _GScanExpressionClass GScanExpressionClass; + + +/* Types naturel équivalant à l'expression */ +typedef enum _ExprValueType +{ + EVT_BOOLEAN, /* Valeur booléenne */ + EVT_INTEGER, /* Nombre entier 64 bits */ + EVT_STRING, /* Chaîne de caractères */ + EVT_REG_EXPR, /* Expression rationnelle */ + + EVT_COUNT, + + EVT_PENDING, /* Nature à déterminer */ + EVT_UNRESOLVABLE, /* Nature indéterminable */ + +} ExprValueType; + + +/* Indique le type défini pour une expression de validation. */ +GType g_scan_expression_get_type(void); + +/* Indique le type de valeur portée par une expression. */ +ExprValueType g_scan_expression_get_value_type(const GScanExpression *); + +/* Vérifie la validité d'une expression. */ +bool g_scan_expression_check_validity(const GScanExpression *); + +/* Reproduit une expression en place dans une nouvelle instance. */ +GScanExpression *g_scan_expression_duplicate(const GScanExpression *); + +/* Réduit une expression à une forme plus simple. */ +GScanExpression *g_scan_expression_reduce(GScanExpression *, GScanContext *, bool); + + + +#endif /* _ANALYSIS_SCAN_EXPR_H */ diff --git a/src/analysis/scan/exprs/Makefile.am b/src/analysis/scan/exprs/Makefile.am new file mode 100644 index 0000000..f164864 --- /dev/null +++ b/src/analysis/scan/exprs/Makefile.am @@ -0,0 +1,24 @@ + +noinst_LTLIBRARIES = libanalysisscanexprs.la + + +libanalysisscanexprs_la_SOURCES = \ + arithmop-int.h \ + arithmop.h arithmop.c \ + boolop-int.h \ + boolop.h boolop.c \ + call-int.h \ + call.h call.c \ + literal-int.h \ + literal.h literal.c \ + relop-int.h \ + relop.h relop.c \ + str-int.h \ + str.h str.c + +libanalysisscanexprs_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libanalysisscanexprs_la_SOURCES:%c=) diff --git a/src/analysis/scan/exprs/arithmop-int.h b/src/analysis/scan/exprs/arithmop-int.h new file mode 100644 index 0000000..75f1dbb --- /dev/null +++ b/src/analysis/scan/exprs/arithmop-int.h @@ -0,0 +1,60 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * arithmop-int.h - prototypes internes pour la gestion des opérations arithmétiques + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_ARITHMOP_INT_H +#define _ANALYSIS_SCAN_EXPRS_ARITHMOP_INT_H + + +#include "arithmop.h" + + +#include "../expr-int.h" + + + +/* Opération arithmétique impliquant deux opérandes (instance) */ +struct _GArithmOperation +{ + GScanExpression parent; /* A laisser en premier */ + + ArithmeticExpressionOperator operator; /* Type d'opération menée */ + + GScanExpression *first; /* Expression impactée #1 */ + GScanExpression *second; /* Expression impactée #2 */ + +}; + +/* Opération arithmétique impliquant deux opérandes (classe) */ +struct _GArithmOperationClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une opération arithmétique entre expressions. */ +bool g_arithmetic_operation_create(GArithmOperation *, ArithmeticExpressionOperator, GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_ARITHMOP_INT_H */ diff --git a/src/analysis/scan/exprs/arithmop.c b/src/analysis/scan/exprs/arithmop.c new file mode 100644 index 0000000..f57e260 --- /dev/null +++ b/src/analysis/scan/exprs/arithmop.c @@ -0,0 +1,414 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * arithmop.c - gestion des opérations arithmétiques + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "arithmop.h" + + +#include "arithmop-int.h" +#include "literal.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des opérations arithmétiques. */ +static void g_arithmetic_operation_class_init(GArithmOperationClass *); + +/* Initialise une instance d'opération arithmétique. */ +static void g_arithmetic_operation_init(GArithmOperation *); + +/* Supprime toutes les références externes. */ +static void g_arithmetic_operation_dispose(GArithmOperation *); + +/* Procède à la libération totale de la mémoire. */ +static void g_arithmetic_operation_finalize(GArithmOperation *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réalise une comparaison entre objets selon un critère précis. */ +static bool g_arithmetic_operation_compare_rich(const GArithmOperation *, const GArithmOperation *, RichCmpOperation, bool *); + +/* Initialise une instance d'opération de relation. */ +static GScanExpression *g_arithmetic_operation_duplicate(const GArithmOperation *); + +/* Réduit une expression à une forme plus simple. */ +GScanExpression *g_arithmetic_operation_reduce(GArithmOperation *, GScanContext *, bool); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une opération de relation entre expressions. */ +G_DEFINE_TYPE(GArithmOperation, g_arithmetic_operation, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des opérations arithmétiques. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_arithmetic_operation_class_init(GArithmOperationClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_arithmetic_operation_dispose; + object->finalize = (GObjectFinalizeFunc)g_arithmetic_operation_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)g_arithmetic_operation_compare_rich; + expr->dup = (dup_expr_fc)g_arithmetic_operation_duplicate; + expr->reduce = (reduce_expr_fc)g_arithmetic_operation_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser. * +* * +* Description : Initialise une instance d'opération arithmétique. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_arithmetic_operation_init(GArithmOperation *op) +{ + op->first = NULL; + op->second = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_arithmetic_operation_dispose(GArithmOperation *op) +{ + g_clear_object(&op->first); + g_clear_object(&op->second); + + G_OBJECT_CLASS(g_arithmetic_operation_parent_class)->dispose(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_arithmetic_operation_finalize(GArithmOperation *op) +{ + G_OBJECT_CLASS(g_arithmetic_operation_parent_class)->finalize(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : operator = type d'opération arithmétique à représenter. * +* first = premier opérande concerné. * +* second = éventuel second opérande impliqué ou NULL. * +* * +* Description : Organise une opération arithmétique entre expressions. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_arithmetic_operation_new(ArithmeticExpressionOperator operator, GScanExpression *first, GScanExpression *second) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_ARITHMETIC_OPERATION, NULL); + + if (!g_arithmetic_operation_create(G_ARITHMETIC_OPERATION(result), operator, first, second)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser pleinement. * +* operator = type d'opération booléenne à représenter. * +* first = premier opérande concerné. * +* second = éventuel second opérande impliqué ou NULL. * +* * +* Description : Met en place une opération arithmétique entre expressions. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_arithmetic_operation_create(GArithmOperation *op, ArithmeticExpressionOperator operator, GScanExpression *first, GScanExpression *second) +{ + bool result; /* Bilan à retourner */ + ExprValueType vtype; /* Type de valeur portée */ + + result = false; + + vtype = g_scan_expression_get_value_type(first); + + if (vtype != EVT_INTEGER && vtype != EVT_PENDING) + goto exit; + + vtype = g_scan_expression_get_value_type(second); + + if (vtype != EVT_INTEGER && vtype != EVT_PENDING) + goto exit; + + if (!g_scan_expression_create(G_SCAN_EXPRESSION(op), EVT_INTEGER)) + goto exit; + + op->operator = operator; + + op->first = first; + g_object_ref(G_OBJECT(op->first)); + + op->second = second; + g_object_ref(G_OBJECT(op->second)); + + result = true; + + exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = premier objet à consulter pour une comparaison. * +* other = second objet à consulter pour une comparaison. * +* op = opération de comparaison à réaliser. * +* status = bilan des opérations de comparaison. [OUT] * +* * +* Description : Réalise une comparaison entre objets selon un critère précis.* +* * +* Retour : true si la comparaison a pu être effectuée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_arithmetic_operation_compare_rich(const GArithmOperation *item, const GArithmOperation *other, RichCmpOperation op, bool *status) +{ + bool result; /* Etat à retourner */ + bool equal; /* Bilan intermédiaire */ + + result = true; // TODO : cmp parent()->type + + if (item->operator != other->operator) + { + result = compare_rich_integer_values(item->operator, other->operator, op); + goto done; + } + + equal = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item), G_COMPARABLE_ITEM(other), RCO_EQ, status); + + if (!equal) + { + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->first), + G_COMPARABLE_ITEM(other->first), + op, status); + goto done; + } + + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->second), + G_COMPARABLE_ITEM(other->second), + op, status); + + done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à copier. * +* * +* Description : Reproduit une expression en place dans une nouvelle instance.* +* * +* Retour : Nouvelle instance d'expression. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GScanExpression *g_arithmetic_operation_duplicate(const GArithmOperation *expr) +{ + GScanExpression *result; /* Instance copiée à retourner */ + + result = g_arithmetic_operation_new(expr->operator, expr->first, expr->second); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* final = impose une conversion finale de dernier tour. * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_arithmetic_operation_reduce(GArithmOperation *expr, GScanContext *ctx, bool final) +{ + GScanExpression *result; /* Instance à renvoyer */ + GScanExpression *new; /* Nouvelle expression obtenue */ + unsigned long long val_1; /* Première valeur à traiter */ + unsigned long long val_2; /* Second valeur à traiter */ + bool valid; /* Validité de ce bilan obtenu */ + unsigned long long reduced; /* Valeur réduite finale */ + + result = NULL; + + /* Réduction des éléments considérés */ + + new = g_scan_expression_reduce(expr->first, ctx, final); + + if (new != NULL) + { + g_object_unref(G_OBJECT(expr->first)); + expr->first = new; + } + + if (expr->second != NULL) + { + new = g_scan_expression_reduce(expr->second, ctx, final); + + if (new != NULL) + { + g_object_unref(G_OBJECT(expr->second)); + expr->second = new; + } + + } + + /* Construction d'une réduction locale ? */ + + if (G_IS_LITERAL_EXPRESSION(expr->first) && G_IS_LITERAL_EXPRESSION(expr->second)) + { + valid = g_literal_expression_get_integer_value(G_LITERAL_EXPRESSION(expr->first), &val_1); + + if (valid) + valid = g_literal_expression_get_integer_value(G_LITERAL_EXPRESSION(expr->second), &val_2); + + if (valid) + switch (expr->operator) + { + case AEO_PLUS: + reduced = val_1 + val_2; + break; + + case AEO_MINUS: + reduced = val_1 - val_2; + break; + + case AEO_MUL: + reduced = val_1 * val_2; + break; + + case AEO_DIV: + valid = (val_2 != 0); + if (valid) + reduced = val_1 / val_2; + break; + + case AEO_MOD: + valid = (val_2 != 0); + if (valid) + reduced = val_1 % val_2; + break; + + } + + if (valid) + result = g_literal_expression_new(EVT_INTEGER, &reduced); + + } + + return result; + +} diff --git a/src/analysis/scan/exprs/arithmop.h b/src/analysis/scan/exprs/arithmop.h new file mode 100644 index 0000000..dcc8bf8 --- /dev/null +++ b/src/analysis/scan/exprs/arithmop.h @@ -0,0 +1,67 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * arithmop.h - prototypes pour la gestion des opérations arithmétiques + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_ARITHMOP_H +#define _ANALYSIS_SCAN_EXPRS_ARITHMOP_H + + +#include "../expr.h" + + + +#define G_TYPE_ARITHMETIC_OPERATION g_arithmetic_operation_get_type() +#define G_ARITHMETIC_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ARITHMETIC_OPERATION, GArithmOperation)) +#define G_IS_ARITHMETIC_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ARITHMETIC_OPERATION)) +#define G_ARITHMETIC_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ARITHMETIC_OPERATION, GArithmOperationClass)) +#define G_IS_ARITHMETIC_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ARITHMETIC_OPERATION)) +#define G_ARITHMETIC_OPERATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ARITHMETIC_OPERATION, GArithmOperationClass)) + + +/* Opération arithmétique impliquant deux opérandes (instance) */ +typedef struct _GArithmOperation GArithmOperation; + +/* Opération arithmétique impliquant deux opérandes (classe) */ +typedef struct _GArithmOperationClass GArithmOperationClass; + + +/* Type d'opération arithmétique */ +typedef enum _ArithmeticExpressionOperator +{ + AEO_PLUS, /* Opération binaire "+" */ + AEO_MINUS, /* Opération binaire "-" */ + AEO_MUL, /* Opération binaire "*" */ + AEO_DIV, /* Opération binaire "\" */ + AEO_MOD, /* Opération binaire "%" */ + +} ArithmeticExpressionOperator; + + +/* Indique le type défini pour une opération arithmétique entre expressions. */ +GType g_arithmetic_operation_get_type(void); + +/* Organise une opération arithmétique entre expressions. */ +GScanExpression *g_arithmetic_operation_new(ArithmeticExpressionOperator, GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_ARITHMOP_H */ diff --git a/src/analysis/scan/exprs/boolop-int.h b/src/analysis/scan/exprs/boolop-int.h new file mode 100644 index 0000000..c381cfe --- /dev/null +++ b/src/analysis/scan/exprs/boolop-int.h @@ -0,0 +1,60 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * boolop-int.h - prototypes internes pour la gestion des opérations booléennes + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_BOOLOP_INT_H +#define _ANALYSIS_SCAN_EXPRS_BOOLOP_INT_H + + +#include "boolop.h" + + +#include "../expr-int.h" + + + +/* Opération booléenne avec un ou deux opérandes (instance) */ +struct _GBoolOperation +{ + GScanExpression parent; /* A laisser en premier */ + + BooleanOperationType type; /* Type d'opération menée */ + + GScanExpression *first; /* Expression impactée #1 */ + GScanExpression *second; /* Expression impactée #2 */ + +}; + +/* Opération booléenne avec un ou deux opérandes (classe) */ +struct _GBoolOperationClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une expression d'opération booléenne. */ +bool g_boolean_operation_create(GBoolOperation *, BooleanOperationType, GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_BOOLOP_INT_H */ diff --git a/src/analysis/scan/exprs/boolop.c b/src/analysis/scan/exprs/boolop.c new file mode 100644 index 0000000..2902fdd --- /dev/null +++ b/src/analysis/scan/exprs/boolop.c @@ -0,0 +1,450 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * boolop.c - gestion des opérations booléennes + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "boolop.h" + + +#include <assert.h> + + +#include "boolop-int.h" +#include "literal.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des opérations booléennes. */ +static void g_boolean_operation_class_init(GBoolOperationClass *); + +/* Initialise une instance d'opération booléenne. */ +static void g_boolean_operation_init(GBoolOperation *); + +/* Supprime toutes les références externes. */ +static void g_boolean_operation_dispose(GBoolOperation *); + +/* Procède à la libération totale de la mémoire. */ +static void g_boolean_operation_finalize(GBoolOperation *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réalise une comparaison entre objets selon un critère précis. */ +static bool g_boolean_operation_compare_rich(const GBoolOperation *, const GBoolOperation *, RichCmpOperation, bool *); + +/* Reproduit une expression en place dans une nouvelle instance. */ +static GScanExpression *g_boolean_operation_duplicate(const GBoolOperation *); + +/* Réduit une expression à une forme plus simple. */ +GScanExpression *g_boolean_operation_reduce(GBoolOperation *, GScanContext *, bool); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une opération booléenne sur expression(s). */ +G_DEFINE_TYPE(GBoolOperation, g_boolean_operation, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des opérations booléennes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_boolean_operation_class_init(GBoolOperationClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_boolean_operation_dispose; + object->finalize = (GObjectFinalizeFunc)g_boolean_operation_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)g_boolean_operation_compare_rich; + expr->dup = (dup_expr_fc)g_boolean_operation_duplicate; + expr->reduce = (reduce_expr_fc)g_boolean_operation_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser. * +* * +* Description : Initialise une instance d'opération booléenne. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_boolean_operation_init(GBoolOperation *op) +{ + op->first = NULL; + op->second = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_boolean_operation_dispose(GBoolOperation *op) +{ + g_clear_object(&op->first); + g_clear_object(&op->second); + + G_OBJECT_CLASS(g_boolean_operation_parent_class)->dispose(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_boolean_operation_finalize(GBoolOperation *op) +{ + G_OBJECT_CLASS(g_boolean_operation_parent_class)->finalize(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : type = type d'opération booléenne à représenter. * +* first = premier opérande concerné. * +* second = éventuel second opérande impliqué ou NULL. * +* * +* Description : Organise un appel de fonction avec ses arguments. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_boolean_operation_new(BooleanOperationType type, GScanExpression *first, GScanExpression *second) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_BOOLEAN_OPERATION, NULL); + + if (!g_boolean_operation_create(G_BOOLEAN_OPERATION(result), type, first, second)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = instance à initialiser pleinement. * +* type = type d'opération booléenne à représenter. * +* first = premier opérande concerné. * +* second = éventuel second opérande impliqué ou NULL. * +* * +* Description : Met en place une expression d'opération booléenne. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_boolean_operation_create(GBoolOperation *op, BooleanOperationType type, GScanExpression *first, GScanExpression *second) +{ + bool result; /* Bilan à retourner */ + + result = false; + + if (g_scan_expression_get_value_type(first) != EVT_BOOLEAN) + goto exit; + + if (g_scan_expression_get_value_type(second) != EVT_BOOLEAN) + goto exit; + + if (!g_scan_expression_create(G_SCAN_EXPRESSION(op), EVT_BOOLEAN)) + goto exit; + + op->type = type; + + switch (type) + { + case BOT_AND: + case BOT_OR: + op->first = first; + g_object_ref(G_OBJECT(op->first)); + + op->second = second; + g_object_ref(G_OBJECT(op->second)); + + result = true; + break; + + case BOT_NOT: + op->first = first; + g_object_ref(G_OBJECT(op->first)); + + result = (second == NULL); + assert(second != NULL); + break; + + } + + exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = premier objet à consulter pour une comparaison. * +* other = second objet à consulter pour une comparaison. * +* op = opération de comparaison à réaliser. * +* status = bilan des opérations de comparaison. [OUT] * +* * +* Description : Réalise une comparaison entre objets selon un critère précis.* +* * +* Retour : true si la comparaison a pu être effectuée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_boolean_operation_compare_rich(const GBoolOperation *item, const GBoolOperation *other, RichCmpOperation op, bool *status) +{ + bool result; /* Etat à retourner */ + bool equal; /* Bilan intermédiaire */ + + result = true; + + if (item->type != other->type) + { + *status = compare_rich_integer_values(item->type, other->type, op); + goto done; + } + + equal = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item), G_COMPARABLE_ITEM(other), RCO_EQ, status); + + if (!equal) + { + *status = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->first), + G_COMPARABLE_ITEM(other->first), + op, status); + goto done; + } + + if (item->second == NULL) + { + assert(other->second == NULL); + + switch (op) + { + case RCO_LT: + case RCO_NE: + case RCO_GT: + *status = false; + break; + + case RCO_LE: + case RCO_EQ: + case RCO_GE: + *status = true; + break; + + } + + } + + else + *status = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->second), + G_COMPARABLE_ITEM(other->second), + op, status); + + done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à copier. * +* * +* Description : Reproduit une expression en place dans une nouvelle instance.* +* * +* Retour : Nouvelle instance d'expression. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GScanExpression *g_boolean_operation_duplicate(const GBoolOperation *expr) +{ + GScanExpression *result; /* Instance copiée à retourner */ + + result = g_boolean_operation_new(expr->type, expr->first, expr->second); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* final = impose une conversion finale de dernier tour. * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_boolean_operation_reduce(GBoolOperation *expr, GScanContext *ctx, bool final) +{ + GScanExpression *result; /* Instance à renvoyer */ + GScanExpression *new; /* Nouvelle expression obtenue */ + bool values[2]; /* Valeurs des éléments portés */ + bool valid[2]; /* Validité de ces valeurs */ + + result = NULL; + + /* Réduction des éléments considérés */ + + new = g_scan_expression_reduce(expr->first, ctx, final); + + if (new != NULL) + { + g_object_unref(G_OBJECT(expr->first)); + expr->first = new; + } + + if (expr->second != NULL) + { + new = g_scan_expression_reduce(expr->second, ctx, final); + + if (new != NULL) + { + g_object_unref(G_OBJECT(expr->second)); + expr->second = new; + } + + } + + /* Construction d'une réduction locale ? */ + + switch (expr->type) + { + case BOT_AND: + if (G_IS_LITERAL_EXPRESSION(expr->first) && G_IS_LITERAL_EXPRESSION(expr->second)) + { + valid[0] = g_literal_expression_get_boolean_value(G_LITERAL_EXPRESSION(expr->first), &values[0]); + valid[1] = g_literal_expression_get_boolean_value(G_LITERAL_EXPRESSION(expr->second), &values[1]); + + if (valid[0] && valid[1]) + result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { values[0] && values[1] }); + + else + /* Etre malin si 0 && x => bilan (si ctx->quick) */ + ; + + } + break; + + case BOT_OR: + if (G_IS_LITERAL_EXPRESSION(expr->first) && G_IS_LITERAL_EXPRESSION(expr->second)) + { + valid[0] = g_literal_expression_get_boolean_value(G_LITERAL_EXPRESSION(expr->first), &values[0]); + valid[1] = g_literal_expression_get_boolean_value(G_LITERAL_EXPRESSION(expr->second), &values[1]); + + if (valid[0] && valid[1]) + result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { values[0] || values[1] }); + + } + break; + + case BOT_NOT: + if (G_IS_LITERAL_EXPRESSION(expr->first)) + { + valid[0] = g_literal_expression_get_boolean_value(G_LITERAL_EXPRESSION(expr->first), &values[0]); + + if (valid[0]) + result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { !values[1] }); + + } + break; + + } + + return result; + +} diff --git a/src/analysis/scan/exprs/boolop.h b/src/analysis/scan/exprs/boolop.h new file mode 100644 index 0000000..4add5a1 --- /dev/null +++ b/src/analysis/scan/exprs/boolop.h @@ -0,0 +1,65 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * boolop.h - prototypes pour la gestion des opérations booléennes + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_BOOLOP_H +#define _ANALYSIS_SCAN_EXPRS_BOOLOP_H + + +#include "../expr.h" + + + +#define G_TYPE_BOOLEAN_OPERATION g_boolean_operation_get_type() +#define G_BOOLEAN_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BOOLEAN_OPERATION, GBoolOperation)) +#define G_IS_BOOLEAN_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BOOLEAN_OPERATION)) +#define G_BOOLEAN_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BOOLEAN_OPERATION, GBoolOperationClass)) +#define G_IS_BOOLEAN_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BOOLEAN_OPERATION)) +#define G_BOOLEAN_OPERATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BOOLEAN_OPERATION, GBoolOperationClass)) + + +/* Opération booléenne avec un ou deux opérandes (instance) */ +typedef struct _GBoolOperation GBoolOperation; + +/* Opération booléenne avec un ou deux opérandes (classe) */ +typedef struct _GBoolOperationClass GBoolOperationClass; + + +/* Types d'opérations booléennes supportées */ +typedef enum _BooleanOperationType +{ + BOT_AND, /* Opérateur binaire "and" */ + BOT_OR, /* Opérateur binaire "or" */ + BOT_NOT, /* Opérateur unaire "not" */ + +} BooleanOperationType; + + +/* Indique le type défini pour une opération booléenne sur expression(s). */ +GType g_boolean_operation_get_type(void); + +/* Organise un appel de fonction avec ses arguments. */ +GScanExpression *g_boolean_operation_new(BooleanOperationType, GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_BOOLOP_H */ diff --git a/src/analysis/scan/exprs/call-int.h b/src/analysis/scan/exprs/call-int.h new file mode 100644 index 0000000..d68977f --- /dev/null +++ b/src/analysis/scan/exprs/call-int.h @@ -0,0 +1,63 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * call-int.h - prototypes internes pour l'organisation d'un appel à un élément de scan enregistré + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_CALL_INT_H +#define _ANALYSIS_SCAN_EXPRS_CALL_INT_H + + +#include "call.h" + + +#include "../expr-int.h" + + + +/* Exécution d'une fonction auxiliaire d'analyse (instance) */ +struct _GPendingCall +{ + GScanExpression parent; /* A laisser en premier */ + + GRegisteredItem *base; /* Base de recherche */ + char *target; /* Cible dans l'espace */ + + GScanExpression **args; /* Arguments d'appel fournis */ + size_t count; /* Quantité de ces arguments */ + + struct _GPendingCall *next; /* Evnetuel prochain élément */ + +}; + +/* Exécution d'une fonction auxiliaire d'analyse (classe) */ +struct _GPendingCallClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une expression d'appel. */ +bool g_pending_call_create(GPendingCall *, const char *, size_t, GScanExpression **, size_t); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_CALL_INT_H */ diff --git a/src/analysis/scan/exprs/call.c b/src/analysis/scan/exprs/call.c new file mode 100644 index 0000000..76f5fc3 --- /dev/null +++ b/src/analysis/scan/exprs/call.c @@ -0,0 +1,426 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * call.c - organisation d'un appel à un élément de scan enregistré + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "call.h" + + +#include <malloc.h> +#include <string.h> + + +#include "call-int.h" +#include "../../../core/global.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des appels de fonction avec arguments. */ +static void g_pending_call_class_init(GPendingCallClass *); + +/* Initialise une instance d'appel de fonction avec arguments. */ +static void g_pending_call_init(GPendingCall *); + +/* Supprime toutes les références externes. */ +static void g_pending_call_dispose(GPendingCall *); + +/* Procède à la libération totale de la mémoire. */ +static void g_pending_call_finalize(GPendingCall *); + +/* Définit une base de recherche pour la cible d'appel. */ +static void g_pending_call_set_base(GPendingCall *, GRegisteredItem *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Reproduit une expression en place dans une nouvelle instance. */ +static GScanExpression *g_pending_call_duplicate(const GPendingCall *); + +/* Réduit une expression à une forme plus simple. */ +GScanExpression *g_pending_call_reduce(GPendingCall *, GScanContext *, bool); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un appel de fonction enregistrée. */ +G_DEFINE_TYPE(GPendingCall, g_pending_call, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des appels de fonction avec arguments. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_pending_call_class_init(GPendingCallClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_pending_call_dispose; + object->finalize = (GObjectFinalizeFunc)g_pending_call_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)NULL; + expr->dup = (dup_expr_fc)g_pending_call_duplicate; + expr->reduce = (reduce_expr_fc)g_pending_call_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : call = instance à initialiser. * +* * +* Description : Initialise une instance d'appel de fonction avec arguments. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_pending_call_init(GPendingCall *call) +{ + call->base = NULL; + call->target = NULL; + + call->args = NULL; + call->count = 0; + + call->next = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : call = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_pending_call_dispose(GPendingCall *call) +{ + size_t i; /* Boucle de parcours */ + + g_clear_object(&call->base); + + for (i = 0; i < call->count; i++) + g_clear_object(&call->args[i]); + + g_clear_object(&call->next); + + G_OBJECT_CLASS(g_pending_call_parent_class)->dispose(G_OBJECT(call)); + +} + + +/****************************************************************************** +* * +* Paramètres : call = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_pending_call_finalize(GPendingCall *call) +{ + if (call->target != NULL) + free(call->target); + + if (call->args != NULL) + free(call->args); + + G_OBJECT_CLASS(g_pending_call_parent_class)->finalize(G_OBJECT(call)); + +} + + +/****************************************************************************** +* * +* Paramètres : target = désignation de l'objet d'appel à identifier. * +* len = taille de cette désignation. * +* args = éventuelle liste d'arguments à actionner. * +* count = quantité de ces arguments. * +* * +* Description : Organise un appel de fonction avec ses arguments. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_pending_call_new(const char *target, size_t len, GScanExpression **args, size_t count) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_PENDING_CALL, NULL); + + if (!g_pending_call_create(G_PENDING_CALL(result), target, len, args, count)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : call = instance à initialiser pleinement. * +* target = désignation de l'objet d'appel à identifier. * +* len = taille de cette désignation. * +* args = éventuelle liste d'arguments à actionner. * +* count = quantité de ces arguments. * +* * +* Description : Met en place une expression d'appel. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_pending_call_create(GPendingCall *call, const char *target, size_t len, GScanExpression **args, size_t count) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + + result = g_scan_expression_create(G_SCAN_EXPRESSION(call), EVT_PENDING); + if (!result) goto exit; + + call->target = strndup(target, len); + + call->args = malloc(count * sizeof(GScanExpression *)); + call->count = count; + + for (i = 0; i < count; i++) + { + call->args[i] = args[i]; + g_object_ref(G_OBJECT(args[i])); + } + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : call = expression d'appel à actualiser. * +* base = zone de recherche pour la résolution à venir. * +* * +* Description : Définit une base de recherche pour la cible d'appel. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_pending_call_set_base(GPendingCall *call, GRegisteredItem *base) +{ + call->base = base; + g_object_ref(G_OBJECT(base)); + +} + + +/****************************************************************************** +* * +* Paramètres : call = expression d'appel à compléter. * +* next = expression d'appel suivante dans la chaîne. * +* * +* Description : Complète la chaine d'expressions d'appel. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_pending_call_attach_next(GPendingCall *call, GPendingCall *next) +{ + call->next = next; + g_object_ref(G_OBJECT(next)); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : expr = expression à copier. * +* * +* Description : Reproduit une expression en place dans une nouvelle instance.* +* * +* Retour : Nouvelle instance d'expression. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GScanExpression *g_pending_call_duplicate(const GPendingCall *expr) +{ + GScanExpression *result; /* Instance copiée à retourner */ + + result = g_pending_call_new(expr->target, strlen(expr->target), expr->args, expr->count); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* final = indique une ultime conversion dans le cycle en cours.* +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_pending_call_reduce(GPendingCall *expr, GScanContext *ctx, bool final) +{ + GScanExpression *result; /* Instance à renvoyer */ + size_t i; /* Boucle de parcours */ + GScanExpression *new; /* Nouvelle expression obtenue */ + bool last; /* Détection de fin de chaîne */ + GRegisteredItem *base; /* Base de recherche courante */ + GRegisteredItem *rebase; /* Nouvelle base résolue */ + GScanExpression *new_next; /* Nouvelle version du suivant */ + + for (i = 0; i < expr->count; i++) + { + new = g_scan_expression_reduce(expr->args[i], ctx, final); + + if (new != NULL) + { + g_object_unref(G_OBJECT(expr->args[i])); + expr->args[i] = new; + } + + } + + last = (expr->next == NULL); + + if (!last) + new_next = g_scan_expression_duplicate(G_SCAN_EXPRESSION(expr->next)); + else + new_next = NULL; + + if (expr->target != NULL) + { + if (expr->base != NULL) + { + base = expr->base; + g_object_ref(G_OBJECT(base)); + } + else + base = G_REGISTERED_ITEM(get_rost_root_namespace()); + + rebase = g_registered_item_resolve(base, expr->target, ctx, + last ? NULL : expr->args, last ? 0 : expr->count, + last, final); + + g_object_unref(G_OBJECT(base)); + + if (rebase == NULL) + { + result = NULL; + goto done; + } + + if (last) + { + g_pending_call_set_base(expr, rebase); + + free(expr->target); + expr->target = NULL; + + } + else + g_pending_call_set_base(G_PENDING_CALL(new_next), rebase); + + } + + if (last) + result = g_registered_item_reduce(expr->base, ctx, expr->args, expr->count, final); + + else + { + result = g_scan_expression_reduce(new_next, ctx, final); + + if (result == NULL) + { + g_object_ref(G_OBJECT(new_next)); + result = new_next; + } + + } + + done: + + g_clear_object(&new_next); + + return result; + +} diff --git a/src/analysis/scan/exprs/call.h b/src/analysis/scan/exprs/call.h new file mode 100644 index 0000000..b69ca85 --- /dev/null +++ b/src/analysis/scan/exprs/call.h @@ -0,0 +1,59 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * call.h - prototypes pour l'organisation d'un appel à un élément de scan enregistré + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_CALL_H +#define _ANALYSIS_SCAN_EXPRS_CALL_H + + +#include "../expr.h" +#include "../item.h" + + + +#define G_TYPE_PENDING_CALL g_pending_call_get_type() +#define G_PENDING_CALL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PENDING_CALL, GPendingCall)) +#define G_IS_PENDING_CALL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PENDING_CALL)) +#define G_PENDING_CALL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PENDING_CALL, GPendingCallClass)) +#define G_IS_PENDING_CALL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PENDING_CALL)) +#define G_PENDING_CALL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PENDING_CALL, GPendingCallClass)) + + +/* Exécution d'une fonction auxiliaire d'analyse (instance) */ +typedef struct _GPendingCall GPendingCall; + +/* Exécution d'une fonction auxiliaire d'analyse (classe) */ +typedef struct _GPendingCallClass GPendingCallClass; + + +/* Indique le type défini pour un appel de fonction enregistrée. */ +GType g_pending_call_get_type(void); + +/* Organise un appel de fonction avec ses arguments. */ +GScanExpression *g_pending_call_new(const char *, size_t, GScanExpression **, size_t); + +/* Complète la chaine d'expressions d'appel. */ +void g_pending_call_attach_next(GPendingCall *, GPendingCall *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_CALL_H */ diff --git a/src/analysis/scan/exprs/literal-int.h b/src/analysis/scan/exprs/literal-int.h new file mode 100644 index 0000000..d803d30 --- /dev/null +++ b/src/analysis/scan/exprs/literal-int.h @@ -0,0 +1,73 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * literal-int.h - prototypes internes pour la représentation d'une valeur concrète + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_LITERAL_INT_H +#define _ANALYSIS_SCAN_EXPRS_LITERAL_INT_H + + +#include "literal.h" + + +#include <stdbool.h> + + +#include "../expr-int.h" + + + +/* Expression portant une valeur concrète (instance) */ +struct _GLiteralExpression +{ + GScanExpression parent; /* A laisser en premier */ + + ExprValueType value_type; /* Type de valeur portée */ + + union + { + bool boolean; /* Valeur booléenne */ + unsigned long long integer; /* Valeur entière 64 bits */ + char *string; /* Chaîne de caractères */ + struct + { + char *regex; /* Formulation d'origine */ + regex_t preg; /* Expression rationnelle */ + }; + + } value; + +}; + +/* Expression portant une valeur concrète (classe) */ +struct _GLiteralExpressionClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une expression de valeur concrête. */ +bool g_literal_expression_create(GLiteralExpression *, ExprValueType, ...); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_LITERAL_INT_H */ diff --git a/src/analysis/scan/exprs/literal.c b/src/analysis/scan/exprs/literal.c new file mode 100644 index 0000000..f40747d --- /dev/null +++ b/src/analysis/scan/exprs/literal.c @@ -0,0 +1,605 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * literal.c - représentation d'une valeur concrète + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "literal.h" + + +#include <assert.h> +#include <stdarg.h> +#include <string.h> + + +#include "literal-int.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des expressions de valeur concrète. */ +static void g_literal_expression_class_init(GLiteralExpressionClass *); + +/* Initialise une instance d'expression de valeur concrète. */ +static void g_literal_expression_init(GLiteralExpression *); + +/* Supprime toutes les références externes. */ +static void g_literal_expression_dispose(GLiteralExpression *); + +/* Procède à la libération totale de la mémoire. */ +static void g_literal_expression_finalize(GLiteralExpression *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réalise une comparaison entre objets selon un critère précis. */ +static bool g_literal_expression_compare_rich(const GLiteralExpression *, const GLiteralExpression *, RichCmpOperation, bool *); + +/* Reproduit une expression en place dans une nouvelle instance. */ +static GScanExpression *g_literal_expression_duplicate(const GLiteralExpression *); + +/* Réduit une expression à une forme plus simple. */ +GScanExpression *g_literal_expression_reduce(GLiteralExpression *, GScanContext *, bool); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un appel de fonction enregistrée. */ +G_DEFINE_TYPE(GLiteralExpression, g_literal_expression, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des expressions de valeur concrète. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_literal_expression_class_init(GLiteralExpressionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_literal_expression_dispose; + object->finalize = (GObjectFinalizeFunc)g_literal_expression_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)g_literal_expression_compare_rich; + expr->dup = (dup_expr_fc)g_literal_expression_duplicate; + expr->reduce = (reduce_expr_fc)g_literal_expression_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = instance à initialiser. * +* * +* Description : Initialise une instance d'expression de valeur concrète. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_literal_expression_init(GLiteralExpression *expr) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : expr = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_literal_expression_dispose(GLiteralExpression *expr) +{ + G_OBJECT_CLASS(g_literal_expression_parent_class)->dispose(G_OBJECT(expr)); + +} + + +/****************************************************************************** +* * +* Paramètres : expr = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_literal_expression_finalize(GLiteralExpression *expr) +{ + G_OBJECT_CLASS(g_literal_expression_parent_class)->finalize(G_OBJECT(expr)); + +} + + +/****************************************************************************** +* * +* Paramètres : vtype = type de valeur associée par l'expression. * +* ... = valeur concrête à intégrer. * +* * +* Description : Organise un appel de fonction avec ses arguments. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_literal_expression_new(ExprValueType vtype, ...) +{ + GScanExpression *result; /* Structure à retourner */ + va_list ap; /* Liste d'arguements */ + void *ptr; /* Vision générique de valeur */ + + result = g_object_new(G_TYPE_LITERAL_EXPRESSION, NULL); + + va_start(ap, vtype); + + ptr = va_arg(ap, void *); + + if (!g_literal_expression_create(G_LITERAL_EXPRESSION(result), vtype, ptr)) + g_clear_object(&result); + + va_end(ap); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = instance à initialiser pleinement. * +* vtype = type de valeur associée par l'expression. * +* ... = valeur concrête à intégrer. * +* * +* Description : Met en place une expression de valeur concrête. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_literal_expression_create(GLiteralExpression *expr, ExprValueType vtype, ...) +{ + bool result; /* Bilan à retourner */ + va_list ap; /* Liste d'arguements */ + const bool *boolean; /* Valeur booléenne */ + const unsigned long long *integer; /* Valeur entière 64 bits */ + const char *string; /* Chaîne de caractères */ + size_t len; /* Taille de la chaîne */ + int cflags; /* Détails de compilation */ + unsigned int i; /* Boucle de parcours */ + char *tmp; /* Zone de travail temporaire */ + int ret; /* Bilan d'une opération */ + + result = g_scan_expression_create(G_SCAN_EXPRESSION(expr), vtype); + + if (result) + { + va_start(ap, vtype); + + switch (vtype) + { + case EVT_BOOLEAN: + boolean = va_arg(ap, const bool *); + expr->value.boolean = *boolean; + break; + + case EVT_INTEGER: + integer = va_arg(ap, const unsigned long long *); + expr->value.integer = *integer; + break; + + case EVT_STRING: + string = va_arg(ap, const char *); + expr->value.string = strdup(string); + break; + + case EVT_REG_EXPR: + string = va_arg(ap, const char *); + len = strlen(string); + + result = (len > 2 && string[0] == '/'); + + cflags = REG_EXTENDED | REG_NOSUB; + + for (i = 0; i < 2 && result; i++) + { + result = (len > 2); + + if (string[len - 1] == 'i') + { + cflags |= REG_ICASE; + len -= 1; + } + + else if (string[len - 1] == 's') + { + cflags |= REG_NEWLINE; + len -= 1; + } + + else if (string[len - 1] == '/') + break; + + } + + if (result) + result = (string[len - 1] == '/'); + + if (result) + { + assert(len > 2); + + tmp = strndup(&string[1], len - 2); + ret = regcomp(&expr->value.preg, tmp, cflags); + free(tmp); + + result = (ret == 0); + + if (result) + expr->value.regex = strdup(string); + + } + + break; + + default: + result = false; + break; + + } + + va_end(ap); + + } + + expr->value_type = vtype; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = premier objet à consulter pour une comparaison. * +* value = valeur portée portée par l'expression. [OUT] * +* * +* Description : Indique la valeur portée par une expression booléenne. * +* * +* Retour : true si l'expression est de type booléen, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_literal_expression_get_boolean_value(const GLiteralExpression *item, bool *value) +{ + bool result; /* Etat à retourner */ + + result = (item->value_type == EVT_BOOLEAN); + + if (result) + *value = item->value.boolean; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = premier objet à consulter pour une comparaison. * +* value = valeur portée portée par l'expression. [OUT] * +* * +* Description : Indique la valeur portée par une expression d'entier. * +* * +* Retour : true si l'expression est de type entier, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_literal_expression_get_integer_value(const GLiteralExpression *item, unsigned long long *value) +{ + bool result; /* Etat à retourner */ + + result = (item->value_type == EVT_INTEGER); + + if (result) + *value = item->value.integer; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = premier objet à consulter pour une comparaison. * +* value = valeur portée portée par l'expression. [OUT] * +* * +* Description : Indique la valeur portée par une expression de chaîne. * +* * +* Retour : true si l'expression est de type entier, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_literal_expression_get_string_value(const GLiteralExpression *item, const char **value) +{ + bool result; /* Etat à retourner */ + + result = (item->value_type == EVT_STRING); + + if (result) + *value = item->value.string; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = premier objet à consulter pour une comparaison. * +* value = valeur portée portée par l'expression. [OUT] * +* * +* Description : Indique la valeur portée par une expression rationnelle. * +* * +* Retour : true si l'expression est de type entier, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_literal_expression_get_regex_value(const GLiteralExpression *item, const regex_t **value) +{ + bool result; /* Etat à retourner */ + + result = (item->value_type == EVT_REG_EXPR); + + if (result) + *value = &item->value.preg; + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = premier objet à consulter pour une comparaison. * +* other = second objet à consulter pour une comparaison. * +* op = opération de comparaison à réaliser. * +* status = bilan des opérations de comparaison. [OUT] * +* * +* Description : Réalise une comparaison entre objets selon un critère précis.* +* * +* Retour : true si la comparaison a pu être effectuée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_literal_expression_compare_rich(const GLiteralExpression *item, const GLiteralExpression *other, RichCmpOperation op, bool *status) +{ + bool result; /* Etat à retourner */ + int cmp; /* Bilan intermédiaire */ + + if (item->value_type != other->value_type) + { + *status = compare_rich_integer_values(item->value_type, other->value_type, op); + result = true; + goto done; + } + + switch (item->value_type) + { + case EVT_BOOLEAN: + switch (op) + { + case RCO_EQ: + *status = (item->value.boolean == other->value.boolean); + result = true; + break; + + case RCO_NE: + *status = (item->value.boolean != other->value.boolean); + result = true; + break; + + default: + result = false; + break; + + }; + break; + + case EVT_INTEGER: + *status = compare_rich_integer_values(item->value.integer, other->value.integer, op); + result = true; + break; + + case EVT_STRING: + cmp = strcmp(item->value.string, other->value.string); + *status = compare_rich_integer_values(cmp, 0, op); + result = true; + break; + + case EVT_REG_EXPR: + cmp = strcmp(item->value.regex, other->value.regex); + *status = compare_rich_integer_values(cmp, 0, op); + result = true; + break; + + default: + result = false; + break; + + } + + done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à copier. * +* * +* Description : Reproduit une expression en place dans une nouvelle instance.* +* * +* Retour : Nouvelle instance d'expression. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GScanExpression *g_literal_expression_duplicate(const GLiteralExpression *expr) +{ + GScanExpression *result; /* Instance copiée à retourner */ + const void *ptr; /* Pointeur vers des données */ + + switch (expr->value_type) + { + case EVT_BOOLEAN: + ptr = &expr->value.boolean; + break; + + case EVT_INTEGER: + ptr = &expr->value.integer; + break; + + case EVT_STRING: + ptr = &expr->value.string; + break; + + case EVT_REG_EXPR: + ptr = &expr->value.regex; + break; + + default: + ptr = NULL; + break; + + } + + assert(ptr != NULL); + + result = g_literal_expression_new(expr->value_type, ptr); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* force = impose une conversion en booléen si possible. * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_literal_expression_reduce(GLiteralExpression *expr, GScanContext *ctx, bool force) +{ + GScanExpression *result; /* Instance à renvoyer */ + + if (!force) + result = NULL; + + else + switch (expr->value_type) + { + case EVT_BOOLEAN: + result = NULL; + break; + + case EVT_INTEGER: + result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { expr->value.integer > 0 }); + break; + + case EVT_STRING: + result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { strlen(expr->value.string) > 0 }); + break; + + case EVT_REG_EXPR: + result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { strlen(expr->value.regex) > 0 }); + break; + + default: + result = NULL; + break; + + } + + return result; + +} diff --git a/src/analysis/scan/exprs/literal.h b/src/analysis/scan/exprs/literal.h new file mode 100644 index 0000000..ac5724f --- /dev/null +++ b/src/analysis/scan/exprs/literal.h @@ -0,0 +1,70 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * literal.h - prototypes pour la représentation d'une valeur concrète + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_LITERAL_H +#define _ANALYSIS_SCAN_EXPRS_LITERAL_H + + +#include <regex.h> + + +#include "../expr.h" + + + +#define G_TYPE_LITERAL_EXPRESSION g_literal_expression_get_type() +#define G_LITERAL_EXPRESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_LITERAL_EXPRESSION, GLiteralExpression)) +#define G_IS_LITERAL_EXPRESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_LITERAL_EXPRESSION)) +#define G_LITERAL_EXPRESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_LITERAL_EXPRESSION, GLiteralExpressionClass)) +#define G_IS_LITERAL_EXPRESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_LITERAL_EXPRESSION)) +#define G_LITERAL_EXPRESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_LITERAL_EXPRESSION, GLiteralExpressionClass)) + + +/* Expression portant une valeur concrète (instance) */ +typedef struct _GLiteralExpression GLiteralExpression; + +/* Expression portant une valeur concrète (classe) */ +typedef struct _GLiteralExpressionClass GLiteralExpressionClass; + + +/* Indique le type défini pour un appel de fonction enregistrée. */ +GType g_literal_expression_get_type(void); + +/* Organise un appel de fonction avec ses arguments. */ +GScanExpression *g_literal_expression_new(ExprValueType, ...); + +/* Indique la valeur portée par une expression booléenne. */ +bool g_literal_expression_get_boolean_value(const GLiteralExpression *, bool *); + +/* Indique la valeur portée par une expression d'entier. */ +bool g_literal_expression_get_integer_value(const GLiteralExpression *, unsigned long long *); + +/* Indique la valeur portée par une expression de chaîne. */ +bool g_literal_expression_get_string_value(const GLiteralExpression *, const char **); + +/* Indique la valeur portée par une expression rationnelle. */ +bool g_literal_expression_get_regex_value(const GLiteralExpression *, const regex_t **); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_LITERAL_H */ diff --git a/src/analysis/scan/exprs/relop-int.h b/src/analysis/scan/exprs/relop-int.h new file mode 100644 index 0000000..273b543 --- /dev/null +++ b/src/analysis/scan/exprs/relop-int.h @@ -0,0 +1,60 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * relop-int.h - prototypes internes pour la gestion des opérations relationnelles + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_RELOP_INT_H +#define _ANALYSIS_SCAN_EXPRS_RELOP_INT_H + + +#include "relop.h" + + +#include "../expr-int.h" + + + +/* Opération relationnelle impliquant deux opérandes (instance) */ +struct _GRelOperation +{ + GScanExpression parent; /* A laisser en premier */ + + RichCmpOperation rel_type; /* Type de relation étudiée */ + + GScanExpression *first; /* Expression impactée #1 */ + GScanExpression *second; /* Expression impactée #2 */ + +}; + +/* Opération relationnelle impliquant deux opérandes (classe) */ +struct _GRelOperationClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une opération relationnelle entre expressions. */ +bool g_relational_operation_create(GRelOperation *, RichCmpOperation, GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_RELOP_INT_H */ diff --git a/src/analysis/scan/exprs/relop.c b/src/analysis/scan/exprs/relop.c new file mode 100644 index 0000000..94ce77d --- /dev/null +++ b/src/analysis/scan/exprs/relop.c @@ -0,0 +1,374 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * relop.c - gestion des opérations relationnelles + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "relop.h" + + +#include "relop-int.h" +#include "literal.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des opérations de relations. */ +static void g_relational_operation_class_init(GRelOperationClass *); + +/* Initialise une instance d'opération de relation. */ +static void g_relational_operation_init(GRelOperation *); + +/* Supprime toutes les références externes. */ +static void g_relational_operation_dispose(GRelOperation *); + +/* Procède à la libération totale de la mémoire. */ +static void g_relational_operation_finalize(GRelOperation *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réalise une comparaison entre objets selon un critère précis. */ +static bool g_relational_operation_compare_rich(const GRelOperation *, const GRelOperation *, RichCmpOperation, bool *); + +/* Initialise une instance d'opération de relation. */ +static GScanExpression *g_relational_operation_duplicate(const GRelOperation *); + +/* Réduit une expression à une forme plus simple. */ +GScanExpression *g_relational_operation_reduce(GRelOperation *, GScanContext *, bool); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une opération de relation entre expressions. */ +G_DEFINE_TYPE(GRelOperation, g_relational_operation, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des opérations de relations. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_relational_operation_class_init(GRelOperationClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_relational_operation_dispose; + object->finalize = (GObjectFinalizeFunc)g_relational_operation_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)g_relational_operation_compare_rich; + expr->dup = (dup_expr_fc)g_relational_operation_duplicate; + expr->reduce = (reduce_expr_fc)g_relational_operation_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser. * +* * +* Description : Initialise une instance d'opération de relation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_relational_operation_init(GRelOperation *op) +{ + op->first = NULL; + op->second = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_relational_operation_dispose(GRelOperation *op) +{ + g_clear_object(&op->first); + g_clear_object(&op->second); + + G_OBJECT_CLASS(g_relational_operation_parent_class)->dispose(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_relational_operation_finalize(GRelOperation *op) +{ + G_OBJECT_CLASS(g_relational_operation_parent_class)->finalize(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : type = type d'opération booléenne à représenter. * +* first = premier opérande concerné. * +* second = éventuel second opérande impliqué ou NULL. * +* * +* Description : Organise une opération relationnelle entre expressions. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_relational_operation_new(RichCmpOperation type, GScanExpression *first, GScanExpression *second) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_RELATIONAL_OPERATION, NULL); + + if (!g_relational_operation_create(G_RELATIONAL_OPERATION(result), type, first, second)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser pleinement. * +* type = type d'opération booléenne à représenter. * +* first = premier opérande concerné. * +* second = éventuel second opérande impliqué ou NULL. * +* * +* Description : Met en place une opération relationnelle entre expressions. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_relational_operation_create(GRelOperation *op, RichCmpOperation type, GScanExpression *first, GScanExpression *second) +{ + bool result; /* Bilan à retourner */ + + result = false; + + if (g_scan_expression_get_value_type(first) != g_scan_expression_get_value_type(first)) + goto exit; + + if (!g_scan_expression_create(G_SCAN_EXPRESSION(op), EVT_BOOLEAN)) + goto exit; + + op->rel_type = type; + + op->first = first; + g_object_ref(G_OBJECT(op->first)); + + op->second = second; + g_object_ref(G_OBJECT(op->second)); + + result = true; + + exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = premier objet à consulter pour une comparaison. * +* other = second objet à consulter pour une comparaison. * +* op = opération de comparaison à réaliser. * +* status = bilan des opérations de comparaison. [OUT] * +* * +* Description : Réalise une comparaison entre objets selon un critère précis.* +* * +* Retour : true si la comparaison a pu être effectuée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_relational_operation_compare_rich(const GRelOperation *item, const GRelOperation *other, RichCmpOperation op, bool *status) +{ + bool result; /* Etat à retourner */ + bool equal; /* Bilan intermédiaire */ + + result = true; // TODO : cmp parent()->type + + if (item->rel_type != other->rel_type) + { + result = compare_rich_integer_values(item->rel_type, other->rel_type, op); + goto done; + } + + equal = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item), G_COMPARABLE_ITEM(other), RCO_EQ, status); + + if (!equal) + { + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->first), + G_COMPARABLE_ITEM(other->first), + op, status); + goto done; + } + + result = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(item->second), + G_COMPARABLE_ITEM(other->second), + op, status); + + done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à copier. * +* * +* Description : Reproduit une expression en place dans une nouvelle instance.* +* * +* Retour : Nouvelle instance d'expression. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GScanExpression *g_relational_operation_duplicate(const GRelOperation *expr) +{ + GScanExpression *result; /* Instance copiée à retourner */ + + result = g_relational_operation_new(expr->rel_type, expr->first, expr->second); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* final = impose une conversion finale de dernier tour. * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_relational_operation_reduce(GRelOperation *expr, GScanContext *ctx, bool final) +{ + GScanExpression *result; /* Instance à renvoyer */ + GScanExpression *new; /* Nouvelle expression obtenue */ + bool status; /* Bilan d'une comparaison */ + bool valid; /* Validité de ce bilan obtenu */ + + result = NULL; + + /* Réduction des éléments considérés */ + + new = g_scan_expression_reduce(expr->first, ctx, final); + + if (new != NULL) + { + g_object_unref(G_OBJECT(expr->first)); + expr->first = new; + } + + if (expr->second != NULL) + { + new = g_scan_expression_reduce(expr->second, ctx, final); + + if (new != NULL) + { + g_object_unref(G_OBJECT(expr->second)); + expr->second = new; + } + + } + + /* Construction d'une réduction locale ? */ + + if (G_IS_LITERAL_EXPRESSION(expr->first) && G_IS_LITERAL_EXPRESSION(expr->second)) + { + valid = g_comparable_item_compare_rich(G_COMPARABLE_ITEM(expr->first), + G_COMPARABLE_ITEM(expr->second), + expr->rel_type, &status); + + if (valid) + result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { status }); + + } + + return result; + +} diff --git a/src/analysis/scan/exprs/relop.h b/src/analysis/scan/exprs/relop.h new file mode 100644 index 0000000..ecbc8ef --- /dev/null +++ b/src/analysis/scan/exprs/relop.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * relop.h - prototypes pour la gestion des opérations relationnelles + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_RELOP_H +#define _ANALYSIS_SCAN_EXPRS_RELOP_H + + +#include "../expr.h" +#include "../../../glibext/comparison.h" + + + +#define G_TYPE_RELATIONAL_OPERATION g_relational_operation_get_type() +#define G_RELATIONAL_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_RELATIONAL_OPERATION, GRelOperation)) +#define G_IS_RELATIONAL_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_RELATIONAL_OPERATION)) +#define G_RELATIONAL_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RELATIONAL_OPERATION, GRelOperationClass)) +#define G_IS_RELATIONAL_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RELATIONAL_OPERATION)) +#define G_RELATIONAL_OPERATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RELATIONAL_OPERATION, GRelOperationClass)) + + +/* Opération relationnelle impliquant deux opérandes (instance) */ +typedef struct _GRelOperation GRelOperation; + +/* Opération relationnelle impliquant deux opérandes (classe) */ +typedef struct _GRelOperationClass GRelOperationClass; + + +/* Indique le type défini pour une opération de relation entre expressions. */ +GType g_relational_operation_get_type(void); + +/* Organise une opération relationnelle entre expressions. */ +GScanExpression *g_relational_operation_new(RichCmpOperation, GScanExpression *, GScanExpression *); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_RELOP_H */ diff --git a/src/analysis/scan/exprs/str-int.h b/src/analysis/scan/exprs/str-int.h new file mode 100644 index 0000000..9bed5cf --- /dev/null +++ b/src/analysis/scan/exprs/str-int.h @@ -0,0 +1,61 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * str-int.h - prototypes internes pour la gestion des opérations booléennes + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_STR_INT_H +#define _ANALYSIS_SCAN_EXPRS_STR_INT_H + + +#include "str.h" + + +#include "../expr-int.h" + + + +/* Opération booléenne avec un ou deux opérandes (instance) */ +struct _GStringOperation +{ + GScanExpression parent; /* A laisser en premier */ + + StringOperationType type; /* Type d'opération menée */ + bool case_sensitive; /* Respect de la casse ? */ + + GScanExpression *first; /* Expression impactée #1 */ + GScanExpression *second; /* Expression impactée #2 */ + +}; + +/* Opération booléenne avec un ou deux opérandes (classe) */ +struct _GStringOperationClass +{ + GScanExpressionClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une expression d'opération traite une chaîne. */ +bool g_string_operation_create(GStringOperation *, StringOperationType, GScanExpression *, GScanExpression *, bool); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_STR_INT_H */ diff --git a/src/analysis/scan/exprs/str.c b/src/analysis/scan/exprs/str.c new file mode 100644 index 0000000..675b2f6 --- /dev/null +++ b/src/analysis/scan/exprs/str.c @@ -0,0 +1,437 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * str.c - gestion des opérations booléennes + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "str.h" + + +#include <assert.h> +#include <string.h> +#include <strings.h> + + +#include "str-int.h" +#include "literal.h" + + + +/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */ + + +/* Initialise la classe des opérations visant des chaînes. */ +static void g_string_operation_class_init(GStringOperationClass *); + +/* Initialise une instance d'opération visant une chaîne. */ +static void g_string_operation_init(GStringOperation *); + +/* Supprime toutes les références externes. */ +static void g_string_operation_dispose(GStringOperation *); + +/* Procède à la libération totale de la mémoire. */ +static void g_string_operation_finalize(GStringOperation *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Reproduit une expression en place dans une nouvelle instance. */ +static GScanExpression *g_string_operation_duplicate(const GStringOperation *); + +/* Réduit une expression à une forme plus simple. */ +GScanExpression *g_string_operation_reduce(GStringOperation *, GScanContext *, bool); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une opération traitant une chaîne de caractères. */ +G_DEFINE_TYPE(GStringOperation, g_string_operation, G_TYPE_SCAN_EXPRESSION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des opérations visant des chaînes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_string_operation_class_init(GStringOperationClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanExpressionClass *expr; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_string_operation_dispose; + object->finalize = (GObjectFinalizeFunc)g_string_operation_finalize; + + expr = G_SCAN_EXPRESSION_CLASS(klass); + + expr->cmp_rich = (compare_expr_rich_fc)NULL; + expr->dup = (dup_expr_fc)g_string_operation_duplicate; + expr->reduce = (reduce_expr_fc)g_string_operation_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser. * +* * +* Description : Initialise une instance d'opération visant une chaîne. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_string_operation_init(GStringOperation *op) +{ + op->first = NULL; + op->second = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_string_operation_dispose(GStringOperation *op) +{ + g_clear_object(&op->first); + g_clear_object(&op->second); + + G_OBJECT_CLASS(g_string_operation_parent_class)->dispose(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_string_operation_finalize(GStringOperation *op) +{ + G_OBJECT_CLASS(g_string_operation_parent_class)->finalize(G_OBJECT(op)); + +} + + +/****************************************************************************** +* * +* Paramètres : type = type d'opération booléenne à représenter. * +* first = premier opérande concerné. * +* second = éventuel second opérande impliqué ou NULL. * +* sensitive = détermine la prise en compte de la casse. * +* * +* Description : Organise un appel de fonction avec ses arguments. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_string_operation_new(StringOperationType type, GScanExpression *first, GScanExpression *second, bool sensitive) +{ + GScanExpression *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_STRING_OPERATION, NULL); + + if (!g_string_operation_create(G_STRING_OPERATION(result), type, first, second, sensitive)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : op = instance à initialiser pleinement. * +* type = type d'opération booléenne à représenter. * +* first = premier opérande concerné. * +* second = éventuel second opérande impliqué ou NULL. * +* sensitive = détermine la prise en compte de la casse. * +* * +* Description : Met en place une expression d'opération traite une chaîne. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_string_operation_create(GStringOperation *op, StringOperationType type, GScanExpression *first, GScanExpression *second, bool sensitive) +{ + bool result; /* Bilan à retourner */ + ExprValueType vtype; /* Type de valeur portée */ + + result = false; + + vtype = g_scan_expression_get_value_type(first); + + if (vtype != EVT_STRING && vtype != EVT_PENDING) + goto exit; + + vtype = g_scan_expression_get_value_type(second); + + if (vtype != EVT_STRING && vtype != EVT_REG_EXPR && vtype != EVT_PENDING) + goto exit; + + op->type = type; + + switch (type) + { + case SOT_CONTAINS: + case SOT_STARTSWITH: + case SOT_ENDSWITH: + op->case_sensitive = sensitive; + break; + + case SOT_MATCHES: + break; + + case SOT_IEQUALS: + assert(!sensitive); + op->case_sensitive = false; + break; + + } + + op->first = first; + g_object_ref(G_OBJECT(op->first)); + + op->second = second; + g_object_ref(G_OBJECT(op->second)); + + result = true; + + exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : op = expression à copier. * +* * +* Description : Reproduit une expression en place dans une nouvelle instance.* +* * +* Retour : Nouvelle instance d'expression. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GScanExpression *g_string_operation_duplicate(const GStringOperation *op) +{ + GScanExpression *result; /* Instance copiée à retourner */ + + result = g_string_operation_new(op->type, op->first, op->second, op->case_sensitive); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : op = expression à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* final = impose une conversion finale de dernier tour. * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_string_operation_reduce(GStringOperation *op, GScanContext *ctx, bool final) +{ + GScanExpression *result; /* Instance à renvoyer */ + GScanExpression *new; /* Nouvelle expression obtenue */ + const char *strings[2]; /* Chaînes en jeu */ + bool status; /* Bilan intermédiaire */ + char *found; /* Eventuelle portion trouvée */ + size_t len[2]; /* Tailles max. de comparaison */ + int ret; /* Bilan de comparaison */ + const regex_t *preg; /* Expression rationnelle */ + + result = NULL; + + /* Réduction des éléments considérés */ + + new = g_scan_expression_reduce(op->first, ctx, final); + + if (new != NULL) + { + g_object_unref(G_OBJECT(op->first)); + op->first = new; + } + + new = g_scan_expression_reduce(op->second, ctx, final); + + if (new != NULL) + { + g_object_unref(G_OBJECT(op->second)); + op->second = new; + } + + /* Construction d'une réduction locale ? */ + + if (!G_IS_LITERAL_EXPRESSION(op->first)) + goto exit; + + if (!G_IS_LITERAL_EXPRESSION(op->second)) + goto exit; + + status = g_literal_expression_get_string_value(G_LITERAL_EXPRESSION(op->first), &strings[0]); + if (!status) goto exit; + + switch (op->type) + { + case SOT_CONTAINS: + + status = g_literal_expression_get_string_value(G_LITERAL_EXPRESSION(op->second), &strings[1]); + if (!status) goto exit; + + if (op->case_sensitive) + found = strstr(strings[0], strings[1]); + else + found = strcasestr(strings[0], strings[1]); + + result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { found != NULL }); + break; + + case SOT_STARTSWITH: + + status = g_literal_expression_get_string_value(G_LITERAL_EXPRESSION(op->second), &strings[1]); + if (!status) goto exit; + + len[1] = strlen(strings[1]); + + if (op->case_sensitive) + ret = strncmp(strings[0], strings[1], len[1]); + else + ret = strncasecmp(strings[0], strings[1], len[1]); + + result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { ret == 0 }); + break; + + case SOT_ENDSWITH: + + len[0] = strlen(strings[0]); + + status = g_literal_expression_get_string_value(G_LITERAL_EXPRESSION(op->second), &strings[1]); + if (!status) goto exit; + + len[1] = strlen(strings[1]); + + if (len[0] < len[1]) + result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { false }); + + else + { + if (op->case_sensitive) + ret = strncmp(strings[0] + (len[0] - len[1]), strings[1], len[1]); + else + ret = strncasecmp(strings[0] + (len[0] - len[1]), strings[1], len[1]); + + result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { ret == 0 }); + + } + break; + + case SOT_MATCHES: + + status = g_literal_expression_get_regex_value(G_LITERAL_EXPRESSION(op->second), &preg); + if (!status) goto exit; + + ret = regexec(preg, strings[0], 0, NULL, 0); + + result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { ret != REG_NOMATCH }); + break; + + case SOT_IEQUALS: + + len[0] = strlen(strings[0]); + + status = g_literal_expression_get_string_value(G_LITERAL_EXPRESSION(op->second), &strings[1]); + if (!status) goto exit; + + len[1] = strlen(strings[1]); + + if (len[0] != len[1]) + result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { false }); + + else + { + ret = strcasecmp(strings[0], strings[1]); + result = g_literal_expression_new(EVT_BOOLEAN, (bool []) { ret == 0 }); + } + break; + + } + + exit: + + return result; + +} diff --git a/src/analysis/scan/exprs/str.h b/src/analysis/scan/exprs/str.h new file mode 100644 index 0000000..195f941 --- /dev/null +++ b/src/analysis/scan/exprs/str.h @@ -0,0 +1,67 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * str.h - prototypes pour la gestion des opérations booléennes + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_EXPRS_STR_H +#define _ANALYSIS_SCAN_EXPRS_STR_H + + +#include "../expr.h" + + + +#define G_TYPE_STRING_OPERATION g_string_operation_get_type() +#define G_STRING_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_STRING_OPERATION, GStringOperation)) +#define G_IS_STRING_OPERATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_STRING_OPERATION)) +#define G_STRING_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_STRING_OPERATION, GStringOperationClass)) +#define G_IS_STRING_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_STRING_OPERATION)) +#define G_STRING_OPERATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_STRING_OPERATION, GStringOperationClass)) + + +/* Opération booléenne avec un ou deux opérandes (instance) */ +typedef struct _GStringOperation GStringOperation; + +/* Opération booléenne avec un ou deux opérandes (classe) */ +typedef struct _GStringOperationClass GStringOperationClass; + + +/* Types d'opérations booléennes supportées */ +typedef enum _StringOperationType +{ + SOT_CONTAINS, /* Opérateurs "[i]contains" */ + SOT_STARTSWITH, /* Opérateurs "[i]startswith" */ + SOT_ENDSWITH, /* Opérateurs "[i]endswith" */ + SOT_MATCHES, /* Opérateur "matches" */ + SOT_IEQUALS, /* Opérateur "iequals" */ + +} StringOperationType; + + +/* Indique le type défini pour une opération traitant une chaîne de caractères. */ +GType g_string_operation_get_type(void); + +/* Organise un appel de fonction avec ses arguments. */ +GScanExpression *g_string_operation_new(StringOperationType, GScanExpression *, GScanExpression *, bool); + + + +#endif /* _ANALYSIS_SCAN_EXPRS_STR_H */ diff --git a/src/analysis/scan/func-int.h b/src/analysis/scan/func-int.h new file mode 100644 index 0000000..6591ba4 --- /dev/null +++ b/src/analysis/scan/func-int.h @@ -0,0 +1,51 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * func-int.h - prototypes internes pour la définition d'une fonction ciblant une propriété pendant un scan + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_FUNC_INT_H +#define _ANALYSIS_SCAN_FUNC_INT_H + + +#include "func.h" + + +#include "item-int.h" + + + +/* Fonction apportant un support d'analyse pendant un scan (instance) */ +struct _GScanFunction +{ + GRegisteredItem parent; /* A laisser en premier */ + +}; + +/* Fonction apportant un support d'analyse pendant un scan (classe) */ +struct _GScanFunctionClass +{ + GRegisteredItemClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _ANALYSIS_SCAN_FUNC_INT_H */ diff --git a/src/analysis/scan/func.c b/src/analysis/scan/func.c new file mode 100644 index 0000000..b839d1d --- /dev/null +++ b/src/analysis/scan/func.c @@ -0,0 +1,126 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * func.c - définition d'une fonction ciblant une propriété pendant un scan + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "func.h" + + +#include "func-int.h" + + + +/* Initialise la classe des fonctions de support pour scan. */ +static void g_scan_function_class_init(GScanFunctionClass *); + +/* Initialise une instance de fonction de support pour scan. */ +static void g_scan_function_init(GScanFunction *); + +/* Supprime toutes les références externes. */ +static void g_scan_function_dispose(GScanFunction *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_function_finalize(GScanFunction *); + + + +/* Indique le type défini pour une définition de fonction de scan. */ +G_DEFINE_TYPE(GScanFunction, g_scan_function, G_TYPE_REGISTERED_ITEM); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des fonctions de support pour scan. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_function_class_init(GScanFunctionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_function_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_function_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance à initialiser. * +* * +* Description : Initialise une instance de fonction de support pour scan. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_function_init(GScanFunction *func) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_function_dispose(GScanFunction *func) +{ + G_OBJECT_CLASS(g_scan_function_parent_class)->dispose(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_function_finalize(GScanFunction *func) +{ + G_OBJECT_CLASS(g_scan_function_parent_class)->finalize(G_OBJECT(func)); + +} diff --git a/src/analysis/scan/func.h b/src/analysis/scan/func.h new file mode 100644 index 0000000..bfc823a --- /dev/null +++ b/src/analysis/scan/func.h @@ -0,0 +1,52 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * func.h - prototypes pour la définition d'une fonction ciblant une propriété pendant un scan + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_FUNC_H +#define _ANALYSIS_SCAN_FUNC_H + + +#include <glib-object.h> + + + +#define G_TYPE_SCAN_FUNCTION g_scan_function_get_type() +#define G_SCAN_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_FUNCTION, GScanFunction)) +#define G_IS_SCAN_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_FUNCTION)) +#define G_SCAN_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_FUNCTION, GScanFunctionClass)) +#define G_IS_SCAN_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_FUNCTION)) +#define G_SCAN_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_FUNCTION, GScanFunctionClass)) + + +/* Fonction apportant un support d'analyse pendant un scan (instance) */ +typedef struct _GScanFunction GScanFunction; + +/* Fonction apportant un support d'analyse pendant un scan (classe) */ +typedef struct _GScanFunctionClass GScanFunctionClass; + + +/* Indique le type défini pour une définition de fonction de scan. */ +GType g_scan_function_get_type(void); + + + +#endif /* _ANALYSIS_SCAN_FUNC_H */ diff --git a/src/analysis/scan/funcs/Makefile.am b/src/analysis/scan/funcs/Makefile.am new file mode 100644 index 0000000..be370ba --- /dev/null +++ b/src/analysis/scan/funcs/Makefile.am @@ -0,0 +1,15 @@ + +noinst_LTLIBRARIES = libanalysisscanfuncs.la + + +libanalysisscanfuncs_la_SOURCES = \ + datasize.h datasize.c \ + uint-int.h \ + uint.h uint.c + +libanalysisscanfuncs_la_CFLAGS = $(LIBGOBJ_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libanalysisscanfuncs_la_SOURCES:%c=) diff --git a/src/analysis/scan/funcs/datasize.c b/src/analysis/scan/funcs/datasize.c new file mode 100644 index 0000000..7e63095 --- /dev/null +++ b/src/analysis/scan/funcs/datasize.c @@ -0,0 +1,214 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * datasize.c - récupération de la taille du contenu scanné + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "datasize.h" + + +#include "../func-int.h" +#include "../exprs/literal.h" + + + +/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */ + + +/* Initialise la classe des mesures de quantité de données. */ +static void g_datasize_function_class_init(GDatasizeFunctionClass *); + +/* Initialise une instance de mesure de quantité de données. */ +static void g_datasize_function_init(GDatasizeFunction *); + +/* Supprime toutes les références externes. */ +static void g_datasize_function_dispose(GDatasizeFunction *); + +/* Procède à la libération totale de la mémoire. */ +static void g_datasize_function_finalize(GDatasizeFunction *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réduit une expression à une forme plus simple. */ +static GScanExpression *g_datasize_function_reduce(GDatasizeFunction *, GScanContext *, GScanExpression **, size_t, bool); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE FONCTION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une mesure de quantité de données scannées. */ +G_DEFINE_TYPE(GDatasizeFunction, g_datasize_function, G_TYPE_SCAN_FUNCTION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des mesures de quantité de données. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_datasize_function_class_init(GDatasizeFunctionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GRegisteredItemClass *registered; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_datasize_function_dispose; + object->finalize = (GObjectFinalizeFunc)g_datasize_function_finalize; + + registered = G_REGISTERED_ITEM_CLASS(klass); + + registered->reduce = (reduce_registered_item_fc)g_datasize_function_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance à initialiser. * +* * +* Description : Initialise une instance de mesure de quantité de données. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_datasize_function_init(GDatasizeFunction *func) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_datasize_function_dispose(GDatasizeFunction *func) +{ + G_OBJECT_CLASS(g_datasize_function_parent_class)->dispose(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_datasize_function_finalize(GDatasizeFunction *func) +{ + G_OBJECT_CLASS(g_datasize_function_parent_class)->finalize(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Constitue une fonction de récupération de taille de données. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanFunction *g_datasize_function_new(void) +{ + GScanFunction *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_DATASIZE_FUNCTION, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : func = élément d'appel à consulter. * +* target = désignation de l'objet d'appel à identifier. * +* ctx = contexte de suivi de l'analyse courante. * +* args = liste d'éventuels arguments fournis. * +* count = taille de cette liste. * +* last = l'élément est-il le dernier d'une chaîne d'appels ? * +* final = indique une ultime conversion dans le cycle en cours.* +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GScanExpression *g_datasize_function_reduce(GDatasizeFunction *func, GScanContext *ctx, GScanExpression **args, size_t count, bool final) +{ + GScanExpression *result; /* Instance à renvoyer */ + GBinContent *content; /* Contenu à manipuler */ + phys_t size; /* Quantité de données liées */ + + content = g_scan_context_get_content(ctx); + + size = g_binary_content_compute_size(content); + + result = g_literal_expression_new(EVT_INTEGER, (unsigned long long []){ size }); + + g_object_unref(G_OBJECT(content)); + + return result; + +} diff --git a/src/analysis/scan/funcs/datasize.h b/src/analysis/scan/funcs/datasize.h new file mode 100644 index 0000000..bdd813d --- /dev/null +++ b/src/analysis/scan/funcs/datasize.h @@ -0,0 +1,55 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * datasize.h - prototypes pour la récupération de la taille du contenu scanné + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_FUNCS_DATASIZE_H +#define _ANALYSIS_SCAN_FUNCS_DATASIZE_H + + +#include "../func.h" + + + +#define G_TYPE_DATASIZE_FUNCTION g_datasize_function_get_type() +#define G_DATASIZE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_DATASIZE_FUNCTION, GDatasizeFunction)) +#define G_IS_DATASIZE_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_DATASIZE_FUNCTION)) +#define G_DATASIZE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DATASIZE_FUNCTION, GDatasizeFunctionClass)) +#define G_IS_DATASIZE_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DATASIZE_FUNCTION)) +#define G_DATASIZE_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DATASIZE_FUNCTION, GDatasizeFunctionClass)) + + +/* Mesure de la quantité de données scannées (instance) */ +typedef GScanFunction GDatasizeFunction; + +/* Mesure de la quantité de données scannées (classe) */ +typedef GScanFunctionClass GDatasizeFunctionClass; + + +/* Indique le type défini pour une mesure de quantité de données scannées. */ +GType g_datasize_function_get_type(void); + +/* Constitue une fonction de récupération de taille de données. */ +GScanFunction *g_datasize_function_new(void); + + + +#endif /* _ANALYSIS_SCAN_FUNCS_DATASIZE_H */ diff --git a/src/analysis/scan/funcs/uint-int.h b/src/analysis/scan/funcs/uint-int.h new file mode 100644 index 0000000..0817805 --- /dev/null +++ b/src/analysis/scan/funcs/uint-int.h @@ -0,0 +1,54 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * uint-int.h - prototypes internes pour la lecture d'un mot à partir de données binaires + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_FUNCS_UINT_INT_H +#define _ANALYSIS_SCAN_FUNCS_UINT_INT_H + + +#include "uint.h" + + +#include "../func-int.h" + + + +/* Fonction conduisant à la lecture d'un mot (instance) */ +struct _GUintFunction +{ + GScanFunction parent; /* A laisser en premier */ + + MemoryDataSize size; /* Taille du mot à lire */ + SourceEndian endian; /* Boutisme à respecter */ + +}; + +/* Fonction conduisant à la lecture d'un mot (classe) */ +struct _GUintFunctionClass +{ + GScanFunctionClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _ANALYSIS_SCAN_FUNCS_UINT_INT_H */ diff --git a/src/analysis/scan/funcs/uint.c b/src/analysis/scan/funcs/uint.c new file mode 100644 index 0000000..6421f52 --- /dev/null +++ b/src/analysis/scan/funcs/uint.c @@ -0,0 +1,266 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * uint.c - lecture d'un mot à partir de données binaires + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "uint.h" + + +#include "uint-int.h" +#include "../exprs/literal.h" + + + +/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */ + + +/* Initialise la classe des lectures de valeurs entières. */ +static void g_uint_function_class_init(GUintFunctionClass *); + +/* Initialise une instance de lecture de valeur entière. */ +static void g_uint_function_init(GUintFunction *); + +/* Supprime toutes les références externes. */ +static void g_uint_function_dispose(GUintFunction *); + +/* Procède à la libération totale de la mémoire. */ +static void g_uint_function_finalize(GUintFunction *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Réduit une expression à une forme plus simple. */ +static GScanExpression *g_uint_function_reduce(GUintFunction *, GScanContext *, GScanExpression **, size_t, bool); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTRODUCTION D'UNE NOUVELLE FONCTION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une lecture de mot à partir de données binaires. */ +G_DEFINE_TYPE(GUintFunction, g_uint_function, G_TYPE_SCAN_FUNCTION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des lectures de valeurs entières. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_uint_function_class_init(GUintFunctionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GRegisteredItemClass *registered; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_uint_function_dispose; + object->finalize = (GObjectFinalizeFunc)g_uint_function_finalize; + + registered = G_REGISTERED_ITEM_CLASS(klass); + + registered->reduce = (reduce_registered_item_fc)g_uint_function_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance à initialiser. * +* * +* Description : Initialise une instance de lecture de valeur entière. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_uint_function_init(GUintFunction *func) +{ + func->size = MDS_UNDEFINED; + func->endian = SRE_LITTLE; + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_uint_function_dispose(GUintFunction *func) +{ + G_OBJECT_CLASS(g_uint_function_parent_class)->dispose(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : func = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_uint_function_finalize(GUintFunction *func) +{ + G_OBJECT_CLASS(g_uint_function_parent_class)->finalize(G_OBJECT(func)); + +} + + +/****************************************************************************** +* * +* Paramètres : size = taille du mot à venir lire dans les données. * +* * +* Description : Constitue une fonction de lecture de valeur entière. * +* * +* Retour : Fonction mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanFunction *g_uint_function_new(MemoryDataSize size) +{ + GScanFunction *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_UINT_FUNCTION, NULL); + + G_UINT_FUNCTION(result)->size = size; + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : func = élément d'appel à consulter. * +* target = désignation de l'objet d'appel à identifier. * +* ctx = contexte de suivi de l'analyse courante. * +* args = liste d'éventuels arguments fournis. * +* count = taille de cette liste. * +* last = l'élément est-il le dernier d'une chaîne d'appels ? * +* final = indique une ultime conversion dans le cycle en cours.* +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GScanExpression *g_uint_function_reduce(GUintFunction *func, GScanContext *ctx, GScanExpression **args, size_t count, bool final) +{ + GScanExpression *result; /* Instance à renvoyer */ + unsigned long long offset; /* Position du mot ciblé */ + bool status; /* Bilan d'une opération */ + GBinContent *content; /* Contenu à manipuler */ + vmpa2t pos; /* Tête de lecture */ + uint8_t val_8; /* Valeur entière sur 8 bits */ + uint16_t val_16; /* Valeur entière sur 16 bits */ + uint32_t val_32; /* Valeur entière sur 32 bits */ + uint64_t val_64; /* Valeur entière sur 64 bits */ + + result = NULL; + + if (count == 1 && G_IS_LITERAL_EXPRESSION(args[0])) + { + status = g_literal_expression_get_integer_value(G_LITERAL_EXPRESSION(args[0]), &offset); + if (!status) goto exit; + + content = g_scan_context_get_content(ctx); + + g_binary_content_compute_start_pos(content, &pos); + advance_vmpa(&pos, offset); + + switch (func->size) + { + case MDS_8_BITS_UNSIGNED: + status = g_binary_content_read_u8(content, &pos, &val_8); + if (status) + result = g_literal_expression_new(EVT_INTEGER, (unsigned long long []){ val_8 }); + break; + + case MDS_16_BITS_UNSIGNED: + status = g_binary_content_read_u16(content, &pos, func->endian, &val_16); + if (status) + result = g_literal_expression_new(EVT_INTEGER, (unsigned long long []){ val_16 }); + break; + + case MDS_32_BITS_UNSIGNED: + status = g_binary_content_read_u32(content, &pos, func->endian, &val_32); + if (status) + result = g_literal_expression_new(EVT_INTEGER, (unsigned long long []){ val_32 }); + break; + + + case MDS_64_BITS_UNSIGNED: + status = g_binary_content_read_u64(content, &pos, func->endian, &val_64); + if (status) + result = g_literal_expression_new(EVT_INTEGER, (unsigned long long []){ val_64 }); + break; + + default: + break; + + } + + g_object_unref(G_OBJECT(content)); + + } + + exit: + + return result; + +} diff --git a/src/analysis/scan/funcs/uint.h b/src/analysis/scan/funcs/uint.h new file mode 100644 index 0000000..fe6cb52 --- /dev/null +++ b/src/analysis/scan/funcs/uint.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * uint.h - prototypes pour la lecture d'un mot à partir de données binaires + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_FUNCS_UINT_H +#define _ANALYSIS_SCAN_FUNCS_UINT_H + + +#include "../func.h" +#include "../../../arch/archbase.h" + + + +#define G_TYPE_UINT_FUNCTION g_uint_function_get_type() +#define G_UINT_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_UINT_FUNCTION, GUintFunction)) +#define G_IS_UINT_FUNCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_UINT_FUNCTION)) +#define G_UINT_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_UINT_FUNCTION, GUintFunctionClass)) +#define G_IS_UINT_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_UINT_FUNCTION)) +#define G_UINT_FUNCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_UINT_FUNCTION, GUintFunctionClass)) + + +/* Fonction conduisant à la lecture d'un mot (instance) */ +typedef struct _GUintFunction GUintFunction; + +/* Fonction conduisant à la lecture d'un mot (classe) */ +typedef struct _GUintFunctionClass GUintFunctionClass; + + +/* Indique le type défini pour une lecture de mot à partir de données binaires. */ +GType g_uint_function_get_type(void); + +/* Constitue une fonction de lecture de valeur entière. */ +GScanFunction *g_uint_function_new(MemoryDataSize); + + + +#endif /* _ANALYSIS_SCAN_FUNCS_UINT_H */ diff --git a/src/analysis/scan/grammar.y b/src/analysis/scan/grammar.y new file mode 100644 index 0000000..ab64ad8 --- /dev/null +++ b/src/analysis/scan/grammar.y @@ -0,0 +1,487 @@ + +%{ + +#include "decl.h" +#include "tokens.h" + + +/* 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 *); + +%} + + +%code requires { + +#define YY_TYPEDEF_YY_SCANNER_T +typedef void *yyscan_t; + +#include "scanner.h" +#include "conds/counter.h" +#include "exprs/arithmop.h" +#include "exprs/boolop.h" +#include "exprs/call.h" +#include "exprs/literal.h" +#include "exprs/str.h" +#include "exprs/relop.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 /////////////////////////////////////////////////////////////////////////// + +} + +%union { + + //char *string; /* Chaîne de caractères #1 */ + const char *cstring; /* Chaîne de caractères #2 */ + unsigned long long integer; /* Valeur entière */ + + struct { + const char *cstring; /* Chaîne de caractères #3 */ + size_t len; /* Taille correspondante */ + } sized_cstring; + + GScanRule *rule; /* Nouvelle règle à intégrer */ + void/*GBytesPattern*/ *pattern; /* Nouveau motif à considérer */ + GScanExpression *expr; /* Expression de condition */ + + struct { + GScanExpression **args; /* Liste d'arguments à fournir */ + size_t count; /* Quantité de ces arguments */ + } args_list; + +} + + +/** + * Cf. + * http://stackoverflow.com/questions/34418381/how-to-reference-lex-or-parse-parameters-in-flex-rules/34420950 + */ + +%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 } + +%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) + +YY_DECL; + +} + + +%token RAW_RULE +%token RULE_NAME + +%token STRINGS CONDITION +%token IDENTIFIER +%token NAME + +%token BRACE_IN BRACE_OUT ASSIGN COLON + + +%token RAW_BLOCK + +%token PLAIN_STRING +%token MASKED_STRING + +%token TRUE_ "true" +%token FALSE_ "false" +%token INTEGER +%token STRING + +%token KB MB GB + +%token AND "and" +%token OR "or" +%token NOT "not" + +%token LT "<" +%token LE "<=" +%token EQ "==" +%token NE "!=" +%token GT ">" +%token GE ">=" + +%token CONTAINS "contains" +%token STARTSWITH "startswith" +%token ENDSWITH "endswith" +%token MATCHES "matches" +%token ICONTAINS "icontains" +%token ISTARTSWITH "istartswith" +%token IENDSWITH "iendswith" +%token IEQUALS "iequals" + +%token PLUS "+" +%token MINUS "-" +%token MUL "*" +%token DIV "\\" +%token MOD "%" + +%token PAREN_O "(" +%token PAREN_C ")" +%token COMMA "," +%token DOT "." + +%token NONE "none" +%token ANY "any" +%token ALL "all" +%token OF "of" +%token THEM "them" + + +%type <cstring> RULE_NAME +%type <cstring> RAW_BLOCK + + +%type <sized_cstring> IDENTIFIER +%type <sized_cstring> NAME + + +%type <integer> INTEGER +%type <cstring> STRING + +%type <rule> rule + +%type <sized_cstring> PLAIN_STRING +%type <pattern> MASKED_STRING + +%type <expr> cexpression +%type <expr> literal +%type <expr> callable +%type <args_list> call_args +%type <expr> bool_expr +%type <expr> rel_expr +%type <expr> str_expr +%type <expr> arithm_expr +%type <expr> set_counter + + + +%left OR +%left AND +%left EQ NE +%left CONTAINS STARTSWITH ENDSWITH MATCHES ICONTAINS ISTARTSWITH IENDSWITH IEQUALS +%left LT LE GT GE +%left PLUS MINUS +%left MUL DIV MOD +%right NOT + + + + +%destructor { printf("-------- Discarding symbol %p.\n", $$); } <rule> + + +%% + + + + /* + + +<raw_block>[ \t\n]+ { } +<raw_block>"{" { + read_block(temp); + yylvalp->cstring = temp; return RAW_BLOCK; + } +<raw_block>"}" { yy_pop_state(); } + + */ + + +rules : /* empty */ + | rule rules { g_content_scanner_add_rule(scanner, $1); } + + //rule : RAW_RULE RULE_NAME { printf("RULE %s\n", $2); } RAW_BLOCK { printf("BLOCK: %s\n", $4); } + +rule : RAW_RULE RULE_NAME + { + *built_rule = g_scan_rule_new($2); + $<rule>$ = *built_rule; + } + BRACE_IN strings condition BRACE_OUT + { + $$ = $<rule>3; + //printf("RULE %s -> %p\n", $2, $$); + } + + + + +strings : /* empty */ + | STRINGS COLON string_decls + ; + + +string_decls : string_decl + | string_decls string_decl + ; + +string_decl : IDENTIFIER ASSIGN PLAIN_STRING + { + GSearchPattern *__pat; + __pat = g_plain_bytes_new((uint8_t *)$3.cstring, $3.len); + g_search_pattern_set_name(__pat, $1.cstring, $1.len); + g_scan_rule_add_local_variable(*built_rule, __pat); + g_object_unref(G_OBJECT(__pat)); + + /* + string_token_t *__token; + //printf("built plain %s\n", $3.cstring); + GBytesPattern *__pat; + __token = create_plain_string_token($3.cstring, $3.len); + printf("token: %p\n", __token); + __pat = g_bytes_pattern_new(); + g_bytes_pattern_append_string(__pat, $3.cstring, $3.len); + g_scan_rule_add_local_variable(*built_rule, $1, G_SEARCH_PATTERN(__pat)); + g_object_unref(G_OBJECT(__pat)); + */ + } + | IDENTIFIER ASSIGN MASKED_STRING + { + printf("built %p\n", $3); + /* + GBytesPattern *__pat; + __pat = g_bytes_pattern_new(); + g_search_pattern_set_name(__pat, $1.cstring, $1.len); + g_bytes_pattern_append_string(__pat, "\xd9\x74\x24\xf4", 4); + g_scan_rule_add_local_variable(*built_rule, G_SEARCH_PATTERN(__pat)); + */ + /* + GSearchPattern *__pat; + __pat = G_SEARCH_PATTERN($3); + if (g_search_pattern_prepare(__pat)) + g_scan_rule_add_local_variable(*built_rule, $1, __pat); + g_clear_object(built_pattern); + */ + } + ; + +condition : /* empty */ + | CONDITION COLON cexpression + { + g_scan_rule_set_match_condition(*built_rule, $3); + g_object_ref(G_OBJECT($3)); + } + ; + +cexpression : IDENTIFIER + { + printf("named var: %s\n", "$1"); + /* + 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; } + | callable { $$ = $1; } + | bool_expr { $$ = $1; } + | rel_expr { $$ = $1; } + | str_expr { $$ = $1; } + | arithm_expr { $$ = $1; } + | set_counter { $$ = $1; } + | "(" cexpression ")" { $$ = $2; } + ; + +literal : "true" { $$ = g_literal_expression_new(EVT_BOOLEAN, (bool []){ true }); } + | "false" { $$ = g_literal_expression_new(EVT_BOOLEAN, (bool []){ false }); } + | INTEGER { $$ = g_literal_expression_new(EVT_INTEGER, &$1); } + | INTEGER KB { $$ = g_literal_expression_new(EVT_INTEGER, (unsigned long long []){ $1 * 1024 }); } + | INTEGER MB { $$ = g_literal_expression_new(EVT_INTEGER, (unsigned long long []){ $1 * 1048576 }); } + | INTEGER GB { $$ = g_literal_expression_new(EVT_INTEGER, (unsigned long long []){ $1 * 1073741824 }); } + | STRING { $$ = g_literal_expression_new(EVT_STRING, $1); } + ; + +callable : NAME { $$ = g_pending_call_new($1.cstring, $1.len, NULL, 0); } + | NAME "(" ")" { $$ = g_pending_call_new($1.cstring, $1.len, NULL, 0); } + | NAME "(" call_args ")" + { + size_t __i; + $$ = g_pending_call_new($1.cstring, $1.len, $3.args, $3.count); + for (__i = 0; __i < $3.count; __i++) + g_object_unref(G_OBJECT($3.args[__i])); + free($3.args); + } + | callable "." NAME + { + GScanExpression *__next; + __next = g_pending_call_new($3.cstring, $3.len, NULL, 0); + g_pending_call_attach_next(G_PENDING_CALL($1), G_PENDING_CALL(__next)); + $$ = $1; + } + | callable "." NAME "(" ")" + { + GScanExpression *__next; + __next = g_pending_call_new($3.cstring, $3.len, NULL, 0); + g_pending_call_attach_next(G_PENDING_CALL($1), G_PENDING_CALL(__next)); + $$ = $1; + } + | callable "." NAME "(" call_args ")" + { + GScanExpression *__next; + size_t __i; + __next = g_pending_call_new($3.cstring, $3.len, $5.args, $5.count); + for (__i = 0; __i < $5.count; __i++) + g_object_unref(G_OBJECT($5.args[__i])); + free($5.args); + g_pending_call_attach_next(G_PENDING_CALL($1), G_PENDING_CALL(__next)); + $$ = $1; + } + ; + +call_args : cexpression + { + $$.count = 1; + $$.args = malloc(sizeof(GScanExpression *)); + $$.args[0] = $1; + } + | call_args "," cexpression + { + $1.count++; + $1.args = realloc($1.args, $1.count * sizeof(GScanExpression *)); + $1.args[$1.count - 1] = $3; + $$ = $1; + } + ; + +bool_expr : cexpression "and" cexpression { $$ = g_boolean_operation_new(BOT_AND, $1, $3); } + | cexpression "or" cexpression { $$ = g_boolean_operation_new(BOT_OR, $1, $3); } + | "not" "(" cexpression ")" { $$ = g_boolean_operation_new(BOT_NOT, $3, NULL); } + ; + +rel_expr : cexpression "<" cexpression { $$ = g_relational_operation_new(RCO_LT, $1, $3); } + | cexpression "<=" cexpression { $$ = g_relational_operation_new(RCO_LE, $1, $3); } + | cexpression "==" cexpression { $$ = g_relational_operation_new(RCO_EQ, $1, $3); } + | cexpression "!=" cexpression { $$ = g_relational_operation_new(RCO_NE, $1, $3); } + | cexpression ">" cexpression { $$ = g_relational_operation_new(RCO_GT, $1, $3); } + | cexpression ">=" cexpression { $$ = g_relational_operation_new(RCO_GT, $1, $3); } + ; + +str_expr : cexpression "contains" cexpression { $$ = g_string_operation_new(SOT_CONTAINS, $1, $3, true); } + | cexpression "startswith" cexpression { $$ = g_string_operation_new(SOT_STARTSWITH, $1, $3, true); } + | cexpression "endswith" cexpression { $$ = g_string_operation_new(SOT_ENDSWITH, $1, $3, true); } + | cexpression "matches" cexpression { $$ = g_string_operation_new(SOT_MATCHES, $1, $3, true); } + | cexpression "icontains" cexpression { $$ = g_string_operation_new(SOT_CONTAINS, $1, $3, false); } + | cexpression "istartswith" cexpression { $$ = g_string_operation_new(SOT_STARTSWITH, $1, $3, false); } + | cexpression "iendswith" cexpression { $$ = g_string_operation_new(SOT_ENDSWITH, $1, $3, false); } + | cexpression "iequals" cexpression { $$ = g_string_operation_new(SOT_IEQUALS, $1, $3, false); } + ; + +arithm_expr : cexpression "+" cexpression { $$ = g_arithmetic_operation_new(AEO_PLUS, $1, $3); } + | cexpression "-" cexpression { $$ = g_arithmetic_operation_new(AEO_MINUS, $1, $3); } + | cexpression "*" cexpression { $$ = g_arithmetic_operation_new(AEO_MUL, $1, $3); } + | cexpression "\\" cexpression { $$ = g_arithmetic_operation_new(AEO_DIV, $1, $3); } + | cexpression "%" cexpression { $$ = g_arithmetic_operation_new(AEO_MOD, $1, $3); } + ; + +set_counter : "none" "of" "them" { $$ = g_literal_expression_new(EVT_BOOLEAN, (bool []){ true }); } + | "any" "of" "them" { $$ = g_literal_expression_new(EVT_BOOLEAN, (bool []){ true }); } + | "all" "of" "them" { $$ = g_literal_expression_new(EVT_BOOLEAN, (bool []){ true }); } + ; + +%% + + +/****************************************************************************** +* * +* Paramètres : scanner = décodeur impliqué dans le processus. * +* temp = zone de travail à destination des lectures. * +* msg = message d'erreur. * +* * +* Description : Affiche un message d'erreur suite à l'analyse en échec. * +* * +* Retour : 0 * +* * +* Remarques : - * +* * +******************************************************************************/ + +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) +{ + printf("YYERROR line %d: %s\n", yyget_lineno(yyscanner), msg); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : scanner = chercheur de motifs à préparer. * +* text = définitions des règles à charger. * +* length = longueur de ces définitions. * +* * +* Description : Complète une recherche de motifs avec des règles. * +* * +* Retour : Bilan à retourner. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool process_rules_definitions(GContentScanner *scanner, const char *text, size_t length) +{ + bool result; /* Bilan à renvoyer */ + GScanRule *built_rule; /* Règle en construction */ + void /*GBytesPattern*/ *built_pattern; /* Motif en construction */ + char *buf; /* Zone de travail temporaire */ + size_t allocated; /* Taille de mémoire allouée */ + size_t used; /* Quantité utilisée */ + yyscan_t lexstate; /* Gestion d'analyse lexicale */ + YY_BUFFER_STATE state; /* Contexte d'analyse */ + int status; /* Bilan d'une analyse */ + + result = false; + + built_rule = NULL; + built_pattern = NULL; + + allocated = 256; + used = 0; + + buf = malloc(allocated * sizeof(char)); + buf[0] = '\0'; + + rost_lex_init(&lexstate); + + state = rost__scan_bytes(text, length, lexstate); + + status = yyparse(scanner, lexstate, &built_rule, &built_pattern, &buf, &allocated, &used); + + result = (status == EXIT_SUCCESS); + + yy_delete_buffer(state, lexstate); + + rost_lex_destroy(lexstate); + + free(buf); + + return result; + +} diff --git a/src/analysis/scan/item-int.h b/src/analysis/scan/item-int.h new file mode 100644 index 0000000..d1151f2 --- /dev/null +++ b/src/analysis/scan/item-int.h @@ -0,0 +1,61 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item-int.h - prototypes internes pour la définition d'un élément appelable lors de l'exécution d'une règle + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_ITEM_INT_H +#define _ANALYSIS_SCAN_ITEM_INT_H + + +#include "item.h" + + +#include <stdbool.h> + + + +/* Lance une résolution d'élément à appeler. */ +typedef GRegisteredItem * (* resolve_registered_item_fc) (GRegisteredItem *, const char *, GScanContext *, GScanExpression **, size_t, bool, bool); + +/* Réduit une expression à une forme plus simple. */ +typedef GScanExpression * (* reduce_registered_item_fc) (GRegisteredItem *, GScanContext *, GScanExpression **, size_t, bool); + + +/* Expression d'évaluation généraliste (instance) */ +struct _GRegisteredItem +{ + GObject parent; /* A laisser en premier */ + +}; + +/* Expression d'évaluation généraliste (classe) */ +struct _GRegisteredItemClass +{ + GObjectClass parent; /* A laisser en premier */ + + resolve_registered_item_fc resolve; /* Opération de résolution */ + reduce_registered_item_fc reduce; /* Opération de réduction */ + +}; + + + +#endif /* _ANALYSIS_SCAN_ITEM_INT_H */ diff --git a/src/analysis/scan/item.c b/src/analysis/scan/item.c new file mode 100644 index 0000000..c0b1532 --- /dev/null +++ b/src/analysis/scan/item.c @@ -0,0 +1,199 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item.c - définition d'un élément appelable lors de l'exécution d'une règle + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "item.h" + + +#include "item-int.h" + + + +/* ----------------------- BASES D'OBJET POUR LE SYSTEME GLIB ----------------------- */ + + +/* Initialise la classe des éléments appelables enregistrés. */ +static void g_registered_item_class_init(GRegisteredItemClass *); + +/* Initialise une instance d'élément appelable enregistré. */ +static void g_registered_item_init(GRegisteredItem *); + +/* Supprime toutes les références externes. */ +static void g_registered_item_dispose(GRegisteredItem *); + +/* Procède à la libération totale de la mémoire. */ +static void g_registered_item_finalize(GRegisteredItem *); + + + +/* ---------------------------------------------------------------------------------- */ +/* BASES D'OBJET POUR LE SYSTEME GLIB */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un élément appelable et enregistré. */ +G_DEFINE_TYPE(GRegisteredItem, g_registered_item, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des éléments appelables enregistrés. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_registered_item_class_init(GRegisteredItemClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_registered_item_dispose; + object->finalize = (GObjectFinalizeFunc)g_registered_item_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : item = instance à initialiser. * +* * +* Description : Initialise une instance d'élément appelable enregistré. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_registered_item_init(GRegisteredItem *item) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : item = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_registered_item_dispose(GRegisteredItem *item) +{ + G_OBJECT_CLASS(g_registered_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_registered_item_finalize(GRegisteredItem *item) +{ + G_OBJECT_CLASS(g_registered_item_parent_class)->finalize(G_OBJECT(item)); + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* target = désignation de l'objet d'appel à identifier. * +* ctx = contexte de suivi de l'analyse courante. * +* args = liste d'éventuels arguments fournis. * +* count = taille de cette liste. * +* last = l'élément est-il le dernier d'une chaîne d'appels ? * +* final = indique une ultime conversion dans le cycle en cours.* +* * +* Description : Lance une résolution d'élément à appeler. * +* * +* Retour : Nouvel élément d'appel identifié ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GRegisteredItem *g_registered_item_resolve(GRegisteredItem *item, const char *target, GScanContext *ctx, GScanExpression **args, size_t count, bool last, bool final) +{ + GRegisteredItem *result; /* Instance à renvoyer */ + GRegisteredItemClass *class; /* Classe à activer */ + + class = G_REGISTERED_ITEM_GET_CLASS(item); + + if (class->resolve == NULL) + result = NULL; + else + result = class->resolve(item, target, ctx, args, count, last, final); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* args = liste d'éventuels arguments fournis. * +* count = taille de cette liste. * +* final = indique une ultime conversion dans le cycle en cours.* +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_registered_item_reduce(GRegisteredItem *item, GScanContext *ctx, GScanExpression **args, size_t count, bool final) +{ + GScanExpression *result; /* Instance à renvoyer */ + GRegisteredItemClass *class; /* Classe à activer */ + + class = G_REGISTERED_ITEM_GET_CLASS(item); + + result = class->reduce(item, ctx, args, count, final); + + return result; + +} diff --git a/src/analysis/scan/item.h b/src/analysis/scan/item.h new file mode 100644 index 0000000..e3e02e6 --- /dev/null +++ b/src/analysis/scan/item.h @@ -0,0 +1,63 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item.h - prototypes pour la définition d'un élément appelable lors de l'exécution d'une règle + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_ITEM_H +#define _ANALYSIS_SCAN_ITEM_H + + +#include <glib-object.h> +#include <stdbool.h> + + +#include "context.h" +#include "expr.h" + + + +#define G_TYPE_REGISTERED_ITEM g_registered_item_get_type() +#define G_REGISTERED_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_REGISTERED_ITEM, GRegisteredItem)) +#define G_IS_REGISTERED_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_REGISTERED_ITEM)) +#define G_REGISTERED_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_REGISTERED_ITEM, GRegisteredItemClass)) +#define G_IS_REGISTERED_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_REGISTERED_ITEM)) +#define G_REGISTERED_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_REGISTERED_ITEM, GRegisteredItemClass)) + + +/* Expression d'évaluation généraliste (instance) */ +typedef struct _GRegisteredItem GRegisteredItem; + +/* Expression d'évaluation généraliste (classe) */ +typedef struct _GRegisteredItemClass GRegisteredItemClass; + + +/* Indique le type défini pour un élément appelable et enregistré. */ +GType g_registered_item_get_type(void); + +/* Lance une résolution d'élément à appeler. */ +GRegisteredItem *g_registered_item_resolve(GRegisteredItem *, const char *, GScanContext *, GScanExpression **, size_t, bool, bool); + +/* Réduit une expression à une forme plus simple. */ +GScanExpression *g_registered_item_reduce(GRegisteredItem *, GScanContext *, GScanExpression **, size_t, bool); + + + +#endif /* _ANALYSIS_SCAN_ITEM_H */ diff --git a/src/analysis/scan/match-int.h b/src/analysis/scan/match-int.h new file mode 100644 index 0000000..9030d75 --- /dev/null +++ b/src/analysis/scan/match-int.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * match-int.h - prototypes internes pour la sauvegarde d'une correspondance identifiée de motif + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_MATCH_INT_H +#define _ANALYSIS_SCAN_MATCH_INT_H + + +#include "match.h" + + + +/* Affiche une correspondance sur la sortie standard. */ +typedef void (* display_scan_match_fc) (const GScanMatch *); + + +/* Correspondance trouvée avec un motif (instance) */ +struct _GScanMatch +{ + GObject parent; /* A laisser en premier */ + + GSearchPattern *source; /* Motif d'origine recherché */ + +}; + +/* Correspondance trouvée avec un motif (classe) */ +struct _GScanMatchClass +{ + GObjectClass parent; /* A laisser en premier */ + + display_scan_match_fc display; /* Impression des résultats */ + +}; + + + +#endif /* _ANALYSIS_SCAN_MATCH_INT_H */ diff --git a/src/analysis/scan/match.c b/src/analysis/scan/match.c new file mode 100644 index 0000000..c7e2a78 --- /dev/null +++ b/src/analysis/scan/match.c @@ -0,0 +1,177 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * match.c - sauvegarde d'une correspondance identifiée de motif + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "match.h" + + +#include "match-int.h" + + + +/* Initialise la classe des correspondances de motifs. */ +static void g_scan_match_class_init(GScanMatchClass *); + +/* Initialise une instance de correspondance de motif trouvée. */ +static void g_scan_match_init(GScanMatch *); + +/* Supprime toutes les références externes. */ +static void g_scan_match_dispose(GScanMatch *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_match_finalize(GScanMatch *); + + + +/* Indique le type défini pour un correspondance de motif identifiée. */ +G_DEFINE_TYPE(GScanMatch, g_scan_match, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des correspondances de motifs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_match_class_init(GScanMatchClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_match_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_match_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : match = instance à initialiser. * +* * +* Description : Initialise une instance de correspondance de motif trouvée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_match_init(GScanMatch *match) +{ + match->source = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : match = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_match_dispose(GScanMatch *match) +{ + g_clear_object(&match->source); + + G_OBJECT_CLASS(g_scan_match_parent_class)->dispose(G_OBJECT(match)); + +} + + +/****************************************************************************** +* * +* Paramètres : match = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_match_finalize(GScanMatch *match) +{ + G_OBJECT_CLASS(g_scan_match_parent_class)->finalize(G_OBJECT(match)); + +} + + +/****************************************************************************** +* * +* Paramètres : match = définition de correspondance à consulter. * +* * +* Description : Indique la source du motif d'origine recherché. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +GSearchPattern *g_scan_match_get_source(const GScanMatch *match) +{ + GSearchPattern *result; /* Source à retourner */ + + result = match->source; + + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : match = définition de correspondance à manipuler. * +* * +* Description : Affiche une correspondance sur la sortie standard. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_match_display(const GScanMatch *match) +{ + GScanMatchClass *class; /* Classe à activer */ + + class = G_SCAN_MATCH_GET_CLASS(match); + + class->display(match); + +} diff --git a/src/analysis/scan/match.h b/src/analysis/scan/match.h new file mode 100644 index 0000000..0990ae0 --- /dev/null +++ b/src/analysis/scan/match.h @@ -0,0 +1,61 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * match.h - prototypes pour la sauvegarde d'une correspondance identifiée de motif + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_MATCH_H +#define _ANALYSIS_SCAN_MATCH_H + + +#include <glib-object.h> + + +#include "pattern.h" + + + +#define G_TYPE_SCAN_MATCH g_scan_match_get_type() +#define G_SCAN_MATCH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MATCH, GScanMatch)) +#define G_IS_SCAN_MATCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MATCH)) +#define G_SCAN_MATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MATCH, GScanMatchClass)) +#define G_IS_SCAN_MATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MATCH)) +#define G_SCAN_MATCH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MATCH, GScanMatchClass)) + + +/* Correspondance trouvée avec un motif (instance) */ +typedef struct _GScanMatch GScanMatch; + +/* Correspondance trouvée avec un motif (classe) */ +typedef struct _GScanMatchClass GScanMatchClass; + + +/* Indique le type défini pour un correspondance de motif identifiée. */ +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 *); + + + +#endif /* _ANALYSIS_SCAN_MATCH_H */ diff --git a/src/analysis/scan/matches/Makefile.am b/src/analysis/scan/matches/Makefile.am new file mode 100644 index 0000000..d6b51c6 --- /dev/null +++ b/src/analysis/scan/matches/Makefile.am @@ -0,0 +1,15 @@ + +noinst_LTLIBRARIES = libanalysisscanmatches.la + + +libanalysisscanmatches_la_SOURCES = \ + bytes-int.h \ + bytes.h bytes.c \ + pending.h pending.c + +libanalysisscanmatches_la_CFLAGS = $(LIBGOBJ_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libanalysisscanmatches_la_SOURCES:%c=) diff --git a/src/analysis/scan/matches/bytes-int.h b/src/analysis/scan/matches/bytes-int.h new file mode 100644 index 0000000..c983aa3 --- /dev/null +++ b/src/analysis/scan/matches/bytes-int.h @@ -0,0 +1,60 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bytes-int.h - prototypes internes pour la sauvegarde d'une correspondance identifiée de suite d'octets + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_MATCHES_BYTES_INT_H +#define _ANALYSIS_SCAN_MATCHES_BYTES_INT_H + + +#include "bytes.h" + + +#include "../match-int.h" + + + +/* Correspondance trouvée avec une chaîne (instance) */ +struct _GBytesMatch +{ + GScanMatch parent; /* A laisser en premier */ + + GBinContent *content; /* Contenu binaire de référence*/ + + phys_t start; /* Début du motif représenté */ + phys_t len; /* Taille du motif représenté */ + +}; + +/* Correspondance trouvée avec une chaîne (classe) */ +struct _GBytesMatchClass +{ + GScanMatchClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une correspondance trouvée avec un motif. */ +bool g_bytes_match_create(GBytesMatch *, GSearchPattern *, GBinContent *, phys_t, phys_t); + + + +#endif /* _ANALYSIS_SCAN_MATCHES_BYTES_INT_H */ diff --git a/src/analysis/scan/matches/bytes.c b/src/analysis/scan/matches/bytes.c new file mode 100644 index 0000000..90fa27d --- /dev/null +++ b/src/analysis/scan/matches/bytes.c @@ -0,0 +1,286 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bytes.h - sauvegarde d'une correspondance identifiée de suite d'octets + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "bytes.h" + + +#include <ctype.h> + + +#include "bytes-int.h" + + + +/* --------------------- CORRESPONDANCE AVEC UNE SUITE D'OCTETS --------------------- */ + + +/* Initialise la classe des correspondances de chaînes. */ +static void g_bytes_match_class_init(GBytesMatchClass *); + +/* Initialise une instance de correspondance de chaîne trouvée. */ +static void g_bytes_match_init(GBytesMatch *); + +/* Supprime toutes les références externes. */ +static void g_bytes_match_dispose(GBytesMatch *); + +/* Procède à la libération totale de la mémoire. */ +static void g_bytes_match_finalize(GBytesMatch *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Affiche une correspondance sur la sortie standard. */ +static void g_bytes_match_display(const GBytesMatch *); + + + +/* ---------------------------------------------------------------------------------- */ +/* CORRESPONDANCE AVEC UNE SUITE D'OCTETS */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un correspondance de chaîne identifiée. */ +G_DEFINE_TYPE(GBytesMatch, g_bytes_match, G_TYPE_SCAN_MATCH); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des correspondances de chaînes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_bytes_match_class_init(GBytesMatchClass *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; + + match = G_SCAN_MATCH_CLASS(klass); + + match->display = (display_scan_match_fc)g_bytes_match_display; + +} + + +/****************************************************************************** +* * +* Paramètres : match = instance à initialiser. * +* * +* Description : Initialise une instance de correspondance de chaîne trouvée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_bytes_match_init(GBytesMatch *match) +{ + match->content = NULL; + + match->start = VMPA_NO_PHYSICAL; + match->len = VMPA_NO_PHYSICAL; + +} + + +/****************************************************************************** +* * +* Paramètres : match = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_bytes_match_dispose(GBytesMatch *match) +{ + g_clear_object(&match->content); + + G_OBJECT_CLASS(g_bytes_match_parent_class)->dispose(G_OBJECT(match)); + +} + + +/****************************************************************************** +* * +* Paramètres : match = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_bytes_match_finalize(GBytesMatch *match) +{ + G_OBJECT_CLASS(g_bytes_match_parent_class)->finalize(G_OBJECT(match)); + +} + + +/****************************************************************************** +* * +* Paramètres : source = lien vers le motif recherché d'origine. * +* content = contenu binaire présentant un motif reconnu. * +* start = position de départ d'un motif détecté. * +* len = taille du motif repéré. * +* * +* Description : Prend note d'une correspondance trouvée avec un motif. * +* * +* Retour : Correspondance mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanMatch *g_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); + + if (!g_bytes_match_create(G_BYTES_MATCH(result), source, content, start, len)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : match = instance à initialiser pleinement. * +* source = lien vers le motif recherché d'origine. * +* content = contenu binaire présentant un motif reconnu. * +* start = position de départ d'un motif détecté. * +* len = taille du motif repéré. * +* * +* Description : Met en place une correspondance trouvée avec un motif. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_bytes_match_create(GBytesMatch *match, GSearchPattern *source, GBinContent *content, phys_t start, phys_t len) +{ + bool result; /* Bilan à retourner */ + GScanMatch *base; /* Lien vers les infos de base */ + + result = true; + + base = G_SCAN_MATCH(match); + + base->source = source; + g_object_ref(G_OBJECT(source)); + + match->content = content; + g_object_ref(G_OBJECT(content)); + + match->start = start; + match->len = len; + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : match = définition de correspondance à manipuler. * +* * +* Description : Affiche une correspondance sur la sortie standard. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_bytes_match_display(const GBytesMatch *match) +{ + 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 */ + + /* Affichage d'un repère */ + + base = G_SCAN_MATCH(match); + + name = g_search_pattern_get_name(base->source); + + /** + * Les fonctionnalités Yara d'origine autorisent les variables anonymes '$'. + * + * Cette absence de nom est supportée ici. + */ + + if (name == NULL) + name = ""; + + printf("0x%llx:$%s: ", (unsigned long long)match->start, name); + + /* Affichage du contenu */ + + 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++) + { + if (isprint(data[i])) + printf("%c", data[i]); + else + printf("\\x%02hhx", data[i]); + } + + printf("\n"); + +} diff --git a/src/analysis/scan/matches/bytes.h b/src/analysis/scan/matches/bytes.h new file mode 100644 index 0000000..22e76a6 --- /dev/null +++ b/src/analysis/scan/matches/bytes.h @@ -0,0 +1,59 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bytes.h - prototypes pour la sauvegarde d'une correspondance identifiée de suite d'octets + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_MATCHES_BYTES_H +#define _ANALYSIS_SCAN_MATCHES_BYTES_H + + +#include <glib-object.h> + + +#include "../match.h" +#include "../../content.h" + + + +#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)) + + +/* Correspondance trouvée avec une chaîne (instance) */ +typedef struct _GBytesMatch GBytesMatch; + +/* Correspondance trouvée avec une chaîne (classe) */ +typedef struct _GBytesMatchClass GBytesMatchClass; + + +/* Indique le type défini pour un correspondance de chaîne identifiée. */ +GType g_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); + + + +#endif /* _ANALYSIS_SCAN_MATCHES_BYTES_H */ diff --git a/src/analysis/scan/matches/pending.c b/src/analysis/scan/matches/pending.c new file mode 100644 index 0000000..700b868 --- /dev/null +++ b/src/analysis/scan/matches/pending.c @@ -0,0 +1,202 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * pending.c - consolidation de correspondances partielles + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "pending.h" + + +#include <assert.h> +#include <malloc.h> +#include <string.h> + + +#define PENDING_ALLOC_SIZE 10 + + + +/****************************************************************************** +* * +* Paramètres : matches = suivi de correspondances à initialiser. * +* * +* Description : Initialise une structure de consolidation de correspondances.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void init_pending_matches(pending_matches_t *matches) +{ + matches->areas = NULL; + matches->allocated = 0; + matches->used = 0; + + matches->initialized = false; + +} + + +/****************************************************************************** +* * +* Paramètres : matches = suivi de correspondances à purger. * +* * +* Description : Libère la mémoire utilisée par une consolidation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void exit_pending_matches(pending_matches_t *matches) +{ + if (matches->areas != NULL) + free(matches->areas); + +} + + +/****************************************************************************** +* * +* 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. * +* * +* Retour : Bilan de l'opération : true en cas de succès des recherches. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool find_target_in_pending_matches(pending_matches_t *matches, phys_t start, size_t *target) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + match_area_t *area; /* Zone à initialiser */ + + assert(mindex <= matches->used); + + result = false; + + for (i = *target; i < matches->used; i++) + { + area = &matches->areas[i]; + + if ((area->start + area->length) == start) + { + *target = i; + result = true; + break; + } + + } + + return result; + +} + + + +/****************************************************************************** +* * +* Paramètres : matches = suivi de correspondances à compléter. * +* start = point de départ d'une nouvelle correspondance. * +* length = taille de la zone couverte. * +* * +* Description : Ajoute au suivi la définition d'une nouvelle correspondance. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void add_pending_matches(pending_matches_t *matches, phys_t start, phys_t length) +{ + match_area_t *area; /* Zone à initialiser */ + + if (matches->used == matches->allocated) + { + matches->allocated += PENDING_ALLOC_SIZE; + + matches->areas = realloc(matches->areas, matches->allocated * sizeof(match_area_t)); + + } + + area = &matches->areas[matches->used++]; + + area->start = start; + area->length = length; + +} + + +/****************************************************************************** +* * +* Paramètres : matches = suivi de correspondances à compléter. * +* target = indice de la zone de correspondance concernée. * +* length = taille de la zone couverte supplémentaire. * +* * +* Description : Etend une zone couverte dans le suivi des correspondances. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void extend_pending_matches(pending_matches_t *matches, size_t target, phys_t length) +{ + assert(target < matches->used); + + matches->areas[target].length += length; + +} + + +/****************************************************************************** +* * +* Paramètres : matches = suivi de correspondances à modifier. * +* target = indice de la zone de correspondance concernée. * +* * +* Description : Retire une correspondance finalement non établie du suivi. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void remove_pending_matches(pending_matches_t *matches, size_t target) +{ + 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)); + + matches->used--; + +} diff --git a/src/analysis/scan/matches/pending.h b/src/analysis/scan/matches/pending.h new file mode 100644 index 0000000..de2fd5f --- /dev/null +++ b/src/analysis/scan/matches/pending.h @@ -0,0 +1,76 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * pending.h - prototypes pour la consolidation de correspondances partielles + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_MATCHES_PENDING_H +#define _ANALYSIS_SCAN_MATCHES_PENDING_H + + +#include "../../content.h" + + + +/* Couverture d'une correspondance */ +typedef struct _match_area_t +{ + phys_t start; /* Point de départ */ + phys_t length; /* Taille de la zone couverte */ + +} match_area_t; + +/* Suivi de correspondances */ +typedef struct _pending_matches_t +{ + match_area_t *areas; /* Zones couvertes */ + size_t allocated; /* Nombre d'allocations */ + size_t used; /* Nombre de zones */ + + bool initialized; /* Etat du suivi */ + +} pending_matches_t; + + +/* Initialise une structure de consolidation de correspondances. */ +void init_pending_matches(pending_matches_t *); + +/* Libère la mémoire utilisée par une consolidation. */ +void exit_pending_matches(pending_matches_t *); + +#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 *); + +/* Ajoute au suivi la définition d'une nouvelle correspondance. */ +void add_pending_matches(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); + +/* Retire une correspondance finalement non établie du suivi. */ +void remove_pending_matches(pending_matches_t *, size_t); + + + +#endif /* _ANALYSIS_SCAN_MATCHES_PENDING_H */ diff --git a/src/analysis/scan/options-int.h b/src/analysis/scan/options-int.h new file mode 100644 index 0000000..a7772ed --- /dev/null +++ b/src/analysis/scan/options-int.h @@ -0,0 +1,52 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * options-int.h - prototypes internes pour le rassemblement des options d'analyse communiquées par le donneur d'ordre + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_OPTIONS_INT_H +#define _ANALYSIS_SCAN_OPTIONS_INT_H + + +#include "options.h" + + + +/* Rassemblement d'options d'analyses (instance) */ +struct _GScanOptions +{ + GObject parent; /* A laisser en premier */ + + GType data_backend; /* Choix du moteur d'analyse */ + + bool print_stats; /* Affichage de statistiques ? */ + +}; + +/* Rassemblement d'options d'analyses (classe) */ +struct _GScanOptionsClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _ANALYSIS_SCAN_OPTIONS_INT_H */ diff --git a/src/analysis/scan/options.c b/src/analysis/scan/options.c new file mode 100644 index 0000000..89e411e --- /dev/null +++ b/src/analysis/scan/options.c @@ -0,0 +1,238 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * options.c - rassemblement des options d'analyse communiquées par le donneur d'ordre + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "options.h" + + +#include "options-int.h" + + + +/* Initialise la classe des ensembles d'options d'analyses. */ +static void g_scan_options_class_init(GScanOptionsClass *); + +/* Initialise une instance de groupe d'options d'analyse. */ +static void g_scan_options_init(GScanOptions *); + +/* Supprime toutes les références externes. */ +static void g_scan_options_dispose(GScanOptions *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_options_finalize(GScanOptions *); + + + +/* Indique le type défini pour un ensemble d'options d'analyses. */ +G_DEFINE_TYPE(GScanOptions, g_scan_options, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des ensembles d'options d'analyses. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_options_class_init(GScanOptionsClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_options_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_options_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : options = instance à initialiser. * +* * +* Description : Initialise une instance de groupe d'options d'analyse. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_options_init(GScanOptions *options) +{ + options->data_backend = G_TYPE_INVALID; + + options->print_stats = false; + +} + + +/****************************************************************************** +* * +* Paramètres : options = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_options_dispose(GScanOptions *options) +{ + G_OBJECT_CLASS(g_scan_options_parent_class)->dispose(G_OBJECT(options)); + +} + + +/****************************************************************************** +* * +* Paramètres : options = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_options_finalize(GScanOptions *options) +{ + G_OBJECT_CLASS(g_scan_options_parent_class)->finalize(G_OBJECT(options)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée un réceptacle pour diverses options d'analyse. * +* * +* Retour : Point de collecte mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanOptions *g_scan_options_new(void) +{ + GScanOptions *result; /* Instance à retourner */ + + result = g_object_new(G_TYPE_SCAN_OPTIONS, NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : options = ensemble d'options d'analyses à consulter. * +* * +* Description : Indique le type d'un moteur d'analyse de données sélectionné.* +* * +* Retour : Type d'objet, idéalement valide. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GType g_scan_options_get_backend_for_data(const GScanOptions *options) +{ + GType result; /* Type à retourner */ + + result = options->data_backend; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : options = ensemble d'options d'analyses à modifier. * +* backend = type du moteur sélectionné. * +* * +* Description : Sélectionne un type de moteur d'analyse pour données brutes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_options_set_backend_for_data(GScanOptions *options, GType backend) +{ + options->data_backend = backend; + +} + + +/****************************************************************************** +* * +* 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é. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_options_get_print_stats(const GScanOptions *options) +{ + bool result; /* Statut à retourner */ + + result = options->print_stats; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : options = ensemble d'options d'analyses à modifier. * +* state = état de l'option visée à conserver. * +* * +* Description : Mémorise un besoin de statistiques en fin de compilation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_options_set_print_stats(GScanOptions *options, bool state) +{ + options->print_stats = state; + +} diff --git a/src/analysis/scan/options.h b/src/analysis/scan/options.h new file mode 100644 index 0000000..a7931c5 --- /dev/null +++ b/src/analysis/scan/options.h @@ -0,0 +1,68 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * options.h - prototypes pour le rassemblement des options d'analyse communiquées par le donneur d'ordre + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_OPTIONS_H +#define _ANALYSIS_SCAN_OPTIONS_H + + +#include <glib-object.h> +#include <stdbool.h> + + + +#define G_TYPE_SCAN_OPTIONS g_scan_options_get_type() +#define G_SCAN_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_OPTIONS, GScanOptions)) +#define G_IS_SCAN_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_OPTIONS)) +#define G_SCAN_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_OPTIONS, GScanOptionsClass)) +#define G_IS_SCAN_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_OPTIONS)) +#define G_SCAN_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_OPTIONS, GScanOptionsClass)) + + +/* Rassemblement d'options d'analyses (instance) */ +typedef struct _GScanOptions GScanOptions; + +/* Rassemblement d'options d'analyses (classe) */ +typedef struct _GScanOptionsClass GScanOptionsClass; + + +/* Indique le type défini pour un ensemble d'options d'analyses. */ +GType g_scan_options_get_type(void); + +/* Crée un réceptacle pour diverses options d'analyse. */ +GScanOptions *g_scan_options_new(void); + +/* Indique le type d'un moteur d'analyse de données sélectionné. */ +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); + +/* Indique un besoin de statistiques en fin de compilation. */ +bool g_scan_options_get_print_stats(const GScanOptions *); + +/* Mémorise un besoin de statistiques en fin de compilation. */ +void g_scan_options_set_print_stats(GScanOptions *, bool); + + + +#endif /* _ANALYSIS_SCAN_OPTIONS_H */ diff --git a/src/analysis/scan/pattern-int.h b/src/analysis/scan/pattern-int.h new file mode 100644 index 0000000..03af30f --- /dev/null +++ b/src/analysis/scan/pattern-int.h @@ -0,0 +1,56 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * pattern-int.h - prototypes internes pour la définition de motif à rechercher + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERN_INT_H +#define _ANALYSIS_SCAN_PATTERN_INT_H + + +#include "pattern.h" + + + +/* Décompte le nombre de correspondances identifiées. */ +typedef size_t (* count_pattern_matchs_fc) (const GSearchPattern *); + + +/* Motif à rechercher au sein d'un contenu (instance) */ +struct _GSearchPattern +{ + GObject parent; /* A laisser en premier */ + + char *name; /* Eventuelle désignation */ + +}; + +/* Motif à rechercher au sein d'un contenu (classe) */ +struct _GSearchPatternClass +{ + GObjectClass parent; /* A laisser en premier */ + + count_pattern_matchs_fc count; /* Décompte des résultats */ + +}; + + + +#endif /* _ANALYSIS_SCAN_PATTERN_INT_H */ diff --git a/src/analysis/scan/pattern.c b/src/analysis/scan/pattern.c new file mode 100644 index 0000000..53a2662 --- /dev/null +++ b/src/analysis/scan/pattern.c @@ -0,0 +1,210 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * pattern.c - définition de motif à localiser dans du contenu binaire + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "pattern.h" + + +#include <malloc.h> +#include <string.h> + + +#include "pattern-int.h" + + + +/* Initialise la classe des motifs à localiser dans du binaire. */ +static void g_search_pattern_class_init(GSearchPatternClass *); + +/* Initialise une instance de motif à localiser dans du binaire. */ +static void g_search_pattern_init(GSearchPattern *); + +/* Supprime toutes les références externes. */ +static void g_search_pattern_dispose(GSearchPattern *); + +/* Procède à la libération totale de la mémoire. */ +static void g_search_pattern_finalize(GSearchPattern *); + + + +/* Indique le type défini pour un motif à localiser. */ +G_DEFINE_TYPE(GSearchPattern, g_search_pattern, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des motifs à localiser dans du binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_search_pattern_class_init(GSearchPatternClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_search_pattern_dispose; + object->finalize = (GObjectFinalizeFunc)g_search_pattern_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : pattern = instance à initialiser. * +* * +* Description : Initialise une instance de motif à localiser dans du binaire.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_search_pattern_init(GSearchPattern *pattern) +{ + pattern->name = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : pattern = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_search_pattern_dispose(GSearchPattern *pattern) +{ + G_OBJECT_CLASS(g_search_pattern_parent_class)->dispose(G_OBJECT(pattern)); + +} + + +/****************************************************************************** +* * +* Paramètres : pattern = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_search_pattern_finalize(GSearchPattern *pattern) +{ + if (pattern->name != NULL) + free(pattern->name); + + G_OBJECT_CLASS(g_search_pattern_parent_class)->finalize(G_OBJECT(pattern)); + +} + + +/****************************************************************************** +* * +* Paramètres : pattern = définition de motif à consulter. * +* * +* Description : Fournit la désignation attribuée à un motif de recherche. * +* * +* Retour : Eventuelle étiquette associée ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_search_pattern_get_name(const GSearchPattern *pattern) +{ + char *result; /* Désignation à retourner */ + + result = pattern->name; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : pattern = définition de motif à consulter. * +* name = désignation en tant que variable locale. * +* len = taille de cette désignation. * +* * +* Description : Inscrit la désignation attribuée à un motif de recherche. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_search_pattern_set_name(GSearchPattern *pattern, const char *name, size_t len) +{ + if (pattern->name != NULL) + free(pattern->name); + + if (name == NULL) + pattern->name = NULL; + else + pattern->name = strndup(name, len); + +} + + +/****************************************************************************** +* * +* Paramètres : pattern = définition de motif à consulter. * +* * +* Description : Décompte le nombre de correspondances identifiées. * +* * +* Retour : Quantité d'identifications réalisées. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_search_pattern_count_matchs(const GSearchPattern *pattern) +{ + size_t result; /* Décompte à retourner */ + GSearchPatternClass *class; /* Classe à activer */ + + class = G_SEARCH_PATTERN_GET_CLASS(pattern); + + result = 0;//class->count(pattern); + + return result; + +} diff --git a/src/analysis/scan/pattern.h b/src/analysis/scan/pattern.h new file mode 100644 index 0000000..9ea66d3 --- /dev/null +++ b/src/analysis/scan/pattern.h @@ -0,0 +1,65 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * pattern.h - prototypes pour la définition de motif à localiser dans du contenu binaire + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERN_H +#define _ANALYSIS_SCAN_PATTERN_H + + +#include <glib-object.h> + + +#include "../../arch/archbase.h" +#include "../../arch/vmpa.h" + + + +#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)) +#define G_SEARCH_PATTERN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SEARCH_PATTERN, GSearchPatternClass)) +#define G_IS_SEARCH_PATTERN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SEARCH_PATTERN)) +#define G_SEARCH_PATTERN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SEARCH_PATTERN, GSearchPatternClass)) + + +/* Motif à rechercher au sein d'un contenu (instance) */ +typedef struct _GSearchPattern GSearchPattern; + +/* Motif à rechercher au sein d'un contenu (classe) */ +typedef struct _GSearchPatternClass GSearchPatternClass; + + +/* Indique le type défini pour un motif à localiser. */ +GType g_search_pattern_get_type(void); + +/* Fournit la désignation attribuée à un motif de recherche. */ +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 *); + + + +#endif /* _ANALYSIS_SCAN_PATTERN_H */ diff --git a/src/analysis/scan/patterns/Makefile.am b/src/analysis/scan/patterns/Makefile.am new file mode 100644 index 0000000..4082275 --- /dev/null +++ b/src/analysis/scan/patterns/Makefile.am @@ -0,0 +1,23 @@ + +noinst_LTLIBRARIES = libanalysisscanpatterns.la + + +libanalysisscanpatterns_la_SOURCES = \ + backend-int.h \ + backend.h backend.c \ + token-int.h \ + token.h token.c + +libanalysisscanpatterns_la_LIBADD = \ + backends/libanalysisscanpatternsbackends.la \ + tokens/libanalysisscanpatternstokens.la + +libanalysisscanpatterns_la_CFLAGS = $(LIBGOBJ_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libanalysisscanpatterns_la_SOURCES:%c=) + + +SUBDIRS = backends tokens diff --git a/src/analysis/scan/patterns/backend-int.h b/src/analysis/scan/patterns/backend-int.h new file mode 100644 index 0000000..698ba5f --- /dev/null +++ b/src/analysis/scan/patterns/backend-int.h @@ -0,0 +1,70 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * backend-int.h - prototypes internes pour une méthode de recherches au sein d'un contenu binaire + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_BACKEND_INT_H +#define _ANALYSIS_SCAN_PATTERNS_BACKEND_INT_H + + +#include "backend.h" + + + +/* Indique la taille maximale des suites d'octets recherchées. */ +typedef size_t (* get_backend_atom_max_size_fc) (const GEngineBackend *); + +/* Inscrit dans le moteur une chaîne de caractères à rechercher. */ +typedef patid_t (* enroll_plain_into_backend_fc) (GEngineBackend *, GScanContext *, const uint8_t *, size_t); + +/* Met en ordre les derniers détails avant un premier scan. */ +typedef void (* warm_up_backend_fc) (GEngineBackend *); + +/* Parcours un contenu binaire à la recherche de motifs. */ +typedef void (* run_backend_scan_fc) (const GEngineBackend *, GScanContext *, GBinContent *); + +/* Imprime quelques faits quant aux éléments mis en place. */ +typedef void (* output_backend_stats_fc) (const GEngineBackend *); + + +/* Méthode de traitement d'un contenu binaire pour recherches (instance) */ +struct _GEngineBackend +{ + GObject parent; /* A laisser en premier */ + +}; + +/* Méthode de traitement d'un contenu binaire pour recherches (classe) */ +struct _GEngineBackendClass +{ + GObjectClass parent; /* A laisser en premier */ + + get_backend_atom_max_size_fc get_max_size; /* Taille maximale d'atome */ + enroll_plain_into_backend_fc enroll_plain; /* Inscription simple */ + warm_up_backend_fc warm_up; /* Préchauffage avant analyse */ + run_backend_scan_fc run_scan; /* Lancement d'une analyse */ + output_backend_stats_fc output; /* Impression de statistiques */ + +}; + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_BACKEND_INT_H */ diff --git a/src/analysis/scan/patterns/backend.c b/src/analysis/scan/patterns/backend.c new file mode 100644 index 0000000..800d0aa --- /dev/null +++ b/src/analysis/scan/patterns/backend.c @@ -0,0 +1,254 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * backend.c - méthode de recherches au sein d'un contenu binaire + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "backend.h" + + +#include "backend-int.h" + + + +/* Initialise la classe des méthodes de recherche pour binaire. */ +static void g_engine_backend_class_init(GEngineBackendClass *); + +/* Initialise une instance de méthode de recherche pour binaire. */ +static void g_engine_backend_init(GEngineBackend *); + +/* Supprime toutes les références externes. */ +static void g_engine_backend_dispose(GEngineBackend *); + +/* Procède à la libération totale de la mémoire. */ +static void g_engine_backend_finalize(GEngineBackend *); + + + +/* Indique le type défini pour une méthode de recherche dans du binaire. */ +G_DEFINE_TYPE(GEngineBackend, g_engine_backend, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des méthodes de recherche pour binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_engine_backend_class_init(GEngineBackendClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_engine_backend_dispose; + object->finalize = (GObjectFinalizeFunc)g_engine_backend_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : backend = instance à initialiser. * +* * +* Description : Initialise une instance de méthode de recherche pour binaire.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_engine_backend_init(GEngineBackend *backend) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : backend = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_engine_backend_dispose(GEngineBackend *backend) +{ + G_OBJECT_CLASS(g_engine_backend_parent_class)->dispose(G_OBJECT(backend)); + +} + + +/****************************************************************************** +* * +* Paramètres : backend = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_engine_backend_finalize(GEngineBackend *backend) +{ + G_OBJECT_CLASS(g_engine_backend_parent_class)->finalize(G_OBJECT(backend)); + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à consulter. * +* * +* Description : Indique la taille maximale des suites d'octets recherchées. * +* * +* Retour : Valeur strictement positive. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_engine_backend_get_atom_max_size(const GEngineBackend *backend) +{ + size_t result; /* Taille à faire connaître */ + GEngineBackendClass *class; /* Classe à activer */ + + class = G_ENGINE_BACKEND_GET_CLASS(backend); + + result = class->get_max_size(backend); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à manipuler. * +* context = contexte de l'analyse à mener. * +* plain = chaîne de caractères classique à intégrer. * +* len = taille de cette chaîne. * +* * +* Description : Inscrit dans le moteur une chaîne de caractères à rechercher.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +patid_t g_engine_backend_enroll_plain_pattern(GEngineBackend *backend, GScanContext *context, const uint8_t *plain, size_t len) +{ + patid_t result; /* Identifiant à retourner */ + GEngineBackendClass *class; /* Classe à activer */ + + class = G_ENGINE_BACKEND_GET_CLASS(backend); + + result = class->enroll_plain(backend, context, plain, len); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à préparer. * +* * +* Description : Met en ordre les derniers détails avant un premier scan. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_engine_backend_warm_up(GEngineBackend *backend) +{ + GEngineBackendClass *class; /* Classe à activer */ + + class = G_ENGINE_BACKEND_GET_CLASS(backend); + + if (class->warm_up != NULL) + class->warm_up(backend); + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à manipuler. * +* context = lieu d'enregistrement des résultats. * +* content = données binaires à analyser. * +* * +* Description : Parcours un contenu binaire à la recherche de motifs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_engine_backend_run_scan(const GEngineBackend *backend, GScanContext *context, GBinContent *content) +{ + GEngineBackendClass *class; /* Classe à activer */ + + class = G_ENGINE_BACKEND_GET_CLASS(backend); + + class->run_scan(backend, context, content); + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à consulter. * +* * +* Description : Imprime quelques faits quant aux éléments mis en place. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_engine_backend_output_stats(const GEngineBackend *backend) +{ + GEngineBackendClass *class; /* Classe à activer */ + + class = G_ENGINE_BACKEND_GET_CLASS(backend); + + if (class->output != NULL) + class->output(backend); + +} diff --git a/src/analysis/scan/patterns/backend.h b/src/analysis/scan/patterns/backend.h new file mode 100644 index 0000000..700366e --- /dev/null +++ b/src/analysis/scan/patterns/backend.h @@ -0,0 +1,73 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * backend.h - prototypes pour une méthode de recherches au sein d'un contenu binaire + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_BACKEND_H +#define _ANALYSIS_SCAN_PATTERNS_BACKEND_H + + +#include <glib-object.h> +#include <stdbool.h> +#include <stdint.h> + + +#include "../context.h" +#include "../../content.h" + + + +#define G_TYPE_ENGINE_BACKEND g_engine_backend_get_type() +#define G_ENGINE_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ENGINE_BACKEND, GEngineBackend)) +#define G_IS_ENGINE_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ENGINE_BACKEND)) +#define G_ENGINE_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ENGINE_BACKEND, GEngineBackendClass)) +#define G_IS_ENGINE_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ENGINE_BACKEND)) +#define G_ENGINE_BACKEND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ENGINE_BACKEND, GEngineBackendClass)) + + +/* Méthode de traitement d'un contenu binaire pour recherches (instance) */ +typedef struct _GEngineBackend GEngineBackend; + +/* Méthode de traitement d'un contenu binaire pour recherches (classe) */ +typedef struct _GEngineBackendClass GEngineBackendClass; + + +/* Indique le type défini pour une méthode de recherche dans du binaire. */ +GType g_engine_backend_get_type(void); + +/* Indique la taille maximale des suites d'octets recherchées. */ +size_t g_engine_backend_get_atom_max_size(const GEngineBackend *); + +/* Inscrit dans le moteur une chaîne de caractères à rechercher. */ +patid_t g_engine_backend_enroll_plain_pattern(GEngineBackend *, GScanContext *, const uint8_t *, size_t); + +/* Met en ordre les derniers détails avant un premier scan. */ +void g_engine_backend_warm_up(GEngineBackend *); + +/* Parcours un contenu binaire à la recherche de motifs. */ +void g_engine_backend_run_scan(const GEngineBackend *, GScanContext *, GBinContent *); + +/* Imprime quelques faits quant aux éléments mis en place. */ +void g_engine_backend_output_stats(const GEngineBackend *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_BACKEND_H */ diff --git a/src/analysis/scan/patterns/backends/Makefile.am b/src/analysis/scan/patterns/backends/Makefile.am new file mode 100644 index 0000000..672b7ff --- /dev/null +++ b/src/analysis/scan/patterns/backends/Makefile.am @@ -0,0 +1,27 @@ + +noinst_LTLIBRARIES = libanalysisscanpatternsbackends.la + + +libanalysisscanpatternsbackends_la_SOURCES = \ + acism-int.h \ + acism.h acism.c \ + bitap-int.h \ + bitap.h bitap.c + +# Cf. https://www.gnu.org/software/automake/manual/html_node/Per_002dObject-Flags.html + +AM_CFLAGS = $(LIBGOBJ_CFLAGS) + + + +#AM_CFLAGS:=$(filter-out -O2,$(AM_CFLAGS)) + + +#bitap.lo: AM_CFLAGS += -Ofast -march=native -falign-functions=1 -falign-jumps=1 -falign-loops=1 -falign-labels=1 #-mavx512bw +#bitap.lo: AM_CFLAGS += -O3 -march=native -falign-functions=1 -falign-jumps=1 -falign-loops=1 -falign-labels=1 #-mavx512bw +bitap.lo: AM_CFLAGS += -g -march=native -mno-vzeroupper -falign-functions=1 -falign-jumps=1 -falign-loops=1 -falign-labels=1 + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libanalysisscanpatternsbackends_la_SOURCES:%c=) diff --git a/src/analysis/scan/patterns/backends/acism-int.h b/src/analysis/scan/patterns/backends/acism-int.h new file mode 100644 index 0000000..57c3c73 --- /dev/null +++ b/src/analysis/scan/patterns/backends/acism-int.h @@ -0,0 +1,160 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * acism-int.h - prototypes internes pour la méthode de recherche basée sur l'algorithme Aho-Corasick Interleaved State-transition Matrix + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_INT_H +#define _ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_INT_H + + +#include "acism.h" + + +#include <stdint.h> + + +#include "../backend-int.h" +#include "../../../../common/bits.h" + + + +//#define __USE_BYTE_FREQ +//#define __SORT_BEFORE_BITMASK + + +#define ACSIM_ATOM_SIZE 7 + + + +/* Définition d'une portion de cible */ +typedef struct _acism_source_t +{ + const uint8_t *atoms; /* Motif remarquable */ + size_t len; /* Nombre d'octets considérés */ + + patid_t pid; /* Identifiant de suivi */ + +} acism_source_t; + +/* Etude de la fréquence des octets pour attribution des codes */ +typedef struct _acism_freq_rank_t +{ + unsigned int frequency; /* Occurrences d'un octet */ + uint8_t rank; /* Valeur dudit octet */ + +} acism_freq_rank_t; + +/* Identifiant unique pour une valeur 8 bits donnée (max 257) */ +typedef uint16_t acism_code_t; + +#define MIN_ACISM_CODE 0 +#define MAX_ACISM_CODE 0xffff + +/* Noeud de l'arborescence brute */ +typedef struct _acism_trie_node_t +{ + struct _acism_trie_node_t *parent; /* Noeud parent pour remontée */ + struct _acism_trie_node_t *sibling; /* Noeud de même niveau suivant*/ + struct _acism_trie_node_t *child; /* Noeud de lecture suivant */ + struct _acism_trie_node_t *suffix_link; /* Retour en cas d'échec */ + + bin_t data; /* Donnée brute représentée */ + acism_code_t code; /* Identifiant du noeud */ + + patid_t pid; /* Identifiant de suivi */ + + acism_code_t min_child_code; /* Plus petit code suivant */ + acism_code_t max_child_code; /* Plus grand code suivant */ + size_t children_count; /* Nombre de codes suivants */ + + size_t matched_atom; /* Indice de correspondance */ + + size_t state_index; /* Indice de le tableau final */ + +} acism_trie_node_t; + +/* Cellule du tableau compressé final */ +typedef union _acism_state_t +{ + uint32_t raw; /* Valeur brute */ + + struct + { + union + { + /* Indice 0 */ + struct + { + unsigned int match : 1; /* Correspondance ici */ + unsigned int suffix : 1; /* Correspondance ailleurs */ + unsigned int unused : 4; /* Espace encore disponible */ + unsigned int atom_size : 3; /* Taille d'atome représenté */ + }; + + /* Indice 1 et + */ + unsigned int code : 9; /* Position depuis la base */ + + }; + + unsigned int index : 23; /* Indice de saut */ + + }; + +} acism_state_t; + +/* Méthode de recherche basée sur l'algorithme Acism (instance) */ +struct _GAcismBackend +{ + GEngineBackend parent; /* A laisser en premier */ + +#ifdef __USE_BYTE_FREQ + acism_code_t codes_for_bytes[256]; /* Traduction octets -> codes */ + acism_code_t codes_count; /* Quantité de traductions */ +#endif + + acism_source_t *sources; /* Liste de motifs remarquables*/ + size_t sources_count; /* Quantité de ces motifs */ + + size_t nchars; /* Taille cumulée des motifs */ + +#ifdef __USE_BYTE_FREQ + acism_freq_rank_t frequencies[256]; /* Fréquences des octets */ +#endif + + acism_trie_node_t *nodes; /* Liste de noeuds */ + size_t nodes_used; /* Nombre de noeuds utilisés */ + + bitfield_t *bitmap_usage; /* Localisation des usages */ + acism_state_t *states; /* Tableau de transitions */ + patid_t *pids; /* Identifiants de motifs */ + +}; + +/* Méthode de recherche basée sur l'algorithme Acism (classe) */ +struct _GAcismBackendClass +{ + GEngineBackendClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_INT_H */ diff --git a/src/analysis/scan/patterns/backends/acism.c b/src/analysis/scan/patterns/backends/acism.c new file mode 100644 index 0000000..12339f2 --- /dev/null +++ b/src/analysis/scan/patterns/backends/acism.c @@ -0,0 +1,1295 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * acism.c - méthode de recherche basée sur l'algorithme Aho-Corasick Interleaved State-transition Matrix + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "acism.h" + + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + + +#include "acism-int.h" +#include "../../../../common/sort.h" + + + +/* ---------------------- IMPLANTATION D'UNE NOUVELLE APPROCHE ---------------------- */ + + +/* Initialise la classe des méthodes basée sur Bitmap. */ +static void g_acism_backend_class_init(GAcismBackendClass *); + +/* Initialise une instance de méthodes basée sur Bitmap. */ +static void g_acism_backend_init(GAcismBackend *); + +/* Supprime toutes les références externes. */ +static void g_acism_backend_dispose(GAcismBackend *); + +/* Procède à la libération totale de la mémoire. */ +static void g_acism_backend_finalize(GAcismBackend *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Indique la taille maximale des suites d'octets recherchées. */ +size_t g_acism_backend_get_atom_max_size(const GAcismBackend *); + +/* Intègre un motif limité de contenu à rechercher. */ +static patid_t g_acism_backend_setup_for(GAcismBackend *, GScanContext *, const uint8_t *, size_t); + +/* Inscrit dans le moteur une chaîne de caractères à rechercher. */ +static patid_t g_acism_backend_enroll_plain_pattern(GAcismBackend *, GScanContext *, const uint8_t *, size_t); + +#ifdef __USE_BYTE_FREQ + +/* Compare un niveau de fréquence avec un autre. */ +static int compare_byte_frequencies(const acism_freq_rank_t *, const acism_freq_rank_t *); + +/* Détermine les identifiants de chaque valeur 8 bits utile. */ +static void g_acism_backend_define_codes(GAcismBackend *); + +#endif + +/* Construit l'arborescence de noeuds de lecture. */ +static void g_acism_backend_build_trie(GAcismBackend *); + +/* Construit l'arborescence de noeuds de lecture. */ +static void g_acism_backend_build_suffix_links(GAcismBackend *); + +#ifdef __SORT_BEFORE_BITMASK + +/* Compare des noeuds selon l'espace de codes couvert. */ +static int compare_node_according_to_code_range(const acism_trie_node_t **, const acism_trie_node_t **); + +#endif + +/* Organise la convertion de l'arborescence en tableau. */ +static void g_acism_backend_prepare_interleave_array(GAcismBackend *); + +/* Compresse l'arborescence dans un tableau de position. */ +static void g_acism_backend_build_interleave_array(GAcismBackend *); + +/* Met en ordre les derniers détails avant un premier scan. */ +static void g_acism_backend_warm_up(GAcismBackend *); + +/* Parcours un contenu binaire à la recherche de motifs. */ +static void g_acism_backend_run_scan(const GAcismBackend *, GScanContext *, GBinContent *); + +/* Affiche les caractéristques d'un noeud et de ses enfants. */ +static void visit_and_output_node(const acism_trie_node_t *, unsigned int); + +/* Imprime quelques faits quant aux éléments mis en place. */ +static void g_acism_backend_output_stats(const GAcismBackend *); + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLANTATION D'UNE NOUVELLE APPROCHE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un moteur de recherche pour données. */ +G_DEFINE_TYPE(GAcismBackend, g_acism_backend, G_TYPE_ENGINE_BACKEND); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des méthodes basée sur Bitmap. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_acism_backend_class_init(GAcismBackendClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GEngineBackendClass *backend; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_acism_backend_dispose; + object->finalize = (GObjectFinalizeFunc)g_acism_backend_finalize; + + backend = G_ENGINE_BACKEND_CLASS(klass); + + backend->get_max_size = (get_backend_atom_max_size_fc)g_acism_backend_get_atom_max_size; + backend->enroll_plain = (enroll_plain_into_backend_fc)g_acism_backend_enroll_plain_pattern; + backend->warm_up = (warm_up_backend_fc)g_acism_backend_warm_up; + backend->run_scan = (run_backend_scan_fc)g_acism_backend_run_scan; + backend->output = (output_backend_stats_fc)g_acism_backend_output_stats; + +} + + +/****************************************************************************** +* * +* Paramètres : backend = instance à initialiser. * +* * +* Description : Initialise une instance de méthodes basée sur Bitmap. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_acism_backend_init(GAcismBackend *backend) +{ +#ifdef __USE_BYTE_FREQ + size_t i; /* Boucle de parcours #1 */ + acism_freq_rank_t *iter; /* Boucle de parcours #2 */ +#endif + +#ifdef __USE_BYTE_FREQ + memset(backend->codes_for_bytes, 0, 256 * sizeof(acism_code_t)); +#endif + + backend->nchars = 0; + +#ifdef __USE_BYTE_FREQ + for (i = 0, iter = backend->frequencies; i < 256; i++, iter++) + { + iter->frequency = 0; + iter->rank = i; + } +#endif + +} + + +/****************************************************************************** +* * +* Paramètres : backend = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_acism_backend_dispose(GAcismBackend *backend) +{ + G_OBJECT_CLASS(g_acism_backend_parent_class)->dispose(G_OBJECT(backend)); + +} + + +/****************************************************************************** +* * +* Paramètres : backend = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_acism_backend_finalize(GAcismBackend *backend) +{ + G_OBJECT_CLASS(g_acism_backend_parent_class)->finalize(G_OBJECT(backend)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée une méthode de recherche basée sur l'algorithme Acism. * +* * +* Retour : Méthode mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GEngineBackend *g_acism_backend_new(void) +{ + GAcismBackend *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_ACISM_BACKEND, NULL); + + return G_ENGINE_BACKEND(result); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à consulter. * +* * +* Description : Indique la taille maximale des suites d'octets recherchées. * +* * +* Retour : Valeur strictement positive. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_acism_backend_get_atom_max_size(const GAcismBackend *backend) +{ + size_t result; /* Taille à faire connaître */ + + result = ACSIM_ATOM_SIZE; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à préparer. * +* context = contexte de l'analyse à mener. * +* plain = chaîne de caractères classique à intégrer. * +* len = taille de cette chaîne. * +* * +* Description : Intègre un motif limité de contenu à rechercher. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static patid_t g_acism_backend_setup_for(GAcismBackend *backend, GScanContext *context, const uint8_t *pattern, size_t len) +{ + patid_t result; /* Identifiant à retourner */ + size_t i; /* Boucle de parcours */ + int ret; /* Bilan d'une comparaison */ + acism_source_t *source; /* Définition à mémoriser */ + + result = INVALID_PATTERN_ID; + + /*Recherche d'un motif déjà sollicité */ + + /** + * '\x00\x00\x00\x00abcd1234' '\x01\x01\x01\x01abcd1234' peuvent en effet + * constituer deux cibles différentes, mais elles comportent normalement + * la même séquence atomique à rechercher : 'abcd1234'. + */ + + for (i = 0; i < backend->sources_count; i++) + { + source = backend->sources + i; + + if (source->len != len) + continue; + + ret = memcmp(source->atoms, pattern, len); + + if (ret == 0) + { + result = source->pid; + break; + } + + } + + /* Introduction d'un nouveau motif au besoin */ + + if (result == INVALID_PATTERN_ID) + { + backend->sources = realloc(backend->sources, ++backend->sources_count * sizeof(acism_source_t)); + + source = &backend->sources[backend->sources_count - 1]; + + source->atoms = pattern; + source->len = len; + + result = g_scan_context_get_new_pattern_id(context); + source->pid = result; + + backend->nchars += len; + +#ifdef __USE_BYTE_FREQ + for (i = 0; i < len; i++) + backend->frequencies[pattern[i]].frequency++; +#endif + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à manipuler. * +* context = contexte de l'analyse à mener. * +* plain = chaîne de caractères classique à intégrer. * +* len = taille de cette chaîne. * +* * +* Description : Inscrit dans le moteur une chaîne de caractères à rechercher.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static patid_t g_acism_backend_enroll_plain_pattern(GAcismBackend *backend, GScanContext *context, const uint8_t *plain, size_t len) +{ + patid_t result; /* Identifiant à retourner */ + + assert(len <= ACSIM_ATOM_SIZE); + + /** + * Le traitement différé des chaînes à rechercher permet deux choses : + * - la construction d'une table de permutation ; + * - le décompte des noeuds à allouer (en une seule fois). + * + * Si l'intention du premier point est louable (densifier les champs de bits + * pour allouer moins et tenir plus facilement dans le cache du CPU), la + * permetutation est extrèmement coûteuse pendant la phase de scan + * (une lecture supplémentaire par octet de données scannées). + * + * Le second point reste valable (à priori). + * + * L'appel à la fonction g_acism_backend_setup_for() demeure donc, et l'arbre + * est construit dans un second temps. La distinction de cette fonction avec + * la procédure d'enrôlement permet potentiellement d'étuer une bascule à + * moindre coût un jour. + */ + + result = g_acism_backend_setup_for(backend, context, plain, len); + + return result; + +} + + +#ifdef __USE_BYTE_FREQ + + +/****************************************************************************** +* * +* Paramètres : a = premier élément à comparer. * +* b = second élément à comparer. * +* * +* Description : Compare un niveau de fréquence avec un autre. * +* * +* Retour : Bilan de la comparaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int compare_byte_frequencies(const acism_freq_rank_t *a, const acism_freq_rank_t *b) +{ + int result; /* Bilan à retourner */ + + /** + * Afin d'obtenir les plus grosses fréquences en premier, + * l'ordre de comparaison est inversé : b < a ? + */ + + result = sort_unsigned_long(b->frequency, a->frequency); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à préparer. * +* * +* Description : Détermine les identifiants de chaque valeur 8 bits utile. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_acism_backend_define_codes(GAcismBackend *backend) +{ + size_t i; /* Boucle de parcours #1 */ + acism_freq_rank_t *iter; /* Boucle de parcours #2 */ + + /** + * La redistribution des valeurs d'octet va permettre de compacter + * par la suite les masques de cellules utilisées pour construire + * le plus petit tableau des états. + * + * L'idée est de grouper le plus possible les états (représentés + * par un indice) autour de l'état 0. + */ + + qsort(backend->frequencies, 256, sizeof(acism_freq_rank_t), (__compar_fn_t)compare_byte_frequencies); + + /* 0 == racine */ + backend->codes_count++; + +#if 0 + for (i = 0, iter = backend->frequencies; i < 256; i++, iter++) + { + if (iter->frequency == 0) + break; + + backend->codes_for_bytes[iter->rank] = backend->codes_count++; + + } +#else + for (i = 0; i < 256; i++) + backend->codes_for_bytes[i] = backend->codes_count++; +#endif + +} + + +#endif + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à préparer. * +* * +* Description : Construit l'arborescence de noeuds de lecture. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_acism_backend_build_trie(GAcismBackend *backend) +{ + size_t i; /* Boucle de parcours #1 */ + acism_trie_node_t *next; /* Prochain noeud disponible */ + acism_trie_node_t *node; /* Tête de parcours */ + acism_source_t *source; /* Définition à mémoriser */ + size_t k; /* Boucle de parcours #2 */ + acism_code_t code; /* Identifiant de symbole */ + acism_trie_node_t *parent; /* Sauvegarde d'un accès */ + + backend->nodes = calloc(backend->nchars + 1, sizeof(acism_trie_node_t)); + + for (i = 0; i < (backend->nchars + 1); i++) + { + backend->nodes[i].min_child_code = MAX_ACISM_CODE; + backend->nodes[i].max_child_code = MIN_ACISM_CODE; + } + + next = backend->nodes + 1; + + for (i = 0; i < backend->sources_count; i++) + { + node = backend->nodes; + + source = &backend->sources[i]; + + for (k = 0; k < source->len && node->child != NULL; k++) + { +#ifdef __USE_BYTE_FREQ + code = backend->codes_for_bytes[source->atoms[k]]; +#else + code = 1 + source->atoms[k]; +#endif + + /* Insertion d'un nouveau noeud au début des enfants */ + if (code < node->child->code) + { + next->parent = node; + next->suffix_link = node; + next->data = source->atoms[k]; + next->code = code; + + next->sibling = node->child; + node->child = next++; + + if (code < node->min_child_code) node->min_child_code = code; + if (code > node->max_child_code) node->max_child_code = code; + node->children_count++; + + node = node->child; + + k++; + break; + + } + + parent = node; + + /* Recherche du point d'insertion idéal */ + for (node = node->child; + node->sibling != NULL && code >= node->sibling->code; + node = node->sibling); + + /* Si le noeud idéal n'existe pas, insertion ordonnée */ + if (code > node->code) + { + next->parent = parent; + next->suffix_link = parent; + next->data = source->atoms[k]; + next->code = code; + + next->sibling = node->sibling; + node->sibling = next++; + + if (code < parent->min_child_code) parent->min_child_code = code; + if (code > parent->max_child_code) parent->max_child_code = code; + parent->children_count++; + + node = node->sibling; + + k++; + break; + + } + + } + + /* Creéation d'une nouvelle branche avec le reliquat */ + for (; k < source->len; k++) + { +#ifdef __USE_BYTE_FREQ + code = backend->codes_for_bytes[source->atoms[k]]; +#else + code = 1 + source->atoms[k]; +#endif + + next->parent = node; + next->suffix_link = node; + next->data = source->atoms[k]; + next->code = code; + + node->child = next++; + + if (code < node->min_child_code) node->min_child_code = code; + if (code > node->max_child_code) node->max_child_code = code; + node->children_count++; + + node = node->child; + + } + + node->matched_atom = i + 1; + + } + + backend->nodes_used = next - backend->nodes; + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à préparer. * +* * +* Description : Construit l'arborescence de noeuds de lecture. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_acism_backend_build_suffix_links(GAcismBackend *backend) +{ + size_t max_pos; /* Tête de lecture finale */ + acism_trie_node_t **stack; /* Pile des noeuds à traiter */ + size_t rd_pos; /* Tête de lecture */ + size_t wr_pos; /* Tête d'écriture */ + acism_trie_node_t *node; /* Noeud à traiter */ + acism_trie_node_t *parent; /* Noeud parent de la chaîne */ + acism_trie_node_t *iter; /* Boucle de parcours */ + + max_pos = backend->nodes_used; + + stack = calloc(max_pos, sizeof(acism_trie_node_t *)); + + /* Initialisation du parcours */ + + rd_pos = 0; + wr_pos = 0; + + stack[wr_pos++] = &backend->nodes[0]; + + assert(backend->nodes->sibling == NULL); + + /* Traitement manuel de démarrage pour éviter une condition en [0] */ + + for (iter = backend->nodes->child; iter != NULL; iter = iter->sibling) + stack[wr_pos++] = iter; + + rd_pos++; + + /* Suivi des liens déjà en place */ + + while (rd_pos < max_pos) + { + assert(rd_pos < wr_pos); + + node = stack[rd_pos++]; + + /* Remontée jusqu'à la découverte d'un lien d'intérêt */ + + for (parent = node->suffix_link; parent != NULL; parent = parent->suffix_link) + { + for (iter = parent->child; iter != NULL; iter = iter->sibling) + if (iter->code == node->code && iter != node) + { + node->suffix_link = iter; + break; + } + + if (iter != NULL) + break; + + } + + if (parent == NULL /* && node != &backend->nodes [0] */) + node->suffix_link = backend->nodes; + + /* Inscription des noeuds suivants */ + + for (iter = node->child; iter != NULL; iter = iter->sibling) + stack[wr_pos++] = iter; + + } + + /* Sortie propre */ + + free(stack); + +} + + +#ifdef __SORT_BEFORE_BITMASK + + +/****************************************************************************** +* * +* Paramètres : a = premier élément à comparer. * +* b = second élément à comparer. * +* * +* Description : Compare des noeuds selon l'espace de codes couvert. * +* * +* Retour : Bilan de la comparaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int compare_node_according_to_code_range(const acism_trie_node_t **a, const acism_trie_node_t **b) +{ + int result; /* Bilan à retourner */ + const acism_trie_node_t *_a; /* Autre vision de l'élément #1*/ + const acism_trie_node_t *_b; /* Autre vision de l'élément #1*/ + acism_code_t range_a; /* Espacement des codes #1 */ + acism_code_t range_b; /* Espacement des codes #2 */ + + result = 0; + + _a = *a; + _b = *b; + + if (_a->child == NULL) + result = (_b->child == NULL ? 0 : 1); + + else if (_b->child == NULL) + result = (_a->child == NULL ? 0 : -1); + + else + { + assert(_a->min_child_code <= _a->max_child_code); + range_a = _a->max_child_code - _a->min_child_code; + + assert(_b->min_child_code <= _b->max_child_code); + range_b = _b->max_child_code - _b->min_child_code; + + result = sort_unsigned_long(range_b, range_a); + + if (result == 0) + result = sort_unsigned_long(_b->children_count, _a->children_count); + + + + + } + + return result; + +} + + +#endif + + +#if 1 + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à préparer. * +* * +* Description : Organise la convertion de l'arborescence en tableau. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_acism_backend_prepare_interleave_array(GAcismBackend *backend) +{ +#ifdef __SORT_BEFORE_BITMASK + acism_trie_node_t **list; /* Liste de noeuds alloués */ +#endif + size_t i; /* Boucle de parcours #1 */ + size_t last_free_state; /* Dernier emplacement dispo. */ + size_t full_size; /* Cartographie entière */ + bitfield_t *global_usage; /* Cartographie des usages */ + bitfield_t *usage; /* Cartographie locale */ + acism_trie_node_t *node; /* Noeud en cours de traitement*/ + acism_trie_node_t *iter; /* Boucle de parcours #2 */ + size_t free_state; /* Emplacement libre trouvé */ + bool found; /* Bilan de recherche */ + + size_t bsum; + + /* Préparation de la liste de noeuds à inscrire */ + +#ifdef __SORT_BEFORE_BITMASK + + list = calloc(backend->nodes_used, sizeof(acism_trie_node_t *)); + + for (i = 0; i < backend->nodes_used; i++) + list[i] = backend->nodes + i; + + qsort(list + 1, backend->nodes_used - 1, sizeof(acism_trie_node_t *), + (__compar_fn_t)compare_node_according_to_code_range); + +#endif + + /* Insertion des noeuds dans l'ordre prévu */ + + last_free_state = 257; + full_size = last_free_state + 257; + global_usage = create_bit_field(full_size, false); + + bsum = 0; + + usage = create_bit_field(257, false); + + for (i = 0; i < backend->nodes_used; i++) + { +#ifdef __SORT_BEFORE_BITMASK + node = list[i]; +#else + node = backend->nodes + i; +#endif + + /* Préparation du masque du noeud */ + + reset_all_in_bit_field(usage); + + set_in_bit_field(usage, 0, 1); + + for (iter = node->child; iter != NULL; iter = iter->sibling) + set_in_bit_field(usage, iter->code, 1); + + assert(popcount_for_bit_field(usage) == (node->children_count + 1)); + + /* Recherche d'une position idéale */ + + if (i == 0) + free_state = 0; + + else + for (free_state = 1; free_state < last_free_state; free_state++) + { + found = test_zeros_within_bit_field(global_usage, free_state, usage); + if (found) break; + } + + /* Suivi global */ + + assert(!test_in_bit_field(global_usage, free_state)); + + or_bit_field_at(global_usage, usage, free_state); + + bsum += node->children_count + 1; + assert(popcount_for_bit_field(global_usage) == bsum); + + node->state_index = free_state; + + if ((free_state + 257) > last_free_state) + { + last_free_state += 257; + full_size += 257; + resize_bit_field(&global_usage, full_size); + } + + } + + /* Sotie encadrée */ + + backend->bitmap_usage = global_usage; + + delete_bit_field(usage); + +#ifdef __SORT_BEFORE_BITMASK + free(list); +#endif + +} + + +#else + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à préparer. * +* * +* Description : Organise la convertion de l'arborescence en tableau. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_acism_backend_prepare_interleave_array(GAcismBackend *backend) +{ + size_t max_pos; /* Tête de lecture finale */ + acism_trie_node_t **stack; /* Pile des noeuds à traiter */ + size_t last_free_state; /* Dernier emplacement dispo. */ + size_t full_size; /* Cartographie entière */ + bitfield_t *global_usage; /* Cartographie des usages */ + bitfield_t *usage; /* Cartographie locale */ + size_t rd_pos; /* Tête de lecture */ + size_t wr_pos; /* Tête d'écriture */ + acism_trie_node_t *node; /* Noeud à traiter */ + acism_trie_node_t *iter; /* Boucle de parcours */ + size_t free_state; /* Emplacement libre trouvé */ + bool found; /* Bilan de recherche */ + + max_pos = backend->nodes_used; + + stack = calloc(max_pos, sizeof(acism_trie_node_t *)); + + last_free_state = 257; + full_size = last_free_state + 257; + global_usage = create_bit_field(full_size, false); + + usage = create_bit_field(257, false); + + /* Initialisation du parcours */ + + rd_pos = 0; + wr_pos = 0; + + stack[wr_pos++] = &backend->nodes[0]; + + assert(backend->nodes->sibling == NULL); + + /* Traitement manuel de démarrage pour éviter une condition en [0] */ + + set_in_bit_field(global_usage, 0, 1); + + for (iter = backend->nodes->child; iter != NULL; iter = iter->sibling) + { + set_in_bit_field(global_usage, iter->code, 1); + stack[wr_pos++] = iter; + } + + rd_pos++; + + /* Suivi des liens déjà en place */ + + while (rd_pos < max_pos) + { + assert(rd_pos < wr_pos); + + node = stack[rd_pos++]; + + /* Préparation du masque du noeud et inscription des noeuds suivants */ + + reset_all_in_bit_field(usage); + + set_in_bit_field(usage, 0, 1); + + for (iter = node->child; iter != NULL; iter = iter->sibling) + { + set_in_bit_field(usage, iter->code, 1); + stack[wr_pos++] = iter; + } + + assert(popcount_for_bit_field(usage) == (node->children_count + 1)); + + /* Recherche d'une position idéale */ + + for (free_state = 1; free_state < last_free_state; free_state++) + { + found = test_zeros_within_bit_field(global_usage, free_state, usage); + if (found) break; + } + + /* Suivi global */ + + assert(!test_in_bit_field(global_usage, free_state)); + + or_bit_field_at(global_usage, usage, free_state); + + node->state_index = free_state; + + if ((free_state + 257) > last_free_state) + { + last_free_state += 257; + full_size += 257; + resize_bit_field(&global_usage, full_size); + } + + } + + /* Sotie encadrée */ + + backend->bitmap_usage = global_usage; + + delete_bit_field(usage); + + free(stack); + +} + + +#endif + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à préparer. * +* * +* Description : Compresse l'arborescence dans un tableau de position. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_acism_backend_build_interleave_array(GAcismBackend *backend) +{ + size_t maxsize; /* Taille maximale du tableau */ + size_t i; /* Boucle de parcours #1 */ + acism_trie_node_t *node; /* Noeud à transcrire */ + acism_state_t *base; /* Base d'une série de cellules*/ + acism_trie_node_t *iter; /* Sous-noeud à inscrire #2 */ + acism_trie_node_t *child; /* Sous-noeud à inscrire #3 */ + uint16_t offset; /* Décalage local */ + + maxsize = get_bit_field_size(backend->bitmap_usage); + + backend->states = calloc(maxsize, sizeof(acism_state_t)); + backend->pids = calloc(maxsize, sizeof(patid_t)); + + for (i = 0; i < backend->nodes_used; i++) + { + node = &backend->nodes[i]; + base = backend->states + node->state_index; + + assert(base[0].code == 0); + assert(base[0].index == 0); + + if (node->matched_atom > 0) + { + base[0].match = 1; + base[0].atom_size = backend->sources[node->matched_atom - 1].len; + + backend->pids[node->state_index] = backend->sources[node->matched_atom - 1].pid; + + for (iter = node->parent->suffix_link; iter != NULL; iter = iter->suffix_link) + { + for (child = iter->child; child != NULL; child = child->sibling) + if (child->code == node->code && child->matched_atom > 0) + break; + + if (child != NULL) + { + base[0].suffix = 1; + break; + } + + } + + } + base[0].index = i == 0 ? 0 : node->suffix_link->state_index; + + for (child = node->child; child != NULL; child = child->sibling) + { + offset = child->code; + + assert(base[offset].code == 0); + assert(base[offset].index == 0); + + base[offset].code = child->code; + base[offset].index = child->state_index; + + } + + } + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à préparer. * +* * +* Description : Met en ordre les derniers détails avant un premier scan. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_acism_backend_warm_up(GAcismBackend *backend) +{ +#ifdef __USE_BYTE_FREQ + + /** + * Attribue un identifiant unique pour chaque octet présent dans les + * motifs recherchés. + */ + g_acism_backend_define_codes(backend); + +#endif + + /** + * Construit une arborescence de lecture à partir des différents + * octets présents dans les motifs. + */ + g_acism_backend_build_trie(backend); + + /** + * Met en place les liens suivis en cas d'échec de correspondance + * lors de la lecture d'un octet supplémentaire. + */ + g_acism_backend_build_suffix_links(backend); + + /** + * Conversion de l'arborescence en tableau plat et compressé. + */ + + g_acism_backend_prepare_interleave_array(backend); + + g_acism_backend_build_interleave_array(backend); + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à manipuler. * +* context = lieu d'enregistrement des résultats. * +* content = données binaires à analyser. * +* * +* Description : Parcours un contenu binaire à la recherche de motifs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_acism_backend_run_scan(const GAcismBackend *backend, GScanContext *context, GBinContent *content) +{ + phys_t dlen; /* Quantité de données */ + vmpa2t pos; /* Point de départ ciblé */ + const bin_t *data; /* Données à analyser */ +#ifdef __USE_BYTE_FREQ + acism_code_t *codes_for_bytes; +#endif + acism_state_t *root; /* Racine de l'arborescence */ + acism_state_t *state; /* Tête de lecture courante */ + phys_t i; /* Boucle de parcours #1 */ + acism_code_t code; /* Code du caractère courant */ + acism_state_t *next; /* Prochaine tête à valider */ + acism_state_t *iter; /* Boucle de parcours #2 */ + acism_state_t *test; /* Test de validité alternative*/ + + dlen = g_binary_content_compute_size(content); + + g_binary_content_compute_start_pos(content, &pos); + data = g_binary_content_get_raw_access(content, &pos, dlen); + + /* Suivi via l'arborescence aplatie */ + +#ifdef __USE_BYTE_FREQ + codes_for_bytes = backend->codes_for_bytes; +#endif + + root = backend->states; + + state = root; + + for (i = 0; i < dlen; i++) + { +#ifdef __USE_BYTE_FREQ + code = 1 + codes_for_bytes[data[i]]; +#else + code = 1 + data[i]; +#endif + + /* Déplacement de la tête de lecture dans l'arborescence */ + + retry: + + next = state + code; + + if (next->code == code) + next = root + next->index; + + else if (state != root) + { + state = root + state->index; + goto retry; + } + + else + continue; + + /* Remontée d'éventuels résultats */ + + if (next->match) + { + g_scan_context_register_atom_match(context, + backend->pids[next - root], + i + 1 - next->atom_size); + + if (next->suffix) + { + for (iter = root + state->index; ; iter = root + iter->index) + { + test = iter + code; + + if (test->code == code) + { + test = root + test->index; + + if (test->match) + { + assert(test->atom_size < next->atom_size); + + g_scan_context_register_atom_match(context, + backend->pids[test - root], + i + 1 - test->atom_size); + + } + + } + + if (iter == root) + break; + + } + + } + + + } + + /* Bascule au caractère suivant */ + + state = next; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : node = noeud d'arborescence à traiter. * +* level = profondeur courante. * +* * +* Description : Affiche les caractéristques d'un noeud et de ses enfants. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void visit_and_output_node(const acism_trie_node_t *node, unsigned int level) +{ + unsigned int i; /* Boucle de parcours #1 */ + acism_trie_node_t *iter; /* Boucle de parcours #2 */ + + for (i = 0; i < level; i++) + printf(" "); + + printf(" '%c' (code=%hhu)\n", node->data, node->code); + + for (iter = node->child; iter != NULL; iter = iter->sibling) + visit_and_output_node(iter, level + 1); + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à consulter. * +* * +* Description : Imprime quelques faits quant aux éléments mis en place. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_acism_backend_output_stats(const GAcismBackend *backend) +{ + printf("nodes used: %zu\n", backend->nodes_used); + + printf("full_size: %zu (real: %zu)\n", + get_bit_field_size(backend->bitmap_usage), + popcount_for_bit_field(backend->bitmap_usage)); + + visit_and_output_node(backend->nodes, 0); + +} diff --git a/src/analysis/scan/patterns/backends/acism.h b/src/analysis/scan/patterns/backends/acism.h new file mode 100644 index 0000000..837022a --- /dev/null +++ b/src/analysis/scan/patterns/backends/acism.h @@ -0,0 +1,59 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * acism.h - prototypes pour la méthode de recherche basée sur l'algorithme Aho-Corasick Interleaved State-transition Matrix + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_H +#define _ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_H + + +#include <glib-object.h> +#include <stdbool.h> + + +#include "../backend.h" + + + +#define G_TYPE_ACISM_BACKEND g_acism_backend_get_type() +#define G_ACISM_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ACISM_BACKEND, GAcismBackend)) +#define G_IS_ACISM_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ACISM_BACKEND)) +#define G_ACISM_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ACISM_BACKEND, GAcismBackendClass)) +#define G_IS_ACISM_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ACISM_BACKEND)) +#define G_ACISM_BACKEND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ACISM_BACKEND, GAcismBackendClass)) + + +/* Méthode de recherche basée sur l'algorithme Acism (instance) */ +typedef struct _GAcismBackend GAcismBackend; + +/* Méthode de recherche basée sur l'algorithme Acism (classe) */ +typedef struct _GAcismBackendClass GAcismBackendClass; + + +/* Indique le type défini pour un moteur de recherche pour données. */ +GType g_acism_backend_get_type(void); + +/* Crée une méthode de recherche basée sur l'algorithme Acism. */ +GEngineBackend *g_acism_backend_new(void); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_H */ diff --git a/src/analysis/scan/patterns/backends/bitap-int.h b/src/analysis/scan/patterns/backends/bitap-int.h new file mode 100644 index 0000000..83ecc17 --- /dev/null +++ b/src/analysis/scan/patterns/backends/bitap-int.h @@ -0,0 +1,118 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bitap-int.h - prototypes internes pour la méthode de recherche basée sur l'algorithme Bitap + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_INT_H +#define _ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_INT_H + + +#include "bitap.h" + + +#include <immintrin.h> + + +#include "../backend-int.h" +#include "../../../../common/cpu.h" + + + +#define BITAP_ATOM_SIZE 7 + + +/* Suivi d'un groupe de chaînes */ +typedef struct _grouped_strings_avx2_t +{ + __m256i pattern_masks[256]; /* Programmation de détections */ + __m256i found_masks; /* Masques multiples d'alerte */ + + __m256i R; /* Résultats courants */ + + size_t m[32]; /* Taille des chaînes */ + + patid_t found_id[32]; /* Indice des résultats */ + + size_t available; /* Nombre de places disponibles*/ + size_t used; /* Quantité de places utilisées*/ + +} grouped_strings_avx2_t; + +/* Suivi de l'ensemble de chaînes */ +typedef struct _group_manager_avx2_t +{ + grouped_strings_avx2_t **strings_8; /* Chaînes de taille 8 max */ + size_t count_8; /* Quantité de ces chaînes */ + +} group_manager_avx2_t; + + +/* Suivi d'un groupe de chaînes */ +typedef struct _grouped_strings_avx512_t +{ + __m512i pattern_masks[256]; /* Programmation de détections */ + __m512i found_masks; /* Masques multiples d'alerte */ + + __m512i R; /* Résultats courants */ + + size_t m[64]; /* Taille des chaînes */ + + patid_t found_id[64]; /* Indice des résultats */ + + size_t used; /* Quantité de places utilisées*/ + size_t available; /* Nombre de places disponibles*/ + +} grouped_strings_avx512_t; + +/* Suivi de l'ensemble de chaînes */ +typedef struct _group_manager_avx512_t +{ + grouped_strings_avx512_t **strings_8; /* Chaînes de taille 8 max */ + size_t count_8; /* Quantité de ces chaînes */ + +} group_manager_avx512_t; + + +/* Méthode de recherche basée sur l'algorithme Bitap (instance) */ +struct _GBitapBackend +{ + GEngineBackend parent; /* A laisser en premier */ + + CPUSMIDFeature optimization; /* Mode de calculs */ + + union + { + group_manager_avx2_t manager_avx2; /* Gestionnaire pour AVX2 */ + group_manager_avx512_t manager_avx512;/* Gestionnaire pour AVX-512 */ + }; + +}; + +/* Méthode de recherche basée sur l'algorithme Bitap (classe) */ +struct _GBitapBackendClass +{ + GEngineBackendClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_INT_H */ diff --git a/src/analysis/scan/patterns/backends/bitap.c b/src/analysis/scan/patterns/backends/bitap.c new file mode 100644 index 0000000..bd80fb0 --- /dev/null +++ b/src/analysis/scan/patterns/backends/bitap.c @@ -0,0 +1,2766 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bitap.c - méthode de recherche basée sur l'algorithme Bitap + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "bitap.h" + + +#include <alloca.h> +#include <assert.h> +#include <sys/mman.h> +#include <sched.h> + + +#include "bitap-int.h" +#include "../../../../core/logs.h" +//#include "../../matches/bytes.h" + + + +/* ---------------------- IMPLANTATION D'UNE NOUVELLE APPROCHE ---------------------- */ + + +/* Initialise la classe des méthodes basée sur Bitmap. */ +static void g_bitap_backend_class_init(GBitapBackendClass *); + +/* Initialise une instance de méthodes basée sur Bitmap. */ +static void g_bitap_backend_init(GBitapBackend *); + +/* Supprime toutes les références externes. */ +static void g_bitap_backend_dispose(GBitapBackend *); + +/* Procède à la libération totale de la mémoire. */ +static void g_bitap_backend_finalize(GBitapBackend *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Indique la taille maximale des suites d'octets recherchées. */ +size_t g_bitap_backend_get_atom_max_size(const GBitapBackend *); + +/* Inscrit dans le moteur une chaîne de caractères à rechercher. */ +static patid_t g_bitap_backend_enroll_plain_pattern(GBitapBackend *, GScanContext *, const uint8_t *, size_t); + +/* Parcours un contenu binaire à la recherche de motifs. */ +static void g_bitap_backend_run_scan(const GBitapBackend *, GScanContext *, GBinContent *); + +/* Imprime quelques faits quant aux éléments mis en place. */ +static void g_bitap_backend_output_stats(const GBitapBackend *); + + + +/* ---------------------- OPTIMISATIONS POUR ARCHITECTURE AVX2 ---------------------- */ + + +/* Indique la valeur portée par une expression rationnelle. */ +static void extend_grouped_strings_avx2(grouped_strings_avx2_t ***, size_t *); + +/* Inscrit dans le moteur une chaîne de caractères à rechercher. */ +static patid_t enroll_plain_pattern_avx2(GBitapBackend *, GScanContext *, const bin_t *, size_t); + +/* Parcours un contenu binaire à la recherche de motifs. */ +static void run_scan_avx2(const GBitapBackend *, GScanContext *, GBinContent *); + + + + + +/* --------------------- OPTIMISATIONS POUR ARCHITECTURE AVX512 --------------------- */ + + +/* Indique la valeur portée par une expression rationnelle. */ +static void extend_grouped_strings_avx512(grouped_strings_avx512_t ***, size_t *); + +/* Inscrit dans le moteur une chaîne de caractères à rechercher. */ +static patid_t enroll_plain_pattern_avx512(GBitapBackend *, GScanContext *, const bin_t *, size_t); + +/* Parcours un contenu binaire à la recherche de motifs. */ +static void run_scan_avx512(const GBitapBackend *, GScanContext *, GBinContent *); + + + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLANTATION D'UNE NOUVELLE APPROCHE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un moteur de recherche pour données. */ +G_DEFINE_TYPE(GBitapBackend, g_bitap_backend, G_TYPE_ENGINE_BACKEND); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des méthodes basée sur Bitmap. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_bitap_backend_class_init(GBitapBackendClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GEngineBackendClass *backend; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_bitap_backend_dispose; + object->finalize = (GObjectFinalizeFunc)g_bitap_backend_finalize; + + backend = G_ENGINE_BACKEND_CLASS(klass); + + backend->get_max_size = (get_backend_atom_max_size_fc)g_bitap_backend_get_atom_max_size; + backend->enroll_plain = (enroll_plain_into_backend_fc)g_bitap_backend_enroll_plain_pattern; + backend->run_scan = (run_backend_scan_fc)g_bitap_backend_run_scan; + backend->output = (output_backend_stats_fc)g_bitap_backend_output_stats; + +} + + +/****************************************************************************** +* * +* Paramètres : backend = instance à initialiser. * +* * +* Description : Initialise une instance de méthodes basée sur Bitmap. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_bitap_backend_init(GBitapBackend *backend) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : backend = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_bitap_backend_dispose(GBitapBackend *backend) +{ + G_OBJECT_CLASS(g_bitap_backend_parent_class)->dispose(G_OBJECT(backend)); + +} + + +/****************************************************************************** +* * +* Paramètres : backend = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_bitap_backend_finalize(GBitapBackend *backend) +{ + G_OBJECT_CLASS(g_bitap_backend_parent_class)->finalize(G_OBJECT(backend)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée une méthode de recherche basée sur l'algorithme Bitap. * +* * +* Retour : Méthode mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GEngineBackend *g_bitap_backend_new(void) +{ + GBitapBackend *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_BITAP_BACKEND, NULL); + + return G_ENGINE_BACKEND(result); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à consulter. * +* * +* Description : Indique la taille maximale des suites d'octets recherchées. * +* * +* Retour : Valeur strictement positive. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_bitap_backend_get_atom_max_size(const GBitapBackend *backend) +{ + size_t result; /* Taille à faire connaître */ + + result = BITAP_ATOM_SIZE; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à manipuler. * +* context = contexte de l'analyse à mener. * +* plain = chaîne de caractères classique à intégrer. * +* len = taille de cette chaîne. * +* * +* Description : Inscrit dans le moteur une chaîne de caractères à rechercher.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static patid_t g_bitap_backend_enroll_plain_pattern(GBitapBackend *backend, GScanContext *context, const uint8_t *plain, size_t len) +{ + patid_t result; /* Identifiant à retourner */ + + + + result = INVALID_PATTERN_ID; + + + + + if (0) + + result = enroll_plain_pattern_avx2(backend, context, plain, len); + + else + + result = enroll_plain_pattern_avx512(backend, context, plain, len); + + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à manipuler. * +* context = lieu d'enregistrement des résultats. * +* content = données binaires à analyser. * +* * +* Description : Parcours un contenu binaire à la recherche de motifs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_bitap_backend_run_scan(const GBitapBackend *backend, GScanContext *context, GBinContent *content) +{ + cpu_set_t old_mask; /* Cartographie des CPU #1 */ + int ret; /* Bilan d'un appel */ + unsigned int cpu; /* Processeur courant */ + cpu_set_t new_mask; /* Cartographie des CPU #2 */ + + ret = sched_getaffinity(0, sizeof(cpu_set_t), &old_mask); + + if (ret != 0) + { + LOG_ERROR_N("sched_getaffinity"); + goto exit; + } + + ret = getcpu(&cpu, NULL); + + if (ret != 0) + { + LOG_ERROR_N("get_cpu"); + goto exit; + } + + CPU_ZERO(&new_mask); + CPU_SET(cpu, &new_mask); + + ret = sched_setaffinity(0, sizeof(cpu_set_t), &new_mask); + + if (ret != 0) + { + LOG_ERROR_N("sched_setaffinity"); + goto exit; + } + + + + if (0) + + run_scan_avx2(backend, context, content); + + else + + run_scan_avx512(backend, context, content); + + + exit: + + ; + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à consulter. * +* * +* Description : Imprime quelques faits quant aux éléments mis en place. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_bitap_backend_output_stats(const GBitapBackend *backend) +{ + printf("hello here!\n"); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* OPTIMISATIONS POUR ARCHITECTURE AVX2 */ +/* ---------------------------------------------------------------------------------- */ + + +/** + * Cf. https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#techs=AVX,AVX2 + */ + + +/****************************************************************************** +* * +* Paramètres : strings = ensemble de groupes constitués. [OUT] * +* count = nombre de groupes courant. [OUT] * +* * +* Description : Indique la valeur portée par une expression rationnelle. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void extend_grouped_strings_avx2(grouped_strings_avx2_t ***strings, size_t *count) +{ + grouped_strings_avx2_t *new; /* Zone supplémentaire */ + size_t i; /* Boucle de parcours */ + + /* Définition d'un nouvel élément vierge */ + + new = aligned_alloc(256, sizeof(grouped_strings_avx2_t)); + + for (i = 0; i < 256; i++) + new->pattern_masks[i] = _mm256_set1_epi8(~0); + + new->found_masks = _mm256_set1_epi8(~0); + + new->R = _mm256_set1_epi8(~1); + + for (i = 0; i < 32; i++) + { + new->m[i] = 0; + + new->found_id[i] = INVALID_PATTERN_ID; + + } + + new->available = 32; + new->used = 0; + + /* Inscription */ + + *strings = realloc(*strings, ++(*count) * sizeof(grouped_strings_avx2_t *)); + + (*strings)[*count - 1] = new; + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à manipuler. * +* context = contexte de l'analyse à mener. * +* plain = chaîne de caractères classique à intégrer. * +* plen = taille de cette chaîne. * +* * +* Description : Inscrit dans le moteur une chaîne de caractères à rechercher.* +* * +* Retour : Indice de résultats pour le motif. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static patid_t enroll_plain_pattern_avx2(GBitapBackend *backend, GScanContext *context, const bin_t *plain, size_t plen) +{ + patid_t result; /* Identifiant à retourner */ + grouped_strings_avx2_t ***strings; /* Groupe de chaînes visé */ + size_t *count; /* Taille de ce groupe */ + grouped_strings_avx2_t *last; /* Dernier groupe à remplir */ + size_t n; /* Indice dans le groupe */ + size_t i; /* Boucle de parcours */ + __m256i *letter; /* Lettre à marquer */ + + /* Sélection du groupe de travail adéquat */ + + strings = &backend->manager_avx2.strings_8; + count = &backend->manager_avx2.count_8; + + /* Préparation de la place nécessaire */ + + if (*count == 0) + { + extend_grouped_strings_avx2(strings, count); + + last = (*strings)[0]; + + } + + else + { + last = (*strings)[*count - 1]; + + if (last->used == last->available) + { + extend_grouped_strings_avx2(strings, count); + last = (*strings)[*count - 1]; + } + + } + + /* Intégration d'une nouvelle chaîne */ + + n = last->used++; + + last->m[n] = plen; + + result = g_scan_context_get_new_pattern_id(context); + + last->found_id[n] = result; + + ((uint8_t *)&last->found_masks)[n] = (1 << plen); + + for (i = 0; i < plen; i++) + { + letter = last->pattern_masks + plain[i]; + ((uint8_t *)letter)[n] &= ~(1 << i); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à manipuler. * +* context = lieu d'enregistrement des résultats. * +* content = données binaires à analyser. * +* * +* Description : Parcours un contenu binaire à la recherche de motifs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void run_scan_avx2(const GBitapBackend *backend, GScanContext *context, GBinContent *content) +{ + const group_manager_avx2_t *manager; /* Accès simplifié */ + phys_t dlen; /* Quantité de données */ + vmpa2t pos; /* Point de départ ciblé */ + const bin_t *data; /* Données à analyser */ + + register __m256i zero asm("ymm11"); /* Constante 0 sur 256 bits */ + size_t k; /* Boucle de parcours #1 */ + grouped_strings_avx2_t group; /* Copie pour accès locaux */ + + register __m256i R asm("ymm12"); /* Résultats courants */ + register __m256i found_masks asm("ymm10"); /* Vérifications accélérées */ + + //__m256i pre_shift_mask; /* Préparation de décalage */ + //phys_t i; /* Boucle de parcours #2 */ + + + + + const bin_t *iter; + const bin_t *maxiter; + //phys_t i; /* Boucle de parcours #2 */ + + volatile register __m256i xxxx; /* Test de correspondances */ + + + __m256i test; /* Test de correspondances */ + __m256i test2; /* Test de correspondances */ + __m256i status; /* Statut d'une comparaison */ + + int masks[10]; + + int mask; /* Masque d'accès rapide */ + size_t j; /* Boucle de parcours #3 */ + + + int ret; + + //return; + + /* Initialisations diverses */ + + manager = &backend->manager_avx2; + + dlen = g_binary_content_compute_size(content); + + g_binary_content_compute_start_pos(content, &pos); + data = g_binary_content_get_raw_access(content, &pos, dlen); + + zero = _mm256_set1_epi16(0); + + asm volatile ("nop;nop;nop;nop;nop;nop;nop;nop;nop;"); + + xxxx = _mm256_set1_epi8(~1); + + asm volatile ("nop;nop;nop;nop;nop;nop;nop;nop;nop;"); + + /* Recherches des chaînes de moins de 8 caractères */ + + printf(" --- manager->count_8: %zu\n", manager->count_8); + + ret = 0; + + for (k = 0; k < manager->count_8; k++) + { + memcpy(&group, manager->strings_8[k], sizeof(grouped_strings_avx2_t)); + + //printf(" --- group.used: %zu\n", group.used); + + + asm volatile + ( + /* + * R = _mm256_set1_epi8(~1); + * + */ + + "movabs $0xfefefefefefefefe, %%rax ; " + "vpbroadcastq %%rax, %[STATE] ; " + + /* + * + */ + + "vmovdqa %[FOUND_SRC], %[FOUND_DST] ; " + + : [STATE] "=v"(R), + [FOUND_DST] "=v"(found_masks) + : [FOUND_SRC] "m"(group.found_masks) + : "memory", "rax" + + ); + + + + + //pre_shift_mask = _mm256_set1_epi8(0xef); + + maxiter = data + dlen; + + + + for (iter = data; (iter + 10) < maxiter; iter += 10) + { + + //printf("--- %llx <-> %c\n", (unsigned long long)(iter - data), *iter); + + + asm volatile + ( +#if 0 + + /* + * R = _mm256_or_si256(R, group.pattern_masks[data[i]]); + * + * Latency : 1-9 + * Throughput : 0.5 + * #Uops : 1-2 + * Port Usage : 1*p015+1*p23 + * + */ + + "vpor %[PATTERN], %[STATE], %[STATE] ; " + +#else + + /* + * %ymm = group.pattern_masks[data[i]]; + * + * Latency : 5-8 + * Throughput : 0.5 + * #Uops : 1 + * Port Usage : 1*p23 + * + */ + + "vmovdqa %[PATTERN0], %%ymm0 ; " + "vmovdqa %[PATTERN1], %%ymm1 ; " + "vmovdqa %[PATTERN2], %%ymm2 ; " + "vmovdqa %[PATTERN3], %%ymm3 ; " + "vmovdqa %[PATTERN4], %%ymm4 ; " + "vmovdqa %[PATTERN5], %%ymm5 ; " + "vmovdqa %[PATTERN6], %%ymm6 ; " + "vmovdqa %[PATTERN7], %%ymm7 ; " + "vmovdqa %[PATTERN7], %%ymm8 ; " + "vmovdqa %[PATTERN7], %%ymm9 ; " + + /* + * R = _mm256_or_si256(R, %ymm); + * + * Latency : 1 + * Throughput : 0.33 + * #Uops : 1 + * Port Usage : 1*p015 + * + */ + + "vpor %%ymm0, %[STATE], %[STATE] ; " + +#endif + + /* + * R = _mm256_add_epi8(R, R); + * + * Latency : 1 + * Throughput : 0.3 + * #Uops : 1 + * Port Usage : 1*p015 + * + */ + + "vpaddb %[STATE], %[STATE], %[STATE] ; " + + /* + * test = _mm256_and_si256(R, group.found_masks); + * + * Latency : 1 + * Throughput : 0.33 + * #Uops : 1 + * Port Usage : 1*p015 + * + */ + + "vpand %[FOUND], %[STATE], %%ymm0 ; " + + /* Déroulemets... */ + + "vpor %%ymm1, %[STATE], %[STATE] ; " + "vpaddb %[STATE], %[STATE], %[STATE] ; " + + "vpor %%ymm2, %[STATE], %[STATE] ; " + "vpaddb %[STATE], %[STATE], %[STATE] ; " + + "vpor %%ymm3, %[STATE], %[STATE] ; " + "vpaddb %[STATE], %[STATE], %[STATE] ; " + + "vpor %%ymm4, %[STATE], %[STATE] ; " + "vpaddb %[STATE], %[STATE], %[STATE] ; " + + "vpor %%ymm5, %[STATE], %[STATE] ; " + "vpaddb %[STATE], %[STATE], %[STATE] ; " + + "vpor %%ymm6, %[STATE], %[STATE] ; " + "vpaddb %[STATE], %[STATE], %[STATE] ; " + + "vpor %%ymm7, %[STATE], %[STATE] ; " + "vpaddb %[STATE], %[STATE], %[STATE] ; " + + "vpor %%ymm8, %[STATE], %[STATE] ; " + "vpaddb %[STATE], %[STATE], %[STATE] ; " + + "vpor %%ymm9, %[STATE], %[STATE] ; " + "vpaddb %[STATE], %[STATE], %[STATE] ; " + + "vpand %[FOUND], %[STATE], %%ymm1 ; " + "vpand %[FOUND], %[STATE], %%ymm2 ; " + "vpand %[FOUND], %[STATE], %%ymm3 ; " + "vpand %[FOUND], %[STATE], %%ymm4 ; " + "vpand %[FOUND], %[STATE], %%ymm5 ; " + "vpand %[FOUND], %[STATE], %%ymm6 ; " + "vpand %[FOUND], %[STATE], %%ymm7 ; " + "vpand %[FOUND], %[STATE], %%ymm8 ; " + "vpand %[FOUND], %[STATE], %%ymm9 ; " + + + + + + /* + * status = _mm256_cmpeq_epi8(test, zero); + * + * Latency : 1 + * Throughput : 0.5 + * #Uops : 1 + * Port Usage : 1*p01 + * + */ + + "vpcmpeqb %%ymm0, %[NUL], %%ymm0 ; " + + /* + * mask = _mm256_movemask_epi8(status); + * + * Latency : <5 + * Throughput : 1 + * #Uops : 1 + * Port Usage : 1*p0 + * + */ + + "vpmovmskb %%ymm0, %[MASK0] ; " + + + + + + "vpcmpeqb %%ymm1, %[NUL], %%ymm1 ; " + "vpcmpeqb %%ymm2, %[NUL], %%ymm2 ; " + "vpcmpeqb %%ymm3, %[NUL], %%ymm3 ; " + "vpcmpeqb %%ymm4, %[NUL], %%ymm4 ; " + "vpcmpeqb %%ymm5, %[NUL], %%ymm5 ; " + "vpcmpeqb %%ymm6, %[NUL], %%ymm6 ; " + "vpcmpeqb %%ymm7, %[NUL], %%ymm7 ; " + "vpcmpeqb %%ymm8, %[NUL], %%ymm8 ; " + "vpcmpeqb %%ymm9, %[NUL], %%ymm9 ; " + + + "vpmovmskb %%ymm1, %[MASK1] ; " + "vpmovmskb %%ymm2, %[MASK2] ; " + "vpmovmskb %%ymm3, %[MASK3] ; " + "vpmovmskb %%ymm4, %[MASK4] ; " + "vpmovmskb %%ymm5, %[MASK5] ; " + "vpmovmskb %%ymm6, %[MASK6] ; " + "vpmovmskb %%ymm7, %[MASK7] ; " + "vpmovmskb %%ymm8, %[MASK8] ; " + "vpmovmskb %%ymm9, %[MASK9] ; " + + + + + + + + + + + //"vmovdqa %%ymm7, %[OUTPUT] ; " + + //"vmovdqa %%ymm8, %[OUTPUT2] ; " + + : [STATE] "+v"(R), + [OUTPUT] "=v"(test), + [OUTPUT2] "=v"(test2), + [MASK0] "=r"(mask), + [MASK1] "=r"(mask), + [MASK2] "=r"(mask), + [MASK3] "=r"(mask), + [MASK4] "=r"(mask), + [MASK5] "=r"(mask), + [MASK6] "=r"(mask), + [MASK7] "=r"(mask), + [MASK8] "=r"(mask), + [MASK9] "=r"(mask), + [NUL] "+v"(zero) + : [PATTERN0] "m"(group./*manager->strings_8[k]->*/pattern_masks[*iter]), + [PATTERN1] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 1)]), + [PATTERN2] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 2)]), + [PATTERN3] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 3)]), + [PATTERN4] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 4)]), + [PATTERN5] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 5)]), + [PATTERN6] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 6)]), + [PATTERN7] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 7)]), + [PATTERN8] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 8)]), + [PATTERN9] "m"(group./*manager->strings_8[k]->*/pattern_masks[*(iter + 9)]), + [FOUND] "v"(found_masks) + : "memory", "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9" + + ); + + + /* + printf(" test: %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx ... %02hhx %02hhx %02hhx %02hhx\n", + ((uint8_t *)&test)[0], + ((uint8_t *)&test)[1], + ((uint8_t *)&test)[2], + ((uint8_t *)&test)[3], + ((uint8_t *)&test)[4], + ((uint8_t *)&test)[5], + ((uint8_t *)&test)[6], + ((uint8_t *)&test)[7], + ((uint8_t *)&test)[16], + ((uint8_t *)&test)[17], + ((uint8_t *)&test)[18], + ((uint8_t *)&test)[19]); + + printf(" test2: %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx ... %02hhx %02hhx %02hhx %02hhx\n", + ((uint8_t *)&test2)[0], + ((uint8_t *)&test2)[1], + ((uint8_t *)&test2)[2], + ((uint8_t *)&test2)[3], + ((uint8_t *)&test2)[4], + ((uint8_t *)&test2)[5], + ((uint8_t *)&test2)[6], + ((uint8_t *)&test2)[7], + ((uint8_t *)&test2)[16], + ((uint8_t *)&test2)[17], + ((uint8_t *)&test2)[18], + ((uint8_t *)&test2)[19]); + */ + +#if 0 + //printf(" > %c\n", data[i]); + + R = _mm256_or_si256(R, group.pattern_masks[*iter]); + + //printf("group pattern: %hhx\n", *((uint8_t *)&group.pattern_masks[data[i]])); + + //printf("R: %hhx\n", *((uint8_t *)&R)); + + //R = _mm256_and_si256(R, pre_shift_mask); + + //printf("R after and: %hhx\n", *((uint8_t *)&R)); + + R = _mm256_add_epi8(R, R); + //R = _mm256_slli_si256(R, 1); + + //printf("R after shift: %hhx\n", *((uint8_t *)&R)); + + test = _mm256_and_si256(R, group.found_masks); + +#if 1 + status = _mm256_cmpeq_epi8(test, zero); + + mask = _mm256_movemask_epi8(status); +#else + //mask = _mm256_movemask_epi8(test) ^ 0xffffffff; + mask = _mm256_movemask_epi8(test); +#endif + + +#endif + + + //printf(" mask : %x\n", mask); + + if (mask != 0) + for (j = 0; j < group.used; j++) + { + if ((mask & 0x1) == 1) + { + //assert((i + 1) >= group.m[j]); + + g_scan_context_register_atom_match(context, + group.found_id[j], + (iter - data) + 1 - group.m[j]); + + } + + mask >>= 1; + + } + + } + + + + + +#if 0 + for (; iter < maxiter; iter++) + { + + //printf("--- %llx <-> %c\n", (unsigned long long)(iter - data), *iter); + + + asm volatile + ( + /* + * R = _mm256_or_si256(R, group.pattern_masks[data[i]]); + * + * Latency : 1 + * Throughput : 0.33 + * #Uops : 1 + * Port Usage : 1*p015 + * + */ + + "vpor %[PATTERN], %[STATE], %[STATE] ; " + + /* + * R = _mm256_add_epi8(R, R); + * + * Latency : 1 + * Throughput : 0.3 + * #Uops : 1 + * Port Usage : 1*p015 + * + */ + + "vpaddb %[STATE], %[STATE], %[STATE] ; " + + /* + * test = _mm256_and_si256(R, group.found_masks); + * + * Latency : 1 + * Throughput : 0.33 + * #Uops : 1 + * Port Usage : 1*p015 + * + */ + + "vpand %[FOUND], %[STATE], %%ymm7 ; " + + /* + * status = _mm256_cmpeq_epi8(test, zero); + * + * Latency : 1 + * Throughput : 0.5 + * #Uops : 1 + * Port Usage : 1*p01 + * + */ + + "vpcmpeqb %%ymm7, %[NUL], %%ymm8 ; " + + /* + * mask = _mm256_movemask_epi8(status); + * + * Latency : <5 + * Throughput : 1 + * #Uops : 1 + * Port Usage : 1*p0 + * + */ + + "vpmovmskb %%ymm8, %[MASK0] ; " + + + //"vmovdqa %%ymm7, %[OUTPUT] ; " + + //"vmovdqa %%ymm8, %[OUTPUT2] ; " + + : [STATE] "+v"(R), + [OUTPUT] "=v"(test), + [OUTPUT2] "=v"(test2), + [MASK0] "=r"(mask), + [NUL] "+v"(zero) + : [PATTERN] "m"(group./*manager->strings_8[k]->*/pattern_masks[*iter]), + [FOUND] "v"(found_masks) + : "memory", "ymm7", "ymm8" + + ); + + + /* + printf(" test: %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx ... %02hhx %02hhx %02hhx %02hhx\n", + ((uint8_t *)&test)[0], + ((uint8_t *)&test)[1], + ((uint8_t *)&test)[2], + ((uint8_t *)&test)[3], + ((uint8_t *)&test)[4], + ((uint8_t *)&test)[5], + ((uint8_t *)&test)[6], + ((uint8_t *)&test)[7], + ((uint8_t *)&test)[16], + ((uint8_t *)&test)[17], + ((uint8_t *)&test)[18], + ((uint8_t *)&test)[19]); + + printf(" test2: %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx ... %02hhx %02hhx %02hhx %02hhx\n", + ((uint8_t *)&test2)[0], + ((uint8_t *)&test2)[1], + ((uint8_t *)&test2)[2], + ((uint8_t *)&test2)[3], + ((uint8_t *)&test2)[4], + ((uint8_t *)&test2)[5], + ((uint8_t *)&test2)[6], + ((uint8_t *)&test2)[7], + ((uint8_t *)&test2)[16], + ((uint8_t *)&test2)[17], + ((uint8_t *)&test2)[18], + ((uint8_t *)&test2)[19]); + */ + +#if 0 + //printf(" > %c\n", data[i]); + + R = _mm256_or_si256(R, group.pattern_masks[*iter]); + + //printf("group pattern: %hhx\n", *((uint8_t *)&group.pattern_masks[data[i]])); + + //printf("R: %hhx\n", *((uint8_t *)&R)); + + //R = _mm256_and_si256(R, pre_shift_mask); + + //printf("R after and: %hhx\n", *((uint8_t *)&R)); + + R = _mm256_add_epi8(R, R); + //R = _mm256_slli_si256(R, 1); + + //printf("R after shift: %hhx\n", *((uint8_t *)&R)); + + test = _mm256_and_si256(R, group.found_masks); + +#if 1 + status = _mm256_cmpeq_epi8(test, zero); + + mask = _mm256_movemask_epi8(status); +#else + //mask = _mm256_movemask_epi8(test) ^ 0xffffffff; + mask = _mm256_movemask_epi8(test); +#endif + + +#endif + + + //printf(" mask : %x\n", mask); + + if (mask != 0) + for (j = 0; j < group.used; j++) + { + if ((mask & 0x1) == 1) + { + //assert((i + 1) >= group.m[j]); + + g_scan_context_register_atom_match(context, + group.found_id[j], + (iter - data) + 1 - group.m[j]); + + } + + mask >>= 1; + + } + + } + +#endif + + + } + + +} + + + + + + + + + + + + + + +#if 0 + + +#if 0 + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à manipuler. * +* context = lieu d'enregistrement des résultats. * +* content = données binaires à analyser. * +* * +* Description : Parcours un contenu binaire à la recherche de motifs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void run_scan_avx2(const GBitapBackend *backend, GScanContext *context, GBinContent *content) +{ + const group_manager_avx2_t *manager; /* Accès simplifié */ + + grouped_strings_avx2_t groups[10]; /* Copie pour accès locaux */ + + + phys_t dlen; /* Quantité de données */ + vmpa2t pos; /* Point de départ ciblé */ + const bin_t *data; /* Données à analyser */ + __m256i zero; /* Constante 0 sur 256 bits */ + size_t k; /* Boucle de parcours #1 */ + + grouped_strings_avx2_t group; /* Copie pour accès locaux */ + __m256i R; /* Résultats courants */ + __m256i pre_shift_mask; /* Préparation de décalage */ + phys_t i; /* Boucle de parcours #2 */ + __m256i test; /* Test de correspondances */ + __m256i status; /* Statut d'une comparaison */ + int mask; /* Masque d'accès rapide */ + size_t j; /* Boucle de parcours #3 */ + + uint32_t leaves; + int ret; + + + phys_t old_i; + phys_t p; + + //return; + + /* Initialisations diverses */ + + manager = &backend->manager_avx2; + + dlen = g_binary_content_compute_size(content); + + g_binary_content_compute_start_pos(content, &pos); + data = g_binary_content_get_raw_access(content, &pos, dlen); + + zero = _mm256_set1_epi16(0); + + /* Recherches des chaînes de moins de 8 caractères */ + + printf(" --- manager->count_8: %zu\n", manager->count_8); + + ret = 0; + + //for (k = 0; k < manager->count_8; k++) + // memcpy(&groups[k], manager->strings_8[k], sizeof(grouped_strings_avx2_t)); + + + for (i = 0; i < dlen; ) + { + + //printf(" --- %llx\n", (unsigned long long)i); + + p = i + 4096; + + if (p > dlen) + p = dlen; + + old_i = i; + + printf("old_i: %llx\n", (unsigned long long)old_i); + + for (k = 0; k < manager->count_8; k++) + { + + group = *manager->strings_8[k]; + + R = group.R; + + for (i = old_i ; i < p; i++) + { + + //group = &groups[k]; + + //printf(" k: %zu i: %llx\n", k, (unsigned long long)i); + + //R = group.R;//_mm256_set1_epi8(~1); + + R = _mm256_or_si256(R, group.pattern_masks[data[i]]); + + R = _mm256_add_epi8(R, R); + + test = _mm256_and_si256(R, group.found_masks); + +#if 0 + status = _mm256_cmpeq_epi8(test, zero); + + mask = _mm256_movemask_epi8(status); +#else + //mask = _mm256_movemask_epi8(test) ^ 0xffffffff; + mask = _mm256_movemask_epi8(test); +#endif + + if (mask != 0xffffffff) + { + leaves = group.leaves; + + for (j = 0; j < group.used; j++) + { + if ((mask & 0x1) == 0) + { + if (leaves & 0x1) //group.leaves & (1u << j)) + ;//define_full_match_avx2(backend, context, content, &group, j, i + 1); + + } + + mask >>= 1; + + leaves >>= 1; + + } + + } + + group.R = R;//_mm256_set1_epi8(~1); + + memcpy(manager->strings_8[k], &group, sizeof(grouped_strings_avx2_t)); + + } + + + } + + } + + printf("oh: %d\n", ret); + + +} + + +#else + + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à manipuler. * +* context = lieu d'enregistrement des résultats. * +* content = données binaires à analyser. * +* * +* Description : Parcours un contenu binaire à la recherche de motifs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void run_scan_avx2(const GBitapBackend *backend, GScanContext *context, GBinContent *content) +{ + const group_manager_avx2_t *manager; /* Accès simplifié */ + phys_t dlen; /* Quantité de données */ + vmpa2t pos; /* Point de départ ciblé */ + const bin_t *data; /* Données à analyser */ + __m256i zero; /* Constante 0 sur 256 bits */ + size_t k; /* Boucle de parcours #1 */ + grouped_strings_avx2_t group; /* Copie pour accès locaux */ + __m256i R; /* Résultats courants */ + __m256i pre_shift_mask; /* Préparation de décalage */ + phys_t i; /* Boucle de parcours #2 */ + __m256i test; /* Test de correspondances */ + __m256i status; /* Statut d'une comparaison */ + int mask; /* Masque d'accès rapide */ + size_t j; /* Boucle de parcours #3 */ + + uint32_t leaves; + int ret; + + //return; + + /* Initialisations diverses */ + + manager = &backend->manager_avx2; + + dlen = g_binary_content_compute_size(content); + + g_binary_content_compute_start_pos(content, &pos); + data = g_binary_content_get_raw_access(content, &pos, dlen); + + zero = _mm256_set1_epi16(0); + + /* Recherches des chaînes de moins de 8 caractères */ + + printf(" --- manager->count_8: %zu\n", manager->count_8); + + ret = 0; + + for (k = 0; k < manager->count_8; k++) + { + memcpy(&group, manager->strings_8[k], sizeof(grouped_strings_avx2_t)); + + //printf(" --- group.used: %zu\n", group.used); + + R = _mm256_set1_epi8(~1); + + //pre_shift_mask = _mm256_set1_epi8(0xef); + + for (i = 0; i < dlen; ++i) + { + //printf(" > %c\n", data[i]); + + R = _mm256_or_si256(R, group.pattern_masks[data[i]]); + + //printf("group pattern: %hhx\n", *((uint8_t *)&group.pattern_masks[data[i]])); + + //printf("R: %hhx\n", *((uint8_t *)&R)); + + //R = _mm256_and_si256(R, pre_shift_mask); + + //printf("R after and: %hhx\n", *((uint8_t *)&R)); + + R = _mm256_add_epi8(R, R); + //R = _mm256_slli_si256(R, 1); + + //printf("R after shift: %hhx\n", *((uint8_t *)&R)); + + test = _mm256_and_si256(R, group.found_masks); + +#if 0 + status = _mm256_cmpeq_epi8(test, zero); + + mask = _mm256_movemask_epi8(status); +#else + //mask = _mm256_movemask_epi8(test) ^ 0xffffffff; + mask = _mm256_movemask_epi8(test); +#endif + + if (mask != 0xffffffff) + { + leaves = group.leaves; + + for (j = 0; j < group.used; j++) + { + if ((mask & 0x1) == 0) + { + //assert((i + 1) >= group.m[j]); + + if (leaves & 0x1) //group.leaves & (1u << j)) + define_full_match_avx2(backend, context, content, &group, j, i + 1); + //else + //{ + // ret++; + //printf("%x\n", (unsigned int)i + 1); + //} + //else + // g_scan_context_register_sub_match(context, group.found_id[j], i + 1 - group.m[j]); + + } + + mask >>= 1; + + leaves >>= 1; + + } + + } + + } + + } + + printf("oh: %d\n", ret); + + /* Recherches des chaînes de moins de 16 caractères */ + + for (k = 0; k < manager->count_16; k++) + { + memcpy(&group, manager->strings_16[k], sizeof(grouped_strings_avx2_t)); + + R = _mm256_set1_epi16(~1); + + for (i = 0; i < dlen; ++i) + { + R = _mm256_or_si256(R, group.pattern_masks[data[i]]); + R = _mm256_slli_epi16(R, 1); + + test = _mm256_and_si256(R, group.found_masks); + + status = _mm256_cmpeq_epi16(test, zero); + + mask = _mm256_movemask_epi8(status); + + if (mask != 0) + for (j = 0; j < group.used; j++) + { + if (mask & 0x3) + { + assert((i + 1) >= group.m[j]); + + if (group.leaves & (1llu << j)) + define_full_match_avx2(backend, context, content, &group, j, i + 1); + else + ;//g_scan_context_register_sub_match(context, group.found_id[j], i + 1 - group.m[j]); + + } + + mask >>= 2; + + } + + } + + } + +} + +#endif + + + +#endif + + + + + + + + + + + + + + + + + + + +/* ---------------------------------------------------------------------------------- */ +/* OPTIMISATIONS POUR ARCHITECTURE AVX512 */ +/* ---------------------------------------------------------------------------------- */ + + +/** + * Cf. https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#techs=AVX_512 + * - https://agner.org/optimize/ + * - https://uops.info/table.html + */ + + +/****************************************************************************** +* * +* Paramètres : strings = ensemble de groupes constitués. [OUT] * +* count = nombre de groupes courant. [OUT] * +* * +* Description : Indique la valeur portée par une expression rationnelle. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void extend_grouped_strings_avx512(grouped_strings_avx512_t ***strings, size_t *count) +{ + grouped_strings_avx512_t *new; /* Zone supplémentaire */ + size_t i; /* Boucle de parcours */ + + /* Définition d'un nouvel élément vierge */ + + new = aligned_alloc(0x1000, sizeof(grouped_strings_avx512_t)); + + for (i = 0; i < 256; i++) + new->pattern_masks[i] = _mm512_set1_epi8(~0); + + new->found_masks = _mm512_set1_epi8(~0); + + new->R = _mm512_set1_epi8(~1); + + for (i = 0; i < 64; i++) + { + new->m[i] = 0; + + new->found_id[i] = INVALID_PATTERN_ID; + + } + + new->available = 64; + new->used = 0; + + /* Inscription */ + + *strings = realloc(*strings, ++(*count) * sizeof(grouped_strings_avx512_t *)); + + (*strings)[*count - 1] = new; + +} + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à manipuler. * +* context = contexte de l'analyse à mener. * +* plain = chaîne de caractères classique à intégrer. * +* plen = taille de cette chaîne. * +* * +* Description : Inscrit dans le moteur une chaîne de caractères à rechercher.* +* * +* Retour : Indice de résultats pour le motif. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static patid_t enroll_plain_pattern_avx512(GBitapBackend *backend, GScanContext *context, const bin_t *plain, size_t plen) +{ + patid_t result; /* Identifiant à retourner */ + grouped_strings_avx512_t ***strings; /* Groupe de chaînes visé */ + size_t *count; /* Taille de ce groupe */ + grouped_strings_avx512_t *last; /* Dernier groupe à remplir */ + size_t n; /* Indice dans le groupe */ + size_t i; /* Boucle de parcours */ + __m512i *letter; /* Lettre à marquer */ + + /* Sélection du groupe de travail adéquat */ + + strings = &backend->manager_avx512.strings_8; + count = &backend->manager_avx512.count_8; + + /* Préparation de la place nécessaire */ + + if (*count == 0) + { + extend_grouped_strings_avx512(strings, count); + + last = (*strings)[0]; + + } + + else + { + last = (*strings)[*count - 1]; + + if (last->used == last->available) + { + extend_grouped_strings_avx512(strings, count); + last = (*strings)[*count - 1]; + } + + } + + /* Intégration d'une nouvelle chaîne */ + + n = last->used++; + + last->m[n] = plen; + + result = g_scan_context_get_new_pattern_id(context); + + last->found_id[n] = result; + + ((uint8_t *)&last->found_masks)[n] = (1 << plen); + + for (i = 0; i < plen; i++) + { + letter = last->pattern_masks + plain[i]; + ((uint8_t *)letter)[n] &= ~(1 << i); + } + + return result; + +} + + + + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à manipuler. * +* context = lieu d'enregistrement des résultats. * +* content = données binaires à analyser. * +* * +* Description : Parcours un contenu binaire à la recherche de motifs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void run_scan_avx512(const GBitapBackend *backend, GScanContext *context, GBinContent *content) +{ + const group_manager_avx512_t *manager; /* Accès simplifié */ + phys_t dlen; /* Quantité de données */ + vmpa2t pos; /* Point de départ ciblé */ + const bin_t *data; /* Données à analyser */ + + //register __m512i zero asm("zmm19"); /* Constante 0 sur 512 bits */ + + //__m512i shift8_mask; /* Masque pour décalage manuel */ + + + size_t k; /* Boucle de parcours #1 */ + /*__attribute__((aligned(0x1000)))*/ grouped_strings_avx512_t group; /* Copie pour accès locaux */ + //void *grpptr; + //grouped_strings_avx512_t *_group; /* Copie pour accès locaux */ + + int ret; + + + register __m512i R asm("zmm28"); /* Résultats courants */ + register __m512i found_masks asm("zmm21"); /* Vérifications accélérées */ + + + register __mmask64 test_mask asm("k6"); + + + register const bin_t *iter asm("rsi"); + register const bin_t *maxiter/* asm("rdi")*/; + //phys_t i; /* Boucle de parcours #2 */ + + + //__m512i test; + + __mmask64 mask; /* Masque d'accès rapide */ + size_t j; /* Boucle de parcours #3 */ + + + /* Initialisations diverses */ + + manager = &backend->manager_avx512; + + dlen = g_binary_content_compute_size(content); + + g_binary_content_compute_start_pos(content, &pos); + data = g_binary_content_get_raw_access(content, &pos, dlen); + + + + /* Recherches des chaînes de moins de 8 caractères */ + + //asm volatile ("nop; nop; nop; nop; nop; nop; nop; "); + + //zero = _mm512_set1_epi8(0); + + //asm volatile ("nop; nop; nop; nop; nop; nop; nop; "); + + //shift8_mask = _mm512_set1_epi8(0x7f); + + + +#define WORK_ON_COPY + + for (k = 0; k < manager->count_8; k++) + { +#ifdef WORK_ON_COPY + memcpy(&group, manager->strings_8[k], sizeof(grouped_strings_avx512_t)); + +#else + + grpptr = alloca(sizeof(grouped_strings_avx512_t) + 0x1000); + + _group = grpptr + 0x1000 - (((unsigned long)grpptr) % 0x1000); + + //_group = manager->strings_8[k]; + + memcpy(_group, manager->strings_8[k], sizeof(grouped_strings_avx512_t)); + + ret = mlock(_group, sizeof(grouped_strings_avx512_t)); + + printf("ret = %d\n", ret); +#endif + + + + //printf(" --- group %p -- used: %zu (sz: %zu)\n", &group, group.used, sizeof(grouped_strings_avx512_t)); + //printf(" --- group.used: %zu (sz: %zu)\n", group.used, sizeof(grouped_strings_avx512_t)); + + + asm volatile + ( + /* + * R = _mm512_set1_epi8(~1); + * + */ + + "movabs $0xfefefefefefefefe, %%rax ; " + "vpbroadcastq %%rax, %[STATE] ; " + + "movabs $0xffffffffffffffff, %%rax ; " + "kmovq %%rax, %[KMASK] ; " + + /* + * + */ + + "vmovdqa64 %[FOUND_SRC], %[FOUND_DST] ; " + + : [STATE] "=v"(R), + [KMASK] "=Yk"(test_mask), + [FOUND_DST] "=v"(found_masks) +#ifdef WORK_ON_COPY + : [FOUND_SRC] "m"(group.found_masks) +#else + : [FOUND_SRC] "m"(_group->found_masks) +#endif + : "memory", "rax" + + ); + + + + + + + + //for (i = 0; i < dlen; i++) + + maxiter = data + dlen; + + for (iter = data; iter < maxiter; iter++) + { + + //printf("--- %llx <-> %c\n", (unsigned long long)(iter - data), *iter); + + + asm volatile goto + ( + /* + * R = _mm512_or_si512(R, group.pattern_masks[*iter]); + * + * Latency : 1-9 + * Throughput : 0.5 + * #Uops : 1-2 + * Port Usage : 1*p05+1*p23 + * + */ + + "vpord %[PATTERN], %[STATE], %[STATE] ; " + + /* + * R = _mm512_add_epi8(R, R); + * + * Latency : 1 + * Throughput : 0.5 + * #Uops : 1 + * Port Usage : 1*p05 + * + */ + + "vpaddb %[STATE], %[STATE], %[STATE] ; " + + /* + * mask = _mm512_test_epi8_mask(R, group.found_masks); + * + * Latency : 3 + * Throughput : 1 + * #Uops : 2 + * Port Usage : 1*p23+1*p5 + * + */ + + /****************************** + * Version 0 + + ******************/ + + //"vptestmb %[FOUND], %[STATE], %%k7 ; " + + /****************************** + * Version 1 + + "vmovdqa64 %[STATE], %%zmm12 ; " + + "vptestmb %[FOUND], %%zmm12, %%k7 ; " + + ******************/ + + /****************************** + * Version 2 + + "vpandd %[STATE], %[FOUND], %%zmm12 ; " + + "vpcmpneqb %[NUL], %%zmm12, %%k7 ; " + + ******************/ + + + "vmovdqa64 %[STATE], %%zmm12 ; " + + "vptestmb %[FOUND], %%zmm12, %%k7 ; " + + + "ktestq %[KMASK], %%k7 ; " + + "jc %l[next_iter] ; " + + + + + + /* + * (suite) + * + * Latency : 3 + * Throughput : 1 + * #Uops : 1 + * Port Usage : 1*p5 + * + */ + + "kmovq %%k7, %[MASK0] ; " + + //"vmovdqa64 %%zmm12, %[OUTPUT] ; " + + //"nop; nop; nop; nop; nop; nop; nop; nop; " + //"nop; nop; nop; nop; nop; nop; nop; nop; " + + : [STATE] "+v"(R), + //[OUTPUT] "=v"(test), + [MASK0] "=r"(mask) + //[NUL] "=v"(zero) +#ifdef WORK_ON_COPY + : [PATTERN] "m"(group.pattern_masks[*iter]), +#else + : [PATTERN] "m"(_group->pattern_masks[*iter]), +#endif + [FOUND] "v"(found_masks), + [KMASK] "Yk"(test_mask) + : "memory", "k7", "zmm12" + : next_iter + + ); + + + + + /* + printf(" found mask: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n", + ((uint8_t *)&group.found_masks)[0], + ((uint8_t *)&group.found_masks)[1], + ((uint8_t *)&group.found_masks)[2], + ((uint8_t *)&group.found_masks)[3], + ((uint8_t *)&group.found_masks)[4], + ((uint8_t *)&group.found_masks)[5], + ((uint8_t *)&group.found_masks)[6], + ((uint8_t *)&group.found_masks)[7]); + + + printf(" test: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n", + ((uint8_t *)&test)[0], + ((uint8_t *)&test)[1], + ((uint8_t *)&test)[2], + ((uint8_t *)&test)[3], + ((uint8_t *)&test)[4], + ((uint8_t *)&test)[5], + ((uint8_t *)&test)[6], + ((uint8_t *)&test)[7]); + + + printf(" -> mask: 0x%llx\n", (unsigned long long)mask); + */ + + +#ifdef WORK_ON_COPY + + //if (mask != 0xffffffffffffffffllu) + for (j = 0; j < group.used; j++) + { + if ((mask & 0x1) == 0) + { + //assert((i + 1) >= group.m[j]); + + g_scan_context_register_atom_match(context, + group.found_id[j], + (iter - data) + 1 - group.m[j]); + + } + + mask >>= 1; + + } + +#else + +# error "WEFEF" + + if (mask != 0xffffffffffffffffllu) + for (j = 0; j < _group->used; j++) + { + if ((mask & 0x1) == 0) + { + //assert((i + 1) >= group.m[j]); + + g_scan_context_register_atom_match(context, + _group->found_id[j], + (iter - data) + 1 - _group->m[j]); + + } + + mask >>= 1; + + } + +#endif + + + next_iter: + + //; + + //iter++; + + } + + } + +} + + + + + + + + + + + +#if 0 + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à manipuler. * +* context = lieu d'enregistrement des résultats. * +* content = données binaires à analyser. * +* * +* Description : Parcours un contenu binaire à la recherche de motifs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void run_scan_avx512____good_asm_perfs(const GBitapBackend *backend, GScanContext *context, GBinContent *content) +{ + const group_manager_avx512_t *manager; /* Accès simplifié */ + phys_t dlen; /* Quantité de données */ + vmpa2t pos; /* Point de départ ciblé */ + const bin_t *data; /* Données à analyser */ + + + //__m512i shift8_mask; /* Masque pour décalage manuel */ + + + size_t k; /* Boucle de parcours #1 */ + grouped_strings_avx512_t group; /* Copie pour accès locaux */ + + register __m512i found_masks asm("zmm21"); /* Vérifications accélérées */ + + + //register volatile __m512i zero/* asm("zmm19")*/; /* Constante 0 sur 512 bits */ + register __m512i R asm("zmm28"); /* Résultats courants */ + + //int counter; + + const bin_t *iter; + const bin_t *maxiter; + //phys_t i; /* Boucle de parcours #2 */ + + + __m512i test; + + __mmask64 mask; /* Masque d'accès rapide */ + size_t j; /* Boucle de parcours #3 */ + + + //register __m512i z30 asm("zmm30"); + + + //return; + + + //counter = 0; + + //return; + + /* Initialisations diverses */ + + manager = &backend->manager_avx512; + + dlen = g_binary_content_compute_size(content); + + g_binary_content_compute_start_pos(content, &pos); + data = g_binary_content_get_raw_access(content, &pos, dlen); + + /* Recherches des chaînes de moins de 8 caractères */ + + printf(" --- manager512->count_8: %zu\n", manager->count_8); + + asm volatile ("nop; nop; nop; nop; nop; nop; nop; "); + + //zero = _mm512_set1_epi8(0); + + asm volatile ("nop; nop; nop; nop; nop; nop; nop; "); + + //shift8_mask = _mm512_set1_epi8(0x7f); + + + for (k = 0; k < manager->count_8; k++) + { + memcpy(&group, manager->strings_8[k], sizeof(grouped_strings_avx512_t)); + + + + + //printf(" --- group %p -- used: %zu (sz: %zu)\n", &group, group.used, sizeof(grouped_strings_avx512_t)); + //printf(" --- group.used: %zu (sz: %zu)\n", group.used, sizeof(grouped_strings_avx512_t)); + + + asm volatile + ( + /* + * R = _mm512_set1_epi8(~1); + * + */ + + "movabs $0xfefefefefefefefe, %%rax ; " + "vpbroadcastq %%rax, %[STATE] ; " + + /* + * + */ + + "vmovdqa64 %[FOUND_SRC], %[FOUND_DST] ; " + + : [STATE] "=v"(R), + [FOUND_DST] "=v"(found_masks) + : [FOUND_SRC] "m"(group.found_masks) + : "memory", "rax" + + ); + + + + + + + + //for (i = 0; i < dlen; i++) + + maxiter = data + dlen; + + for (iter = data; iter < maxiter; iter++) + { + + //printf("--- %llx <-> %c\n", (unsigned long long)(iter - data), *iter); + + + asm volatile + ( + + /* + * R = _mm512_or_si512(R, group.pattern_masks[*iter]); + * + * Latency : 1-9 + * Throughput : 0.5 + * #Uops : 1-2 + * Port Usage : 1*p05+1*p23 + * + */ + + "vpord %[PATTERN], %[STATE], %[STATE] ; " + + /* + * R = _mm512_add_epi8(R, R); + * + * Latency : 1 + * Throughput : 0.5 + * #Uops : 1 + * Port Usage : 1*p05 + * + */ + + "vpaddb %[STATE], %[STATE], %[STATE] ; " + + /* + * mask = _mm512_test_epi8_mask(R, group.found_masks); + * + * Latency : 3 + * Throughput : 1 + * #Uops : 2 + * Port Usage : 1*p23+1*p5 + * + */ + + /****************************** + * Version 0 + + ******************/ + + "vptestmb %[FOUND], %[STATE], %%k7 ; " + + /****************************** + * Version 1 + + "vmovdqa64 %[STATE], %%zmm12 ; " + + "vptestmb %[FOUND], %%zmm12, %%k0 ; " + + ******************/ + + /****************************** + * Version 2 + + "vpandd %[STATE], %[FOUND], %%zmm12 ; " + + "vpcmpneqb %[NUL], %%zmm12, %%k7 ; " + + ******************/ + + /* + * (suite) + * + * Latency : 3 + * Throughput : 1 + * #Uops : 1 + * Port Usage : 1*p5 + * + */ + + "kmovq %%k7, %[MASK0] ; " + + //"vmovdqa64 %%zmm12, %[OUTPUT] ; " + + //"nop; nop; nop; nop; nop; nop; nop; nop; " + //"nop; nop; nop; nop; nop; nop; nop; nop; " + + : [STATE] "+v"(R), + [OUTPUT] "=v"(test), + [MASK0] "=r"(mask)/*, + [NUL] "+v"(zero)*/ + : [PATTERN] "v"(group.pattern_masks[*iter]), + [FOUND] "v"(found_masks) + : "memory", "k0", "zmm12" + + ); + + + + + /* + printf(" found mask: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n", + ((uint8_t *)&group.found_masks)[0], + ((uint8_t *)&group.found_masks)[1], + ((uint8_t *)&group.found_masks)[2], + ((uint8_t *)&group.found_masks)[3], + ((uint8_t *)&group.found_masks)[4], + ((uint8_t *)&group.found_masks)[5], + ((uint8_t *)&group.found_masks)[6], + ((uint8_t *)&group.found_masks)[7]); + + + printf(" test: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n", + ((uint8_t *)&test)[0], + ((uint8_t *)&test)[1], + ((uint8_t *)&test)[2], + ((uint8_t *)&test)[3], + ((uint8_t *)&test)[4], + ((uint8_t *)&test)[5], + ((uint8_t *)&test)[6], + ((uint8_t *)&test)[7]); + + + printf(" -> mask: 0x%llx\n", (unsigned long long)mask); + */ + +#if 0 + + /* + printf(" R: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n", + ((uint8_t *)&R)[0], + ((uint8_t *)&R)[1], + ((uint8_t *)&R)[2], + ((uint8_t *)&R)[3], + ((uint8_t *)&R)[4], + ((uint8_t *)&R)[5], + ((uint8_t *)&R)[6], + ((uint8_t *)&R)[7]); + + printf(" found mask: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n", + ((uint8_t *)&group.found_masks)[0], + ((uint8_t *)&group.found_masks)[1], + ((uint8_t *)&group.found_masks)[2], + ((uint8_t *)&group.found_masks)[3], + ((uint8_t *)&group.found_masks)[4], + ((uint8_t *)&group.found_masks)[5], + ((uint8_t *)&group.found_masks)[6], + ((uint8_t *)&group.found_masks)[7]); + */ + + /* + + printf(" test: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n", + ((uint8_t *)&test)[0], + ((uint8_t *)&test)[1], + ((uint8_t *)&test)[2], + ((uint8_t *)&test)[3], + ((uint8_t *)&test)[4], + ((uint8_t *)&test)[5], + ((uint8_t *)&test)[6], + ((uint8_t *)&test)[7]); + + */ + +#endif + + + + + +# define TEST_MASK 0xffffffffffffffffllu +# define TEST_BIT 0 + + + //printf("mask: %llx\n", (unsigned long long)mask); + + + if (mask != TEST_MASK) + { + //printf("mask: %llx\n", (unsigned long long)mask); + + //counter++; + //printf("Ouhc: %p - %x\n", &group, *((uint8_t *)&mask)); + //printf("Ouhc: %x\n", 1); + //asm("vzeroupper;"); + //printf("Ouhc: %hhx\n", R[0]); + for (j = 0; j < group.used; j++) + { + if ((mask & 0x1) == TEST_BIT) + { + //assert((i + 1) >= group.m[j]); + + //printf(">> FOUND %zu @ %x !!!!!!!!!!!!!!\n", j, (unsigned int)i + 1); + printf(">> FOUND %zu @ %x !!!!!!!!!!!!!!\n", j, (unsigned int)(iter - data) + 1); + + + } + + mask >>= 1; + //printf("> mask: %llx\n", (unsigned long long)mask); + + } + + + + } + + + + } + + //printf("%hhx\n", ((uint8_t *)&R)[0], ((uint8_t *)&mask)[0]); + + } + + //printf("counter=%d\n", counter); + + +} + + + + +/****************************************************************************** +* * +* Paramètres : backend = moteur de recherche à manipuler. * +* context = lieu d'enregistrement des résultats. * +* content = données binaires à analyser. * +* * +* Description : Parcours un contenu binaire à la recherche de motifs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void run_scan_avx512_best_test(const GBitapBackend *backend, GScanContext *context, GBinContent *content) +{ + const group_manager_avx512_t *manager; /* Accès simplifié */ + phys_t dlen; /* Quantité de données */ + vmpa2t pos; /* Point de départ ciblé */ + const bin_t *data; /* Données à analyser */ + + + //__m512i shift8_mask; /* Masque pour décalage manuel */ + + + size_t k; /* Boucle de parcours #1 */ + grouped_strings_avx512_t group; /* Copie pour accès locaux */ + + //register __m512i zero; /* Constante 0 sur 512 bits */ + register __m512i R; /* Résultats courants */ + + //int counter; + + const bin_t *iter; + const bin_t *maxiter; + //phys_t i; /* Boucle de parcours #2 */ + + + //__m512i test; + + __mmask64 mask; /* Masque d'accès rapide */ + size_t j; /* Boucle de parcours #3 */ + + //return; + + + //counter = 0; + + //return; + + /* Initialisations diverses */ + + manager = &backend->manager_avx512; + + dlen = g_binary_content_compute_size(content); + + g_binary_content_compute_start_pos(content, &pos); + data = g_binary_content_get_raw_access(content, &pos, dlen); + + /* Recherches des chaînes de moins de 8 caractères */ + + printf(" --- manager512->count_8: %zu\n", manager->count_8); + + //zero = _mm512_set1_epi8(0); + + //shift8_mask = _mm512_set1_epi8(0x7f); + + + + for (k = 0; k < manager->count_8; k++) + { + memcpy(&group, manager->strings_8[k], sizeof(grouped_strings_avx512_t)); + + //printf(" --- group %p -- used: %zu (sz: %zu)\n", &group, group.used, sizeof(grouped_strings_avx512_t)); + //printf(" --- group.used: %zu (sz: %zu)\n", group.used, sizeof(grouped_strings_avx512_t)); + + R = _mm512_set1_epi8(~1); + + + + /* vpord zmm, zmm, zmm : latence 1, 1*p05 */ + //R = _mm512_or_si512(R, group.pattern_masks[data[0]]); + + //for (i = 0; i < dlen; i++) + + maxiter = data + dlen; + + for (iter = data; iter < maxiter; iter++) + { + + //printf("--- %llx <-> %c\n", (unsigned long long)(iter - data), *iter); + + + //R = _mm512_or_si512(R, group.pattern_masks[data[i]]); + R = _mm512_or_si512(R, group.pattern_masks[*iter]); + + +#if 1 + /* vpaddb zmm, zmm, zmm : latence 1, 1*p05 */ + R = _mm512_add_epi8(R, R); +#else + /* vpandd zmm, zmm, zmm : latence 1, 1*p5 */ + R = _mm512_and_si512(R, shift8_mask); + /* vpslldq zmm, zmm, imm8 : latence 1, 1*p5 */ + R = _mm512_bslli_epi128(R, 1); + +#endif + + /* + printf(" R: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n", + ((uint8_t *)&R)[0], + ((uint8_t *)&R)[1], + ((uint8_t *)&R)[2], + ((uint8_t *)&R)[3], + ((uint8_t *)&R)[4], + ((uint8_t *)&R)[5], + ((uint8_t *)&R)[6], + ((uint8_t *)&R)[7]); + + printf(" found mask: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n", + ((uint8_t *)&group.found_masks)[0], + ((uint8_t *)&group.found_masks)[1], + ((uint8_t *)&group.found_masks)[2], + ((uint8_t *)&group.found_masks)[3], + ((uint8_t *)&group.found_masks)[4], + ((uint8_t *)&group.found_masks)[5], + ((uint8_t *)&group.found_masks)[6], + ((uint8_t *)&group.found_masks)[7]); + */ + +#if 1 + /* vptestmb k, zmm, zmm : latence 3, 1*p5 */ + mask = _mm512_test_epi8_mask(R, group.found_masks); + + + //test = _mm512_add_epi64(R, zero); + + //mask = _mm512_test_epi8_mask(test, group.found_masks); + + + + + +# define TEST_MASK 0xffffffffffffffffllu +# define TEST_BIT 0 + + /* comparaison : != */ + + +#else + /* vpandd zmm, zmm, zmm : latence 1, 1*p05 */ + test = _mm512_and_si512(R, group.found_masks); + + + printf(" test: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n", + ((uint8_t *)&test)[0], + ((uint8_t *)&test)[1], + ((uint8_t *)&test)[2], + ((uint8_t *)&test)[3], + ((uint8_t *)&test)[4], + ((uint8_t *)&test)[5], + ((uint8_t *)&test)[6], + ((uint8_t *)&test)[7]); + + /* vpmovb2m k, zmm : latence 3 (au lieu de 1 !?), 1*p0 */ + //mask = _mm512_movepi8_mask(test); + +# define TEST_MASK 0 +# define TEST_BIT 0 + + + //test = _mm512_popcnt_epi8(test); + +#endif + + + //printf(" final mask: %16llx\n", (unsigned long long)mask); + + + + //R = _mm512_or_si512(R, group.pattern_masks[data[i + 1]]); + +#if 1 + + + if (mask != TEST_MASK) + { + //counter++; + //printf("Ouhc: %p - %x\n", &group, *((uint8_t *)&mask)); + printf("Ouhc: %p\n", &group); + //printf("Ouhc: %hhx\n", R[0]); + for (j = 0; j < group.used; j++) + { + if ((mask & 0x1) == TEST_BIT) + { + //assert((i + 1) >= group.m[j]); + + //printf(">> FOUND %zu @ %x !!!!!!!!!!!!!!\n", j, (unsigned int)i + 1); + printf(">> FOUND %zu @ %x !!!!!!!!!!!!!!\n", j, (unsigned int)(iter - data) + 1); + + + } + + mask >>= 1; + + } + + + + } + + +#else + + if (_mm512_reduce_or_epi64(test) != 0) + { + for (j = 0; j < group.used; j++) + { + if (((uint8_t *)&test)[j] == 0) + { + //assert((i + 1) >= group.m[j]); + + printf(">> FOUND %zu @ %x !!!!!!!!!!!!!!\n", j, (unsigned int)i + 1); + + } + + + } + + } + +#endif + + + } + + //printf("%hhx\n", ((uint8_t *)&R)[0], ((uint8_t *)&mask)[0]); + + } + + //printf("counter=%d\n", counter); + + +} + + + + + +static void run_scan_avx512__saved(const GBitapBackend *backend, GScanContext *context, GBinContent *content) +{ + const group_manager_avx512_t *manager; /* Accès simplifié */ + phys_t dlen; /* Quantité de données */ + vmpa2t pos; /* Point de départ ciblé */ + const bin_t *data; /* Données à analyser */ + + + __m512i shift8_mask; /* Masque pour décalage manuel */ + + + size_t k; /* Boucle de parcours #1 */ + grouped_strings_avx512_t group; /* Copie pour accès locaux */ + + + __m512i R; /* Résultats courants */ + + //int counter; + + phys_t i; /* Boucle de parcours #2 */ + + + __m512i test; + + __mmask64 mask; /* Masque d'accès rapide */ + size_t j; /* Boucle de parcours #3 */ + + + + //counter = 0; + + //return; + + /* Initialisations diverses */ + + manager = &backend->manager_avx512; + + dlen = g_binary_content_compute_size(content); + + g_binary_content_compute_start_pos(content, &pos); + data = g_binary_content_get_raw_access(content, &pos, dlen); + + /* Recherches des chaînes de moins de 8 caractères */ + + printf(" --- manager512->count_8: %zu\n", manager->count_8); + + + + shift8_mask = _mm512_set1_epi8(0x7f); + + + for (k = 0; k < manager->count_8; k++) + { + memcpy(&group, manager->strings_8[k], sizeof(grouped_strings_avx512_t)); + + //printf(" --- group %p -- used: %zu (sz: %zu)\n", &group, group.used, sizeof(grouped_strings_avx512_t)); + //printf(" --- group.used: %zu (sz: %zu)\n", group.used, sizeof(grouped_strings_avx512_t)); + + R = _mm512_set1_epi8(~1); + + /* vpord zmm, zmm, zmm : latence 1, 1*p05 */ + R = _mm512_or_si512(R, group.pattern_masks[data[0]]); + + for (i = 0; i < dlen; i++) + { + + /* + printf("--- %llx <-> %c\n", (unsigned long long)i, data[i]); + + printf(" R: %hhx %hhx %hhx %hhx\n", + ((uint8_t *)&R)[0], + ((uint8_t *)&R)[1], + ((uint8_t *)&R)[2], + ((uint8_t *)&R)[3]); + + printf(" mask: %hhx %hhx %hhx %hhx\n", + ((uint8_t *)&group.pattern_masks[data[i]])[0], + ((uint8_t *)&group.pattern_masks[data[i]])[1], + ((uint8_t *)&group.pattern_masks[data[i]])[2], + ((uint8_t *)&group.pattern_masks[data[i]])[3]); + */ + + //R = _mm512_or_si512(R, group.pattern_masks[data[i]]); + + /* + printf(" R: %hhx %hhx %hhx %hhx\n", + ((uint8_t *)&R)[0], + ((uint8_t *)&R)[1], + ((uint8_t *)&R)[2], + ((uint8_t *)&R)[3]); + */ + +#if 1 + /* vpaddb zmm, zmm, zmm : latence 1, 1*p05 */ + R = _mm512_add_epi8(R, R); +#else + /* vpandd zmm, zmm, zmm : latence 1, 1*p5 */ + R = _mm512_and_si512(R, shift8_mask); + /* vpslldq zmm, zmm, imm8 : latence 1, 1*p5 */ + R = _mm512_bslli_epi128(R, 1); + +#endif + +#if 1 + /* vptestmb k, zmm, zmm : latence 3, 1*p5 */ + mask = _mm512_test_epi8_mask(R, group.found_masks); +#else + test = _mm512_and_si512(R, group.found_masks); + test = _mm512_popcnt_epi8(test); + +#endif + + /* + printf(" found mask: %hhx %hhx %hhx %hhx\n", + ((uint8_t *)&group.found_masks)[0], + ((uint8_t *)&group.found_masks)[1], + ((uint8_t *)&group.found_masks)[2], + ((uint8_t *)&group.found_masks)[3]); + + printf(" final mask: %16llx\n", (unsigned long long)mask); + */ + + + R = _mm512_or_si512(R, group.pattern_masks[data[i + 1]]); + +#if 1 + + if (mask != 0xffffffffffffffffllu) + { + //counter++; + //printf("Ouhc: %p - %x\n", &group, *((uint8_t *)&mask)); + //printf("Ouhc: %p\n", &group); + for (j = 0; j < group.used; j++) + { + if ((mask & 0x1) == 0) + { + //assert((i + 1) >= group.m[j]); + + printf(">> FOUND %zu @ %x !!!!!!!!!!!!!!\n", j, (unsigned int)i + 1); + + + } + + mask >>= 1; + + } + + + + } + + +#else + + if (_mm512_reduce_or_epi64(test) != 0) + { + for (j = 0; j < group.used; j++) + { + if (((uint8_t *)&test)[j] == 0) + { + //assert((i + 1) >= group.m[j]); + + printf(">> FOUND %zu @ %x !!!!!!!!!!!!!!\n", j, (unsigned int)i + 1); + + } + + + } + + } + +#endif + + + } + + //printf("%hhx\n", ((uint8_t *)&R)[0], ((uint8_t *)&mask)[0]); + + } + + //printf("counter=%d\n", counter); + + +} +#endif + + + diff --git a/src/analysis/scan/patterns/backends/bitap.h b/src/analysis/scan/patterns/backends/bitap.h new file mode 100644 index 0000000..1cb384c --- /dev/null +++ b/src/analysis/scan/patterns/backends/bitap.h @@ -0,0 +1,59 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bitap.h - prototypes pour la méthode de recherche basée sur l'algorithme Bitap + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_H +#define _ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_H + + +#include <glib-object.h> +#include <stdbool.h> + + +#include "../backend.h" + + + +#define G_TYPE_BITAP_BACKEND g_bitap_backend_get_type() +#define G_BITAP_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BITAP_BACKEND, GBitapBackend)) +#define G_IS_BITAP_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BITAP_BACKEND)) +#define G_BITAP_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BITAP_BACKEND, GBitapBackendClass)) +#define G_IS_BITAP_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BITAP_BACKEND)) +#define G_BITAP_BACKEND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BITAP_BACKEND, GBitapBackendClass)) + + +/* Méthode de recherche basée sur l'algorithme Bitap (instance) */ +typedef struct _GBitapBackend GBitapBackend; + +/* Méthode de recherche basée sur l'algorithme Bitap (classe) */ +typedef struct _GBitapBackendClass GBitapBackendClass; + + +/* Indique le type défini pour un moteur de recherche pour données. */ +GType g_bitap_backend_get_type(void); + +/* Crée une méthode de recherche basée sur l'algorithme Bitap. */ +GEngineBackend *g_bitap_backend_new(void); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_H */ diff --git a/src/analysis/scan/patterns/token-int.h b/src/analysis/scan/patterns/token-int.h new file mode 100644 index 0000000..a9667c9 --- /dev/null +++ b/src/analysis/scan/patterns/token-int.h @@ -0,0 +1,61 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * token-int.h - prototypes internes pour les bribes de recherche textuelle + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKEN_INT_H +#define _ANALYSIS_SCAN_PATTERNS_TOKEN_INT_H + + +#include "token.h" + + +#include "../pattern-int.h" + + + +/* Inscrit la définition d'un motif dans un moteur de recherche. */ +typedef bool (* enroll_token_fc) (GStringToken *, GScanContext *, GEngineBackend *, size_t); + +/* Transforme les correspondances locales en trouvailles. */ +typedef void (* check_token_fc) (const GStringToken *, GScanContext *, GBinContent *, pending_matches_t *); + + +/* Encadrement d'une bribe de recherche textuelle (instance) */ +struct _GStringToken +{ + GSearchPattern parent; /* A laisser en premier */ + +}; + +/* Encadrement d'une bribe de recherche textuelle (classe) */ +struct _GStringTokenClass +{ + GSearchPatternClass parent; /* A laisser en premier */ + + enroll_token_fc enroll; /* Inscription d'un motif */ + check_token_fc check; /* Conversion en trouvailles */ + +}; + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKEN_INT_H */ diff --git a/src/analysis/scan/patterns/token.c b/src/analysis/scan/patterns/token.c new file mode 100644 index 0000000..d8a5cbc --- /dev/null +++ b/src/analysis/scan/patterns/token.c @@ -0,0 +1,193 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * token.c - bribes de recherche textuelle + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "token.h" + + +#include <assert.h> + + +#include "token-int.h" + + + +/* Initialise la classe des bribes de recherche textuelle. */ +static void g_string_token_class_init(GStringTokenClass *); + +/* Initialise une instance de bribe de recherche textuelle. */ +static void g_string_token_init(GStringToken *); + +/* Supprime toutes les références externes. */ +static void g_string_token_dispose(GStringToken *); + +/* Procède à la libération totale de la mémoire. */ +static void g_string_token_finalize(GStringToken *); + + + +/* Indique le type défini pour une bribe de recherche textuelle. */ +G_DEFINE_TYPE(GStringToken, g_string_token, G_TYPE_SEARCH_PATTERN); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des bribes de recherche textuelle. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_string_token_class_init(GStringTokenClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GSearchPatternClass *pattern; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_string_token_dispose; + object->finalize = (GObjectFinalizeFunc)g_string_token_finalize; + + 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); + +} + + +/****************************************************************************** +* * +* Paramètres : token = instance à initialiser. * +* * +* Description : Initialise une instance de bribe de recherche textuelle. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_string_token_init(GStringToken *token) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : token = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_string_token_dispose(GStringToken *token) +{ + G_OBJECT_CLASS(g_string_token_parent_class)->dispose(G_OBJECT(token)); + +} + + +/****************************************************************************** +* * +* Paramètres : token = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_string_token_finalize(GStringToken *token) +{ + G_OBJECT_CLASS(g_string_token_parent_class)->finalize(G_OBJECT(token)); + +} + + +/****************************************************************************** +* * +* Paramètres : token = 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_string_token_enroll(GStringToken *token, GScanContext *context, GEngineBackend *backend, size_t maxsize) +{ + bool result; /* Statut à retourner */ + GStringTokenClass *class; /* Classe de l'instance */ + + assert(g_engine_backend_get_atom_max_size(backend) == maxsize); + + class = G_STRING_TOKEN_GET_CLASS(token); + + result = class->enroll(token, context, backend, maxsize); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : token = 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 : - * +* * +******************************************************************************/ + +void g_string_token_check(const GStringToken *token, GScanContext *context, GBinContent *content, pending_matches_t *matches) +{ + GStringTokenClass *class; /* Classe de l'instance */ + + class = G_STRING_TOKEN_GET_CLASS(token); + + class->check(token, context, content, matches); + +} diff --git a/src/analysis/scan/patterns/token.h b/src/analysis/scan/patterns/token.h new file mode 100644 index 0000000..c1cb173 --- /dev/null +++ b/src/analysis/scan/patterns/token.h @@ -0,0 +1,62 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * token.h - prototypes pour les bribes de recherche textuelle + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKEN_H +#define _ANALYSIS_SCAN_PATTERNS_TOKEN_H + + +#include <glib-object.h> + + +#include "backend.h" +#include "../matches/pending.h" + + + +#define G_TYPE_STRING_TOKEN g_string_token_get_type() +#define G_STRING_TOKEN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_STRING_TOKEN, GStringToken)) +#define G_IS_STRING_TOKEN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_STRING_TOKEN)) +#define G_STRING_TOKEN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_STRING_TOKEN, GStringTokenClass)) +#define G_IS_STRING_TOKEN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_STRING_TOKEN)) +#define G_STRING_TOKEN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_STRING_TOKEN, GStringTokenClass)) + + +/* Encadrement d'une bribe de recherche textuelle (instance) */ +typedef struct _GStringToken GStringToken; + +/* Encadrement d'une bribe de recherche textuelle (classe) */ +typedef struct _GStringTokenClass GStringTokenClass; + + +/* Indique le type défini pour une bribe de recherche textuelle. */ +GType g_string_token_get_type(void); + +/* Inscrit la définition d'un motif dans un moteur de recherche. */ +bool g_string_token_enroll(GStringToken *, GScanContext *, GEngineBackend *, size_t); + +/* Transforme les correspondances locales en trouvailles. */ +void g_string_token_check(const GStringToken *, GScanContext *, GBinContent *, pending_matches_t *); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKEN_H */ diff --git a/src/analysis/scan/patterns/tokens/Makefile.am b/src/analysis/scan/patterns/tokens/Makefile.am new file mode 100644 index 0000000..00cff2a --- /dev/null +++ b/src/analysis/scan/patterns/tokens/Makefile.am @@ -0,0 +1,13 @@ + +noinst_LTLIBRARIES = libanalysisscanpatternstokens.la + + +libanalysisscanpatternstokens_la_SOURCES = \ + plain.h plain.c + +libanalysisscanpatternstokens_la_CFLAGS = $(LIBGOBJ_CFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%) + +dev_HEADERS = $(libanalysisscanpatternstokens_la_SOURCES:%c=) diff --git a/src/analysis/scan/patterns/tokens/plain.c b/src/analysis/scan/patterns/tokens/plain.c new file mode 100644 index 0000000..9eb731e --- /dev/null +++ b/src/analysis/scan/patterns/tokens/plain.c @@ -0,0 +1,374 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain.c - 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 <http://www.gnu.org/licenses/>. + */ + + +#include "plain.h" + + +#include <malloc.h> +#include <string.h> + + +#include "../token-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); + +/* Initialise une instance de recherche de texte brut. */ +static void g_plain_bytes_init(GPlainBytes *); + +/* Supprime toutes les références externes. */ +static void g_plain_bytes_dispose(GPlainBytes *); + +/* Procède à la libération totale de la mémoire. */ +static void g_plain_bytes_finalize(GPlainBytes *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Inscrit la définition d'un motif dans un moteur de recherche. */ +static bool g_plain_bytes_enroll(GPlainBytes *, GScanContext *, GEngineBackend *, size_t); + +/* Transforme les correspondances locales en trouvailles. */ +static void g_plain_bytes_check(const GPlainBytes *, 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(GPlainBytes, g_plain_bytes, G_TYPE_STRING_TOKEN); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des recherches de texte brut. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_plain_bytes_class_init(GPlainBytesClass *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_plain_bytes_dispose; + object->finalize = (GObjectFinalizeFunc)g_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); + + token = G_STRING_TOKEN_CLASS(klass); + + token->enroll = (enroll_token_fc)g_plain_bytes_enroll; + token->check = (check_token_fc)g_plain_bytes_check; + +} + + +/****************************************************************************** +* * +* Paramètres : pattern = instance à initialiser. * +* * +* Description : Initialise une instance de recherche de texte brut. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_plain_bytes_init(GPlainBytes *bytes) +{ + bytes->raw = NULL; + bytes->allocated = 0; + bytes->used = 0; + + bytes->atom_pos = 0; + bytes->atom_len = 0; + bytes->atom_rem = 0; + bytes->pid = INVALID_PATTERN_ID; + +} + + +/****************************************************************************** +* * +* Paramètres : bytes = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_plain_bytes_dispose(GPlainBytes *bytes) +{ + G_OBJECT_CLASS(g_plain_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_plain_bytes_finalize(GPlainBytes *bytes) +{ + if (bytes->raw != NULL) + free(bytes->raw); + + G_OBJECT_CLASS(g_plain_bytes_parent_class)->finalize(G_OBJECT(bytes)); + +} + + +/****************************************************************************** +* * +* Paramètres : text = texte brut à rechercher. * +* len = longueur de ce texte. * +* * +* Description : Construit un gestionnaire de recherche de texte brut. * +* * +* Retour : Mécanismes mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GSearchPattern *g_plain_bytes_new(const uint8_t *raw, size_t len) +{ + GPlainBytes *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_PLAIN_BYTES, NULL); + + result->raw = malloc(len); + result->allocated = len; + result->used = len; + + memcpy(result->raw, raw, len); + + return G_SEARCH_PATTERN(result); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* 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_plain_bytes_enroll(GPlainBytes *bytes, GScanContext *context, GEngineBackend *backend, size_t maxsize) +{ + bool result; /* Statut à retourner */ + + + result = true; + + + + bytes->atom_pos = 0; + + if (bytes->used > maxsize) // Attention à la position de départ (à retrancher) ! + { + bytes->atom_len = maxsize; + bytes->atom_rem = bytes->used - maxsize; + } + else + { + bytes->atom_len = bytes->used; + bytes->atom_rem = 0; + } + + + bytes->pid = g_engine_backend_enroll_plain_pattern(backend, context, bytes->raw, bytes->atom_len); + + + + result = (bytes->pid != INVALID_PATTERN_ID); + + + + 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_plain_bytes_check(const GPlainBytes *bytes, GScanContext *context, GBinContent *content, pending_matches_t *matches) +{ + bool initialized; /* Initialisation du suivi ? */ + 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 */ + 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++) + { + start = found[i] - bytes->atom_pos; + + /* Recherche d'un point de départ attendu et conforme ? */ + + if (initialized) + if (!find_target_in_pending_matches(matches, start, &mindex)) + continue; + + init_vmpa(&pos, start, VMPA_NO_VIRTUAL); + + /* Validation du contenu avant l'atome */ + + if (bytes->atom_pos > 0) + { + 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; + + } + + /* Validation du contenu après l'atome */ + + if (bytes->atom_rem > 0) + { + advance_vmpa(&pos, bytes->atom_len); + + ptr = g_binary_content_get_raw_access(content, &pos, bytes->atom_rem); + + ret = memcmp(bytes->raw + bytes->atom_pos + bytes->atom_len, ptr, bytes->atom_rem); + if (ret != 0) goto exclude_false_positive; + + } + + /* Mémorisation de la correspondance */ + + if (initialized) + extend_pending_matches(matches, mindex, bytes->used); + else + add_pending_matches(matches, start, bytes->used); + + continue; + + exclude_false_positive: + + if (initialized) + remove_pending_matches(matches, mindex); + + } + + set_pending_matches_initialized(matches); + +} diff --git a/src/analysis/scan/patterns/tokens/plain.h b/src/analysis/scan/patterns/tokens/plain.h new file mode 100644 index 0000000..de1d4ec --- /dev/null +++ b/src/analysis/scan/patterns/tokens/plain.h @@ -0,0 +1,67 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain.h - prototypes 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_H +#define _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_H + + +#include <glib-object.h> +#include <stdint.h> + + +#include "../../pattern.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)) + + +/* Représentation d'une suite d'octets à retrouver (instance) */ +typedef struct _GPlainBytes GPlainBytes; + +/* Représentation d'une suite d'octets à retrouver (classe) */ +typedef struct _GPlainBytesClass GPlainBytesClass; + + +/* Propriétés d'un élément textuel à rechercher */ +typedef enum _StringTokenAttrib +{ + STP_CASE_INSENSITIVE, + +} StringTokenAttrib; + + +/* Indique le type défini pour une suite d'octets à retrouver dans un binaire. */ +GType g_plain_bytes_get_type(void); + +/* Construit un gestionnaire de recherche de texte brut. */ +GSearchPattern *g_plain_bytes_new(const uint8_t *, size_t); + + + +#endif /* _ANALYSIS_SCAN_PATTERNS_TOKENS_PLAIN_H */ diff --git a/src/analysis/scan/rule-int.h b/src/analysis/scan/rule-int.h new file mode 100644 index 0000000..b43c20b --- /dev/null +++ b/src/analysis/scan/rule-int.h @@ -0,0 +1,59 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * rule-int.h - prototypes internes pour la gestion d'une règle de détection par motifs + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_RULE_INT_H +#define _ANALYSIS_SCAN_RULE_INT_H + + +#include "rule.h" + + + +#define PATTERN_ALLOC_SIZE 20 + + +/* Représentation d'une règle de détection statique (instance) */ +struct _GScanRule +{ + GObject parent; /* A laisser en premier */ + + char *name; /* Désignation de la règle */ + + 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 */ + + GScanExpression *condition; /* Condition de correspondance */ + +}; + +/* Représentation d'une règle de détection statique (classe) */ +struct _GScanRuleClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _ANALYSIS_SCAN_RULE_INT_H */ diff --git a/src/analysis/scan/rule.c b/src/analysis/scan/rule.c new file mode 100644 index 0000000..6c771fb --- /dev/null +++ b/src/analysis/scan/rule.c @@ -0,0 +1,383 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * rule.c - parcours de contenus à la recherche de motifs + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "rule.h" + + +#include <assert.h> +#include <strings.h> + + +#include "rule-int.h" +#include "matches/bytes.h" +#include "patterns/token.h" + + + +/* Initialise la classe des règles de détection statique. */ +static void g_scan_rule_class_init(GScanRuleClass *); + +/* Initialise une instance de règle de détection statique. */ +static void g_scan_rule_init(GScanRule *); + +/* Supprime toutes les références externes. */ +static void g_scan_rule_dispose(GScanRule *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_rule_finalize(GScanRule *); + + + +/* Indique le type défini pour une règle de détection par motifs. */ +G_DEFINE_TYPE(GScanRule, g_scan_rule, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des règles de détection statique. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_rule_class_init(GScanRuleClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_rule_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_rule_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = instance à initialiser. * +* * +* Description : Initialise une instance de règle de détection statique. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_rule_init(GScanRule *rule) +{ + rule->name = NULL; + + rule->data_locals = NULL; + rule->data_allocated = 0; + rule->data_used = 0; + + rule->condition = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_rule_dispose(GScanRule *rule) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < rule->data_used; i++) + g_clear_object(&rule->data_locals[i]); + + g_clear_object(&rule->condition); + + G_OBJECT_CLASS(g_scan_rule_parent_class)->dispose(G_OBJECT(rule)); + +} + + +/****************************************************************************** +* * +* Paramètres : rule = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_rule_finalize(GScanRule *rule) +{ + if (rule->name != NULL) + free(rule->name); + + G_OBJECT_CLASS(g_scan_rule_parent_class)->finalize(G_OBJECT(rule)); + +} + + +/****************************************************************************** +* * +* Paramètres : name = désignation à associer à la future règle. * +* * +* Description : Crée une règle de détection statique à l'aide de motifs. * +* * +* Retour : Règle de détection mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanRule *g_scan_rule_new(const char *name) +{ + GScanRule *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_RULE, NULL); + + result->name = strdup(name); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à compléter. * +* pattern = nouveau motif de détection. * +* * +* Description : Intègre une nouvelle variable locale à une règle. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_rule_add_local_variable(GScanRule *rule, GSearchPattern *pattern) +{ + if (G_IS_STRING_TOKEN(pattern)) + { + if (rule->data_used == rule->data_allocated) + { + rule->data_allocated += PATTERN_ALLOC_SIZE; + rule->data_locals = realloc(rule->data_locals, rule->data_allocated * sizeof(GSearchPattern *)); + } + + rule->data_locals[rule->data_used++] = pattern; + g_object_ref(G_OBJECT(pattern)); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à consulter. * +* target = nom d'une variable locale à retrouver. * +* * +* Description : Fournit une variable locale à une règle selon un nom. * +* * +* Retour : Motif de détection retrouvé ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GSearchPattern *g_scan_rule_get_local_variable(GScanRule *rule, const char *target) +{ + GSearchPattern *result; /* Variable à retourner */ + size_t i; /* Boucle de parcours */ + const char *name; /* Désignation d'un motif */ + + result = NULL; + + for (i = 0; i < rule->data_used; i++) + { + name = g_search_pattern_get_name(rule->data_locals[i]); + + if (strcmp(name, target) == 0) + { + result = rule->data_locals[i]; + break; + } + + } + + if (result != NULL) + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à compléter. * +* expr = expression de condition à satisfaire. * +* * +* Description : Définit l'expression d'une correspondance recherchée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_rule_set_match_condition(GScanRule *rule, GScanExpression *expr) +{ + rule->condition = expr; + + g_object_ref(G_OBJECT(expr)); + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à considérer. * +* backend = moteur d'analyse pour données brutes. * +* context = contexte de l'analyse à mener. * +* * +* Description : Prépare le suivi de recherche de motifs pour une règle. * +* * +* Retour : Bilan de l'opération à renvoyer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_rule_setup_backend(GScanRule *rule, GEngineBackend *backend, GScanContext *context) +{ + bool result; /* Statut à retourner */ + size_t maxsize; /* Taille maximale des atomes */ + GSearchPattern *pattern; /* Motif à intégrer */ + GScanOptions *options; /* Options d'analyse */ + size_t i; /* Boucle de parcours */ + + /* Suivi des conditions de correspondance */ + + result = g_scan_context_set_rule_condition(context, rule->name, rule->condition); + if (!result) goto exit; + + /* Programmation des motifs recherchés */ + + maxsize = g_engine_backend_get_atom_max_size(backend); + + for (i = 0; i < rule->data_used && result; i++) + { + pattern = rule->data_locals[i]; + result = g_string_token_enroll(G_STRING_TOKEN(pattern), context, backend, maxsize); + } + + g_engine_backend_warm_up(backend); + + /* Affichage éventuel de statistiques */ + + options = g_scan_context_get_options(context); + + if (g_scan_options_get_print_stats(options)) + g_engine_backend_output_stats(backend); + + + g_object_unref(G_OBJECT(options)); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : rule = règle de détection à considérer. * +* backend = moteur d'analyse pour données brutes. * +* context = contexte de l'analyse à mener. * +* * +* Description : Lance une analyse d'un contenu binaire selon une règle. * +* * +* Retour : Contexte de suivi pour l'analyse menée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_scan_rule_analyze(GScanRule *rule, GEngineBackend *backend, GScanContext *context) +{ + GBinContent *content; /* Contenu à manipuler */ + pending_matches_t matches; /* Suivi de correspondances */ + size_t i; /* Boucle de parcours #1 */ + GSearchPattern *pattern; /* Motif à intégrer */ + size_t k; /* Boucle de parcours #2 */ + match_area_t *area; /* Zone à initialiser */ + GScanMatch *match; /* Correspondance à mémoriser */ + + content = g_scan_context_get_content(context); + + g_engine_backend_run_scan(backend, context, content); + + /* Consolidation des résultats */ + + for (i = 0; i < rule->data_used; i++) + { + init_pending_matches(&matches); + + pattern = rule->data_locals[i]; + + g_string_token_check(G_STRING_TOKEN(pattern), context, content, &matches); + + for (k = 0; k < matches.used; k++) + { + area = &matches.areas[k]; + + match = g_bytes_match_new(G_SEARCH_PATTERN(pattern), content, area->start, area->length); + g_scan_context_register_full_match(context, match); + g_object_unref(G_OBJECT(match)); + + } + + exit_pending_matches(&matches); + + } + + /* Sortie propre */ + + g_object_unref(G_OBJECT(content)); + +} diff --git a/src/analysis/scan/rule.h b/src/analysis/scan/rule.h new file mode 100644 index 0000000..edd57b3 --- /dev/null +++ b/src/analysis/scan/rule.h @@ -0,0 +1,77 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scanner.h - prototypes pour le parcours de contenus à la recherche de motifs + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_RULE_H +#define _ANALYSIS_SCAN_RULE_H + + +#include <glib-object.h> + + +#include "cond.h" +#include "context.h" +#include "pattern.h" +#include "expr.h" +#include "patterns/backend.h" + + + +#define G_TYPE_SCAN_RULE g_scan_rule_get_type() +#define G_SCAN_RULE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_RULE, GScanRule)) +#define G_IS_SCAN_RULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_RULE)) +#define G_SCAN_RULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_RULE, GScanRuleClass)) +#define G_IS_SCAN_RULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_RULE)) +#define G_SCAN_RULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_RULE, GScanRuleClass)) + + +/* Représentation d'une règle de détection statique (instance) */ +typedef struct _GScanRule GScanRule; + +/* Représentation d'une règle de détection statique (classe) */ +typedef struct _GScanRuleClass GScanRuleClass; + + +/* Indique le type défini pour une règle de détection par motifs. */ +GType g_scan_rule_get_type(void); + +/* Crée une règle de détection statique à l'aide de motifs. */ +GScanRule *g_scan_rule_new(const char *); + +/* Intègre une nouvelle variable locale à une règle. */ +void g_scan_rule_add_local_variable(GScanRule *, GSearchPattern *); + +/* Fournit une variable locale à une règle selon un nom. */ +GSearchPattern *g_scan_rule_get_local_variable(GScanRule *, const char *); + +/* Définit l'expression d'une correspondance recherchée. */ +void g_scan_rule_set_match_condition(GScanRule *, GScanExpression *); + +/* Prépare le suivi de recherche de motifs pour une règle. */ +bool g_scan_rule_setup_backend(GScanRule *, GEngineBackend *, GScanContext *); + +/* Lance une analyse d'un contenu binaire selon une règle. */ +void g_scan_rule_analyze(GScanRule *, GEngineBackend *, GScanContext *); + + + +#endif /* _ANALYSIS_SCAN_RULE_H */ diff --git a/src/analysis/scan/scanner-int.h b/src/analysis/scan/scanner-int.h new file mode 100644 index 0000000..54b4f62 --- /dev/null +++ b/src/analysis/scan/scanner-int.h @@ -0,0 +1,63 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scanner-int.h - prototypes internes pour le parcours de contenus à la recherche de motifs + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_SCANNER_INT_H +#define _ANALYSIS_SCAN_SCANNER_INT_H + + +#include "scanner.h" + + +#include "patterns/backend.h" + + + +/* Encadrement d'une recherche au sein de contenus binaires (instance) */ +struct _GContentScanner +{ + GObject parent; /* A laisser en premier */ + + GScanRule **rules; /* Règles de détection */ + size_t rule_count; /* Nombre de ces règles */ + + GEngineBackend *data_backend; /* Moteur pour les données */ + +}; + +/* Encadrement d'une recherche au sein de contenus binaires (classe) */ +struct _GContentScannerClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un scanner de contenus binaires. */ +bool g_content_scanner_create_from_text(GContentScanner *, const char *); + +/* Met en place un scanner de contenus binaires. */ +bool g_content_scanner_create_from_file(GContentScanner *, const char *); + + + +#endif /* _ANALYSIS_SCAN_SCANNER_INT_H */ diff --git a/src/analysis/scan/scanner.c b/src/analysis/scan/scanner.c new file mode 100644 index 0000000..ae3cb9a --- /dev/null +++ b/src/analysis/scan/scanner.c @@ -0,0 +1,342 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scanner.c - parcours de contenus à la recherche de motifs + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "scanner.h" + + +#include <assert.h> + + +#include "decl.h" +#include "scanner-int.h" +#include "../contents/file.h" + + + +/* Initialise la classe des recherches dans du binaire. */ +static void g_content_scanner_class_init(GContentScannerClass *); + +/* Initialise une instance de recherche dans du binaire. */ +static void g_content_scanner_init(GContentScanner *); + +/* Supprime toutes les références externes. */ +static void g_content_scanner_dispose(GContentScanner *); + +/* Procède à la libération totale de la mémoire. */ +static void g_content_scanner_finalize(GContentScanner *); + + + +/* Indique le type défini pour une recherche dans du binaire. */ +G_DEFINE_TYPE(GContentScanner, g_content_scanner, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des recherches dans du binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_content_scanner_class_init(GContentScannerClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_content_scanner_dispose; + object->finalize = (GObjectFinalizeFunc)g_content_scanner_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : scanner = instance à initialiser. * +* * +* Description : Initialise une instance de recherche dans du binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_content_scanner_init(GContentScanner *scanner) +{ + scanner->rules = NULL; + scanner->rule_count = 0; + + scanner->data_backend = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : scanner = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_content_scanner_dispose(GContentScanner *scanner) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < scanner->rule_count; i++) + g_clear_object(&scanner->rules[i]); + + g_clear_object(&scanner->data_backend); + + G_OBJECT_CLASS(g_content_scanner_parent_class)->dispose(G_OBJECT(scanner)); + +} + + +/****************************************************************************** +* * +* Paramètres : scanner = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_content_scanner_finalize(GContentScanner *scanner) +{ + if (scanner->rules != NULL) + free(scanner->rules); + + G_OBJECT_CLASS(g_content_scanner_parent_class)->finalize(G_OBJECT(scanner)); + +} + + +/****************************************************************************** +* * +* Paramètres : text = définitions textuelles de règles de recherche. * +* * +* Description : Prépare une recherche de motifs dans du contenu binaire. * +* * +* Retour : Mécanismes mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GContentScanner *g_content_scanner_new_from_text(const char *text) +{ + GContentScanner *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_CONTENT_SCANNER, NULL); + + if (!g_content_scanner_create_from_text(result, text)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : scanner = scanner de contenus à initialiser pleinement. * +* text = définitions textuelles de règles de recherche. * +* * +* Description : Met en place un scanner de contenus binaires. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_content_scanner_create_from_text(GContentScanner *scanner, const char *text) +{ + bool result; /* Bilan à retourner */ + size_t length; /* Taille de la définition */ + + length = strlen(text); + + result = process_rules_definitions(scanner, text, length); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : filename = chemin vers des définitions de règles. * +* * +* Description : Prépare une recherche de motifs dans du contenu binaire. * +* * +* Retour : Mécanismes mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GContentScanner *g_content_scanner_new_from_file(const char *filename) +{ + GContentScanner *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_CONTENT_SCANNER, NULL); + + if (!g_content_scanner_create_from_file(result, filename)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : scanner = scanner de contenus à initialiser pleinement. * +* filename = chemin vers des définitions de règles. * +* * +* Description : Met en place un scanner de contenus binaires. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_content_scanner_create_from_file(GContentScanner *scanner, const char *filename) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Fichier à parcourir */ + phys_t size; /* Taille du contenu associé */ + vmpa2t start; /* Tête de lecture */ + const bin_t *data; /* Données à consulter */ + + result = false; + + content = g_file_content_new(filename); + if (content == NULL) goto no_content; + + size = g_binary_content_compute_size(content); + + g_binary_content_compute_start_pos(content, &start); + data = g_binary_content_get_raw_access(content, &start, size); + + result = process_rules_definitions(scanner, (char *)data, size); + + g_object_unref(G_OBJECT(content)); + + no_content: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : scanner = gestionnaire de recherche à compléter. * +* rule = règle de détection à intégrer. * +* * +* Description : Intègre une nouvelle règle de détection. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_content_scanner_add_rule(GContentScanner *scanner, GScanRule *rule) +{ + scanner->rules = realloc(scanner->rules, ++scanner->rule_count * sizeof(GScanRule *)); + + scanner->rules[scanner->rule_count - 1] = rule; + + g_object_ref(G_OBJECT(rule)); + +} + + +/****************************************************************************** +* * +* Paramètres : scanner = gestionnaire de recherche à compléter. * +* options = ensemble des options d'analyses à respecter. * +* content = contenu à parcourir et analyser. * +* * +* Description : Lance une analyse d'un contenu binaire. * +* * +* Retour : Contexte de suivi pour l'analyse menée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanContext *g_content_scanner_analyze(GContentScanner *scanner, GScanOptions *options, GBinContent *content) +{ + GScanContext *result; /* Bilan global à retourner */ + bool status; /* Bilan d'opération locale */ + size_t i; /* Boucle de parcours */ + + result = g_scan_context_new(options); + + if (scanner->data_backend == NULL) + { + scanner->data_backend = g_object_new(g_scan_options_get_backend_for_data(options), NULL); + assert(scanner->data_backend != NULL); + + status = (scanner->data_backend != NULL); + + for (i = 0; i < scanner->rule_count && status; i++) + status = g_scan_rule_setup_backend(scanner->rules[i], scanner->data_backend, result); + + if (!status) + { + g_clear_object(&result); + goto exit; + } + + } + + g_scan_context_set_content(result, content); + + for (i = 0; i < scanner->rule_count; i++) + g_scan_rule_analyze(scanner->rules[i], scanner->data_backend, result); + + exit: + + return result; + +} diff --git a/src/analysis/scan/scanner.h b/src/analysis/scan/scanner.h new file mode 100644 index 0000000..8a3919a --- /dev/null +++ b/src/analysis/scan/scanner.h @@ -0,0 +1,77 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scanner.h - prototypes pour le parcours de contenus à la recherche de motifs + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_SCANNER_H +#define _ANALYSIS_SCAN_SCANNER_H + + +#include <glib-object.h> + + +#include "context.h" +#include "expr.h" +#include "options.h" +#include "rule.h" + + + +#define G_TYPE_CONTENT_SCANNER g_content_scanner_get_type() +#define G_CONTENT_SCANNER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_CONTENT_SCANNER, GContentScanner)) +#define G_IS_CONTENT_SCANNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_CONTENT_SCANNER)) +#define G_CONTENT_SCANNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_CONTENT_SCANNER, GContentScannerClass)) +#define G_IS_CONTENT_SCANNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_CONTENT_SCANNER)) +#define G_CONTENT_SCANNER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_CONTENT_SCANNER, GContentScannerClass)) + + +/* Encadrement d'une recherche au sein de contenus binaires (instance) */ +typedef struct _GContentScanner GContentScanner; + +/* Encadrement d'une recherche au sein de contenus binaires (classe) */ +typedef struct _GContentScannerClass GContentScannerClass; + + +/* Indique le type défini pour une recherche dans du binaire. */ +GType g_content_scanner_get_type(void); + +/* Prépare une recherche de motifs dans du contenu binaire. */ +GContentScanner *g_content_scanner_new_from_text(const char *); + +/* Prépare une recherche de motifs dans du contenu binaire. */ +GContentScanner *g_content_scanner_new_from_file(const char *); + +/* Intègre une nouvelle règle de détection. */ +void g_content_scanner_add_rule(GContentScanner *, GScanRule *); + +/* Définit l'expression d'une correspondance recherchée. */ +GScanContext *g_content_scanner_analyze(GContentScanner *, GScanOptions *, GBinContent *); + + + + + +/* Lance une analyse d'un élément, fichier ou répertoire. */ +//void g_content_scanner_analyze(GContentScanner *, const char *); + + + +#endif /* _ANALYSIS_SCAN_SCANNER_H */ diff --git a/src/analysis/scan/space-int.h b/src/analysis/scan/space-int.h new file mode 100644 index 0000000..fa4437d --- /dev/null +++ b/src/analysis/scan/space-int.h @@ -0,0 +1,55 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * space-int.h - prototypes internes pour la définition d'un espace de noms pour les fonctions de scan + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_SPACE_INT_H +#define _ANALYSIS_SCAN_SPACE_INT_H + + +#include "space.h" + + +#include "item-int.h" + + + +/* Espace de noms pour un groupe de fonctions (instance) */ +struct _GScanNamespace +{ + GRegisteredItem parent; /* A laisser en premier */ + + GRegisteredItem **children; /* Sous-éléments inscrits */ + char **names; /* Désignations correspondantes*/ + size_t count; /* Quantité de sous-éléments */ + +}; + +/* Espace de noms pour un groupe de fonctions (classe) */ +struct _GScanNamespaceClass +{ + GRegisteredItemClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _ANALYSIS_SCAN_SPACE_INT_H */ diff --git a/src/analysis/scan/space.c b/src/analysis/scan/space.c new file mode 100644 index 0000000..f10424b --- /dev/null +++ b/src/analysis/scan/space.c @@ -0,0 +1,310 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * space.c - définition d'un espace de noms pour les fonctions de scan + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "space.h" + + +#include <assert.h> +#include <string.h> + + +#include "space-int.h" + + + +/* ------------------------- SOCLE POUR LES ESPACES DE NOMS ------------------------- */ + + +/* Initialise la classe des espaces de noms pour scan. */ +static void g_scan_namespace_class_init(GScanNamespaceClass *); + +/* Initialise une instance d'espace de noms pour scan. */ +static void g_scan_namespace_init(GScanNamespace *); + +/* Supprime toutes les références externes. */ +static void g_scan_namespace_dispose(GScanNamespace *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_namespace_finalize(GScanNamespace *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Lance une résolution d'élément à appeler. * +* * +* Retour : Nouvel élément d'appel identifié ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GRegisteredItem *g_scan_namespace_resolve(GScanNamespace *, const char *, GScanContext *, GScanExpression **, size_t, bool, bool); + +/* Réduit une expression à une forme plus simple. */ +GScanExpression *g_scan_namespace_reduce(GScanNamespace *, GScanContext *, GScanExpression **, size_t, bool); + + + +/* ---------------------------------------------------------------------------------- */ +/* SOCLE POUR LES ESPACES DE NOMS */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une définition d'espace de noms. */ +G_DEFINE_TYPE(GScanNamespace, g_scan_namespace, G_TYPE_REGISTERED_ITEM); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des espaces de noms pour scan. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_namespace_class_init(GScanNamespaceClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GRegisteredItemClass *registered; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_namespace_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_namespace_finalize; + + registered = G_REGISTERED_ITEM_CLASS(klass); + + registered->resolve = (resolve_registered_item_fc)g_scan_namespace_resolve; + registered->reduce = (reduce_registered_item_fc)g_scan_namespace_reduce; + +} + + +/****************************************************************************** +* * +* Paramètres : space = instance à initialiser. * +* * +* Description : Initialise une instance d'espace de noms pour scan. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_namespace_init(GScanNamespace *space) +{ + space->children = NULL; + space->names = NULL; + space->count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : space = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_namespace_dispose(GScanNamespace *space) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < space->count; i++) + g_clear_object(&space->children[i]); + + G_OBJECT_CLASS(g_scan_namespace_parent_class)->dispose(G_OBJECT(space)); + +} + + +/****************************************************************************** +* * +* Paramètres : space = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_namespace_finalize(GScanNamespace *space) +{ + size_t i; /* Boucle de parcours */ + + if (space->children != NULL) + free(space->children); + + for (i = 0; i < space->count; i++) + free(space->names[i]); + + if (space->names != NULL) + free(space->names); + + G_OBJECT_CLASS(g_scan_namespace_parent_class)->finalize(G_OBJECT(space)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit un nouvel espace de noms pour scan. * +* * +* Retour : Adresse de la structure mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanNamespace *g_scan_namespace_new(void) +{ + GScanNamespace *result; /* Instance à retourner */ + + result = g_object_new(G_TYPE_SCAN_NAMESPACE, NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : space = espace de noms à compléter. * +* type = type d'élément à intégrer. * +* name = nom du futur espace ou NULL pour une racine. * +* * +* Description : Intègre un nouvel élément dans l'esapce de noms. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_scan_namespace_register(GScanNamespace *space, GRegisteredItem *child, const char *name) +{ + bool result; /* Bilan à retourner */ + + result = true; + + space->count++; + + space->children = realloc(space->children, space->count * sizeof(GRegisteredItem *)); + space->children[space->count - 1] = child; + + space->names = realloc(space->names, space->count * sizeof(char *)); + space->names[space->count - 1] = strdup(name); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : space = élément d'appel à consulter. * +* target = désignation de l'objet d'appel à identifier. * +* ctx = contexte de suivi de l'analyse courante. * +* args = liste d'éventuels arguments fournis. * +* count = taille de cette liste. * +* last = l'élément est-il le dernier d'une chaîne d'appels ? * +* final = indique une ultime conversion dans le cycle en cours.* +* * +* Description : Lance une résolution d'élément à appeler. * +* * +* Retour : Nouvel élément d'appel identifié ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GRegisteredItem *g_scan_namespace_resolve(GScanNamespace *space, const char *target, GScanContext *ctx, GScanExpression **args, size_t count, bool last, bool final) +{ + GRegisteredItem *result; /* Instance à renvoyer */ + size_t i; /* Boucle de parcours */ + + result = NULL; + + for (i = 0; i < space->count; i++) + if (strcmp(target, space->names[i]) == 0) + { + result = space->children[i]; + g_object_ref(G_OBJECT(result)); + break; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : space = élément d'appel à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* args = liste d'éventuels arguments fournis. * +* count = taille de cette liste. * +* final = indique une ultime conversion dans le cycle en cours.* +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanExpression *g_scan_namespace_reduce(GScanNamespace *space, GScanContext *ctx, GScanExpression **args, size_t count, bool final) +{ + GScanExpression *result; /* Instance à renvoyer */ + + assert(false); + + result = NULL; + + return result; + +} diff --git a/src/analysis/scan/space.h b/src/analysis/scan/space.h new file mode 100644 index 0000000..9058959 --- /dev/null +++ b/src/analysis/scan/space.h @@ -0,0 +1,62 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * space.h - prototypes pour la définition d'un espace de noms pour les fonctions de scan + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_SCAN_SPACE_H +#define _ANALYSIS_SCAN_SPACE_H + + +#include <glib-object.h> +#include <stdbool.h> + + +#include "item.h" + + + +#define G_TYPE_SCAN_NAMESPACE g_scan_namespace_get_type() +#define G_SCAN_NAMESPACE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_NAMESPACE, GScanNamespace)) +#define G_IS_SCAN_NAMESPACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_NAMESPACE)) +#define G_SCAN_NAMESPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_NAMESPACE, GScanNamespaceClass)) +#define G_IS_SCAN_NAMESPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_NAMESPACE)) +#define G_SCAN_NAMESPACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_NAMESPACE, GScanNamespaceClass)) + + +/* Espace de noms pour un groupe de fonctions (instance) */ +typedef struct _GScanNamespace GScanNamespace; + +/* Espace de noms pour un groupe de fonctions (classe) */ +typedef struct _GScanNamespaceClass GScanNamespaceClass; + + +/* Indique le type défini pour une définition d'espace de noms. */ +GType g_scan_namespace_get_type(void); + +/* Construit un nouvel espace de noms pour scan. */ +GScanNamespace *g_scan_namespace_new(void); + +/* Intègre un nouvel élément dans l'esapce de noms. */ +bool g_scan_namespace_register(GScanNamespace *, GRegisteredItem *, const char *); + + + +#endif /* _ANALYSIS_SCAN_SPACE_H */ diff --git a/src/analysis/scan/tokens.l b/src/analysis/scan/tokens.l new file mode 100644 index 0000000..92a5340 --- /dev/null +++ b/src/analysis/scan/tokens.l @@ -0,0 +1,306 @@ + +%top { + +#include "grammar.h" + +} + + +%{ + +//#include "manual.h" + +#include <assert.h> +#include <stdbool.h> +#include <stdlib.h> + + +#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'; \ + \ + }) + + + + +#define PUSH_STATE(s) yy_push_state(s, yyscanner) +#define POP_STATE yy_pop_state(yyscanner) + + + +#define EXTEND_BUFFER_IF_NEEDED(extra) \ + if ((*used + extra) > *allocated) \ + { \ + *allocated *= 2; \ + *buf = realloc(*buf, *allocated); \ + } + + +%} + + +%option bison-bridge reentrant +%option stack +%option nounput +%option noinput +%option noyywrap +%option noyy_top_state +%option yylineno +%option never-interactive + + +%x rule_intro +%x raw_block + +%x strings +%x strval +%x strval_raw +%x strval_hex + +%x condition +%x strlit + +%x wait_for_colon + + +%x comment + + +%% + + + + +"rule" { PUSH_STATE(rule_intro); return RAW_RULE; } + +<rule_intro>[A-Za-z0-9_]+ { yylval->cstring = yytext; return RULE_NAME; } + +<rule_intro>[ \t]* { } +<rule_intro>"{" { POP_STATE; PUSH_STATE(raw_block); return BRACE_IN; } + +<raw_block>"strings" { PUSH_STATE(strings); PUSH_STATE(wait_for_colon); return STRINGS; } +<raw_block,strings>"condition" { PUSH_STATE(condition); PUSH_STATE(wait_for_colon); return CONDITION; } + + + + + + +<condition>"true" { return TRUE_; } +<condition>"false" { return FALSE_; } + +<condition>(0|[1-9][0-9]*) { yylval->integer = strtoull(yytext, NULL, 10); return INTEGER; } +<condition>0x[0-9a-f]+ { yylval->integer = strtoull(yytext, NULL, 16); return INTEGER; } + +<condition>[kK][bB] { return KB; } +<condition>[mM][bB] { return MB; } +<condition>[gG][bB] { return GB; } + +<condition>"\"" { + *used = 0; + PUSH_STATE(strlit); + } + +<strlit>"\"" { + POP_STATE; + EXTEND_BUFFER_IF_NEEDED(1); + (*buf)[(*used)++] = '\0'; + yylval->cstring = *buf; + return STRING; + } + +<strlit>"\\\"" { EXTEND_BUFFER_IF_NEEDED(1); (*buf)[(*used)++] = '"'; } +<strlit>"\\t" { EXTEND_BUFFER_IF_NEEDED(1); (*buf)[(*used)++] = '\t'; } +<strlit>"\\r" { EXTEND_BUFFER_IF_NEEDED(1); (*buf)[(*used)++] = '\r'; } +<strlit>"\\n" { EXTEND_BUFFER_IF_NEEDED(1); (*buf)[(*used)++] = '\n'; } +<strlit>"\\\\" { EXTEND_BUFFER_IF_NEEDED(1); (*buf)[(*used)++] = '\\'; } + +<strlit>\\x[0-9a-fA-F]{2} { + char __ch; + __ch = strtol(yytext + 2, NULL, 16); + EXTEND_BUFFER_IF_NEEDED(1); + (*buf)[(*used)++] = __ch; + } + +<strlit>[^\\\"]+ { + size_t __len; + __len = strlen(yytext); + EXTEND_BUFFER_IF_NEEDED(__len); + strcpy(&(*buf)[*used], yytext); + *used += __len; + } + + + + +<condition>"and" { return AND; } +<condition>"or" { return OR; } +<condition>"not" { return NOT; } + +<condition>"<" { return LT; } +<condition>"<=" { return LE; } +<condition>"==" { return EQ; } +<condition>"!=" { return NE; } +<condition>">" { return GT; } +<condition>">=" { return GE; } + +<condition>"contains" { return CONTAINS; } +<condition>"startswith" { return STARTSWITH; } +<condition>"endswith" { return ENDSWITH; } +<condition>"matches" { return MATCHES; } +<condition>"icontains" { return ICONTAINS; } +<condition>"istartswith" { return ISTARTSWITH; } +<condition>"iendswith" { return IENDSWITH; } +<condition>"iequals" { return IEQUALS; } + +<condition>"+" { return PLUS; } +<condition>"-" { return MINUS; } +<condition>"*" { return MUL; } +<condition>"\\" { return DIV; } +<condition>"%" { return MOD; } + +<condition>"(" { return PAREN_O; } +<condition>")" { return PAREN_C; } +<condition>"," { return COMMA; } +<condition>"." { return DOT; } + +<condition>"none" { return NONE; } +<condition>"any" { return ANY; } +<condition>"all" { return ALL; } +<condition>"of" { return OF; } +<condition>"them" { return THEM; } + + +<strings,condition>$[A-Za-z0-9_]* { + yylval->sized_cstring.cstring = yytext + 1; + yylval->sized_cstring.len = yyleng - 1; + return IDENTIFIER; + } +<condition>[A-Za-z_][A-Za-z0-9_]* { + yylval->sized_cstring.cstring = yytext; + yylval->sized_cstring.len = yyleng; + return NAME; + } + +<strings>"=" { PUSH_STATE(strval); return ASSIGN; } + + +<strval>\"[^\"\\]+\" { + POP_STATE; + yylval->sized_cstring.cstring = yytext + 1; + yylval->sized_cstring.len = yyleng - 2; + return PLAIN_STRING; + } + + + + +<strval>"\"" { + POP_STATE; + // *built_pattern = g_bytes_pattern_new(); + PUSH_STATE(strval_raw); + } +<strval>"{" { + POP_STATE; + // *built_pattern = g_bytes_pattern_new(); + PUSH_STATE(strval_hex); + } + +<strval_raw>"\"" { POP_STATE; /*yylval->pattern = *built_pattern*/; return MASKED_STRING; } + +<strval_raw>"\\\"" { }//g_bytes_pattern_append_data(*built_pattern, '"', 0xff); } +<strval_raw>"\\t" { }//g_bytes_pattern_append_data(*built_pattern, '\t', 0xff); } +<strval_raw>"\\r" { }//g_bytes_pattern_append_data(*built_pattern, '\r', 0xff); } +<strval_raw>"\\n" { }//g_bytes_pattern_append_data(*built_pattern, '\n', 0xff); } +<strval_raw>"\\\\" { }//g_bytes_pattern_append_data(*built_pattern, '\\', 0xff); } + +<strval_raw>\\x[0-9a-fA-F]{2} { + uint8_t __ch; + __ch = strtol(yytext + 2, NULL, 16); + //g_bytes_pattern_append_data(*built_pattern, __ch, 0xff); + } + +<strval_raw>. { }//g_bytes_pattern_append_data(*built_pattern, *yytext, 0xff); } + +<strval_hex>"}" { POP_STATE; /*yylval->pattern = *built_pattern;*/ return MASKED_STRING; } + +<strval_hex>[0-9a-fA-F]{2} { + uint8_t __ch; + __ch = strtol(yytext, NULL, 16); + //g_bytes_pattern_append_data(*built_pattern, __ch, 0xff); + } + +<strval_hex>"??" { /*g_bytes_pattern_insert_space(*built_pattern, 1, 1);*/ } + + + + + +<wait_for_colon>":" { POP_STATE; return COLON; } + +<raw_block,strings,condition>"}" { POP_STATE; return BRACE_OUT; } + + + +%{ /* Commentaires */ %} + +<*>"/*" { PUSH_STATE(comment); } +<comment>"*/" { POP_STATE; } +<comment>(.|\n) { } + +<*>"//"[^\n]* { } + + +%{ /* Actions par défaut */ %} + +<*>[ \t\n]+ { } + +<*>. { + char *msg; + int ret; + ret = asprintf(&msg, "Unhandled token in rule definition: '%s'", yytext); + if (ret == -1) + YY_FATAL_ERROR("Unhandled token in undisclosed rule definition"); + else + { + YY_FATAL_ERROR(msg); + free(msg); + } + } + + +%% diff --git a/src/core/core.c b/src/core/core.c index 62f6821..01ebbe1 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -40,6 +40,7 @@ #include "params.h" #include "processors.h" #include "queue.h" +#include "../analysis/scan/core.h" #include "../common/io.h" #include "../common/xdg.h" #include "../glibext/linesegment.h" @@ -65,6 +66,7 @@ bool load_all_core_components(bool cs) char *cfgdir; /* Répertoire de configuration */ GContentExplorer *explorer; /* Explorateur de contenus */ GContentResolver *resolver; /* Résolveur de contenus */ + GScanNamespace *root_ns; /* Espace de noms ROST racine */ /** * On mémorise les passages réussis. @@ -103,6 +105,11 @@ bool load_all_core_components(bool cs) resolver = g_content_resolver_new(); set_current_content_resolver(resolver); + root_ns = g_scan_namespace_new(); + set_rost_root_namespace(root_ns); + + if (result) result = populate_main_scan_namespace(root_ns); + if (result) result = init_segment_content_hash_table(); register_arch_gtypes(); @@ -143,6 +150,8 @@ void unload_all_core_components(bool cs) unload_processors_definitions(); + set_rost_root_namespace(NULL); + set_current_content_resolver(NULL); set_current_content_explorer(NULL); diff --git a/src/core/global.c b/src/core/global.c index 4ebb9e0..c99d711 100644 --- a/src/core/global.c +++ b/src/core/global.c @@ -40,6 +40,9 @@ static GContentExplorer *_explorer = NULL; /* Résolveur de contenus */ static GContentResolver *_resolver = NULL; +/* Espace de noms racine pour ROST */ +static GScanNamespace *_rost_root_ns = NULL; + /* Projet global actif */ static GStudyProject *_project = NULL; @@ -224,6 +227,54 @@ GContentResolver *get_current_content_resolver(void) /****************************************************************************** * * +* Paramètres : ns = espace de noms racine de ROST. * +* * +* Description : Définit l'adresse de l'espace de noms principal pour ROST. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void set_rost_root_namespace(GScanNamespace *ns) +{ + if (_rost_root_ns != NULL) + g_object_unref(G_OBJECT(_rost_root_ns)); + + _rost_root_ns = ns; + + if (ns != NULL) + g_object_ref_sink(G_OBJECT(ns)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit l'adresse de l'espace de noms principal pour ROST. * +* * +* Retour : Espace de noms racine de ROST ou NULL si aucun (!). * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanNamespace *get_rost_root_namespace(void) +{ + assert(_rost_root_ns != NULL); + + g_object_ref(G_OBJECT(_rost_root_ns)); + + return _rost_root_ns; + +} + + +/****************************************************************************** +* * * Paramètres : project = éventuelle adresse du nouveau projet principal. * * * * Description : Définit l'adresse du projet courant. * diff --git a/src/core/global.h b/src/core/global.h index 088a7c9..0a9172b 100644 --- a/src/core/global.h +++ b/src/core/global.h @@ -30,6 +30,7 @@ #include "../analysis/loading.h" #include "../analysis/project.h" +#include "../analysis/scan/space.h" #include "../glibext/delayed.h" @@ -58,6 +59,12 @@ void set_current_content_resolver(GContentResolver *); /* Fournit l'adresse du résolveur de contenus courant. */ GContentResolver *get_current_content_resolver(void); +/* Définit l'adresse de l'espace de noms principal pour ROST. */ +void set_rost_root_namespace(GScanNamespace *); + +/* Fournit l'adresse de l'espace de noms principal pour ROST. */ +GScanNamespace *get_rost_root_namespace(void); + /* Définit l'adresse du projet courant. */ void set_current_project(GStudyProject *); diff --git a/src/rost.c b/src/rost.c new file mode 100644 index 0000000..37ca098 --- /dev/null +++ b/src/rost.c @@ -0,0 +1,316 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * rost.c - fichier d'entrée du centre de collecte + * + * 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 <getopt.h> +#include <libgen.h> +#include <locale.h> +#include <stdlib.h> + + +#include <config.h> +#include <i18n.h> + + + +#include "gleak.h" +#include "analysis/contents/file.h" +#include "analysis/scan/options.h" +#include "analysis/scan/scanner.h" +#include "analysis/scan/patterns/backends/bitap.h" +#include "analysis/scan/patterns/backends/acism.h" +#include "core/core.h" +#include "core/global.h" +#include "core/logs.h" +#include "core/paths.h" + + + +/* Affiche des indications quant à l'utilisation du programme. */ +static void show_rost_help(const char *); + +/* Affiche des indications sur la version courante du programme. */ +static void show_rost_version(void); + + + +/****************************************************************************** +* * +* Paramètres : name = nom du programme en question. * +* * +* Description : Affiche des indications quant à l'utilisation du programme. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void show_rost_help(const char *name) +{ + char *tmp; /* Conservation modifiable */ + char *base; /* Version courte du nom */ + + tmp = strdup(name); + + base = basename(tmp); + + printf("\n"); + + printf("Usage: %s [--help] [--version] [--verbosity] [options] <rules file> <file | dir>\n", base); + + printf("\n"); + + printf("\t-h --help\t\tShow this help message.\n"); + printf("\t-v --version\t\tDisplay the program version.\n"); + + printf("\n"); + + printf("\t-A --algorithm=name\tSelect one of the available algorithms for data: bitmap, acism (default: acsim).\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); + + printf("\n"); + + free(tmp); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Affiche des indications sur la version courante du programme.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void show_rost_version(void) +{ + char *edir; /* Répertoire de base effectif */ + + printf("\n"); + + printf("-o- Chrysalide ROST r%u -o-\n", REVISION); + printf(_("Last compiled on %s at %s\n"), __DATE__, __TIME__); + + printf("\n"); + + edir = get_effective_directory(PLUGINS_LIB_DIR); + printf(_("Plugins library directory: %s\n"), edir); + free(edir); + + edir = get_effective_directory(PLUGINS_DATA_DIR); + printf(_("Plugins data directory: %s\n"), edir); + free(edir); + + edir = get_effective_directory(LOCALE_DIR); + printf(_("Locale directory: %s\n"), edir); + free(edir); + + printf("\n"); + +} + + +/****************************************************************************** +* * +* Paramètres : argc = nombre d'arguments dans la ligne de commande. * +* argv = arguments de la ligne de commande. * +* * +* Description : Point d'entrée du programme. * +* * +* Retour : EXIT_SUCCESS si le prgm s'est déroulé sans encombres. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int main(int argc, char **argv) +{ + int result; /* Bilan de l'exécution */ + bool show_help; /* Affichage de l'aide ? */ + bool show_version; /* Affichage de la version ? */ + LogMessageType verbosity; /* Niveau de filtre de message */ + GScanOptions *options; /* Options d'analyses */ + int index; /* Indice d'argument */ + int ret; /* Bilan d'un appel */ + char *rules; /* Définition de règles */ + char *target; /* Cible communiquée */ + char *edir; /* Répertoire de base effectif */ + GContentScanner *scanner; /* Encadrement d'une recherche */ + GBinContent *content; /* Contenu à analyser */ + GScanContext *context; /* Contexte des trouvailles */ + + static struct option long_options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { "algorithm", required_argument, NULL, 'A' }, + { "print-stats", no_argument, NULL, 'S' }, + { "verbosity", required_argument, NULL, 'V' }, + { NULL, 0, NULL, 0 } + }; + + result = EXIT_FAILURE; + + /* Décodage des options */ + + show_help = false; + show_version = false; + + verbosity = LMT_INFO; + + options = g_scan_options_new(); + + g_scan_options_set_backend_for_data(options, G_TYPE_ACISM_BACKEND); + + while (true) + { + ret = getopt_long(argc, argv, "hvA:SV:", long_options, &index); + if (ret == -1) break; + + switch (ret) + { + case 'h': + show_help = true; + break; + + case 'v': + show_version = true; + break; + + case 'A': + if (strcmp(optarg, "bitmap") == 0) + g_scan_options_set_backend_for_data(options, G_TYPE_BITAP_BACKEND); + else if (strcmp(optarg, "acism") == 0) + g_scan_options_set_backend_for_data(options, G_TYPE_ACISM_BACKEND); + else + g_scan_options_set_backend_for_data(options, G_TYPE_INVALID); + break; + + case 'S': + g_scan_options_set_print_stats(options, true); + break; + + case 'V': + verbosity = strtoul(optarg, NULL, 10); + break; + + } + + } + + if ((optind + 2) != argc) + { + show_rost_help(argv[0]); + result = EXIT_FAILURE; + goto done; + } + + rules = argv[optind]; + target = argv[optind + 1]; + + /* Actions de base */ + + if (show_help) + { + show_rost_help(argv[0]); + result = EXIT_SUCCESS; + goto done; + } + + if (show_version) + { + show_rost_version(); + result = EXIT_SUCCESS; + goto done; + } + + if (g_scan_options_get_backend_for_data(options) == G_TYPE_INVALID) + { + show_rost_help(argv[0]); + result = EXIT_FAILURE; + goto done; + } + + /* Lancement des choses sérieuses */ + + setlocale(LC_ALL, ""); + edir = get_effective_directory(LOCALE_DIR); + bindtextdomain(PACKAGE, edir); + free(edir); + textdomain(PACKAGE); + + /* Initialisation de GTK */ + g_set_prgname("ROST"); + //gtk_init(&argc, &argv); + + /* Initialisation du programme */ + + set_batch_mode(); + + set_log_verbosity(verbosity); + + /* + if (!load_all_core_components(false)) + goto done; + */ + + /* Traitement des recherches */ + + scanner = g_content_scanner_new_from_file(rules); + + content = g_file_content_new(target); + + context = g_content_scanner_analyze(scanner, options, content); + + g_scan_context_display(context); + + g_object_unref(G_OBJECT(context)); + g_object_unref(G_OBJECT(content)); + + g_object_unref(G_OBJECT(scanner)); + + g_object_unref(G_OBJECT(options)); + + /* Sortie */ + + //unload_all_core_components(false); + +#ifdef TRACK_GOBJECT_LEAKS + remember_gtypes_for_leaks(); +#endif + +#ifdef TRACK_GOBJECT_LEAKS + dump_remaining_gtypes(); +#endif + + done: + + return result; + +} diff --git a/tests/analysis/scan/expr.py b/tests/analysis/scan/expr.py new file mode 100644 index 0000000..dbe8c55 --- /dev/null +++ b/tests/analysis/scan/expr.py @@ -0,0 +1,169 @@ + + +from chrysacase import ChrysalideTestCase +from pychrysalide.analysis.scan import ScanExpression +from pychrysalide.glibext import ComparableItem + + +class TestScanExpression(ChrysalideTestCase): + """TestCase for analysis.scan.ScanExpression.""" + + + def testDirectInstances(self): + """Reject direct instances.""" + + with self.assertRaisesRegex(RuntimeError, 'pychrysalide.analysis.scan.ScanExpression is an abstract class'): + + e = ScanExpression() + + + def testBooleanComparison(self): + """Compare custom scan expressions.""" + + class StrLenExpr(ScanExpression): + + def __init__(self, value): + super().__init__(ScanExpression.ExprValueType.STRING) + self._value = value + + def _cmp_rich(self, other, op): + + if op == ComparableItem.RichCmpOperation.EQ: + return len(self._value) == len(other._value) + + + e0 = StrLenExpr('00000000000') + + e1 = StrLenExpr('00000000000') + + e2 = StrLenExpr('000000000000000000000000000') + + self.assertTrue(e0 == e1) + + # !? + # Python teste e0 != e1 (non implémenté), puis e1 != e0 (pareil) et en déduit une différence ! + # self.assertFalse(e0 != e1) + + self.assertFalse(e0 == e2) + + # TypeError: '<' not supported between instances of 'StrLenExpr' and 'StrLenExpr' + with self.assertRaisesRegex(TypeError, '\'<\' not supported between instances'): + self.assertTrue(e0 < e1) + + + + + + + # def testTypeSubclassing(self): + # """Verify the data type subclassing is working.""" + + # class MyType(DataType): + + # def __init__(self, num): + # super(MyType, self).__init__() + # self._num = num + + # def _to_string(self, include): + # return '%x' % self._num + + # def _dup(self): + # return MyType(self._num) + + # tp = MyType(0x123) + + # self.assertEqual(str(tp), '123') + + # tp2 = tp.dup() + + # self.assertEqual(str(tp), str(tp2)) + + + # def testTypeDefaultProperties(self): + # """Check for default values of some type properties.""" + + # class MyPropType(DataType): + # pass + + # tp = MyPropType() + + # self.assertTrue(tp.handle_namespaces) + + # self.assertFalse(tp.is_pointer) + + # self.assertFalse(tp.is_reference) + + # class MyPropType2(DataType): + + # def _handle_namespaces(self): + # return True + + # def _is_pointer(self): + # return 123 < 1234 + + # def _is_reference(self): + # return False + + # tp2 = MyPropType2() + + # self.assertTrue(tp.handle_namespaces) + + # self.assertTrue(tp2.is_pointer) + + # self.assertFalse(tp2.is_reference) + + + # def testTypeNamespaces(self): + # """Test the type namespace property.""" + + # class MyNSType(DataType): + + # def __init__(self, name): + # super(MyNSType, self).__init__() + # self._name = name + + # def _to_string(self, include): + # return self._name + + # tp = MyNSType('TP') + # ns = MyNSType('NS') + + # self.assertIsNone(tp.namespace) + + # tp.namespace = (ns, '.') + + # self.assertEqual(str(tp), 'NS.TP') + + # self.assertEqual(tp.namespace, (ns, '.')) + + + # def testTypeHash(self): + # """Hash a user-defined type.""" + + # class MyUserType(DataType): + + # def __init__(self, name): + # super(MyUserType, self).__init__() + # self._name = name + + # def _hash(self): + # return hash(self._name) + + # tp = MyUserType('random') + + # self.assertEqual(tp.hash, hash('random') & ((1 << 32) - 1)) + + # class MyOutOfRangeUserType(DataType): + + # hard_coded_hash = -8752470794866657507 + + # def __init__(self, name): + # super(MyOutOfRangeUserType, self).__init__() + # self._name = name + + # def _hash(self): + # return self.hard_coded_hash + + # tp = MyOutOfRangeUserType('out-of-range') + + # self.assertEqual(tp.hash, MyOutOfRangeUserType.hard_coded_hash & ((1 << 32) - 1)) diff --git a/tests/analysis/scan/exprs.py b/tests/analysis/scan/exprs.py new file mode 100644 index 0000000..c89dc59 --- /dev/null +++ b/tests/analysis/scan/exprs.py @@ -0,0 +1,122 @@ + +from chrysacase import ChrysalideTestCase +from pychrysalide.analysis.contents import MemoryContent +from pychrysalide.analysis.scan import ContentScanner +from pychrysalide.analysis.scan import ScanOptions +from pychrysalide.analysis.scan.patterns.backends import AcismBackend + + +class TestScanExpressions(ChrysalideTestCase): + """TestCase for analysis.scan.exprs.*.""" + + @classmethod + def setUpClass(cls): + + super(TestScanExpressions, cls).setUpClass() + + cls._options = ScanOptions() + cls._options.backend_for_data = AcismBackend + + + def testBasicStringOperations(self): + """Evaluate basic string operations.""" + + cnt = MemoryContent(b'empty') + + rule = ''' +rule test { + + condition: + "123abc456" contains "abc" + +} +''' + + scanner = ContentScanner(rule) + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(ctx.has_match_for_rule('test')) + + rule = ''' +rule test { + + condition: + "123\t456" contains "\t" + +} +''' + + scanner = ContentScanner(rule) + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(ctx.has_match_for_rule('test')) + + rule = ''' +rule test { + + condition: + "123-456" startswith "1" + +} +''' + + scanner = ContentScanner(rule) + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(ctx.has_match_for_rule('test')) + + rule = ''' +rule test { + + condition: + "123-456" startswith "1234" + +} +''' + + scanner = ContentScanner(rule) + ctx = scanner.analyze(self._options, cnt) + + self.assertFalse(ctx.has_match_for_rule('test')) + + rule = ''' +rule test { + + condition: + "123-456" endswith "6" + +} +''' + + scanner = ContentScanner(rule) + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(ctx.has_match_for_rule('test')) + + rule = ''' +rule test { + + condition: + "123-456" endswith "3456" + +} +''' + + scanner = ContentScanner(rule) + ctx = scanner.analyze(self._options, cnt) + + self.assertFalse(ctx.has_match_for_rule('test')) + + rule = ''' +rule test { + + condition: + "ABCD" iequals "AbCd" + +} +''' + + scanner = ContentScanner(rule) + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(ctx.has_match_for_rule('test')) diff --git a/tests/analysis/scan/func.py b/tests/analysis/scan/func.py new file mode 100644 index 0000000..bd7d0ce --- /dev/null +++ b/tests/analysis/scan/func.py @@ -0,0 +1,16 @@ + + +from chrysacase import ChrysalideTestCase +from pychrysalide.analysis.scan import ScanFunction + + +class TestScanFunction(ChrysalideTestCase): + """TestCase for analysis.scan.ScanFunction.""" + + + def testDirectInstances(self): + """Reject direct instances.""" + + with self.assertRaisesRegex(RuntimeError, 'pychrysalide.analysis.scan.ScanFunction is an abstract class'): + + f = ScanFunction('name') diff --git a/tests/analysis/scan/grammar.py b/tests/analysis/scan/grammar.py new file mode 100644 index 0000000..5a2e1d5 --- /dev/null +++ b/tests/analysis/scan/grammar.py @@ -0,0 +1,286 @@ + +from chrysacase import ChrysalideTestCase +from pychrysalide.analysis.contents import MemoryContent +from pychrysalide.analysis.scan import ContentScanner +from pychrysalide.analysis.scan import ScanOptions +from pychrysalide.analysis.scan.patterns.backends import AcismBackend + + +class TestRostGrammar(ChrysalideTestCase): + """TestCase for analysis.scan.ScanExpression.""" + + @classmethod + def setUpClass(cls): + + super(TestRostGrammar, cls).setUpClass() + + cls._options = ScanOptions() + cls._options.backend_for_data = AcismBackend + + + def testComments(self): + """Ensure comments do not bother rule definitions.""" + + cnt = MemoryContent(b'no_real_content') + + rule = ''' +/* + Multi-line header... +*/ + +rule test { // comment + + /* + * Some context + */ + + condition: /* List of condition(s) */ + true // Dummy condition + +} +''' + + scanner = ContentScanner(rule) + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) + + + def testUintCast(self): + """Process nested integer values from binary content.""" + + cnt = MemoryContent(b'\x4d\x5a\x00\x00' + b'\x50\x45\x00\x00' + 52 * b'\x00' + b'\x04\x00\x00\x00') + + rule = ''' +rule IsPE { + + condition: + + // MZ signature at offset 0 and ... + + uint16(0) == 0x5a4d and + + // ... PE signature at offset stored in the MZ header at offset 0x3c + + uint32(uint32(0x3c)) == 0x00004550 + +} +''' + + scanner = ContentScanner(rule) + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('IsPE')) + + + def testBasicBooleanConditions(self): + """Evaluate basic boolean conditions.""" + + cnt = MemoryContent(b'0123') + + rule = ''' +rule test { + + condition: + true and false + +} +''' + + scanner = ContentScanner(rule) + + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(not(ctx is None)) + self.assertFalse(ctx.has_match_for_rule('test')) + + rule = ''' +rule test { + + condition: + true or false + +} +''' + + scanner = ContentScanner(rule) + + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) + + + def testArithmeticOpeations(self): + """Compute some arithmetic operations.""" + + cnt = MemoryContent(b'0123') + + rule = ''' +rule test { + + condition: + 1 + 4 * 3 + 2 == 15 + +} +''' + + scanner = ContentScanner(rule) + + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) + + + rule = ''' +rule test { + + condition: + (1 + 4) * 3 + 2 == 17 + +} +''' + + scanner = ContentScanner(rule) + + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) + + + rule = ''' +rule test { + + condition: + 1 + 4 * (3 + 2) == 21 + +} +''' + + scanner = ContentScanner(rule) + + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) + + + rule = ''' +rule test { + + condition: + (1 + 4) * (3 + 2) == 25 + +} +''' + + scanner = ContentScanner(rule) + + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) + + + def testSizeUnits(self): + """Evaluate size units.""" + + cnt = MemoryContent(b'0123') + + + rule = ''' +rule test { + + condition: + 1KB == 1024 + +} +''' + + scanner = ContentScanner(rule) + + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) + + + rule = ''' +rule test { + + condition: + 2MB == 2 * 1024 * 1024 + +} +''' + + scanner = ContentScanner(rule) + + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) + + + rule = ''' +rule test { + + condition: + 4Kb == (4 * 1024) + +} +''' + + scanner = ContentScanner(rule) + + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) + + + rule = ''' +rule test { + + condition: + 1KB <= 1024 and 1024 < 1MB + +} +''' + + scanner = ContentScanner(rule) + + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) + + + def testNamespace(self): + """Resolve main functions with the root scan namesapce.""" + + cnt = MemoryContent(b'\x01\x02\x03\x04') + + rule = ''' +rule test { + + condition: + datasize == 4 + +} +''' + + scanner = ContentScanner(rule) + + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) + + + rule = ''' +rule test { + + condition: + uint16(0) == 0x201 and uint16(datasize - 2) == 0x0403 + +} +''' + + scanner = ContentScanner(rule) + + ctx = scanner.analyze(self._options, cnt) + + self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) diff --git a/tests/analysis/scan/options.py b/tests/analysis/scan/options.py new file mode 100644 index 0000000..7617b3a --- /dev/null +++ b/tests/analysis/scan/options.py @@ -0,0 +1,16 @@ + + +from chrysacase import ChrysalideTestCase +from gi._constants import TYPE_INVALID +from pychrysalide.analysis.scan import ScanOptions + + +class TestScanOptions(ChrysalideTestCase): + """TestCase for analysis.scan.ScanOptions.""" + + def testEmptyOptions(self): + """Check default scan options.""" + + ops = ScanOptions() + + self.assertEqual(ops.backend_for_data, TYPE_INVALID) |