From c12d6a5d11bf9a2436ff78e393173ca59b6c9c46 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Wed, 7 Apr 2021 00:55:54 +0200 Subject: Provide several kinds of hashes for binary files. --- configure.ac | 2 + plugins/Makefile.am | 1 + plugins/bhash/Makefile.am | 52 +++ plugins/bhash/core.c | 74 ++++ plugins/bhash/core.h | 38 ++ plugins/bhash/imphash.c | 244 +++++++++++++ plugins/bhash/imphash.h | 40 +++ plugins/bhash/python/Makefile.am | 21 ++ plugins/bhash/python/imphash.c | 135 ++++++++ plugins/bhash/python/imphash.h | 39 +++ plugins/bhash/python/module.c | 90 +++++ plugins/bhash/python/module.h | 38 ++ plugins/bhash/python/rich.c | 194 +++++++++++ plugins/bhash/python/rich.h | 39 +++ plugins/bhash/python/tlsh.c | 256 ++++++++++++++ plugins/bhash/python/tlsh.h | 39 +++ plugins/bhash/rich.c | 181 ++++++++++ plugins/bhash/rich.h | 44 +++ plugins/bhash/tlsh.c | 724 +++++++++++++++++++++++++++++++++++++++ plugins/bhash/tlsh.h | 46 +++ plugins/pe/python/routine.c | 46 ++- plugins/pe/routine.c | 31 +- plugins/pe/routine.h | 5 +- plugins/pe/symbols.c | 7 +- plugins/winordinals/assign.c | 2 +- 25 files changed, 2380 insertions(+), 8 deletions(-) create mode 100644 plugins/bhash/Makefile.am create mode 100644 plugins/bhash/core.c create mode 100644 plugins/bhash/core.h create mode 100644 plugins/bhash/imphash.c create mode 100644 plugins/bhash/imphash.h create mode 100644 plugins/bhash/python/Makefile.am create mode 100644 plugins/bhash/python/imphash.c create mode 100644 plugins/bhash/python/imphash.h create mode 100644 plugins/bhash/python/module.c create mode 100644 plugins/bhash/python/module.h create mode 100644 plugins/bhash/python/rich.c create mode 100644 plugins/bhash/python/rich.h create mode 100644 plugins/bhash/python/tlsh.c create mode 100644 plugins/bhash/python/tlsh.h create mode 100644 plugins/bhash/rich.c create mode 100644 plugins/bhash/rich.h create mode 100644 plugins/bhash/tlsh.c create mode 100644 plugins/bhash/tlsh.h 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 . + */ + + +#include "core.h" + + +#include +#include + + +#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 . + */ + + +#ifndef _PLUGINS_BHASH_CORE_H +#define _PLUGINS_BHASH_CORE_H + + +#include +#include + + + +/* 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 . + */ + + +#include "imphash.h" + + +#include +#include +#include + + +#include +#include +#include +#include + + + +/* 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 . + */ + + +#ifndef _PLUGINS_BHASH_IMPHASH_H +#define _PLUGINS_BHASH_IMPHASH_H + + +#include + + +#include + + + +/* 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 + + +#include +#include +#include + + +#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 +#include + + + +/* 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 +#include + + +#include +#include + + +#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 + + + +/* 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 + + +#include +#include +#include + + +#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 +#include + + + +/* 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 + + +#include +#include +#include + + +#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 +#include + + + +/* 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 . + */ + + +#include "rich.h" + + +#include +#include + + + +/****************************************************************************** +* * +* 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 . + */ + + +#ifndef _PLUGINS_BHASH_RICH_H +#define _PLUGINS_BHASH_RICH_H + + +#include +#include + + +#include + + + +/* 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 . + */ + + +#include "tlsh.h" + + +#include +#include +#include +#include + + +#include +#include + + +#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 + + +#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 . + */ + + +#ifndef _PLUGINS_BHASH_TLSH_H +#define _PLUGINS_BHASH_TLSH_H + + +#include + + +#include + + + +/* 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 */ -- cgit v0.11.2-87-g4458