From 9b36cb0609e6553f2c89c0b5909aa8c6482f9c7f Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 3 Jan 2016 16:32:47 -0500 Subject: dumpelf: improve decoding - push down section header validity checks (previous one was too strict) - fix section header walking (was missing braces in for loop) - dump all of the pad bytes in the elf header - expand program header output and decode/explain more fields - use uintptr_t for doing pointer math - handle SHT_NOBITS better --- dumpelf.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 26 deletions(-) diff --git a/dumpelf.c b/dumpelf.c index 8abad61..d765164 100644 --- a/dumpelf.c +++ b/dumpelf.c @@ -111,10 +111,7 @@ static void dumpelf(const char *filename, long file_cnt) } \ offset = EGET(strtbl->sh_offset); \ for (i = 0; i < shnum; ++i, ++shdr) \ - if (!VALID_SHDR(elf, shdr)) { \ - printf(" /* corrupt section headers ! */ "); \ - break; \ - } \ + /* Don't use VALID_SHDR as we want to decode the fields */ \ dump_shdr(elf, shdr, i, elf->vdata + offset + EGET(shdr->sh_name)); \ } DUMP_SHDRS(32) @@ -155,6 +152,7 @@ static void dumpelf(const char *filename, long file_cnt) /* get out of here */ unreadelf(elf); } + static void dump_ehdr(elfobj *elf, const void *ehdr_void) { #define DUMP_EHDR(B) \ @@ -168,8 +166,7 @@ static void dump_ehdr(elfobj *elf, const void *ehdr_void) "\t\t/* [%i] EI_VERSION: */ %i , /* (%s) */\n" \ "\t\t/* [%i] EI_OSABI: */ %i , /* (%s) */\n" \ "\t\t/* [%i] EI_ABIVERSION: */ %i ,\n" \ - "\t\t/* [%i] EI_PAD: */ 0x%02X /* x %i bytes */\n" \ - /* "\t\t/ [%i] EI_BRAND: / 0x%02X\n" */ \ + "\t\t/* [%i-%i] EI_PAD: */ 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X,\n" \ "\t},\n", \ EI_MAG0, (unsigned int)ehdr->e_ident[EI_MAG0], ehdr->e_ident[EI_MAG1], ehdr->e_ident[EI_MAG2], ehdr->e_ident[EI_MAG3], \ EI_CLASS, (int)ehdr->e_ident[EI_CLASS], get_elfeitype(EI_CLASS, ehdr->e_ident[EI_CLASS]), \ @@ -177,18 +174,25 @@ static void dump_ehdr(elfobj *elf, const void *ehdr_void) EI_VERSION, (int)ehdr->e_ident[EI_VERSION], get_elfeitype(EI_VERSION, ehdr->e_ident[EI_VERSION]), \ EI_OSABI, (int)ehdr->e_ident[EI_OSABI], get_elfeitype(EI_OSABI, ehdr->e_ident[EI_OSABI]), \ EI_ABIVERSION, (int)ehdr->e_ident[EI_ABIVERSION], \ - EI_PAD, (unsigned int)ehdr->e_ident[EI_PAD], EI_NIDENT - EI_PAD \ - /* EI_BRAND, ehdr->e_ident[EI_BRAND] */ \ + EI_PAD, EI_NIDENT - 1, \ + (unsigned int)ehdr->e_ident[EI_PAD + 0], \ + (unsigned int)ehdr->e_ident[EI_PAD + 1], \ + (unsigned int)ehdr->e_ident[EI_PAD + 2], \ + (unsigned int)ehdr->e_ident[EI_PAD + 3], \ + (unsigned int)ehdr->e_ident[EI_PAD + 4], \ + (unsigned int)ehdr->e_ident[EI_PAD + 5], \ + (unsigned int)ehdr->e_ident[EI_PAD + 6] \ ); \ printf("\t.e_type = %-10i , /* (%s) */\n", (int)EGET(ehdr->e_type), get_elfetype(elf)); \ printf("\t.e_machine = %-10i , /* (%s) */\n", (int)EGET(ehdr->e_machine), get_elfemtype(elf)); \ - printf("\t.e_version = %-10i ,\n", (int)EGET(ehdr->e_version)); \ - printf("\t.e_entry = 0x%-8lX ,\n", (unsigned long)EGET(ehdr->e_entry)); \ + printf("\t.e_version = %-10i , /* (%s) */\n", (int)EGET(ehdr->e_version), get_elfeitype(EI_VERSION, EGET(ehdr->e_version))); \ + printf("\t.e_entry = 0x%-8lX , /* (start address at runtime) */\n", (unsigned long)EGET(ehdr->e_entry)); \ printf("\t.e_phoff = %-10li , /* (bytes into file) */\n", (unsigned long)EGET(ehdr->e_phoff)); \ printf("\t.e_shoff = %-10li , /* (bytes into file) */\n", (unsigned long)EGET(ehdr->e_shoff)); \ printf("\t.e_flags = 0x%-8X ,\n", (unsigned int)EGET(ehdr->e_flags)); \ printf("\t.e_ehsize = %-10i , /* (bytes) */\n", (int)EGET(ehdr->e_ehsize)); \ printf("\t.e_phentsize = %-10i , /* (bytes) */\n", (int)EGET(ehdr->e_phentsize)); \ + /* TODO: Handle PN_XNUM */ \ printf("\t.e_phnum = %-10i , /* (program headers) */\n", (int)EGET(ehdr->e_phnum)); \ printf("\t.e_shentsize = %-10i , /* (bytes) */\n", (int)EGET(ehdr->e_shentsize)); \ printf("\t.e_shnum = %-10i , /* (section headers) */\n", (int)EGET(ehdr->e_shnum)); \ @@ -198,28 +202,63 @@ static void dump_ehdr(elfobj *elf, const void *ehdr_void) DUMP_EHDR(32) DUMP_EHDR(64) } + +static const char *dump_p_flags(uint32_t type, uint32_t flags) +{ + static char buf[1024]; + char *p = buf; + p[0] = p[1] = p[2] = '\0'; + + if (flags & PF_R) + p = stpcpy(p, " | PF_R"); + if (flags & PF_W) + p = stpcpy(p, " | PF_W"); + if (flags & PF_X) + p = stpcpy(p, " | PF_X"); + flags &= ~(PF_R | PF_W | PF_X); + + switch (type) { + case PT_PAX_FLAGS: +#define X(b) if (flags & b) { p = stpcpy(p, " | " #b); flags &= ~b; } + X(PF_PAGEEXEC) X(PF_NOPAGEEXEC) + X(PF_SEGMEXEC) X(PF_NOSEGMEXEC) + X(PF_MPROTECT) X(PF_NOMPROTECT) + X(PF_RANDEXEC) X(PF_NORANDEXEC) + X(PF_EMUTRAMP) X(PF_NOEMUTRAMP) + X(PF_RANDMMAP) X(PF_NORANDMMAP) +#undef X + break; + } + + if (flags) + sprintf(p, " | 0x%X", flags); + + return buf + 3; +} static void dump_phdr(elfobj *elf, const void *phdr_void, long phdr_cnt) { #define DUMP_PHDR(B) \ if (elf->elf_class == ELFCLASS ## B) { \ const Elf ## B ## _Phdr *phdr = PHDR ## B (phdr_void); \ - switch (EGET(phdr->p_type)) { \ + uint32_t p_type = EGET(phdr->p_type); \ + switch (p_type) { \ case PT_DYNAMIC: phdr_dynamic_void = phdr_void; break; \ } \ - printf("/* Program Header #%li 0x%lX */\n{\n", phdr_cnt, (unsigned long)phdr_void - (unsigned long)elf->data); \ - printf("\t.p_type = %-10li , /* [%s] */\n", (long)EGET(phdr->p_type), get_elfptype(EGET(phdr->p_type))); \ - printf("\t.p_offset = %-10li ,\n", (long)EGET(phdr->p_offset)); \ - printf("\t.p_vaddr = 0x%-8lX ,\n", (unsigned long)EGET(phdr->p_vaddr)); \ - printf("\t.p_paddr = 0x%-8lX ,\n", (unsigned long)EGET(phdr->p_paddr)); \ - printf("\t.p_filesz = %-10li ,\n", (long)EGET(phdr->p_filesz)); \ - printf("\t.p_memsz = %-10li ,\n", (long)EGET(phdr->p_memsz)); \ - printf("\t.p_flags = %-10li ,\n", (long)EGET(phdr->p_flags)); \ - printf("\t.p_align = %-10li\n", (long)EGET(phdr->p_align)); \ + printf("/* Program Header #%li 0x%lX */\n{\n", phdr_cnt, (uintptr_t)phdr_void - (uintptr_t)elf->data); \ + printf("\t.p_type = %-10li , /* [%s] */\n", (long)p_type, get_elfptype(p_type)); \ + printf("\t.p_offset = %-10li , /* (bytes into file) */\n", (long)EGET(phdr->p_offset)); \ + printf("\t.p_vaddr = 0x%-8lX , /* (virtual addr at runtime) */\n", (unsigned long)EGET(phdr->p_vaddr)); \ + printf("\t.p_paddr = 0x%-8lX , /* (physical addr at runtime) */\n", (unsigned long)EGET(phdr->p_paddr)); \ + printf("\t.p_filesz = %-10li , /* (bytes in file) */\n", (long)EGET(phdr->p_filesz)); \ + printf("\t.p_memsz = %-10li , /* (bytes in mem at runtime) */\n", (long)EGET(phdr->p_memsz)); \ + printf("\t.p_flags = 0x%-8lX , /* %s */\n", (unsigned long)EGET(phdr->p_flags), dump_p_flags(p_type, EGET(phdr->p_flags))); \ + printf("\t.p_align = %-10li , /* (min mem alignment in bytes) */\n", (long)EGET(phdr->p_align)); \ printf("},\n"); \ } DUMP_PHDR(32) DUMP_PHDR(64) } + static void dump_shdr(elfobj *elf, const void *shdr_void, long shdr_cnt, const char *name) { unsigned long i; @@ -233,22 +272,31 @@ static void dump_shdr(elfobj *elf, const void *shdr_void, long shdr_cnt, const c #define DUMP_SHDR(B) \ if (elf->elf_class == ELFCLASS ## B) { \ const Elf ## B ## _Shdr *shdr = SHDR ## B (shdr_void); \ + Elf ## B ## _Off offset = EGET(shdr->sh_offset); \ uint32_t type = EGET(shdr->sh_type); \ uint ## B ## _t size = EGET(shdr->sh_size); \ + \ printf("/* Section Header #%li '%s' 0x%lX */\n{\n", \ - shdr_cnt, name, (unsigned long)shdr_void - (unsigned long)elf->data); \ + shdr_cnt, name, (uintptr_t)shdr_void - (uintptr_t)elf->data); \ printf("\t.sh_name = %-10i ,\n", (int)EGET(shdr->sh_name)); \ printf("\t.sh_type = %-10i , /* [%s] */\n", (int)EGET(shdr->sh_type), get_elfshttype(type)); \ printf("\t.sh_flags = %-10li ,\n", (long)EGET(shdr->sh_flags)); \ printf("\t.sh_addr = 0x%-8lX ,\n", (unsigned long)EGET(shdr->sh_addr)); \ - printf("\t.sh_offset = %-10i , /* (bytes) */\n", (int)EGET(shdr->sh_offset)); \ - printf("\t.sh_size = %-10li , /* (bytes) */\n", (long)EGET(shdr->sh_size)); \ + printf("\t.sh_offset = %-10li , /* (bytes) */\n", (long)offset); \ + printf("\t.sh_size = %-10lu , /* (bytes) */\n", (unsigned long)size); \ printf("\t.sh_link = %-10i ,\n", (int)EGET(shdr->sh_link)); \ printf("\t.sh_info = %-10i ,\n", (int)EGET(shdr->sh_info)); \ printf("\t.sh_addralign = %-10li ,\n", (long)EGET(shdr->sh_addralign)); \ printf("\t.sh_entsize = %-10li\n", (long)EGET(shdr->sh_entsize)); \ - if (size && be_verbose) { \ - void *vdata = elf->vdata + EGET(shdr->sh_offset); \ + \ + if (type == SHT_NOBITS) { \ + /* Special case so we can do valid check next. */ \ + if (be_verbose) \ + printf("\t/* NOBITS sections do not occupy the file. */\n"); \ + } else if (!(offset < (uint64_t)elf->len && size < (uint64_t)elf->len && offset <= elf->len - size)) { \ + printf(" /* corrupt section header ! */ "); \ + } else if (size && be_verbose) { \ + void *vdata = elf->vdata + offset; \ unsigned char *data = vdata; \ switch (type) { \ case SHT_PROGBITS: { \ @@ -258,6 +306,7 @@ static void dump_shdr(elfobj *elf, const void *shdr_void, long shdr_cnt, const c } \ if (strcmp(name, ".comment") != 0) \ break; \ + break; \ } \ case SHT_STRTAB: { \ char b; \ @@ -315,6 +364,7 @@ static void dump_shdr(elfobj *elf, const void *shdr_void, long shdr_cnt, const c DUMP_SHDR(32) DUMP_SHDR(64) } + static void dump_dyn(elfobj *elf, const void *dyn_void, long dyn_cnt) { #define DUMP_DYN(B) \ @@ -322,7 +372,7 @@ static void dump_dyn(elfobj *elf, const void *dyn_void, long dyn_cnt) const Elf ## B ## _Dyn *dyn = dyn_void; \ unsigned long tag = EGET(dyn->d_tag); \ printf("/* Dynamic tag #%li '%s' 0x%lX */\n{\n", \ - dyn_cnt, get_elfdtype(tag), (unsigned long)dyn_void - (unsigned long)elf->data); \ + dyn_cnt, get_elfdtype(tag), (uintptr_t)dyn_void - (uintptr_t)elf->data); \ printf("\t.d_tag = 0x%-8lX ,\n", tag); \ printf("\t.d_un = {\n"); \ printf("\t\t.d_val = 0x%-8lX ,\n", (unsigned long)EGET(dyn->d_un.d_val)); \ -- cgit v1.2.3-65-gdbad