/** * @brief Main function performing ALTPLT, ALTGOT, and EXTPLT techniques. * @param file The host file. * @param modulo Always inject sections with a size being a multiple of mod. * @return Success (0) or Error (-1). */ int elfsh_copy_plt(elfshobj_t *file, u_int modulo) { PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Some sanity checks */ if (elfsh_static_file(file)) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); if (FILE_IS_MIPS(file) && elfsh_dynamic_file(file) && (elfsh_build_plt(file) < 0)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to build MIPS plt", -1); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, elfsh_relink_plt(file, modulo)); }
/** * Fixup the binary, inject symbols and sort SHT * @param file * @return */ void elfsh_fixup(elfshobj_t *file) { elfsh_Shdr *got; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (file->hdr->e_type == ET_REL || elfsh_static_file(file)) elfsh_sort_sht(file); /* .got sht entsize fixup */ got = elfsh_get_sht_entry_by_name(file, ELFSH_SECTION_NAME_GOT); if (got != NULL && got->sh_entsize == 0) got->sh_entsize = sizeof(eresi_Addr); PROFILER_OUT(__FILE__, __FUNCTION__, __LINE__); }
/** * Inject a ET_REL object into a ET_EXEC object * @param file * @param rel * @return */ int elfsh_inject_etrel(elfshobj_t *file, elfshobj_t *rel) { u_int mod; u_int pgsize; u_int index; elfshsect_t *sect; elfshsect_t *hooks; int ret = 0; static int depth = 0; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Sanity checks */ if (file == NULL || file->hdr == NULL || rel == NULL || rel->hdr == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL parameter", -1); if (rel->hdr->e_type != ET_REL || (file->hdr->e_type != ET_EXEC && file->hdr->e_type != ET_DYN)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Bad parameter types", -1); #if __DEBUG_RELADD__ if (rel->pending) { printf("[DEBUG_RELADD] BUG BUG BUG \n"); exit(0); } printf("[DEBUG_RELADD] INJECTING %s in %s (depth %d)\n", rel->name, file->name, depth++); #endif /* Set pending injection flag */ rel->pending = 1; /* If not already done */ elfsh_setup_hooks(); /* First physically insert all BSS in the file and fuse ** the module's BSS with the last one */ if (elfsh_fuse_bss(file, rel) < 0) { rel->pending = 0; PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cant fuze BSS sections", -1); } /* First pass : find and inject all allocatable sections */ for (index = 0; index < rel->hdr->e_shnum; index++) { /* Get the current section */ sect = elfsh_get_section_by_index(rel, index, NULL, NULL); if (sect == NULL) { rel->pending = 0; PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cant read section in ET_REL", -1); } /* Check if the current section need to be mapped */ if (elfsh_get_section_allocflag(sect->shdr) && sect->shdr->sh_size && sect->shdr->sh_type == SHT_PROGBITS) { mod = 0; if (elfsh_inject_etrel_section(file, sect, mod) < 0) { rel->pending = 0; PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to inject ET_REL section", -1); } } } /* compute the inject modulo */ mod = elfsh_get_pagesize(file); //mod = sizeof(eresi_Addr); /* Do a copy of the procedure linkage table for eventual redirection */ if (!elfsh_static_file(file) && elfsh_copy_plt(file, mod) < 0) { rel->pending = 0; PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to copy PLT", -1); } /* Create an additional hook table for non-plt function redirection */ hooks = elfsh_get_section_by_name(file, ELFSH_SECTION_NAME_HOOKS, 0, 0, 0); if (!hooks) { int mode; /* get injection mode */ ELFSH_SELECT_INJECTION(file,NULL,mode); pgsize = elfsh_get_pagesize(file); pgsize *= 4; /* We need a lot more than a page to trace big binaries like ssh */ hooks = elfsh_insert_section(file, ELFSH_SECTION_NAME_HOOKS, NULL, mode, pgsize - 1, pgsize); if (!hooks) { rel->pending = 0; PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot inject .hooks", -1); } hooks->curend = 0; } #if __DEBUG_RELADD__ printf("[DEBUG_RELADD] Entering intermediate symbol injection loop\n"); #endif /* Intermediate pass 2 : Inject ET_REL symbol table into host file */ if (elfsh_fuse_etrel_symtab(file, rel) < 0) { rel->pending = 0; PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to fuze symbol tables", -1); } #if __DEBUG_RELADD__ printf("[DEBUG_RELADD] Entering final relocation loop\n"); elfsh_print_sectlist(file, "before relocation"); #endif /* Now call the relocation on the object's sections */ ret = elfsh_relocate_object(file, rel, ELFSH_RELOC_STAGE1); rel->pending = 0; depth--; PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (ret)); }
/** * Find the host symbol we rely on for performing the relocation * @param enew * @param reltab * @param sym * @param name * @param stage * @param symtype * @return */ static int elfsh_find_relocsym(elfshsect_t *enew, elfshsect_t *reltab, elfsh_Sym **sym, char *name, char stage, elfsh_Half symtype) { elfshobj_t *dep; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* If this symbol is a old_ one, accept it to be relocated in 2nd stage */ /* This is because function redirection may be done after ET_REL injection */ if (strstr(name, "old_") && stage == ELFSH_RELOC_STAGE1) { #if __DEBUG_RELADD__ printf("[DEBUG_RELADD] %s symbol not found at RELOC_STAGE1, continue\n", name); #endif if (enew->parent->nbrel < ELFSH_MAXREL) { if (enew->parent->listrel[enew->parent->nbrel] != reltab->parent) { enew->parent->listrel[enew->parent->nbrel++] = reltab->parent; #if __DEBUG_RELADD__ printf("[DEBUG_RELADD] %s object relocation will have a second stage\n", reltab->parent->name); #endif } PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (0)); } } /* We have a different behavior depending on the symbol type */ switch (symtype) { /* The symbol is not found so we request a enew PLT entry for it */ case STT_NOTYPE: if (!elfsh_static_file(enew->parent)) { *sym = elfsh_request_pltent(enew->parent, name); if (*sym) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (1)); } else { #if __DEBUG_STATIC__ printf("STT_NOTYPE in static file while relocating %s\n", reltab->parent->name); #endif dep = elfsh_find_obj_by_symbol(name); /* no symbol found */ if (dep == ((void *) -1)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to inject ET_REL dependence", -1); /* Use stage 2 relocation as the best et_rel is beeing inserted */ if (dep == NULL) { #if __DEBUG_STATIC__ printf("[DEBUG_STATIC] Loop in dependency detected -> STAGE2 relocation\n"); #endif if (enew->parent->nbrel < ELFSH_MAXREL && enew->parent->listrel[enew->parent->nbrel] != reltab->parent) { enew->parent->listrel[enew->parent->nbrel++] = reltab->parent; #if __DEBUG_STATIC__ printf("[DEBUG_STATIC] %s object relocation will have a second stage\n", reltab->parent->name); #endif PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (0)); } PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to add stage 2 relocation", -1); } /* symbol found, gonna try to inject et_rel */ if (dep != NULL && dep != reltab->parent && elfsh_inject_etrel(enew->parent, dep) < 0) { PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to inject ET_REL dependence", -1); } PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (2)); } break; case STT_SECTION: printf("STT_SECTION\n"); break; case STT_FUNC: printf("STT_FUNC\n"); break; case STT_OBJECT: printf("STT_OBJECT\n"); break; case STT_COMMON: printf("STT_COMMON\n"); break; case STT_BLOCK: printf("STT_BLOCK\n"); } #if __DEBUG_STATIC__ printf("[DEBUG_STATIC] Not found after OLD check : sym = %s \n", name); #endif PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cant find requested symbol in ET_EXEC\n", -1); }