/* 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;
}