diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2024-08-17 14:25:04 +0200 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2024-08-17 14:25:04 +0200 |
| commit | d47b1b0e5679652e6b5fb5fd4cee52b775229a63 (patch) | |
| tree | 46f331bed24c7b7212fb7005c162d324a6956d23 /src | |
| parent | fa87b0fcef3dff593a507b3200ef83d846101d64 (diff) | |
| download | box64-d47b1b0e5679652e6b5fb5fd4cee52b775229a63.tar.gz box64-d47b1b0e5679652e6b5fb5fd4cee52b775229a63.zip | |
[BOX32] Added 32bits elf header parser and dumper
Diffstat (limited to 'src')
| -rw-r--r-- | src/elfs/elfhash.c | 35 | ||||
| -rw-r--r-- | src/elfs/elfload_dump.c | 44 | ||||
| -rwxr-xr-x | src/elfs/elfload_dump32.c | 352 | ||||
| -rw-r--r-- | src/elfs/elfloader.c | 2 | ||||
| -rw-r--r-- | src/elfs/elfloader_private.h | 1 | ||||
| -rw-r--r-- | src/elfs/elfparser.c | 3 | ||||
| -rwxr-xr-x | src/elfs/elfparser32.c | 466 | ||||
| -rw-r--r-- | src/elfs/elfparser64.c | 406 | ||||
| -rw-r--r-- | src/include/elfload_dump.h | 9 |
9 files changed, 901 insertions, 417 deletions
diff --git a/src/elfs/elfhash.c b/src/elfs/elfhash.c index 61d1af65..a20c31d9 100644 --- a/src/elfs/elfhash.c +++ b/src/elfs/elfhash.c @@ -18,7 +18,12 @@ #include "elfload_dump.h" #include "elfloader_private.h" -const char* GetSymbolVersion32(elfheader_t* h, int version) { /* TODO */ return NULL; } +const char* GetSymbolVersion32(elfheader_t* h, int version) +#ifndef BOX32 +{ return NULL; } +#else + ; +#endif const char* GetSymbolVersion64(elfheader_t* h, int version) { if(version<2) @@ -44,7 +49,12 @@ const char* GetSymbolVersion(elfheader_t* h, int version) return box64_is32bits?GetSymbolVersion32(h, version):GetSymbolVersion64(h, version); } -const char* GetParentSymbolVersion32(elfheader_t* h, int index) { /* TODO */ return NULL; } +const char* GetParentSymbolVersion32(elfheader_t* h, int index) +#ifndef BOX32 +{ return NULL; } +#else + ; +#endif const char* GetParentSymbolVersion64(elfheader_t* h, int index) { if(!h->VerDef._64 || (index<1)) @@ -111,7 +121,12 @@ uint16_t GetSymbolVersionFlag(elfheader_t* h, int index) { } -int GetVersionIndice32(elfheader_t* h, const char* vername) { /* TODO */ return 0; } +int GetVersionIndice32(elfheader_t* h, const char* vername) +#ifndef BOX32 +{ return 0; } +#else + ; +#endif int GetVersionIndice64(elfheader_t* h, const char* vername) { if(!vername) @@ -132,7 +147,12 @@ int GetVersionIndice(elfheader_t* h, const char* vername) return box64_is32bits?GetVersionIndice32(h, vername):GetVersionIndice64(h, vername); } -int GetNeededVersionCnt32(elfheader_t* h, const char* libname) { /* TODO */ return 0; } +int GetNeededVersionCnt32(elfheader_t* h, const char* libname) +#ifndef BOX32 +{ return 0; } +#else + ; +#endif int GetNeededVersionCnt64(elfheader_t* h, const char* libname) { if(!libname) @@ -153,7 +173,12 @@ int GetNeededVersionCnt(elfheader_t* h, const char* libname) return box64_is32bits?GetNeededVersionCnt32(h, libname):GetNeededVersionCnt64(h, libname); } -const char* GetNeededVersionString32(elfheader_t* h, const char* libname, int idx) { /* TODO */ return NULL; } +const char* GetNeededVersionString32(elfheader_t* h, const char* libname, int idx) +#ifndef BOX32 +{ return NULL; } +#else + ; +#endif const char* GetNeededVersionString64(elfheader_t* h, const char* libname, int idx) { if(!libname) diff --git a/src/elfs/elfload_dump.c b/src/elfs/elfload_dump.c index 5c5f349a..18d4dbc6 100644 --- a/src/elfs/elfload_dump.c +++ b/src/elfs/elfload_dump.c @@ -174,7 +174,9 @@ static const char* DumpPHEntry(Elf64_Phdr *e) } return buff; } - +#ifndef BOX32 +const char* DumpRelType32(int t) { return NULL; } +#endif const char* DumpRelType64(int t) { static char buff[50]; @@ -241,6 +243,9 @@ static const char* DumpSym(elfheader_t *h, Elf64_Sym* sym, int version) return buff; } +#ifndef BOX32 +const char* SymName32(elfheader_t *h, Elf32_Sym* sym) { return NULL; } +#endif const char* SymName64(elfheader_t *h, Elf64_Sym* sym) { return h->DynStr+sym->st_name; @@ -250,6 +255,9 @@ static const char* IdxSymName(elfheader_t *h, int sym) return h->DynStr+h->DynSym._64[sym].st_name; } +#ifndef BOX32 +void DumpMainHeader32(Elf32_Ehdr *header, elfheader_t *h) { } +#endif void DumpMainHeader64(Elf64_Ehdr *header, elfheader_t *h) { if(box64_dump) { @@ -275,7 +283,9 @@ void DumpMainHeader64(Elf64_Ehdr *header, elfheader_t *h) printf_dump(LOG_NEVER, "ELF Dump Sections ====\n"); } } - +#ifndef BOX32 +void DumpSymTab32(elfheader_t *h) { } +#endif void DumpSymTab64(elfheader_t *h) { if(box64_dump && h->SymTab._64) { @@ -289,6 +299,9 @@ void DumpSymTab64(elfheader_t *h) } } +#ifndef BOX32 +void DumpDynamicSections32(elfheader_t *h) { } +#endif void DumpDynamicSections64(elfheader_t *h) { if(box64_dump && h->Dynamic._64) { @@ -299,6 +312,9 @@ void DumpDynamicSections64(elfheader_t *h) } } +#ifndef BOX32 +void DumpDynSym32(elfheader_t *h) { } +#endif void DumpDynSym64(elfheader_t *h) { if(box64_dump && h->DynSym._64) { @@ -312,7 +328,12 @@ void DumpDynSym64(elfheader_t *h) } } -void DumpDynamicNeeded32(elfheader_t *h) { /* TODO */} +void DumpDynamicNeeded32(elfheader_t *h) +#ifndef BOX32 + { } +#else + ; +#endif void DumpDynamicNeeded(elfheader_t *h) { if(box64_is32bits) @@ -328,7 +349,12 @@ void DumpDynamicNeeded(elfheader_t *h) } } -void DumpDynamicRPath32(elfheader_t *h) { /* TODO */} +void DumpDynamicRPath32(elfheader_t *h) +#ifndef BOX32 +{ } +#else + ; +#endif void DumpDynamicRPath(elfheader_t *h) { if(box64_is32bits) @@ -348,6 +374,9 @@ void DumpDynamicRPath(elfheader_t *h) } } +#ifndef BOX32 +void DumpRelTable32(elfheader_t *h, int cnt, Elf32_Rel *rel, const char* name) { } +#endif void DumpRelTable64(elfheader_t *h, int cnt, Elf64_Rel *rel, const char* name) { if(box64_dump) { @@ -360,7 +389,9 @@ void DumpRelTable64(elfheader_t *h, int cnt, Elf64_Rel *rel, const char* name) printf_dump(LOG_NEVER, "ELF Dump Rel Table=====\n"); } } - +#ifndef BOX32 +void DumpRelATable32(elfheader_t *h, int cnt, Elf32_Rela *rela, const char* name) { } +#endif void DumpRelATable64(elfheader_t *h, int cnt, Elf64_Rela *rela, const char* name) { if(box64_dump && h->rela) { @@ -375,6 +406,9 @@ void DumpRelATable64(elfheader_t *h, int cnt, Elf64_Rela *rela, const char* name } } +#ifndef BOX32 +void DumpRelRTable32(elfheader_t *h, int cnt, Elf32_Relr *relr, const char *name) { } +#endif void DumpRelRTable64(elfheader_t *h, int cnt, Elf64_Relr *relr, const char *name) { if(box64_dump && h->relr) { diff --git a/src/elfs/elfload_dump32.c b/src/elfs/elfload_dump32.c new file mode 100755 index 00000000..b6d8df41 --- /dev/null +++ b/src/elfs/elfload_dump32.c @@ -0,0 +1,352 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <elf.h> + +#include "box64version.h" +#include "elfloader.h" +#include "debug.h" +#include "elfload_dump.h" +#include "elfloader_private.h" +#include "box32.h" + +static const char* DumpSection(Elf32_Shdr *s, char* SST) { + static char buff[400]; + switch (s->sh_type) { + case SHT_NULL: + return "SHT_NULL"; + #define GO(A) \ + case A: \ + sprintf(buff, #A " Name=\"%s\"(%d) off=0x%X, size=%d, attr=0x%04X, addr=%p(%02X), link/info=%d/%d", \ + SST+s->sh_name, s->sh_name, s->sh_offset, s->sh_size, s->sh_flags, from_ptrv(s->sh_addr), s->sh_addralign, s->sh_link, s->sh_info); \ + break + GO(SHT_PROGBITS); + GO(SHT_SYMTAB); + GO(SHT_STRTAB); + GO(SHT_RELA); + GO(SHT_HASH); + GO(SHT_DYNAMIC); + GO(SHT_NOTE); + GO(SHT_NOBITS); + GO(SHT_REL); + GO(SHT_SHLIB); + GO(SHT_DYNSYM); + GO(SHT_INIT_ARRAY); + GO(SHT_FINI_ARRAY); + GO(SHT_PREINIT_ARRAY); + GO(SHT_GROUP); + GO(SHT_SYMTAB_SHNDX); + GO(SHT_NUM); + GO(SHT_LOPROC); + GO(SHT_HIPROC); + GO(SHT_LOUSER); + GO(SHT_HIUSER); + #if defined(SHT_GNU_versym) && defined(SHT_GNU_ATTRIBUTES) + GO(SHT_GNU_versym); + GO(SHT_GNU_ATTRIBUTES); + GO(SHT_GNU_HASH); + GO(SHT_GNU_LIBLIST); + GO(SHT_CHECKSUM); + GO(SHT_LOSUNW); + //GO(SHT_SUNW_move); + GO(SHT_SUNW_COMDAT); + GO(SHT_SUNW_syminfo); + GO(SHT_GNU_verdef); + GO(SHT_GNU_verneed); + #endif + #undef GO + default: + sprintf(buff, "0x%X unknown type", s->sh_type); + } + return buff; +} + +static const char* DumpDynamic(Elf32_Dyn *s) { + static char buff[200]; + switch (s->d_tag) { + case DT_NULL: + return "DT_NULL: End Dynamic Section"; + #define GO(A, Add) \ + case A: \ + sprintf(buff, #A " %s=0x%X", (Add)?"Addr":"Val", (Add)?s->d_un.d_ptr:s->d_un.d_val); \ + break + GO(DT_NEEDED, 0); + GO(DT_PLTRELSZ, 0); + GO(DT_PLTGOT, 1); + GO(DT_HASH, 1); + GO(DT_STRTAB, 1); + GO(DT_SYMTAB, 1); + GO(DT_RELA, 1); + GO(DT_RELASZ, 0); + GO(DT_RELAENT, 0); + GO(DT_STRSZ, 0); + GO(DT_SYMENT, 0); + GO(DT_INIT, 1); + GO(DT_FINI, 1); + GO(DT_SONAME, 0); + GO(DT_RPATH, 0); + GO(DT_SYMBOLIC, 0); + GO(DT_REL, 1); + GO(DT_RELSZ, 0); + GO(DT_RELENT, 0); + GO(DT_PLTREL, 0); + GO(DT_DEBUG, 0); + GO(DT_TEXTREL, 0); + GO(DT_JMPREL, 1); + GO(DT_BIND_NOW, 1); + GO(DT_INIT_ARRAY, 1); + GO(DT_FINI_ARRAY, 1); + GO(DT_INIT_ARRAYSZ, 0); + GO(DT_FINI_ARRAYSZ, 0); + GO(DT_RUNPATH, 0); + GO(DT_FLAGS, 0); + GO(DT_ENCODING, 0); + #if defined(DT_NUM) && defined(DT_TLSDESC_PLT) + GO(DT_NUM, 0); + GO(DT_VALRNGLO, 0); + GO(DT_GNU_PRELINKED, 0); + GO(DT_GNU_CONFLICTSZ, 0); + GO(DT_GNU_LIBLISTSZ, 0); + GO(DT_CHECKSUM, 0); + GO(DT_PLTPADSZ, 0); + GO(DT_MOVEENT, 0); + GO(DT_MOVESZ, 0); + GO(DT_FEATURE_1, 0); + GO(DT_POSFLAG_1, 0); + GO(DT_SYMINSZ, 0); + GO(DT_SYMINENT, 0); + GO(DT_ADDRRNGLO, 0); + GO(DT_GNU_HASH, 0); + GO(DT_TLSDESC_PLT, 0); + GO(DT_TLSDESC_GOT, 0); + GO(DT_GNU_CONFLICT, 0); + GO(DT_GNU_LIBLIST, 0); + GO(DT_CONFIG, 0); + GO(DT_DEPAUDIT, 0); + GO(DT_AUDIT, 0); + GO(DT_PLTPAD, 0); + GO(DT_MOVETAB, 0); + GO(DT_SYMINFO, 0); + GO(DT_VERSYM, 0); + GO(DT_RELACOUNT, 0); + GO(DT_RELCOUNT, 0); + GO(DT_FLAGS_1, 0); + GO(DT_VERDEF, 0); + GO(DT_VERDEFNUM, 0); + GO(DT_VERNEED, 0); + GO(DT_VERNEEDNUM, 0); + GO(DT_AUXILIARY, 0); + GO(DT_FILTER, 0); + #endif + #undef GO + default: + sprintf(buff, "0x%X unknown type", s->d_tag); + } + return buff; +} + +static const char* DumpPHEntry(Elf32_Phdr *e) +{ + static char buff[500]; + memset(buff, 0, sizeof(buff)); + switch(e->p_type) { + case PT_NULL: sprintf(buff, "type: %s", "PT_NULL"); break; + #define GO(T) case T: sprintf(buff, "type: %s, Off=%x vaddr=%p paddr=%p filesz=%u memsz=%u flags=%x align=%u", #T, e->p_offset, from_ptrv(e->p_vaddr), from_ptrv(e->p_paddr), e->p_filesz, e->p_memsz, e->p_flags, e->p_align); break + GO(PT_LOAD); + GO(PT_DYNAMIC); + GO(PT_INTERP); + GO(PT_NOTE); + GO(PT_SHLIB); + GO(PT_PHDR); + GO(PT_TLS); + #ifdef PT_NUM + GO(PT_NUM); + GO(PT_LOOS); + GO(PT_GNU_EH_FRAME); + GO(PT_GNU_STACK); + GO(PT_GNU_RELRO); + #endif + #undef GO + default: sprintf(buff, "type: %x, Off=%x vaddr=%p paddr=%p filesz=%u memsz=%u flags=%x align=%u", e->p_type, e->p_offset, from_ptrv(e->p_vaddr), from_ptrv(e->p_paddr), e->p_filesz, e->p_memsz, e->p_flags, e->p_align); break; + } + return buff; +} + +const char* DumpRelType32(int t) +{ + static char buff[50]; + memset(buff, 0, sizeof(buff)); + switch(t) { + #define GO(T) case T: sprintf(buff, "type: %s", #T); break + GO(R_386_NONE); + GO(R_386_32); + GO(R_386_PC32); + GO(R_386_GOT32); + GO(R_386_PLT32); + GO(R_386_COPY); + GO(R_386_GLOB_DAT); + GO(R_386_JMP_SLOT); + GO(R_386_RELATIVE); + GO(R_386_GOTOFF); + GO(R_386_GOTPC); + GO(R_386_PC8); + GO(R_386_TLS_TPOFF); + GO(R_386_TLS_GD_32); + GO(R_386_TLS_DTPMOD32); + GO(R_386_TLS_DTPOFF32); + GO(R_386_TLS_TPOFF32); + #undef GO + default: sprintf(buff, "type: 0x%x (unknown)", t); break; + } + return buff; +} + +static const char* DumpSym(elfheader_t *h, Elf32_Sym* sym, int version) +{ + static char buff[4096]; + const char* vername = (version==-1)?"(none)":((version==0)?"*local*":((version==1)?"*global*":GetSymbolVersion(h, version))); + memset(buff, 0, sizeof(buff)); + sprintf(buff, "\"%s\", value=%p, size=%d, info/other=%d/%d index=%d (ver=%d/%s)", + h->DynStr+sym->st_name, from_ptrv(sym->st_value), sym->st_size, + sym->st_info, sym->st_other, sym->st_shndx, version, vername); + return buff; +} + +const char* SymName32(elfheader_t *h, Elf32_Sym* sym) +{ + return h->DynStr+sym->st_name; +} +static const char* IdxSymName(elfheader_t *h, int sym) +{ + return h->DynStr+h->DynSym._32[sym].st_name; +} + +void DumpMainHeader32(Elf32_Ehdr *header, elfheader_t *h) +{ + if(box64_dump) { + printf_dump(LOG_NEVER, "ELF Dump main header\n"); + printf_dump(LOG_NEVER, " Entry point = %p\n", from_ptrv(header->e_entry)); + printf_dump(LOG_NEVER, " Program Header table offset = %p\n", from_ptrv(header->e_phoff)); + printf_dump(LOG_NEVER, " Section Header table offset = %p\n", from_ptrv(header->e_shoff)); + printf_dump(LOG_NEVER, " Flags = 0x%X\n", header->e_flags); + printf_dump(LOG_NEVER, " ELF Header size = %d\n", header->e_ehsize); + printf_dump(LOG_NEVER, " Program Header Entry num/size = %d(%d)/%d\n", h->numPHEntries, header->e_phnum, header->e_phentsize); + printf_dump(LOG_NEVER, " Section Header Entry num/size = %d(%d)/%d\n", h->numSHEntries, header->e_shnum, header->e_shentsize); + printf_dump(LOG_NEVER, " Section Header index num = %d(%d)\n", h->SHIdx, header->e_shstrndx); + printf_dump(LOG_NEVER, "ELF Dump ==========\n"); + + printf_dump(LOG_NEVER, "ELF Dump PEntries (%d)\n", h->numSHEntries); + for (int i=0; i<h->numPHEntries; ++i) + printf_dump(LOG_NEVER, " PHEntry %04d : %s\n", i, DumpPHEntry(h->PHEntries._32+i)); + printf_dump(LOG_NEVER, "ELF Dump PEntries ====\n"); + + printf_dump(LOG_NEVER, "ELF Dump Sections (%d)\n", h->numSHEntries); + for (int i=0; i<h->numSHEntries; ++i) + printf_dump(LOG_NEVER, " Section %04d : %s\n", i, DumpSection(h->SHEntries._32+i, h->SHStrTab)); + printf_dump(LOG_NEVER, "ELF Dump Sections ====\n"); + } +} + +void DumpSymTab32(elfheader_t *h) +{ + if(box64_dump && h->SymTab._32) { + const char* name = ElfName(h); + printf_dump(LOG_NEVER, "ELF Dump SymTab(%d)=\n", h->numSymTab); + for (int i=0; i<h->numSymTab; ++i) + printf_dump(LOG_NEVER, " %s:SymTab[%d] = \"%s\", value=%p, size=%d, info/other=%d/%d index=%d\n", name, + i, h->StrTab+h->SymTab._32[i].st_name, from_ptrv(h->SymTab._32[i].st_value), h->SymTab._32[i].st_size, + h->SymTab._32[i].st_info, h->SymTab._32[i].st_other, h->SymTab._32[i].st_shndx); + printf_dump(LOG_NEVER, "ELF Dump SymTab=====\n"); + } +} + +void DumpDynamicSections32(elfheader_t *h) +{ + if(box64_dump && h->Dynamic._32) { + printf_dump(LOG_NEVER, "ELF Dump Dynamic(%d)=\n", h->numDynamic); + for (int i=0; i<h->numDynamic; ++i) + printf_dump(LOG_NEVER, " Dynamic %04d : %s\n", i, DumpDynamic(h->Dynamic._32+i)); + printf_dump(LOG_NEVER, "ELF Dump Dynamic=====\n"); + } +} + +void DumpDynSym32(elfheader_t *h) +{ + if(box64_dump && h->DynSym._32) { + const char* name = ElfName(h); + printf_dump(LOG_NEVER, "ELF Dump DynSym(%d)=\n", h->numDynSym); + for (int i=0; i<h->numDynSym; ++i) { + int version = h->VerSym?((Elf32_Half*)((uintptr_t)h->VerSym+h->delta))[i]:-1; + printf_dump(LOG_NEVER, " %s:DynSym[%d] = %s\n", name, i, DumpSym(h, h->DynSym._32+i, version)); + } + printf_dump(LOG_NEVER, "ELF Dump DynSym=====\n"); + } +} + +void DumpDynamicNeeded32(elfheader_t *h) +{ + if(box64_dump && h->DynStrTab) { + printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n"); + for (int i=0; i<h->numDynamic; ++i) + if(h->Dynamic._32[i].d_tag==DT_NEEDED) { + printf_dump(LOG_NEVER, " Needed : %s\n", h->DynStrTab+h->Dynamic._32[i].d_un.d_val + h->delta); + } + printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n"); + } +} + +void DumpDynamicRPath32(elfheader_t *h) +{ + if(box64_dump && h->DynStrTab) { + printf_dump(LOG_NEVER, "ELF Dump DT_RPATH/DT_RUNPATH=====\n"); + for (int i=0; i<h->numDynamic; ++i) { + if(h->Dynamic._32[i].d_tag==DT_RPATH) { + printf_dump(LOG_NEVER, " RPATH : %s\n", h->DynStrTab+h->Dynamic._32[i].d_un.d_val + h->delta); + } + if(h->Dynamic._32[i].d_tag==DT_RUNPATH) { + printf_dump(LOG_NEVER, " RUNPATH : %s\n", h->DynStrTab+h->Dynamic._32[i].d_un.d_val + h->delta); + } + } + printf_dump(LOG_NEVER, "=====ELF Dump DT_RPATH/DT_RUNPATH\n"); + } +} + +void DumpRelTable32(elfheader_t *h, int cnt, Elf32_Rel *rel, const char* name) +{ + if(box64_dump) { + const char* elfname = ElfName(h); + printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, rel); + for (int i = 0; i<cnt; ++i) + printf_dump(LOG_NEVER, " %s:Rel[%d] = %p (0x%X: %s, sym=0x%0X/%s)\n", elfname, + i, from_ptrv(rel[i].r_offset), rel[i].r_info, DumpRelType32(ELF32_R_TYPE(rel[i].r_info)), + ELF32_R_SYM(rel[i].r_info), IdxSymName(h, ELF32_R_SYM(rel[i].r_info))); + printf_dump(LOG_NEVER, "ELF Dump %s Table=====\n", name); + } +} + +void DumpRelATable32(elfheader_t *h, int cnt, Elf32_Rela *rela, const char* name) +{ + if(box64_dump && h->rela) { + const char* elfname = ElfName(h); + printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, rela); + for (int i = 0; i<cnt; ++i) + printf_dump(LOG_NEVER, " %s:RelA[%d] = %p (0x%X: %s, sym=0x%X/%s) Addend=%d\n", elfname, + i, from_ptrv(rela[i].r_offset), rela[i].r_info, DumpRelType32(ELF32_R_TYPE(rela[i].r_info)), + ELF32_R_SYM(rela[i].r_info), IdxSymName(h, ELF32_R_SYM(rela[i].r_info)), + rela[i].r_addend); + printf_dump(LOG_NEVER, "ELF Dump %s Table=====\n", name); + } +} + +void DumpRelRTable32(elfheader_t *h, int cnt, Elf32_Relr *relr, const char* name) +{ + if(box64_dump && h->relr) { + const char* elfname = ElfName(h); + printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, relr); + for (int i = 0; i<cnt; ++i) + printf_dump(LOG_NEVER, " %s:%s[%d] = %p\n", elfname, name, + i, from_ptrv(relr[i])); + printf_dump(LOG_NEVER, "ELF Dump %s Table=====\n", name); + } +} + diff --git a/src/elfs/elfloader.c b/src/elfs/elfloader.c index 20fa13c0..beeacbfb 100644 --- a/src/elfs/elfloader.c +++ b/src/elfs/elfloader.c @@ -55,7 +55,7 @@ int getElfIndex(box64context_t* ctx, elfheader_t* head) { elfheader_t* LoadAndCheckElfHeader(FILE* f, const char* name, int exec) { - elfheader_t *h = ParseElfHeader64(f, name, exec); + elfheader_t *h = box64_is32bits?ParseElfHeader32(f, name, exec):ParseElfHeader64(f, name, exec); if(!h) return NULL; diff --git a/src/elfs/elfloader_private.h b/src/elfs/elfloader_private.h index d881149a..3743ce25 100644 --- a/src/elfs/elfloader_private.h +++ b/src/elfs/elfloader_private.h @@ -198,6 +198,7 @@ typedef struct elfheader_s { #define ELF64_ST_VISIBILITY(o) ((o) & 0x03) #endif +elfheader_t* ParseElfHeader32(FILE* f, const char* name, int exec); elfheader_t* ParseElfHeader64(FILE* f, const char* name, int exec); const char* BindSym(int bind); diff --git a/src/elfs/elfparser.c b/src/elfs/elfparser.c index 8f51e8c3..c9919123 100644 --- a/src/elfs/elfparser.c +++ b/src/elfs/elfparser.c @@ -61,6 +61,9 @@ static void LoadNamedSection(FILE *f, Elf64_Shdr *s, int size, char* SHStrTab, c } } +#ifndef BOX32 +elfheader_t* ParseElfHeader32(FILE* f, const char* name, int exec) { return NULL; } +#endif elfheader_t* ParseElfHeader64(FILE* f, const char* name, int exec) { Elf64_Ehdr header; diff --git a/src/elfs/elfparser32.c b/src/elfs/elfparser32.c new file mode 100755 index 00000000..b4bb78e4 --- /dev/null +++ b/src/elfs/elfparser32.c @@ -0,0 +1,466 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <elf.h> + +#include "box64version.h" +#include "elfloader.h" +#include "debug.h" +#include "elfload_dump.h" +#include "elfloader_private.h" +#include "box32.h" + +#ifndef PN_XNUM +#define PN_XNUM (0xffff) +#endif + +static int LoadSH(FILE *f, Elf32_Shdr *s, void** SH, const char* name, uint32_t type) +{ + if(type && (s->sh_type != type)) { + printf_log(LOG_INFO, "Section Header \"%s\" (off=%d, size=%d) has incorect type (%d != %d)\n", name, s->sh_offset, s->sh_size, s->sh_type, type); + return -1; + } + if (type==SHT_SYMTAB && s->sh_size%sizeof(Elf32_Sym)) { + printf_log(LOG_INFO, "Section Header \"%s\" (off=%d, size=%d) has size (not multiple of %ld)\n", name, s->sh_offset, s->sh_size, sizeof(Elf32_Sym)); + } + *SH = box_calloc(1, s->sh_size); + fseeko64(f, s->sh_offset ,SEEK_SET); + if(fread(*SH, s->sh_size, 1, f)!=1) { + printf_log(LOG_INFO, "Cannot read Section Header \"%s\" (off=%d, size=%d)\n", name, s->sh_offset, s->sh_size); + return -1; + } + + return 0; +} + +static int FindSection(Elf32_Shdr *s, int n, char* SHStrTab, const char* name) +{ + for (int i=0; i<n; ++i) { + if(s[i].sh_type!=SHT_NULL) + if(!strcmp(SHStrTab+s[i].sh_name, name)) + return i; + } + return 0; +} + +static void LoadNamedSection(FILE *f, Elf32_Shdr *s, int size, char* SHStrTab, const char* name, const char* clearname, uint32_t type, void** what, size_t* num) +{ + int n = FindSection(s, size, SHStrTab, name); + printf_log(LOG_DEBUG, "Loading %s (idx = %d)\n", clearname, n); + if(n) + LoadSH(f, s+n, what, name, type); + if(type==SHT_SYMTAB || type==SHT_DYNSYM) { + if(*what && num) + *num = s[n].sh_size / sizeof(Elf32_Sym); + } else if(type==SHT_DYNAMIC) { + if(*what && num) + *num = s[n].sh_size / sizeof(Elf32_Dyn); + } +} + +elfheader_t* ParseElfHeader32(FILE* f, const char* name, int exec) +{ + Elf32_Ehdr header; + int level = (exec)?LOG_INFO:LOG_DEBUG; + if(fread(&header, sizeof(Elf32_Ehdr), 1, f)!=1) { + printf_log(level, "Cannot read ELF Header\n"); + return NULL; + } + if(memcmp(header.e_ident, ELFMAG, SELFMAG)!=0) { + printf_log(LOG_INFO, "Not an ELF file (sign=%c%c%c%c)\n", header.e_ident[0], header.e_ident[1], header.e_ident[2], header.e_ident[3]); + return NULL; + } + if(header.e_ident[EI_CLASS]!=ELFCLASS32) { + if(header.e_ident[EI_CLASS]==ELFCLASS64) { + printf_log(LOG_INFO, "This is a 64bits ELF! box32 can only run 32bits ELF!\n"); + } else { + printf_log(LOG_INFO, "Not a 32bits ELF (%d)\n", header.e_ident[EI_CLASS]); + } + return NULL; + } + if(header.e_ident[EI_DATA]!=ELFDATA2LSB) { + printf_log(LOG_INFO, "Not a LittleEndian ELF (%d)\n", header.e_ident[EI_DATA]); + return NULL; + } + if(header.e_ident[EI_VERSION]!=EV_CURRENT) { + printf_log(LOG_INFO, "Incorrect ELF version (%d)\n", header.e_ident[EI_VERSION]); + return NULL; + } + if(header.e_ident[EI_OSABI]!=ELFOSABI_LINUX && header.e_ident[EI_OSABI]!=ELFOSABI_NONE && header.e_ident[EI_OSABI]!=ELFOSABI_SYSV) { + printf_log(LOG_INFO, "Not a Linux ELF (%d)\n",header.e_ident[EI_OSABI]); + return NULL; + } + + if(header.e_type != ET_EXEC && header.e_type != ET_DYN) { + printf_log(LOG_INFO, "Not an Executable (%d)\n", header.e_type); + return NULL; + } + + if(header.e_machine != EM_386) { + printf_log(level, "Not an i386 ELF (%d)\n", header.e_machine); + return NULL; + } + + if(header.e_entry == 0 && exec) { + printf_log(LOG_INFO, "No entry point in ELF\n"); + return NULL; + } + if(header.e_phentsize != sizeof(Elf32_Phdr)) { + printf_log(LOG_INFO, "Program Header Entry size incorrect (%d != %ld)\n", header.e_phentsize, sizeof(Elf32_Phdr)); + return NULL; + } + if(header.e_shentsize != sizeof(Elf32_Shdr) && header.e_shentsize != 0) { + printf_log(LOG_INFO, "Section Header Entry size incorrect (%d != %ld)\n", header.e_shentsize, sizeof(Elf32_Shdr)); + return NULL; + } + + elfheader_t *h = box_calloc(1, sizeof(elfheader_t)); + h->name = box_strdup(name); + h->entrypoint = header.e_entry; + h->numPHEntries = header.e_phnum; + h->numSHEntries = header.e_shnum; + h->SHIdx = header.e_shstrndx; + h->e_type = header.e_type; + if(header.e_shentsize && header.e_shnum) { + // special cases for nums + if(h->numSHEntries == 0) { + printf_log(LOG_DEBUG, "Read number of Sections in 1st Section\n"); + // read 1st section header and grab actual number from here + fseeko64(f, header.e_shoff, SEEK_SET); + Elf32_Shdr section; + if(fread(§ion, sizeof(Elf32_Shdr), 1, f)!=1) { + box_free(h); + printf_log(LOG_INFO, "Cannot read Initial Section Header\n"); + return NULL; + } + h->numSHEntries = section.sh_size; + } + // now read all section headers + printf_log(LOG_DEBUG, "Read %d Section header\n", h->numSHEntries); + h->SHEntries._32 = (Elf32_Shdr*)box_calloc(h->numSHEntries, sizeof(Elf32_Shdr)); + fseeko64(f, header.e_shoff ,SEEK_SET); + if(fread(h->SHEntries._32, sizeof(Elf32_Shdr), h->numSHEntries, f)!=h->numSHEntries) { + FreeElfHeader(&h); + printf_log(LOG_INFO, "Cannot read all Section Header\n"); + return NULL; + } + + if(h->numPHEntries == PN_XNUM) { + printf_log(LOG_DEBUG, "Read number of Program Header in 1st Section\n"); + // read 1st section header and grab actual number from here + h->numPHEntries = h->SHEntries._32[0].sh_info; + } + } + + printf_log(LOG_DEBUG, "Read %d Program header\n", h->numPHEntries); + h->PHEntries._32 = (Elf32_Phdr*)box_calloc(h->numPHEntries, sizeof(Elf32_Phdr)); + fseeko64(f, header.e_phoff ,SEEK_SET); + if(fread(h->PHEntries._32, sizeof(Elf32_Phdr), h->numPHEntries, f)!=h->numPHEntries) { + FreeElfHeader(&h); + printf_log(LOG_INFO, "Cannot read all Program Header\n"); + return NULL; + } + + if(header.e_shentsize && header.e_shnum) { + if(h->SHIdx == SHN_XINDEX) { + printf_log(LOG_DEBUG, "Read number of String Table in 1st Section\n"); + h->SHIdx = h->SHEntries._32[0].sh_link; + } + if(h->SHIdx > h->numSHEntries) { + printf_log(LOG_INFO, "Incoherent Section String Table Index : %d / %d\n", h->SHIdx, h->numSHEntries); + FreeElfHeader(&h); + return NULL; + } + // load Section table + printf_log(LOG_DEBUG, "Loading Sections Table String (idx = %d)\n", h->SHIdx); + if(LoadSH(f, h->SHEntries._32+h->SHIdx, (void*)&h->SHStrTab, ".shstrtab", SHT_STRTAB)) { + FreeElfHeader(&h); + return NULL; + } + if(box64_dump) DumpMainHeader32(&header, h); + + LoadNamedSection(f, h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".strtab", "SymTab Strings", SHT_STRTAB, (void**)&h->StrTab, NULL); + LoadNamedSection(f, h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".symtab", "SymTab", SHT_SYMTAB, (void**)&h->SymTab._32, &h->numSymTab); + if(box64_dump && h->SymTab._32) DumpSymTab32(h); + + LoadNamedSection(f, h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".dynamic", "Dynamic", SHT_DYNAMIC, (void**)&h->Dynamic._32, &h->numDynamic); + if(box64_dump && h->Dynamic._32) DumpDynamicSections32(h); + // grab DT_REL & DT_RELA stuffs + // also grab the DT_STRTAB string table + { + for (int i=0; i<h->numDynamic; ++i) { + Elf32_Dyn d = h->Dynamic._32[i]; + Elf32_Word val = d.d_un.d_val; + Elf32_Addr ptr = d.d_un.d_ptr; + switch (d.d_tag) { + case DT_REL: + h->rel = ptr; + break; + case DT_RELSZ: + h->relsz = val; + break; + case DT_RELENT: + h->relent = val; + break; + case DT_RELA: + h->rela = ptr; + break; + case DT_RELASZ: + h->relasz = val; + break; + case DT_RELAENT: + h->relaent = val; + break; + case DT_RELR: + h->relr = ptr; + break; + case DT_RELRSZ: + h->relrsz = val; + break; + case DT_RELRENT: + h->relrent = val; + break; + case DT_PLTGOT: + h->pltgot = ptr; + break; + case DT_PLTREL: + h->pltrel = val; + break; + case DT_PLTRELSZ: + h->pltsz = val; + break; + case DT_JMPREL: + h->jmprel = ptr; + break; + case DT_STRTAB: + h->DynStrTab = (char *)from_ptr(ptr); + break; + case DT_STRSZ: + h->szDynStrTab = val; + break; + case DT_INIT: // Entry point + h->initentry = ptr; + printf_log(LOG_DEBUG, "The DT_INIT is at address %p\n", from_ptrv(h->initentry)); + break; + case DT_INIT_ARRAY: + h->initarray = ptr; + printf_log(LOG_DEBUG, "The DT_INIT_ARRAY is at address %p\n", from_ptrv(h->initarray)); + break; + case DT_INIT_ARRAYSZ: + h->initarray_sz = val / sizeof(Elf32_Addr); + printf_log(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %d\n", h->initarray_sz); + break; + case DT_PREINIT_ARRAYSZ: + if(val) + printf_log(LOG_NONE, "Warning, PreInit Array (size=%d) present and ignored!\n", val); + break; + case DT_FINI: // Exit hook + h->finientry = ptr; + printf_log(LOG_DEBUG, "The DT_FINI is at address %p\n", from_ptrv(h->finientry)); + break; + case DT_FINI_ARRAY: + h->finiarray = ptr; + printf_log(LOG_DEBUG, "The DT_FINI_ARRAY is at address %p\n", from_ptrv(h->finiarray)); + break; + case DT_FINI_ARRAYSZ: + h->finiarray_sz = val / sizeof(Elf32_Addr); + printf_log(LOG_DEBUG, "The DT_FINI_ARRAYSZ is %d\n", h->finiarray_sz); + break; + case DT_VERNEEDNUM: + h->szVerNeed = val; + printf_log(LOG_DEBUG, "The DT_VERNEEDNUM is %d\n", h->szVerNeed); + break; + case DT_VERNEED: + h->VerNeed._32 = (Elf32_Verneed*)from_ptr(ptr); + printf_log(LOG_DEBUG, "The DT_VERNEED is at address %p\n", h->VerNeed); + break; + case DT_VERDEFNUM: + h->szVerDef = val; + printf_log(LOG_DEBUG, "The DT_VERDEFNUM is %d\n", h->szVerDef); + break; + case DT_VERDEF: + h->VerDef._32 = (Elf32_Verdef*)from_ptr(ptr); + printf_log(LOG_DEBUG, "The DT_VERDEF is at address %p\n", h->VerDef); + break; + case DT_HASH: + h->hash = ptr; + printf_dump(LOG_DEBUG, "The DT_HASH is at address %p\n", (void*)h->hash); + break; + case DT_GNU_HASH: + h->gnu_hash = ptr; + printf_dump(LOG_DEBUG, "The DT_GNU_HASH is at address %p\n", (void*)h->gnu_hash); + break; + } + } + if(h->rel) { + if(h->relent != sizeof(Elf32_Rel)) { + printf_log(LOG_NONE, "Rel Table Entry size invalid (0x%x should be 0x%lx)\n", h->relent, sizeof(Elf32_Rel)); + FreeElfHeader(&h); + return NULL; + } + printf_log(LOG_DEBUG, "Rel Table @%p (0x%x/0x%x)\n", from_ptrv(h->rel), h->relsz, h->relent); + } + if(h->rela) { + if(h->relaent != sizeof(Elf32_Rela)) { + printf_log(LOG_NONE, "RelA Table Entry size invalid (0x%x should be 0x%lx)\n", h->relaent, sizeof(Elf32_Rela)); + FreeElfHeader(&h); + return NULL; + } + printf_log(LOG_DEBUG, "RelA Table @%p (0x%x/0x%x)\n", from_ptrv(h->rela), h->relasz, h->relaent); + } + if(h->jmprel) { + if(h->pltrel == DT_REL) { + h->pltent = sizeof(Elf32_Rel); + } else if(h->pltrel == DT_RELA) { + h->pltent = sizeof(Elf32_Rela); + } else { + printf_log(LOG_NONE, "PLT Table type is unknown (size = 0x%x, type=%d)\n", h->pltsz, h->pltrel); + FreeElfHeader(&h); + return NULL; + } + if((h->pltsz / h->pltent)*h->pltent != h->pltsz) { + printf_log(LOG_NONE, "PLT Table Entry size invalid (0x%x, ent=0x%x, type=%d)\n", h->pltsz, h->pltent, h->pltrel); + FreeElfHeader(&h); + return NULL; + } + printf_log(LOG_DEBUG, "PLT Table @%p (type=%d 0x%x/0x%0x)\n", from_ptrv(h->jmprel), h->pltrel, h->pltsz, h->pltent); + } + if(h->DynStrTab && h->szDynStrTab) { + //DumpDynamicNeeded32(h); cannot dump now, it's not loaded yet + } + } + // look for PLT Offset + int ii = FindSection(h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".got.plt"); + if(ii) { + h->gotplt = h->SHEntries._32[ii].sh_addr; + h->gotplt_end = h->gotplt + h->SHEntries._32[ii].sh_size; + printf_log(LOG_DEBUG, "The GOT.PLT Table is at address %p\n", from_ptrv(h->gotplt)); + } + ii = FindSection(h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".got"); + if(ii) { + h->got = h->SHEntries._32[ii].sh_addr; + h->got_end = h->got + h->SHEntries._32[ii].sh_size; + printf_log(LOG_DEBUG, "The GOT Table is at address %p..%p\n", from_ptrv(h->got), from_ptrv(h->got_end)); + } + ii = FindSection(h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".plt"); + if(ii) { + h->plt = h->SHEntries._32[ii].sh_addr; + h->plt_end = h->plt + h->SHEntries._32[ii].sh_size; + printf_log(LOG_DEBUG, "The PLT Table is at address %p..%p\n", from_ptrv(h->plt), from_ptrv(h->plt_end)); + } + // grab version of symbols + ii = FindSection(h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".gnu.version"); + if(ii) { + h->VerSym = (Elf32_Half*)from_ptrv(h->SHEntries._32[ii].sh_addr); + printf_log(LOG_DEBUG, "The .gnu.version is at address %p\n", h->VerSym); + } + // grab .text for main code + ii = FindSection(h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".text"); + if(ii) { + h->text = (uintptr_t)(h->SHEntries._32[ii].sh_addr); + h->textsz = h->SHEntries._32[ii].sh_size; + printf_log(LOG_DEBUG, "The .text is at address %p, and is %d big\n", from_ptrv(h->text), h->textsz); + } + + LoadNamedSection(f, h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".dynstr", "DynSym Strings", SHT_STRTAB, (void**)&h->DynStr, NULL); + LoadNamedSection(f, h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".dynsym", "DynSym", SHT_DYNSYM, (void**)&h->DynSym, &h->numDynSym); + } + + return h; +} + +const char* GetParentSymbolVersion32(elfheader_t* h, int index) +{ + if(!h->VerDef._32 || (index<1)) + return NULL; + Elf32_Verdef *def = (Elf32_Verdef*)((uintptr_t)h->VerDef._32 + h->delta); + while(def) { + if(def->vd_ndx==index) { + if(def->vd_cnt<1) + return NULL; + /*if(def->vd_flags&VER_FLG_BASE) + return NULL;*/ + Elf32_Verdaux *aux = (Elf32_Verdaux*)((uintptr_t)def + def->vd_aux); + return h->DynStr+aux->vda_name; // return Parent, so 1st aux + } + def = def->vd_next?((Elf32_Verdef*)((uintptr_t)def + def->vd_next)):NULL; + } + return NULL; +} + +const char* GetSymbolVersion32(elfheader_t* h, int version) +{ + version&=0x7fff; // remove bit15 that switch between hidden/public + if(!h->VerNeed._32 || (version<2)) + return NULL; + /*if(version==1) + return "*";*/ + Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed._32 + h->delta); + while(ver) { + Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux); + for(int j=0; j<ver->vn_cnt; ++j) { + if(aux->vna_other==version) + return h->DynStr+aux->vna_name; + aux = (Elf32_Vernaux*)((uintptr_t)aux + aux->vna_next); + } + ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL; + } + return GetParentSymbolVersion32(h, version); // if symbol is "internal", use Def table instead +} + +int GetVersionIndice32(elfheader_t* h, const char* vername) +{ + if(!vername) + return 0; + if(h->VerDef._32) { + Elf32_Verdef *def = (Elf32_Verdef*)((uintptr_t)h->VerDef._32 + h->delta); + while(def) { + Elf32_Verdaux *aux = (Elf32_Verdaux*)((uintptr_t)def + def->vd_aux); + if(!strcmp(h->DynStr+aux->vda_name, vername)) + return def->vd_ndx; + def = def->vd_next?((Elf32_Verdef*)((uintptr_t)def + def->vd_next)):NULL; + } + } + return 0; +} + +int GetNeededVersionCnt32(elfheader_t* h, const char* libname) +{ + if(!libname) + return 0; + if(h->VerNeed._32) { + Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed._32 + h->delta); + while(ver) { + char *filename = h->DynStr + ver->vn_file; + Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux); + if(!strcmp(filename, libname)) + return ver->vn_cnt; + ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL; + } + } + return 0; +} + +const char* GetNeededVersionString32(elfheader_t* h, const char* libname, int idx) +{ + if(!libname) + return 0; + if(h->VerNeed._32) { + Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed._32 + h->delta); + while(ver) { + char *filename = h->DynStr + ver->vn_file; + Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux); + if(!strcmp(filename, libname)) { + for(int j=0; j<ver->vn_cnt; ++j) { + if(j==idx) + return h->DynStr+aux->vna_name; + aux = (Elf32_Vernaux*)((uintptr_t)aux + aux->vna_next); + } + return NULL; // idx out of bound, return NULL... + } + ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL; + } + } + return NULL; +} diff --git a/src/elfs/elfparser64.c b/src/elfs/elfparser64.c deleted file mode 100644 index e496ca8b..00000000 --- a/src/elfs/elfparser64.c +++ /dev/null @@ -1,406 +0,0 @@ -#define _GNU_SOURCE -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <elf.h> - -#include "box64version.h" -#include "elfloader.h" -#include "debug.h" -#include "elfload_dump.h" -#include "elfloader_private.h" - -#ifndef PN_XNUM -#define PN_XNUM (0xffff) -#endif -#ifndef DT_GNU_HASH -#define DT_GNU_HASH 0x6ffffef5 -#endif - -static int LoadSH(FILE *f, Elf64_Shdr *s, void** SH, const char* name, uint32_t type) -{ - if(type && (s->sh_type != type)) { - printf_log(LOG_INFO, "Section Header \"%s\" (off=%ld, size=%ld) has incorect type (%d != %d)\n", name, s->sh_offset, s->sh_size, s->sh_type, type); - return -1; - } - if (type==SHT_SYMTAB && s->sh_size%sizeof(Elf64_Sym)) { - printf_log(LOG_INFO, "Section Header \"%s\" (off=%ld, size=%ld) has size (not multiple of %ld)\n", name, s->sh_offset, s->sh_size, sizeof(Elf64_Sym)); - } - *SH = box_calloc(1, s->sh_size); - fseeko64(f, s->sh_offset ,SEEK_SET); - if(fread(*SH, s->sh_size, 1, f)!=1) { - printf_log(LOG_INFO, "Cannot read Section Header \"%s\" (off=%ld, size=%ld)\n", name, s->sh_offset, s->sh_size); - return -1; - } - - return 0; -} - -static int FindSection(Elf64_Shdr *s, int n, char* SHStrTab, const char* name) -{ - for (int i=0; i<n; ++i) { - if(s[i].sh_type!=SHT_NULL) - if(!strcmp(SHStrTab+s[i].sh_name, name)) - return i; - } - return 0; -} - -static void LoadNamedSection(FILE *f, Elf64_Shdr *s, int size, char* SHStrTab, const char* name, const char* clearname, uint32_t type, void** what, size_t* num) -{ - int n = FindSection(s, size, SHStrTab, name); - printf_dump(LOG_DEBUG, "Loading %s (idx = %d)\n", clearname, n); - if(n) - LoadSH(f, s+n, what, name, type); - if(type==SHT_SYMTAB || type==SHT_DYNSYM) { - if(*what && num) - *num = s[n].sh_size / sizeof(Elf64_Sym); - } else if(type==SHT_DYNAMIC) { - if(*what && num) - *num = s[n].sh_size / sizeof(Elf64_Dyn); - } -} - -elfheader_t* ParseElfHeader64(FILE* f, const char* name, int exec) -{ - Elf64_Ehdr header; - int level = (exec)?LOG_INFO:LOG_DEBUG; - if(fread(&header, sizeof(Elf64_Ehdr), 1, f)!=1) { - printf_log(level, "Cannot read ELF Header\n"); - return NULL; - } - if(memcmp(header.e_ident, ELFMAG, SELFMAG)!=0) { - printf_log(LOG_INFO, "Not an ELF file (sign=%c%c%c%c)\n", header.e_ident[0], header.e_ident[1], header.e_ident[2], header.e_ident[3]); - return NULL; - } - if(header.e_ident[EI_CLASS]!=ELFCLASS64) { - if(strstr(name, ".so")) { - // less naging on libs... - printf_dump(LOG_DEBUG, "Not a 64bits ELF (%d)\n", header.e_ident[EI_CLASS]); - return NULL; - } - if(header.e_ident[EI_CLASS]==ELFCLASS32) { - printf_log(LOG_INFO, "This is a 32bits ELF! box64 can only run 64bits ELF (%s)!\n", name); - } else { - printf_log(LOG_INFO, "Not a 64bits ELF (%d)\n", header.e_ident[EI_CLASS]); - } - return NULL; - } - if(header.e_ident[EI_DATA]!=ELFDATA2LSB) { - printf_log(LOG_INFO, "Not a LittleEndian ELF (%d)\n", header.e_ident[EI_DATA]); - return NULL; - } - if(header.e_ident[EI_VERSION]!=EV_CURRENT) { - printf_log(LOG_INFO, "Incorrect ELF version (%d)\n", header.e_ident[EI_VERSION]); - return NULL; - } - if(header.e_ident[EI_OSABI]!=ELFOSABI_LINUX && header.e_ident[EI_OSABI]!=ELFOSABI_NONE && header.e_ident[EI_OSABI]!=ELFOSABI_SYSV) { - printf_log(LOG_INFO, "Not a Linux ELF (%d)\n",header.e_ident[EI_OSABI]); - return NULL; - } - - if(header.e_type != ET_EXEC && header.e_type != ET_DYN) { - printf_log(LOG_INFO, "Not an Executable (%d)\n", header.e_type); - return NULL; - } - - if(header.e_machine != EM_X86_64) { - printf_log(level, "Not an x86_64 ELF (%d)\n", header.e_machine); - return NULL; - } - - if(header.e_entry == 0 && exec) { - printf_log(LOG_INFO, "No entry point in ELF\n"); - return NULL; - } - if(header.e_phentsize != sizeof(Elf64_Phdr)) { - printf_log(LOG_INFO, "Program Header Entry size incorrect (%d != %ld)\n", header.e_phentsize, sizeof(Elf64_Phdr)); - return NULL; - } - if(header.e_shentsize != sizeof(Elf64_Shdr) && header.e_shentsize != 0) { - printf_log(LOG_INFO, "Section Header Entry size incorrect (%d != %ld)\n", header.e_shentsize, sizeof(Elf64_Shdr)); - return NULL; - } - - elfheader_t *head = box_calloc(1, sizeof(elfheader_t)); - elfheader64_t* h = &head->_64; - h->name = box_strdup(name); - h->entrypoint = header.e_entry; - h->numPHEntries = header.e_phnum; - h->numSHEntries = header.e_shnum; - h->SHIdx = header.e_shstrndx; - h->e_type = header.e_type; - // special cases for nums - if(header.e_shentsize && !h->numSHEntries) { - printf_dump(LOG_DEBUG, "Read number of Sections in 1st Section\n"); - // read 1st section header and grab actual number from here - fseeko64(f, header.e_shoff, SEEK_SET); - Elf64_Shdr section; - if(fread(§ion, sizeof(Elf64_Shdr), 1, f)!=1) { - box_free(h); - printf_log(LOG_INFO, "Cannot read Initial Section Header\n"); - return NULL; - } - h->numSHEntries = section.sh_size; - } - if(header.e_shentsize && h->numSHEntries) { - // now read all section headers - printf_dump(LOG_DEBUG, "Read %zu Section header\n", h->numSHEntries); - h->SHEntries = (Elf64_Shdr*)box_calloc(h->numSHEntries, sizeof(Elf64_Shdr)); - fseeko64(f, header.e_shoff ,SEEK_SET); - if(fread(h->SHEntries, sizeof(Elf64_Shdr), h->numSHEntries, f)!=h->numSHEntries) { - FreeElfHeader(&head); - printf_log(LOG_INFO, "Cannot read all Section Header\n"); - return NULL; - } - - if(h->numPHEntries == PN_XNUM) { - printf_dump(LOG_DEBUG, "Read number of Program Header in 1st Section\n"); - // read 1st section header and grab actual number from here - h->numPHEntries = h->SHEntries[0].sh_info; - } - } - - printf_dump(LOG_DEBUG, "Read %zu Program header\n", h->numPHEntries); - h->PHEntries = (Elf64_Phdr*)box_calloc(h->numPHEntries, sizeof(Elf64_Phdr)); - fseeko64(f, header.e_phoff ,SEEK_SET); - if(fread(h->PHEntries, sizeof(Elf64_Phdr), h->numPHEntries, f)!=h->numPHEntries) { - FreeElfHeader(&head); - printf_log(LOG_INFO, "Cannot read all Program Header\n"); - return NULL; - } - - if(header.e_shentsize && header.e_shnum) { - if(h->SHIdx == SHN_XINDEX) { - printf_dump(LOG_DEBUG, "Read number of String Table in 1st Section\n"); - h->SHIdx = h->SHEntries[0].sh_link; - } - if(h->SHIdx > h->numSHEntries) { - printf_log(LOG_INFO, "Incoherent Section String Table Index : %zu / %zu\n", h->SHIdx, h->numSHEntries); - FreeElfHeader(&head); - return NULL; - } - // load Section table - printf_dump(LOG_DEBUG, "Loading Sections Table String (idx = %zu)\n", h->SHIdx); - if(LoadSH(f, h->SHEntries+h->SHIdx, (void*)&h->SHStrTab, ".shstrtab", SHT_STRTAB)) { - FreeElfHeader(&head); - return NULL; - } - if(box64_dump) DumpMainHeader(&header, head); - - LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".strtab", "SymTab Strings", SHT_STRTAB, (void**)&h->StrTab, NULL); - LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".symtab", "SymTab", SHT_SYMTAB, (void**)&h->SymTab, &h->numSymTab); - if(box64_dump && h->SymTab) DumpSymTab64(head); - - LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynamic", "Dynamic", SHT_DYNAMIC, (void**)&h->Dynamic, &h->numDynamic); - if(box64_dump && h->Dynamic) DumpDynamicSections64(h); - // grab DT_REL & DT_RELA stuffs - // also grab the DT_STRTAB string table - { - for (size_t i=0; i<h->numDynamic; ++i) { - Elf64_Dyn d = h->Dynamic[i]; - Elf64_Word val = d.d_un.d_val; - Elf64_Addr ptr = d.d_un.d_ptr; - switch (d.d_tag) { - case DT_REL: - h->rel = ptr; - break; - case DT_RELSZ: - h->relsz = val; - break; - case DT_RELENT: - h->relent = val; - break; - case DT_RELA: - h->rela = ptr; - break; - case DT_RELASZ: - h->relasz = val; - break; - case DT_RELAENT: - h->relaent = val; - break; - case DT_RELR: - h->relr = ptr; - break; - case DT_RELRSZ: - h->relrsz = val; - break; - case DT_RELRENT: - h->relrent = val; - break; - case DT_PLTGOT: - h->pltgot = ptr; - break; - case DT_PLTREL: - h->pltrel = val; - break; - case DT_PLTRELSZ: - h->pltsz = val; - break; - case DT_JMPREL: - h->jmprel = ptr; - break; - case DT_STRTAB: - h->DynStrTab = (char*)(ptr); - break; - case DT_STRSZ: - h->szDynStrTab = val; - break; - case DT_INIT: // Entry point - h->initentry = ptr; - printf_dump(LOG_DEBUG, "The DT_INIT is at address %p\n", (void*)h->initentry); - break; - case DT_INIT_ARRAY: - h->initarray = ptr; - printf_dump(LOG_DEBUG, "The DT_INIT_ARRAY is at address %p\n", (void*)h->initarray); - break; - case DT_INIT_ARRAYSZ: - h->initarray_sz = val / sizeof(Elf64_Addr); - printf_dump(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %zu\n", h->initarray_sz); - break; - case DT_PREINIT_ARRAYSZ: - #ifndef ANDROID - if(val) - printf_log(LOG_NONE, "Warning, PreInit Array (size=%d) present and ignored!\n", val); - #endif - break; - case DT_FINI: // Exit hook - h->finientry = ptr; - printf_dump(LOG_DEBUG, "The DT_FINI is at address %p\n", (void*)h->finientry); - break; - case DT_FINI_ARRAY: - h->finiarray = ptr; - printf_dump(LOG_DEBUG, "The DT_FINI_ARRAY is at address %p\n", (void*)h->finiarray); - break; - case DT_FINI_ARRAYSZ: - h->finiarray_sz = val / sizeof(Elf64_Addr); - printf_dump(LOG_DEBUG, "The DT_FINI_ARRAYSZ is %zu\n", h->finiarray_sz); - break; - case DT_VERNEEDNUM: - h->szVerNeed = val; - printf_dump(LOG_DEBUG, "The DT_VERNEEDNUM is %d\n", h->szVerNeed); - break; - case DT_VERNEED: - h->VerNeed = (Elf64_Verneed*)ptr; - printf_dump(LOG_DEBUG, "The DT_VERNEED is at address %p\n", h->VerNeed); - break; - case DT_VERDEFNUM: - h->szVerDef = val; - printf_dump(LOG_DEBUG, "The DT_VERDEFNUM is %d\n", h->szVerDef); - break; - case DT_VERDEF: - h->VerDef = (Elf64_Verdef*)ptr; - printf_dump(LOG_DEBUG, "The DT_VERDEF is at address %p\n", h->VerDef); - break; - case DT_FLAGS: - h->flags = val; - printf_dump(LOG_DEBUG, "The DT_FLAGS is 0x%x\n", h->flags); - break; - case DT_HASH: - h->hash = ptr; - printf_dump(LOG_DEBUG, "The DT_HASH is at address %p\n", (void*)h->hash); - break; - case DT_GNU_HASH: - h->gnu_hash = ptr; - printf_dump(LOG_DEBUG, "The DT_GNU_HASH is at address %p\n", (void*)h->gnu_hash); - break; - } - } - if(h->rel) { - if(h->relent != sizeof(Elf64_Rel)) { - printf_log(LOG_NONE, "Rel Table Entry size invalid (0x%x should be 0x%zx)\n", h->relent, sizeof(Elf64_Rel)); - FreeElfHeader(&head); - return NULL; - } - printf_dump(LOG_DEBUG, "Rel Table @%p (0x%zx/0x%x)\n", (void*)h->rel, h->relsz, h->relent); - } - if(h->rela) { - if(h->relaent != sizeof(Elf64_Rela)) { - printf_log(LOG_NONE, "RelA Table Entry size invalid (0x%x should be 0x%zx)\n", h->relaent, sizeof(Elf64_Rela)); - FreeElfHeader(&head); - return NULL; - } - printf_dump(LOG_DEBUG, "RelA Table @%p (0x%zx/0x%x)\n", (void*)h->rela, h->relasz, h->relaent); - } - if(h->jmprel) { - if(h->pltrel == DT_REL) { - h->pltent = sizeof(Elf64_Rel); - } else if(h->pltrel == DT_RELA) { - h->pltent = sizeof(Elf64_Rela); - } else { - printf_log(LOG_NONE, "PLT Table type is unknown (size = 0x%zx, type=%ld)\n", h->pltsz, h->pltrel); - FreeElfHeader(&head); - return NULL; - } - if((h->pltsz / h->pltent)*h->pltent != h->pltsz) { - printf_log(LOG_NONE, "PLT Table Entry size invalid (0x%zx, ent=0x%x, type=%ld)\n", h->pltsz, h->pltent, h->pltrel); - FreeElfHeader(&head); - return NULL; - } - printf_dump(LOG_DEBUG, "PLT Table @%p (type=%ld 0x%zx/0x%0x)\n", (void*)h->jmprel, h->pltrel, h->pltsz, h->pltent); - } - } - // look for PLT Offset - int ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".got.plt"); - if(ii) { - h->gotplt = h->SHEntries[ii].sh_addr; - h->gotplt_end = h->gotplt + h->SHEntries[ii].sh_size; - printf_dump(LOG_DEBUG, "The GOT.PLT Table is at address %p\n", (void*)h->gotplt); - } - ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".got"); - if(ii) { - h->got = h->SHEntries[ii].sh_addr; - h->got_end = h->got + h->SHEntries[ii].sh_size; - printf_dump(LOG_DEBUG, "The GOT Table is at address %p..%p\n", (void*)h->got, (void*)h->got_end); - } - ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".plt"); - if(ii) { - h->plt = h->SHEntries[ii].sh_addr; - h->plt_end = h->plt + h->SHEntries[ii].sh_size; - printf_dump(LOG_DEBUG, "The PLT Table is at address %p..%p\n", (void*)h->plt, (void*)h->plt_end); - } - // grab version of symbols - ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".gnu.version"); - if(ii) { - h->VerSym = (Elf64_Half*)(h->SHEntries[ii].sh_addr); - printf_dump(LOG_DEBUG, "The .gnu.version is at address %p\n", h->VerSym); - } - // grab .text for main code - ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".text"); - if(ii) { - h->text = (uintptr_t)(h->SHEntries[ii].sh_addr); - h->textsz = h->SHEntries[ii].sh_size; - printf_dump(LOG_DEBUG, "The .text is at address %p, and is %zu big\n", (void*)h->text, h->textsz); - } - ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".eh_frame"); - if(ii) { - h->ehframe = (uintptr_t)(h->SHEntries[ii].sh_addr); - h->ehframe_end = h->ehframe + h->SHEntries[ii].sh_size; - printf_dump(LOG_DEBUG, "The .eh_frame section is at address %p..%p\n", (void*)h->ehframe, (void*)h->ehframe_end); - } - ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".eh_frame_hdr"); - if(ii) { - h->ehframehdr = (uintptr_t)(h->SHEntries[ii].sh_addr); - printf_dump(LOG_DEBUG, "The .eh_frame_hdr section is at address %p\n", (void*)h->ehframehdr); - } - - LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynstr", "DynSym Strings", SHT_STRTAB, (void**)&h->DynStr, NULL); - LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynsym", "DynSym", SHT_DYNSYM, (void**)&h->DynSym, &h->numDynSym); - } - - return head; -} - -const char* BindSym64(int bind) -{ - switch(bind) { - case STB_GLOBAL: return "STB_GLOBAL"; - case STB_WEAK: return "STB_WEAK"; - case STB_LOCAL: return "STB_LOCAL"; - case STB_GNU_UNIQUE: return "STB_GNU_UNIQUE"; - } - static char tmp[50]; - sprintf(tmp, "??? 0x%x", bind); - return tmp; -} diff --git a/src/include/elfload_dump.h b/src/include/elfload_dump.h index 74906b5e..3fa0a910 100644 --- a/src/include/elfload_dump.h +++ b/src/include/elfload_dump.h @@ -3,16 +3,25 @@ typedef struct elfheader_s elfheader_t; +const char* SymName32(elfheader_t *h, Elf32_Sym* sym); const char* SymName64(elfheader_t *h, Elf64_Sym* sym); +const char* DumpRelType32(int t); const char* DumpRelType64(int t); +void DumpMainHeader32(Elf32_Ehdr *header, elfheader_t *h); void DumpMainHeader64(Elf64_Ehdr *header, elfheader_t *h); +void DumpSymTab32(elfheader_t *h); void DumpSymTab64(elfheader_t *h); +void DumpDynamicSections32(elfheader_t *h); void DumpDynamicSections64(elfheader_t *h); void DumpDynamicNeeded(elfheader_t *h); void DumpDynamicRPath(elfheader_t *h); +void DumpDynSym32(elfheader_t *h); void DumpDynSym64(elfheader_t *h); +void DumpRelTable32(elfheader_t *h, int cnt, Elf32_Rel *rel, const char* name); void DumpRelTable64(elfheader_t *h, int cnt, Elf64_Rel *rel, const char* name); +void DumpRelATable32(elfheader_t *h, int cnt, Elf32_Rela *rela, const char* name); void DumpRelATable64(elfheader_t *h, int cnt, Elf64_Rela *rela, const char* name); +void DumpRelRTable32(elfheader_t *h, int cnt, Elf32_Relr *relr, const char *name); void DumpRelRTable64(elfheader_t *h, int cnt, Elf64_Relr *relr, const char *name); void DumpBinary(char* p, int sz); |