/* Chrysalide - Outil d'analyse de fichiers binaires
* formats.c - enregistrement et fourniture des formats de binaires supportés
*
* Copyright (C) 2015 Cyrille Bagard
*
* This file is part of Chrysalide.
*
* Chrysalide is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Chrysalide is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Foobar. If not, see .
*/
#include "formats.h"
#include
#include
#include
#include "../format/dex/dex.h"
#include "../format/dwarf/dwarf.h"
#include "../format/dwarf/v2/dwarf.h"
#include "../format/dwarf/v3/dwarf.h"
#include "../format/dwarf/v4/dwarf.h"
#include "../format/elf/elf.h"
/* Eléments pour détection */
typedef struct _format_matcher_t
{
format_match_fc func; /* Recherche de correspondance */
void *data; /* Eventuelle donnée à y lier */
} format_matcher_t;
/* Caractéristiques d'un processeur */
typedef struct _format_loader_t
{
char *key; /* Clef pour un accès rapide */
char *name; /* Désignation humaine */
format_load_fc func; /* Procédure de chargement */
} format_loader_t;
/* Mémorisation des détections de format enregistrées */
static format_matcher_t *_formats_matchers = NULL;
static size_t _formats_matchers_count = 0;
/* Mémorisation des types de formats enregistrés */
static format_loader_t *_formats_loaders = NULL;
static size_t _formats_loaders_count = 0;
/* Verrou pour des accès atomiques */
static GRWLock _formats_lock;
/* Retrouve l'enregistrement correspondant à une architecture. */
static format_loader_t *find_format_by_key(const char *);
/******************************************************************************
* *
* Paramètres : func = procédure de détection à utiliser. *
* data = éventuelle donnée à associer aux opérations. *
* *
* Description : Enregistre un détection de format(s) binaire(s). *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool register_format_matcher(format_match_fc func, void *data)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
const format_matcher_t *cur; /* Elément parcouru et analysé */
format_matcher_t *new; /* Nouvel élément à définir */
g_rw_lock_writer_lock(&_formats_lock);
for (i = 0; i < _formats_matchers_count; i++)
{
cur = &_formats_matchers[i];
if (cur->func == func && cur->data == data)
break;
}
result = (i == _formats_matchers_count);
if (result)
{
_formats_matchers = (format_matcher_t *)realloc(_formats_matchers,
++_formats_matchers_count * sizeof(format_matcher_t));
new = &_formats_matchers[_formats_matchers_count - 1];
new->func = func;
new->data = data;
}
g_rw_lock_writer_unlock(&_formats_lock);
return result;
}
/******************************************************************************
* *
* Paramètres : key = désignation rapide et interne d'un format. *
* name = désignation humaine au format de binaire. *
* func = procédure de chargement associée. *
* *
* Description : Enregistre un format de contenu binaire donné. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool register_format_loader(const char *key, const char *name, format_load_fc func)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
format_loader_t *new; /* Nouvel élément à définir */
g_rw_lock_writer_lock(&_formats_lock);
for (i = 0; i < _formats_loaders_count; i++)
if (strcmp(_formats_loaders[i].key, key) == 0 && strcmp(_formats_loaders[i].name, name) == 0)
break;
result = (i == _formats_loaders_count);
if (result)
{
_formats_loaders = (format_loader_t *)realloc(_formats_loaders,
++_formats_loaders_count * sizeof(format_loader_t));
new = &_formats_loaders[_formats_loaders_count - 1];
new->key = strdup(key);
new->name = strdup(name);
new->func = func;
}
g_rw_lock_writer_unlock(&_formats_lock);
return result;
}
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Charge les définitions de formats "natifs". *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool load_hard_coded_formats_definitions(void)
{
bool result; /* Bilan à retourner */
result = true;
/* Détections */
result &= register_format_matcher(dex_is_matching, NULL);
result &= register_format_matcher(dwarf_is_matching, NULL);
result &= register_format_matcher(elf_is_matching, NULL);
/* Chargements */
result &= register_format_loader("dex", "Dalvik Executable format", g_dex_format_new);
result &= register_format_loader("dwarf_v2", "Debugging With Arbitrary Record Formats (v2)",
g_dwarfv2_format_new);
result &= register_format_loader("dwarf_v3", "Debugging With Arbitrary Record Formats (v3)",
g_dwarfv3_format_new);
result &= register_format_loader("dwarf_v4", "Debugging With Arbitrary Record Formats (v4)",
g_dwarfv4_format_new);
result &= register_format_loader("elf", "Executable and Linkable Format", g_elf_format_new);
return result;
}
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Décharge toutes les définitions de formats. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void unload_formats_definitions(void)
{
size_t i; /* Boucle de parcours */
if (_formats_matchers != NULL)
free(_formats_matchers);
_formats_matchers = NULL;
_formats_matchers_count = 0;
for (i = 0; i < _formats_loaders_count; i++)
{
free(_formats_loaders[i].key);
free(_formats_loaders[i].name);
}
if (_formats_loaders != NULL)
free(_formats_loaders);
_formats_loaders = NULL;
_formats_loaders_count = 0;
}
/******************************************************************************
* *
* Paramètres : key = nom technique du processeur recherché. *
* *
* Description : Retrouve l'enregistrement correspondant à une architecture. *
* *
* Retour : Définition trouvée ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
static format_loader_t *find_format_by_key(const char *key)
{
format_loader_t *result; /* Trouvaille à retourner */
size_t i; /* Boucle de parcours */
/**
* Le verrou d'accès global doit être posé !
*/
result = NULL;
if (key != NULL)
for (i = 0; i < _formats_loaders_count; i++)
if (strcmp(_formats_loaders[i].key, key) == 0)
result = &_formats_loaders[i];
return result;
}
/******************************************************************************
* *
* Paramètres : key = nom technique du format recherché. *
* *
* Description : Fournit le nom humain du format binaire visé. *
* *
* Retour : Désignation humaine trouvée ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
const char *get_binary_format_name(const char *key)
{
const char *result; /* Description à retourner */
format_loader_t *def; /* Définition d'architecture */
g_rw_lock_reader_lock(&_formats_lock);
def = find_format_by_key(key);
if (def == NULL)
result = NULL;
else
result = def->name;
g_rw_lock_reader_unlock(&_formats_lock);
return result;
}
/******************************************************************************
* *
* Paramètres : content = contenu binaire à parcourir. *
* parent = éventuel format exécutable déjà chargé. *
* key = identifiant de format trouvé ou NULL. [OUT] *
* *
* Description : Identifie un format binaire par son contenu. *
* *
* Retour : Conclusion de haut niveau sur la reconnaissance effectuée. *
* *
* Remarques : - *
* *
******************************************************************************/
FormatMatchStatus find_matching_format(GBinContent *content, GExeFormat *parent, char **key)
{
FormatMatchStatus result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
const format_matcher_t *cur; /* Elément parcouru et analysé */
result = FMS_UNKNOWN;
g_rw_lock_reader_lock(&_formats_lock);
for (i = 0; i < _formats_matchers_count && result == FMS_UNKNOWN; i++)
{
cur = &_formats_matchers[i];
result = cur->func(content, parent, cur->data, key);
}
g_rw_lock_reader_unlock(&_formats_lock);
return result;
}
/******************************************************************************
* *
* Paramètres : key = nom technique du processeur recherché. *
* content = contenu binaire pré-chargé à traiter. *
* parent = contenu binaire principal éventuel déjà chargé. *
* *
* Description : Charge le format binaire correspondant à un type. *
* *
* Retour : Format binaire instancié. *
* *
* Remarques : - *
* *
******************************************************************************/
GBinFormat *load_new_named_format(const char *key, GBinContent *content, GExeFormat *parent)
{
GBinFormat *result; /* Instance à retourner */
format_loader_t *def; /* Définition d'architecture */
g_rw_lock_reader_lock(&_formats_lock);
def = find_format_by_key(key);
if (def == NULL)
result = NULL;
else
{
extern GtkStatusStack *get_global_status(void);
result = def->func(content, parent, get_global_status());
}
g_rw_lock_reader_unlock(&_formats_lock);
return result;
}