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