From a08653637257ceaef8e61d965ab0d6c52b0c697d Mon Sep 17 00:00:00 2001 From: norly Date: Sun, 2 Jun 2013 04:05:30 +0100 Subject: [PATCH] Guess where unknown functions are in .rel.plt --- include/libelfu/types.h | 1 + src/model/fromFile.c | 3 ++ src/model/layout.c | 6 +++ src/model/reladd.c | 6 +-- src/model/relocate.c | 96 ++++++++++++++++++++++++++++++++++++++--- 5 files changed, 103 insertions(+), 9 deletions(-) diff --git a/include/libelfu/types.h b/include/libelfu/types.h index 2a0fcf3..b216e53 100644 --- a/include/libelfu/types.h +++ b/include/libelfu/types.h @@ -61,6 +61,7 @@ typedef struct ElfuSym { unsigned char other; ElfuScn *scnptr; + int shndx; CIRCLEQ_ENTRY(ElfuSym) elem; } ElfuSym; diff --git a/src/model/fromFile.c b/src/model/fromFile.c index 84ec143..23105e6 100644 --- a/src/model/fromFile.c +++ b/src/model/fromFile.c @@ -52,12 +52,14 @@ static ElfuSymtab* symtabFromScn32(ElfuScn *ms, ElfuScn**origScnArr) case SHN_ABS: case SHN_COMMON: sym->scnptr = NULL; + sym->shndx = cursym->st_shndx; break; default: sym->scnptr = origScnArr[cursym->st_shndx - 1]; break; } + CIRCLEQ_INSERT_TAIL(&st->syms, sym, elem); } @@ -404,6 +406,7 @@ ElfuElf* elfu_mFromElf(Elf *e) switch (ms->shdr.sh_type) { case SHT_SYMTAB: + case SHT_DYNSYM: if (me->elfclass == ELFCLASS32) { ms->symtab = symtabFromScn32(ms, secArray); } else if (me->elfclass == ELFCLASS64) { diff --git a/src/model/layout.c b/src/model/layout.c index d5d49d8..e4b3fb1 100644 --- a/src/model/layout.c +++ b/src/model/layout.c @@ -82,6 +82,12 @@ GElf_Addr elfu_mLayoutGetSpaceInPhdr(ElfuElf *me, GElf_Word size, assert(!(w && x)); + /* Treat read-only data as executable. + * That's what the GNU toolchain does on x86. */ + if (!w && !x) { + x = 1; + } + /* Find first and last LOAD PHDRs. * Don't compare p_memsz - segments don't overlap in memory. */ CIRCLEQ_FOREACH(mp, &me->phdrList, elem) { diff --git a/src/model/reladd.c b/src/model/reladd.c index a3ccc99..80f106f 100644 --- a/src/model/reladd.c +++ b/src/model/reladd.c @@ -111,10 +111,10 @@ static ElfuScn* insertSection(ElfuElf *me, ElfuElf *mrel, ElfuScn *oldscn) return newscn; } else { - ELFU_WARN("insertSection: Skipping section %s with flags %jd (type %d).\n", + ELFU_WARN("insertSection: Skipping non-memory section %s (type %d flags %jd).\n", elfu_mScnName(mrel, oldscn), - oldscn->shdr.sh_flags, - oldscn->shdr.sh_type); + oldscn->shdr.sh_type, + oldscn->shdr.sh_flags); goto ERROR; } diff --git a/src/model/relocate.c b/src/model/relocate.c index 1b4f9ff..972bda3 100644 --- a/src/model/relocate.c +++ b/src/model/relocate.c @@ -1,8 +1,86 @@ #include #include +#include #include +static void* subFindByName(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) +{ + char *name = (char*)aux1; + (void)aux2; + + if (elfu_mScnName(me, ms)) { + if (!strcmp(elfu_mScnName(me, ms), name)) { + return ms; + } + } + + /* Continue */ + return NULL; +} + +/* Hazard a guess where a function may be found in the PLT */ +static GElf_Word pltLookupVal(ElfuElf *metarget, char *name) +{ + ElfuScn *relplt; + ElfuScn *plt; + ElfuRel *rel; + GElf_Word j; + + relplt = elfu_mScnForall(metarget, subFindByName, ".rel.plt", NULL); + if (!relplt) { + ELFU_WARN("dynsymLookupVal: Could not find .rel.plt section in destination ELF.\n"); + return 0; + } + + plt = elfu_mScnForall(metarget, subFindByName, ".plt", NULL); + if (!plt) { + ELFU_WARN("dynsymLookupVal: Could not find .plt section in destination ELF.\n"); + return 0; + } + + + /* Look up name */ + assert(relplt->reltab); + assert(relplt->linkptr); + assert(relplt->linkptr->symtab); + j = 0; + CIRCLEQ_FOREACH(rel, &relplt->reltab->rels, elem) { + GElf_Word i; + ElfuSym *sym; + + j++; + + if (rel->type != R_386_JMP_SLOT) { + continue; + } + + sym = CIRCLEQ_FIRST(&relplt->linkptr->symtab->syms); + for (i = 1; i < rel->sym; i++) { + sym = CIRCLEQ_NEXT(sym, elem); + } + + if (!sym->name) { + continue; + } + + if (!strcmp(sym->name, name)) { + /* If this is the symbol we are looking for, then in an x86 binary + * the jump to the dynamic symbol is probably at offset (j * 16) + * from the start of the PLT, where j is the PLT entry and 16 is + * the number of bytes the machine code in a PLT entry take. */ + GElf_Addr addr = plt->shdr.sh_addr + (16 * j); + ELFU_DEBUG("dynsymLookupVal: Guessing symbol '%s' is in destination memory at %jx (PLT entry #%d).\n", name, addr, j); + return addr; + } + } + + ELFU_WARN("dynsymLookupVal: Could not find symbol '%s' in destination ELF.\n", name); + + return 0; +} + + static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word entry) { GElf_Word i; @@ -26,9 +104,16 @@ static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word ent if (sym->scnptr) { assert(elfu_mScnByOldscn(metarget, sym->scnptr)); return elfu_mScnByOldscn(metarget, sym->scnptr)->shdr.sh_addr + sym->value; + } else if (sym->shndx == SHN_UNDEF) { + /* Look the symbol up in .dyn.plt. If it cannot be found there then + * .rel.dyn may need to be expanded with a COPY relocation so the + * dynamic linker fixes up the (TODO). */ + return pltLookupVal(metarget, sym->name); + } else if (sym->shndx == SHN_ABS) { + return sym->value; } else { - // TODO: UNDEF, ABS, or COMMON - ELFU_WARN("symtabLookupVal: Returning 0 for UNDEF, ABS, or COMMON symbol.\n"); + ELFU_WARN("symtabLookupVal: Symbol binding COMMON is not supported, using 0.\n"); + return 0; } break; case STT_SECTION: @@ -36,11 +121,10 @@ static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word ent assert(elfu_mScnByOldscn(metarget, sym->scnptr)); return elfu_mScnByOldscn(metarget, sym->scnptr)->shdr.sh_addr; case STT_FILE: - // TODO - ELFU_WARN("symtabLookupVal: Returning 0 for FILE symbol.\n"); - break; + ELFU_WARN("symtabLookupVal: Symbol type FILE is not supported, using 0.\n"); + return 0; default: - ELFU_WARN("symtabLookupVal: Unknown symbol type %d.\n", sym->type); + ELFU_WARN("symtabLookupVal: Unknown symbol type %d for %s.\n", sym->type, sym->name); return 0; } } -- 2.30.2