summaryrefslogtreecommitdiff
path: root/src/format/elf/elf.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2015-12-29 15:08:17 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2015-12-29 15:08:17 (GMT)
commit5cad06b6a52e17d5649e0152c15745a96f7c0efa (patch)
treee26b0857ed6cddd70bce33f983a97e5245fae3fe /src/format/elf/elf.c
parent73fb6dd90282dd10a6c3febe7348ad698c0336a8 (diff)
Handled ELF overlapping program and section headers.
Diffstat (limited to 'src/format/elf/elf.c')
-rw-r--r--src/format/elf/elf.c150
1 files changed, 134 insertions, 16 deletions
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, &section))
+ 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);
+
}