/** * Get comment section * @param file * @return */ elfshsect_t *elfsh_get_comments(elfshobj_t *file) { elfshsect_t *enew; int size; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (NULL == file) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL paramater", NULL); enew = elfsh_get_section_by_name(file, ELFSH_SECTION_NAME_COMMENT, NULL, NULL, &size); if (NULL == enew) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get .comment by name", NULL); if (NULL == elfsh_readmem(enew)) { enew->data = elfsh_load_section(file, enew->shdr); if (NULL == elfsh_readmem(enew)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to load .comment", NULL); } file->secthash[ELFSH_SECTION_COMMENT] = enew; PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (enew)); }
/** * Return a pointer on ".reginfo" ri_gp_value * @param file * @return */ elfsh_Sword *elfsh_get_gpvalue_addr(elfshobj_t* file) { elfshsect_t *reginfo; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (file == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL parameter", NULL); reginfo = elfsh_get_section_by_name(file,".reginfo", NULL, NULL, NULL); if (reginfo == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "No .reginfo section", NULL); if (reginfo->data == NULL) reginfo->data = elfsh_load_section(file, reginfo->shdr); if (reginfo->data == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Can't read .reginfo section", NULL); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (&((elfsh_RegInfo *) elfsh_readmem(reginfo))->ri_gp_value)); }
/** * Remap a section which type is SHT_SYMTAB or SHT_DYNSYM * @param s * @param diff * @return */ int elfsh_reloc_symtab(elfshsect_t *s, eresi_Addr diff) { elfsh_Sym *symtab; u_int i; eresi_Addr vaddr; u_int count; eresi_Addr base; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (s == NULL || s->shdr == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL parameter", -1); else if (s->shdr->sh_type != SHT_SYMTAB && s->shdr->sh_type != SHT_DYNSYM) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Section is not a symbol table", -1); symtab = elfsh_readmem(s); base = elfsh_get_object_baseaddr(s->parent); for (count = i = 0; i < s->shdr->sh_size / sizeof(elfsh_Sym); i++) { vaddr = elfsh_get_symbol_value(symtab + i); if (vaddr > base) { elfsh_set_symbol_value(symtab + i, vaddr + diff); count++; } } /* Synchronize the symtab hash table */ elfsh_sync_sorted_symtab(s); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (count)); }
/** * Call the type dependant remapping routine for this section * @param sect * @param diff * @return */ int elfsh_relocate_section(elfshsect_t *sect, eresi_Addr diff) { int ret; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); ret = 0; if (sect == NULL || elfsh_readmem(sect) == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL paramater", -1); if (sect->shdr->sh_addr != NULL) elfsh_find_rel(sect); if (sect->shdr->sh_type == SHT_SYMTAB) ret = elfsh_reloc_symtab(sect, diff); else if (sect->shdr->sh_type == SHT_DYNSYM) ret = elfsh_reloc_symtab(sect, diff); else if (sect->shdr->sh_type == SHT_RELA || sect->shdr->sh_type == SHT_REL) ret = elfsh_reloc_rel(sect, diff); else if (sect->shdr->sh_type == SHT_DYNAMIC) ret = elfsh_reloc_dynamic(sect, diff); else if (!strcmp(sect->name, ELFSH_SECTION_NAME_CTORS)) ret = elfsh_reloc_ctors(sect, diff); else if (!strcmp(sect->name, ELFSH_SECTION_NAME_DTORS)) ret = elfsh_reloc_dtors(sect, diff); else if (!strcmp(sect->name, ELFSH_SECTION_NAME_GOT)) ret = elfsh_reloc_got(sect, diff); else if (sect->shdr->sh_addr != NULL) ret = elfsh_reloc_raw(sect, diff); if (ret < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Relocation recovery failed for this section", -1); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (ret)); }
/** * Remap sections of type SHT_REL and SHT_RELA * @param sect * @param diff * @return */ int elfsh_reloc_rel(elfshsect_t *sect, eresi_Addr diff) { elfshsect_t *parent; elfsh_Rel *rel; u_int index; u_int count; u_int nbr; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (sect == NULL || sect->shdr == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL parameter", -1); else if (sect->shdr->sh_type != SHT_REL && sect->shdr->sh_type != SHT_RELA) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unexpected section type", -1); nbr = sect->shdr->sh_size / sizeof(elfsh_Rel); for (rel = elfsh_readmem(sect), count = index = 0; index < nbr; index++) { parent = elfsh_get_parent_section(sect->parent, rel[index].r_offset, NULL); if (rel[index].r_offset && parent != NULL && parent->shdr->sh_addr != NULL) { rel[index].r_offset += diff; count++; } } PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (count)); }
/** * Remap the .dynamic section * @param sect * @param diff * @return */ int elfsh_reloc_dynamic(elfshsect_t *sect, eresi_Addr diff) { elfshsect_t *parent; elfsh_Dyn *dyn; u_int index; u_int count; eresi_Addr val; u_int nbr; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (sect == NULL || sect->shdr == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL parameter", -1); else if (sect->shdr->sh_type != SHT_DYNAMIC) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unexpected section type", -1); nbr = sect->shdr->sh_size / sizeof(elfsh_Dyn); for (dyn = elfsh_readmem(sect), count = index = 0; index < nbr; index++) { val = elfsh_get_dynentry_val(dyn + index); parent = elfsh_get_parent_section(sect->parent, val, NULL); if (val && parent != NULL && parent->shdr->sh_addr != NULL) { elfsh_set_dynentry_val(dyn + index, val + diff); count++; } } PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (count)); }
/** * Remap a section using its extra relocation entries * @param cur * @param diff * @return */ int elfsh_reloc_raw(elfshsect_t *cur, eresi_Addr diff) { u_int index; eresi_Addr addr; elfshsect_t *target; char *str; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (cur == NULL || cur->shdr == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL parameter", -1); if (elfsh_readmem(cur) == NULL || cur->rel == NULL) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); /* Read the actual section and find valid references */ for (index = 0; index < cur->srcref; index++) switch (cur->rel[index].type) { /* Relocate by : section[idx_dst].vaddr + off_dst */ case ELFSH_RELOC_SECTBASE: target = elfsh_get_section_by_index(cur->parent, cur->rel[index].idx_dst, NULL, NULL); if (target == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid IDX_DST", -1); str = elfsh_readmem(cur) + cur->rel[index].off_src; addr = target->shdr->sh_addr + cur->rel[index].off_dst + diff; memcpy(str, &addr, sizeof(eresi_Addr)); /* Do not relocate */ case ELFSH_RELOC_FP: default: break; } PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (cur->srcref)); }
/** * Not used ATM since it triggers more false positives ;P * @param sect * @param diff * @return */ int elfsh_reloc_hash(elfshsect_t *sect, eresi_Addr diff) { PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (sect == NULL || sect->shdr == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL parameter", -1); else if (sect->shdr->sh_type != SHT_HASH) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Section is not HASH", -1); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (elfsh_reloc_array(sect->parent, elfsh_readmem(sect), sect->shdr->sh_size / sizeof(eresi_Addr), diff))); }
/** * Remap Global Offset Table * @param sect * @param diff * @return */ int elfsh_reloc_got(elfshsect_t *sect, eresi_Addr diff) { PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (sect == NULL || sect->shdr == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL parameter", -1); else if (strcmp(sect->name, ELFSH_SECTION_NAME_GOT)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unexpected section name", -1); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (elfsh_reloc_array(sect->parent, elfsh_readmem(sect), sect->shdr->sh_size / sizeof(eresi_Addr), diff))); }
/** * Debug : print the section list * @param obj * @param label * @return */ int elfsh_print_sectlist(elfshobj_t *obj, char *label) { elfshsect_t *actual; u_int index; u_char *data; char *sctname; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); printf(" [SCTLIST][%s]\n", label); for (index = 0, actual = obj->sectlist; actual != NULL; index++, actual = actual->next) { sctname = elfsh_get_section_name(obj, actual); if (sctname == NULL) sctname = "UNK"; data = elfsh_readmem(actual); if (data == (u_char *)NULL) data = (u_char *)"\xFF\xFF\xFF"; printf(" [%03u:%03u] %-15s HDRNAM: %-15s BYTES[%02X %02X %02X] P(%8p) " "A(%8p) N(%8p) SCTIDX(%03u) HDRFOFF:%010u SZ:%010u VADDR:%08X \n", index, actual->index, (actual->name != NULL ? actual->name : "UNK"), sctname, (u_int) data[0], (u_int) data[1], (u_int) data[2], actual->prev, actual, actual->next, actual->index, (u_int) actual->shdr->sh_offset, (u_int) actual->shdr->sh_size, (u_int) actual->shdr->sh_addr); } puts(" [EOL]\n"); fflush(stdout); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * Retreive the information giving the entry * @param file elfsh object. * @param ent * @return */ char *elfsh_get_dynentry_string(elfshobj_t *file, elfsh_Dyn *ent) { void *data; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (file == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL parameter", NULL); if (file->secthash[ELFSH_SECTION_DYNSYM] == NULL && elfsh_get_dynsymtab(file, NULL) == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get DYNSYM", NULL); if (ent->d_un.d_val > file->secthash[ELFSH_SECTION_DYNSTR]->shdr->sh_size) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid .dynstr offset", NULL); data = elfsh_readmem(file->secthash[ELFSH_SECTION_DYNSTR]); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, ((char *) data + ent->d_un.d_val)); }
/** * Read the destructor array in .dtors * @param file * @param num * @return */ eresi_Addr *elfsh_get_dtors(elfshobj_t *file, int *num) { elfshsect_t *enew; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Sanity checks */ if (file == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL parameter", NULL); /* Load dtors */ enew = file->secthash[ELFSH_SECTION_DTORS]; if (enew == NULL) { enew = elfsh_get_section_by_name(file, ELFSH_SECTION_NAME_DTORS, NULL, NULL, NULL); if (NULL == enew) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get DTORS by name", NULL); } /* Read dtors */ if (NULL == enew->data) { enew->data = elfsh_load_section(file, enew->shdr); if (NULL == enew->data) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to load DTORS", NULL); file->secthash[ELFSH_SECTION_DTORS] = enew; } /* Return data */ if (num != NULL) *num = enew->shdr->sh_size / sizeof(eresi_Addr); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (elfsh_readmem(enew))); }
/** * Get an entry from .comment * @param file * @param range * @return */ char *elfsh_get_comments_entry(elfshobj_t *file, u_int range) { int index; int act; char *data; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); #define CHECK_SZ (index < file->secthash[ELFSH_SECTION_COMMENT]->shdr->sh_size) if (!file->secthash[ELFSH_SECTION_COMMENT] && !elfsh_get_comments(file)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get .comments", NULL); index = act = 0; data = elfsh_readmem(file->secthash[ELFSH_SECTION_COMMENT]); while (!data[index] && CHECK_SZ) index++; while (act != range && CHECK_SZ) if (!data[index]) { act++; while (!data[index] && CHECK_SZ) index++; } else index++; #undef CHECK_SZ if (index < file->secthash[ELFSH_SECTION_COMMENT]->shdr->sh_size) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (data + index)); PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get .comments entry", NULL); }
/** * Get function addr list from call search basic * @param file target file * @param addr address list */ int elfsh_addr_get_func_list(elfshobj_t *file, eresi_Addr **addr) { int ret; int index; asm_instr instr; elfsh_SAddr foffset; elfsh_Word len; char *base; asm_processor proc; eresi_Addr base_vaddr, caddr; u_char found = 0; elfshsect_t *text; eresi_Addr *vaddr; const int astep = 20; u_int apos = 0; btree_t *broot = NULL; u_int diff; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (!file || !addr) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid parameters", -1); /* Search entrypoint section, our address must be in this section */ text = elfsh_get_parent_section(file, elfsh_get_entrypoint(file->hdr), &foffset); if (!text) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot find parent section from entry point", -1); if (!elfsh_get_anonymous_section(file, text)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get an anonymous section", -1); base = elfsh_readmem(text); len = text->shdr->sh_size; /* Get the virtual address */ base_vaddr = (elfsh_is_runtime_mode() && !elfsh_section_is_runtime(text) ? file->rhdr.base + elfsh_get_section_addr(text->shdr) : elfsh_get_section_addr(text->shdr)); /* Setup asm_processor structure */ if (etrace_setup_proc(file, &proc) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Failed during proc structure setup", -1); XALLOC(__FILE__, __FUNCTION__, __LINE__, vaddr, sizeof(eresi_Addr)*astep, -1); /* Despite the fact that we choose the right architecture to init asm, Our approach is totally architecture independant as we search using global type ASM_TYPE_CALLPROC and we know that op[0].imm will contain a relative value. */ for (index = 0; index < len; index += ret) { /* Read an instruction */ if ((ret = asm_read_instr(&instr, (u_char *) (base + index), len - index, &proc))) { /* Global assembler filter */ if ((instr.type & ASM_TYPE_CALLPROC) && instr.op[0].imm != 0) { caddr = base_vaddr + index + instr.op[0].imm + instr.len; /* Found a call check its local */ if (INTERVAL(base_vaddr, caddr, base_vaddr + len)) { found = 1; diff = (u_int) caddr; /* Avoid double entrie */ if (btree_get_elem(broot, diff) != NULL) goto next; btree_insert(&broot, diff, (void *)0x1); /* Next will be the last of the current list then realloc */ if ((apos+1) % astep == 0) { XREALLOC(__FILE__, __FUNCTION__, __LINE__, vaddr, vaddr, sizeof(eresi_Addr)*(apos+1+astep), -1); /* Blank new elements */ memset(&vaddr[apos], 0x00, astep*sizeof(eresi_Addr)); } vaddr[apos++] = caddr; } } } next: if (ret <= 0) ret = 1; } /* If nothing found we free allocated buffer and return an error */ if (!found) { XFREE(__FILE__, __FUNCTION__, __LINE__, vaddr); PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "No call internal found", -3); } btree_free(broot, 0); *addr = vaddr; PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * Search a call for a given address * @param file target file * @param addr supose to be a function */ int elfsh_addr_is_called(elfshobj_t *file, eresi_Addr addr) { int ret; int index; asm_instr instr; elfsh_SAddr foffset; elfsh_Word len; char *base; asm_processor proc; eresi_Addr base_vaddr; u_char found = 0; elfshsect_t *text; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (!file) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid parameter", -1); /* Search entrypoint section, our address must be in this section */ text = elfsh_get_parent_section(file, elfsh_get_entrypoint(file->hdr), &foffset); if (!text) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot find parent section from entry point", -1); if (!elfsh_get_anonymous_section(file, text)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get an anonymous section", -1); base = elfsh_readmem(text); len = text->shdr->sh_size; /* Get the virtual address */ base_vaddr = (elfsh_is_runtime_mode() && !elfsh_section_is_runtime(text) ? file->rhdr.base + elfsh_get_section_addr(text->shdr) : elfsh_get_section_addr(text->shdr)); /* Our address is valid ? */ if (!INTERVAL(base_vaddr, addr, (base_vaddr + len))) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Not in entrypoint section", -4); /* Setup asm_processor structure */ if (etrace_setup_proc(file, &proc) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Failed during proc structure setup", -1); /* Despite the fact that we choose the right architecture to init asm, Our approach is totally architecture independant as we search using global type ASM_TYPE_CALLPROC and we know that op[0].imm will contain a relative value. */ for (index = 0; index < len; index += ret) { /* Read an instruction */ if ((ret = asm_read_instr(&instr, (u_char *) (base + index), len - index, &proc))) { /* Global assembler filter */ if ((instr.type & ASM_TYPE_CALLPROC) && instr.op[0].imm != 0) { /* Found the correct call */ if (base_vaddr + index + instr.op[0].imm + instr.len == addr) { found = 1; break; } } } if (ret <= 0) ret = 1; } if (!found) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "No call found", -3); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * Relocate the just injected section * @param enew * @param reltab * @param stage * @return */ static int elfsh_relocate_etrel_section(elfshsect_t *enew, elfshsect_t *reltab, u_char stage) { elfsh_Rel *cur; volatile u_int index; elfsh_Sym *sym; volatile u_int size; eresi_Addr *dword; eresi_Addr addr; char *name; char tmpname[BUFSIZ]; elfshsect_t *sect; u_int entsz; elfshsect_t *plt; void *data; elfsh_Half symtype; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* ET_REL object is not mapped we use unconditionaly the ondisk relocation tables for such operation */ data = reltab->data; #if __DEBUG_RELADD__ fprintf(stderr, "[DEBUG_RELADD] Using reloc table from %s [%s] data at %p \n", reltab->parent->name, reltab->name, data); #endif /* Loop on the relocation table entries */ size = (reltab->shdr->sh_type == SHT_RELA ? sizeof(elfsh_Rela) : sizeof(elfsh_Rel)); size = reltab->shdr->sh_size / size; plt = elfsh_get_plt(enew->parent, NULL); if (NULL == plt && elfsh_dynamic_file(enew->parent)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get plt", -1); entsz = elfsh_get_pltentsz(enew->parent); if (entsz < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get pltentsz", -1); for (index = 0; index < size; index++) { #if __DEBUG_RELADD__ fprintf(stderr, "[DEBUG_RELADD] relocation loop stage %u for section %s index %u \n", stage, enew->name, index); #endif /* We try a enew relocation now that the ET_REL dependence is mapped */ retry: /* Get symbol value in ET_REL */ cur = (reltab->shdr->sh_type == SHT_RELA ? (void *) (((elfsh_Rela *) data) + index) : (void *) (((elfsh_Rel *) data) + index)); sym = elfsh_get_symbol_from_reloc(reltab->parent, cur); name = elfsh_get_symname_from_reloc(reltab->parent, cur); if (sym == NULL || name == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to find symbol in ET_REL", -1); /* Grab a pointer on the dword that need to be relocated */ dword = (eresi_Addr *) ((char *) elfsh_readmem(enew) + cur->r_offset); /* ** If symbol type is NOTYPE, we use ET_EXEC symtab, else if ** symbol link is COMMON, we use ET_REL symbol inserted in ET_EXEC ** during BSS sizescan in bss.c:elfsh_find_bsslen() */ symtype = elfsh_get_symbol_type(sym); if (elfsh_get_symbol_bind(sym) != STB_LOCAL && /* patch BEOS */ (symtype == STT_NOTYPE || elfsh_get_symbol_link(sym) == SHN_COMMON)) { if (stage == ELFSH_RELOC_STAGE2 && !strstr(name, "old_")) continue; /* If the symbol is not found and we are still in the first stage relocation, just pass it */ sym = elfsh_get_metasym_by_name(enew->parent, name); if (!sym) { switch (elfsh_find_relocsym(enew, reltab, &sym, name, stage, symtype)) { case 2: #if __DEBUG_STATIC__ fprintf(stderr, "[DEBUG_STATIC] RETRY\n"); #endif goto retry; break; case 0: continue; case 1: break; case -1: default: PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to satisfy symbol in ET_REL", -1); } } addr = sym->st_value; #if __DEBUG_RELADD__ fprintf(stderr, "[DEBUG_RELADD] Relocate using existing symbol %-20s " AFMT "]\n", name, (eresi_Addr) addr); #endif } /* Compute addr giving the injected section's vaddr in ET_EXEC */ else { /* All the following relocs are computed in stage 1 */ if (stage == ELFSH_RELOC_STAGE2) continue; /* Find target section in ET_REL */ sect = elfsh_get_section_by_index(reltab->parent, sym->st_shndx, NULL, NULL); if (sect == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cant find extracted section in ET_REL", -1); #if __DEBUG_RELADD__ fprintf(stderr, "[DEBUG_RELADD] Found -%s- section (idx = %u), now looking at " "injected base address\n", sect->name, sect->index); #endif /* Find corresponding inserted section in ET_EXEC */ snprintf(tmpname, sizeof(tmpname), "%s%s", reltab->parent->name, sect->name); sect = elfsh_get_section_by_name(enew->parent, tmpname, NULL, NULL, NULL); if (sect == NULL) { #if __DEBUG_RELADD__ elfsh_print_sectlist(reltab->parent, "HEH"); fprintf(stderr, "[DEBUG_RELADD] Did not found %s section (sym = %s) \n", tmpname, name); #endif PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cant find inserted section in ET_EXEC", -1); } /* Compute pointer value */ addr = sect->shdr->sh_addr; addr += ((elfsh_get_symbol_type(sym) == STT_SECTION && !FILE_IS_SPARC(sect->parent) && !FILE_IS_ALPHA64(sect->parent) && !FILE_IS_MIPS(sect->parent)) ? *dword : sym->st_value); #if __DEBUG_RELADD__ fprintf(stderr, "[DEBUG_RELADD] Relocate using section %-20s base [-> " AFMT "] \n", sect->name, (eresi_Addr) addr); #endif } /* Perform relocation */ if (elfsh_relocate_entry(enew, cur, dword, addr, reltab) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to relocate entry", -1); } PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * @brief Match a function in a symbol table. * @param sect Section pointer for symbol table. * @param num Element number. * @param preg Reguler expression to use. * @param func_list Function table. * @param count Counter pointer (from the table). * @param get_symname Function ptr to get symbol name. * @return Success (0) or Error (-1). */ static int trace_match_symtab(elfshsect_t *sect, int num, regex_t *preg, char ***func_list, u_int *count, char *(*get_symname)(elfshobj_t *f, elfsh_Sym *s)) { u_int index; elfsh_Sym *table; char *name; char **f_list; u_int cnum; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Check argument before anything */ if (!sect || !preg || !func_list || !count || !get_symname) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid parameters", -1); f_list = *func_list; cnum = *count; table = (elfsh_Sym *) (sect->shdr->sh_addr ? elfsh_readmem(sect) : sect->data); /* Parse every function */ for (index = 0; index < num; index++) { /* Only functions */ if (elfsh_get_symbol_type(table + index) != STT_FUNC || table[index].st_value == 0) continue; name = get_symname(sect->parent, table + index); /* Check if this name is valid */ if (name == NULL || *name == 0) continue; /* We match a function */ if (regexec(preg, name, 0, 0, 0) == 0) { /* Do we need to realloc ? */ if (((cnum+1) % TRACE_MATCH_ALLOCSTEP) == 0) { XREALLOC(__FILE__, __FUNCTION__, __LINE__, f_list, f_list, sizeof(char*) * (cnum + 1 + TRACE_MATCH_ALLOCSTEP), -1); /* Blank new elements */ memset(&f_list[cnum], 0x00, TRACE_MATCH_ALLOCSTEP*sizeof(char*)); /* Update the pointer, data can move during a reallocation */ *func_list = f_list; } /* Add the function in the table */ f_list[cnum] = name; *count = ++cnum; } } PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * Static hooking for Mips32 * Note : a new technique is beeing considered that * may invalidate this handler as it (at least * change the way it should be implemented) * * Make sure to ask anything before deciding to implement it * * @param file * @param name * @param symbol * @param addr */ int elfsh_cflow_mips32(elfshobj_t *file, char *name, elfsh_Sym *symbol, eresi_Addr addr) { elfshsect_t *hooks; elfshsect_t *source; uint32_t buff[3]; int ret, len; int off; char *hookbuf; char *hook; //elfsh_Sym sym; char bufname[BUFSIZ]; void *data; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* func+0: [addu t9, (hook-func)] func+4: [jump hook] func+8: [nop] func+c: [???] hook: ... old_entry+0: [addu t9, (func-old_entry)] old_entry+4: [instr1] old_entry+8: [instr2] old_entry+c: [instr3] old_entry+10: [jmp func+8] old_entry+14: [nop] */ /* Resolve parameters */ off = elfsh_get_foffset_from_vaddr(file, symbol->st_value); if (!off) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid address to hijack", -1); ret = elfsh_readmemf(file, off, (void *) buff, 3*4); if (ret != 3*4) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Function too small to be hijacked", -1); /* If the hook section does not exist, create it */ hooks = elfsh_get_section_by_name(file, ELFSH_SECTION_NAME_HOOKS, 0, 0, 0); if (!hooks) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot get .HOOKS", -1); hook = (char *) (hooks->shdr->sh_addr + hooks->curend); if (((uint32_t) symbol->st_value & 0xf0000000) != (addr & 0xf0000000)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "hook function too far from hijacked function", -1); if (((uint32_t) hook & 0xf0000000) != ((symbol->st_value + 0x8) & 0xf0000000)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "hook section too far from hijacked function", -1); if ((addr - (uint32_t) symbol->st_value) & (0xffffffff<<16)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "hook function too far from hijacked function", -1); if (((uint32_t) symbol->st_value - (uint32_t) hook) & (0xffffffff<<16)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "hook section too far from hijacked function", -1); /* Determine the minimal aligned length */ /* RISC's powa */ /* 3 instructions : 1 add t9..., 1 jmp, 1 nop for delay slot */ ret = 3 * 4; /* Create the hook for this function */ data = elfsh_readmem(hooks); memset(data + hooks->curend, 0x00, 40); // nop /* addi $t, $s, imm : 0010 00ss ssst tttt iiii iiii iiii iiii */ *((uint32_t *) ((char *) (data + hooks->curend) + 0x0)) = 0x23390000; *((uint32_t *) ((char *) (data + hooks->curend) + 0x0)) |= (((uint32_t) symbol->st_value - (uint32_t)hook) & 0x0000ffff); /* first three hijacked function's instructions */ *((uint32_t *) ((char *) (data + hooks->curend) + 0x4)) = buff[0]; *((uint32_t *) ((char *) (data + hooks->curend) + 0x8)) = buff[1]; *((uint32_t *) ((char *) (data + hooks->curend) + 0xc)) = buff[2]; /* non-linked jump to func + 8 (where should be a NOP) */ /* mips32 jump use the 4 MSB of PC reg and 26 bits from instruction left shited by 2 */ memcpy(data + hooks->curend + 0x10, "\x08\x00\x00\x00", 4); *((uint32_t *) ((char *) (data + hooks->curend) + 0x10)) |= ((symbol->st_value + 0x8) & (~ 0xe0000000 ))>>2; /* NOTE : there must be a NOP after this last jump */ /* Insert the old symbol on the original saved bytes */ //name = elfsh_get_symbol_name(file, symbo); snprintf(bufname, BUFSIZ, "old_%s", name); elfsh_insert_funcsym(file, bufname, (eresi_Addr) hook, ret + 0x10, hooks->index); /* snprintf(bufname, BUFSIZ, "hook_%s", name); elfsh_insert_funcsym(file, bufname, addr, ret + 8, hooks->index); */ /* We need to grab the parent section to compute the remaining offset */ source = elfsh_get_parent_section_by_foffset(file, off, NULL); if (!source) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot find parent section for hooked addr", -1); /* Install the hook */ hookbuf = alloca(ret); /* patch t9 reg */ *((uint32_t *) ((char *) (hookbuf) + 0x0)) = 0x23390000; *((uint32_t *) ((char *) (hookbuf) + 0x0)) |= ((addr - symbol->st_value) & 0x0000ffff); /* jump to hook func */ *((uint32_t *) ((char *) (hookbuf) + 0x4)) = 0x08000000; *((uint32_t *) ((char *) (hookbuf) + 0x4)) |= ((uint32_t) (addr ) & (~0xe0000000))>>2; /* delay slot's NOP */ *((uint32_t *) ((char *) (hookbuf) + 0x8)) = 0x00000000; len = elfsh_writememf(file, off, hookbuf, ret); if (len != ret) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Error during hook installation", -1); /* Everything OK, ret is always 3*4 on mips32 (RISC strike again) */ hooks->curend += ret + 6; // (6 = 1 add, 3 instr, 1 jump, 1 nop) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * ALTPLT hijacking on MIPS32 * * On MIPS we need to restore 2 words from .alt.got to .got * and callback __libc_start_main. * * Update: we also need to copy .got values for extern * variables. We put ld/st pairs in .pad.got so that we * fill those only one time, before calling __libc_start_main * * The code works and is functional -mm * * @param file * @param symbol * @param addr * @return */ int elfsh_hijack_altplt_mips32(elfshobj_t *file, elfsh_Sym *symbol, eresi_Addr addr) { elfshsect_t *altgotprolog, *altgot, *padgot, *got, *start; elfshsect_t *dynsym, *dynamic; elfsh_Sym *sym; elfsh_Dyn *dynent, *dynent2; uint32_t gotno, gotsym; u_int varnbr, gotnbr, symnbr; u_int opcodendx, gotindex, index, varindex; uint32_t *opcode; uint16_t diff; uint16_t gotdiff; uint32_t *originstr; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Regular checks */ if (!FILE_IS_MIPS(file)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "File is not MIPS", -1); altgotprolog = file->secthash[ELFSH_SECTION_ALTGOTPROLOG]; altgot = file->secthash[ELFSH_SECTION_ALTGOT]; padgot = file->secthash[ELFSH_SECTION_PADGOT]; got = file->secthash[ELFSH_SECTION_GOT]; start = file->secthash[ELFSH_SECTION_MIPSTART]; dynsym = file->secthash[ELFSH_SECTION_DYNSYM]; dynamic = file->secthash[ELFSH_SECTION_DYNAMIC]; if (!altgotprolog || !altgot || !got || !padgot || !dynsym || !dynamic) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot find GOT, ALTGOTPROLOG, ALTGOT" " PADGOT, DYSYM, DYNAMIC or MIPSTART section", -1); /* Signed 16bits displacement from %gp to last word of .pad.got */ diff = 0x800c; originstr = elfsh_readmem(padgot->data) + padgot->shdr->sh_size - 4; *originstr = altgotprolog->shdr->sh_addr; gotdiff = (uint16_t) got->shdr->sh_addr - altgot->shdr->sh_addr; /* Valid _start signature on Linux, may you FIXME for other OS */ /* lw t9, __libc_start_main_off(gp) */ originstr = ((uint32_t *) elfsh_readmem(start) + 19); /* Grab infos on .got using .dynamic */ dynent = elfsh_get_dynamic_entry_by_type(file, DT_MIPS_GOTSYM); gotsym = (dynent ? elfsh_get_dynentry_val(dynent) : 0); symnbr = dynamic->shdr->sh_size / sizeof(elfsh_Sym); if (symnbr < gotsym) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "DYNSYM smaller than DT_MIPS_GOTSYM", -1); dynent2 = elfsh_get_dynamic_entry_by_type(file, DT_MIPS_LOCAL_GOTNO); gotno = (dynent2 ? elfsh_get_dynentry_val(dynent2) : 0); gotnbr = got->shdr->sh_size / sizeof(eresi_Addr); if (gotnbr < gotno) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "GOT smaller than DT_MIPS_GOTSYM", -1); sym = elfsh_readmem(dynsym); sym += gotsym; /* Find all .dynsym entries matching external variables (Assuming .got and .rel entries are in the same order) Copy their .alt.got entries value in .got */ for (varnbr = 0, gotindex = gotno, index = gotsym; index < symnbr && gotno < gotnbr; index++, gotindex++) if (elfsh_get_symbol_type(sym + index) == STT_OBJECT && !sym[index].st_value) varnbr++; printf("[DEBUG_GOTPLT:mips] Found %u extern variables\n", varnbr); XALLOC(__FILE__, __FUNCTION__, __LINE__,opcode, (9 + (varnbr * 2)) * sizeof(uint32_t), -1); /* __asm__("addi $t0, $gp, 0x8010;"); __asm__("addi $t1, $t0, gotdiff;"); __asm__("lw $t2, 0($t0);"); __asm__("lw $t3, 4($t0);"); __asm__("sw $t2, 0($t1);"); __asm__("sw $t3, 4($t1);"); __asm__("lw $t9, __libc_start_main_off($gp)"); <=== __asm__("jr $t9;"); __asm__("nop;"); */ opcode[0] = 0x23888010; /* compute .alt.got addr */ opcode[1] = 0x21090000 | gotdiff; /* compute .got addr */ opcode[2] = 0x8d0a0000; /* load first .alt.got word */ opcode[3] = 0x8d0b0004; /* load second .alt.got word */ opcode[4] = 0xad2a0000; /* write first .alt.got word into .got */ opcode[5] = 0xad2b0004; /* write second .alt.got word into .got */ opcode[6] = *originstr; /* reload __libc_start_main addr into $t9 */ /* Compute the static __libc_start_main hijack in .start */ *originstr = (*originstr & 0xFFFF0000) | diff; /* Now generate the ld/st pairs a la mano residing in .pad.got */ printf("Using GOTNO = %u and GOTSYM = %u\n", gotno, gotsym); opcodendx = 7; for (index = varindex = 0, gotindex = gotno; varindex < varnbr; index++, gotindex++) if (elfsh_get_symbol_type(sym + index) == STT_OBJECT && !sym[index].st_value) { printf("Using GOT index %u \n", gotindex); opcode[opcodendx++] = 0x8d0a0000 | (uint16_t) gotindex * sizeof(eresi_Addr); opcode[opcodendx++] = 0xad2a0000 | (uint16_t) gotindex * sizeof(eresi_Addr); varindex++; } opcode[opcodendx++] = 0x0320f809; /* call restored $t9 */ opcode[opcodendx++] = 0x00000000; /* nop delay slot */ if (padgot->shdr->sh_size < sizeof(uint32_t) * varnbr * 2) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".pad.got section too small", -1); elfsh_writememf(file, altgotprolog->shdr->sh_offset, opcode, sizeof(uint32_t) * 7); elfsh_writememf(file, padgot->shdr->sh_offset, opcode + 7, sizeof(uint32_t) * (2 + (varnbr * 2))); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * @brief On MIPS there is no .plt section : call to libraries are done * using an indirect jump on .got value directly from .text. If * we want to be able to call the original function from the hook * function, we need to create a plt-like section and mirror the * Global Offset Table (.got). * * By default, .got points in some code stub standing in .text. This * code stubs looks much like a PLT. Indeed, there is a kind of PLT * on MIPS but it is embedded in the .text section. What we do in this * function is to disambiguize .plt and .text, so that we can apply * ALTPLT technique as well on MIPS. * * Unlike on ALPHA, we cannot move relocations from .got to .alt.got * since MIPS binaries have no relocation tables in ET_EXEC objects. * What we do instead is changing the processor specific DT_PLTGOT * entry in the .dynamic section and continue to rely on the ALTPLT * technique (call's the original functions using the injected 'old_' * symbol) just like ALTPLT redirection on other architectures. -mm * * @param file Host file. * @return Success (0) or Error (-1). */ int elfsh_build_plt(elfshobj_t *file) { elfshsect_t *text; elfsh_SAddr off; char buff[16] = {0x00}; eresi_Addr pltaddr = 0; eresi_Addr pltend = 0; elfsh_Shdr start; elfsh_Shdr plt; elfshsect_t *enew; eresi_Addr lsize; unsigned int size; char *data; char *tdata; unsigned int idx; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* First checks */ text = elfsh_get_parent_section(file, elfsh_get_entrypoint(file->hdr), &off); if (!text) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot find parent section from entry point", -1); if (!elfsh_get_anonymous_section(file, text)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get an anonymous section", -1); /* ** Find the embedded plt by searching the nop;nop;nop;nop; signature ** that delimit the beginning and the end of plt. This is MIPS specific ** since only MIPS needs this. */ tdata = elfsh_readmem(text); for (off = 0; off < text->shdr->sh_size; off += 4) if (!memcmp(tdata + off, buff, sizeof(buff))) { pltaddr = text->shdr->sh_addr + off + 16; for (off += 16; off < text->shdr->sh_size; off += 4) if (!memcmp(tdata + off, buff, 16)) { pltend = text->shdr->sh_addr + off + 16; goto found; } PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot find PLT end", -1); } found: idx = text->index; if (!pltaddr) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot find PLT start", -1); /* ** Now create additional section header table entries so that we reduce the ** MIPS model to our standard ALTPLT/ALTGOT model. ** ** Do not use the elfsh_insert_*_section() since we want no address space ** shifting. */ /* .start */ lsize = pltaddr - text->shdr->sh_addr; size = (unsigned int) lsize; start = elfsh_create_shdr(0, SHT_PROGBITS, SHF_EXECINSTR | SHF_ALLOC, text->shdr->sh_addr, text->shdr->sh_offset, size, 0, 0, 0, 0); enew = elfsh_create_section(ELFSH_SECTION_NAME_START); XALLOC(__FILE__, __FUNCTION__, __LINE__,data, size, -1); memcpy(data, tdata, size); elfsh_insert_shdr(file, start, idx, enew->name, 0); elfsh_add_section(file, enew, idx, data, ELFSH_SHIFTING_MIPSPLT); file->secthash[ELFSH_SECTION_MIPSTART] = enew; /* .plt */ lsize = pltend - pltaddr; size = (unsigned int) lsize; plt = elfsh_create_shdr(0, SHT_PROGBITS, SHF_EXECINSTR | SHF_ALLOC, start.sh_addr + start.sh_size, start.sh_offset + start.sh_size, size, 0, 0, 0, 0); enew = elfsh_create_section(ELFSH_SECTION_NAME_PLT); XALLOC(__FILE__, __FUNCTION__, __LINE__,data, size, -1); memcpy(data, tdata + start.sh_size, size); elfsh_insert_shdr(file, plt, idx + 1, enew->name, 0); elfsh_add_section(file, enew, idx + 1, data, ELFSH_SHIFTING_MIPSPLT); /* Shift .text data, sh_offset, sh_addr, and sh_size correctly */ text->shdr->sh_offset += (start.sh_size + plt.sh_size); text->shdr->sh_addr += (start.sh_size + plt.sh_size); memmove(tdata, tdata + start.sh_size + plt.sh_size, text->shdr->sh_size - (start.sh_size + plt.sh_size)); text->shdr->sh_size -= (start.sh_size + plt.sh_size); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * @brief Display relocation entries */ int cmd_rel() { elfshsect_t *sect; elfsh_Rel *rel; regex_t *tmp; char *type; char *typeshort; char *name; u_int index; u_int index2; u_int typenum; char buff[256]; u_int size; revmconst_t *types; char addstr[32]; char logbuf[BUFSIZ]; void *data; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Sanity checks */ sect = elfsh_get_reloc(world.curjob->curfile, 0, &size); if (sect == NULL) RET(-1); /* Choose between global or local regx */ FIRSTREGX(tmp); snprintf(logbuf, BUFSIZ - 1, " [RELOCATION TABLES]\n [Object %s]\n\n", world.curjob->curfile->name); revm_output(logbuf); /* We need to iterate as much as there is .rel* sections */ for (index2 = 0; sect; index2++) { snprintf(logbuf, BUFSIZ - 1, " {Section %s} \n", elfsh_get_section_name(world.curjob->curfile, sect)); revm_output(logbuf); /* Iterate on the .rel entries array for each .rel section */ data = elfsh_readmem(sect); for (index = 0; index < size; index++) { /* Get the current relocation entry */ if (sect->shdr->sh_type == SHT_RELA) { rel = (void *) ((elfsh_Rela *) data + index); snprintf(addstr, sizeof(addstr), "add[%s]", revm_colornumber("%08u", (unsigned int) ((elfsh_Rela *) rel)->r_addend)); } else { rel = (elfsh_Rel *) data + index; addstr[0] = 0x00; } /* Get linked symbol name */ name = elfsh_get_symname_from_reloc(world.curjob->curfile, rel); typenum = elfsh_get_reltype(rel); types = revm_getrelascii(world.curjob->curfile); type = (char *) (typenum > ELFSH_RELOC_MAX(world.curjob->curfile) ? NULL : types[typenum].desc); typeshort = (char *) (typenum > ELFSH_RELOC_MAX(world.curjob->curfile) ? NULL : types[typenum].name); /* Output is different depending on the quiet flag */ if (!world.state.revm_quiet) snprintf(buff, sizeof(buff), " [%s] %s %s %s%s%s : %s %s => %s\n", revm_colornumber("%03u", index), revm_colortypestr_fmt("%-15s", typeshort), revm_coloraddress(XFMT, elfsh_get_reloffset(rel)), revm_colorfieldstr("sym["), revm_colornumber("%03u", elfsh_get_relsym(rel)), revm_colorfieldstr("]"), (name != NULL ? revm_colorstr_fmt("%-30s", name) : revm_colorwarn_fmt("%-30s", "<?>")), addstr, revm_colortypestr(type)); else snprintf(buff, sizeof(buff), " [%s] %s %s %s%s%s : %s %s\n", revm_colornumber("%03u", index), revm_colortypestr_fmt("%-15s", typeshort), revm_coloraddress(XFMT, elfsh_get_reloffset(rel)), revm_colorfieldstr("sym["), revm_colornumber("%03u", elfsh_get_relsym(rel)), revm_colorfieldstr("]"), (name != NULL ? revm_colorstr_fmt("%-22s", name) : revm_colorwarn_fmt("%-22s", "<?>")), addstr); /* Print it if it matchs the regex */ if (NULL == tmp || (tmp != NULL && name != NULL && 0 == regexec(tmp, buff, 0, 0, 0))) switch (revm_output(buff)) { case -1: revm_endline(); revm_output("\n"); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); case -2: revm_endline(); goto next; } revm_endline(); } next: sect = elfsh_get_reloc(world.curjob->curfile, index2 + 1, &size); revm_output("\n"); } revm_output("\n"); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * Load linkmap * @param name * @return */ int e2dbg_linkmap_load(char *name) { static int done = 0; elfshsect_t *got; eresi_Addr *linkmap_entry; void *data; #if defined(sun) Link_map *actual; #else elfshlinkmap_t *actual; #endif char *gotname; char *ename; elfsh_Ehdr *hdr; u_int elftypenum; elfsh_Sym *endsym; char buff[64]; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (done) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg] Starting Loading LINKMAP !! \n"); #endif e2dbg_user_hooks_install(); revm_config(E2DBG_CONFIG); /* Load debugged file */ if (name) { /* No need to fill ET_EXEC base addr */ if (!revm_is_loaded(name) && revm_file_load(name, 0, NULL) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot load file", -1); #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] file %s loaded\n", name); #endif world.curjob->curfile->linkmap = E2DBG_DYNAMIC_LINKMAP; world.curjob->curfile->iotype = ELFSH_IOTYPE_EMBEDDED; world.curjob->curfile->running = 0; } #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] Before switch\n"); #endif /* Switch to obj 1 */ if (revm_doswitch(1) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot switch on object 1", -1); #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] After switch \n"); #endif /* Base address for PIE binaries have to be imported */ if (world.curjob->curfile->hdr->e_type == ET_DYN && !world.curjob->curfile->rhdr.base) { #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] Inside ET_DYN condition\n"); #endif endsym = elfsh_get_symbol_by_name(world.curjob->curfile, "_end"); fprintf(stderr, "endsym = " AFMT " \n", (eresi_Addr) endsym); sleep(1); #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] Filling PIE base" " (_end ondisk = " AFMT " / _end in memory = " AFMT ") ! \n", endsym->st_value, e2dbgworld.syms.piebase); #endif world.curjob->curfile->rhdr.base = e2dbgworld.syms.piebase - endsym->st_value; } /* Get ALTGOT or GOT if we used LD_PRELOAD */ if (!e2dbgworld.preloaded) { gotname = ELFSH_SECTION_NAME_ALTGOT; got = elfsh_get_section_by_name(world.curjob->curfile, gotname, NULL, NULL, NULL); } else got = elfsh_get_gotsct(world.curjob->curfile); #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] %s section at " XFMT "\n", got->name, got->shdr->sh_addr); fprintf(stderr, "[e2dbg_linkmap_load] BASE = %08x\n", world.curjob->curfile->rhdr.base); #endif /* Fix first file linkmap entry */ if (world.curjob->curfile->linkmap == E2DBG_DYNAMIC_LINKMAP) { /* Fix first file linkmap entry */ hdr = elfsh_get_hdr(world.curjob->curfile); if (!hdr) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot get ELF header", -1); elftypenum = elfsh_get_objtype(hdr); //fprintf(stderr, "[e2dbg_linkmap_load] after ELF header \n"); /* Get ALTGOT entry */ data = elfsh_readmem(got); //fprintf(stderr, "[e2dbg_linkmap_load] after get_raw (data = %08X) \n", data); linkmap_entry = elfsh_get_got_entry_by_index(data, 1); //fprintf(stderr, "[e2dbg_linkmap_load] after entry_by_index (linkmap_entry = %08x)\n", // linkmap_entry); #if defined(__FreeBSD__) || defined(__NetBSD__) world.curjob->curfile->linkmap = (elfshlinkmap_t *) &((Obj_Entry *) elfsh_get_got_val(linkmap_entry))->linkmap; #elif defined(sun) world.curjob->curfile->linkmap = e2dbgworld.syms.map; #else world.curjob->curfile->linkmap = (elfshlinkmap_t *) elfsh_get_got_val(linkmap_entry); #endif } #if __DEBUG_LINKMAP__ else fprintf(stderr, "[e2dbg_linkmap_load] Linkmap was -NOT- dynamic\n"); fprintf(stderr, "[e2dbg_linkmap_load] LINKMAP Found at " XFMT "\n", world.curjob->curfile->linkmap); #endif revm_doswitch(1); /* now load all linkmap's files */ for (actual = elfsh_linkmap_get_lprev(world.curjob->curfile->linkmap); actual != NULL; actual = elfsh_linkmap_get_lprev(actual)) { #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] Running on LINKMAP PREV " XFMT "\n", actual); #endif ename = elfsh_linkmap_get_lname(actual); if (ename && *ename && !revm_is_loaded(ename)) { if (revm_file_load(ename, elfsh_linkmap_get_laddr(actual), world.curjob->curfile->linkmap) < 0) e2dbg_output(" [EE] Loading failed"); world.curjob->curfile->iotype = ELFSH_IOTYPE_EMBEDDED; } } #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] Running on LINKMAP NEXT\n"); #endif for (actual = elfsh_linkmap_get_lnext(world.curjob->curfile->linkmap); actual != NULL; actual = elfsh_linkmap_get_lnext(actual)) { ename = elfsh_linkmap_get_lname(actual); #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] Running on LINKMAP NEXT " XFMT " (%s baseaddr %08X) \n", actual, ename, actual->laddr); #endif if (ename && *ename && !revm_is_loaded(ename)) { if (revm_file_load(ename, elfsh_linkmap_get_laddr(actual), world.curjob->curfile->linkmap) < 0) e2dbg_output(" [EE] Loading failed"); world.curjob->curfile->iotype = ELFSH_IOTYPE_EMBEDDED; } } /* Everything was OK */ e2dbg_output("\n"); //elfsh_set_runtime_mode(); revm_doswitch(1); snprintf(buff, sizeof(buff), " [*] Target PID = %u \n", getpid()); e2dbg_output(buff); done = 1; PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * Print the chosen symbol table * @param file * @param sect * @param tab * @param num * @param regx * @param get_symname * @return */ int ds(elfshobj_t *file, elfshsect_t *sect, u_int num, regex_t *regx, char *(*get_symname)(elfshobj_t *f, elfsh_Sym *s)) { elfsh_Sym *table; char *name; char *type; char *bind; u_int typenum; u_int bindnum; u_int foff; u_int index; char *sect_name; char buff[512]; char off[50]; char type_unk[ERESI_MEANING + 1]; char bind_unk[ERESI_MEANING + 1]; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Sort the table if necessary */ if (world.state.sort != NULL) switch (*world.state.sort) { case ELFSH_SORT_BY_ADDR: table = sect->altdata; break; case ELFSH_SORT_BY_SIZE: table = sect->terdata; break; default: PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unknown sort mode", -1); } /* Avoid reading inexistant memory in the process for .symtab */ else table = (elfsh_Sym *) (sect->shdr->sh_addr ? elfsh_readmem(sect) : sect->data); /* Browse symtab */ for (index = 0; index < num; index++) { /* Retreive names */ typenum = elfsh_get_symbol_type(table + index); bindnum = elfsh_get_symbol_bind(table + index); type = (char *) (typenum > ELFSH_SYMTYPE_MAX ? revm_build_unknown(type_unk, "type", typenum) : elfsh_sym_type[typenum].desc); bind = (char *) (bindnum >= ELFSH_SYMBIND_MAX ? revm_build_unknown(bind_unk, "type", bindnum) : elfsh_sym_bind[bindnum].desc); name = get_symname(world.curjob->curfile, table + index); sect_name = NULL; sect = elfsh_get_parent_section(world.curjob->curfile, table[index].st_value, NULL); if (sect == NULL && table[index].st_shndx) sect = elfsh_get_section_by_index(world.curjob->curfile, table[index].st_shndx, NULL, NULL); if (sect != NULL) sect_name = elfsh_get_section_name(world.curjob->curfile, sect); /* Fixup names */ if (name == NULL || *name == 0) name = ELFSH_NULL_STRING; if (type == NULL || *type == 0) type = ELFSH_NULL_STRING; if (bind == NULL || *bind == 0) bind = ELFSH_NULL_STRING; if (sect_name == NULL) sect_name = ELFSH_NULL_STRING; foff = (!table[index].st_value ? 0 : elfsh_get_foffset_from_vaddr(world.curjob->curfile, table[index].st_value)); if (sect && sect->shdr->sh_addr != table[index].st_value) snprintf(off, sizeof(off), " + %s", revm_colornumber("%u", (u_int) (table[index].st_value - sect->shdr->sh_addr))); else *off = '\0'; /* Different output depending on the quiet flag */ if (!world.state.revm_quiet) { snprintf(buff, sizeof(buff), " %s %s %s %s %s%s " "%s%s %s%s %s%s => %s%s\n", revm_colornumber("[%03u]", index), revm_coloraddress(XFMT, (eresi_Addr) elfsh_get_symbol_value(table + index) + file->rhdr.base), revm_colortypestr_fmt("%-8s", type), revm_colorstr_fmt("%-40s", name), revm_colorfieldstr("size:"), revm_colornumber("%010u", elfsh_get_symbol_size(table + index)), revm_colorfieldstr("foffset:"), revm_colornumber("%06u", foff), revm_colorfieldstr("scope:"), revm_colortypestr_fmt("%-6s", bind), revm_colorfieldstr("sctndx:"), revm_colornumber("%02u", elfsh_get_symbol_link(table + index)), revm_colorstr(sect_name), off); } else { snprintf(buff, sizeof(buff), " %s %s %s %s %s%s %s%s %s%-6s\n", revm_colornumber("[%03u]", index), revm_coloraddress(XFMT, (eresi_Addr) elfsh_get_symbol_value(table + index) + file->rhdr.base), revm_colortypestr_fmt("%-8s", type), revm_colorstr_fmt("%-15s", name), revm_colorfieldstr("sz:"), revm_colornumber("%06u", elfsh_get_symbol_size(table + index)), revm_colorfieldstr("foff:"), revm_colornumber("%06u", foff), revm_colorfieldstr("scop:"), revm_colortypestr_fmt("%-6s", bind)); } if (regx == NULL || (regx != NULL && regexec(regx, buff, 0, 0, 0) == 0)) { /* If the user ask quit, we just break */ if (revm_output(buff) == -1) break; } revm_endline(); } revm_endline(); revm_output("\n"); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * Change endianess of .dynamic * @param newent * @return */ int elfsh_endianize_dynamic(elfshsect_t *newent) { elfsh_Dyn *dyn; u_int idx; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Sanity check */ if (!newent) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL parameter", -1); #if __BYTE_ORDER == __LITTLE_ENDIAN if (newent->parent->hdr->e_ident[EI_DATA] == ELFDATA2MSB) { #elif __BYTE_ORDER == __BIG_ENDIAN if (newent->parent->hdr->e_ident[EI_DATA] == ELFDATA2LSB) { #else #error Unexpected __BYTE_ORDER ! #endif dyn = (elfsh_Dyn *) elfsh_readmem(newent); for (idx = 0; idx < newent->shdr->sh_size / sizeof(elfsh_Dyn); idx++) { dyn[idx].d_tag = swaplong(dyn[idx].d_tag); dyn[idx].d_un.d_val = swaplong(dyn[idx].d_un.d_val); } } PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); } /** * Return a ptr on the dynamic section * @param file * @param num * @return */ elfsh_Dyn *elfsh_get_dynamic(elfshobj_t *file, u_int *num) { elfshsect_t *newent = NULL; /* to shut gcc up with -Wall */ int nbr; elfsh_Dyn *ret; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (file->secthash[ELFSH_SECTION_DYNAMIC] == NULL) { newent = elfsh_get_section_by_type(file, SHT_DYNAMIC, NULL, NULL, &nbr, 0); if (newent == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get .dynamic by type", NULL); file->secthash[ELFSH_SECTION_DYNAMIC] = newent; } newent = file->secthash[ELFSH_SECTION_DYNAMIC]; nbr = file->secthash[ELFSH_SECTION_DYNAMIC]->shdr->sh_size / sizeof(elfsh_Dyn); if (num != NULL) *num = nbr; if (newent->data == NULL) { newent->data = elfsh_load_section(file, newent->shdr); if (newent->data == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to load .dynamic", NULL); elfsh_endianize_dynamic(newent); } ret = (elfsh_Dyn *) elfsh_readmem(newent); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, ret); }
/** * @brief Copy the PLT of an ET_EXEC object for the ALTPLT technique. * and the GOT of an ET_EXEC object for the ALTGOT technique. * @param file Host file. * @param mod Always inject sections with size being a multiple of mod. * @return Success (0) or Error (-1). */ int elfsh_relink_plt(elfshobj_t *file, u_int mod) { elfshsect_t *got; elfshsect_t *plt; elfshsect_t *symtab; elfshsect_t *dynsym; elfshsect_t *prolog; elfshsect_t *extplt = NULL; elfshsect_t *altgot = NULL; /* shut the nice talkative */ elfshsect_t *enew = NULL; /* compiler also know as gcc */ elfsh_Shdr hdr; elfsh_Sym *sym; elfsh_Sym newsym; char buf[BUFSIZ]; u_int off; u_int entsz; int mode; eresi_Addr addr; char *prologdata; u_int sz; char *name; u_char ostype; eresi_Addr diff; u_int extplt_size; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Get PLT */ if (file->secthash[ELFSH_SECTION_ALTPLT] != NULL) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); plt = elfsh_get_plt(file, NULL); if (NULL == plt) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "PLT section not found", -1); entsz = elfsh_get_pltentsz(file); if (entsz < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Failed to get PLT entry size", -1); /* Get GOT (recent ld call it .got.plt) */ got = elfsh_get_gotsct(file); if (NULL == got) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "GOT section not found", -1); /* Get symtabs */ if (NULL == elfsh_get_dynsymtab(file, NULL)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "DYNSYM not found", -1); if (NULL == elfsh_get_symtab(file, NULL)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "SYMTAB not found", -1); /* Some fingerprint */ ostype = elfsh_get_ostype(file); if (ostype == ELFSH_OS_ERROR) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid OS target", -1); /* Insert alternative .plt */ dynsym = file->secthash[ELFSH_SECTION_DYNSYM]; symtab = file->secthash[ELFSH_SECTION_SYMTAB]; /* FreeBSD and BeoS is incompatible with pre-interp injection */ /* Solaris needs self-mutating code for ALTPLT technique */ /* %gp offsets on ALPHA/MIPS requires data injection */ ELFSH_SELECT_INJECTION(file,NULL,mode); /* Map .alt.plt.prolog on ALPHA, or .alt.got.prolog on MIPS */ if (FILE_IS_MIPS(file) || FILE_IS_ALPHA64(file)) { if (FILE_IS_MIPS(file)) { name = ELFSH_SECTION_NAME_ALTGOTPROLOG; sz = 28; } else { name = ELFSH_SECTION_NAME_ALTPLTPROLOG; sz = 48; } prolog = elfsh_create_section(name); hdr = elfsh_create_shdr(0, SHT_PROGBITS, SHF_EXECINSTR | SHF_ALLOC, 0, 0, sz, 0, 0, 0, 0); XALLOC(__FILE__, __FUNCTION__, __LINE__, prologdata, sz, -1); if (elfsh_insert_mapped_section(file, prolog, hdr, prologdata, mode, mod) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.{plt,got}.prolog insertion failed", -1); enew = elfsh_get_section_by_name(file, name, NULL, NULL, NULL); if (enew == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.{plt,got}.prolog insertion failed", -1); file->secthash[ELFSH_SECTION_ALTPLTPROLOG] = enew; } /* Map .alt.plt (or .pad.got on MIPS) On MIPS we use .pad.got in order to align .alt.got on a 0x1000 bound boundary. On ALPHA and SPARC, .alt.plt will be relocated instead of .plt */ sz = plt->shdr->sh_size; if (FILE_IS_MIPS(file)) { addr = enew->shdr->sh_addr + enew->shdr->sh_size; if ((addr - (got->shdr->sh_addr)) % 1024) sz = 1024 - ((addr - (got->shdr->sh_addr)) % 1024); XALLOC(__FILE__, __FUNCTION__, __LINE__, prologdata, sz, -1); memset(prologdata, 0x00, sz); name = ELFSH_SECTION_NAME_PADGOT; } else { XALLOC(__FILE__, __FUNCTION__, __LINE__, prologdata, sz, -1); memcpy(prologdata, elfsh_readmem(plt), sz); name = ELFSH_SECTION_NAME_ALTPLT; } enew = elfsh_create_section(name); hdr = elfsh_create_shdr(0, SHT_PROGBITS, SHF_EXECINSTR | SHF_ALLOC, 0, 0, sz, 0, 0, 0, 0); if (elfsh_insert_mapped_section(file, enew, hdr, prologdata, mode, mod) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.plt|.pad.got insertion failed", -1); enew = elfsh_get_section_by_name(file, name, NULL, NULL, NULL); if (enew == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.plt|.pad.got insertion failed", -1); file->secthash[ELFSH_SECTION_ALTPLT] = enew; /* Map .alt.got (all architectures except SPARC) */ /* On IA32, remap GOT with a doubled size for non-present symbol resolving */ if (FILE_IS_MIPS(file) || FILE_IS_ALPHA64(file) || FILE_IS_IA32(file)) { sz = (FILE_IS_MIPS(file) ? got->shdr->sh_size : FILE_IS_IA32(file) ? got->shdr->sh_size * 4 : plt->shdr->sh_size / elfsh_get_pltentsz(file) * sizeof(eresi_Addr)); altgot = elfsh_create_section(ELFSH_SECTION_NAME_ALTGOT); hdr = elfsh_create_shdr(0, SHT_PROGBITS, SHF_ALLOC | SHF_WRITE, 0, 0, sz, 0, 0, 0, sizeof(eresi_Addr)); XALLOC(__FILE__, __FUNCTION__, __LINE__, prologdata, sz, -1); memcpy(prologdata, elfsh_readmem(got), got->shdr->sh_size); if (elfsh_insert_mapped_section(file, altgot, hdr, prologdata, ELFSH_DATA_INJECTION, mod) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.got insertion failed", -1); altgot = elfsh_get_section_by_name(file, ELFSH_SECTION_NAME_ALTGOT, NULL, NULL, NULL); if (altgot == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.got insertion failed", -1); file->secthash[ELFSH_SECTION_ALTGOT] = altgot; altgot->curend = got->shdr->sh_size; memset(elfsh_readmem(altgot) + got->shdr->sh_size, 0x00, got->shdr->sh_size); altgot->shdr->sh_entsize = sizeof(eresi_Addr); } /* Insert EXTPLT in order to be able to resolve non present symbols */ if (FILE_IS_IA32(file)) { extplt_size = plt->shdr->sh_size * 2; extplt = elfsh_create_section(ELFSH_SECTION_NAME_EXTPLT); hdr = elfsh_create_shdr(0, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0, 0, extplt_size, 0, 0, 0, 0); XALLOC(__FILE__, __FUNCTION__, __LINE__, prologdata, plt->shdr->sh_size, -1); memcpy(prologdata, elfsh_readmem(plt), plt->shdr->sh_size); if (elfsh_insert_mapped_section(file, extplt, hdr, prologdata, mode, mod) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".ext.plt insertion failed", -1); extplt = elfsh_get_section_by_name(file, ELFSH_SECTION_NAME_EXTPLT, NULL, NULL, NULL); if (extplt == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".ext.plt insertion failed", -1); file->secthash[ELFSH_SECTION_EXTPLT] = extplt; extplt->curend = elfsh_get_first_pltentsz(file); } /* Loop on .plt and inject 'old_symnam' symbols */ for (off = 0; off < plt->shdr->sh_size; off += entsz) { /* SPARC does not have ALTGOT */ if (FILE_IS_MIPS(file) || FILE_IS_ALPHA64(file) || FILE_IS_IA32(file)) diff = (uint32_t) altgot->shdr->sh_addr - got->shdr->sh_addr; else diff = 0; /* Special case for the first plt entry */ if (off == 0 && elfsh_altplt_firstent(enew, &off, symtab, file, extplt, plt, diff) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "ALTPLT on first entry failed", -1); else if (off == 0) continue; /* Get the existing symbol name for this plt entry ... */ sym = elfsh_get_sym_by_value(elfsh_readmem(dynsym), dynsym->shdr->sh_size / sizeof(elfsh_Sym), plt->shdr->sh_addr + off, NULL, ELFSH_EXACTSYM); /* New versions of ld do not fill the vaddr of dynamic symbols, do it ourself. Do not insert old symbol in emergency cases */ if (sym == NULL) { if ((sym = elfsh_restore_dynsym(file, plt, off, dynsym)) == NULL) continue; name = elfsh_get_dynsymbol_name(file, sym); /* __gmon_start__ should not be resolved if it was not already done by gcc */ if (name && !strcmp(name, "__gmon_start__")) sym->st_value = 0x0; } /* ... and we inject the 'old' occurence symbol pointing in .alt.plt (.plt on MIPS) */ if (!FILE_IS_MIPS(file)) addr = enew->shdr->sh_addr + off; else addr = plt->shdr->sh_addr + off; #if __BYTE_ORDER == __BIG_ENDIAN if (file->hdr->e_ident[EI_DATA] == ELFDATA2LSB) #elif __BYTE_ORDER == __LITTLE_ENDIAN if (file->hdr->e_ident[EI_DATA] == ELFDATA2MSB) #else #error Unexpected __BYTE_ORDER ! #endif addr = swaplong(addr); /* Injection */ name = elfsh_get_dynsymbol_name(file, sym); newsym = elfsh_create_symbol(addr, entsz, STT_FUNC, 0, 0, 0); snprintf(buf, BUFSIZ, "old_%s", name); if (elfsh_insert_symbol(symtab, &newsym, buf) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "old_* symbol injection failed", -1); #if __DEBUG_COPYPLT__ printf("[DEBUG_COPYPLT] Symbol at .plt + %u injected" " succesfully (%s) \n", off, buf); #endif /* On ALPHA, shift the relocation offset from .got to .alt.got to avoid hooks removing when calling back the original function. */ if (FILE_IS_ALPHA64(file) && elfsh_shift_alpha_relocs(file, name, altgot, off) < 0) continue; /* Reencode the PLT entry to use the alternative GOT */ /* This condition is for compatibility with other archs where EXTPLT is not yet supported. For those we do not enter the hook */ if (FILE_IS_IA32(file)) { diff = (eresi_Addr) altgot->shdr->sh_addr - got->shdr->sh_addr; elfsh_encodeplt(file, plt, diff, off); if (file->hdr->e_type == ET_DYN) elfsh_encodeplt(file, file->secthash[ELFSH_SECTION_ALTPLT], diff, off); diff = (eresi_Addr) altgot->shdr->sh_addr - got->shdr->sh_addr + got->shdr->sh_size; elfsh_encodeplt(file, extplt, diff, off); } } /* Activate ALTGOT */ if (elfsh_redirect_pltgot(file, altgot, got, plt, enew) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "PLTGOT redirection failed", -1); /* Activate EXTPLT */ if (elfsh_extplt_mirror_sections(file) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Section mirroring failed", -1); #if __DEBUG_COPYPLT__ printf("[DEBUG_COPYPLT] Section Mirrored Successfully ! \n"); #endif /* Everything is 0k4y */ if (elfsh_sync_sorted_symtab(symtab) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "symtab synchronisation failed", -1); if (elfsh_sync_sorted_symtab(dynsym) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "dynsym synchronisation failed", -1); elfsh_sync_sectnames(file); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }