From: norly Date: Wed, 26 Jun 2013 18:57:39 +0000 (+0100) Subject: Separate PLT lookup X-Git-Url: https://git.enpas.org/?p=centaur.git;a=commitdiff_plain;h=95516f950cf67ee154f362425c1472637d9f3e22 Separate PLT lookup --- diff --git a/include/libelfu/modelops.h b/include/libelfu/modelops.h index c0a5851..3ebf0a3 100644 --- a/include/libelfu/modelops.h +++ b/include/libelfu/modelops.h @@ -10,12 +10,11 @@ #define ELFU_SYMSTR(symtabscn, off) ((symtabscn)->linkptr->databuf + (off)) -GElf_Word elfu_mSymtabLookupVal(ElfuElf *me, ElfuScn *msst, GElf_Word entry); -GElf_Word elfu_mSymtabLookupAddrByName(ElfuElf *me, ElfuScn *msst, char *name); -void elfu_mSymtabFlatten(ElfuElf *me); - - -void elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt); + int elfu_mSymtabLookupSymToAddr(ElfuElf *me, ElfuScn *msst, ElfuSym *sym, GElf_Addr *result); + char* elfu_mSymtabSymToName(ElfuScn *msst, ElfuSym *sym); + ElfuSym* elfu_mSymtabIndexToSym(ElfuScn *msst, GElf_Word entry); +GElf_Addr elfu_mSymtabLookupAddrByName(ElfuElf *me, ElfuScn *msst, char *name); + void elfu_mSymtabFlatten(ElfuElf *me); typedef void* (PhdrHandlerFunc)(ElfuElf *me, ElfuPhdr *mp, void *aux1, void *aux2); @@ -54,7 +53,10 @@ GElf_Addr elfu_mLayoutGetSpaceInPhdr(ElfuElf *me, GElf_Word size, int elfu_mLayoutAuto(ElfuElf *me); -void elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt); +int elfu_mDynLookupPltAddrByName(ElfuElf *me, char *name, GElf_Addr *result); + + +int elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt); int elfu_mCheck(ElfuElf *me); @@ -68,7 +70,7 @@ void elfu_mDumpElf(ElfuElf *me); ElfuElf* elfu_mFromElf(Elf *e); void elfu_mToElf(ElfuElf *me, Elf *e); -void elfu_mReladd(ElfuElf *me, const ElfuElf *mrel); + int elfu_mReladd(ElfuElf *me, const ElfuElf *mrel); void elfu_mDetour(ElfuElf *me, GElf_Addr from, GElf_Addr to); diff --git a/src/elfucli.c b/src/elfucli.c index b3ea29f..d5f55be 100644 --- a/src/elfucli.c +++ b/src/elfucli.c @@ -149,8 +149,14 @@ int main(int argc, char **argv) goto ERR; } else { printf("--reladd: Injecting %s...\n", optarg); - elfu_mCheck(mrel); - elfu_mReladd(me, mrel); + if (elfu_mCheck(mrel)) { + printf("--reladd: Check for input file failed.\n"); + goto ERR; + } + if (elfu_mReladd(me, mrel)) { + printf("--reladd: Failed.\n"); + goto ERR; + } printf("--reladd: Injected %s.\n", optarg); } } diff --git a/src/libelfu/model/symtab.c b/src/libelfu/model/symtab.c index 1dd778e..0cf107b 100644 --- a/src/libelfu/model/symtab.c +++ b/src/libelfu/model/symtab.c @@ -4,103 +4,62 @@ #include -static void* subFindByName(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) +int elfu_mSymtabLookupSymToAddr(ElfuElf *me, ElfuScn *msst, ElfuSym *sym, GElf_Addr *result) { - char *name = (char*)aux1; - (void)aux2; + char *symname = ELFU_SYMSTR(msst, sym->name); - 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 *me, char *name) -{ - ElfuScn *relplt; - ElfuScn *plt; - ElfuRel *rel; - GElf_Word j; - - relplt = elfu_mScnForall(me, subFindByName, ".rel.plt", NULL); - if (!relplt) { - /* x86-64 uses .rela.plt instead */ - relplt = elfu_mScnForall(me, subFindByName, ".rela.plt", NULL); - } - if (!relplt) { - ELFU_WARN("dynsymLookupVal: Could not find .rel.plt section in destination ELF.\n"); - return 0; - } + switch (sym->type) { + case STT_NOTYPE: + case STT_OBJECT: + case STT_FUNC: + if (sym->shndx == SHN_UNDEF) { + return -1; + } else if (sym->shndx == SHN_ABS) { + *result = sym->value; + return 0; + } else if (sym->shndx == SHN_COMMON) { + return -1; + } else { + ElfuScn *newscn; - plt = elfu_mScnForall(me, subFindByName, ".plt", NULL); - if (!plt) { - ELFU_WARN("dynsymLookupVal: Could not find .plt section in destination ELF.\n"); - return 0; + assert (sym->scnptr); + newscn = elfu_mScnByOldscn(me, sym->scnptr); + assert(newscn); + *result = newscn->shdr.sh_addr + sym->value; + return 0; + } + break; + case STT_SECTION: + assert(sym->scnptr); + assert(elfu_mScnByOldscn(me, sym->scnptr)); + *result = elfu_mScnByOldscn(me, sym->scnptr)->shdr.sh_addr; + return 0; + case STT_FILE: + ELFU_WARN("elfu_mSymtabLookupSymToAddr: Symbol type FILE is not supported.\n"); + return -1; + default: + ELFU_WARN("elfu_mSymtabLookupSymToAddr: Unknown symbol type %d for %s.\n", sym->type, symname); + return -1; } +} - /* Look up name. If the j-th entry in .rel.plt has the name we are - * looking for, we assume that the (j+1)-th entry in .plt is machine - * code to jump to the function. - * Your mileage may vary, but it works on my GNU binaries. */ - assert(relplt->linkptr); - j = 0; - CIRCLEQ_FOREACH(rel, &relplt->reltab.rels, elem) { - GElf_Word i; - ElfuSym *sym; - char *symname; - - j++; - - /* We only consider runtime relocations for functions. - * Technically, these relocations write the functions' addresses - * to the GOT, not the PLT, after the dynamic linker has found - * them. */ - if ((me->elfclass == ELFCLASS32 && rel->type != R_386_JMP_SLOT) - || (me->elfclass == ELFCLASS64 && rel->type != R_X86_64_JUMP_SLOT)) { - continue; - } - /* Get the (rel->sym)-th symbol from the symbol table that - * .rel.plt points to. */ - sym = CIRCLEQ_FIRST(&relplt->linkptr->symtab.syms); - for (i = 1; i < rel->sym; i++) { - sym = CIRCLEQ_NEXT(sym, elem); - } - - symname = ELFU_SYMSTR(relplt->linkptr, sym->name); - if (!strcmp(symname, 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 %x (PLT entry #%u).\n", name, (unsigned)addr, j); - return addr; - } - } - - ELFU_WARN("dynsymLookupVal: Could not find symbol '%s' in destination ELF.\n", name); +char* elfu_mSymtabSymToName(ElfuScn *msst, ElfuSym *sym) +{ + assert(msst); + assert(sym); - return 0; + return ELFU_SYMSTR(msst, sym->name); } -/* Look up a value in the symbol table section *msst which is in *me. - * If it is not found there, see if we can find it in *me's PLT. */ -GElf_Word elfu_mSymtabLookupVal(ElfuElf *me, ElfuScn *msst, GElf_Word entry) +ElfuSym* elfu_mSymtabIndexToSym(ElfuScn *msst, GElf_Word entry) { GElf_Word i; ElfuSym *sym; - char *symname; - assert(me); assert(msst); assert(entry > 0); assert(!CIRCLEQ_EMPTY(&msst->symtab.syms)); @@ -109,44 +68,14 @@ GElf_Word elfu_mSymtabLookupVal(ElfuElf *me, ElfuScn *msst, GElf_Word entry) for (i = 1; i < entry; i++) { sym = CIRCLEQ_NEXT(sym, elem); } - symname = ELFU_SYMSTR(msst, sym->name); - switch (sym->type) { - case STT_NOTYPE: - case STT_OBJECT: - case STT_FUNC: - if (sym->scnptr) { - ElfuScn *newscn = elfu_mScnByOldscn(me, sym->scnptr); - assert(newscn); - return newscn->shdr.sh_addr + sym->value; - } else if (sym->shndx == SHN_UNDEF) { - /* Look the symbol up in .rel.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(me, symname); - } else if (sym->shndx == SHN_ABS) { - return sym->value; - } else { - ELFU_WARN("symtabLookupVal: Symbol binding COMMON is not supported, using 0.\n"); - return 0; - } - break; - case STT_SECTION: - assert(sym->scnptr); - assert(elfu_mScnByOldscn(me, sym->scnptr)); - return elfu_mScnByOldscn(me, sym->scnptr)->shdr.sh_addr; - case STT_FILE: - ELFU_WARN("symtabLookupVal: Symbol type FILE is not supported, using 0.\n"); - return 0; - default: - ELFU_WARN("symtabLookupVal: Unknown symbol type %d for %s.\n", sym->type, symname); - return 0; - } + return sym; } + /* Look up a value in the symbol table section *msst which is in *me. */ -GElf_Word elfu_mSymtabLookupAddrByName(ElfuElf *me, ElfuScn *msst, char *name) +GElf_Addr elfu_mSymtabLookupAddrByName(ElfuElf *me, ElfuScn *msst, char *name) { ElfuSym *sym; diff --git a/src/libelfu/modelops/dynlookup.c b/src/libelfu/modelops/dynlookup.c new file mode 100644 index 0000000..a2cd3ae --- /dev/null +++ b/src/libelfu/modelops/dynlookup.c @@ -0,0 +1,93 @@ +#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 */ +int elfu_mDynLookupPltAddrByName(ElfuElf *me, char *name, GElf_Addr *result) +{ + ElfuScn *relplt; + ElfuScn *plt; + ElfuRel *rel; + GElf_Word j; + + relplt = elfu_mScnForall(me, subFindByName, ".rel.plt", NULL); + if (!relplt) { + /* x86-64 uses .rela.plt instead */ + relplt = elfu_mScnForall(me, subFindByName, ".rela.plt", NULL); + } + if (!relplt) { + ELFU_WARN("elfu_mDynLookupPltAddr: Could not find .rel.plt section in destination ELF.\n"); + return -1; + } + + plt = elfu_mScnForall(me, subFindByName, ".plt", NULL); + if (!plt) { + ELFU_WARN("elfu_mDynLookupPltAddr: Could not find .plt section in destination ELF.\n"); + return -1; + } + + + /* Look up name. If the j-th entry in .rel.plt has the name we are + * looking for, we assume that the (j+1)-th entry in .plt is machine + * code to jump to the function. + * Your mileage may vary, but it works on my GNU binaries. */ + assert(relplt->linkptr); + j = 0; + CIRCLEQ_FOREACH(rel, &relplt->reltab.rels, elem) { + GElf_Word i; + ElfuSym *sym; + char *symname; + + j++; + + /* We only consider runtime relocations for functions. + * Technically, these relocations write the functions' addresses + * to the GOT, not the PLT, after the dynamic linker has found + * them. */ + if ((me->elfclass == ELFCLASS32 && rel->type != R_386_JMP_SLOT) + || (me->elfclass == ELFCLASS64 && rel->type != R_X86_64_JUMP_SLOT)) { + continue; + } + + /* Get the (rel->sym)-th symbol from the symbol table that + * .rel.plt points to. */ + sym = CIRCLEQ_FIRST(&relplt->linkptr->symtab.syms); + for (i = 1; i < rel->sym; i++) { + sym = CIRCLEQ_NEXT(sym, elem); + } + + symname = ELFU_SYMSTR(relplt->linkptr, sym->name); + if (!strcmp(symname, 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("elfu_mDynLookupPltAddr: Guessing symbol '%s' is in destination memory at %x (PLT entry #%u).\n", name, (unsigned)addr, j); + *result = addr; + return 0; + } + } + + ELFU_WARN("elfu_mDynLookupPltAddr: Could not find symbol '%s' in destination ELF.\n", name); + + return -1; +} diff --git a/src/libelfu/modelops/reladd.c b/src/libelfu/modelops/reladd.c index 55438db..bf3b8ca 100644 --- a/src/libelfu/modelops/reladd.c +++ b/src/libelfu/modelops/reladd.c @@ -210,7 +210,9 @@ static void* subScnAdd2(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2) case SHT_RELA: /* 4 */ case SHT_REL: /* 9 */ /* Relocate. */ - elfu_mRelocate(me, elfu_mScnByOldscn(me, ms->infoptr), ms); + if (elfu_mRelocate(me, elfu_mScnByOldscn(me, ms->infoptr), ms)) { + return (void*)-1; + } break; /* The next section types either do not occur in .o files, or are @@ -328,7 +330,7 @@ static void mergeSymtab(ElfuElf *me, const ElfuElf *mrel) -void elfu_mReladd(ElfuElf *me, const ElfuElf *mrel) +int elfu_mReladd(ElfuElf *me, const ElfuElf *mrel) { assert(me); assert(mrel); @@ -339,8 +341,13 @@ void elfu_mReladd(ElfuElf *me, const ElfuElf *mrel) mergeSymtab(me, mrel); /* Do relocations and other stuff */ - elfu_mScnForall((ElfuElf*)mrel, subScnAdd2, me, NULL); + if (elfu_mScnForall((ElfuElf*)mrel, subScnAdd2, me, NULL)) { + ELFU_WARN("elfu_mReladd: Reladd aborted. Target model is unclean.\n"); + return -1; + } /* Re-layout to accommodate new contents */ elfu_mLayoutAuto(me); + + return 0; } diff --git a/src/libelfu/modelops/relocate.c b/src/libelfu/modelops/relocate.c index 2eada04..7f78524 100644 --- a/src/libelfu/modelops/relocate.c +++ b/src/libelfu/modelops/relocate.c @@ -6,9 +6,10 @@ /* Apply relocation information from section *msrt to data in * section *mstarget (which is stored in *metarget). */ -void elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt) +int elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt) { ElfuRel *rel; + ElfuSym *sym; assert(mstarget); assert(msrt); @@ -20,51 +21,100 @@ void elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt) CIRCLEQ_FOREACH(rel, &msrt->reltab.rels, elem) { Elf32_Word *dest32 = (Elf32_Word*)(mstarget->databuf + rel->offset); Elf64_Word *dest64 = (Elf64_Word*)(mstarget->databuf + rel->offset); + GElf_Addr s; + int haveSymval = 0; + sym = elfu_mSymtabIndexToSym(msrt->linkptr, rel->sym); + assert(sym); + + haveSymval = !elfu_mSymtabLookupSymToAddr(metarget, + msrt->linkptr, + sym, + &s); + if (!haveSymval) { + if (sym->shndx == SHN_UNDEF) { + haveSymval = !elfu_mDynLookupPltAddrByName(metarget, + elfu_mSymtabSymToName(msrt->linkptr, sym), + &s); + } else if (sym->shndx == SHN_COMMON) { + // TODO: Lookup in .rel.dyn + } + } if (metarget->elfclass == ELFCLASS32) { Elf32_Word a32 = rel->addendUsed ? rel->addend : *dest32; Elf32_Addr p32 = mstarget->shdr.sh_addr + rel->offset; - Elf32_Addr s32 = elfu_mSymtabLookupVal(metarget, msrt->linkptr, rel->sym); - switch(rel->type) { - case R_386_NONE: - ELFU_DEBUG("Skipping relocation: R_386_NONE\n"); - break; - case R_386_32: - *dest32 = s32 + a32; - break; - case R_386_PC32: - *dest32 = s32 + a32 - p32; - break; + Elf32_Addr s32 = (Elf32_Addr)s; + switch(metarget->ehdr.e_machine) { + case EM_386: + switch(rel->type) { + case R_386_NONE: + ELFU_DEBUG("Skipping relocation: R_386_NONE\n"); + break; + case R_386_32: + if (!haveSymval) { + goto MISSINGSYM; + } + *dest32 = s32 + a32; + break; + case R_386_PC32: + if (!haveSymval) { + goto MISSINGSYM; + } + *dest32 = s32 + a32 - p32; + break; + default: + ELFU_DEBUG("elfu_mRelocate: Skipping unknown relocation type %d\n", rel->type); + } + break; default: - ELFU_DEBUG("Skipping relocation: Unknown type %d\n", rel->type); + ELFU_WARN("elfu_mRelocate: Unknown machine type. Aborting.\n"); } } else if (metarget->elfclass == ELFCLASS64) { - Elf64_Word a64 = rel->addend; + Elf64_Word a64 = rel->addendUsed ? rel->addend : *dest64; Elf64_Addr p64 = mstarget->shdr.sh_addr + rel->offset; - Elf64_Addr s64 = elfu_mSymtabLookupVal(metarget, msrt->linkptr, rel->sym); - - /* x86-64 only uses RELA with explicit addend. */ - assert(rel->addendUsed); + Elf64_Addr s64 = (Elf64_Addr)s; - switch(rel->type) { - case R_X86_64_NONE: - ELFU_DEBUG("Skipping relocation: R_386_NONE\n"); + switch(metarget->ehdr.e_machine) { + case EM_X86_64: + switch(rel->type) { + case R_X86_64_NONE: + ELFU_DEBUG("Skipping relocation: R_386_NONE\n"); + break; + case R_X86_64_64: + if (!haveSymval) { + goto MISSINGSYM; + } + *dest64 = s64 + a64; + break; + case R_X86_64_PC32: + if (!haveSymval) { + goto MISSINGSYM; + } + *dest32 = s64 + a64 - p64; + break; + case R_X86_64_32: + if (!haveSymval) { + goto MISSINGSYM; + } + *dest32 = s64 + a64; + break; + default: + ELFU_DEBUG("elfu_mRelocate: Skipping unknown relocation type %d", rel->type); + } break; - case R_X86_64_64: - *dest64 = s64 + a64; - break; - case R_X86_64_PC32: - *dest32 = s64 + a64 - p64; - break; - case R_X86_64_32: - *dest32 = s64 + a64; - break; - default: - ELFU_DEBUG("Skipping relocation: Unknown type %d", rel->type); + ELFU_WARN("elfu_mRelocate: Unknown machine type. Aborting.\n"); } } } + + return 0; + + MISSINGSYM: + ELFU_WARN("elfu_mRelocate: Could not resolve symbol %s. Aborting.\n", + elfu_mSymtabSymToName(msrt->linkptr, sym)); + return -1; + }