/* Chrysalide - Outil d'analyse de fichiers binaires * rich.c - lecture des informations enrichies d'un format PE * * 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 "rich.h" #include #include #include #include "pe-int.h" /****************************************************************************** * * * Paramètres : format = description de l'exécutable à compléter. * * * * Description : Extrait si elles existant les informations enrichies du PE. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void extract_pe_rich_header(GPeFormat *format) { const image_dos_header *header; /* En-tête avec positions */ bin_t *dans; /* Motif "DanS" trouvé */ GBinContent *content; /* Contenu à parcourir */ vmpa2t start; /* Position de départ */ const bin_t *data; /* Données brutes à analyser */ bin_t *rich; /* Marqueur "Rich" trouvé */ uint32_t checksum; /* Empreinte appliquée */ bool status; /* Bilan d'une lecture */ bin_t words[8]; /* Premiers mots trouvés */ header = g_pe_format_get_dos_header(format); dans = NULL; /* Recherche du marqueur final */ content = g_known_format_get_content(G_KNOWN_FORMAT(format)); g_binary_content_compute_start_pos(content, &start); data = g_binary_content_get_raw_access(content, &start, header->e_lfanew); if (data == NULL) goto exit; rich = memmem(data, header->e_lfanew, "Rich", 4); if (rich == NULL) goto exit; /* Constitution des premiers mots */ g_binary_content_compute_start_pos(content, &start); advance_vmpa(&start, rich - data); advance_vmpa(&start, 4); status = g_binary_content_read_u32(content, &start, SRE_LITTLE, &checksum); if (!status) goto exit; g_binary_content_compute_start_pos(content, &start); advance_vmpa(&start, rich - data); advance_vmpa(&start, 4); status = g_binary_content_read_raw(content, &start, 4, words + 4); assert(status); words[0] = 'D' ^ words[4]; words[1] = 'a' ^ words[5]; words[2] = 'n' ^ words[6]; words[3] = 'S' ^ words[7]; /* Recherche du marqueur initial et conclusion */ dans = memmem(data, header->e_lfanew, words, 8); if (dans != NULL && ((rich - dans) % 8 != 0)) dans = NULL; exit: if (dans == NULL) { init_vmpa(&start, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL); init_mrange(&format->rich_header, &start, 0); } else { init_vmpa(&start, (bin_t *)dans - data, VMPA_NO_VIRTUAL); init_mrange(&format->rich_header, &start, rich + 8 - dans); } g_object_unref(G_OBJECT(content)); } /****************************************************************************** * * * Paramètres : format = format en place à consulter. * * area = localisation à constituer. [OUT] * * * * Description : Décrit la zone couverte par l'en-tête enrichi du format. * * * * Retour : Validité de la zone définie en sortie. * * * * Remarques : - * * * ******************************************************************************/ bool g_pe_format_get_rich_header_area(const GPeFormat *format, mrange_t *area) { bool result; /* Validité à renvoyer */ result = (get_mrange_length(&format->rich_header) > 0); if (result) copy_mrange(area, &format->rich_header); return result; } /****************************************************************************** * * * Paramètres : format = format en place à consulter. * * checksum = empreinte incrustée à retrouver. [OUT] * * * * Description : Présente l'empreinte d'un en-tête enrichi du format chargé. * * * * Retour : Validité de la zone définie en sortie. * * * * Remarques : - * * * ******************************************************************************/ bool g_pe_format_get_rich_header_checksum(const GPeFormat *format, uint32_t *checksum) { bool result; /* Validité à renvoyer */ GBinContent *content; /* Contenu à parcourir */ vmpa2t pos; /* Tête de lecture */ #ifndef NDEBUG bool status; /* Bilan d'une lecture */ #endif result = (get_mrange_length(&format->rich_header) > 0); if (result) { content = g_known_format_get_content(G_KNOWN_FORMAT(format)); copy_vmpa(&pos, get_mrange_addr(&format->rich_header)); advance_vmpa(&pos, sizeof(uint32_t)); #ifndef NDEBUG status = g_binary_content_read_u32(content, &pos, SRE_LITTLE, checksum); assert(status); #else g_binary_content_read_u32(content, &pos, SRE_LITTLE, checksum); #endif g_object_unref(G_OBJECT(content)); } return result; } /****************************************************************************** * * * Paramètres : format = format en place à consulter. * * count = nombre d'éléments de la liste constituée. [OUT] * * * * Description : Présente l'en-tête enrichi du format chargé. * * * * Retour : Tableau de valeurs brutes d'information. * * * * Remarques : - * * * ******************************************************************************/ uint64_t *g_pe_format_get_rich_header(const GPeFormat *format, size_t *count) { uint64_t *result; /* Valeurs à retourner */ GBinContent *content; /* Contenu à parcourir */ vmpa2t iter; /* Tête de lecture */ size_t i; /* Boucle de parcours */ #ifndef NDEBUG bool status; /* Bilan d'une lecture */ #endif if (get_mrange_length(&format->rich_header) == 0) { *count = 0; result = NULL; } else { *count = get_mrange_length(&format->rich_header) / 8; result = malloc(*count * sizeof(uint64_t)); content = g_known_format_get_content(G_KNOWN_FORMAT(format)); copy_vmpa(&iter, get_mrange_addr(&format->rich_header)); for (i = 0; i < *count; i++) { #ifndef NDEBUG status = g_binary_content_read_u64(content, &iter, SRE_LITTLE, &result[i]); assert(status); #else g_binary_content_read_u64(content, &iter, SRE_LITTLE, &result[i]); #endif } g_object_unref(G_OBJECT(content)); } return result; } /****************************************************************************** * * * Paramètres : format = format en place à consulter. * * count = nombre d'éléments de la liste constituée. [OUT] * * * * Description : Présente les identifiants contenues dans l'en-tête enrichi. * * * * Retour : Tableau de valeurs raffinées d'information. * * * * Remarques : - * * * ******************************************************************************/ comp_id_t *g_pe_format_get_comp_ids(const GPeFormat *format, size_t *count) { comp_id_t *result; /* Identifiants à retourner */ uint64_t *values; /* Valeurs brutes à traiter */ size_t vcount; /* Quantité de ces valeurs */ uint64_t mask; /* Masque à appliquer */ size_t i; /* Boucle de parcours */ values = g_pe_format_get_rich_header(format, &vcount); if (vcount > 2) { mask = ((values[0] >> 32) & 0xffffffff); mask |= (mask << 32); *count = vcount - 2; result = malloc(*count * sizeof(comp_id_t)); for (i = 0; i < *count; i++) { values[i + 1] ^= mask; result[i].minor_cv = values[i + 1] & 0xffff; result[i].prod_id = (values[i + 1] >> 16) & 0xffff; result[i].count = (values[i + 1] >> 32) & 0xffffffff; } } else { *count = 0; result = NULL; } if (values != NULL) free(values); return result; }