From 6c51b9eed427fd55ce1457834853386cc8d543cd Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Mon, 29 Jan 2018 21:56:31 +0100 Subject: Handled properly imported/exported ELF symbols, as well as all other symbols. --- ChangeLog | 42 ++ plugins/elf/dynamic.c | 107 +++++ plugins/elf/dynamic.h | 6 + plugins/elf/elf_def.h | 4 +- plugins/elf/format.c | 25 ++ plugins/elf/helper_arm.c | 195 +++++---- plugins/elf/helper_arm.h | 4 +- plugins/elf/loading.c | 453 ++++++++++++++++++-- plugins/elf/loading.h | 40 +- plugins/elf/section.c | 7 +- plugins/elf/symbols.c | 1020 ++++++++++++++++++++++++++++++++-------------- plugins/elf/symbols.h | 16 +- src/analysis/binary.c | 4 +- src/common/sort.c | 31 ++ src/common/sort.h | 4 + src/format/format-int.h | 5 + src/format/format.c | 189 ++++++++- src/format/format.h | 14 + src/format/symiter.c | 5 + 19 files changed, 1716 insertions(+), 455 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2ec6dab..da7fe01 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,45 @@ +18-01-29 Cyrille Bagard + + * plugins/elf/dynamic.c: + * plugins/elf/dynamic.h: + Extract more information from the PT_DYNAMIC segment. + + * plugins/elf/elf_def.h: + Improve the macro definitions for relocations. + + * plugins/elf/format.c: + Insert some extra processings atfer the disassembly process. + + * plugins/elf/helper_arm.c: + * plugins/elf/helper_arm.h: + Resolve relocation offsets for ARM. + + * plugins/elf/loading.c: + * plugins/elf/loading.h: + Rely on threads to load more ELF information. + + * plugins/elf/section.c: + Make all arguments optional when looking for section parameters. + + * plugins/elf/symbols.c: + * plugins/elf/symbols.h: + Handle properly imported/exported ELF symbols, as well as all other symbols. + + * src/analysis/binary.c: + Update the format symbols after disassembling. + + * src/common/sort.c: + * src/common/sort.h: + Compare uint64_t integers. + + * src/format/format-int.h: + * src/format/format.c: + * src/format/format.h: + Update code for post-processing. Create new ways to search for symbols. + + * src/format/symiter.c: + Add a check for locked format symbol list. + 18-01-26 Cyrille Bagard * plugins/elf/format.c: diff --git a/plugins/elf/dynamic.c b/plugins/elf/dynamic.c index ed681d1..f1d5e02 100644 --- a/plugins/elf/dynamic.c +++ b/plugins/elf/dynamic.c @@ -111,6 +111,35 @@ bool find_elf_dynamic_item_from_pheader(const GElfFormat *format, const elf_phdr /****************************************************************************** * * +* Paramètres : format = informations chargées à consulter. * +* type = sorte d'élément recherché. * +* item = élément retrouvé dans la section. [OUT] * +* * +* Description : Retrouve rapidement un élément dans la section dynamique. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool find_elf_dynamic_item(const GElfFormat *format, int64_t type, elf_dyn *item) +{ + bool result; /* Bilan à retourner */ + elf_phdr dynamic; /* En-tête de programme DYNAMIC*/ + + result = find_elf_dynamic_program_header(format, &dynamic); + + if (result) + result = find_elf_dynamic_item_from_pheader(format, &dynamic, type, item); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : format = description de l'exécutable à consulter. * * count = nombre d'éléments dans la liste constituée. * * * @@ -202,3 +231,81 @@ const char **list_elf_needed_objects(const GElfFormat *format, size_t *count) return result; } + + +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à manipuler. * +* virt = position en mémoire de la PLT. [OUT] * +* * +* Description : Retrouve l'adresse de la PLT en se basant sur la GOT. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool resolve_plt_using_got(GElfFormat *format, virt_t *virt) +{ + bool result; /* Bilan à retourner */ + elf_phdr dynamic; /* Programme à analyser */ + elf_dyn pltgot; /* Table de type DT_PLTGOT */ + virt_t got_virt; /* Adresse mémoire de la GOT */ + vmpa2t got_addr; /* Localisation complète */ + GBinContent *content; /* Contenu binaire à parcourir */ + uint32_t raw_32; /* Valeur brute de 32 bits lue */ + uint64_t raw_64; /* Valeur brute de 64 bits lue */ + + result = false; + + if (!find_elf_program_by_type(format, PT_DYNAMIC, &dynamic)) + goto rpug_exit; + + if (!find_elf_dynamic_item_from_pheader(format, &dynamic, DT_PLTGOT, &pltgot)) + goto rpug_exit; + + got_virt = ELF_DYN(format, pltgot, d_un.d_ptr); + + if (!g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), got_virt, &got_addr)) + goto rpug_exit; + + content = G_BIN_FORMAT(format)->content; + + /** + * Quelques pistes pour la connaissance des premières cellules d'une GOT : + * + * "Lazy procedure linkage with the PLT" (mot clef : GOT+4). + * http://www.iecc.com/linker/linker10.html + * + * "How the ELF Ruined Christmas" (mot clef : GOT[1]). + * https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-di-frederico.pdf + */ + + if (format->is_32b) + { + advance_vmpa(&got_addr, 3 * sizeof(uint32_t)); + + result = g_binary_content_read_u32(content, &got_addr, format->endian, &raw_32); + + if (result) + *virt = raw_32; + + } + + else + { + advance_vmpa(&got_addr, 3 * sizeof(uint64_t)); + + result = g_binary_content_read_u64(content, &got_addr, format->endian, &raw_64); + + if (result) + *virt = raw_64; + + } + + rpug_exit: + + return result; + +} diff --git a/plugins/elf/dynamic.h b/plugins/elf/dynamic.h index c166712..1ca4785 100644 --- a/plugins/elf/dynamic.h +++ b/plugins/elf/dynamic.h @@ -36,9 +36,15 @@ bool find_elf_dynamic_program_header(const GElfFormat *, elf_phdr *); /* Retrouve un élément donné dans la section dynamique. */ bool find_elf_dynamic_item_from_pheader(const GElfFormat *, const elf_phdr *, int64_t, elf_dyn *); +/* Retrouve rapidement un élément dans la section dynamique. */ +bool find_elf_dynamic_item(const GElfFormat *, int64_t, elf_dyn *); + /* Fournit la liste des objets partagés requis. */ const char **list_elf_needed_objects(const GElfFormat *, size_t *); +/* Retrouve l'adresse de la PLT en se basant sur la GOT. */ +bool resolve_plt_using_got(GElfFormat *, virt_t *); + #endif /* _PLUGINS_ELF_DYNAMIC_H */ diff --git a/plugins/elf/elf_def.h b/plugins/elf/elf_def.h index 06adff7..2120afa 100644 --- a/plugins/elf/elf_def.h +++ b/plugins/elf/elf_def.h @@ -599,8 +599,8 @@ typedef union _elf_rel #define ELF_REL(fmt, rl, fld) (fmt->is_32b ? (rl).rel32.fld : (rl).rel64.fld) -#define ELF_REL_SYM(fmt, rl) (fmt->is_32b ? ELF32_R_SYM(rl.rel32.r_info) : ELF64_R_SYM(rl.rel64.r_info)) -#define ELF_REL_TYPE(fmt, rl) (fmt->is_32b ? ELF32_R_TYPE(rl.rel32.r_info) : ELF64_R_TYPE(rl.rel64.r_info)) +#define ELF_REL_SYM(fmt, rl) (fmt->is_32b ? ELF32_R_SYM((rl).rel32.r_info) : ELF64_R_SYM((rl).rel64.r_info)) +#define ELF_REL_TYPE(fmt, rl) (fmt->is_32b ? ELF32_R_TYPE((rl).rel32.r_info) : ELF64_R_TYPE((rl).rel64.r_info)) #define ELF_SIZEOF_REL(fmt) (fmt->is_32b ? sizeof(elf32_rel) : sizeof(elf64_rel)) diff --git a/plugins/elf/format.c b/plugins/elf/format.c index 9e3b636..d48eef9 100644 --- a/plugins/elf/format.c +++ b/plugins/elf/format.c @@ -62,6 +62,9 @@ static void g_elf_format_finalize(GElfFormat *); /* Informe quant au boutisme utilisé. */ static SourceEndian g_elf_format_get_endianness(const GElfFormat *); +/* Réalise un traitement post-désassemblage. */ +static void g_elf_format_complete_analysis(GElfFormat *, GtkStatusStack *); + /* Indique le type d'architecture visée par le format. */ static const char *g_elf_format_get_target_machine(const GElfFormat *); @@ -157,6 +160,8 @@ static void g_elf_format_class_init(GElfFormatClass *klass) fmt->get_endian = (format_get_endian_fc)g_elf_format_get_endianness; + fmt->complete = (format_complete_analysis_fc)g_elf_format_complete_analysis; + exe = G_EXE_FORMAT_CLASS(klass); exe->get_machine = (get_target_machine_fc)g_elf_format_get_target_machine; @@ -340,6 +345,26 @@ static SourceEndian g_elf_format_get_endianness(const GElfFormat *format) /****************************************************************************** * * +* Paramètres : format = description de l'exécutable à manipuler. * +* status = barre de statut à tenir informée. * +* * +* Description : Réalise un traitement post-désassemblage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_elf_format_complete_analysis(GElfFormat *format, GtkStatusStack *status) +{ + refresh_elf_relocations(format, status); + +} + + +/****************************************************************************** +* * * Paramètres : format = informations chargées à consulter. * * * * Description : Indique le type d'architecture visée par le format. * diff --git a/plugins/elf/helper_arm.c b/plugins/elf/helper_arm.c index a037469..4c34d78 100644 --- a/plugins/elf/helper_arm.c +++ b/plugins/elf/helper_arm.c @@ -24,15 +24,8 @@ #include "helper_arm.h" -#include - - -#include - - #include "elf_def_arm.h" #include "elf-int.h" -#include "symbols.h" @@ -70,12 +63,11 @@ const char *get_elf_program_arm_type_desc(uint32_t p_type) /****************************************************************************** * * -* Paramètres : format = description de l'exécutable à compléter. * -* relxxx = section .rel.xxx trouvée (zone à traiter). * -* dynsym = section .dynsym trouvée (info. dynamiques). * -* dynstr = section .dynstr trouvée (chaînes de caractères). * +* Paramètres : format = description de l'exécutable à manipuler. * +* range = emplacement de la procédure de liaison. * +* offset = décalage retrouvé par désassemblage... [OUT] * * * -* Description : Charge en mémoire la liste des symboles relogés. * +* Description : Retrouve le décalage appliqué lors d'une résolution. * * * * Retour : Bilan de l'opération. * * * @@ -83,87 +75,124 @@ const char *get_elf_program_arm_type_desc(uint32_t p_type) * * ******************************************************************************/ -bool load_elf_arm_relocated_symbols(GElfFormat *format, const elf_shdr *relxxx, const elf_shdr *dynsym, const elf_shdr *dynstr) +bool retrieve_arm_linkage_offset(GElfFormat *format, const mrange_t *range, uint64_t *offset) { bool result; /* Bilan à retourner */ - phys_t rel_start; /* Début de la zone à traiter */ - phys_t rel_size; /* Taille de cette même zone */ - GBinFormat *base; /* Autre version du format */ - phys_t iter; /* Boucle de parcours */ - elf_rel reloc; /* Infos de relocalisation */ - off_t index; /* Indice de la portion visée */ - elf_sym sym; /* Définition complète */ - const char *name; /* Nom du symbole trouvé */ - char *plt_name; /* Adaptation de l'étiquette */ - virt_t virt; /* Adresse en mémoire virtuelle*/ - virt_t final_virt; /* Adresse virtuelle retenue */ - bool status; /* Bilan d'une opération */ - vmpa2t addr; /* Localisation d'une routine */ - GBinRoutine *routine; /* Nouvelle routine trouvée */ - GBinSymbol *symbol; /* Nouveau symbole construit */ - mrange_t range; /* Couverture mémoire associée */ - - result = true; - - get_elf_section_content(format, relxxx, &rel_start, &rel_size, NULL); - - base = G_BIN_FORMAT(format); - - for (iter = rel_start; iter < (rel_start + rel_size); ) + GBinContent *content; /* Contenu binaire à parcourir */ + vmpa2t pos; /* Tete de lecture */ + uint32_t raw; /* Valeur brute lue */ + uint32_t shift; /* Décalage arithmétique */ + + /** + * Pour faciliter la compréhension, on peut s'appuyer sur la lecture de : + * + * http://blog.qt.io/blog/2010/12/04/moving-code-around/ + * + */ + + content = G_BIN_FORMAT(format)->content; + + copy_vmpa(&pos, get_mrange_addr(range)); + + result = g_binary_content_read_u32(content, &pos, format->endian, &raw); + if (!result) goto ralo_exit; + + /** + * On ne reconnaît pour l'instant que la seule combinaison suivante. + * + * Charge de compléter cette reconnaissance en fonction de nouvelles + * découvertes ! + */ + + /** + * R_ARM_JUMP_SLOT : + * + * e28fc600 add ip, pc, #0, 12 + * e28cca08 add ip, ip, #8, 20 ; 0x8000 + * e5bcf310 ldr pc, [ip, #784]! ; 0x310 + */ + + if (raw == 0xe28fc600) { - result = read_elf_relocation(format, &iter, &reloc); - if (!result) break; - - index = ELF_REL_SYM(format, reloc); - - if (!get_elf_symbol_by_index(format, dynsym, index, &sym)) - continue; - - name = get_elf_symbol_name(format, dynsym, dynstr, index); - - if (name == NULL) - name = "unknown"; - - asprintf(&plt_name, "%s@plt", name); - - switch (ELF_REL_TYPE(format, reloc)) + *offset = get_virt_addr(get_mrange_addr(range)) + 8; + + result = g_binary_content_read_u32(content, &pos, format->endian, &raw); + if (!result) goto ralo_exit; + + /** + * La seconde instruction répond à l'encodage spécifié dans : + * + * A8.8.5 - ADD (immediate, ARM) + * + * 31 30 29 28 | 27 26 25 24 23 22 21 20 | 19 18 17 16 | 15 14 13 12 | 11 10 9 8 7 6 5 4 3 2 1 0 + * cond | 0 0 1 0 1 0 0 S | Rn | Rd | imm12 + * + * On a donc : + * + * ADD{S}{}{} {,} , # + * + * Avec : + * + * - S = 0. + * - Rn = ip = r12 = 0xc + * - Rd = ip = r12 = 0xc + * - const = ARMExpandImm(imm12) + * + * Le fonctionnement de la macro ARMExpandImm est détaillé dans : + * + * A5.2.4 - Modified immediate constants in ARM instructions + * + */ + + if ((raw & 0xfffff000) != 0xe28cc000) { - case R_ARM_JUMP_SLOT: - - virt = ELF_SYM(format, sym, st_value); - if (virt == 0) goto lears_next; - - final_virt = virt & ~0x1; - - status = g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), final_virt, &addr); - if (!status) goto lears_next; - - routine = try_to_demangle_routine(plt_name); - symbol = G_BIN_SYMBOL(routine); - - init_mrange(&range, &addr, 0); - g_binary_symbol_set_range(symbol, &range); - - /* Comptabilisation pour le désassemblage brut */ - g_binary_format_register_code_point(base, virt, false); - - break; - - default: - assert(false); - symbol = NULL; - break; + result = false; + goto ralo_exit; + } + shift = 32 - ((raw & 0xf00) >> 8) * 2; + + *offset += (raw & 0xf) << shift; + + result = g_binary_content_read_u32(content, &pos, format->endian, &raw); + if (!result) goto ralo_exit; + + /** + * La dernière instruction répond à l'encodage spéficié dans : + * + * A8.8.63 - LDR (immediate, ARM) + * + * 31 30 29 28 | 27 26 25 24 23 22 21 20 | 19 18 17 16 | 15 14 13 12 | 11 10 9 8 7 6 5 4 3 2 1 0 + * cond | 0 1 0 P U 0 W 1 | Rn | Rt | imm12 + * + * On a donc : + * + * LDR{}{} , [, #+/-]! + * + * Avec : + * + * - P = 1 (index). + * - U = 1 (add). + * - W = 1 (wback). + * - Rn = ip = r12 = 0xc + * - Rt = pc = r15 = 0xf + * + */ + + if ((raw & 0xfffff000) != 0xe5bcf000) + { + result = false; + goto ralo_exit; } - if (symbol != NULL) - g_binary_format_add_symbol(base, symbol); + *offset += (raw & 0xfff); - lears_next: + } - free(plt_name); + else + result = false; - } + ralo_exit: return result; diff --git a/plugins/elf/helper_arm.h b/plugins/elf/helper_arm.h index d4be96c..07549ad 100644 --- a/plugins/elf/helper_arm.h +++ b/plugins/elf/helper_arm.h @@ -32,8 +32,8 @@ /* Fournit la description humaine d'un type de segment ELF. */ const char *get_elf_program_arm_type_desc(uint32_t); -/* Charge en mémoire la liste des symboles relogés. */ -bool load_elf_arm_relocated_symbols(GElfFormat *, const elf_shdr *, const elf_shdr *, const elf_shdr *); +/* Retrouve le décalage appliqué lors d'une résolution. */ +bool retrieve_arm_linkage_offset(GElfFormat *, const mrange_t *, uint64_t *); diff --git a/plugins/elf/loading.c b/plugins/elf/loading.c index 377eb14..5d82fcc 100644 --- a/plugins/elf/loading.c +++ b/plugins/elf/loading.c @@ -24,13 +24,19 @@ #include "loading.h" +#include +#include + + #include +#include +#include #include +#include #include #include "elf-int.h" -#include "section.h" @@ -41,24 +47,58 @@ struct _GElfLoading GElfFormat *format; /* Format à faire évoluer */ + phys_t str_start; /* Chaînes à disposition */ + union { struct { - const elf_shdr *section; /* Section à éplucher */ bool use_virt; /* Représentatio par défaut */ - elf_shdr strtab; /* Section .strtab trouvée */ - bool has_strtab; /* Présence de cette section */ + }; + + struct + { + elf_rel *relocs_to_fill; /* Tableau à remplir */ + + }; + + struct + { + elf_rel *relocs; /* Relocalisations présentes */ + size_t rel_count; /* Qté de ces relocalisations */ + + phys_t sym_start; /* Début de zone des symboles */ + uint32_t sym_count; /* Nombre de symboles présents */ }; + }; - elf_loading_cb callback; /* Routine de traitement finale*/ - phys_t first; /* Position du premier élément */ - phys_t begin; /* Point de départ du parcours */ - phys_t end; /* Point d'arrivée exclu */ + union + { + struct + { + phys_t begin; /* Point de départ du parcours */ + phys_t end; /* Point d'arrivée exclu */ + + elf_loading_cb callback_0; /* Routine de traitement #0 */ + + }; + + struct + { + sym_iter_t *iter; /* Symboles à parcourir */ + + elf_applying_cb callback_1; /* Routine de traitement #1 */ + + }; + + }; + + unsigned int kind; /* Type de traitements */ + bool status; /* Bilan des traitements */ activity_id_t id; /* Identifiant pour messages */ @@ -136,6 +176,7 @@ static void g_elf_loading_class_init(GElfLoadingClass *klass) static void g_elf_loading_init(GElfLoading *loading) { + loading->status = false; } @@ -180,12 +221,61 @@ static void g_elf_loading_finalize(GElfLoading *loading) /****************************************************************************** * * -* Paramètres : format = = ensemble d'instructions désassemblées. * -* section = prototypes existants à insérer. * -* use_virt = quantité de ces prototypes. * -* first = position du premier élément. * +* Paramètres : format = ensemble d'instructions désassemblées. * +* str_start = début des chaînes de caractères à consulter. * +* first = position du premier élément. * +* begin = point de départ du parcours de liste. * +* end = point d'arrivée exclu du parcours. * +* id = identifiant du message affiché à l'utilisateur. * +* callback = routine de traitements particuliers. * +* * +* Description : Crée une tâche de chargement pour ELF différée. * +* * +* Retour : Tâche créée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GElfLoading *g_elf_loading_new_for_symbols(GElfFormat *format, phys_t str_start, phys_t first, phys_t begin, phys_t end, activity_id_t id, elf_loading_cb callback) +{ + GElfLoading *result; /* Tâche à retourner */ +#ifndef NDEBUG + bool status; /* Etat d'une consultation */ +#endif + + result = g_object_new(G_TYPE_ELF_LOADING, NULL); + + result->format = format; + + result->str_start = str_start; + +#ifndef NDEBUG + status = g_generic_config_get_value(get_main_configuration(), MPK_FORMAT_NO_NAME, &result->use_virt); + assert(status); +#else + g_generic_config_get_value(get_main_configuration(), MPK_FORMAT_NO_NAME, &result->use_virt); +#endif + + result->begin = begin; + result->end = end; + result->callback_0 = callback; + + result->kind = 0; + + result->id = id; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = ensemble d'instructions désassemblées. * * begin = point de départ du parcours de liste. * * end = point d'arrivée exclu du parcours. * +* relocs = table des relocalisations à remplir. * * id = identifiant du message affiché à l'utilisateur. * * callback = routine de traitements particuliers. * * * @@ -197,7 +287,7 @@ static void g_elf_loading_finalize(GElfLoading *loading) * * ******************************************************************************/ -GElfLoading *g_elf_loading_new(GElfFormat *format, const elf_shdr *section, bool use_virt, phys_t first, phys_t begin, phys_t end, activity_id_t id, elf_loading_cb callback) +GElfLoading *g_elf_loading_new_for_relocations(GElfFormat *format, phys_t begin, phys_t end, elf_rel *relocs, activity_id_t id, elf_loading_cb callback) { GElfLoading *result; /* Tâche à retourner */ @@ -205,17 +295,15 @@ GElfLoading *g_elf_loading_new(GElfFormat *format, const elf_shdr *section, bool result->format = format; - result->section = section; - result->use_virt = use_virt; + result->str_start = VMPA_NO_PHYSICAL; - result->has_strtab = find_elf_section_by_index(format, - ELF_SHDR(format, *section, sh_link), - &result->strtab); + result->relocs_to_fill = relocs; - result->callback = callback; - result->first = first; result->begin = begin; result->end = end; + result->callback_0 = callback; + + result->kind = 0; result->id = id; @@ -226,8 +314,55 @@ GElfLoading *g_elf_loading_new(GElfFormat *format, const elf_shdr *section, bool /****************************************************************************** * * -* Paramètres : study = étude de routines à mener. * -* status = barre de statut à tenir informée. * +* Paramètres : format = ensemble d'instructions désassemblées. * +* iter = itérateur sur les symboles à parcourir. * +* str_start = début de la zone contenant les descriptions. * +* relocs = table des relocalisations chargées. * +* rel_count = nombre de ces éléments à interpréter. * +* sym_start = localisation du début de la zone de symboles. * +* sym_count = nombre de descriptions de symbole attendues. * +* id = identifiant du message affiché à l'utilisateur. * +* callback = routine de traitements particuliers. * +* * +* Description : Crée une tâche de chargement pour ELF différée. * +* * +* Retour : Tâche créée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GElfLoading *g_elf_loading_new_for_applying(GElfFormat *format, sym_iter_t *iter, phys_t str_start, elf_rel *relocs, size_t rel_count, phys_t sym_start, uint32_t sym_count, activity_id_t id, elf_applying_cb callback) +{ + GElfLoading *result; /* Tâche à retourner */ + + result = g_object_new(G_TYPE_ELF_LOADING, NULL); + + result->format = format; + + result->str_start = str_start; + + result->relocs = relocs; + result->rel_count = rel_count; + result->sym_start = sym_start; + result->sym_count = sym_count; + + result->iter = iter; + result->callback_1 = callback; + + result->kind = 1; + + result->id = id; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : loading = traitements différés à mener. * +* status = barre de statut à tenir informée. * * * * Description : Assure le chargement pour un format ELF en différé. * * * @@ -239,22 +374,66 @@ GElfLoading *g_elf_loading_new(GElfFormat *format, const elf_shdr *section, bool static void g_elf_loading_process(GElfLoading *loading, GtkStatusStack *status) { + GElfFormat *format; /* Format plus accessible */ phys_t iter; /* Boucle de parcours */ phys_t old; /* Sauvegarde du point d'avant */ bool ret; /* Bilan d'un appel */ + size_t processed; /* Nombre de symboles traités */ + GBinSymbol *symbol; /* Symbole analysé */ + + format = loading->format; - for (iter = loading->begin; iter < loading->end; ) + switch (loading->kind) { - old = iter; - ret = loading->callback(loading, loading->format, &iter); + case 0: - if (!ret) - { - log_variadic_message(LMT_ERROR, _("Error while loading ELF data @ 0x%08x!"), old); + for (iter = loading->begin; iter < loading->end; ) + { + old = iter; + ret = loading->callback_0(loading, format, &iter); + + if (!ret) + { + log_variadic_message(LMT_ERROR, _("Error while loading ELF data @ 0x%08x!"), old); + break; + } + + gtk_status_stack_update_activity_value(status, loading->id, 1); + + } + + loading->status = (iter == loading->end); break; - } - gtk_status_stack_update_activity_value(status, loading->id, 1); + case 1: + + ret = true; + + processed = 0; + + for (symbol = get_symbol_iterator_next(loading->iter); + symbol != NULL && ret; + symbol = get_symbol_iterator_next(loading->iter)) + { + ret = loading->callback_1(loading, format, symbol); + + if (!ret) + { + log_variadic_message(LMT_ERROR, _("Error while applying ELF relocation %zu!"), processed); + break; + } + + processed++; + + gtk_status_stack_update_activity_value(status, loading->id, 1); + + if (processed == loading->rel_count) + break; + + } + + loading->status = (processed == loading->rel_count); + break; } @@ -263,14 +442,95 @@ static void g_elf_loading_process(GElfLoading *loading, GtkStatusStack *status) /****************************************************************************** * * -* Paramètres : loading = chargement pour ELF à mener. * -* section = prototypes existants à insérer. [OUT] * -* use_virt = quantité de ces prototypes. [OUT] * -* strtab = informations quant à la table des chaînes. [OUT]* -* has_strtab = validité du champ précédemment renseigné. [OUT] * -* first = position du premier élément. [OUT] * +* Paramètres : loading = procédure de chargements écoulés à consulter. * +* * +* Description : Fournit le bilan des traitements différés. * +* * +* Retour : true si tout s'est bien déroulé. * * * -* Description : Fournit les infos utiles au chargement de symbols internes. * +* Remarques : - * +* * +******************************************************************************/ + +bool g_elf_loading_get_status(const GElfLoading *loading) +{ + return loading->status; + +} + + +/****************************************************************************** +* * +* Paramètres : loading = chargement pour ELF à mener. * +* name = indice de la désignation du symbole concerné. * +* virt = adresse virtuelle du symbole en mémoire. * +* prefix = préfixe d'une désignation par défaut. * +* alt = zone de constitution d'un nom alternatif. [OUT] * +* addr = localisation compléte à associer au symbole. [OUT] * +* * +* Description : Construit la désignation adaptée à un symbole. * +* * +* Retour : Pointeur vers une étiquette constituée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_elf_loading_build_name(const GElfLoading *loading, uint32_t name, virt_t virt, const char *prefix, char *alt, vmpa2t *addr) +{ + const char *result; /* Désignation à retourner */ + GElfFormat *format; /* Format plus accessible */ + vmpa2t pos; /* Position de lecture */ + const GBinContent *content; /* Contenu binaire à lire */ + size_t plen; /* Taille du préfixe */ + + result = NULL; + + format = loading->format; + + if (g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), virt, addr)) + { + init_vmpa(&pos, loading->str_start + name, VMPA_NO_VIRTUAL); + + content = G_BIN_FORMAT(format)->content; + + result = (const char *)g_binary_content_get_raw_access(content, &pos, 1); + + if (result != NULL && result[0] == '\0') + result = NULL; + + if (result == NULL) + { + /** + * Charge à l'appelant de s'assurer que la zone tampon est assez grande ! + */ + + strcpy(alt, prefix); + plen = strlen(prefix); + + if (loading->use_virt) + vmpa2_virt_to_string(addr, MDS_UNDEFINED, alt + plen, NULL); + else + vmpa2_phys_to_string(addr, MDS_UNDEFINED, alt + plen, NULL); + + result = alt; + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : loading = chargement pour ELF à compléter. * +* iter = tête de lecture courante. * +* reloc = relocalisation à conserver en mémoire. * +* * +* Description : Intègre dans la liste adaptée une relocalisation chargée. * * * * Retour : - * * * @@ -278,14 +538,121 @@ static void g_elf_loading_process(GElfLoading *loading, GtkStatusStack *status) * * ******************************************************************************/ -void g_elf_loading_get_internal_info(GElfLoading *loading, const elf_shdr **section, bool *use_virt, const elf_shdr **strtab, bool *has_strtab, phys_t *first) +void g_elf_loading_store_relocation(const GElfLoading *loading, const phys_t *iter, const elf_rel *reloc) +{ + GElfFormat *format; /* Format plus accessible */ + size_t index; /* Indice de l'élément */ + + format = loading->format; + + index = (*iter - loading->begin); + + assert(index % sizeof(ELF_SIZEOF_REL(format)) == 0); + + index /= sizeof(ELF_SIZEOF_REL(format)); + + /* La tête de lecture a consommé un élément ! */ + index--; + + memcpy(&loading->relocs_to_fill[index], reloc, sizeof(elf_rel)); + +} + + +/****************************************************************************** +* * +* Paramètres : loading = chargement pour ELF à consulter. * +* offset = décalage à retrouver idéalement. * +* reloc = informations quant à la relocalisation. [OUT] * +* * +* Description : Recherche une relocalisation par son décalage. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_elf_loading_search_for_relocation(const GElfLoading *loading, const uint64_t *offset, elf_rel **reloc) { - *section = loading->section; - *use_virt = loading->use_virt; + bool result; /* Validité à faire remonter */ + void *found; /* Eventuel élément trouvé */ + + int compare_relocations(const uint64_t *off, const elf_rel *rel) + { + return sort_uint64_t(*off, ELF_REL(loading->format, *rel, r_offset)); + } - *strtab = &loading->strtab; - *has_strtab = loading->has_strtab; + found = bsearch(offset, loading->relocs, loading->rel_count, + sizeof(elf_rel), (__compar_fn_t)compare_relocations); - *first = loading->first; + result = (found != NULL); + + if (result) + *reloc = (elf_rel *)found; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : loading = chargement pour ELF à poursuivre. * +* index = indice du symbole concerné. * +* * +* Description : Construit la désignation adaptée à un symbole importé. * +* * +* Retour : Nouvelle étiquette constituée ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *g_elf_loading_build_plt_name(const GElfLoading *loading, uint64_t index) +{ + char *result; /* Désignation à retourner */ + GElfFormat *format; /* Format plus accessible */ + phys_t offset; /* Tête de lecture brute */ + elf_sym sym; /* Symbole aux infos visées */ + bool status; /* Bilan de récupération */ + uint32_t name; /* Indice du nom du symbole */ + vmpa2t pos; /* Position de lecture */ + const GBinContent *content; /* Contenu binaire à lire */ + const char *prefix; /* Première partie de nom */ + + format = loading->format; + + offset = loading->sym_start + index * ELF_SIZEOF_SYM(format); + + status = read_elf_symbol(format, &offset, &sym); + + if (!status) + result = NULL; + + else + { + name = ELF_SYM(format, sym, st_name); + + offset = loading->str_start + name; + + init_vmpa(&pos, offset, VMPA_NO_VIRTUAL); + + content = G_BIN_FORMAT(format)->content; + + prefix = (const char *)g_binary_content_get_raw_access(content, &pos, 1); + + if (prefix != NULL && prefix[0] == '\0') + result = NULL; + + else + { + result = strdup(prefix); + result = stradd(result, "@plt"); + } + + } + + return result; } diff --git a/plugins/elf/loading.h b/plugins/elf/loading.h index 03ac184..79ea67f 100644 --- a/plugins/elf/loading.h +++ b/plugins/elf/loading.h @@ -25,6 +25,7 @@ #define _PLUGINS_ELF_LOADING_H +#include #include @@ -32,12 +33,12 @@ -#define G_TYPE_ELF_LOADING g_elf_loading_get_type() -#define G_ELF_LOADING(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_elf_loading_get_type(), GElfLoading)) -#define G_IS_ELF_LOADING(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_elf_loading_get_type())) -#define G_ELF_LOADING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ELF_LOADING, GElfLoadingClass)) -#define G_IS_ELF_LOADING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ELF_LOADING)) -#define G_ELF_LOADING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ELF_LOADING, GElfLoadingClass)) +#define G_TYPE_ELF_LOADING g_elf_loading_get_type() +#define G_ELF_LOADING(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ELF_LOADING, GElfLoading)) +#define G_IS_ELF_LOADING(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ELF_LOADING)) +#define G_ELF_LOADING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ELF_LOADING, GElfLoadingClass)) +#define G_IS_ELF_LOADING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ELF_LOADING)) +#define G_ELF_LOADING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ELF_LOADING, GElfLoadingClass)) /* Fraction de loading à limiter (instance) */ @@ -50,15 +51,36 @@ typedef struct _GElfLoadingClass GElfLoadingClass; /* Assure un chargement pour ELF en différé. */ typedef bool (* elf_loading_cb) (GElfLoading *, GElfFormat *, phys_t *); +/* Assure l'intégration d'un symbole issu des relocalisations. */ +typedef bool (* elf_applying_cb) (GElfLoading *, GElfFormat *, GBinSymbol *); + /* Indique le type défini pour les tâches de chargements pour format ELF. */ GType g_elf_loading_get_type(void); /* Crée une tâche de chargement pour ELF différée. */ -GElfLoading *g_elf_loading_new(GElfFormat *, const elf_shdr *, bool, phys_t, phys_t, phys_t, activity_id_t, elf_loading_cb); +GElfLoading *g_elf_loading_new_for_symbols(GElfFormat *, phys_t, phys_t, phys_t, phys_t, activity_id_t, elf_loading_cb); + +/* Crée une tâche de chargement pour ELF différée. */ +GElfLoading *g_elf_loading_new_for_relocations(GElfFormat *, phys_t, phys_t, elf_rel *, activity_id_t, elf_loading_cb); + +/* Crée une tâche de chargement pour ELF différée. */ +GElfLoading *g_elf_loading_new_for_applying(GElfFormat *, sym_iter_t *, phys_t, elf_rel *, size_t, phys_t, uint32_t, activity_id_t, elf_applying_cb); + +/* Fournit le bilan des traitements différés. */ +bool g_elf_loading_get_status(const GElfLoading *); + +/* Construit la désignation adaptée à un symbole. */ +const char *g_elf_loading_build_name(const GElfLoading *, uint32_t, virt_t, const char *, char *, vmpa2t *); + +/* Intègre dans la liste adaptée une relocalisation chargée. */ +void g_elf_loading_store_relocation(const GElfLoading *, const phys_t *, const elf_rel *); + +/* Recherche une relocalisation par son décalage. */ +bool g_elf_loading_search_for_relocation(const GElfLoading *, const uint64_t *, elf_rel **); -/* Fournit les infos utiles au chargement de symbols internes. */ -void g_elf_loading_get_internal_info(GElfLoading *, const elf_shdr **, bool *, const elf_shdr **, bool *, phys_t *); +/* Construit la désignation adaptée à un symbole importé. */ +char *g_elf_loading_build_plt_name(const GElfLoading *, uint64_t); diff --git a/plugins/elf/section.c b/plugins/elf/section.c index 556c0ed..5e42b0a 100644 --- a/plugins/elf/section.c +++ b/plugins/elf/section.c @@ -195,8 +195,11 @@ bool find_elf_sections_by_type(const GElfFormat *format, uint32_t type, elf_shdr void get_elf_section_content(const GElfFormat *format, const elf_shdr *section, phys_t *offset, phys_t *size, virt_t *addr) { - *offset = ELF_SHDR(format, *section, sh_offset); - *size = ELF_SHDR(format, *section, sh_size); + if (offset != NULL) + *offset = ELF_SHDR(format, *section, sh_offset); + + if (size != NULL) + *size = ELF_SHDR(format, *section, sh_size); if (addr != NULL) *addr = ELF_SHDR(format, *section, sh_addr); diff --git a/plugins/elf/symbols.c b/plugins/elf/symbols.c index 7bf68f5..4854d7b 100644 --- a/plugins/elf/symbols.c +++ b/plugins/elf/symbols.c @@ -26,15 +26,17 @@ #include #include +#include #include #include #include #include +#include #include #include -#include +#include #include @@ -47,11 +49,7 @@ - - - - - +/* ------------------------- CHARGEMENT GLOBAL DES SYMBOLES ------------------------- */ /* Enregistre un point d'entrée au sein d'un binaire ELF. */ @@ -60,44 +58,59 @@ static void register_elf_entry_point(GElfFormat *, virt_t, phys_t, GBinRoutine * /* Enumère tous les points d'entrée principaux d'un binaire ELF. */ static bool load_all_elf_basic_entry_points(GElfFormat *); +/* Assure le chargement des symboles internes ELF en différé. */ +static bool do_elf_symbol_loading(GElfLoading *, GElfFormat *, bool, phys_t *, GBinSymbol **); +/* Charge tous les symboles possibles. */ +static void add_all_elf_symbols(GElfFormat *, phys_t, size_t, phys_t, GWorkQueue *, wgroup_id_t, elf_loading_cb, GtkStatusStack *, activity_id_t); +/* --------------------------- DETAIL DES SYMBOLES LOCAUX --------------------------- */ - - -/* -------------------------- DETAIL DES SYMBOLES INTERNES -------------------------- */ - - -/* Assure le chargement des symboles internes ELF en différé. */ -static bool do_elf_internal_symbol_loading(GElfLoading *, GElfFormat *, phys_t *); +/* Assure le chargement des symboles locaux ELF en différé. */ +static bool do_elf_local_symbol_loading(GElfLoading *, GElfFormat *, phys_t *); /* Charge tous les symboles internes possibles. */ -static bool load_elf_internal_symbols(GElfFormat *, wgroup_id_t, GtkStatusStack *); +static bool load_elf_local_symbols(GElfFormat *, wgroup_id_t, GtkStatusStack *); + +/* --------------------------- DETAIL DE SYMBOLES GLOBAUX --------------------------- */ -/* -------------------------- DETAIL DES SYMBOLES EXTERNES -------------------------- */ +/* Assure le chargement des symboles globaux ELF en différé. */ +static bool do_elf_global_symbol_loading(GElfLoading *, GElfFormat *, phys_t *); -/* Retrouve un élément donné dans la section dynamique. */ -static bool find_elf_dynamic_item(const GElfFormat *, const elf_shdr *, int32_t, elf_dyn *); +/* Dénombre le nombre de symboles en lien avec l'extérieur. */ +static bool count_elf_global_symbols(GElfFormat *, GExeFormat *, uint32_t *); /* Charge tous les éléments dynamiques externes possibles. */ -static bool load_elf_external_symbols(GElfFormat *, const elf_shdr *); +static bool load_elf_global_symbols(GElfFormat *, wgroup_id_t, GtkStatusStack *); +/* ----------------------- PRISE EN COMPTE DE RELOCALISATIONS ----------------------- */ +/* Assure le chargement des relocalisations ELF en différé. */ +static bool do_elf_relocation_loading(GElfLoading *, GElfFormat *, phys_t *); +/* Charge en mémoire toutes les relocalisations présentes. */ +static bool load_elf_relocations(GElfFormat *, const elf_phdr *, elf_rel **, size_t *, GtkStatusStack *); +/* Assure l'intégration d'un symbole issu des relocalisations. */ +static bool do_elf_relocation_renaming(GElfLoading *, GElfFormat *, GBinSymbol *); +/* Applique les étiquettes issues des relocalisations. */ +static bool apply_elf_relocations(GElfFormat *, elf_rel *, size_t, sym_iter_t *, GtkStatusStack *); +/* ---------------------------------------------------------------------------------- */ +/* CHARGEMENT GLOBAL DES SYMBOLES */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** @@ -118,46 +131,31 @@ bool load_elf_symbols(GElfFormat *format, GtkStatusStack *status) bool result; /* Bilan à retourner */ wgroup_id_t gid; /* Identifiant pour les tâches */ - elf_shdr *sections; /* Groupe de sections trouvées */ - size_t count; /* Quantité de données */ - result = true; gid = g_work_queue_define_work_group(get_work_queue()); /* Symboles internes */ - result &= load_elf_internal_symbols(format, gid, status); - - - + result &= load_elf_local_symbols(format, gid, status); - /* Symboles externes */ + /* Symboles importés et/ou exportés */ - if (find_elf_sections_by_type(format, SHT_DYNAMIC, §ions, &count)) + if (find_elf_dynamic_program_header(format, (elf_phdr []) { 0 })) { log_variadic_message(LMT_INFO, _("Binary is dynamically linked")); - result &= load_elf_external_symbols(format, §ions[0]); - - free(sections); + result &= load_elf_global_symbols(format, gid, status); } else log_variadic_message(LMT_INFO, _("Binary is statically linked")); - - - /* Symboles d'entrée, si encore besoin */ /** * Le tri en préalable */ - - - - result &= load_all_elf_basic_entry_points(format); return result; @@ -165,9 +163,6 @@ bool load_elf_symbols(GElfFormat *format, GtkStatusStack *status) } - - - /****************************************************************************** * * * Paramètres : format = description de l'exécutable à compléter. * @@ -429,68 +424,293 @@ static bool load_all_elf_basic_entry_points(GElfFormat *format) } +/****************************************************************************** +* * +* Paramètres : loading = chargement de symboles en cours. * +* format = format ELF à compléter. * +* local = s'apprête-t-on à constuire un symbole interne ? * +* iter = tête de lecture évoluant avec le temps. [OUT] * +* new = éventuel renseignement du nouveau symbole. [OUT] * +* * +* Description : Assure le chargement des symboles internes ELF en différé. * +* * +* Retour : Bilan de l'exécution, utile pour la poursuite du traitement. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool do_elf_symbol_loading(GElfLoading *loading, GElfFormat *format, bool local, phys_t *iter, GBinSymbol **new) +{ + bool result; /* Bilan à retourner */ + elf_sym sym; /* Symbole aux infos visées */ + virt_t virt; /* Adresse virtuelle */ + SymbolStatus status; /* Visibilité du symbole */ + GBinFormat *base; /* Version basique du format */ + uint32_t index; /* Indice du nom du symbole */ + const char *name; /* Nom du symbole trouvé */ + GBinSymbol *symbol; /* Nouveau symbole construit */ + char alt_name[6 + VMPA_MAX_LEN]; /* Nom abstrait de substitution*/ + virt_t original_virt; /* Adresse virtuelle retenue */ + vmpa2t addr; /* Localisation d'un symbole */ + mrange_t range; /* Couverture mémoire associée */ + GBinRoutine *routine; /* Nouvelle routine trouvée */ + + if (new != NULL) + *new = NULL; + + result = read_elf_symbol(format, iter, &sym); + if (!result) goto desl_done; + + /** + * Si l'adresse virtuelle est nulle, on ne peut ratacher le symbole à aucune position... + * + * On ne réalise donc aucune opération ici, quitte à laisser une seconde passe + * s'occuper des symboles importés par exemple. + */ + + virt = ELF_SYM(format, sym, st_value); + if (virt == 0) goto desl_done; + + /** + * En ce qui concerne la nature de la visibilité, on distingue les deux situations suivantes : + * - zone DYNSYM : uniquement les importations / exportations. + * - zone SYMTAB : tous les symboles. + * + * La première zone doit donc être traitée en amont, et la seconde complète les traitements + * avec à priori uniquement des symboles locaux. + */ + + if (local) + status = SSS_INTERNAL; + + else + status = ELF_SYM(format, sym, st_shndx) == 0 ? SSS_IMPORTED : SSS_EXPORTED; + + /* Traitements particuliers */ + + base = G_BIN_FORMAT(format); + + index = ELF_SYM(format, sym, st_name); + switch (ELF_ST_TYPE(format, sym)) + { + case STT_OBJECT: + + name = g_elf_loading_build_name(loading, index, virt, "obj_", alt_name, &addr); + if (name == NULL) break; + + init_mrange(&range, &addr, ELF_SYM(format, sym, st_size)); + + symbol = g_binary_symbol_new(&range, STP_OBJECT); + + g_binary_symbol_set_alt_label(symbol, name); + + break; + + case STT_FUNC: + + original_virt = virt; + + /* Ajustement de la position */ + + if (ELF_HDR(format, format->header, e_machine) == EM_ARM) + virt &= ~0x1; + + /* Constitution d'une routine */ + + name = g_elf_loading_build_name(loading, index, virt, "func_", alt_name, &addr); + if (name == NULL) break; + + routine = try_to_demangle_routine(name); + symbol = G_BIN_SYMBOL(routine); + + init_mrange(&range, &addr, ELF_SYM(format, sym, st_size)); + + g_binary_symbol_set_range(symbol, &range); + + /* Comptabilisation pour le désassemblage brut */ + + g_binary_format_register_code_point(base, original_virt, false); + + break; + + default: + symbol = NULL; + break; + + } + + if (symbol != NULL) + { + g_binary_symbol_set_status(symbol, status); + + if (new != NULL) + { + g_object_ref(G_OBJECT(symbol)); + *new = symbol; + } + + g_binary_format_add_symbol(base, symbol); + } + desl_done: + return result; +} /****************************************************************************** * * -* Paramètres : format = description de l'exécutable à consulter. * -* sym = section comprenant les symboles à venir lire. * -* index = indice de l'entrée à venir lire. * -* symbol = ensemble d'informations lues. [OUT] * +* Paramètres : format = description de l'exécutable à compléter. * +* sym_start = localisation du début de la zone de symboles. * +* count = nombre de descriptions de symbole attendues. * +* str_start = début de la zone contenant les descriptions. * +* wq = espace de travail dédié. * +* gid = groupe de travail impliqué. * +* callback = routine de traitements particuliers. * +* status = barre de statut à tenir informée. * +* msg = identifiant du message de progression. * * * -* Description : Récupère la définition complète d'un symbole donné. * +* Description : Charge tous les symboles possibles. * * * -* Retour : Bilan de l'opération. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -bool get_elf_symbol_by_index(GElfFormat *format, const elf_shdr *sym, off_t index, elf_sym *symbol) +static void add_all_elf_symbols(GElfFormat *format, phys_t sym_start, size_t count, phys_t str_start, GWorkQueue *wq, wgroup_id_t gid, elf_loading_cb callback, GtkStatusStack *status, activity_id_t msg) { - phys_t sym_start; /* Début de section */ - phys_t sym_size; /* Taille de section */ - phys_t offset; /* Emplacement à venir lire */ + phys_t sym_size; /* Taille de chaque symbole lu */ + guint runs_count; /* Qté d'exécutions parallèles */ + phys_t run_size; /* Volume réparti par exécution*/ + guint i; /* Boucle de parcours */ + phys_t begin; /* Début de zone de traitement */ + phys_t end; /* Fin d'un zone de traitement */ + GElfLoading *loading; /* Tâche de chargement à lancer*/ + + sym_size = ELF_SIZEOF_SYM(format); + + runs_count = g_get_num_processors(); - get_elf_section_content(format, sym, &sym_start, &sym_size, NULL); + run_size = count / runs_count; - offset = sym_start + index * ELF_SIZEOF_SYM(format); - if ((offset + ELF_SIZEOF_SYM(format)) > (sym_start + sym_size)) return NULL; + gtk_status_stack_extend_activity(status, msg, count); - return read_elf_symbol(format, &offset, symbol); + for (i = 0; i < runs_count; i++) + { + begin = sym_start + i * run_size * sym_size; + + if ((i + 1) == runs_count) + end = sym_start + count * sym_size; + else + end = begin + run_size * sym_size; + + loading = g_elf_loading_new_for_symbols(format, str_start, sym_start, begin, end, msg, callback); + + g_work_queue_schedule_work(wq, G_DELAYED_WORK(loading), gid); + + } } + +/* ---------------------------------------------------------------------------------- */ +/* DETAIL DES SYMBOLES LOCAUX */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * -* Paramètres : format = description de l'exécutable à consulter. * -* sym = section comprenant les symboles à venir lire. * -* str = section de chaînes de caractères pour les noms. * -* index = indice de l'entrée à venir lire. * +* Paramètres : loading = chargement de symboles externes en cours. * +* format = format ELF à compléter. * +* iter = tête de lecture évoluant avec le temps. [OUT] * * * -* Description : Récupère la désignation d'un symbole donné. * +* Description : Assure le chargement des symboles locaux ELF en différé. * * * -* Retour : Nom du symbole trouvé, ou NULL si erreur ou non adapté. * +* Retour : Bilan de l'exécution, utile pour la poursuite du traitement. * * * * Remarques : - * * * ******************************************************************************/ -const char *get_elf_symbol_name(GElfFormat *format, const elf_shdr *sym, const elf_shdr *str, off_t index) +static bool do_elf_local_symbol_loading(GElfLoading *loading, GElfFormat *format, phys_t *iter) { - const char *result; /* Résultat à retourner */ - elf_sym symbol; /* Symbole aux infos visées */ + bool result; /* Bilan à retourner */ + + result = do_elf_symbol_loading(loading, format, true, iter, NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à compléter. * +* gid = groupe de travail impliqué. * +* status = barre de statut à tenir informée. * +* * +* Description : Charge tous les symboles internes possibles. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool load_elf_local_symbols(GElfFormat *format, wgroup_id_t gid, GtkStatusStack *status) +{ + bool result; /* Bilan à retourner */ + activity_id_t msg; /* Message de progression */ + GWorkQueue *queue; /* Gestionnaire de différés */ + size_t size; /* Taille de chaque symbole lu */ + elf_shdr *symtabs; /* Groupe de sections trouvées */ + size_t count; /* Quantité de données */ + size_t i; /* Boucle de parcours */ + phys_t sym_start; /* Début de la zone à traiter */ + phys_t sym_size; /* Taille de cette même zone */ + size_t sym_count; /* Nombre de symboles déduits */ + elf_shdr strtab; /* Section dédiées aux chaînes */ + phys_t str_start; /* Début de cette section */ + + result = true; + + msg = gtk_status_stack_add_activity(status, _("Loading local symbols..."), 0); + + queue = get_work_queue(); + + size = ELF_SIZEOF_SYM(format); + + if (find_elf_sections_by_type(format, SHT_SYMTAB, &symtabs, &count)) + for (i = 0; i < count; i++) + { + get_elf_section_content(format, &symtabs[i], &sym_start, &sym_size, NULL); + + if (sym_size % size != 0) + continue; + + sym_count = sym_size / size; - result = NULL; + if (!find_elf_section_by_index(format, ELF_SHDR(format, symtabs[i], sh_link), &strtab)) + continue; - if (get_elf_symbol_by_index(format, sym, index, &symbol)) - result = extract_name_from_elf_string_section(format, str, ELF_SYM(format, symbol, st_name)); + get_elf_section_content(format, &strtab, &str_start, NULL, NULL); + + add_all_elf_symbols(format, sym_start, sym_count, str_start, + queue, gid, do_elf_local_symbol_loading, status, msg); + + } + + g_work_queue_wait_for_completion(queue, gid); + + gtk_status_stack_remove_activity(status, msg); + + if (symtabs != NULL) free(symtabs); return result; @@ -499,181 +719,193 @@ const char *get_elf_symbol_name(GElfFormat *format, const elf_shdr *sym, const e /* ---------------------------------------------------------------------------------- */ -/* DETAIL DES SYMBOLES INTERNES */ +/* DETAIL DE SYMBOLES GLOBAUX */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : loading = chargement de symboles internes en cours. * +* Paramètres : loading = chargement de symboles externes en cours. * * format = format ELF à compléter. * * iter = tête de lecture évoluant avec le temps. [OUT] * * * -* Description : Assure le chargement des symboles internes ELF en différé. * +* Description : Assure le chargement des symboles globaux ELF en différé. * * * -* Retour : - * +* Retour : Bilan de l'exécution, utile pour la poursuite du traitement. * * * * Remarques : - * * * ******************************************************************************/ -static bool do_elf_internal_symbol_loading(GElfLoading *loading, GElfFormat *format, phys_t *iter) +static bool do_elf_global_symbol_loading(GElfLoading *loading, GElfFormat *format, phys_t *iter) { bool result; /* Bilan à retourner */ - elf_sym sym; /* Symbole aux infos visées */ - SymbolStatus status; /* Visibilité du symbole */ - vmpa2t addr; /* Localisation d'un symbole */ - virt_t virt; /* Adresse virtuelle */ - const elf_shdr *section; /* Groupe de sections trouvées */ - bool use_virt; /* Choix de construction de nom*/ - const elf_shdr *strtab; /* Section .strtab trouvée */ - bool has_strtab; /* Présence de cette section */ - phys_t first; /* Position du premier élément */ - const char *name; /* Nom du symbole trouvé */ - GBinFormat *base; /* Version basique du format */ - GBinSymbol *symbol; /* Nouveau symbole construit */ - char alt_name[6 + VMPA_MAX_LEN]; /* Nom abstrait de substitution*/ - virt_t final_virt; /* Adresse virtuelle retenue */ - mrange_t range; /* Couverture mémoire associée */ - GBinRoutine *routine; /* Nouvelle routine trouvée */ - - result = read_elf_symbol(format, iter, &sym); - if (!result) goto geslp_done; + GBinSymbol *symbol; /* Nouveau symbole en place */ - /* Nature de la visibilité et adresse associée */ + result = do_elf_symbol_loading(loading, format, false, iter, &symbol); - if (ELF_SYM(format, sym, st_shndx) == 0) - { - status = SSS_IMPORTED; - init_vmpa(&addr, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL); - - } + return result; - else - { - status = SSS_EXPORTED; +} - virt = ELF_SYM(format, sym, st_value); - if (virt == 0) goto geslp_done; - } +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à consulter. * +* exec = autre vision de ce format. * +* count = nombre de symboles présents. [OUT] * +* * +* Description : Dénombre le nombre de symboles en lien avec l'extérieur. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ - /* Première ébauche de nom */ +static bool count_elf_global_symbols(GElfFormat *format, GExeFormat *exec, uint32_t *count) +{ + bool result; /* Bilan à retourner */ + elf_dyn hash; /* Table de type DT_HASH */ + bool found; /* Détection validée */ + vmpa2t addr; /* Position de départ brute */ - g_elf_loading_get_internal_info(loading, §ion, &use_virt, &strtab, &has_strtab, &first); + result = false; - if (!has_strtab) - name = NULL; + /** + * Cf. l'astuce indiquée par : + * + * - http://www.gabriel.urdhr.fr/2015/09/28/elf-file-format/#symbol-tables + * - http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#hash + * + */ - else - name = get_elf_symbol_name(format, section, strtab, - ((*iter - first) / ELF_SIZEOF_SYM(format)) - 1); + found = find_elf_dynamic_item(format, DT_HASH, &hash); + if (!found) goto cegs_exit; - /* Traitements particuliers */ + exec = G_EXE_FORMAT(format); - base = G_BIN_FORMAT(format); + result = g_exe_format_translate_address_into_vmpa(exec, ELF_DYN(format, hash, d_un.d_ptr), &addr); + if (!result) goto cegs_exit; - switch (ELF_ST_TYPE(format, sym)) - { - case STT_OBJECT: + advance_vmpa(&addr, 4); - /* Ajustement de la position */ + result = g_binary_content_read_u32(G_BIN_FORMAT(format)->content, &addr, format->endian, count); + if (!result) goto cegs_exit; - if (!g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), virt, &addr)) - { - symbol = NULL; - break; - } + cegs_exit: - /* Création d'un nom unique ? */ + return result; - if (name == NULL) - { - strcpy(alt_name, "obj_"); +} - if (use_virt) - vmpa2_virt_to_string(&addr, MDS_UNDEFINED, alt_name + 4, NULL); - else - vmpa2_phys_to_string(&addr, MDS_UNDEFINED, alt_name + 4, NULL); - name = alt_name; +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à compléter. * +* gid = groupe de travail impliqué. * +* status = barre de statut à tenir informée. * +* * +* Description : Charge tous les éléments dynamiques externes possibles. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ - } +static bool load_elf_global_symbols(GElfFormat *format, wgroup_id_t gid, GtkStatusStack *status) +{ + bool result; /* Bilan à retourner */ + GExeFormat *exec; /* Autre vision du format */ + elf_dyn strtab; /* Table de type DT_STRTAB */ + phys_t str_start; /* Début de zone des chaînes */ + elf_dyn symtab; /* Table de type DT_SYMTAB */ + phys_t sym_start; /* Début de zone des symboles */ + uint32_t count; /* Nombre de symboles présents */ + activity_id_t msg; /* Message de progression */ + GWorkQueue *queue; /* Gestionnaire de différés */ + result = true; - /* TODO */ + /** + * Les spécifications ne sont pas très claires sur le nombre de tables + * possible... On y parle de LA table des symboles, ce qui laisse penser + * qu'il ne peut y en avoir qu'une. + */ - symbol = NULL; + exec = G_EXE_FORMAT(format); + /* Récupération du début des chaînes de description */ - break; + result = find_elf_dynamic_item(format, DT_STRTAB, &strtab); + if (!result) goto lees_exit; - case STT_FUNC: + result = g_exe_format_translate_address_into_offset(exec, ELF_DYN(format, strtab, d_un.d_ptr), &str_start); + if (!result) goto lees_exit; - /* Ajustement de la position */ + /* Récupération du début des définitions de symboles */ - if (status == SSS_IMPORTED) - init_mrange(&range, &addr, 0); + result = find_elf_dynamic_item(format, DT_SYMTAB, &symtab); + if (!result) goto lees_exit; - else - { - if (ELF_HDR(format, format->header, e_machine) == EM_ARM) - final_virt = virt & ~0x1; - else - final_virt = virt; + result = g_exe_format_translate_address_into_offset(exec, ELF_DYN(format, symtab, d_un.d_ptr), &sym_start); + if (!result) goto lees_exit; - if (!g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), final_virt, &addr)) - { - symbol = NULL; - break; - } + /* Détermination du nombre d'éléments */ - init_mrange(&range, &addr, ELF_SYM(format, sym, st_size)); + result = count_elf_global_symbols(format, exec, &count); + if (!result) goto lees_exit; - } + /* Chargement des symboles */ - /* Création d'un nom unique ? */ + msg = gtk_status_stack_add_activity(status, _("Loading global symbols..."), 0); - if (name == NULL) - { - strcpy(alt_name, "func_"); + queue = get_work_queue(); - if (use_virt) - vmpa2_virt_to_string(&addr, MDS_UNDEFINED, alt_name + 5, NULL); - else - vmpa2_phys_to_string(&addr, MDS_UNDEFINED, alt_name + 5, NULL); + add_all_elf_symbols(format, sym_start, count, str_start, + queue, gid, do_elf_global_symbol_loading, status, msg); - name = alt_name; + g_work_queue_wait_for_completion(queue, gid); - } + gtk_status_stack_remove_activity(status, msg); - /* Routine */ + lees_exit: - routine = try_to_demangle_routine(name); - symbol = G_BIN_SYMBOL(routine); + return result; - /* Comptabilisation pour le désassemblage brut */ +} - g_binary_format_register_code_point(G_BIN_FORMAT(format), virt, false); - break; - default: - symbol = NULL; - break; +/* ---------------------------------------------------------------------------------- */ +/* PRISE EN COMPTE DE RELOCALISATIONS */ +/* ---------------------------------------------------------------------------------- */ - } - if (symbol != NULL) - { - g_binary_symbol_set_range(symbol, &range); - g_binary_symbol_set_status(symbol, status); +/****************************************************************************** +* * +* Paramètres : loading = chargement de relocalisations en cours. * +* format = format ELF à compléter. * +* iter = tête de lecture évoluant avec le temps. [OUT] * +* * +* Description : Assure le chargement des relocalisations ELF en différé. * +* * +* Retour : Bilan de l'exécution, utile pour la poursuite du traitement. * +* * +* Remarques : - * +* * +******************************************************************************/ - g_binary_format_add_symbol(base, symbol); +static bool do_elf_relocation_loading(GElfLoading *loading, GElfFormat *format, phys_t *iter) +{ + bool result; /* Bilan à retourner */ + elf_rel reloc; /* Relocalisation constituée */ - } + result = read_elf_relocation(format, iter, &reloc); - geslp_done: + if (result) + g_elf_loading_store_relocation(loading, iter, &reloc); return result; @@ -682,11 +914,13 @@ static bool do_elf_internal_symbol_loading(GElfLoading *loading, GElfFormat *for /****************************************************************************** * * -* Paramètres : format = description de l'exécutable à compléter. * -* gid = groupe de travail impliqué. * - status = barre de statut à tenir informée. * +* Paramètres : format = informations chargées à consulter. * +* dynamic = en-tête de programme de type DYNAMIC. * +* relocs = liste des relocalisations triées à charger. [OUT] * +* count = taille de cette liste. [OUT] * +* status = barre de statut à tenir informée. * * * -* Description : Charge tous les symboles internes possibles. * +* Description : Charge en mémoire toutes les relocalisations présentes. * * * * Retour : Bilan de l'opération. * * * @@ -694,101 +928,158 @@ static bool do_elf_internal_symbol_loading(GElfLoading *loading, GElfFormat *for * * ******************************************************************************/ -static bool load_elf_internal_symbols(GElfFormat *format, wgroup_id_t gid, GtkStatusStack *status) +static bool load_elf_relocations(GElfFormat *format, const elf_phdr *dynamic, elf_rel **relocs, size_t *count, GtkStatusStack *status) { bool result; /* Bilan à retourner */ - bool no_name; /* Choix de construction de nom*/ + GExeFormat *exec; /* Autre vision du format */ + elf_dyn jmprel; /* Table des relocalisations */ + vmpa2t start; /* Position de départ brute */ + elf_dyn pltrelsz; /* Taille de table en octets */ + uint64_t length; /* Nombre total des éléments */ + mrange_t shr_range; /* Emplacement des relocs. #1 */ + mrange_t phr_range; /* Emplacement des relocs. #2 */ + phys_t rel_size; /* Taille de chaque élément lu */ + bool ret; /* Bilan d'un appel */ activity_id_t msg; /* Message de progression */ GWorkQueue *queue; /* Gestionnaire de différés */ - elf_shdr *dynsym_sections; /* Groupe de sections trouvées */ - size_t count; /* Quantité de données */ - elf_shdr *symtab_sections; /* Groupe de sections trouvées */ - size_t i; /* Boucle de parcours */ + wgroup_id_t gid; /* Identifiant pour les tâches */ + guint runs_count; /* Qté d'exécutions parallèles */ + phys_t run_size; /* Volume réparti par exécution*/ + GElfLoading **loadings; /* Tâches de chargement */ + guint i; /* Boucle de parcours */ + phys_t begin; /* Début de zone de traitement */ + phys_t end; /* Fin d'un zone de traitement */ result = true; - /* Charge tous les symboles définis dans une section */ - void add_all_symbols_from_section(const elf_shdr *section, bool use_virt, GWorkQueue *wq, activity_id_t id) - { - phys_t start; /* Début de la zone à traiter */ - phys_t size; /* Taille de cette même zone */ - phys_t sym_size; /* Taille de chaque symbole lu */ - guint runs_count; /* Qté d'exécutions parallèles */ - phys_t run_size; /* Volume réparti par exécution*/ - guint i; /* Boucle de parcours */ - phys_t begin; /* Début de zone de traitement */ - phys_t end; /* Fin d'un zone de traitement */ - GElfLoading *loading; /* Tâche de chargement à lancer*/ + *relocs = NULL; + *count = 0; - get_elf_section_content(format, section, &start, &size, NULL); + exec = G_EXE_FORMAT(format); - sym_size = ELF_SIZEOF_SYM(format); + /* Collecte des informations */ - runs_count = g_get_num_processors(); + if (!find_elf_dynamic_item_from_pheader(format, dynamic, DT_JMPREL, &jmprel)) + goto ler_exit; - run_size = size / (sym_size * runs_count); + result = g_exe_format_translate_address_into_vmpa(exec, ELF_DYN(format, jmprel, d_un.d_ptr), &start); - gtk_status_stack_extend_activity(status, id, size / sym_size); + if (!result) + goto ler_exit; - for (i = 0; i < runs_count; i++) - { - begin = start + i * run_size * sym_size; + if (!find_elf_dynamic_item_from_pheader(format, dynamic, DT_PLTRELSZ, &pltrelsz)) + goto ler_exit; - if ((i + 1) == runs_count) - end = start + size; - else - end = begin + run_size * sym_size; + length = ELF_DYN(format, pltrelsz, d_un.d_val); - loading = g_elf_loading_new(format, section, use_virt, start, begin, end, - id, do_elf_internal_symbol_loading); + /* Corrélation des informations */ - g_work_queue_schedule_work(wq, G_DELAYED_WORK(loading), gid); + ret = find_elf_section_range_by_name(format, ".rel.plt", &shr_range); - } + if (ret) + { + init_mrange(&phr_range, &start, length); + + if (cmp_mrange(&phr_range, &shr_range) != 0) + log_simple_message(LMT_BAD_BINARY, + _("The linker PLT and the PLT section differ by their area definition.")); } - if (!g_generic_config_get_value(get_main_configuration(), MPK_FORMAT_NO_NAME, &no_name)) - return false; + /* Détermination du nombre d'éléments */ - msg = gtk_status_stack_add_activity(status, _("Loading internal symbols..."), 0); + rel_size = ELF_SIZEOF_REL(format); + + if (length % rel_size != 0) + { + result = false; + goto ler_exit; + } + + length /= rel_size; + + /* Chargement en mémoire des relocalisations */ + + if (length == 0) + goto ler_exit; + + *relocs = (elf_rel *)malloc(length * sizeof(elf_rel)); + *count = length; + + msg = gtk_status_stack_add_activity(status, _("Loading relocations..."), length); queue = get_work_queue(); + gid = g_work_queue_define_work_group(queue); - if (find_elf_sections_by_type(format, SHT_DYNSYM, &dynsym_sections, &count)) - for (i = 0; i < count; i++) - add_all_symbols_from_section(&dynsym_sections[i], no_name, queue, msg); + runs_count = g_get_num_processors(); - if (find_elf_sections_by_type(format, SHT_SYMTAB, &symtab_sections, &count)) - for (i = 0; i < count; i++) - add_all_symbols_from_section(&symtab_sections[i], no_name, queue, msg); + run_size = length / runs_count; + + loadings = (GElfLoading **)malloc(runs_count * sizeof(GElfLoading *)); + + for (i = 0; i < runs_count; i++) + { + begin = get_phy_addr(&start) + i * run_size * rel_size; + + if ((i + 1) == runs_count) + end = get_phy_addr(&start) + length * rel_size; + else + end = begin + run_size * rel_size; + + loadings[i] = g_elf_loading_new_for_relocations(format, begin, end, + (*relocs) + i * run_size, + msg, do_elf_relocation_loading); + + g_object_ref(G_OBJECT(loadings[i])); + + g_work_queue_schedule_work(queue, G_DELAYED_WORK(loadings[i]), gid); + + } g_work_queue_wait_for_completion(queue, gid); gtk_status_stack_remove_activity(status, msg); - if (dynsym_sections != NULL) free(dynsym_sections); - if (symtab_sections != NULL) free(symtab_sections); + /* Vérifications du bon déroulement */ - return result; + for (i = 0; i < runs_count; i++) + { + result &= g_elf_loading_get_status(loadings[i]); -} + g_object_ref(G_OBJECT(loadings[i])); + } + free(loadings); -/* ---------------------------------------------------------------------------------- */ -/* DETAIL DES SYMBOLES EXTERNES */ -/* ---------------------------------------------------------------------------------- */ + if (!result) + { + free(*relocs); + goto ler_exit; + } + + /* Tri de la liste obtenue */ + + int compare_relocations(const elf_rel *a, const elf_rel *b) + { + return sort_uint64_t(ELF_REL(format, *a, r_offset), ELF_REL(format, *b, r_offset)); + } + + qsort(*relocs, *count, sizeof(elf_rel), (__compar_fn_t)compare_relocations); + + ler_exit: + + return result; + +} /****************************************************************************** * * -* Paramètres : format = informations chargées à consulter. * -* dynamic = section de type SHT_DYNAMIC. * -* type = sorte d'élément recherché. * -* item = élément retrouvé dans la section. [OUT] * +* Paramètres : format = informations chargées à consulter. * +* status = barre de statut à tenir informée. * * * -* Description : Retrouve un élément donné dans la section dynamique. * +* Description : Actualise la désignation des fonctions externes à reloger. * * * * Retour : Bilan de l'opération. * * * @@ -796,55 +1087,71 @@ static bool load_elf_internal_symbols(GElfFormat *format, wgroup_id_t gid, GtkSt * * ******************************************************************************/ -static bool find_elf_dynamic_item(const GElfFormat *format, const elf_shdr *section, int32_t type, elf_dyn *item) +bool refresh_elf_relocations(GElfFormat *format, GtkStatusStack *status) { bool result; /* Bilan à retourner */ - const GBinContent *content; /* Contenu binaire à lire */ - phys_t pos; /* Position de lecture */ - vmpa2t tmp; /* Position écrasable */ - int32_t tag32; /* Type de l'entrée (32 bits) */ - int64_t tag64; /* Type de l'entrée (64 bits) */ + elf_phdr dynamic; /* En-tête de programme DYNAMIC*/ + elf_rel *relocs; /* Relocalisations présentes */ + size_t rel_count; /* Qté de ces relocalisations */ + virt_t plt_virt; /* Adresse de la PLT */ + GExeFormat *exec; /* Autre vision du format */ + vmpa2t plt_addr; /* Localisation complète */ + GBinFormat *base; /* Autre vision du format */ + size_t first; /* Indice du premier symbole */ + sym_iter_t *iter; /* Boucle de parcours */ result = true; - content = G_BIN_FORMAT(format)->content; + if (!find_elf_dynamic_program_header(format, &dynamic)) + goto rer_quick_exit; - for (pos = ELF_SHDR(format, *section, sh_offset); - result; - pos += ELF_SIZEOF_DYN(format)) - { - init_vmpa(&tmp, pos, VMPA_NO_VIRTUAL); + /* Chargement des relocalisations */ - if (format->is_32b) - { - result = g_binary_content_read_s32(content, &tmp, format->endian, &tag32); - if (tag32 == type) break; - } - else - { - result = g_binary_content_read_s64(content, &tmp, format->endian, &tag64); - if (tag64 == type) break; - } + if (!load_elf_relocations(format, &dynamic, &relocs, &rel_count, status)) + goto rer_quick_exit; - } + /* Localisation du code de la PLT */ + + if (!resolve_plt_using_got(format, &plt_virt)) + goto rer_exit; + + exec = G_EXE_FORMAT(format); + + if (!g_exe_format_translate_address_into_vmpa(exec, plt_virt, &plt_addr)) + goto rer_exit; + + /* Parcours des symboles */ + + base = G_BIN_FORMAT(format); + + /** + * Il existe normalement un symbole "plt_entry" créé au chargement des symboles... + */ + + g_binary_format_lock_symbols_rd(base); + + result = g_binary_format_find_symbol_index_at(base, &plt_addr, &first); + + if (result) + iter = create_symbol_iterator(base, first); + + g_binary_format_unlock_symbols_rd(base); if (result) { - init_vmpa(&tmp, pos, VMPA_NO_VIRTUAL); + result = apply_elf_relocations(format, relocs, rel_count, iter, status); - if (format->is_32b) - { - result = g_binary_content_read_s32(content, &tmp, format->endian, &item->dyn32.d_tag); - result &= g_binary_content_read_s32(content, &tmp, format->endian, &item->dyn32.d_un.d_val); - } - else - { - result = g_binary_content_read_s64(content, &tmp, format->endian, &item->dyn64.d_tag); - result &= g_binary_content_read_s64(content, &tmp, format->endian, &item->dyn64.d_un.d_val); - } + delete_symbol_iterator(iter); } + rer_exit: + + if (relocs != NULL) + free(relocs); + + rer_quick_exit: + return result; } @@ -852,52 +1159,171 @@ static bool find_elf_dynamic_item(const GElfFormat *format, const elf_shdr *sect /****************************************************************************** * * -* Paramètres : format = informations chargées à consulter. * -* dynamic = section de type SHT_DYNAMIC. * +* Paramètres : loading = chargement de relocalisations en cours. * +* format = format ELF à compléter. * +* symbol = symbole courant issu de la liste à analyser. * * * -* Description : Charge tous les éléments dynamiques externes possibles. * +* Description : Assure l'intégration d'un symbole issu des relocalisations. * * * -* Retour : Bilan de l'opération. * +* Retour : Bilan de l'exécution, utile pour la poursuite du traitement. * * * * Remarques : - * * * ******************************************************************************/ -static bool load_elf_external_symbols(GElfFormat *format, const elf_shdr *section) +static bool do_elf_relocation_renaming(GElfLoading *loading, GElfFormat *format, GBinSymbol *symbol) { bool result; /* Bilan à retourner */ - elf_dyn item; /* Elément dynamique */ - elf_shdr relxxx; /* Section .rel.xxx trouvée */ - elf_shdr dynsym; /* Section .dynsym trouvée */ - elf_shdr dynstr; /* Section .dynstr trouvée */ + const mrange_t *range; /* Espace occupé par le symbole*/ + SymbolType stype; /* Type de symbole présenté */ + uint64_t offset; /* Décalage à retrouver */ + elf_rel *reloc; /* Infos de relocalisation */ + uint64_t index; /* Indice du symbole concerné */ + char *name; /* Nouvelle désignation */ +#ifndef NDEBUG + const char *label; /* Etiquette courante */ +#endif - result = true; + result = false; + + range = g_binary_symbol_get_range(symbol); + + stype = g_binary_symbol_get_target_type(symbol); - /* Section .rel.plt */ - if (find_elf_dynamic_item(format, section, DT_JMPREL, &item)) + if (stype != STP_ROUTINE && stype != STP_CODE_LABEL && stype != STP_ENTRY_POINT) { - result &= find_elf_section_by_virtual_address(format, ELF_DYN(format, item, d_un.d_ptr), &relxxx); + g_binary_format_add_error(G_BIN_FORMAT(format), BFE_SPECIFICATION, get_mrange_addr(range), + _("The PLT seems to contains more than routines")); - if (result) - result = find_elf_section_by_index(format, ELF_SHDR(format, relxxx, sh_link), &dynsym); + goto derr_exit; - if (result) - result = find_elf_section_by_index(format, ELF_SHDR(format, dynsym, sh_link), &dynstr); + } - if (result) - switch (ELF_HDR(format, format->header, e_machine)) - { - case EM_ARM: - result = load_elf_arm_relocated_symbols(format, &relxxx, &dynsym, &dynstr); - break; + /* Assurance du port du type adapté */ - default: - break; + g_binary_symbol_set_status(symbol, SSS_IMPORTED); - } + /* Détermination de la relocalisation associée */ + + if (ELF_HDR(format, format->header, e_machine) == EM_ARM) + result = retrieve_arm_linkage_offset(format, range, &offset); + else + result = false; + if (!result) goto derr_exit; + + result = g_elf_loading_search_for_relocation(loading, &offset, &reloc); + if (!result) goto derr_exit; + + /* Récupération des données du symbole visé */ + + index = ELF_REL_SYM(format, *reloc); + + name = g_elf_loading_build_plt_name(loading, index); + +#ifndef NDEBUG + + label = g_binary_symbol_get_label(symbol); + + if (strncmp(label, "sub_", 4) != 0 && strncmp(label, "loc_", 4) != 0) + { + if (strncmp(name, label, strlen(label)) != 0) + g_binary_format_add_error(G_BIN_FORMAT(format), BFE_SPECIFICATION, get_mrange_addr(range), + _("Mismatch detected in the ELF symbol address")); } +#endif + + g_binary_symbol_set_alt_label(symbol, name); + + free(name); + + derr_exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = format ELF à compléter. * +* relocs = table des relocalisations chargées. * +* rel_count = nombre de ces éléments à interpréter. * +* iter = itérateur sur les symboles à parcourir. * +* status = barre de statut à tenir informée. * +* * +* Description : Applique les étiquettes issues des relocalisations. * +* * +* Retour : Bilan des traitements. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool apply_elf_relocations(GElfFormat *format, elf_rel *relocs, size_t rel_count, sym_iter_t *iter, GtkStatusStack *status) +{ + bool result; /* Bilan à retourner */ + GExeFormat *exec; /* Autre vision du format */ + elf_dyn strtab; /* Table de type DT_STRTAB */ + phys_t str_start; /* Début de zone des chaînes */ + elf_dyn symtab; /* Table de type DT_SYMTAB */ + phys_t sym_start; /* Début de zone des symboles */ + uint32_t sym_count; /* Nombre de symboles présents */ + activity_id_t msg; /* Message de progression */ + GWorkQueue *queue; /* Gestionnaire de différés */ + wgroup_id_t gid; /* Identifiant pour les tâches */ + GElfLoading *loading; /* Tâche de chargement */ + + exec = G_EXE_FORMAT(format); + + /* Récupération du début des chaînes de description */ + + result = find_elf_dynamic_item(format, DT_STRTAB, &strtab); + if (!result) goto aer_exit; + + result = g_exe_format_translate_address_into_offset(exec, ELF_DYN(format, strtab, d_un.d_ptr), &str_start); + if (!result) goto aer_exit; + + /* Récupération du début des définitions de symboles */ + + result = find_elf_dynamic_item(format, DT_SYMTAB, &symtab); + if (!result) goto aer_exit; + + result = g_exe_format_translate_address_into_offset(exec, ELF_DYN(format, symtab, d_un.d_ptr), &sym_start); + if (!result) goto aer_exit; + + /* Détermination du nombre d'éléments */ + + result = count_elf_global_symbols(format, exec, &sym_count); + if (!result) goto aer_exit; + + /* Mise en application des références externes */ + + msg = gtk_status_stack_add_activity(status, _("Applying relocations..."), rel_count); + + queue = get_work_queue(); + gid = g_work_queue_define_work_group(queue); + + loading = g_elf_loading_new_for_applying(format, iter, str_start, relocs, rel_count, + sym_start, sym_count, msg, do_elf_relocation_renaming); + + g_object_ref(G_OBJECT(loading)); + + g_work_queue_schedule_work(queue, G_DELAYED_WORK(loading), gid); + + g_work_queue_wait_for_completion(queue, gid); + + gtk_status_stack_remove_activity(status, msg); + + /* Vérification du bon déroulement */ + + result = g_elf_loading_get_status(loading); + + g_object_unref(G_OBJECT(loading)); + + aer_exit: + return result; } diff --git a/plugins/elf/symbols.h b/plugins/elf/symbols.h index c5e150b..9e987eb 100644 --- a/plugins/elf/symbols.h +++ b/plugins/elf/symbols.h @@ -28,25 +28,25 @@ #include "format.h" +#include #include #include +/* ------------------------- CHARGEMENT GLOBAL DES SYMBOLES ------------------------- */ + + /* Charge en mémoire la liste humaine des symboles. */ bool load_elf_symbols(GElfFormat *, GtkStatusStack *); -/* Récupère la définition complète d'un symbole donné. */ -bool get_elf_symbol_by_index(GElfFormat *, const elf_shdr *, off_t, elf_sym *); -/* Récupère la désignation d'un symbole donné. */ -const char *get_elf_symbol_name(GElfFormat *, const elf_shdr *, const elf_shdr *, off_t); -/* Récupère la définition complète d'un symbole donné. */ -bool get_elf_symbol_by_index(GElfFormat *, const elf_shdr *, off_t, elf_sym *); +/* ----------------------- PRISE EN COMPTE DE RELOCALISATIONS ----------------------- */ + -/* Récupère la désignation d'un symbole donné. */ -const char *get_elf_symbol_name(GElfFormat *, const elf_shdr *, const elf_shdr *, off_t); +/* Actualise la désignation des fonctions externes à reloger. */ +bool refresh_elf_relocations(GElfFormat *, GtkStatusStack *); diff --git a/src/analysis/binary.c b/src/analysis/binary.c index f38cf66..1a93470 100644 --- a/src/analysis/binary.c +++ b/src/analysis/binary.c @@ -1694,7 +1694,7 @@ bool *g_loaded_binary_display_decomp_lines(GLoadedBinary *binary) * Remarques : - * * * ******************************************************************************/ - +#include "../gui/core/global.h" void ack_completed_disassembly(GDelayedDisassembly *disass, GLoadedBinary *binary) { //GRenderingLine *line; /* "Première" ligne de rendu */ @@ -1706,7 +1706,7 @@ void ack_completed_disassembly(GDelayedDisassembly *disass, GLoadedBinary *binar - + g_binary_format_complete_analysis(G_BIN_FORMAT(binary->format), get_global_status()); diff --git a/src/common/sort.c b/src/common/sort.c index 014d6c7..5cf3132 100644 --- a/src/common/sort.c +++ b/src/common/sort.c @@ -94,6 +94,37 @@ int sort_unsigned_long(unsigned long a, unsigned long b) /****************************************************************************** * * +* Paramètres : a = premier élément à consulter et comparer. * +* b = second élément à consulter et comparer. * +* * +* Description : Compare une valeur de 64 bits avec une autre. * +* * +* Retour : Bilan de la comparaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int sort_uint64_t(uint64_t a, uint64_t b) +{ + int result; /* Bilan à renvoyer */ + + if (a < b) + result = -1; + + else if (a > b) + result = 1; + + else + result = 0; + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : a = premier élément à consulter et comparer. * * b = second élément à consulter et comparer. * * compar = méthode de comparaison entre éléments. * diff --git a/src/common/sort.h b/src/common/sort.h index a887543..4ec5214 100644 --- a/src/common/sort.h +++ b/src/common/sort.h @@ -26,6 +26,7 @@ #include +#include #include @@ -36,6 +37,9 @@ int sort_boolean(bool, bool); /* Compare une valeur avec une autre. */ int sort_unsigned_long(unsigned long, unsigned long); +/* Compare une valeur de 64 bits avec une autre. */ +int sort_uint64_t(uint64_t, uint64_t); + /* Compare un pointeur avec un autre. */ int sort_pointer(const void *, const void *, __compar_fn_t); diff --git a/src/format/format-int.h b/src/format/format-int.h index f377ca3..5c1ae07 100644 --- a/src/format/format-int.h +++ b/src/format/format-int.h @@ -39,6 +39,9 @@ /* Indique le boutisme employé par le format binaire analysé. */ typedef SourceEndian (* format_get_endian_fc) (const GBinFormat *); +/* Réalise un traitement post-désassemblage. */ +typedef void (* format_complete_analysis_fc) (GBinFormat *, GtkStatusStack *); + /* Procède à la décompilation complète du format. */ typedef void (* format_decompile_fc) (const GBinFormat *, void/*GCodeBuffer*/ *, const char *); @@ -105,6 +108,8 @@ struct _GBinFormatClass format_get_endian_fc get_endian; /* Boutisme employé */ + format_complete_analysis_fc complete; /* Terminaison d'analyse */ + }; diff --git a/src/format/format.c b/src/format/format.c index 5b96b59..88367f6 100644 --- a/src/format/format.c +++ b/src/format/format.c @@ -64,6 +64,9 @@ static void g_binary_format_delete_duplicated_symbols(GBinFormat *); /* Recherche le symbole associé à une adresse. */ static bool _g_binary_format_find_symbol(const GBinFormat *, const vmpa2t *, __compar_fn_t, size_t *, GBinSymbol **); +/* Recherche un symbole particulier. */ +static bool __g_binary_format_find_symbol(const GBinFormat *, const void *, __compar_fn_t, size_t *, GBinSymbol **); + /* Indique le type défini pour un format binaire générique. */ @@ -369,6 +372,31 @@ void g_binary_format_activate_disassembling_context(GBinFormat *format, GProcCon } +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à manipuler. * +* status = barre de statut à tenir informée. * +* * +* Description : Réalise un traitement post-désassemblage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_binary_format_complete_analysis(GBinFormat *format, GtkStatusStack *status) +{ + GBinFormatClass *class; /* Classe de l'instance */ + + class = G_BIN_FORMAT_GET_CLASS(format); + + if (class->complete != NULL) + class->complete(format, status); + +} + + /* ---------------------------------------------------------------------------------- */ /* RASSEMBLEMENT ET GESTION DE SYMBOLES */ @@ -450,6 +478,26 @@ void g_binary_format_lock_unlock_symbols_wr(GBinFormat *format, bool state) * * * Paramètres : format = architecture à consulter via la procédure. * * * +* Description : Assure qu'un verrou est bien posé pour l'accès aux symboles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ +#ifndef NDEBUG +void g_binary_format_check_for_symbols_lock(const GBinFormat *format) +{ + assert(g_atomic_int_get(&format->sym_locked) > 0); + +} +#endif + + +/****************************************************************************** +* * +* Paramètres : format = architecture à consulter via la procédure. * +* * * Description : Fournit la marque de dernière modification des symboles. * * * * Retour : Marque de la dernière modification de la liste de symboles. * @@ -882,11 +930,6 @@ bool g_binary_format_find_symbol_by_label(GBinFormat *format, const char *label, static bool _g_binary_format_find_symbol(const GBinFormat *format, const vmpa2t *addr, __compar_fn_t fn, size_t *index, GBinSymbol **symbol) { - bool result; /* Bilan à retourner */ - void *found; /* Résultat de recherches */ - - assert(g_atomic_int_get(&format->sym_locked) > 0); - /** * Pour ce qui est des justifications quant à la vérification suivante, * se référer aux commentaires placés dans g_binary_format_add_symbol(). @@ -894,7 +937,35 @@ static bool _g_binary_format_find_symbol(const GBinFormat *format, const vmpa2t assert(has_phys_addr(addr)); - found = bsearch(addr, format->symbols, format->sym_count, sizeof(GBinSymbol *), fn); + return __g_binary_format_find_symbol(format, addr, fn, index, symbol); + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* key = clef fournie pour distinguer les éléments. * +* fn = méthode de comparaison des symboles. * +* index = indice de l'éventuel symbole trouvé ou NULL. [OUT] * +* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * +* * +* Description : Recherche un symbole particulier. * +* * +* Retour : true si l'opération a été un succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool __g_binary_format_find_symbol(const GBinFormat *format, const void *key, __compar_fn_t fn, size_t *index, GBinSymbol **symbol) +{ + bool result; /* Bilan à retourner */ + void *found; /* Résultat de recherches */ + + assert(g_atomic_int_get(&format->sym_locked) > 0); + + found = bsearch(key, format->symbols, format->sym_count, sizeof(GBinSymbol *), fn); if (found != NULL) { @@ -913,8 +984,11 @@ static bool _g_binary_format_find_symbol(const GBinFormat *format, const vmpa2t else { - *symbol = NULL; + if (symbol != NULL) + *symbol = NULL; + result = false; + } return result; @@ -926,6 +1000,45 @@ static bool _g_binary_format_find_symbol(const GBinFormat *format, const vmpa2t * * * Paramètres : format = informations chargées à consulter. * * addr = adresse à cibler lors des recherches. * +* index = indice de l'éventuel symbole trouvé. [OUT] * +* * +* Description : Recherche l'indice du symbole correspondant à une adresse. * +* * +* Retour : true si l'opération a été un succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_binary_format_find_symbol_index_at(GBinFormat *format, const vmpa2t *addr, size_t *index) +{ + bool result; /* Bilan à retourner */ + + int find_symbol(const vmpa2t *addr, const GBinSymbol **sym) + { + const mrange_t *range; /* Espace mémoire parcouru */ + + range = g_binary_symbol_get_range(*sym); + + return cmp_vmpa(addr, get_mrange_addr(range)); + + } + + g_binary_format_lock_symbols_rd(format); + + result = _g_binary_format_find_symbol(format, addr, (__compar_fn_t)find_symbol, index, NULL); + + g_binary_format_unlock_symbols_rd(format); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* addr = adresse à cibler lors des recherches. * * symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * * * * Description : Recherche le symbole correspondant à une adresse. * @@ -1056,6 +1169,68 @@ bool g_binary_format_find_next_symbol_at(GBinFormat *format, const vmpa2t *addr, /****************************************************************************** * * * Paramètres : format = informations chargées à consulter. * +* range = zone à cibler lors des recherches. * +* index = indice de l'éventuel symbole trouvé. [OUT] * +* * +* Description : Recherche le premier symbole inclus dans une zone mémoire. * +* * +* Retour : true si l'opération a été un succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_binary_format_find_first_symbol_inside(GBinFormat *format, const mrange_t *range, size_t *index) +{ + bool result; /* Bilan à retourner */ + const GBinSymbol *prev; /* Symbole précédent */ + const mrange_t *srange; /* Espace mémoire associé */ + int ret; /* Bilan de comparaison */ + + int find_symbol(const mrange_t *ref_range, const GBinSymbol **sym) + { + const mrange_t *sym_range; /* Espace mémoire parcouru */ + + int ret; + + sym_range = g_binary_symbol_get_range(*sym); + + ret = cmp_mrange_with_vmpa(ref_range, get_mrange_addr(sym_range)); + + ret *= -1; + + return ret; + + } + + g_rw_lock_reader_lock(&format->syms_lock); + + result = __g_binary_format_find_symbol(format, range, (__compar_fn_t)find_symbol, index, NULL); + + if (result) + while (*index > 0) + { + prev = format->symbols[*index - 1]; + srange = g_binary_symbol_get_range(prev); + + ret = cmp_mrange_with_vmpa(range, get_mrange_addr(srange)); + assert(ret <= 0); + + if (ret < 0) break; + else (*index)--; + + } + + g_rw_lock_reader_unlock(&format->syms_lock); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * * addr = adresse à cibler lors des recherches. * * strict = indication de tolérance acceptée. * * symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * diff --git a/src/format/format.h b/src/format/format.h index 9a3a6e3..4052482 100644 --- a/src/format/format.h +++ b/src/format/format.h @@ -70,6 +70,9 @@ void g_binary_format_preload_disassembling_context(GBinFormat *, GProcContext *, /* Définit les points de départ d'un contexte de désassemblage. */ void g_binary_format_activate_disassembling_context(GBinFormat *, GProcContext *, GtkStatusStack *); +/* Réalise un traitement post-désassemblage. */ +void g_binary_format_complete_analysis(GBinFormat *, GtkStatusStack *); + /* ---------------------- RASSEMBLEMENT ET GESTION DE SYMBOLES ---------------------- */ @@ -87,6 +90,11 @@ void g_binary_format_lock_unlock_symbols_wr(GBinFormat *, bool); #define g_binary_format_lock_symbols_wr(f) g_binary_format_lock_unlock_symbols_wr(f, true) #define g_binary_format_unlock_symbols_wr(f) g_binary_format_lock_unlock_symbols_wr(f, false) +/* Assure qu'un verrou est bien posé pour l'accès aux symboles. */ +#ifndef NDEBUG +void g_binary_format_check_for_symbols_lock(const GBinFormat *); +#endif + /* Fournit la marque de dernière modification des symboles. */ unsigned int g_binary_format_get_symbols_stamp(const GBinFormat *); @@ -108,6 +116,9 @@ char *create_string_label(GBinFormat *, const vmpa2t *, size_t); /* Recherche le symbole correspondant à une étiquette. */ bool g_binary_format_find_symbol_by_label(GBinFormat *, const char *, GBinSymbol **); +/* Recherche l'indice du symbole correspondant à une adresse. */ +bool g_binary_format_find_symbol_index_at(GBinFormat *, const vmpa2t *, size_t *); + /* Recherche le symbole correspondant à une adresse. */ bool g_binary_format_find_symbol_at(GBinFormat *, const vmpa2t *, GBinSymbol **); @@ -117,6 +128,9 @@ bool g_binary_format_find_symbol_for(GBinFormat *, const vmpa2t *, GBinSymbol ** /* Recherche le symbole suivant celui lié à une adresse. */ bool g_binary_format_find_next_symbol_at(GBinFormat *, const vmpa2t *, GBinSymbol **); +/* Recherche le premier symbole inclus dans une zone mémoire. */ +bool g_binary_format_find_first_symbol_inside(GBinFormat *, const mrange_t *, size_t *); + /* Recherche le symbole correspondant à une adresse. */ bool g_binary_format_resolve_symbol(GBinFormat *, const vmpa2t *, bool, GBinSymbol **, phys_t *); diff --git a/src/format/symiter.c b/src/format/symiter.c index 74b4abb..230b4ac 100644 --- a/src/format/symiter.c +++ b/src/format/symiter.c @@ -63,6 +63,11 @@ sym_iter_t *create_symbol_iterator(GBinFormat *format, size_t index) { sym_iter_t *result; /* Structure à retourner */ +#ifndef NDEBUG + if (index > 0) + g_binary_format_check_for_symbols_lock(format); +#endif + result = (sym_iter_t *)malloc(sizeof(sym_iter_t)); g_object_ref(G_OBJECT(format)); -- cgit v0.11.2-87-g4458