From 5cad06b6a52e17d5649e0152c15745a96f7c0efa Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Tue, 29 Dec 2015 16:08:17 +0100 Subject: Handled ELF overlapping program and section headers. --- ChangeLog | 13 ++++ src/arch/vmpa.c | 42 +++++++++++++ src/arch/vmpa.h | 3 + src/format/elf/elf.c | 150 +++++++++++++++++++++++++++++++++++++++++----- src/glibext/gbinportion.c | 57 ++++++++++++++++-- 5 files changed, 244 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index 25e74e3..fcec4f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,18 @@ 15-12-29 Cyrille Bagard + * src/arch/vmpa.c: + * src/arch/vmpa.h: + Detect intersections between two ranges. + + * src/format/elf/elf.c: + Handle ELF overlapping program and section headers. + + * src/glibext/gbinportion.c: + Create a new layer for the portion which is overlapping the ones of the + current layer. + +15-12-29 Cyrille Bagard + * src/arch/processor.c: * src/arch/processor.h: Make it possible to find instructions by their addresses in a flexible way. diff --git a/src/arch/vmpa.c b/src/arch/vmpa.c index a2430b5..e2da876 100644 --- a/src/arch/vmpa.c +++ b/src/arch/vmpa.c @@ -990,6 +990,48 @@ bool mrange_contains_addr_inclusive(const mrange_t *range, const vmpa2t *addr) /****************************************************************************** * * * Paramètres : range = zone mémoire à consulter. * +* other = autre zone mémoire à manipuler. * +* * +* Description : Détermine si deux zones mémoire se chevauchent ou non. * +* * +* Retour : Bilan de la consultation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool mrange_intersects_mrange(const mrange_t *range, const mrange_t *other) +{ + bool result; /* Bilan à retourner */ + vmpa2t end; /* Fin d'une zone mémoire */ + + result = false; + + result |= mrange_contains_addr(range, &other->addr); + result |= mrange_contains_addr(other, &range->addr); + + if (get_mrange_length(other) > 0) + { + compute_mrange_end_addr(other, &end); + deminish_vmpa(&end, 1); + result |= mrange_contains_addr(range, &end); + } + + if (get_mrange_length(range) > 0) + { + compute_mrange_end_addr(range, &end); + deminish_vmpa(&end, 1); + result |= mrange_contains_addr(other, &end); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : range = zone mémoire à consulter. * * addr = localisation mémoire à déterminer. * * * * Description : Calcule la position extérieure finale d'une couverture. * diff --git a/src/arch/vmpa.h b/src/arch/vmpa.h index 4470676..eb63324 100644 --- a/src/arch/vmpa.h +++ b/src/arch/vmpa.h @@ -198,6 +198,9 @@ bool mrange_contains_addr(const mrange_t *, const vmpa2t *); /* Indique si une localisation est incluse dans une zone ou non. */ bool mrange_contains_addr_inclusive(const mrange_t *, const vmpa2t *); +/* Détermine si deux zones mémoire se chevauchent ou non. */ +bool mrange_intersects_mrange(const mrange_t *, const mrange_t *); + /* Calcule la position extérieure finale d'une couverture. */ void compute_mrange_end_addr(const mrange_t *, vmpa2t *); diff --git a/src/format/elf/elf.c b/src/format/elf/elf.c index 3491c71..a48e3b3 100644 --- a/src/format/elf/elf.c +++ b/src/format/elf/elf.c @@ -365,9 +365,11 @@ static const char *g_elf_format_get_target_machine(const GElfFormat *format) static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer *main) { GPortionLayer *layer; /* Couche à mettre en place */ + uint16_t max; /* Décompte d'éléments traités */ + elf_phdr *sorted_phdrs; /* Liste de segments triée */ uint16_t i; /* Boucle de parcours */ off_t offset; /* Début de part de programme */ - elf_phdr phdr; /* En-tête de programme ELF */ + elf_phdr *phdr; /* En-tête de programme ELF */ uint32_t p_flags; /* Droits associés à une partie*/ const char *background; /* Fond signigicatif */ GBinPortion *new; /* Nouvelle portion définie */ @@ -376,25 +378,87 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer PortionAccessRights rights; /* Droits d'une portion */ elf_shdr strings; /* Section des descriptions */ bool has_strings; /* Section trouvée ? */ - elf_shdr section; /* En-tête de section ELF */ + elf_shdr *sorted_shdrs; /* Liste de sections triée */ + elf_shdr *section; /* En-tête de section ELF */ uint64_t sh_flags; /* Droits associés à une partie*/ const char *name; /* Nom trouvé ou NULL */ - /* Côté segments basiques */ + /** + * La copie des différents en-têtes cherche à reproduire l'inclusion native + * du format : + * + * EXIDX 0x001178 0x00009178 0x00009178 0x00008 0x00008 R 0x4 + * PHDR 0x000034 0x00008034 0x00008034 0x00120 0x00120 R E 0x4 + * INTERP 0x000154 0x00008154 0x00008154 0x00019 0x00019 R 0x1 + * LOAD 0x000000 0x00008000 0x00008000 0x01184 0x01184 R E 0x8000 + * + */ + + /** + * Côté segments basiques. + */ layer = g_portion_layer_new(NO_LENGTH_YET, _("Segment")); g_portion_layer_attach_sub(main, layer); - for (i = 0; i < ELF_HDR(format, format->header, e_phnum); i++) + /* Constitution d'une liste de travail */ + + max = ELF_HDR(format, format->header, e_phnum); + + sorted_phdrs = (elf_phdr *)calloc(max, sizeof(elf_phdr)); + + for (i = 0; i < max; i++) { offset = ELF_HDR(format, format->header, e_phoff) + ELF_HDR(format, format->header, e_phentsize) * i; - if (!read_elf_program_header(format, offset, &phdr)) + if (!read_elf_program_header(format, offset, &sorted_phdrs[i])) + { + if (format->is_32b) + sorted_phdrs[i].phdr32.p_type = PT_NULL; + else + sorted_phdrs[i].phdr64.p_type = PT_NULL; + } + + } + + /* Tri de cette liste */ + + int sort_phdr(elf_phdr *a, elf_phdr *b) + { + uint64_t filesz_a; /* Taille de l'en-tête 'a' */ + uint64_t filesz_b; /* Taille de l'en-tête 'b' */ + int status; /* Bilan d'une comparaison */ + + filesz_a = ELF_PHDR(format, *a, p_filesz); + filesz_b = ELF_PHDR(format, *b, p_filesz); + + if (filesz_a < filesz_b) + status = 1; + + else if (filesz_a > filesz_b) + status = -1; + + else + status = 0; + + return status; + + } + + qsort(sorted_phdrs, max, sizeof(elf_phdr), (__compar_fn_t)sort_phdr); + + /* Inclusion de ces en-têtes */ + + for (i = 0; i < max; i++) + { + phdr = &sorted_phdrs[i]; + + if (ELF_PHDR(format, *phdr, p_type) == PT_NULL) continue; - p_flags = ELF_PHDR(format, phdr, p_flags); + p_flags = ELF_PHDR(format, *phdr, p_flags); if (p_flags & PF_X) background = BPC_CODE; else if (p_flags & PF_W) background = BPC_DATA; @@ -404,12 +468,12 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer snprintf(desc, MAX_PORTION_DESC, "%s \"%s\"", _("Segment"), - get_elf_program_type_desc(ELF_PHDR(format, phdr, p_type))); + get_elf_program_type_desc(ELF_PHDR(format, *phdr, p_type))); g_binary_portion_set_desc(new, desc); - init_vmpa(&addr, ELF_PHDR(format, phdr, p_offset), ELF_PHDR(format, phdr, p_vaddr)); - g_binary_portion_set_values(new, &addr, ELF_PHDR(format, phdr, p_filesz)); + init_vmpa(&addr, ELF_PHDR(format, *phdr, p_offset), ELF_PHDR(format, *phdr, p_vaddr)); + g_binary_portion_set_values(new, &addr, ELF_PHDR(format, *phdr, p_filesz)); rights = PAC_NONE; if (p_flags & PF_R) rights |= PAC_READ; @@ -422,7 +486,11 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer } - /* Inclusion des sections, si possible... */ + free(sorted_phdrs); + + /** + * Inclusion des sections, si possible... + */ has_strings = find_elf_section_by_index(format, ELF_HDR(format, format->header, e_shstrndx), @@ -432,12 +500,60 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer g_portion_layer_attach_sub(main, layer); - for (i = 0; i < ELF_HDR(format, format->header, e_shnum); i++) + /* Constitution d'une liste de travail */ + + max = ELF_HDR(format, format->header, e_shnum); + + sorted_shdrs = (elf_shdr *)calloc(max, sizeof(elf_shdr)); + + for (i = 0; i < max; i++) + { + if (!find_elf_section_by_index(format, i, &sorted_shdrs[i])) + { + if (format->is_32b) + sorted_shdrs[i].shdr32.sh_offset = 0; + else + sorted_shdrs[i].shdr64.sh_offset = 0; + } + + } + + /* Tri de cette liste */ + + int sort_shdr(elf_shdr *a, elf_shdr *b) + { + uint64_t size_a; /* Taille de l'en-tête 'a' */ + uint64_t size_b; /* Taille de l'en-tête 'b' */ + int status; /* Bilan d'une comparaison */ + + size_a = ELF_SHDR(format, *a, sh_size); + size_b = ELF_SHDR(format, *b, sh_size); + + if (size_a < size_b) + status = 1; + + else if (size_a > size_b) + status = -1; + + else + status = 0; + + return status; + + } + + qsort(sorted_shdrs, max, sizeof(elf_shdr), (__compar_fn_t)sort_shdr); + + /* Inclusion de ces en-têtes */ + + for (i = 0; i < max; i++) { - if (!find_elf_section_by_index(format, i, §ion)) + section = &sorted_shdrs[i]; + + if (ELF_SHDR(format, *section, sh_offset) == 0) continue; - sh_flags = ELF_SHDR(format, section, sh_flags); + sh_flags = ELF_SHDR(format, *section, sh_flags); if ((sh_flags & SHF_ALLOC) == 0) continue; @@ -450,7 +566,7 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer if (has_strings) name = extract_name_from_elf_string_section(format, &strings, - ELF_SHDR(format, section, sh_name)); + ELF_SHDR(format, *section, sh_name)); else name = NULL; if (name != NULL) @@ -460,8 +576,8 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer g_binary_portion_set_desc(new, desc); - init_vmpa(&addr, ELF_SHDR(format, section, sh_offset), ELF_SHDR(format, section, sh_addr)); - g_binary_portion_set_values(new, &addr, ELF_SHDR(format, section, sh_size)); + init_vmpa(&addr, ELF_SHDR(format, *section, sh_offset), ELF_SHDR(format, *section, sh_addr)); + g_binary_portion_set_values(new, &addr, ELF_SHDR(format, *section, sh_size)); rights = PAC_NONE; if (sh_flags & SHF_ALLOC) rights |= PAC_READ; @@ -474,6 +590,8 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer } + free(sorted_shdrs); + } diff --git a/src/glibext/gbinportion.c b/src/glibext/gbinportion.c index 790614a..abdec60 100644 --- a/src/glibext/gbinportion.c +++ b/src/glibext/gbinportion.c @@ -898,14 +898,61 @@ void g_portion_layer_attach_sub(GPortionLayer *layer, GPortionLayer *sub) void g_portion_layer_include(GPortionLayer *layer, GBinPortion *portion) { - layer->portions = (GBinPortion **)realloc(layer->portions, - ++layer->count * sizeof(GBinPortion *)); + GPortionLayer *sub; /* Sous couche indispensable */ + bool conflict; /* Conflit dû aux débordements */ + const mrange_t *range; /* Emplacement de la portion */ + size_t i; /* Boucle de parcours */ + const mrange_t *other; /* Emplacements déjà occupés */ + + /** + * On prend ici en compte le genre de situations suivantes : + * + * [21] .bss NOBITS 00088240 07823c 0018c8 00 WA 0 0 8 + * [22] __libc_freeres_ptrs NOBITS 00089b08 07823c 000018 00 WA 0 0 4 + * [23] .comment PROGBITS 00000000 07823c 000022 01 MS 0 0 1 + * + * Pendant le désassemblage, la procédure n'aime pas trop les intersections + * de zones mémoire. + */ + + conflict = false; + + range = g_binary_portion_get_range(portion); + + for (i = 0; i < layer->count && !conflict; i++) + { + other = g_binary_portion_get_range(layer->portions[i]); - layer->portions[layer->count - 1] = portion; + conflict = mrange_intersects_mrange(range, other); - g_binary_portion_set_level(portion, &layer->level); + } + + /* La portion recouvre-t-elle une portion déjà existante ? */ + if (conflict) + { + if (layer->sub_layer == NULL) + { + sub = g_portion_layer_new(layer->length, layer->name); + g_portion_layer_attach_sub(layer, sub); + } - qsort(layer->portions, layer->count, sizeof(GBinPortion *), (__compar_fn_t)g_binary_portion_compare); + g_portion_layer_include(layer->sub_layer, portion); + + } + + /* Sinon on l'intègre dans la couche courante */ + else + { + layer->portions = (GBinPortion **)realloc(layer->portions, + ++layer->count * sizeof(GBinPortion *)); + + layer->portions[layer->count - 1] = portion; + + g_binary_portion_set_level(portion, &layer->level); + + qsort(layer->portions, layer->count, sizeof(GBinPortion *), (__compar_fn_t)g_binary_portion_compare); + + } } -- cgit v0.11.2-87-g4458