From: norly Date: Thu, 20 Jun 2013 18:02:44 +0000 (+0100) Subject: Clean up code using ElfuScn X-Git-Url: https://git.enpas.org/?p=centaur.git;a=commitdiff_plain;h=70b271e345debda7437c18f86c0f715a42a8267a Clean up code using ElfuScn --- diff --git a/Makefile b/Makefile index e063a29..8cef4c9 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ LIBOBJS := $(patsubst %.c, $(BUILDDIR)/%.o, $(LIBSRCS)) EXEOBJS := $(patsubst %.c, $(BUILDDIR)/%.o, $(EXESRCS)) INCLUDES := $(patsubst %, -I%, $(INCLUDEDIR) $(SRCDIR)) $(shell pkg-config --cflags-only-I $(LIBRARIES)) -CFLAGS := -g -Wall -pedantic -Wno-variadic-macros -fPIC $(shell pkg-config --cflags-only-other $(LIBRARIES)) +CFLAGS := -g -Wall -std=gnu99 -pedantic -fPIC $(shell pkg-config --cflags-only-other $(LIBRARIES)) LDFLAGS := $(shell pkg-config --libs $(LIBRARIES)) diff --git a/include/libelfu/modelops.h b/include/libelfu/modelops.h index fec6821..4dacd43 100644 --- a/include/libelfu/modelops.h +++ b/include/libelfu/modelops.h @@ -7,7 +7,7 @@ #include -#define ELFU_SYMSTR(symtabscn, off) (((char*)(symtabscn)->linkptr->data.d_buf) + (off)) +#define ELFU_SYMSTR(symtabscn, off) ((symtabscn)->linkptr->databuf + (off)) GElf_Word elfu_mSymtabLookupVal(ElfuElf *me, ElfuScn *msst, GElf_Word entry); @@ -29,6 +29,7 @@ typedef void* (SectionHandlerFunc)(ElfuElf *me, ElfuScn *ms, void *aux1, void *a ElfuScn* elfu_mScnByOldscn(ElfuElf *me, ElfuScn *oldscn); char* elfu_mScnName(ElfuElf *me, ElfuScn *ms); ElfuScn** elfu_mScnSortedByOffset(ElfuElf *me, size_t *count); +ElfuScn* elfu_mScnAlloc(); GElf_Addr elfu_mLayoutGetSpaceInPhdr(ElfuElf *me, GElf_Word size, diff --git a/include/libelfu/types.h b/include/libelfu/types.h index e4dd26c..ab9f76c 100644 --- a/include/libelfu/types.h +++ b/include/libelfu/types.h @@ -58,10 +58,9 @@ typedef struct ElfuReltab { typedef struct ElfuScn { GElf_Shdr shdr; - Elf_Data data; - struct ElfuScn *linkptr; struct ElfuScn *infoptr; + char *databuf; struct ElfuScn *oldptr; diff --git a/src/libelfu/model/phdr.c b/src/libelfu/model/phdr.c new file mode 100644 index 0000000..d26eb77 --- /dev/null +++ b/src/libelfu/model/phdr.c @@ -0,0 +1,36 @@ +#include +#include + + +size_t elfu_mPhdrCount(ElfuElf *me) +{ + ElfuPhdr *mp; + size_t i = 0; + + assert(me); + + CIRCLEQ_FOREACH(mp, &me->phdrList, elem) { + i++; + } + + return i; +} + + + +void elfu_mPhdrUpdateChildOffsets(ElfuPhdr *mp) +{ + ElfuScn *ms; + ElfuPhdr *mpc; + + assert(mp); + assert(mp->phdr.p_type == PT_LOAD); + + CIRCLEQ_FOREACH(mpc, &mp->childPhdrList, elemChildPhdr) { + mpc->phdr.p_offset = mp->phdr.p_offset + (mpc->phdr.p_vaddr - mp->phdr.p_vaddr); + } + + CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) { + ms->shdr.sh_offset = mp->phdr.p_offset + (ms->shdr.sh_addr - mp->phdr.p_vaddr); + } +} diff --git a/src/libelfu/model/section.c b/src/libelfu/model/section.c new file mode 100644 index 0000000..c93c5c8 --- /dev/null +++ b/src/libelfu/model/section.c @@ -0,0 +1,221 @@ +#include +#include +#include +#include + + +/* Meta-functions */ + +void* elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2) +{ + ElfuPhdr *mp; + ElfuScn *ms; + + // TODO: Sort PHDRs by offset before interating + + CIRCLEQ_FOREACH(mp, &me->phdrList, elem) { + if (mp->phdr.p_type != PT_LOAD) { + continue; + } + + CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) { + void *rv = f(me, ms, aux1, aux2); + + if (rv) { + return rv; + } + } + } + + CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) { + void *rv = f(me, ms, aux1, aux2); + + if (rv) { + return rv; + } + } + + return NULL; +} + + + + +/* Counting */ + +static void* subCounter(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) +{ + size_t *i = (size_t*)aux1; + ElfuScn *otherScn = (ElfuScn*)aux2; + + if (ms == otherScn) { + return ms; + } + + *i += 1; + + /* Continue */ + return NULL; +} + + +size_t elfu_mScnCount(ElfuElf *me) +{ + /* NULL section *is not* counted */ + size_t i = 0; + + assert(me); + + elfu_mScnForall(me, subCounter, &i, NULL); + + return i; +} + + +/* Returns the index a section would have in the flattened ELF */ +size_t elfu_mScnIndex(ElfuElf *me, ElfuScn *ms) +{ + /* NULL section *is* counted */ + size_t i = 1; + + assert(me); + assert(ms); + + elfu_mScnForall(me, subCounter, &i, ms); + + /* If this assertion is broken then ms is not a section in me. */ + assert(i <= elfu_mScnCount(me)); + return i; +} + + +static void* subOldscn(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) +{ + ElfuScn *otherScn = (ElfuScn*)aux1; + (void)aux2; + + if (ms->oldptr == otherScn) { + return ms; + } + + /* Continue */ + return NULL; +} + +/* Returns the section with oldscn == oldscn */ +ElfuScn* elfu_mScnByOldscn(ElfuElf *me, ElfuScn *oldscn) +{ + assert(me); + assert(oldscn); + + return elfu_mScnForall(me, subOldscn, oldscn, NULL); +} + + + + +/* Convenience */ + +char* elfu_mScnName(ElfuElf *me, ElfuScn *ms) +{ + assert(me); + assert(ms); + + if (!me->shstrtab) { + return NULL; + } + + if (!me->shstrtab->databuf) { + return NULL; + } + + return &me->shstrtab->databuf[ms->shdr.sh_name]; +} + + +static void* subScnsToArray(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) +{ + ElfuScn **arr = (ElfuScn**)aux1; + size_t *i = (size_t*)aux2; + + arr[(*i)] = ms; + *i += 1; + + /* Continue */ + return NULL; +} + +static int cmpScnOffs(const void *ms1, const void *ms2) +{ + ElfuScn *s1; + ElfuScn *s2; + + assert(ms1); + assert(ms2); + + s1 = *(ElfuScn**)ms1; + s2 = *(ElfuScn**)ms2; + + assert(s1); + assert(s2); + + + if (s1->shdr.sh_offset < s2->shdr.sh_offset) { + return -1; + } else if (s1->shdr.sh_offset == s2->shdr.sh_offset) { + return 0; + } else /* if (s1->shdr.sh_offset > s2->shdr.sh_offset) */ { + return 1; + } +} + +ElfuScn** elfu_mScnSortedByOffset(ElfuElf *me, size_t *count) +{ + size_t numSecs; + ElfuScn **sortedSecs; + size_t i; + + assert(me); + + /* Sort sections by offset in file */ + numSecs = elfu_mScnCount(me); + sortedSecs = malloc(numSecs * sizeof(*sortedSecs)); + if (!sortedSecs) { + ELFU_WARN("elfu_mScnSortedByOffset: Failed to allocate memory.\n"); + return NULL; + } + + i = 0; + elfu_mScnForall(me, subScnsToArray, sortedSecs, &i); + assert(i == numSecs); + + qsort(sortedSecs, numSecs, sizeof(*sortedSecs), cmpScnOffs); + + *count = numSecs; + + return sortedSecs; +} + + + +/* + * Allocation, destruction + */ + +ElfuScn* elfu_mScnAlloc() +{ + ElfuScn *ms; + + ms = malloc(sizeof(ElfuScn)); + if (!ms) { + ELFU_WARN("mScnCreate: malloc() failed for ElfuScn.\n"); + return NULL; + } + + memset(ms, 0, sizeof(*ms)); + + CIRCLEQ_INIT(&ms->symtab.syms); + CIRCLEQ_INIT(&ms->reltab.rels); + + return ms; +} diff --git a/src/libelfu/model/symtab.c b/src/libelfu/model/symtab.c new file mode 100644 index 0000000..165e00e --- /dev/null +++ b/src/libelfu/model/symtab.c @@ -0,0 +1,267 @@ +#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 *me, char *name) +{ + ElfuScn *relplt; + ElfuScn *plt; + ElfuRel *rel; + GElf_Word j; + + relplt = elfu_mScnForall(me, subFindByName, ".rel.plt", NULL); + if (!relplt) { + ELFU_WARN("dynsymLookupVal: Could not find .rel.plt section in destination ELF.\n"); + return 0; + } + + plt = elfu_mScnForall(me, subFindByName, ".plt", NULL); + if (!plt) { + ELFU_WARN("dynsymLookupVal: Could not find .plt section in destination ELF.\n"); + return 0; + } + + + /* 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); + + return 0; +} + + + +/* 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) +{ + GElf_Word i; + ElfuSym *sym; + char *symname; + + assert(me); + assert(msst); + assert(entry > 0); + assert(!CIRCLEQ_EMPTY(&msst->symtab.syms)); + + sym = CIRCLEQ_FIRST(&msst->symtab.syms); + 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; + } +} + + +/* 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) +{ + ElfuSym *sym; + size_t numsyms = 0; + + elfu_mLayoutAuto(me); + + /* Update section indexes and count symbols */ + CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) { + if (sym->scnptr) { + sym->shndx = elfu_mScnIndex(me, sym->scnptr); + } + + numsyms++; + } + + /* Copy symbols to elfclass-specific format */ + if (me->elfclass == ELFCLASS32) { + size_t newsize = (numsyms + 1) * sizeof(Elf32_Sym); + size_t i; + + if (me->symtab->databuf) { + free(me->symtab->databuf); + } + me->symtab->databuf = malloc(newsize); + assert(me->symtab->databuf); + + me->symtab->shdr.sh_size = newsize; + memset(me->symtab->databuf, 0, newsize); + + i = 1; + CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) { + Elf32_Sym *es = ((Elf32_Sym*)me->symtab->databuf) + i; + + es->st_name = sym->name; + es->st_value = sym->value; + es->st_size = sym->size; + es->st_info = ELF32_ST_INFO(sym->bind, sym->type); + es->st_other = sym->other; + es->st_shndx = sym->shndx; + + i++; + } + } else if (me->elfclass == ELFCLASS64) { + size_t newsize = (numsyms + 1) * sizeof(Elf64_Sym); + size_t i; + + if (me->symtab->databuf) { + free(me->symtab->databuf); + } + me->symtab->databuf = malloc(newsize); + assert(me->symtab->databuf); + + me->symtab->shdr.sh_size = newsize; + memset(me->symtab->databuf, 0, newsize); + + i = 1; + CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) { + Elf64_Sym *es = ((Elf64_Sym*)me->symtab->databuf) + i; + + es->st_name = sym->name; + es->st_value = sym->value; + es->st_size = sym->size; + es->st_info = ELF64_ST_INFO(sym->bind, sym->type); + es->st_other = sym->other; + es->st_shndx = sym->shndx; + + i++; + } + } else { + /* Unknown elfclass */ + assert(0); + } + + elfu_mLayoutAuto(me); +} diff --git a/src/libelfu/modelops/clone.c b/src/libelfu/modelops/clone.c index 8f92919..8b9b0bc 100644 --- a/src/libelfu/modelops/clone.c +++ b/src/libelfu/modelops/clone.c @@ -9,33 +9,27 @@ ElfuScn* elfu_mCloneScn(ElfuScn *ms) assert(ms); - newscn = malloc(sizeof(ElfuScn)); + newscn = elfu_mScnAlloc(); if (!newscn) { ELFU_WARN("elfu_nCloneScn: Could not allocate memory for new ElfuScn.\n"); return NULL; } newscn->shdr = ms->shdr; - newscn->data = ms->data; - if (ms->data.d_buf) { - void *newbuf = malloc(ms->data.d_size); + + if (ms->databuf) { + void *newbuf = malloc(ms->shdr.sh_size); if (!newbuf) { ELFU_WARN("elfu_nCloneScn: Could not allocate memory for new data buffer.\n"); free(newscn); return NULL; } - memcpy(newbuf, ms->data.d_buf, ms->data.d_size); - newscn->data.d_buf = newbuf; + memcpy(newbuf, ms->databuf, ms->shdr.sh_size); + newscn->databuf = newbuf; } - newscn->linkptr = NULL; - newscn->infoptr = NULL; - newscn->oldptr = ms; - CIRCLEQ_INIT(&ms->symtab.syms); - CIRCLEQ_INIT(&ms->reltab.rels); - return newscn; } diff --git a/src/libelfu/modelops/detour.c b/src/libelfu/modelops/detour.c index 075d945..86ac46b 100644 --- a/src/libelfu/modelops/detour.c +++ b/src/libelfu/modelops/detour.c @@ -47,5 +47,5 @@ void elfu_mDetour(ElfuElf *me, GElf_Addr from, GElf_Addr to) (unsigned)to); *(Elf32_Word*)(detourcode + 1) = to - from - 5; - memcpy((char*)ms->data.d_buf + scnoffset, detourcode, 5); + memcpy(ms->databuf + scnoffset, detourcode, 5); } diff --git a/src/libelfu/modelops/fromFile.c b/src/libelfu/modelops/fromFile.c index dd8b462..9c25e29 100644 --- a/src/libelfu/modelops/fromFile.c +++ b/src/libelfu/modelops/fromFile.c @@ -11,13 +11,13 @@ static void parseSymtab(ElfuElf *me, ElfuScn *ms, ElfuScn**origScnArr) size_t i; assert(ms); - assert(ms->data.d_buf); + assert(ms->databuf); assert(origScnArr); /* Parse symbols from their elfclass-specific format */ if (me->elfclass == ELFCLASS32) { for (i = 1; (i + 1) * sizeof(Elf32_Sym) <= ms->shdr.sh_size; i++) { - Elf32_Sym *cursym = ((Elf32_Sym*)ms->data.d_buf) + i; + Elf32_Sym *cursym = ((Elf32_Sym*)ms->databuf) + i; ElfuSym *newsym = malloc(sizeof(*sym)); assert(newsym); @@ -29,13 +29,11 @@ static void parseSymtab(ElfuElf *me, ElfuScn *ms, ElfuScn**origScnArr) newsym->other = cursym->st_other; newsym->shndx = cursym->st_shndx; - - CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, newsym, elem); } } else if (me->elfclass == ELFCLASS64) { for (i = 1; (i + 1) * sizeof(Elf64_Sym) <= ms->shdr.sh_size; i++) { - Elf64_Sym *cursym = ((Elf64_Sym*)ms->data.d_buf) + i; + Elf64_Sym *cursym = ((Elf64_Sym*)ms->databuf) + i; ElfuSym *newsym = malloc(sizeof(*sym)); assert(newsym); @@ -47,8 +45,6 @@ static void parseSymtab(ElfuElf *me, ElfuScn *ms, ElfuScn**origScnArr) newsym->other = cursym->st_other; newsym->shndx = cursym->st_shndx; - - CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, newsym, elem); } } else { @@ -77,11 +73,11 @@ static void parseReltab32(ElfuScn *ms) size_t i; assert(ms); - assert(ms->data.d_buf); + assert(ms->databuf); for (i = 0; (i + 1) * sizeof(Elf32_Rel) <= ms->shdr.sh_size; i++) { - Elf32_Rel *currel = &(((Elf32_Rel*)ms->data.d_buf)[i]); + Elf32_Rel *currel = &(((Elf32_Rel*)ms->databuf)[i]); ElfuRel *rel; rel = malloc(sizeof(*rel)); @@ -103,11 +99,11 @@ static void parseRelatab64(ElfuScn *ms) size_t i; assert(ms); - assert(ms->data.d_buf); + assert(ms->databuf); for (i = 0; (i + 1) * sizeof(Elf64_Rela) <= ms->shdr.sh_size; i++) { - Elf64_Rela *currel = &(((Elf64_Rela*)ms->data.d_buf)[i]); + Elf64_Rela *currel = &(((Elf64_Rela*)ms->databuf)[i]); ElfuRel *rel; rel = malloc(sizeof(*rel)); @@ -210,29 +206,20 @@ static ElfuScn* modelFromSection(Elf_Scn *scn) assert(scn); - ms = malloc(sizeof(ElfuScn)); + ms = elfu_mScnAlloc(); if (!ms) { - ELFU_WARN("modelFromSection: malloc() failed for ElfuScn.\n"); goto ERROR; } - + /* Copy SHDR */ assert(gelf_getshdr(scn, &ms->shdr) == &ms->shdr); - /* Copy each data part in source segment */ - ms->data.d_align = 1; - ms->data.d_buf = NULL; - ms->data.d_off = 0; - ms->data.d_type = ELF_T_BYTE; - ms->data.d_size = ms->shdr.sh_size; - ms->data.d_version = elf_version(EV_NONE); - if (ms->shdr.sh_type != SHT_NOBITS - && ms->shdr.sh_size > 0) { + if (SCNFILESIZE(&ms->shdr) > 0) { Elf_Data *data; - ms->data.d_buf = malloc(ms->shdr.sh_size); - if (!ms->data.d_buf) { + ms->databuf = malloc(ms->shdr.sh_size); + if (!ms->databuf) { ELFU_WARN("modelFromSection: malloc() failed for data buffer (%x bytes).\n", (unsigned)ms->shdr.sh_size); goto ERROR; } @@ -241,30 +228,20 @@ static ElfuScn* modelFromSection(Elf_Scn *scn) data = elf_rawdata(scn, NULL); assert(data); - ms->data.d_align = data->d_align; - ms->data.d_type = data->d_type; - ms->data.d_version = data->d_version; + /* elf_rawdata() always returns ELF_T_BYTE */ + assert(data->d_type == ELF_T_BYTE); while (data) { if (data->d_off + data->d_size > ms->shdr.sh_size) { ELFU_WARN("modelFromSection: libelf delivered a bogus data blob. Skipping\n"); } else { - memcpy((char*)ms->data.d_buf + data->d_off, data->d_buf, data->d_size); + memcpy((char*)ms->databuf + data->d_off, data->d_buf, data->d_size); } data = elf_rawdata(scn, data); } } - ms->linkptr = NULL; - ms->infoptr = NULL; - - ms->oldptr = NULL; - - CIRCLEQ_INIT(&ms->symtab.syms); - CIRCLEQ_INIT(&ms->reltab.rels); - - return ms; ERROR: diff --git a/src/libelfu/modelops/layout.c b/src/libelfu/modelops/layout.c index 8abc766..65a713d 100644 --- a/src/libelfu/modelops/layout.c +++ b/src/libelfu/modelops/layout.c @@ -121,21 +121,15 @@ GElf_Addr elfu_mLayoutGetSpaceInPhdr(ElfuElf *me, GElf_Word size, if (ms->shdr.sh_offset == endOff) { assert(ms->shdr.sh_type == SHT_NOBITS); assert(ms->shdr.sh_size == nobitsize); - ms->data.d_buf = malloc(ms->shdr.sh_size); - memset(ms->data.d_buf, '\0', ms->shdr.sh_size); - if (!ms->data.d_buf) { + ms->databuf = malloc(ms->shdr.sh_size); + memset(ms->databuf, '\0', ms->shdr.sh_size); + if (!ms->databuf) { ELFU_WARN("mExpandNobits: Could not allocate %u bytes for NOBITS expansion. Data may be inconsistent.\n", (unsigned)ms->shdr.sh_size); assert(0); goto ERROR; } - ms->data.d_align = 1; - ms->data.d_off = 0; - ms->data.d_type = ELF_T_BYTE; - ms->data.d_size = ms->shdr.sh_size; - ms->data.d_version = elf_version(EV_NONE); - ms->shdr.sh_type = SHT_PROGBITS; ms->shdr.sh_addr = endAddr; } diff --git a/src/libelfu/modelops/phdr.c b/src/libelfu/modelops/phdr.c deleted file mode 100644 index d26eb77..0000000 --- a/src/libelfu/modelops/phdr.c +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include - - -size_t elfu_mPhdrCount(ElfuElf *me) -{ - ElfuPhdr *mp; - size_t i = 0; - - assert(me); - - CIRCLEQ_FOREACH(mp, &me->phdrList, elem) { - i++; - } - - return i; -} - - - -void elfu_mPhdrUpdateChildOffsets(ElfuPhdr *mp) -{ - ElfuScn *ms; - ElfuPhdr *mpc; - - assert(mp); - assert(mp->phdr.p_type == PT_LOAD); - - CIRCLEQ_FOREACH(mpc, &mp->childPhdrList, elemChildPhdr) { - mpc->phdr.p_offset = mp->phdr.p_offset + (mpc->phdr.p_vaddr - mp->phdr.p_vaddr); - } - - CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) { - ms->shdr.sh_offset = mp->phdr.p_offset + (ms->shdr.sh_addr - mp->phdr.p_vaddr); - } -} diff --git a/src/libelfu/modelops/reladd.c b/src/libelfu/modelops/reladd.c index bc909e4..8c56d4f 100644 --- a/src/libelfu/modelops/reladd.c +++ b/src/libelfu/modelops/reladd.c @@ -11,19 +11,18 @@ static int appendData(ElfuScn *ms, void *buf, size_t len) assert(ms); assert(ms->shdr.sh_type != SHT_NOBITS); - assert(ms->data.d_buf); + assert(ms->databuf); - newbuf = realloc(ms->data.d_buf, ms->shdr.sh_size + len); + newbuf = realloc(ms->databuf, ms->shdr.sh_size + len); if (!newbuf) { ELFU_WARN("appendData: malloc() failed for newbuf.\n"); return 1; } - ms->data.d_buf = newbuf; + ms->databuf = newbuf; memcpy(newbuf + ms->shdr.sh_size, buf, len); ms->shdr.sh_size += len; - ms->data.d_size += len; - assert(ms->shdr.sh_size == ms->data.d_size); + assert(ms->shdr.sh_size == ms->shdr.sh_size); return 0; } @@ -45,13 +44,12 @@ static ElfuScn* insertSection(ElfuElf *me, ElfuElf *mrel, ElfuScn *oldscn) if (newscn->shdr.sh_type == SHT_NOBITS) { /* Expand this to SHT_PROGBITS, then insert as such. */ - assert(!newscn->data.d_buf); + assert(!newscn->databuf); - newscn->data.d_buf = malloc(newscn->shdr.sh_size); - if (!newscn->data.d_buf) { + newscn->databuf = malloc(newscn->shdr.sh_size); + if (!newscn->databuf) { goto ERROR; } - newscn->data.d_size = newscn->shdr.sh_size; newscn->shdr.sh_type = SHT_PROGBITS; } @@ -250,19 +248,18 @@ static void insertSymClone(ElfuElf *me, const ElfuScn *oldmsst, const ElfuSym *o /* Expand .strtab, append symbol name, link newsym to it */ newsize = me->symtab->linkptr->shdr.sh_size + strlen(oldsymname) + 1; - newbuf = realloc(me->symtab->linkptr->data.d_buf, newsize); + newbuf = realloc(me->symtab->linkptr->databuf, newsize); if (!newbuf) { ELFU_WARN("insertSymClone: realloc() failed for strtab.\n"); goto ERROR; } - me->symtab->linkptr->data.d_buf = newbuf; + me->symtab->linkptr->databuf = newbuf; newsym->name = me->symtab->linkptr->shdr.sh_size; strcpy(newbuf + newsym->name, oldsymname); - me->symtab->linkptr->data.d_size = newsize; me->symtab->linkptr->shdr.sh_size = newsize; diff --git a/src/libelfu/modelops/relocate.c b/src/libelfu/modelops/relocate.c index eefed02..2eada04 100644 --- a/src/libelfu/modelops/relocate.c +++ b/src/libelfu/modelops/relocate.c @@ -18,8 +18,8 @@ void elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt) (unsigned)mstarget->shdr.sh_size); CIRCLEQ_FOREACH(rel, &msrt->reltab.rels, elem) { - Elf32_Word *dest32 = (Elf32_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset); - Elf64_Word *dest64 = (Elf64_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset); + Elf32_Word *dest32 = (Elf32_Word*)(mstarget->databuf + rel->offset); + Elf64_Word *dest64 = (Elf64_Word*)(mstarget->databuf + rel->offset); if (metarget->elfclass == ELFCLASS32) { diff --git a/src/libelfu/modelops/section.c b/src/libelfu/modelops/section.c deleted file mode 100644 index 2675126..0000000 --- a/src/libelfu/modelops/section.c +++ /dev/null @@ -1,196 +0,0 @@ -#include -#include -#include - - -/* Meta-functions */ - -void* elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2) -{ - ElfuPhdr *mp; - ElfuScn *ms; - - // TODO: Sort PHDRs by offset before interating - - CIRCLEQ_FOREACH(mp, &me->phdrList, elem) { - if (mp->phdr.p_type != PT_LOAD) { - continue; - } - - CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) { - void *rv = f(me, ms, aux1, aux2); - - if (rv) { - return rv; - } - } - } - - CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) { - void *rv = f(me, ms, aux1, aux2); - - if (rv) { - return rv; - } - } - - return NULL; -} - - - - -/* Counting */ - -static void* subCounter(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) -{ - size_t *i = (size_t*)aux1; - ElfuScn *otherScn = (ElfuScn*)aux2; - - if (ms == otherScn) { - return ms; - } - - *i += 1; - - /* Continue */ - return NULL; -} - - -size_t elfu_mScnCount(ElfuElf *me) -{ - /* NULL section *is not* counted */ - size_t i = 0; - - assert(me); - - elfu_mScnForall(me, subCounter, &i, NULL); - - return i; -} - - -/* Returns the index a section would have in the flattened ELF */ -size_t elfu_mScnIndex(ElfuElf *me, ElfuScn *ms) -{ - /* NULL section *is* counted */ - size_t i = 1; - - assert(me); - assert(ms); - - elfu_mScnForall(me, subCounter, &i, ms); - - /* If this assertion is broken then ms is not a section in me. */ - assert(i <= elfu_mScnCount(me)); - return i; -} - - -static void* subOldscn(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) -{ - ElfuScn *otherScn = (ElfuScn*)aux1; - (void)aux2; - - if (ms->oldptr == otherScn) { - return ms; - } - - /* Continue */ - return NULL; -} - -/* Returns the section with oldscn == oldscn */ -ElfuScn* elfu_mScnByOldscn(ElfuElf *me, ElfuScn *oldscn) -{ - assert(me); - assert(oldscn); - - return elfu_mScnForall(me, subOldscn, oldscn, NULL); -} - - - - -/* Convenience */ - -char* elfu_mScnName(ElfuElf *me, ElfuScn *ms) -{ - assert(me); - assert(ms); - - if (!me->shstrtab) { - return NULL; - } - - if (!me->shstrtab->data.d_buf) { - return NULL; - } - - return &((char*)me->shstrtab->data.d_buf)[ms->shdr.sh_name]; -} - - -static void* subScnsToArray(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) -{ - ElfuScn **arr = (ElfuScn**)aux1; - size_t *i = (size_t*)aux2; - - arr[(*i)] = ms; - *i += 1; - - /* Continue */ - return NULL; -} - -static int cmpScnOffs(const void *ms1, const void *ms2) -{ - ElfuScn *s1; - ElfuScn *s2; - - assert(ms1); - assert(ms2); - - s1 = *(ElfuScn**)ms1; - s2 = *(ElfuScn**)ms2; - - assert(s1); - assert(s2); - - - if (s1->shdr.sh_offset < s2->shdr.sh_offset) { - return -1; - } else if (s1->shdr.sh_offset == s2->shdr.sh_offset) { - return 0; - } else /* if (s1->shdr.sh_offset > s2->shdr.sh_offset) */ { - return 1; - } -} - -ElfuScn** elfu_mScnSortedByOffset(ElfuElf *me, size_t *count) -{ - size_t numSecs; - ElfuScn **sortedSecs; - size_t i; - - assert(me); - - /* Sort sections by offset in file */ - numSecs = elfu_mScnCount(me); - sortedSecs = malloc(numSecs * sizeof(*sortedSecs)); - if (!sortedSecs) { - ELFU_WARN("elfu_mScnSortedByOffset: Failed to allocate memory.\n"); - return NULL; - } - - i = 0; - elfu_mScnForall(me, subScnsToArray, sortedSecs, &i); - assert(i == numSecs); - - qsort(sortedSecs, numSecs, sizeof(*sortedSecs), cmpScnOffs); - - *count = numSecs; - - return sortedSecs; -} diff --git a/src/libelfu/modelops/symtab.c b/src/libelfu/modelops/symtab.c deleted file mode 100644 index ef8443f..0000000 --- a/src/libelfu/modelops/symtab.c +++ /dev/null @@ -1,269 +0,0 @@ -#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 *me, char *name) -{ - ElfuScn *relplt; - ElfuScn *plt; - ElfuRel *rel; - GElf_Word j; - - relplt = elfu_mScnForall(me, subFindByName, ".rel.plt", NULL); - if (!relplt) { - ELFU_WARN("dynsymLookupVal: Could not find .rel.plt section in destination ELF.\n"); - return 0; - } - - plt = elfu_mScnForall(me, subFindByName, ".plt", NULL); - if (!plt) { - ELFU_WARN("dynsymLookupVal: Could not find .plt section in destination ELF.\n"); - return 0; - } - - - /* 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); - - return 0; -} - - - -/* 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) -{ - GElf_Word i; - ElfuSym *sym; - char *symname; - - assert(me); - assert(msst); - assert(entry > 0); - assert(!CIRCLEQ_EMPTY(&msst->symtab.syms)); - - sym = CIRCLEQ_FIRST(&msst->symtab.syms); - 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; - } -} - - -/* 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) -{ - ElfuSym *sym; - size_t numsyms = 0; - - elfu_mLayoutAuto(me); - - /* Update section indexes and count symbols */ - CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) { - if (sym->scnptr) { - sym->shndx = elfu_mScnIndex(me, sym->scnptr); - } - - numsyms++; - } - - /* Copy symbols to elfclass-specific format */ - if (me->elfclass == ELFCLASS32) { - size_t newsize = (numsyms + 1) * sizeof(Elf32_Sym); - size_t i; - - if (me->symtab->data.d_buf) { - free(me->symtab->data.d_buf); - } - me->symtab->data.d_buf = malloc(newsize); - assert(me->symtab->data.d_buf); - - me->symtab->data.d_size = newsize; - me->symtab->shdr.sh_size = newsize; - memset(me->symtab->data.d_buf, 0, newsize); - - i = 1; - CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) { - Elf32_Sym *es = ((Elf32_Sym*)me->symtab->data.d_buf) + i; - - es->st_name = sym->name; - es->st_value = sym->value; - es->st_size = sym->size; - es->st_info = ELF32_ST_INFO(sym->bind, sym->type); - es->st_other = sym->other; - es->st_shndx = sym->shndx; - - i++; - } - } else if (me->elfclass == ELFCLASS64) { - size_t newsize = (numsyms + 1) * sizeof(Elf64_Sym); - size_t i; - - if (me->symtab->data.d_buf) { - free(me->symtab->data.d_buf); - } - me->symtab->data.d_buf = malloc(newsize); - assert(me->symtab->data.d_buf); - - me->symtab->data.d_size = newsize; - me->symtab->shdr.sh_size = newsize; - memset(me->symtab->data.d_buf, 0, newsize); - - i = 1; - CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) { - Elf64_Sym *es = ((Elf64_Sym*)me->symtab->data.d_buf) + i; - - es->st_name = sym->name; - es->st_value = sym->value; - es->st_size = sym->size; - es->st_info = ELF64_ST_INFO(sym->bind, sym->type); - es->st_other = sym->other; - es->st_shndx = sym->shndx; - - i++; - } - } else { - /* Unknown elfclass */ - assert(0); - } - - elfu_mLayoutAuto(me); -} diff --git a/src/libelfu/modelops/toFile.c b/src/libelfu/modelops/toFile.c index 368f12a..ff01390 100644 --- a/src/libelfu/modelops/toFile.c +++ b/src/libelfu/modelops/toFile.c @@ -59,18 +59,18 @@ static void* modelToSection(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) /* Data */ - if (ms->data.d_buf) { + if (ms->databuf) { Elf_Data *dataOut = elf_newdata(scnOut); if (!dataOut) { ELFU_WARNELF("elf_newdata"); } - dataOut->d_align = ms->data.d_align; - dataOut->d_buf = ms->data.d_buf; - dataOut->d_off = ms->data.d_off; - dataOut->d_type = ms->data.d_type; - dataOut->d_size = ms->data.d_size; - dataOut->d_version = ms->data.d_version; + dataOut->d_align = 1; + dataOut->d_buf = ms->databuf; + dataOut->d_off = 0; + dataOut->d_type = ELF_T_BYTE; + dataOut->d_size = ms->shdr.sh_size; + dataOut->d_version = elf_version(EV_NONE); } return NULL;