/** * 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)); }
void fix_dynamic_table(elf_bf_exec_t *env) { elfsh_Dyn *dyn; elfshobj_t *f = env->ee_lm.lm_f; dyn = elfsh_get_dynamic_entry_by_type(f, DT_RELA); env->ee_rela_orig = elfsh_get_dynentry_val(dyn); elfsh_set_dynentry_val(dyn, elfsh_get_section_addr(env->ee_lm.lm_reloc->shdr)); dyn = elfsh_get_dynamic_entry_by_type(f, DT_RELASZ); env->ee_relasz_orig = elfsh_get_dynentry_val(dyn); elfsh_set_dynentry_val(dyn, elfsh_get_section_size(env->ee_lm.lm_reloc->shdr)); env->ee_dt_relasz_value = elfsh_get_section_size(env->ee_lm.lm_reloc->shdr); env->ee_reloc_end_value = elfsh_get_section_addr(env->ee_lm.lm_reloc->shdr) + env->ee_dt_relasz_value; dyn = elfsh_get_dynamic_entry_by_type(f, DT_GNU_HASH); env->ee_dt_gnu_hash = elfsh_get_dynentry_val(dyn); dyn = elfsh_get_dynamic_entry_by_type(f, DT_SYMTAB); env->ee_sym_orig = elfsh_get_dynentry_val(dyn); elfsh_set_dynentry_val(dyn, elfsh_get_section_addr(env->ee_lm.lm_sym->shdr)); dyn = elfsh_get_dynamic_entry_by_type(f, DT_JMPREL); env->ee_dt_jmprel_value = elfsh_get_dynentry_val(dyn); elfsh_set_dynentry_val(dyn, 0); dyn = elfsh_get_dynamic_entry_by_type(f, DT_PLTRELSZ); env->ee_dt_pltrelsz_value = elfsh_get_dynentry_val(dyn); elfsh_set_dynentry_val(dyn, 0); //dyn = elfsh_get_dynamic_entry_by_type(f, DT_SYMENT); //env->ee_sym_orig = elfsh_get_dynentry_val(dyn); }
/** * Shift the .dynamic section in ET_DYN files * * @param file * @param size * @return */ int elfsh_shift_dynamic(elfshobj_t *file, u_int size) { elfsh_Dyn *dyn; u_int nbr; u_int idx; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); dyn = elfsh_get_dynamic(file, &nbr); if (dyn == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot find .dynamic in ET_DYN", -1); for (idx = 0; idx < nbr; idx++) if (elfsh_shiftable_dynent(dyn + idx)) elfsh_set_dynentry_val(dyn + idx, elfsh_get_dynentry_val(dyn + idx) + size); 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); }
//just cont number of symbols if lm_allocated is false void init_tape_syms(elf_bf_exec_t *env) { elf_bf_Sym *sym, *psym, *ifunc, *execmap, *ptrtapecpy, *stackaddr, *getchar, *putchar, *ldbase, *libcbase, *execmapvalue, *putcharextra; elf_bf_Sym top; if (env->ee_lm.lm_allocated){ psym = calloc(1, sizeof(elf_bf_Sym)); sym = calloc(1, sizeof(elf_bf_Sym)); ptrtapecpy = calloc(1, sizeof(elf_bf_Sym)); ifunc = calloc(1, sizeof(elf_bf_Sym)); execmap = calloc(1, sizeof(elf_bf_Sym)); stackaddr = calloc(1, sizeof(elf_bf_Sym)); ldbase = calloc(1, sizeof(elf_bf_Sym)); libcbase = calloc(1, sizeof(elf_bf_Sym)); getchar = calloc(1, sizeof(elf_bf_Sym)); putchar = calloc(1, sizeof(elf_bf_Sym)); putcharextra = calloc(1, sizeof(elf_bf_Sym)); execmapvalue = calloc(1, sizeof(elf_bf_Sym)); } eresi_Addr index = env->ee_num_used_syms; //index++; //printf("index: %d\n", index); //symtab_get_sym(&(env->ee_lm), index++, nsym); symtab_get_sym(&(env->ee_lm), index++, psym); symtab_get_sym(&(env->ee_lm), index++, sym); symtab_get_sym(&(env->ee_lm), index++, ifunc); symtab_get_sym(&(env->ee_lm), index++, ptrtapecpy); symtab_get_sym(&(env->ee_lm), index++, execmap); symtab_get_sym(&(env->ee_lm), index++, stackaddr); symtab_get_sym(&(env->ee_lm), index++, ldbase); symtab_get_sym(&(env->ee_lm), index++, libcbase); symtab_get_sym(&(env->ee_lm), index++, getchar); symtab_get_sym(&(env->ee_lm), index++, putchar); symtab_get_sym(&(env->ee_lm), index++, putcharextra); symtab_get_sym(&(env->ee_lm), index, execmapvalue); if (env->ee_lm.lm_allocated){ env->ee_num_used_syms = index; symtab_get_sym(&(env->ee_lm), index+1, &top); //keeps the tape head symbol number //address of where tape head is pointing's value symtab_set_sym(psym, 1, top.addr, STT_FUNC); //assume tape head value is zero symtab_set_sym(sym, 1, 0, STT_FUNC); symtab_set_sym(ifunc, 8, 0, STT_GNU_IFUNC); //elfsh_set_symbol_link(ifunc->sym, 1); symtab_set_sym(ptrtapecpy, 1, symtab_get_value_addr(sym), STT_FUNC); //start it up with address of PLTGOT elfsh_Dyn *dyn; eresi_Addr pltgot; dyn = elfsh_get_dynamic_entry_by_type(env->ee_lm.lm_f, DT_PLTGOT); pltgot = elfsh_get_dynentry_val(dyn); env->ee_dt_pltgot = pltgot+8; symtab_set_sym(execmap, 8, pltgot+8, STT_FUNC); symtab_set_sym(stackaddr, 8, 0, STT_FUNC); symtab_set_sym(ldbase, 8, 0, STT_FUNC); symtab_set_sym(libcbase, 8, 0, STT_FUNC); symtab_set_sym(getchar, 8, 0, STT_FUNC); symtab_set_sym(putchar, 8, 0, STT_FUNC); symtab_set_sym(putcharextra, 0, 0, STT_FUNC); //we jsut want a readable address here //printf("ptr_tape_ptr %x, tape_ptr %x, copy %x\n", symtab_get_index(psym), symtab_get_index(sym), symtab_get_index(ptrtapecpy)); symtab_set_sym(execmapvalue, 8, 0, STT_FUNC); //env->ee_tape_symnum = psym->index; env->ee_ptr_tape_ptr = psym; env->ee_tape_ptr = sym; env->ee_lm.lm_ifunc = ifunc; env->ee_ptr_tape_copy = ptrtapecpy; env->ee_exec_map = execmap; env->ee_stack_addr = stackaddr; env->ee_ld_base = ldbase; env->ee_libc_base = libcbase; env->ee_lm.lm_getchar = getchar; env->ee_lm.lm_putchar = putchar; env->ee_lm.lm_putcharextra = putcharextra; env->ee_exec_map_value = execmapvalue; } env->ee_num_new_syms = index - env->ee_num_used_syms; }