/** * Retreive the virtual address given the file offset * @param file * @param foffset * @return */ int elfsh_get_vaddr_from_foffset(elfshobj_t *file, u_int foffset) { elfshsect_t *root; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); root = elfsh_get_parent_section_by_foffset(file, foffset, NULL); if (root) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (root->shdr->sh_addr + (foffset - root->shdr->sh_offset))); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * Perform a raw write on the object cache data * @param file * @param foffset * @param src_buff * @param len * @return */ int elfsh_raw_write(elfshobj_t *file, u_int foffset, void *src_buff, int len) { elfshsect_t *sect; int sect_off; void *dst; int prot; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); sect = elfsh_get_parent_section_by_foffset(file, foffset, NULL); if (sect == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid virtual address", -1); sect_off = foffset - sect->shdr->sh_offset; if (sect_off + len > sect->shdr->sh_size) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Section too short", -1); dst = elfsh_get_anonymous_section(file, sect); if (dst == NULL) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); if (elfsh_is_runtime_mode()) { prot = elfsh_munprotect(file, (eresi_Addr) dst + sect_off, len); memcpy(dst + sect_off, src_buff, len); elfsh_mprotect(file, (eresi_Addr) dst + sect_off, len, prot); } else memcpy(dst + sect_off, src_buff, len); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (len)); }
/** * Perform a raw read on the object cache data * @param file * @param foffset * @param dest_buff * @param len * @return */ int elfsh_raw_read(elfshobj_t *file, u_int foffset, void *dest_buff, int len) { volatile elfshsect_t *sect; volatile void *src; volatile int sect_off; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); sect = elfsh_get_parent_section_by_foffset(file, foffset, NULL); if (sect == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid virtual address", -1); sect_off = foffset - sect->shdr->sh_offset; if (sect_off + len > sect->shdr->sh_size) len -= (sect_off + len - sect->shdr->sh_size); src = elfsh_get_anonymous_section(file, sect); if (src == NULL) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); memcpy(dest_buff, src + sect_off, len); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (len)); }
/** * 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); }