/*
 * Dumps shellcode from main()
 *
 * inane <admin@inane.demon.co.uk>
 * 
 * Just do this:
 *
 * int main()
 * {
 *   __asm__("
 *     <shellcode>
 *   ");
 * }
 *
 * Then run this program on the compiled binary.
 */

#include <stdio.h>
#include <stdlib.h>
#include <elf.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#if defined (__linux__)
#define EHDR      struct elf32_hdr
#define SHDR      Elf32_Shdr
#define PHDR      Elf32_Phdr
#define SYM       Elf32_Sym
#else
#error "Could not determine system type"
#endif

#define EHDR_SIZE sizeof(EHDR)
#define SHDR_SIZE sizeof(SHDR)
#define PHDR_SIZE sizeof(PHDR)
#define SYM_SIZE  sizeof(SYM)

void
phex (unsigned char * ptr, int len)
{
  int i = 0;

  /* Jump over procedure prologue */

  ptr += 3;  

  fprintf(stdout, "char shellcode[] = \"");
  while (len--) 
  {
    /* Gotta check to see if this is the procedure epilogue */

    if (*ptr == 0x89 && ptr[1] == 0xec && ptr[2] == 0x5d) break;

    fprintf(stdout, "\\x%.2x", (unsigned char)*ptr);

    if (i++ == 6) 
    {
      fprintf(stdout, "\"\n                   \"");
      i = 0; 
    }

    ++ptr;
  }

  fprintf(stdout, "\";\n");
  fflush(stdout);
}

SYM * 
locate_symbol (SHDR * secp, SYM * first, char * strt, char * name)
{
  char * ptr,
       * val;
  SYM * symp;
  int count = 0;
 
  ptr = (char *)first;
  for (symp = first; count < secp->sh_size; count += SYM_SIZE) 
  {
    if (symp->st_name)
    {
      val = strt + symp->st_name;

      if (!strcmp(val, name))
      {
        return symp;
      }

    }

    ptr += SYM_SIZE; 
    symp = (SYM *)ptr;
  }
}

SHDR * 
locate_section (EHDR * elf_p, SHDR * first, char * strt,
                char * memory, char * name)
{
  char * ptr,
       * val;
  SHDR * secp;
  int i = 0;

  ptr = (char *)first;
  for (secp = first; i < elf_p->e_shnum; ++i) 
  {
    val = strt + secp->sh_name;

    if (!strcmp(val, name))
    {
      return secp;
    }

    ptr += elf_p->e_shentsize;
    secp = (SHDR *)ptr;
  }

}

int main (int argc, char * * argv) 
{
  int fd;
  char * memory;  /* Entire file */
  struct stat st; 
  EHDR * elf;     /* Elf header */
  SHDR * sh,
       * first_sh;
  char * ptr,
       * strt,
       * sym_strt;
  SYM  * sptr;
  int i;

  if (argc < 2) 
  {
    fprintf(stderr, "Usage: %s <elf_file>\n", *argv);
    return EXIT_SUCCESS;
  }

  else if (stat(argv[1], &st)) 
  {
    fprintf(stderr, "Could not stat file: %s\n", strerror(errno));
    return EXIT_FAILURE;
  }

  else if (!(memory = (char *)malloc(st.st_size))) 
  {
    fprintf(stderr, "Could not allocate memory\n");
    return EXIT_FAILURE;
  }

  if (!(fd = open(argv[1], O_RDONLY))) 
  {
    fprintf(stderr, "Could not open file: %s\n", strerror(errno));
    return EXIT_FAILURE;
  }   

  if (read(fd, memory, st.st_size) != st.st_size) 
  {
    fprintf(stderr, "Could not read full file\n");
    return EXIT_FAILURE;
  }

  close(fd);
  elf = (EHDR *)memory;
 
  if (*elf->e_ident != 0x7f ||
       elf->e_ident[1] != 'E' ||
       elf->e_ident[2] != 'L' ||
       elf->e_ident[3] != 'F') {
    fprintf(stderr, "This isn't an ELF file\n");
    return EXIT_FAILURE;
  }

  /* Locate the string table */

  ptr = memory + elf->e_shoff; 
  first_sh = (SHDR *)ptr;
  ptr += elf->e_shstrndx * elf->e_shentsize; 
  sh = (SHDR *)ptr;
  strt = memory + sh->sh_offset;

  /* Locate string symbol table */

  if (!(sh = locate_section(elf, first_sh, strt, memory, ".strtab")))
  {
    fprintf(stderr, "Could not locate symbol string table\n");
    return EXIT_FAILURE;
  }
  sym_strt = (char *)memory + sh->sh_offset;
  
  /* Next locate the symbol table */

  if (!(sh = locate_section(elf, first_sh, strt, memory, ".symtab")))
  {
    fprintf(stderr, "Could not locate symbol table\n");
    return EXIT_FAILURE;
  }

  /* Get address of first symbol table entry */

  ptr = (char *)memory + sh->sh_offset;

  if (!(sptr = locate_symbol(sh, (SYM *)ptr, sym_strt, "_start")))
  { 
    fprintf(stderr, "Could not find main symbol\n");
    return EXIT_FAILURE;
  }

  i = sptr->st_value;

  /* Search through symbol table for "main" */

  if (!(sptr = locate_symbol(sh, (SYM *)ptr, sym_strt, "main")))
  {
    fprintf(stderr, "Could not find main symbol\n");
    return EXIT_FAILURE; 
  }

  /* Locate ".text" section */

  if (!(sh = locate_section(elf, first_sh, strt, memory, ".text")))
  {
    fprintf(stderr, "Could not locate text section\n");
    return EXIT_FAILURE;
  }

  /* Use offset from first address, to main address to 
     get offset of main code */
   
  ptr = (char *)memory + sh->sh_offset + (sptr->st_value - i);

  phex(ptr, sptr->st_size);

  return EXIT_SUCCESS;
}