summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2021-04-06 22:55:54 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2021-04-06 22:55:54 (GMT)
commitc12d6a5d11bf9a2436ff78e393173ca59b6c9c46 (patch)
treeb579b642e301f5d6e6d88fb0213a54db6bf6fd38
parentc4d2e0fa48eab453d5c43a3c0938427617449a6a (diff)
Provide several kinds of hashes for binary files.
-rw-r--r--configure.ac2
-rw-r--r--plugins/Makefile.am1
-rw-r--r--plugins/bhash/Makefile.am52
-rw-r--r--plugins/bhash/core.c74
-rw-r--r--plugins/bhash/core.h38
-rw-r--r--plugins/bhash/imphash.c244
-rw-r--r--plugins/bhash/imphash.h40
-rw-r--r--plugins/bhash/python/Makefile.am21
-rw-r--r--plugins/bhash/python/imphash.c135
-rw-r--r--plugins/bhash/python/imphash.h39
-rw-r--r--plugins/bhash/python/module.c90
-rw-r--r--plugins/bhash/python/module.h38
-rw-r--r--plugins/bhash/python/rich.c194
-rw-r--r--plugins/bhash/python/rich.h39
-rw-r--r--plugins/bhash/python/tlsh.c256
-rw-r--r--plugins/bhash/python/tlsh.h39
-rw-r--r--plugins/bhash/rich.c181
-rw-r--r--plugins/bhash/rich.h44
-rw-r--r--plugins/bhash/tlsh.c724
-rw-r--r--plugins/bhash/tlsh.h46
-rw-r--r--plugins/pe/python/routine.c46
-rw-r--r--plugins/pe/routine.c31
-rw-r--r--plugins/pe/routine.h5
-rw-r--r--plugins/pe/symbols.c7
-rw-r--r--plugins/winordinals/assign.c2
25 files changed, 2380 insertions, 8 deletions
diff --git a/configure.ac b/configure.ac
index d7a6844..291acca 100644
--- a/configure.ac
+++ b/configure.ac
@@ -465,6 +465,8 @@ AC_CONFIG_FILES([Makefile
plugins/arm/v7/opcodes/Makefile
plugins/arm/v7/operands/Makefile
plugins/arm/v7/registers/Makefile
+ plugins/bhash/Makefile
+ plugins/bhash/python/Makefile
plugins/bootimg/Makefile
plugins/bootimg/python/Makefile
plugins/dalvik/Makefile
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 4addee5..608c927 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -9,6 +9,7 @@ endif
SUBDIRS = \
$(PYTHON3_SUBDIRS) \
arm \
+ bhash \
bootimg \
dex \
dalvik \
diff --git a/plugins/bhash/Makefile.am b/plugins/bhash/Makefile.am
new file mode 100644
index 0000000..44d1c21
--- /dev/null
+++ b/plugins/bhash/Makefile.am
@@ -0,0 +1,52 @@
+
+lib_LTLIBRARIES = libbhash.la
+
+libdir = $(pluginslibdir)
+
+
+if BUILD_PYTHON3_BINDINGS
+
+PYTHON3_LIBADD = \
+ python/libbhashpython.la
+
+if BUILD_DISCARD_LOCAL
+
+PYTHON3_LDFLAGS = -Wl,-rpath,$(pluginslibdir) \
+ -L$(top_srcdir)/plugins/pychrysalide/.libs -l:pychrysalide.so
+
+else
+
+PYTHON3_LDFLAGS = -Wl,-rpath,$(abs_top_srcdir)/plugins/pychrysalide/.libs \
+ -L$(top_srcdir)/plugins/pychrysalide/.libs -l:pychrysalide.so
+
+endif
+
+PYTHON3_SUBDIRS = python
+
+endif
+
+
+libbhash_la_SOURCES = \
+ core.h core.c \
+ imphash.h imphash.c \
+ tlsh.h tlsh.c \
+ rich.h rich.c
+
+libbhash_la_LIBADD = \
+ $(PYTHON3_LIBADD)
+
+libbhash_la_LDFLAGS = \
+ -L$(top_srcdir)/src/.libs -lchrysacore \
+ $(PYTHON3_LDFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir)
+
+dev_HEADERS = $(libbhash_la_SOURCES:%c=)
+
+
+AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
+AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
+
+SUBDIRS = $(PYTHON3_SUBDIRS)
diff --git a/plugins/bhash/core.c b/plugins/bhash/core.c
new file mode 100644
index 0000000..91a0bf2
--- /dev/null
+++ b/plugins/bhash/core.c
@@ -0,0 +1,74 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.c - prototypes pour le calcul d'empreintes de binaires
+ *
+ * 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "core.h"
+
+
+#include <config.h>
+#include <plugins/self.h>
+
+
+#ifdef HAVE_PYTHON3_BINDINGS
+# include "python/module.h"
+#endif
+
+
+#ifdef HAVE_PYTHON3_BINDINGS_
+# define PG_REQ RL("PyChrysalide")
+#else
+# define PG_REQ NO_REQ
+#endif
+
+
+
+DEFINE_CHRYSALIDE_PLUGIN("BHash", "Special hash methods for binaries",
+ PACKAGE_VERSION, CHRYSALIDE_WEBSITE("doc/formats"),
+ PG_REQ, AL(PGA_PLUGIN_INIT));
+
+
+
+/******************************************************************************
+* *
+* Paramètres : plugin = greffon à manipuler. *
+* *
+* Description : Prend acte du chargement du greffon. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
+{
+ bool result; /* Bilan à retourner */
+
+#ifdef HAVE_PYTHON3_BINDINGS
+ result = add_bhash_module_to_python_module();
+#else
+ result = true;
+#endif
+
+ return result;
+
+}
diff --git a/plugins/bhash/core.h b/plugins/bhash/core.h
new file mode 100644
index 0000000..bc6d9e9
--- /dev/null
+++ b/plugins/bhash/core.h
@@ -0,0 +1,38 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.h - prototypes pour le calcul d'empreintes de binaires
+ *
+ * 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_BHASH_CORE_H
+#define _PLUGINS_BHASH_CORE_H
+
+
+#include <plugins/plugin.h>
+#include <plugins/plugin-int.h>
+
+
+
+/* Prend acte du chargement du greffon. */
+G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *);
+
+
+
+#endif /* _PLUGINS_BHASH_CORE_H */
diff --git a/plugins/bhash/imphash.c b/plugins/bhash/imphash.c
new file mode 100644
index 0000000..2352bac
--- /dev/null
+++ b/plugins/bhash/imphash.c
@@ -0,0 +1,244 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * imphash.c - calculs d'empreintes sur la base des importations
+ *
+ * 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "imphash.h"
+
+
+#include <malloc.h>
+#include <stdlib.h>
+#include <strings.h>
+
+
+#include <common/extstr.h>
+#include <common/sort.h>
+#include <plugins/pe/format.h>
+#include <plugins/pe/routine.h>
+
+
+
+/* Mémorisation d'un symbole importé */
+typedef struct _imported_sym_t
+{
+ size_t index; /* Position dans les imports */
+ char *name; /* Désignation pour empreinte */
+
+} imported_sym_t;
+
+/* Dresse la liste des symboles importés pour un format. */
+static imported_sym_t *list_all_pe_imports_for_hash(const GPeFormat *, size_t *);
+
+/* Etablit une comparaison entre deux importations. */
+static int compare_imports_by_name(const imported_sym_t *, const imported_sym_t *);
+
+/* Etablit une comparaison entre deux importations. */
+static int compare_imports_by_index(const imported_sym_t *, const imported_sym_t *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : format = format chargé dont l'analyse est faite. *
+* count = taille de la liste retournée. [OUT] *
+* *
+* Description : Dresse la liste des symboles importés pour un format. *
+* *
+* Retour : Liste de symboles mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static imported_sym_t *list_all_pe_imports_for_hash(const GPeFormat *format, size_t *count)
+{
+ imported_sym_t *result; /* Liste de symboles */
+ GBinFormat *base; /* Format basique du binaire */
+ size_t sym_count; /* Nombre de ces symboles */
+ size_t i; /* Boucle de parcours */
+ GBinSymbol *symbol; /* Commodité d'accès */
+ const char *name; /* Désignation actuelle */
+ const char *library; /* Fichier DLL à charger */
+ char *item; /* Nouvelle entrée de la liste */
+ char *dot; /* Point à raccourcir */
+
+ result = NULL;
+ *count = 0;
+
+ base = G_BIN_FORMAT(format);
+
+ g_binary_format_lock_symbols_rd(base);
+
+ sym_count = g_binary_format_count_symbols(base);
+
+ for (i = 0; i < sym_count; i++)
+ {
+ symbol = g_binary_format_get_symbol(base, i);
+
+ if (!G_IS_PE_IMPORTED_ROUTINE(symbol))
+ goto next;
+
+ name = g_binary_routine_get_name(G_BIN_ROUTINE(symbol));
+
+ if (name == NULL)
+ goto next;
+
+ library = g_pe_imported_routine_get_library(G_PE_IMPORTED_ROUTINE(symbol));
+
+ if (library == NULL)
+ goto next;
+
+ item = malloc((strlen(library) + 1 + strlen(name) + 1) * sizeof(char));
+
+ strcpy(item, library);
+
+ dot = strchr(item, '.');
+
+ if (dot != NULL)
+ *dot = '\0';
+
+ strcat(item, ".");
+ strcat(item, name);
+
+ item = strlower(item);
+
+ result = realloc(result, ++(*count) * sizeof(imported_sym_t));
+
+ result[*count - 1].index = g_pe_imported_routine_get_index(G_PE_IMPORTED_ROUTINE(symbol));
+ result[*count - 1].name = item;
+
+ next:
+
+ g_object_unref(G_OBJECT(symbol));
+
+ }
+
+ g_binary_format_unlock_symbols_rd(base);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : p1 = première importation à traiter. *
+* p2 = seconde importation à traiter. *
+* *
+* Description : Etablit une comparaison entre deux importations. *
+* *
+* Retour : Bilan de la comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int compare_imports_by_name(const imported_sym_t *p1, const imported_sym_t *p2)
+{
+ int result; /* Bilan à retourner */
+
+ result = strcmp(p1->name, p2->name);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : p1 = première importation à traiter. *
+* p2 = seconde importation à traiter. *
+* *
+* Description : Etablit une comparaison entre deux importations. *
+* *
+* Retour : Bilan de la comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int compare_imports_by_index(const imported_sym_t *p1, const imported_sym_t *p2)
+{
+ int result; /* Bilan à retourner */
+
+ result = sort_unsigned_long(p1->index, p2->index);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : format = format en place à consulter. *
+* std = précise si la méthode de calcul est standard. *
+* *
+* Description : Calcule l'empreinte des importations d'un format PE. *
+* *
+* Retour : Empreinte MD5 calculée ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *compute_pe_import_hash(const GPeFormat *format, bool std)
+{
+ char *result; /* Empreinte à retourner */
+ size_t count; /* Quantité de symboles */
+ imported_sym_t *list; /* Liste de symboles */
+ GChecksum *checksum; /* Preneur d'empreinte */
+ size_t i; /* Boucle de parcours */
+
+ result = NULL;
+
+ list = list_all_pe_imports_for_hash(format, &count);
+
+ if (list != NULL)
+ {
+ if (std)
+ qsort(list, count, sizeof(imported_sym_t), (__compar_fn_t)compare_imports_by_name);
+ else
+ qsort(list, count, sizeof(imported_sym_t), (__compar_fn_t)compare_imports_by_index);
+
+ checksum = g_checksum_new(G_CHECKSUM_MD5);
+
+ for (i = 0; i < count; i++)
+ {
+ if (i > 0)
+ g_checksum_update(checksum, (unsigned char *)",", 1);
+
+ g_checksum_update(checksum, (unsigned char *)list[i].name, strlen(list[i].name));
+
+ free(list[i].name);
+
+ }
+
+ result = strdup(g_checksum_get_string(checksum));
+
+ g_checksum_free(checksum);
+
+ free(list);
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/bhash/imphash.h b/plugins/bhash/imphash.h
new file mode 100644
index 0000000..d2f5946
--- /dev/null
+++ b/plugins/bhash/imphash.h
@@ -0,0 +1,40 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * imphash.h - prototypes pour les calculs d'empreintes sur la base des importations
+ *
+ * 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_BHASH_IMPHASH_H
+#define _PLUGINS_BHASH_IMPHASH_H
+
+
+#include <stdbool.h>
+
+
+#include <plugins/pe/format.h>
+
+
+
+/* Calcule l'empreinte des importations d'un format PE. */
+char *compute_pe_import_hash(const GPeFormat *, bool);
+
+
+
+#endif /* _PLUGINS_BHASH_IMPHASH_H */
diff --git a/plugins/bhash/python/Makefile.am b/plugins/bhash/python/Makefile.am
new file mode 100644
index 0000000..822a716
--- /dev/null
+++ b/plugins/bhash/python/Makefile.am
@@ -0,0 +1,21 @@
+
+noinst_LTLIBRARIES = libbhashpython.la
+
+libbhashpython_la_SOURCES = \
+ imphash.h imphash.c \
+ module.h module.c \
+ tlsh.h tlsh.c \
+ rich.h rich.c
+
+libbhashpython_la_LDFLAGS =
+
+
+devdir = $(includedir)/chrysalide/$(subdir)
+
+dev_HEADERS = $(libbhashpython_la_SOURCES:%c=)
+
+
+AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+ -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT
+
+AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
diff --git a/plugins/bhash/python/imphash.c b/plugins/bhash/python/imphash.c
new file mode 100644
index 0000000..c01628d
--- /dev/null
+++ b/plugins/bhash/python/imphash.c
@@ -0,0 +1,135 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * imphash.c - équivalent Python du fichier "plugins/bhash/imphash.c"
+ *
+ * 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 "imphash.h"
+
+
+#include <pygobject.h>
+
+
+#include <plugins/pe/python/format.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../imphash.h"
+
+
+
+/* Calcule l'empreinte des importations d'un format PE. */
+static PyObject *py_bhash_compute_pe_import_hash(PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* args = paramètre à récupérer pour le traitement. *
+* *
+* Description : Calcule l'empreinte des importations d'un format PE. *
+* *
+* Retour : Empreinte MD5 calculée ou None en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_bhash_compute_pe_import_hash(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Valeur à retourner */
+ int std; /* Méthode de calcul */
+ GPeFormat *format; /* Format PE à manipuler */
+ int ret; /* Bilan de lecture des args. */
+ char *digest; /* Empreinte calculée */
+
+#define BHASH_COMPUTE_PE_IMPORT_HASH_METHOD PYTHON_METHOD_DEF \
+( \
+ compute_pe_import_hash, "format, /, std=True", \
+ METH_VARARGS, py_bhash, \
+ "Compute the import hash for a given PE format.\n" \
+ "\n" \
+ "The *format* argument is a PE file format provided as a" \
+ " pychrysalide.format.pe.PeFormat instance and *std* defines the" \
+ " kind of hash to compute.\n" \
+ "\n" \
+ "The standard version has been created by Mandiant/FireEye; the" \
+ " other one is used by the popular pefile Python module.\n" \
+ "\n" \
+ "The returned value is a MD5 digest string or *None* in case of" \
+ " error." \
+)
+
+ result = NULL;
+
+ std = 1;
+
+ ret = PyArg_ParseTuple(args, "O&|p", convert_to_pe_format, &format, &std);
+ if (!ret) goto exit;
+
+ digest = compute_pe_import_hash(format, std);
+
+ if (digest != NULL)
+ {
+ result = PyUnicode_FromString(digest);
+ free(digest);
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : super = module dont la définition est à compléter. *
+* *
+* Description : Définit une extension du module 'bhash' à compléter. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_bhash_module_with_imphash(PyObject *super)
+{
+ bool result; /* Bilan à retourner */
+
+ static PyMethodDef py_imphash_methods[] = {
+ BHASH_COMPUTE_PE_IMPORT_HASH_METHOD,
+ { NULL }
+ };
+
+ result = register_python_module_methods(super, py_imphash_methods);
+
+ return result;
+
+}
diff --git a/plugins/bhash/python/imphash.h b/plugins/bhash/python/imphash.h
new file mode 100644
index 0000000..fa5ff2c
--- /dev/null
+++ b/plugins/bhash/python/imphash.h
@@ -0,0 +1,39 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * imphash.h - équivalent Python du fichier "plugins/bhash/imphash.h"
+ *
+ * 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_BHASH_PYTHON_IMPHASH_H
+#define _PLUGINS_BHASH_PYTHON_IMPHASH_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Définit une extension du module 'bhash' à compléter. */
+bool populate_bhash_module_with_imphash(PyObject *);
+
+
+
+#endif /* _PLUGINS_BHASH_PYTHON_IMPHASH_H */
diff --git a/plugins/bhash/python/module.c b/plugins/bhash/python/module.c
new file mode 100644
index 0000000..deb5d28
--- /dev/null
+++ b/plugins/bhash/python/module.c
@@ -0,0 +1,90 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.c - intégration du répertoire bhash en tant que module
+ *
+ * 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 "module.h"
+
+
+#include <assert.h>
+#include <Python.h>
+
+
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "imphash.h"
+#include "tlsh.h"
+#include "rich.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Ajoute le module 'plugins.bhash' au module Python. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool add_bhash_module_to_python_module(void)
+{
+ bool result; /* Bilan à retourner */
+ PyObject *super; /* Module à compléter */
+ PyObject *module; /* Sous-module mis en place */
+
+#define PYCHRYSALIDE_PLUGINS_BHASH_DOC \
+ "bhash is a module providing several kinds of hashes for binary files."
+
+ static PyModuleDef py_chrysalide_bhash_module = {
+
+ .m_base = PyModuleDef_HEAD_INIT,
+
+ .m_name = "pychrysalide.plugins.bhash",
+ .m_doc = PYCHRYSALIDE_PLUGINS_BHASH_DOC,
+
+ .m_size = -1,
+
+ };
+
+ result = false;
+
+ super = get_access_to_python_module("pychrysalide.plugins");
+
+ module = build_python_module(super, &py_chrysalide_bhash_module);
+
+ result = (module != NULL);
+
+ if (result) result = populate_bhash_module_with_imphash(module);
+ if (result) result = populate_bhash_module_with_tlsh(module);
+ if (result) result = populate_bhash_module_with_rich_header(module);
+
+ assert(result);
+
+ return result;
+
+}
diff --git a/plugins/bhash/python/module.h b/plugins/bhash/python/module.h
new file mode 100644
index 0000000..057cfdf
--- /dev/null
+++ b/plugins/bhash/python/module.h
@@ -0,0 +1,38 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * module.h - prototypes pour l'intégration du répertoire bhash en tant que module
+ *
+ * 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_BHASH_PYTHON_MODULE_H
+#define _PLUGINS_BHASH_PYTHON_MODULE_H
+
+
+#include <stdbool.h>
+
+
+
+/* Ajoute le module 'plugins.bhash' au module Python. */
+bool add_bhash_module_to_python_module(void);
+
+
+
+#endif /* _PLUGINS_BHASH_PYTHON_MODULE_H */
diff --git a/plugins/bhash/python/rich.c b/plugins/bhash/python/rich.c
new file mode 100644
index 0000000..1a8b894
--- /dev/null
+++ b/plugins/bhash/python/rich.c
@@ -0,0 +1,194 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * rich.c - équivalent Python du fichier "plugins/bhash/rich.c"
+ *
+ * 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 "rich.h"
+
+
+#include <pygobject.h>
+
+
+#include <plugins/pe/python/format.h>
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../rich.h"
+
+
+
+/* Calcule la valeur pour empreinte d'en-tête PE enrichi. */
+static PyObject *py_bhash_compute_pe_rich_header_checksum(PyObject *, PyObject *);
+
+/* Calcule l'empreinte des informations d'en-tête PE enrichi. */
+static PyObject *py_bhash_compute_pe_rich_header_hash(PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* args = paramètre à récupérer pour le traitement. *
+* *
+* Description : Calcule la valeur pour empreinte d'en-tête PE enrichi. *
+* *
+* Retour : None ou empreinte déterminée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_bhash_compute_pe_rich_header_checksum(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Valeur à retourner */
+ GPeFormat *format; /* Format PE à manipuler */
+ int ret; /* Bilan de lecture des args. */
+ uint32_t csum; /* Empreinte réalisée */
+ bool status; /* Bilan de l'opération */
+
+#define BHASH_COMPUTE_PE_RICH_HEADER_CHECKSUM_METHOD PYTHON_METHOD_DEF \
+( \
+ compute_pe_rich_header_checksum, "format, /", \
+ METH_VARARGS, py_bhash, \
+ "Compute the expected value for the Rich header checksum of a PE" \
+ " file.\n" \
+ "\n" \
+ "The *format* argument is a PE file format provided as a" \
+ " pychrysalide.format.pe.PeFormat instance.\n" \
+ "\n" \
+ "The returned value is a 32-bit integer value or *None* in case of" \
+ " error." \
+)
+
+ result = NULL;
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_pe_format, &format);
+ if (!ret) goto exit;
+
+ status = compute_pe_rich_header_checksum(format, &csum);
+
+ if (status)
+ result = PyLong_FromUnsignedLong(csum);
+
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* args = paramètre à récupérer pour le traitement. *
+* *
+* Description : Calcule l'empreinte des informations d'en-tête PE enrichi. *
+* *
+* Retour : Empreinte MD5 calculée ou None en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_bhash_compute_pe_rich_header_hash(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Valeur à retourner */
+ int pv; /* Sélection de l'empreinte */
+ GPeFormat *format; /* Format PE à manipuler */
+ int ret; /* Bilan de lecture des args. */
+ char *digest; /* Empreinte calculée */
+
+#define BHASH_COMPUTE_PE_RICH_HEADER_HASH_METHOD PYTHON_METHOD_DEF \
+( \
+ compute_pe_rich_header_hash, "format, /, pv=True", \
+ METH_VARARGS, py_bhash, \
+ "Compute the Rich hash or the RichPV hash for a given PE format.\n" \
+ "\n" \
+ "The *format* argument is a PE file format provided as a" \
+ " pychrysalide.format.pe.PeFormat instance and *pv* defines the" \
+ " kind of hash to compute.\n" \
+ "\n" \
+ "The returned value is a MD5 digest string or *None* in case of" \
+ " error." \
+)
+
+ result = NULL;
+
+ pv = 1;
+
+ ret = PyArg_ParseTuple(args, "O&|p", convert_to_pe_format, &format, &pv);
+ if (!ret) goto exit;
+
+ digest = compute_pe_rich_header_hash(format, pv);
+
+ if (digest != NULL)
+ {
+ result = PyUnicode_FromString(digest);
+ free(digest);
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : super = module dont la définition est à compléter. *
+* *
+* Description : Définit une extension du module 'bhash' à compléter. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_bhash_module_with_rich_header(PyObject *super)
+{
+ bool result; /* Bilan à retourner */
+
+ static PyMethodDef py_rich_header_methods[] = {
+ BHASH_COMPUTE_PE_RICH_HEADER_CHECKSUM_METHOD,
+ BHASH_COMPUTE_PE_RICH_HEADER_HASH_METHOD,
+ { NULL }
+ };
+
+ result = register_python_module_methods(super, py_rich_header_methods);
+
+ return result;
+
+}
diff --git a/plugins/bhash/python/rich.h b/plugins/bhash/python/rich.h
new file mode 100644
index 0000000..45125bc
--- /dev/null
+++ b/plugins/bhash/python/rich.h
@@ -0,0 +1,39 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * rich.h - équivalent Python du fichier "plugins/bhash/rich.h"
+ *
+ * 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_BHASH_PYTHON_RICH_H
+#define _PLUGINS_BHASH_PYTHON_RICH_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Définit une extension du module 'bhash' à compléter. */
+bool populate_bhash_module_with_rich_header(PyObject *);
+
+
+
+#endif /* _PLUGINS_BHASH_PYTHON_RICH_H */
diff --git a/plugins/bhash/python/tlsh.c b/plugins/bhash/python/tlsh.c
new file mode 100644
index 0000000..351327e
--- /dev/null
+++ b/plugins/bhash/python/tlsh.c
@@ -0,0 +1,256 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tlsh.c - équivalent Python du fichier "plugins/bhash/tlsh.c"
+ *
+ * Copyright (C) 2021 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 "tlsh.h"
+
+
+#include <pygobject.h>
+
+
+#include <plugins/pychrysalide/access.h>
+#include <plugins/pychrysalide/helpers.h>
+#include <plugins/pychrysalide/analysis/content.h>
+
+
+#include "../tlsh.h"
+
+
+
+/* Calcule l'empreinte TLSH d'un contenu binaire. */
+static PyObject *py_bhash_compute_content_tlsh_hash(PyObject *, PyObject *);
+
+/* Indique si une chaîne représente à priori une empreinte TLSH. */
+static PyObject *py_bhash_is_valid_tlsh_hash(PyObject *, PyObject *);
+
+/* Détermine la similarité entre deux empreintes TLSH. */
+static PyObject *py_bhash_compare_tlsh_hash(PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* args = paramètre à récupérer pour le traitement. *
+* *
+* Description : Calcule l'empreinte TLSH d'un contenu binaire. *
+* *
+* Retour : Empreinte TLSH calculée ou None en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_bhash_compute_content_tlsh_hash(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Valeur à retourner */
+ int version; /* Affichage de la version ? */
+ GBinContent *content; /* Contenu binaire à traiter */
+ int ret; /* Bilan de lecture des args. */
+ char *digest; /* Empreinte calculée */
+
+#define BHASH_COMPUTE_CONTENT_TLSH_HASH_METHOD PYTHON_METHOD_DEF \
+( \
+ compute_content_tlsh_hash, "content, /, version=True", \
+ METH_VARARGS, py_bhash, \
+ "Compute the TLSH compact hash for a given binary content with a" \
+ " 1-byte checksum.\n" \
+ "\n" \
+ "The *content* argument is a pychrysalide.analysis.BinContent" \
+ " instance providing the data to process. The optional *version*" \
+ " parameter add a 'T?' prefix to the result.\n" \
+ "\n" \
+ "The returned value is a MD5 digest string or *None* in case of" \
+ " error." \
+)
+
+ result = NULL;
+
+ version = 1;
+
+ ret = PyArg_ParseTuple(args, "O&|p", convert_to_binary_content, &content, &version);
+ if (!ret) goto exit;
+
+ digest = compute_content_tlsh_hash(content, version);
+
+ if (digest != NULL)
+ {
+ result = PyUnicode_FromString(digest);
+ free(digest);
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* args = paramètre à récupérer pour le traitement. *
+* *
+* Description : Indique si une chaîne représente à priori une empreinte TLSH.*
+* *
+* Retour : Bilan de l'analyse. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_bhash_is_valid_tlsh_hash(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Valeur à retourner */
+ const char *h; /* Chaîne à considérer */
+ int ret; /* Bilan de lecture des args. */
+ bool status; /* Validité de la chaîne */
+
+#define BHASH_IS_VALID_TLSH_HASH_METHOD PYTHON_METHOD_DEF \
+( \
+ is_valid_tlsh_hash, "h", \
+ METH_VARARGS, py_bhash, \
+ "Check if a *h* string can be considered as a valid TLSH compact" \
+ " hash.\n" \
+ "\n" \
+ "The returned value is a boolean value." \
+)
+
+ result = NULL;
+
+ ret = PyArg_ParseTuple(args, "s", &h);
+ if (!ret) goto exit;
+
+ status = is_valid_tlsh_hash(h);
+
+ result = status ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* args = paramètres à récupérer pour le traitement. *
+* *
+* Description : Détermine la similarité entre deux empreintes TLSH. *
+* *
+* Retour : Degré de différence relevé ou None en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_bhash_compare_tlsh_hash(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Valeur à retourner */
+ bool length; /* Indication de taille ? */
+ const char *ha; /* Première chaîne à considérer*/
+ const char *hb; /* Seconde chaîne à considérer */
+ int ret; /* Bilan de lecture des args. */
+ int32_t diff; /* Différence à calculer */
+ bool status; /* Validité de l'opération */
+
+#define BHASH_COMPARE_TLSH_HASH_METHOD PYTHON_METHOD_DEF \
+( \
+ compare_tlsh_hash, "ha, hb, /, length=True", \
+ METH_VARARGS, py_bhash, \
+ "Compare two TLSH compact hashes.\n" \
+ "\n" \
+ "The *ha* and *hb* arguments are strings from which the hashes" \
+ " will be rebuilt. The" \
+ " pychrysalide.plugins.bhash.compute_content_tlsh_hash() method" \
+ " can be used to create such strings. The filtering of valid" \
+ " inputs rely internally on the" \
+ " pychrysalide.plugins.bhash.is_valid_tlsh_hash() function.\n" \
+ "\n" \
+ "The *length* argument defines if the TLSH data size hint has to" \
+ " be considered by the comparison process.\n" \
+ "\n" \
+ "The returned value is a difference level provided as an integer" \
+ " value or *None* in case of error." \
+)
+
+ result = NULL;
+
+ length = 1;
+
+ ret = PyArg_ParseTuple(args, "ss|p", &ha, &hb, &length);
+ if (!ret) goto exit;
+
+ status = compare_tlsh_hash(ha, hb, length, &diff);
+
+ if (status)
+ result = PyLong_FromLong(diff);
+
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : super = module dont la définition est à compléter. *
+* *
+* Description : Définit une extension du module 'bhash' à compléter. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool populate_bhash_module_with_tlsh(PyObject *super)
+{
+ bool result; /* Bilan à retourner */
+
+ static PyMethodDef py_tlsh_methods[] = {
+ BHASH_COMPUTE_CONTENT_TLSH_HASH_METHOD,
+ BHASH_IS_VALID_TLSH_HASH_METHOD,
+ BHASH_COMPARE_TLSH_HASH_METHOD,
+ { NULL }
+ };
+
+ result = register_python_module_methods(super, py_tlsh_methods);
+
+ return result;
+
+}
diff --git a/plugins/bhash/python/tlsh.h b/plugins/bhash/python/tlsh.h
new file mode 100644
index 0000000..7312b97
--- /dev/null
+++ b/plugins/bhash/python/tlsh.h
@@ -0,0 +1,39 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tlsh.h - équivalent Python du fichier "plugins/bhash/tlsh.h"
+ *
+ * Copyright (C) 2021 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_BHASH_PYTHON_TLSH_H
+#define _PLUGINS_BHASH_PYTHON_TLSH_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Définit une extension du module 'bhash' à compléter. */
+bool populate_bhash_module_with_tlsh(PyObject *);
+
+
+
+#endif /* _PLUGINS_BHASH_PYTHON_TLSH_H */
diff --git a/plugins/bhash/rich.c b/plugins/bhash/rich.c
new file mode 100644
index 0000000..b5bed4e
--- /dev/null
+++ b/plugins/bhash/rich.c
@@ -0,0 +1,181 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * rich.c - calculs d'empreintes relatifs aux en-têtes PE enrichis
+ *
+ * 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "rich.h"
+
+
+#include <format/known.h>
+#include <plugins/pe/rich.h>
+
+
+
+/******************************************************************************
+* *
+* Paramètres : format = format en place à consulter. *
+* csum = empreinte à déterminer. [OUT] *
+* *
+* Description : Calcule la valeur pour empreinte d'en-tête PE enrichi. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool compute_pe_rich_header_checksum(const GPeFormat *format, uint32_t *csum)
+{
+ bool result; /* Bilan à retourner */
+ mrange_t area; /* Zone couverte par l'en-tête */
+ GBinContent *content; /* Contenu à parcourir */
+ vmpa2t start; /* Position de départ */
+ phys_t offset; /* Position du début d'en-tête */
+ const bin_t *data; /* Données brutes à analyser */
+ phys_t i; /* Boucle de parcours #0 */
+ comp_id_t *ids; /* Identifiants à traiter */
+ size_t count; /* Quantité de ces identifiants*/
+ size_t k; /* Boucle de parcours #1 */
+
+ result = g_pe_format_get_rich_header_area(format, &area);
+
+ if (!result)
+ *csum = 0;
+
+ else
+ {
+
+#define rol32(word, shift) \
+ ((uint32_t)word) << (shift & 31) | ((uint32_t)word) >> (32 - (shift & 31))
+
+ /* Première source de calculs */
+
+ content = g_known_format_get_content(G_KNOWN_FORMAT(format));
+
+ g_binary_content_compute_start_pos(content, &start);
+
+ offset = get_phy_addr(get_mrange_addr(&area)) - get_phy_addr(&start);
+
+ *csum = offset;
+
+ data = g_binary_content_get_raw_access(content, &start, offset);
+ if (data == NULL)
+ {
+ g_object_unref(G_OBJECT(content));
+ result = false;
+ goto exit;
+ }
+
+ for (i = 0; i < offset; i++)
+ {
+ /* Saut du champ e_lfanew, non initialisé lors de la construction */
+ if (0x3c <= i && i < 0x40)
+ continue;
+
+ *csum += rol32(data[i], i);
+
+ }
+
+ g_object_unref(G_OBJECT(content));
+
+ /* Seconde source de calculs */
+
+ ids = g_pe_format_get_comp_ids(format, &count);
+
+ for (k = 0; k < count; k++)
+ *csum += rol32((ids[k].prod_id << 16) | ids[k].minor_cv, ids[k].count);
+
+ if (ids != NULL)
+ free(ids);
+
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : format = format en place à consulter. *
+* pv = forme d'empreinte à construire. *
+* *
+* Description : Calcule l'empreinte des informations d'en-tête PE enrichi. *
+* *
+* Retour : Empreinte MD5 calculée ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *compute_pe_rich_header_hash(const GPeFormat *format, bool pv)
+{
+ char *result; /* Empreinte à retourner */
+ comp_id_t *ids; /* Identifiants à traiter */
+ size_t count; /* Quantité de ces identifiants*/
+ GChecksum *checksum; /* Preneur d'empreinte */
+ size_t i; /* Boucle de parcours */
+ uint32_t value; /* Valeur à prendre en compte */
+
+ ids = g_pe_format_get_comp_ids(format, &count);
+
+ if (ids == NULL)
+ result = NULL;
+
+ else
+ {
+ checksum = g_checksum_new(G_CHECKSUM_MD5);
+
+ if (!pv)
+ {
+ g_checksum_update(checksum, "DanS", 4);
+ g_checksum_update(checksum, "\x00\x00\x00\x00", 4);
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ if (pv && i == 0)
+ continue;
+
+ value = (ids[i].prod_id << 16) | ids[i].minor_cv;
+ g_checksum_update(checksum, (char *)&value, sizeof(value));
+
+ if (!pv)
+ {
+ value = ids[i].count;
+ g_checksum_update(checksum, (char *)&value, sizeof(value));
+ }
+
+ }
+
+ result = strdup(g_checksum_get_string(checksum));
+
+ g_checksum_free(checksum);
+
+ free(ids);
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/bhash/rich.h b/plugins/bhash/rich.h
new file mode 100644
index 0000000..051c9f6
--- /dev/null
+++ b/plugins/bhash/rich.h
@@ -0,0 +1,44 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * rich.h - prototypes pour les calculs d'empreintes relatifs aux en-têtes PE enrichis
+ *
+ * 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_BHASH_RICH_H
+#define _PLUGINS_BHASH_RICH_H
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+
+#include <plugins/pe/format.h>
+
+
+
+/* Calcule la valeur pour empreinte d'en-tête PE enrichi. */
+bool compute_pe_rich_header_checksum(const GPeFormat *, uint32_t *);
+
+/* Calcule l'empreinte des informations d'en-tête PE enrichi. */
+char *compute_pe_rich_header_hash(const GPeFormat *, bool);
+
+
+
+#endif /* _PLUGINS_BHASH_RICH_H */
diff --git a/plugins/bhash/tlsh.c b/plugins/bhash/tlsh.c
new file mode 100644
index 0000000..92064de
--- /dev/null
+++ b/plugins/bhash/tlsh.c
@@ -0,0 +1,724 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tlsh.c - calculs d'empreintes selon l'algorithme TLSH
+ *
+ * Copyright (C) 2021 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/>.
+ */
+
+
+#include "tlsh.h"
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+
+
+#include <common/hex.h>
+#include <common/pearson.h>
+
+
+#define BUCKETS_COUNT 256
+
+#define BUCKETS_USED 128
+
+#define HASH_CODE_SIZE ((BUCKETS_USED * 2) / 8)
+
+#define TLSH_STRING_LEN (2 + 2 + 2 + 2 + HASH_CODE_SIZE * 2)
+
+#define TLSH_LENGTH_MULTIPLIER 12
+#define TLSH_QRATIO_MULTIPLIER 12
+
+
+/* Mémorisation des informations brutes */
+typedef struct _tlsh_info_t
+{
+ phys_t data_length; /* Taille des données traitées */
+
+ uint32_t buckets[BUCKETS_COUNT]; /* Bac pour compteurs */
+ uint8_t checksum; /* Empreinte globale */
+
+ uint32_t q1; /* Première valeur pivot (75%) */
+ uint32_t q2; /* Deuxième valeur pivot (50%) */
+ uint32_t q3; /* Troisième valeur pivot (25%)*/
+
+ uint8_t q1_ratio : 4; /* Ratio de portion #1 */
+ uint8_t q2_ratio : 4; /* Ratio de portion #2 */
+
+ uint8_t captured_length; /* Tranche associée à la taille*/
+
+} tlsh_info_t;
+
+/* Récupération des informations d'une empreinte */
+typedef struct _recovered_tlsh_info_t
+{
+ uint8_t checksum; /* Empreinte globale */
+
+ uint8_t captured_length; /* Tranche associée à la taille*/
+
+ uint8_t q1_ratio : 4; /* Ratio de portion #1 */
+ uint8_t q2_ratio : 4; /* Ratio de portion #2 */
+
+ uint8_t code[HASH_CODE_SIZE]; /* Coeur de l'empreinte */
+
+} recovered_tlsh_info_t;
+
+
+/* Détermine l'indice du compteur destiné à un triplet d'octets. */
+static uint8_t define_tlsh_mapping(uint8_t, uint8_t, uint8_t, uint8_t);
+
+/* Définit tous les compteurs associés aux triplets d'octets. */
+static bool fill_tlsh_buckets(const GBinContent *, tlsh_info_t *);
+
+/* Compare deux compteurs de triplets d'octets. */
+static int compare_tlsh_buckets(const uint32_t *, const uint32_t *);
+
+/* Détermine les points de pivot au sein des bacs de compteurs. */
+static void find_tlsh_quartiles(tlsh_info_t *);
+
+/* Construit une empreinte TLSH sur les bases calculées. */
+static char *build_tlsh_hash(const tlsh_info_t *, bool);
+
+/* Reconstruit les informations portées par une empreinte TLSH. */
+static bool recover_tlsh_hash(const char *, recovered_tlsh_info_t *);
+
+/* Calcule une différence entre deux valeurs selon deux axes. */
+static int32_t diff_tlsh_values_two_way(uint32_t, uint32_t, uint32_t);
+
+/* Calcule le degré de différence entre deux octets TLSH. */
+static uint8_t diff_tlsh_bits(uint8_t, uint8_t);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : salt = sel à intégrer à la préparation. *
+* b0 = premier octet à manipuler. *
+* b1 = deuxième octet à manipuler. *
+* b2 = troisième octet à manipuler. *
+* *
+* Description : Détermine l'indice du compteur destiné à un triplet d'octets.*
+* *
+* Retour : Indice du bac de destination pour décompte. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static uint8_t define_tlsh_mapping(uint8_t salt, uint8_t b0, uint8_t b1, uint8_t b2)
+{
+ uint8_t result; /* Valeur à retourner */
+ const uint8_t *table; /* Permutations à utiliser */
+
+ table = (const uint8_t *)get_pearson_permutations();
+
+ result = table[salt ^ b0];
+ result = table[result ^ b1];
+ result = table[result ^ b2];
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : content = contenu binaire à consulter. *
+* info = informations à constituer en partie. [OUT] *
+* *
+* Description : Définit tous les compteurs associés aux triplets d'octets. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool fill_tlsh_buckets(const GBinContent *content, tlsh_info_t *info)
+{
+ bool result; /* Bilan à retourner */
+ phys_t len; /* Taille des données présentes*/
+ vmpa2t start; /* Première position de donnée */
+ const uint8_t *data; /* Données à parcourir */
+ phys_t i; /* Boucle de parcours */
+ uint8_t index; /* Indice de compteur visé */
+
+ result = false;
+
+ len = g_binary_content_compute_size(content);
+
+ if (len < 5)
+ goto exit;
+
+ g_binary_content_compute_start_pos(content, &start);
+ data = g_binary_content_get_raw_access(content, &start, len);
+
+ info->data_length = len;
+
+ memset(info->buckets, 0, sizeof(uint32_t) * BUCKETS_COUNT);
+ info->checksum = 0;
+
+ for (i = 0; i <= (len - 5); i++)
+ {
+ info->checksum = define_tlsh_mapping(1, data[i + 4], data[i + 3], info->checksum);
+
+ index = define_tlsh_mapping( 49, data[i + 4], data[i + 3], data[i + 2]);
+ info->buckets[index]++;
+
+ index = define_tlsh_mapping( 12, data[i + 4], data[i + 3], data[i + 1]);
+ info->buckets[index]++;
+
+ index = define_tlsh_mapping( 84, data[i + 4], data[i + 3], data[i + 0]);
+ info->buckets[index]++;
+
+ index = define_tlsh_mapping(178, data[i + 4], data[i + 2], data[i + 1]);
+ info->buckets[index]++;
+
+ index = define_tlsh_mapping(166, data[i + 4], data[i + 2], data[i + 0]);
+ info->buckets[index]++;
+
+ index = define_tlsh_mapping(230, data[i + 4], data[i + 1], data[i + 0]);
+ info->buckets[index]++;
+
+ }
+
+ result = true;
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : a = premier bacs de décompte à consulter. *
+* b = second bacs de décompte à consulter. *
+* *
+* Description : Compare deux compteurs de triplets d'octets. *
+* *
+* Retour : Bilan de comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int compare_tlsh_buckets(const uint32_t *a, const uint32_t *b)
+{
+ int result; /* Bilan à retourner */
+
+ if (*a < *b)
+ result = -1;
+
+ else if (*a > *b)
+ result = 1;
+
+ else
+ result = 0;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : info = informations à constituer en partie. [OUT] *
+* *
+* Description : Détermine les points de pivot au sein des bacs de compteurs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void find_tlsh_quartiles(tlsh_info_t *info)
+{
+ uint32_t copy[BUCKETS_USED]; /* Copie modifiable */
+
+ memcpy(copy, info->buckets, BUCKETS_USED * sizeof(uint32_t));
+
+ qsort(copy, BUCKETS_USED, sizeof(uint32_t), (__compar_fn_t)compare_tlsh_buckets);
+
+ /**
+ * q1 = quantité telle que 75% des buckets >= q1
+ * q2 = quantité telle que 50% des buckets >= q2
+ * q3 = quantité telle que 25% des buckets >= q3
+ */
+
+ info->q1 = copy[BUCKETS_USED / 4 - 1];
+
+ info->q2 = copy[BUCKETS_USED / 2 - 1];
+
+ info->q3 = copy[(3 * BUCKETS_USED) / 4 - 1];
+
+}
+
+
+
+
+
+#include <math.h>
+
+
+#define LOG_1_5 0.4054651
+#define LOG_1_3 0.26236426
+#define LOG_1_1 0.095310180
+
+
+unsigned char l_capturing(unsigned int len) {
+ int i;
+ if( len <= 656 ) {
+ i = (int) floor( logf((float) len) / LOG_1_5 );
+ } else if( len <= 3199 ) {
+ i = (int) floor( logf((float) len) / LOG_1_3 - 8.72777 );
+ } else {
+ i = (int) floor( logf((float) len) / LOG_1_1 - 62.5472 );
+ }
+
+ return (unsigned char) (i & 0xFF);
+}
+
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : info = informations à consulter. *
+* version = affichage de la version ? *
+* *
+* Description : Construit une empreinte TLSH sur les bases calculées. *
+* *
+* Retour : Empreinte construite ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *build_tlsh_hash(const tlsh_info_t *info, bool version)
+{
+ char *result; /* Empreinte à retourner */
+ char *pos; /* Tête de lecture */
+ char tmp[HASH_CODE_SIZE * 2]; /* Stockage temporaire */
+ char *code; /* Empreinte des compteurs */
+ size_t i; /* Boucle de parcours */
+ size_t offset; /* Rang d'intervention */
+
+ static char hex_lookup[] = "0123456789ABCDEF";
+
+ result = malloc(TLSH_STRING_LEN + 1);
+
+ /* Indication de version ? */
+
+ if (version)
+ {
+ result[0] = 'T';
+ result[1] = '1';
+ pos = result + 2;
+ }
+ else
+ pos = result;
+
+ /* Empreinte concise */
+
+ *(pos++) = hex_lookup[info->checksum & 0xf];
+ *(pos++) = hex_lookup[(info->checksum >> 4) & 0xf];
+
+ /* Taille représentée */
+
+ *(pos++) = hex_lookup[info->captured_length & 0xf];
+ *(pos++) = hex_lookup[(info->captured_length >> 4) & 0xf];
+
+ /* Ratios */
+
+ *(pos++) = hex_lookup[info->q1_ratio];
+
+ *(pos++) = hex_lookup[info->q2_ratio];
+
+ /* Empreinte du contenu binaire */
+
+ code = &tmp[HASH_CODE_SIZE - 1];
+
+ for (i = 0; i < BUCKETS_USED; i++)
+ {
+ if ((i % 4) == 0)
+ *code = 0;
+
+ offset = (i % 4) * 2;
+
+ if (info->buckets[i] <= info->q1)
+ ;
+
+ else if (info->buckets[i] <= info->q2)
+ (*code) |= (1 << offset);
+
+ else if (info->buckets[i] <= info->q3)
+ (*code) |= (2 << offset);
+
+ else
+ (*code) |= (3 << offset);
+
+ if (((i + 1) % 4) == 0)
+ code--;
+
+ }
+
+ encode_hex(tmp, HASH_CODE_SIZE, false, pos);
+
+ assert(pos + (HASH_CODE_SIZE * 2) < result + (TLSH_STRING_LEN + 1));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : content = contenu binaire à consulter. *
+* version = affichage de la version ? *
+* *
+* Description : Calcule l'empreinte TLSH d'un contenu binaire. *
+* *
+* Retour : Empreinte TLSH calculée ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *compute_content_tlsh_hash(const GBinContent *content, bool version)
+{
+ char *result; /* Empreinte à retourner */
+ bool status; /* Bilan d'un appel */
+ tlsh_info_t info; /* Informations brutes */
+
+ result = NULL;
+
+ status = fill_tlsh_buckets(content, &info);
+ if (!status) goto exit;
+
+ find_tlsh_quartiles(&info);
+
+ if (info.q3 == 0)
+ goto exit;
+
+ info.q1_ratio = ((float)(info.q1 * 100) / (float)info.q3);
+ info.q2_ratio = ((float)(info.q2 * 100) / (float)info.q3);
+
+ info.captured_length = l_capturing(info.data_length);
+
+ result = build_tlsh_hash(&info, version);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : h = chaîne de caratères à valider. *
+* *
+* Description : Indique si une chaîne représente à priori une empreinte TLSH.*
+* *
+* Retour : Bilan de l'analyse. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool is_valid_tlsh_hash(const char *h)
+{
+ bool result; /* Bilan à renvoyer */
+ size_t len; /* Taille de la chaîne */
+
+ len = strlen(h);
+
+ if (len == (TLSH_STRING_LEN - 2))
+ result = true;
+
+ else if (len == TLSH_STRING_LEN)
+ result = (h[0] == 'T' && h[1] == '1');
+
+ else
+ result = false;
+
+ // TODO check hex
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : h = chaîne de caratères à consulter. *
+* info = informations portées par une empreinte TLSH. *
+* *
+* Description : Reconstruit les informations portées par une empreinte TLSH. *
+* *
+* Retour : Bilan de la reconstruction. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool recover_tlsh_hash(const char *h, recovered_tlsh_info_t *info)
+{
+ bool result; /* Bilan à renvoyer */
+ const char *pos; /* Tête de lecture */
+ uint8_t value; /* Valeur récupérée */
+ size_t i; /* Boucle de parcours */
+
+ result = is_valid_tlsh_hash(h);
+ if (!result) goto exit;
+
+ /* Indication de version ? */
+
+ pos = (h[0] == 'T' ? h + 2 : h);
+
+ /* Empreinte concise */
+
+ result = decode_hex_digit(pos++, &value);
+ assert(result);
+ if (!result) goto exit;
+
+ info->checksum = value;
+
+ result = decode_hex_digit(pos++, &value);
+ assert(result);
+ if (!result) goto exit;
+
+ info->checksum |= (value << 4);
+
+ /* Taille représentée */
+
+ result = decode_hex_digit(pos++, &value);
+ assert(result);
+ if (!result) goto exit;
+
+ info->captured_length = value;
+
+ result = decode_hex_digit(pos++, &value);
+ assert(result);
+ if (!result) goto exit;
+
+ info->captured_length |= (value << 4);
+
+ /* Ratios */
+
+ result = decode_hex_digit(pos++, &value);
+ assert(result);
+ if (!result) goto exit;
+
+ info->q1_ratio = value;
+
+ result = decode_hex_digit(pos++, &value);
+ assert(result);
+ if (!result) goto exit;
+
+ info->q2_ratio = value;
+
+ /* Empreinte du contenu binaire */
+
+ for (i = 0; i < HASH_CODE_SIZE; i++)
+ {
+ result = decode_hex_digit(pos++, &value);
+ assert(result);
+ if (!result) goto exit;
+
+ info->code[HASH_CODE_SIZE - i - 1] = (value << 4);
+
+ result = decode_hex_digit(pos++, &value);
+ assert(result);
+ if (!result) goto exit;
+
+ info->code[HASH_CODE_SIZE - i - 1] |= value;
+
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : a = première valeur à analyser. *
+* b = seconde valeur à analyser. *
+* range = espace de valeurs à considérer. *
+* *
+* Description : Calcule une différence entre deux valeurs selon deux axes. *
+* *
+* Retour : Différence déterminée entre les deux valeurs. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int32_t diff_tlsh_values_two_way(uint32_t a, uint32_t b, uint32_t range)
+{
+ int32_t result; /* Différence à retourner */
+ int32_t diff_1; /* Première différence */
+ int32_t diff_2; /* Seconde différence */
+
+ if (a < b)
+ {
+ diff_1 = b - a;
+ diff_2 = range + a - b;
+ }
+ else
+ {
+ diff_1 = a - b;
+ diff_2 = range + b - a;
+ }
+
+ result = MIN(diff_1, diff_2);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : a = premier octet à analyser. *
+* b = second octet à analyser. *
+* *
+* Description : Calcule le degré de différence entre deux octets TLSH. *
+* *
+* Retour : Différence déterminée entre les deux octets. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static uint8_t diff_tlsh_bits(uint8_t a, uint8_t b)
+{
+ uint8_t result; /* Valeur à renvoyer */
+ uint8_t partial; /* Différence partielle */
+
+ result = 0;
+
+ partial = abs(a % 4 - b % 4);
+ result += (partial == 3 ? 6 : partial);
+
+ a /= 4; b /= 4;
+
+ partial = abs(a % 4 - b % 4);
+ result += (partial == 3 ? 6 : partial);
+
+ a /= 4; b /= 4;
+
+ partial = abs(a % 4 - b % 4);
+ result += (partial == 3 ? 6 : partial);
+
+ a /= 4; b /= 4;
+
+ partial = abs(a % 4 - b % 4);
+ result += (partial == 3 ? 6 : partial);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : ha = première chaîne de caratères à consulter. *
+* hb = première chaîne de caratères à consulter. *
+* length = l'indication de taille doit être considérée ? *
+* diff = degré de différence relevé. [OUT] *
+* *
+* Description : Détermine la similarité entre deux empreintes TLSH. *
+* *
+* Retour : Validité de l'opération menée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool compare_tlsh_hash(const char *ha, const char *hb, bool length, int32_t *diff)
+{
+ bool result; /* Validité à retourner */
+ recovered_tlsh_info_t info_a; /* Empreinte à manipuler #0 */
+ recovered_tlsh_info_t info_b; /* Empreinte à manipuler #1 */
+ int32_t partial; /* Différence calculée */
+ size_t i; /* Boucle de parcours */
+
+ result = recover_tlsh_hash(ha, &info_a);
+ if (!result) goto exit;
+
+ result = recover_tlsh_hash(hb, &info_b);
+ if (!result) goto exit;
+
+ *diff = 0;
+
+ /* Empreinte concise */
+
+ if (info_a.checksum != info_b.checksum)
+ *diff += 1;
+
+ /* Taille représentée */
+
+ if (length)
+ {
+ partial = diff_tlsh_values_two_way(info_a.captured_length, info_b.captured_length, 2 << 8);
+
+ if (partial > 1)
+ partial *= TLSH_LENGTH_MULTIPLIER;
+
+ *diff += partial;
+
+ }
+
+ /* Ratios */
+
+ partial = diff_tlsh_values_two_way(info_a.q1_ratio, info_b.q1_ratio, 2 << 4);
+
+ if (partial > 1)
+ partial *= TLSH_QRATIO_MULTIPLIER;
+
+ *diff += partial;
+
+ partial = diff_tlsh_values_two_way(info_a.q2_ratio, info_b.q2_ratio, 2 << 4);
+
+ if (partial > 1)
+ partial *= TLSH_QRATIO_MULTIPLIER;
+
+ *diff += partial;
+
+ /* Empreinte du contenu binaire */
+
+ for (i = 0; i < HASH_CODE_SIZE; i++)
+ *diff += diff_tlsh_bits(info_a.code[i], info_b.code[i]);
+
+ exit:
+
+ return result;
+
+}
diff --git a/plugins/bhash/tlsh.h b/plugins/bhash/tlsh.h
new file mode 100644
index 0000000..d8805ad
--- /dev/null
+++ b/plugins/bhash/tlsh.h
@@ -0,0 +1,46 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tlsh.h - prototypes pour les calculs d'empreintes selon l'algorithme TLSH
+ *
+ * Copyright (C) 2021 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 _PLUGINS_BHASH_TLSH_H
+#define _PLUGINS_BHASH_TLSH_H
+
+
+#include <stdbool.h>
+
+
+#include <analysis/content.h>
+
+
+
+/* Calcule l'empreinte TLSH d'un contenu binaire. */
+char *compute_content_tlsh_hash(const GBinContent *, bool);
+
+/* Indique si une chaîne représente à priori une empreinte TLSH. */
+bool is_valid_tlsh_hash(const char *);
+
+/* Détermine la similarité entre deux empreintes TLSH. */
+bool compare_tlsh_hash(const char *, const char *, bool, int32_t *);
+
+
+
+#endif /* _PLUGINS_BHASH_TLSH_H */
diff --git a/plugins/pe/python/routine.c b/plugins/pe/python/routine.c
index 89075ea..cebeb2a 100644
--- a/plugins/pe/python/routine.c
+++ b/plugins/pe/python/routine.c
@@ -62,6 +62,9 @@ static int py_pe_exported_routine_set_ordinal(PyObject *, PyObject *, void *);
" imported from other PE file symbol."
+/* Fournit la position du symbole dans les importations. */
+static PyObject *py_pe_imported_routine_get_index(PyObject *, void *);
+
/* Fournit le fichier DLL visé par une importation de format PE. */
static PyObject *py_pe_imported_routine_get_library(PyObject *, void *);
@@ -285,6 +288,44 @@ int convert_to_pe_exported_routine(PyObject *arg, void *dst)
* Paramètres : self = objet Python concerné par l'appel. *
* closure = non utilisé ici. *
* *
+* Description : Fournit la position du symbole dans les importations. *
+* *
+* Retour : Indice positif ou nul. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_pe_imported_routine_get_index(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GPeImportedRoutine *routine; /* Version native */
+ size_t index; /* Position dans les imports */
+
+#define PE_IMPORTED_ROUTINE_INDEX_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ index, py_pe_imported_routine, \
+ "Position of the symbol inside the importations table.\n" \
+ "\n" \
+ "The returned value is an integer." \
+)
+
+ routine = G_PE_IMPORTED_ROUTINE(pygobject_get(self));
+
+ index = g_pe_imported_routine_get_index(routine);
+
+ result = PyLong_FromSize_t(index);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
* Description : Fournit le fichier DLL visé par une importation de format PE.*
* *
* Retour : Désignation d'une bibliothèque Windows. *
@@ -299,7 +340,7 @@ static PyObject *py_pe_imported_routine_get_library(PyObject *self, void *closur
GPeImportedRoutine *routine; /* Version native */
const char *library; /* Nom de bibliothèque */
-#define PE_IMPORTED_ROUTINE_ORDINAL_ATTRIB PYTHON_GETSET_DEF_FULL \
+#define PE_IMPORTED_ROUTINE_LIBRARY_ATTRIB PYTHON_GETSET_DEF_FULL \
( \
library, py_pe_imported_routine, \
"Imported DLL's name for the symbol.\n" \
@@ -373,7 +414,8 @@ PyTypeObject *get_python_pe_imported_routine_type(void)
};
static PyGetSetDef py_pe_imported_routine_getseters[] = {
- PE_IMPORTED_ROUTINE_ORDINAL_ATTRIB,
+ PE_IMPORTED_ROUTINE_INDEX_ATTRIB,
+ PE_IMPORTED_ROUTINE_LIBRARY_ATTRIB,
{ NULL }
};
diff --git a/plugins/pe/routine.c b/plugins/pe/routine.c
index 3f2e5ba..5973487 100644
--- a/plugins/pe/routine.c
+++ b/plugins/pe/routine.c
@@ -72,6 +72,7 @@ struct _GPeImportedRoutine
GPeExportedRoutine parent; /* A laisser en premier */
char *library; /* Bibliothèque de rattachement*/
+ size_t index; /* Position dans les imports */
};
@@ -355,7 +356,8 @@ static void g_pe_imported_routine_finalize(GPeImportedRoutine *routine)
/******************************************************************************
* *
-* Paramètres : name = désignation humainement lisible. *
+* Paramètres : name = désignation humainement lisible. *
+* index = position du symbole dans les importations. *
* *
* Description : Crée une représentation de routine importée pour format PE. *
* *
@@ -365,7 +367,7 @@ static void g_pe_imported_routine_finalize(GPeImportedRoutine *routine)
* *
******************************************************************************/
-GPeImportedRoutine *g_pe_imported_routine_new(const char *name)
+GPeImportedRoutine *g_pe_imported_routine_new(const char *name, size_t index)
{
GPeImportedRoutine *result; /* Structure à retourner */
@@ -374,6 +376,31 @@ GPeImportedRoutine *g_pe_imported_routine_new(const char *name)
if (name != NULL)
g_binary_routine_set_name(G_BIN_ROUTINE(result), strdup(name));
+ result->index = index;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : routine = routine ayant pour origine un fichier PE. *
+* *
+* Description : Fournit la position du symbole dans les importations. *
+* *
+* Retour : Indice positif ou nul. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t g_pe_imported_routine_get_index(const GPeImportedRoutine *routine)
+{
+ size_t result; /* Indice à retourner */
+
+ result = routine->index;
+
return result;
}
diff --git a/plugins/pe/routine.h b/plugins/pe/routine.h
index 62faaaa..f0ec71e 100644
--- a/plugins/pe/routine.h
+++ b/plugins/pe/routine.h
@@ -98,7 +98,10 @@ typedef struct _GPeImportedRoutineClass GPeImportedRoutineClass;
GType g_pe_imported_routine_get_type(void);
/* Crée une représentation de routine importée pour format PE. */
-GPeImportedRoutine *g_pe_imported_routine_new(const char *);
+GPeImportedRoutine *g_pe_imported_routine_new(const char *, size_t);
+
+/* Fournit la position du symbole dans les importations. */
+size_t g_pe_imported_routine_get_index(const GPeImportedRoutine *);
/* Définit le fichier DLL visé par une importation de format PE. */
void g_pe_imported_routine_set_library(GPeImportedRoutine *, const char *);
diff --git a/plugins/pe/symbols.c b/plugins/pe/symbols.c
index 9217466..94f97a8 100644
--- a/plugins/pe/symbols.c
+++ b/plugins/pe/symbols.c
@@ -196,6 +196,7 @@ static bool load_pe_imported_symbols(GPeFormat *format, wgroup_id_t gid, GtkStat
GBinFormat *base; /* Version basique du format */
GExeFormat *exe; /* Autre vision du format */
const GBinContent *content; /* Contenu binaire à lire */
+ size_t counter; /* Compteur d'importations */
image_import_descriptor *iter; /* Boucle de parcours */
vmpa2t dll; /* Nom de la DLL concernée */
bool ret; /* Bilan d'un traitement */
@@ -223,6 +224,8 @@ static bool load_pe_imported_symbols(GPeFormat *format, wgroup_id_t gid, GtkStat
content = G_KNOWN_FORMAT(format)->content;
+ counter = 0;
+
for (iter = imports; iter->original_first_thunk != 0; iter++)
{
/* Bibliothèque impactée */
@@ -262,7 +265,7 @@ static bool load_pe_imported_symbols(GPeFormat *format, wgroup_id_t gid, GtkStat
if (val64 & 0x8000000000000000)
{
- routine = g_pe_imported_routine_new(NULL);
+ routine = g_pe_imported_routine_new(NULL, counter++);
g_pe_exported_routine_set_ordinal(G_PE_EXPORTED_ROUTINE(routine), val64 & 0xffff);
@@ -280,7 +283,7 @@ static bool load_pe_imported_symbols(GPeFormat *format, wgroup_id_t gid, GtkStat
hint += 2;
//routine = g_binary_format_decode_routine(base, hint);
- routine = g_pe_imported_routine_new((char *)hint);
+ routine = g_pe_imported_routine_new((char *)hint, counter++);
}
diff --git a/plugins/winordinals/assign.c b/plugins/winordinals/assign.c
index 16b7eaa..03e1165 100644
--- a/plugins/winordinals/assign.c
+++ b/plugins/winordinals/assign.c
@@ -235,7 +235,7 @@ static GOrdinalResolver *g_ordinal_resolver_new(GPeFormat *format, size_t begin,
static void g_ordinal_resolver_process(GOrdinalResolver *resolver, GtkStatusStack *status)
{
GBinFormat *base; /* Format basique du binaire */
- size_t i; /* Boucle de parcours #1 */
+ size_t i; /* Boucle de parcours */
GBinSymbol *symbol; /* Commodité d'accès */
uint16_t ordinal; /* Ordinal défini */
const char *name; /* Désignation actuelle */