Esempio n. 1
0
/**
 * 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));
}
Esempio n. 2
0
/**
 * 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));
}
Esempio n. 3
0
/**
 * 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));
}
Esempio n. 4
0
/**
 * 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));
}
Esempio n. 5
0
/**
 * 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));
}
Esempio n. 6
0
/**
 * 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));
}
Esempio n. 7
0
/**
 * 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));
}
Esempio n. 8
0
/**
 * 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)));
}
Esempio n. 9
0
/**
 * 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)));
}
Esempio n. 10
0
/**
 * 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);
}
Esempio n. 11
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));
}
Esempio n. 12
0
/**
 * 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)));
}
Esempio n. 13
0
/**
 * 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);
}
Esempio n. 14
0
/**
 * 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);
}
Esempio n. 15
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);
}
Esempio n. 16
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);
}
Esempio n. 17
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); 
}
Esempio n. 18
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);
}
Esempio n. 19
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);
}
Esempio n. 20
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);
}
Esempio n. 21
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);
}
Esempio n. 22
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);
}
Esempio n. 23
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);
}
Esempio n. 24
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);
}
Esempio n. 25
0
/**
 * @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);
}