From: norly Date: Tue, 18 Jun 2013 07:47:33 +0000 (+0100) Subject: Basic detour support X-Git-Url: https://git.enpas.org/?p=centaur.git;a=commitdiff_plain;h=c98d704a812502c34d82e34949f37c8b87ae6018 Basic detour support --- diff --git a/include/libelfu/modelops.h b/include/libelfu/modelops.h index cf11b20..fec6821 100644 --- a/include/libelfu/modelops.h +++ b/include/libelfu/modelops.h @@ -11,6 +11,7 @@ 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); @@ -54,4 +55,6 @@ ElfuElf* elfu_mFromElf(Elf *e); void elfu_mReladd(ElfuElf *me, const ElfuElf *mrel); +void elfu_mDetour(ElfuElf *me, GElf_Addr from, GElf_Addr to); + #endif diff --git a/src/elfucli.c b/src/elfucli.c index 0fd5a2d..cd8f0ba 100644 --- a/src/elfucli.c +++ b/src/elfucli.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -19,6 +20,7 @@ static void printUsage(char *progname) " -c, --check Do a few sanity checks and print any errors\n" " -d, --dump Dump current model state (debug only)\n" " --reladd obj.o Insert object file contents\n" + " --detour from,to Write a jump to at \n" " -o, --output outfile Where to write the modified ELF file to\n" "\n"); } @@ -42,6 +44,7 @@ int main(int argc, char **argv) {"input", 1, 0, 'i'}, {"output", 1, 0, 'o'}, {"reladd", 1, 0, 10001}, + {"detour", 1, 0, 10002}, {NULL, 0, NULL, 0} }; @@ -148,6 +151,41 @@ int main(int argc, char **argv) } } break; + case 10002: + if (!me) { + goto ERR_NO_INPUT; + } else { + GElf_Addr from; + GElf_Addr to; + char *second; + + strtok_r(optarg, ",", &second); + printf("--detour: From '%s' to '%s'\n", optarg, second); + + + from = strtoul(optarg, NULL, 0); + if (from == 0) { + from = elfu_mSymtabLookupAddrByName(me, me->symtab, optarg); + } + if (from == 0) { + printf("--detour: Cannot parse argument 1, aborting.\n"); + goto ERR; + } + printf("--detour: From %x\n", (unsigned)from); + + to = strtoul(second, NULL, 0); + if (to == 0) { + to = elfu_mSymtabLookupAddrByName(me, me->symtab, second); + } + if (to == 0) { + printf("--detour: Cannot parse argument 2, aborting.\n"); + goto ERR; + } + printf("--detour: To %x\n", (unsigned)to); + + elfu_mDetour(me, from, to); + } + break; case '?': default: printUsage(progname); diff --git a/src/modelops/detour.c b/src/modelops/detour.c new file mode 100644 index 0000000..075d945 --- /dev/null +++ b/src/modelops/detour.c @@ -0,0 +1,51 @@ +#include +#include + +static void* subFindByAddr(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) +{ + GElf_Addr a = *(GElf_Addr*)aux1; + + if (OVERLAPPING(ms->shdr.sh_addr, ms->shdr.sh_size, a, 1)) { + return ms; + } + + /* Continue */ + return NULL; +} + + +void elfu_mDetour(ElfuElf *me, GElf_Addr from, GElf_Addr to) +{ + ElfuScn *ms; + GElf_Word scnoffset; + unsigned char detourcode[] = {0xe9, 0xfc, 0xff, 0xff, 0xff}; + + ms = elfu_mScnForall(me, subFindByAddr, &from, NULL); + + if (!ms) { + ELFU_WARN("mDetour: Cannot find address %x in any section.\n", + (unsigned)from); + return; + } + + if (ms->shdr.sh_type != SHT_PROGBITS) { + ELFU_WARN("mDetour: Cannot detour in non-PROGBITS section %s.\n", + elfu_mScnName(me, ms)); + return; + } + + scnoffset = from - ms->shdr.sh_addr; + + if (ms->shdr.sh_size - scnoffset < 5) { + ELFU_WARN("mDetour: Not enough space to insert a detour.\n"); + return; + } + + ELFU_DEBUG("mDetour: Detouring at address %x in section %s to %x.\n", + (unsigned)from, + elfu_mScnName(me, ms), + (unsigned)to); + + *(Elf32_Word*)(detourcode + 1) = to - from - 5; + memcpy((char*)ms->data.d_buf + scnoffset, detourcode, 5); +} diff --git a/src/modelops/symtab.c b/src/modelops/symtab.c index e62871f..ef8443f 100644 --- a/src/modelops/symtab.c +++ b/src/modelops/symtab.c @@ -141,6 +141,52 @@ GElf_Word elfu_mSymtabLookupVal(ElfuElf *me, ElfuScn *msst, GElf_Word entry) } +/* Look up a value in the symbol table section *msst which is in *me. */ +GElf_Word elfu_mSymtabLookupAddrByName(ElfuElf *me, ElfuScn *msst, char *name) +{ + ElfuSym *sym; + + assert(me); + assert(msst); + assert(name); + assert(strlen(name) > 0); + assert(!CIRCLEQ_EMPTY(&msst->symtab.syms)); + + CIRCLEQ_FOREACH(sym, &msst->symtab.syms, elem) { + char *symname = ELFU_SYMSTR(msst, sym->name); + + if (!strcmp(symname, name)) { + goto SYMBOL_FOUND; + } + } + return 0; + + + SYMBOL_FOUND: + + switch (sym->type) { + case STT_NOTYPE: + case STT_OBJECT: + case STT_FUNC: + if (sym->scnptr) { + GElf_Addr a = sym->value; + a += me->ehdr.e_type == ET_REL ? sym->scnptr->shdr.sh_addr : 0; + return a; + } else if (sym->shndx == SHN_UNDEF) { + return 0; + } else if (sym->shndx == SHN_ABS) { + return sym->value; + } else { + ELFU_WARN("elfu_mSymtabLookupAddrByName: Symbol binding COMMON is not supported, using 0.\n"); + return 0; + } + break; + default: + return 0; + } +} + + /* Convert symtab from memory model to elfclass specific format */ void elfu_mSymtabFlatten(ElfuElf *me)