summaryrefslogtreecommitdiff
path: root/plugins/pe/rich.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2021-04-05 22:59:31 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2021-04-05 23:11:48 (GMT)
commitb0347ca45a08ac63bc6dd6f244b046c6d19a6cdd (patch)
tree9af1ec9901ddcf696bd3297633faf9fb46712396 /plugins/pe/rich.c
parentcf0b5d5f07e8102f2c9a04012bf29cabda9d85e4 (diff)
Build a partial working support for the PE format.
Diffstat (limited to 'plugins/pe/rich.c')
-rw-r--r--plugins/pe/rich.c312
1 files changed, 312 insertions, 0 deletions
diff --git a/plugins/pe/rich.c b/plugins/pe/rich.c
new file mode 100644
index 0000000..7764f09
--- /dev/null
+++ b/plugins/pe/rich.c
@@ -0,0 +1,312 @@
+
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "rich.h"
+
+
+#include <assert.h>
+#include <string.h>
+
+
+#include <format/known.h>
+
+
+#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;
+
+}