/* Chrysalide - Outil d'analyse de fichiers binaires
* executable.c - support des formats d'exécutables
*
* Copyright (C) 2009-2019 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 "executable.h"
#include
#include
#include
//#include
#include
#include "executable-int.h"
#include "../core/logs.h"
/*
#include "../plugins/pglist.h"
*/
/* Initialise la classe des formats d'exécutables génériques. */
static void g_executable_format_class_init(GExecutableFormatClass *);
/* Initialise une instance de format d'exécutable générique. */
static void g_executable_format_init(GExecutableFormat *);
/* Supprime toutes les références externes. */
static void g_executable_format_dispose(GExecutableFormat *);
/* Procède à la libération totale de la mémoire. */
static void g_executable_format_finalize(GExecutableFormat *);
/* Indique le type défini pour un format d'exécutable générique. */
G_DEFINE_TYPE(GExecutableFormat, g_executable_format, G_TYPE_PROGRAM_FORMAT);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des formats d'exécutables génériques. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_executable_format_class_init(GExecutableFormatClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_executable_format_dispose;
object->finalize = (GObjectFinalizeFunc)g_executable_format_finalize;
}
/******************************************************************************
* *
* Paramètres : format = instance à initialiser. *
* *
* Description : Initialise une instance de format d'exécutable générique. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_executable_format_init(GExecutableFormat *format)
{
format->portions = NULL;
}
/******************************************************************************
* *
* Paramètres : format = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_executable_format_dispose(GExecutableFormat *format)
{
g_clear_object(&format->portions);
G_OBJECT_CLASS(g_executable_format_parent_class)->dispose(G_OBJECT(format));
}
/******************************************************************************
* *
* Paramètres : format = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_executable_format_finalize(GExecutableFormat *format)
{
G_OBJECT_CLASS(g_executable_format_parent_class)->finalize(G_OBJECT(format));
}
/******************************************************************************
* *
* Paramètres : format = description du format à initialiser pleinement. *
* content = contenu binaire à parcourir. *
* *
* Description : Met en place un nouveau contenu binaire à analyser. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_executable_format_create(GExecutableFormat *format, GBinContent *content)
{
bool result; /* Bilan à retourner */
vmpa2t addr; /* Emplacement vide de sens */
phys_t length; /* Taille de portion globale */
GExecutableFormatClass *class; /* Classe de l'instance */
result = g_program_format_create(G_PROGRAM_FORMAT(format), content);
if (!result) goto exit;
/* Définition de portions */
/**
* Avant de lire l'entête du format, on ne sait pas où on se trouve !
*/
init_vmpa(&addr, 0, VMPA_NO_VIRTUAL);
length = g_binary_content_compute_size(G_KNOWN_FORMAT(format)->content);
format->portions = g_binary_portion_new(&addr, length);
class = G_EXECUTABLE_FORMAT_GET_CLASS(format);
if (class->refine_portions != NULL)
result = class->refine_portions(format);
exit:
return result;
}
/******************************************************************************
* *
* Paramètres : format = description du format exécutable à consulter. *
* *
* Description : Indique le type d'architecture visée par le format. *
* *
* Retour : Identifiant de l'architecture ciblée par le format. *
* *
* Remarques : - *
* *
******************************************************************************/
char *g_executable_format_get_target_machine(const GExecutableFormat *format)
{
char *result; /* Désignation à retourner */
GExecutableFormatClass *class; /* Classe de l'instance */
class = G_EXECUTABLE_FORMAT_GET_CLASS(format);
result = class->get_machine(format);
//assert(result != NULL);
return result;
}
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à consulter. *
* addr = adresse principale trouvée si possible. [OUT] *
* *
* Description : Fournit l'adresse principale associée à un format. *
* *
* Retour : Validité de l'adresse transmise. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_executable_format_get_main_address(GExecutableFormat *format, vmpa2t *addr)
{
bool result; /* Bilan à retourner */
GExecutableFormatClass *class; /* Classe de l'instance */
class = G_EXECUTABLE_FORMAT_GET_CLASS(format);
result = class->get_main_addr(format, addr);
return result;
}
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à modifier. *
* portion = portion à inclure dans les définitions du format. *
* origin = source de définition de la portion fournie. *
* *
* Description : Procède à l'enregistrement d'une portion dans un format. *
* *
* Retour : Bilan de l'opération : true si inclusion, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_executable_format_include_portion(GExecutableFormat *format, GBinaryPortion *portion, const vmpa2t *origin)
{
bool result; /* Bilan à retourner */
phys_t available; /* Taille totale du bianire */
const mrange_t *range; /* Emplacement de la portion */
phys_t start; /* Début de zone de la portion */
vmpa2t no_origin; /* Emplacement inconnu */
char *msg; /* Description d'une erreur */
phys_t remaining; /* Taille maximale envisageable*/
bool truncated; /* Modification faite ? */
result = false;
available = g_binary_content_compute_size(G_KNOWN_FORMAT(format)->content);
range = g_binary_portion_get_range(portion);
start = get_phy_addr(get_mrange_addr(range));
if (get_mrange_length(range) == 0)
log_variadic_message(LMT_BAD_BINARY, _("The binary portion '%s' is empty and thus useless... Discarding!"),
g_binary_portion_get_desc(portion));
else if (start >= available)
{
if (origin == NULL)
{
init_vmpa(&no_origin, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL);
origin = &no_origin;
}
asprintf(&msg, _("Defined binary portion '%s' is out of the file scope... Discarding!"),
g_binary_portion_get_desc(portion));
//g_binary_format_add_error(G_BIN_FORMAT(format), BFE_STRUCTURE, origin, msg);
free(msg);
}
else
{
remaining = available - start;
truncated = g_binary_portion_limit_range(portion, remaining);
if (truncated)
log_variadic_message(LMT_BAD_BINARY, _("Truncated binary portion '%s' to fit the binary content size!"),
g_binary_portion_get_desc(portion));
result = g_binary_portion_include(format->portions, portion);
}
return result;
}
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à consulter. *
* *
* Description : Fournit la première couche des portions composent le binaire.*
* *
* Retour : Arborescence des différentes portions binaires. *
* *
* Remarques : Le compteur de références de l'instance renvoyée doit être *
* décrémenté après usage. *
* *
******************************************************************************/
GBinaryPortion *g_executable_format_get_portions(GExecutableFormat *format)
{
GBinaryPortion *result; /* Instance à retourner */
result = format->portions;
assert(result != NULL);
ref_object(result);
return result;
}
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à consulter. *
* off = position physique à retrouver. *
* pos = position correspondante. [OUT] *
* *
* Description : Fournit l'emplacement correspondant à une position physique. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_executable_format_translate_offset_into_vmpa(GExecutableFormat *format, phys_t off, vmpa2t *pos)
{
bool result; /* Bilan à retourner */
GExecutableFormatClass *class; /* Classe de l'instance */
class = G_EXECUTABLE_FORMAT_GET_CLASS(format);
result = class->translate_phys(format, off, pos);
return result;
}
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à consulter. *
* off = position physique à retrouver. *
* pos = position correspondante. [OUT] *
* *
* Description : Fournit l'emplacement correspondant à une position physique. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_executable_format_translate_offset_into_vmpa_without_virt(const GExecutableFormat *format, phys_t off, vmpa2t *pos)
{
init_vmpa(pos, off, VMPA_NO_VIRTUAL);
return true;
}
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à consulter. *
* off = position physique à retrouver. *
* pos = position correspondante. [OUT] *
* *
* Description : Fournit l'emplacement correspondant à une position physique. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_executable_format_translate_offset_into_vmpa_with_portions(GExecutableFormat *format, phys_t off, vmpa2t *pos)
{
bool result; /* Bilan à retourner */
if (format->portions == NULL)
result = false;
else
result = g_binary_portion_translate_offset_into_vmpa(format->portions, off, pos);
return result;
}
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à consulter. *
* addr = adresse virtuelle à retrouver. *
* pos = position correspondante. [OUT] *
* *
* Description : Fournit l'emplacement correspondant à une adresse virtuelle. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_executable_format_translate_address_into_vmpa(GExecutableFormat *format, virt_t addr, vmpa2t *pos)
{
bool result; /* Bilan à retourner */
GExecutableFormatClass *class; /* Classe de l'instance */
class = G_EXECUTABLE_FORMAT_GET_CLASS(format);
result = class->translate_virt(format, addr, pos);
return result;
}
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à consulter. *
* addr = adresse virtuelle à retrouver. *
* pos = position correspondante. [OUT] *
* *
* Description : Fournit l'emplacement correspondant à une adresse virtuelle. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_executable_format_translate_address_into_vmpa_without_virt(const GExecutableFormat *format, virt_t addr, vmpa2t *pos)
{
/**
* S'il n'y a pas de notion de mémoire virtuelle, positions physiques et
* adresses virtuelles se confondent.
*
* On reste néanmoins cohérent, et on n'utilise donc pas d'adresse virtuelle.
*
* Les sauts dans le code renvoient de façon transparente vers des positions
* physiques.
*/
init_vmpa(pos, addr, VMPA_NO_VIRTUAL);
return true;
}
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à consulter. *
* addr = adresse virtuelle à retrouver. *
* pos = position correspondante. [OUT] *
* *
* Description : Fournit l'emplacement correspondant à une adresse virtuelle. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_executable_format_translate_address_into_vmpa_with_portions(GExecutableFormat *format, virt_t addr, vmpa2t *pos)
{
bool result; /* Bilan à retourner */
if (format->portions == NULL)
result = false;
else
result = g_binary_portion_translate_address_into_vmpa(format->portions, addr, pos);
return result;
}