Exemplo n.º 1
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);
}
Exemplo n.º 2
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);
}