diff options
Diffstat (limited to 'plugins/pe/format.c')
-rw-r--r-- | plugins/pe/format.c | 714 |
1 files changed, 629 insertions, 85 deletions
diff --git a/plugins/pe/format.c b/plugins/pe/format.c index 8533d25..f5bdac1 100644 --- a/plugins/pe/format.c +++ b/plugins/pe/format.c @@ -21,74 +21,122 @@ */ -#include "pe.h" +#include "format.h" -#include <string.h> +#include <assert.h> #include "pe-int.h" +#include "rich.h" #include "section.h" #include "symbols.h" -/* Initialise la classe des formats d'exécutables PE. */ +/* Initialise la classe des formats d'exécutables ELF. */ static void g_pe_format_class_init(GPeFormatClass *); -/* Initialise une instance de format d'exécutable PE. */ +/* Initialise une instance de format d'exécutable ELF. */ static void g_pe_format_init(GPeFormat *); +/* Supprime toutes les références externes. */ +static void g_pe_format_dispose(GPeFormat *); + +/* Procède à la libération totale de la mémoire. */ +static void g_pe_format_finalize(GPeFormat *); + +/* Indique la désignation interne du format. */ +static char *g_pe_format_get_key(const GPeFormat *); + +/* Fournit une description humaine du format. */ +static char *g_pe_format_get_description(const GPeFormat *); + +/* Assure l'interprétation d'un format en différé. */ +static bool g_pe_format_analyze(GPeFormat *, wgroup_id_t, GtkStatusStack *); + +/* Informe quant au boutisme utilisé. */ +static SourceEndian g_pe_format_get_endianness(const GPeFormat *); + /* Indique le type d'architecture visée par le format. */ static const char *g_pe_format_get_target_machine(const GPeFormat *); -/* Fournit les références aux zones binaires à analyser. */ -//static GBinPart **g_pe_format_get_parts(const GPeFormat *, size_t *); +/* Fournit l'adresse principale associée à un format Elf. */ +static bool g_pe_format_get_main_address(GPeFormat *, vmpa2t *); + + +#if 0 + +/* Etend la définition des portions au sein d'un binaire. */ +static void g_pe_format_refine_portions(GPeFormat *); + +#endif + + + +/* Fournit l'emplacement correspondant à une adresse virtuelle. */ +bool g_pe_format_translate_address_into_vmpa_using_portions(GPeFormat *, virt_t, vmpa2t *); + + +#if 0 + +/* Fournit l'emplacement d'une section donnée. */ +static bool g_pe_format_get_section_range_by_name(const GPeFormat *, const char *, mrange_t *); +#endif + + /****************************************************************************** * * -* Paramètres : content = contenu binaire à parcourir. * +* Paramètres : content = contenu binaire à traiter. * * * -* Description : Indique si le format peut être pris en charge ici. * +* Description : Valide un contenu comme étant un format PE. * * * -* Retour : true si la réponse est positive, false sinon. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -bool pe_is_matching(GBinContent *content) +bool check_pe_format(const GBinContent *content) { - bool result; /* Bilan à faire connaître */ - image_dos_header dos_header; /* En-tête DOS */ + bool result; /* Bilan à faire remonter */ + vmpa2t addr; /* Tête de lecture initiale */ + char magic[4]; /* Idenfiant standard */ + GPeFormat format; /* Format factice */ - result = false; -#if 0 - if (length >= 2) + init_vmpa(&addr, 0, VMPA_NO_VIRTUAL); + + result = g_binary_content_read_raw(content, &addr, 2, (bin_t *)magic); + + if (result) + result = (memcmp(magic, "\x4d\x5a" /* MZ */, 2) == 0); + + if (result) { - result = (strncmp((const char *)content, "\x4d\x5a" /* MZ */, 2) == 0); - result &= length >= sizeof(image_dos_header); + G_KNOWN_FORMAT(&format)->content = (GBinContent *)content; + result = read_dos_image_header(&format, &format.dos_header); } if (result) { - memcpy(&dos_header, content, sizeof(image_dos_header)); + init_vmpa(&addr, format.dos_header.e_lfanew, VMPA_NO_VIRTUAL); - result = length >= (dos_header.e_lfanew + 4); + result = g_binary_content_read_raw(content, &addr, 4, (bin_t *)magic); - result &= (strncmp((const char *)&content[dos_header.e_lfanew], - "\x50\x45\x00\x00" /* PE00 */, 4) == 0); + if (result) + result = (memcmp(magic, "\x50\x45\x00\x00" /* PE00 */, 4) == 0); } -#endif + return result; } -/* Indique le type défini pour un format d'exécutable PE. */ +/* Indique le type défini pour un format d'exécutable ELF. */ G_DEFINE_TYPE(GPeFormat, g_pe_format, G_TYPE_EXE_FORMAT); @@ -96,7 +144,7 @@ G_DEFINE_TYPE(GPeFormat, g_pe_format, G_TYPE_EXE_FORMAT); * * * Paramètres : klass = classe à initialiser. * * * -* Description : Initialise la classe des formats d'exécutables PE. * +* Description : Initialise la classe des formats d'exécutables ELF. * * * * Retour : - * * * @@ -106,6 +154,36 @@ G_DEFINE_TYPE(GPeFormat, g_pe_format, G_TYPE_EXE_FORMAT); static void g_pe_format_class_init(GPeFormatClass *klass) { + GObjectClass *object; /* Autre version de la classe */ + GKnownFormatClass *known; /* Version de format connu */ + GBinFormatClass *fmt; /* Version en format basique */ + GExeFormatClass *exe; /* Version en exécutable */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_pe_format_dispose; + object->finalize = (GObjectFinalizeFunc)g_pe_format_finalize; + + known = G_KNOWN_FORMAT_CLASS(klass); + + known->get_key = (known_get_key_fc)g_pe_format_get_key; + known->get_desc = (known_get_desc_fc)g_pe_format_get_description; + known->analyze = (known_analyze_fc)g_pe_format_analyze; + + fmt = G_BIN_FORMAT_CLASS(klass); + + fmt->get_endian = (format_get_endian_fc)g_pe_format_get_endianness; + + exe = G_EXE_FORMAT_CLASS(klass); + + exe->get_machine = (get_target_machine_fc)g_pe_format_get_target_machine; + exe->get_main_addr = (get_main_addr_fc)g_pe_format_get_main_address; + //exe->refine_portions = (refine_portions_fc)g_pe_format_refine_portions; + + //exe->translate_phys = (translate_phys_fc)g_exe_format_translate_offset_into_vmpa_using_portions; + exe->translate_virt = (translate_virt_fc)g_pe_format_translate_address_into_vmpa_using_portions; + + //exe->get_range_by_name = (get_range_by_name_fc)g_pe_format_get_section_range_by_name; } @@ -114,7 +192,7 @@ static void g_pe_format_class_init(GPeFormatClass *klass) * * * Paramètres : format = instance à initialiser. * * * -* Description : Initialise une instance de format d'exécutable PE. * +* Description : Initialise une instance de format d'exécutable ELF. * * * * Retour : - * * * @@ -124,6 +202,50 @@ static void g_pe_format_class_init(GPeFormatClass *klass) static void g_pe_format_init(GPeFormat *format) { + format->sections = NULL; + + format->loaded = false; + +} + + +/****************************************************************************** +* * +* Paramètres : format = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_pe_format_dispose(GPeFormat *format) +{ + G_OBJECT_CLASS(g_pe_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_pe_format_finalize(GPeFormat *format) +{ + if (format->sections != NULL) + free(format->sections); + + G_OBJECT_CLASS(g_pe_format_parent_class)->finalize(G_OBJECT(format)); } @@ -131,7 +253,6 @@ static void g_pe_format_init(GPeFormat *format) /****************************************************************************** * * * Paramètres : content = contenu binaire à parcourir. * -* length = taille du contenu en question. * * * * Description : Prend en charge un nouveau format PE. * * * @@ -141,53 +262,140 @@ static void g_pe_format_init(GPeFormat *format) * * ******************************************************************************/ -GBinFormat *g_pe_format_new(const bin_t *content, off_t length) +GExeFormat *g_pe_format_new(GBinContent *content) { GPeFormat *result; /* Structure à retourner */ - off_t offset; /* Tête de lecture */ + if (!check_pe_format(content)) + return NULL; - int i; + result = g_object_new(G_TYPE_PE_FORMAT, NULL); + g_known_format_set_content(G_KNOWN_FORMAT(result), content); - result = g_object_new(G_TYPE_PE_FORMAT, NULL); + return G_EXE_FORMAT(result); - //g_binary_format_set_content(G_BIN_FORMAT(result), content, length); +} - offset = 0; - if (!read_dos_image_header(result, &offset, &result->dos_header)) - { - /* TODO */ - return NULL; - } +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à consulter. * +* * +* Description : Indique la désignation interne du format. * +* * +* Retour : Désignation du format. * +* * +* Remarques : - * +* * +******************************************************************************/ - offset = result->dos_header.e_lfanew; +static char *g_pe_format_get_key(const GPeFormat *format) +{ + char *result; /* Désignation à retourner */ - if (!read_pe_nt_header(result, &offset, &result->nt_headers)) - { - /* TODO */ - return NULL; - } + result = strdup("pe"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à consulter. * +* * +* Description : Fournit une description humaine du format. * +* * +* Retour : Description du format. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_pe_format_get_description(const GPeFormat *format) +{ + char *result; /* Désignation à retourner */ + + result = strdup("Portable Executable"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = format chargé dont l'analyse est lancée. * +* gid = groupe de travail dédié. * +* status = barre de statut à tenir informée. * +* * +* Description : Assure l'interprétation d'un format en différé. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ - result->section_offset = offset; +static bool g_pe_format_analyze(GPeFormat *format, wgroup_id_t gid, GtkStatusStack *status) +{ + bool result; /* Bilan à retourner */ + GExeFormat *exe; /* Autre version du format */ + vmpa2t section_start; /* Zone de départ des sections */ - printf("offset :: 0x%08x\n", offset); + exe = G_EXE_FORMAT(format); - printf("Format :: 0x%08x\n", result->nt_headers.signature); + result = read_dos_image_header(format, &format->dos_header); + if (!result) goto error; - printf("directories :: %d\n", result->nt_headers.optional_header.number_of_rva_and_sizes); + result = read_pe_nt_header(format, &format->nt_headers, §ion_start); + if (!result) goto error; - for (i = 0; i < result->nt_headers.optional_header.number_of_rva_and_sizes; i++) - printf(" [%d] addr=0x%08x size=%d\n", i, - result->nt_headers.optional_header.data_directory[i].virtual_address, - result->nt_headers.optional_header.data_directory[i].size); + format->sections = read_all_pe_sections(format, §ion_start); + if (format->sections == NULL) goto error; + extract_pe_rich_header(format); - load_pe_symbols(result); + result = load_pe_symbols(format, gid, status); + if (!result) goto error; + result = g_executable_format_complete_loading(exe, gid, status); + if (!result) goto error; - return G_BIN_FORMAT(result); + error: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* * +* Description : Informe quant au boutisme utilisé. * +* * +* Retour : Indicateur de boutisme. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static SourceEndian g_pe_format_get_endianness(const GPeFormat *format) +{ + SourceEndian result; /* Boutisme à retourner */ + + /** + * Sauf exception, le boutisme est généralement petit. + * + * Cf. https://reverseengineering.stackexchange.com/a/17923 + * https://docs.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions?view=msvc-160#endianness + */ + + result = SRE_LITTLE; + + return result; } @@ -206,69 +414,405 @@ GBinFormat *g_pe_format_new(const bin_t *content, off_t length) static const char *g_pe_format_get_target_machine(const GPeFormat *format) { - return "i386"; + const char *result; /* Identifiant à retourner */ + + switch (format->nt_headers.file_header.machine) + { + case IMAGE_FILE_MACHINE_I386: + result = "i386"; + break; + + case IMAGE_FILE_MACHINE_R3000: + case IMAGE_FILE_MACHINE_R4000: + case IMAGE_FILE_MACHINE_R10000: + case IMAGE_FILE_MACHINE_WCEMIPSV2: + case IMAGE_FILE_MACHINE_MIPS16: + case IMAGE_FILE_MACHINE_MIPSFPU: + case IMAGE_FILE_MACHINE_MIPSFPU16: + result = "mips"; + break; + + case IMAGE_FILE_MACHINE_ARM: + case IMAGE_FILE_MACHINE_THUMB: + case IMAGE_FILE_MACHINE_ARMNT: + result = "armv7"; + break; + + case IMAGE_FILE_MACHINE_UNKNOWN: + default: + result = NULL; + break; + + } + + return result; } /****************************************************************************** * * -* Paramètres : format = informations chargées à consulter. * -* count = quantité de zones listées. [OUT] * +* Paramètres : format = description de l'exécutable à consulter. * +* addr = adresse principale trouvée si possible. [OUT] * * * -* Description : Fournit les références aux zones binaires à analyser. * +* Description : Fournit l'adresse principale associée à un format Elf. * * * -* Retour : Zones binaires à analyser. * +* Retour : Bilan des recherches. * * * * Remarques : - * * * ******************************************************************************/ + +static bool g_pe_format_get_main_address(GPeFormat *format, vmpa2t *addr) +{ + bool result; /* Bilan à retourner */ + GBinSymbol *symbol; /* Point d'entrée trouvé */ + GBinFormat *base; /* Version d'instance parente */ + const mrange_t *range; /* Emplacement de ce point */ + + result = false; + symbol = NULL; + + base = G_BIN_FORMAT(format); + + if (g_binary_format_find_symbol_by_label(base, "main", &symbol)) + goto done; + + if (g_binary_format_find_symbol_by_label(base, "_start", &symbol)) + goto done; + + if (g_binary_format_find_symbol_by_label(base, "entry_point", &symbol)) + goto done; + + done: + + if (symbol != NULL) + { + result = true; + + range = g_binary_symbol_get_range(symbol); + + copy_vmpa(addr, get_mrange_addr(range)); + + g_object_unref(G_OBJECT(symbol)); + + } + + return result; + +} + + #if 0 -static GBinPart **g_pe_format_get_parts(const GPeFormat *format, size_t *count) + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* * +* Description : Etend la définition des portions au sein d'un binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_pe_format_refine_portions(GPeFormat *format) +{ + +} + +#endif + + + +/****************************************************************************** +* * +* 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_pe_format_translate_address_into_vmpa_using_portions(GPeFormat *format, virt_t addr, vmpa2t *pos) { - GBinPart **result; /* Tableau à retourner */ + bool result; /* Bilan à retourner */ uint16_t i; /* Boucle de parcours */ - image_section_header section; /* En-tête de section PE */ - GBinPart *part; /* Partie à intégrer à la liste*/ - char name[IMAGE_SIZEOF_SHORT_NAME + 1]; /* Nom de section utilisable */ + const image_section_header *section; /* Section à consulter */ + phys_t diff; /* Décallage à appliquer */ - result = NULL; - *count = 0; + result = false; - for (i = 0; i < format->nt_headers.file_header.number_of_sections; i++) + for (i = 0; i < format->nt_headers.file_header.number_of_sections && !result; i++) { - if (!find_pe_section_by_index(format, i, §ion)) + section = &format->sections[i]; + + if (addr < section->virtual_address) + continue; + + if (addr >= (section->virtual_address + section->size_of_raw_data)) continue; - if (section.characteristics & IMAGE_SCN_MEM_EXECUTE) - { - part = g_binary_part_new(); + diff = addr - section->virtual_address; - memset(name, 0, (IMAGE_SIZEOF_SHORT_NAME + 1) * sizeof(char)); - memcpy(name, section.name, (IMAGE_SIZEOF_SHORT_NAME + 1) * sizeof(char)); + init_vmpa(pos, section->pointer_to_raw_data + diff, addr); - g_binary_part_set_name(part, name); + result = true; - printf("section '%s'\n", name); + } - g_binary_part_set_values(part, - section.pointer_to_raw_data, - section.size_of_raw_data, - section.virtual_address); + //printf(" // trans // %x -> %x (valid? %d)\n", (unsigned int)addr, (unsigned int)pos->physical, result); - printf("section[%d] start=0x%08x size=%d addr=0x%08x\n", i, - section.pointer_to_raw_data, - section.size_of_raw_data, - section.virtual_address); + return result; - result = (GBinPart **)realloc(result, ++(*count) * sizeof(GBinPart *)); - result[*count - 1] = part; +} + + + + +#if 0 - } +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à consulter. * +* name = nom de la section recherchée. * +* range = emplacement en mémoire à renseigner. [OUT] * +* * +* Description : Fournit l'emplacement d'une section donnée. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_pe_format_get_section_range_by_name(const GPeFormat *format, const char *name, mrange_t *range) +{ + bool result; /* Bilan à retourner */ + phys_t offset; /* Position physique de section*/ + phys_t size; /* Taille de la section trouvée*/ + virt_t address; /* Adresse virtuelle de section*/ + vmpa2t tmp; /* Adresse à initialiser */ + + result = find_elf_section_content_by_name(format, name, &offset, &size, &address); + + if (result) + { + init_vmpa(&tmp, offset, address); + init_mrange(range, &tmp, size); } return result; } #endif + + + + + + + + +/****************************************************************************** +* * +* Paramètres : format = format en place à consulter. * +* * +* Description : Présente l'en-tête MS-DOS du format chargé. * +* * +* Retour : Pointeur vers la description principale. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const image_dos_header *g_pe_format_get_dos_header(const GPeFormat *format) +{ + const image_dos_header *result; /* Informations à retourner */ + + result = &format->dos_header; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = format en place à consulter. * +* * +* Description : Présente l'en-tête NT du format chargé. * +* * +* Retour : Pointeur vers la description principale. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const image_nt_headers *g_pe_format_get_nt_headers(const GPeFormat *format) +{ + const image_nt_headers *result; /* Informations à retourner */ + + result = &format->nt_headers; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = format en place à consulter. * +* * +* Description : Indique si le format PE est en 32 bits ou en 64 bits. * +* * +* Retour : true si le format est en 32 bits, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_pe_format_get_is_32b(const GPeFormat *format) +{ + bool result; /* Nature à retourner */ + + assert(format->loaded); + + switch (format->nt_headers.optional_header.header_32.magic) + { + case IMAGE_NT_OPTIONAL_HDR32_MAGIC: + result = true; + break; + case IMAGE_NT_OPTIONAL_HDR64_MAGIC: + result = false; + break; + default: + result = true; + assert(false); + break; + } + + return result; + + +} + + +/****************************************************************************** +* * +* Paramètres : format = format en place à consulter. * +* count = taille (fixe) du tableau renvoyé. [OUT] * +* * +* Description : Offre un raccourci vers les répertoires du format PE. * +* * +* Retour : Pointeur vers le tableau des répertoires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const image_data_directory *g_pe_format_get_directories(const GPeFormat *format, size_t *count) +{ + const image_data_directory *result; /* Liste à retourner */ + + if (count != NULL) + *count = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; + + if (g_pe_format_get_is_32b(format)) + result = format->nt_headers.optional_header.header_32.data_directory; + else + result = format->nt_headers.optional_header.header_64.data_directory; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = format en place à consulter. * +* index = indice du répertoire visé. * +* * +* Description : Extrait le contenu d'un répertoire du format PE. * +* * +* Retour : Pointeur vers un contenu chargé ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +void *g_pe_format_get_directory(const GPeFormat *format, size_t index) +{ + void *result; /* Données à retourner */ + const image_data_directory *dir; /* Localisation du répertoire */ + vmpa2t pos; /* Tête de lecture */ + bool status; /* Bilan d'un traitement */ + image_export_directory *export; /* Répertoire de type 0 */ + image_import_descriptor *imports; /* Répertoire de type 1 */ + size_t imported_count; /* Quantité de DLL requises */ + + result = NULL; + + if (index >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) + goto exit; + + dir = g_pe_format_get_directories(format, NULL); + dir += index; + + status = g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), dir->virtual_address, &pos); + if (!status) goto exit; + + switch (index) + { + case IMAGE_DIRECTORY_ENTRY_EXPORT: + + export = malloc(sizeof(image_export_directory)); + + status = read_pe_image_export_directory(format, &pos, export); + + if (!status) + { + free(export); + goto exit; + } + + result = export; + break; + + case IMAGE_DIRECTORY_ENTRY_IMPORT: + + imports = NULL; + imported_count = 0; + + do + { + imports = realloc(imports, ++imported_count * sizeof(image_import_descriptor)); + + status = read_pe_image_import_descriptor(format, &pos, imports + (imported_count - 1)); + + if (!status) + { + free(imports); + goto exit; + } + + } + while (imports[imported_count - 1].original_first_thunk != 0); + + result = imports; + break; + + } + + exit: + + return result; + +} |