/* Chrysalide - Outil d'analyse de fichiers binaires * file.c - chargement de données binaires à partir d'un fichier * * Copyright (C) 2015 Cyrille Bagard * * This file is part of Chrysalide. * * OpenIDA 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. * * OpenIDA 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 "file.h" #include #include #include #include #include #include #include "../content-int.h" /* Contenu de données binaires issues d'un fichier (instance) */ struct _GFileContent { GObject parent; /* A laisser en premier */ bin_t *data; /* Contenu binaire représenté */ mrange_t range; /* Couverture du binaire */ GChecksum *checksum; /* Calcul de l'empreinte */ bool cs_computed; /* Calcul effectué ? */ }; /* Contenu de données binaires issues d'un fichier (classe) */ struct _GFileContentClass { GObjectClass parent; /* A laisser en premier */ }; /* Initialise la classe des contenus de données binaires. */ static void g_file_content_class_init(GFileContentClass *); /* Initialise une instance de contenu de données binaires. */ static void g_file_content_init(GFileContent *); /* Procède à l'initialisation de l'interface de lecture. */ static void g_file_content_interface_init(GBinContentInterface *); /* Supprime toutes les références externes. */ static void g_file_content_dispose(GFileContent *); /* Procède à la libération totale de la mémoire. */ static void g_file_content_finalize(GFileContent *); /* Fournit une empreinte unique (SHA256) pour les données. */ static const gchar *g_file_content_get_checksum(GFileContent *); /* Détermine le nombre d'octets lisibles. */ static phys_t g_file_content_compute_size(const GFileContent *); /* Donne accès à une portion des données représentées. */ static const bin_t *g_file_content_get_raw_access(const GFileContent *, vmpa2t *, phys_t); /* Fournit une portion des données représentées. */ static bool g_file_content_read_raw(const GFileContent *, vmpa2t *, phys_t, bin_t *); /* Lit un nombre non signé sur quatre bits. */ static bool g_file_content_read_u4(const GFileContent *, vmpa2t *, bool *, uint8_t *); /* Lit un nombre non signé sur un octet. */ static bool g_file_content_read_u8(const GFileContent *, vmpa2t *, uint8_t *); /* Lit un nombre non signé sur deux octets. */ static bool g_file_content_read_u16(const GFileContent *, vmpa2t *, SourceEndian, uint16_t *); /* Lit un nombre non signé sur quatre octets. */ static bool g_file_content_read_u32(const GFileContent *, vmpa2t *, SourceEndian, uint32_t *); /* Lit un nombre non signé sur huit octets. */ static bool g_file_content_read_u64(const GFileContent *, vmpa2t *, SourceEndian, uint64_t *); /* Indique le type défini par la GLib pour les contenus de données. */ G_DEFINE_TYPE_WITH_CODE(GFileContent, g_file_content, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(G_TYPE_BIN_CONTENT, g_file_content_interface_init)) /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des contenus de données binaires. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_file_content_class_init(GFileContentClass *klass) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_file_content_dispose; object->finalize = (GObjectFinalizeFunc)g_file_content_finalize; } /****************************************************************************** * * * Paramètres : content = instance à initialiser. * * * * Description : Initialise une instance de contenu de données binaires. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_file_content_init(GFileContent *content) { content->checksum = g_checksum_new(G_CHECKSUM_SHA256); assert(content->checksum != NULL); content->cs_computed = false; } /****************************************************************************** * * * Paramètres : iface = interface GLib à initialiser. * * * * Description : Procède à l'initialisation de l'interface de lecture. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_file_content_interface_init(GBinContentInterface *iface) { iface->get_checksum = (get_checksum_fc)g_file_content_get_checksum; iface->compute_size = (compute_size_fc)g_file_content_compute_size; iface->get_raw_access = (get_raw_access_fc)g_file_content_get_raw_access; iface->read_raw = (read_raw_fc)g_file_content_read_raw; iface->read_u4 = (read_u4_fc)g_file_content_read_u4; iface->read_u8 = (read_u8_fc)g_file_content_read_u8; iface->read_u16 = (read_u16_fc)g_file_content_read_u16; iface->read_u32 = (read_u32_fc)g_file_content_read_u32; iface->read_u64 = (read_u64_fc)g_file_content_read_u64; } /****************************************************************************** * * * Paramètres : content = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_file_content_dispose(GFileContent *content) { g_checksum_free(content->checksum); G_OBJECT_CLASS(g_file_content_parent_class)->dispose(G_OBJECT(content)); } /****************************************************************************** * * * Paramètres : content = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_file_content_finalize(GFileContent *content) { if (content->data != NULL) free(content->data); G_OBJECT_CLASS(g_file_content_parent_class)->finalize(G_OBJECT(content)); } /****************************************************************************** * * * Paramètres : filename = chemin d'accès au fichier à charger. * * * * Description : Charge en mémoire le contenu d'un fichier donné. * * * * Retour : Représentation de contenu à manipuler ou NULL en cas d'échec.* * * * Remarques : - * * * ******************************************************************************/ GBinContent *g_file_content_new(const char *filename) { GFileContent *result; /* Structure à retourner */ int fd; /* Descripteur du fichier */ struct stat info; /* Informations sur le fichier */ int ret; /* Bilan d'un appel */ void *content; /* Contenu brut du fichier */ vmpa2t base; /* Localisation des données */ /* Récupération des données */ fd = open(filename, O_RDONLY); if (fd == -1) { perror("open"); goto gbcnff_error; } ret = fstat(fd, &info); if (ret == -1) { close(fd); perror("fstat"); goto gbcnff_error; } content = mmap(NULL, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (content == MAP_FAILED) { close(fd); perror("mmap"); goto gbcnff_error; } /* Constitution du contenu officiel */ result = g_object_new(G_TYPE_FILE_CONTENT, NULL); result->data = (bin_t *)malloc(info.st_size); memcpy(result->data, content, info.st_size); munmap(content, info.st_size); close(fd); init_vmpa(&base, 0, VMPA_NO_VIRTUAL); init_mrange(&result->range, &base, info.st_size); return G_BIN_CONTENT(result); gbcnff_error: return NULL; } /****************************************************************************** * * * Paramètres : content = contenu binaire à venir lire. * * * * Description : Fournit une empreinte unique (SHA256) pour les données. * * * * Retour : Chaîne représentant l'empreinte du contenu binaire. * * * * Remarques : - * * * ******************************************************************************/ static const gchar *g_file_content_get_checksum(GFileContent *content) { if (!content->cs_computed) { g_checksum_reset(content->checksum); g_checksum_update(content->checksum, content->data, get_mrange_length(&content->range)); content->cs_computed = true; } return g_checksum_get_string(content->checksum); } /****************************************************************************** * * * Paramètres : content = contenu binaire à venir lire. * * * * Description : Détermine le nombre d'octets lisibles. * * * * Retour : Quantité représentée. * * * * Remarques : - * * * ******************************************************************************/ static phys_t g_file_content_compute_size(const GFileContent *content) { phys_t result; /* Quantité trouvée à retourner*/ result = get_mrange_length(&content->range); return result; } /****************************************************************************** * * * Paramètres : content = contenu binaire à venir lire. * * addr = position de la tête de lecture. * * length = quantité d'octets à lire. * * * * Description : Donne accès à une portion des données représentées. * * * * Retour : Pointeur vers les données à lire ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static const bin_t *g_file_content_get_raw_access(const GFileContent *content, vmpa2t *addr, phys_t length) { phys_t offset; /* Emplacement de départ */ offset = get_phy_addr(addr); if (offset == VMPA_NO_PHYSICAL) return NULL; if ((offset + length) >= get_mrange_length(&content->range)) return NULL; advance_vmpa(addr, length); return &content->data[offset]; } /****************************************************************************** * * * Paramètres : content = contenu binaire à venir lire. * * addr = position de la tête de lecture. * * length = quantité d'octets à lire. * * out = réceptacle disponible pour ces données. [OUT] * * * * Description : Fournit une portion des données représentées. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool g_file_content_read_raw(const GFileContent *content, vmpa2t *addr, phys_t length, bin_t *out) { bool result; /* Bilan à remonter */ const bin_t *data; /* Pointeur vers données utiles*/ data = g_file_content_get_raw_access(content, addr, length); if (data != NULL) { result = true; memcpy(out, data, length); } else result = false; return result; } /****************************************************************************** * * * Paramètres : content = contenu binaire à venir lire. * * addr = position de la tête de lecture. * * low = position éventuelle des 4 bits visés. [OUT] * * val = lieu d'enregistrement de la lecture. [OUT] * * * * Description : Lit un nombre non signé sur quatre bits. * * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool g_file_content_read_u4(const GFileContent *content, vmpa2t *addr, bool *low, uint8_t *val) { bool result; /* Bilan de lecture à renvoyer */ phys_t pos; /* Tête de lecture courante */ phys_t length; /* Taille de la surface dispo. */ pos = get_phy_addr(addr); if (pos == VMPA_NO_PHYSICAL) return false; length = get_mrange_length(&content->range); result = read_u4(val, content->data, &pos, length, low); if (result) advance_vmpa(addr, pos - get_phy_addr(addr)); return result; } /****************************************************************************** * * * Paramètres : content = contenu binaire à venir lire. * * addr = position de la tête de lecture. * * val = lieu d'enregistrement de la lecture. [OUT] * * * * Description : Lit un nombre non signé sur un octet. * * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool g_file_content_read_u8(const GFileContent *content, vmpa2t *addr, uint8_t *val) { bool result; /* Bilan de lecture à renvoyer */ phys_t pos; /* Tête de lecture courante */ phys_t length; /* Taille de la surface dispo. */ pos = get_phy_addr(addr); if (pos == VMPA_NO_PHYSICAL) return false; length = get_mrange_length(&content->range); result = read_u8(val, content->data, &pos, length); if (result) advance_vmpa(addr, pos - get_phy_addr(addr)); return result; } /****************************************************************************** * * * Paramètres : content = contenu binaire à venir lire. * * addr = position de la tête de lecture. * * endian = ordre des bits dans la source. * * val = lieu d'enregistrement de la lecture. [OUT] * * * * Description : Lit un nombre non signé sur deux octets. * * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool g_file_content_read_u16(const GFileContent *content, vmpa2t *addr, SourceEndian endian, uint16_t *val) { bool result; /* Bilan de lecture à renvoyer */ phys_t pos; /* Tête de lecture courante */ phys_t length; /* Taille de la surface dispo. */ pos = get_phy_addr(addr); if (pos == VMPA_NO_PHYSICAL) return false; length = get_mrange_length(&content->range); result = read_u16(val, content->data, &pos, length, endian); if (result) advance_vmpa(addr, pos - get_phy_addr(addr)); return result; } /****************************************************************************** * * * Paramètres : content = contenu binaire à venir lire. * * addr = position de la tête de lecture. * * endian = ordre des bits dans la source. * * val = lieu d'enregistrement de la lecture. [OUT] * * * * Description : Lit un nombre non signé sur quatre octets. * * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool g_file_content_read_u32(const GFileContent *content, vmpa2t *addr, SourceEndian endian, uint32_t *val) { bool result; /* Bilan de lecture à renvoyer */ phys_t pos; /* Tête de lecture courante */ phys_t length; /* Taille de la surface dispo. */ pos = get_phy_addr(addr); if (pos == VMPA_NO_PHYSICAL) return false; length = get_mrange_length(&content->range); result = read_u32(val, content->data, &pos, length, endian); if (result) advance_vmpa(addr, pos - get_phy_addr(addr)); return result; } /****************************************************************************** * * * Paramètres : content = contenu binaire à venir lire. * * addr = position de la tête de lecture. * * endian = ordre des bits dans la source. * * val = lieu d'enregistrement de la lecture. [OUT] * * * * Description : Lit un nombre non signé sur huit octets. * * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool g_file_content_read_u64(const GFileContent *content, vmpa2t *addr, SourceEndian endian, uint64_t *val) { bool result; /* Bilan de lecture à renvoyer */ phys_t pos; /* Tête de lecture courante */ phys_t length; /* Taille de la surface dispo. */ pos = get_phy_addr(addr); if (pos == VMPA_NO_PHYSICAL) return false; length = get_mrange_length(&content->range); result = read_u64(val, content->data, &pos, length, endian); if (result) advance_vmpa(addr, pos - get_phy_addr(addr)); return result; }