Example #1
0
int main(int argc, char **argv)
{
   Elf32_Ehdr	*e_hdr_in, *e_hdr_out, *e_hdr_inj;
   Elf32_Phdr	*p_hdr_in, *p_hdr_out, *code_hdr, *data_hdr, *dyn_hdr;
   Elf32_Shdr   *s_hdr_out, *s_hdr_str_out;
   int		fd_in;
   int		fd_out;
   off_t	fd_in_sz, fd_out_sz;
   uint32_t     pltgot, *fix, msk, user_offset, base_block, hook_sz, inj_sz, over_sz;
   char         *s_str_out;
   int          i;

   if (argc != 3)
   {
      printf("usage: %s <ld-linux.so> <pie.elf>\n", argv[0]);
      return -1;
   }

   /* check input file */
   if ((fd_in = open(argv[1], O_RDONLY)) == -1)
   {
      printf("can't open file %s\n", argv[1]);
      return -1;
   }

   fd_in_sz = lseek(fd_in, 0, SEEK_END);
   lseek(fd_in, 0, SEEK_SET);
   e_hdr_in = (Elf32_Ehdr*)mmap(NULL, fd_in_sz, PROT_READ, MAP_PRIVATE, fd_in, 0);
   p_hdr_in = (Elf32_Phdr*)((uint32_t)e_hdr_in + e_hdr_in->e_phoff);

   /* load file to inject */
   if (load_code_from_file(argv[2], &e_hdr_inj, &inj_sz) == -1)
      return -1;

   hook_sz = (uint32_t)payload - (uint32_t)shatner;
   over_sz = hook_sz + inj_sz;

   /* build out file */
   if ((fd_out = open(LDOUTFILE, O_RDWR|O_CREAT|O_TRUNC, 0755)) == -1)
   {
      printf("can't open file "LDOUTFILE"\n");
      return -1;
   }

   fd_out_sz = fd_in_sz + over_sz;

   lseek(fd_out, fd_out_sz - 1, SEEK_SET);
   write(fd_out, "\x00", 1);
   lseek(fd_out, 0, SEEK_SET);
   e_hdr_out = (Elf32_Ehdr*)mmap(NULL, fd_out_sz, PROT_READ|PROT_WRITE, MAP_SHARED, fd_out, 0);

   /* copy elf hdr */
   uint32_t offset = (uint32_t)e_hdr_out;
   memcpy((void*)offset, (void*)e_hdr_in, e_hdr_in->e_ehsize);

   /* install hook */
   offset += e_hdr_in->e_ehsize;
   memcpy((void*)offset, (void*)shatner, hook_sz);

   base_block = offset;

   /* save fixed ld entry point */
   fix = (uint32_t*)((uint32_t)base_block + 2);
   *fix = e_hdr_out->e_entry + over_sz;

   /* inject external code */
   inject_code_from_file(base_block, offset+hook_sz, e_hdr_inj);

   /* copy remaining */
   offset += over_sz;
   memcpy((void*)offset, (void*)e_hdr_in+e_hdr_in->e_ehsize, fd_in_sz - e_hdr_in->e_ehsize);

   /*
   ** Fix Elf header
   */
   e_hdr_out->e_entry  = e_hdr_out->e_ehsize;
   e_hdr_out->e_phoff += over_sz;
   e_hdr_out->e_shoff += over_sz;

   /*
   ** Fix Program headers
   */
   printf("p_hdr #%d\n", e_hdr_out->e_phnum);
   p_hdr_out = (Elf32_Phdr*)((uint32_t)e_hdr_out + e_hdr_out->e_phoff);
   code_hdr = (Elf32_Phdr*)0;
   data_hdr = (Elf32_Phdr*)0;

   for (i=0 ; i<e_hdr_out->e_phnum ; i++, p_hdr_out++)
   {
      if (!p_hdr_out->p_memsz)
	 continue;

      if (p_hdr_out->p_type == PT_LOAD && (p_hdr_out->p_flags & (PF_R|PF_X)) && i == 0)
      {
	 code_hdr = p_hdr_out;
	 code_hdr->p_filesz += over_sz;
	 code_hdr->p_memsz  += over_sz;
	 continue;
      }

      if (p_hdr_out->p_type == PT_LOAD && (p_hdr_out->p_flags & (PF_R|PF_W)) && i == 1)
      {
	 data_hdr = p_hdr_out;
	 msk = data_hdr->p_align - 1;
      }

      if (p_hdr_out->p_type == PT_DYNAMIC)
	 dyn_hdr = p_hdr_out;

      printf("fixing phdr %d\n", i);
      p_hdr_out->p_offset += over_sz;
      p_hdr_out->p_vaddr  += over_sz;
      p_hdr_out->p_paddr  += over_sz;
   }

   if (!code_hdr || !data_hdr || !dyn_hdr)
   {
      printf("bad program headers\n");
      return -1;
   }

   /*
   ** Fix Section headers
   */
   s_hdr_out = (Elf32_Shdr*)((uint32_t)e_hdr_out + e_hdr_out->e_shoff);
   s_hdr_str_out = &s_hdr_out[e_hdr_out->e_shstrndx];
   s_str_out = (uint8_t*)e_hdr_out + s_hdr_str_out->sh_offset + over_sz;
   printf("s_hdr #%d | s_hdr_str 0x%x\n", e_hdr_out->e_shnum, s_str_out);

   for (i=0 ; i<e_hdr_out->e_shnum ; i++, s_hdr_out++)
   {
      if (s_hdr_out->sh_size == 0)
	 continue;

      s_hdr_out->sh_offset += over_sz;

      if (s_hdr_out->sh_flags & SHF_ALLOC)
	 s_hdr_out->sh_addr += over_sz;

      printf("\\_fix shdr %s addr 0x%x off 0x%x\n",
	     &s_str_out[s_hdr_out->sh_name], s_hdr_out->sh_addr, s_hdr_out->sh_offset);

      /* fix .dynamic */
      if (s_hdr_out->sh_type == SHT_DYNAMIC)
      {
	 Elf32_Dyn *dyn_s = (Elf32_Dyn*)((uint32_t)e_hdr_out + s_hdr_out->sh_offset);
	 Elf32_Dyn *dyn   = dyn_s;

	 while (dyn->d_tag != DT_NULL)
	 {
	    switch (dyn->d_tag)
	    {
	    case DT_PLTGOT:
	    case DT_JMPREL:
	    case DT_GNU_HASH:
	    case DT_HASH:
	    case DT_STRTAB:
	    case DT_SYMTAB:
	    case DT_REL:
	    case DT_RELA:
	    case DT_VERDEF:
	    case DT_VERSYM:
	       dyn->d_un.d_ptr += over_sz;
	       printf(" \\_fix 0x%x\n", dyn->d_un.d_ptr);
	       break;
	    case DT_SONAME:
	       printf(" \\_soname 0x%x\n", dyn->d_un.d_val);
	       break;
	    case DT_INIT_ARRAY:
	    case DT_FINI_ARRAY:
	       printf("!!!! WARNING need to patch ARRAY !!!!\n");
	       break;
	    }

	    if (dyn->d_tag == DT_PLTGOT)
	    {
	       pltgot = dyn->d_un.d_ptr;
	       printf(" \\_found .got.plt @ 0x%x\n", pltgot);
	    }

	    dyn++;
	 }

	 /* compute user offset to save old user entry into .dynamic[NULL].d_un.d_ptr */
	 user_offset = ((code_hdr->p_memsz + msk) & (~msk)) + (dyn_hdr->p_vaddr & msk) + ((uint32_t)dyn - (uint32_t)dyn_s) + 4;
	 printf("computed user_offset 0x%x\n", user_offset);

	 fix  = (uint32_t*)((uint32_t)base_block + 6);
	 *fix = user_offset;
      }

      /* fix .dynsym */
      if (s_hdr_out->sh_type == SHT_DYNSYM)
      {
      	 Elf32_Sym *sym = (Elf32_Sym*)((uint32_t)e_hdr_out + s_hdr_out->sh_offset);
      	 uint32_t nr = s_hdr_out->sh_size/s_hdr_out->sh_entsize;
      	 int z;
      	 for (z=0 ; z<nr ; z++)
      	 {
	    if (sym->st_size)
	    {
	       sym->st_value += over_sz;
	       printf(" \\_fix 0x%x\n", sym->st_value);
	    }
      	    sym++;
      	 }
      }

      /* fix .got.plt */
      if (s_hdr_out->sh_addr == pltgot)
      {
      	 uint32_t *got = (uint32_t*)((uint32_t)e_hdr_out + s_hdr_out->sh_offset);
      	 uint32_t nr = s_hdr_out->sh_size/s_hdr_out->sh_entsize;
      	 int z;
      	 for (z=0 ; z<nr ; z++)
      	 {
	    *got += over_sz;
	    printf(" \\_fix 0x%x\n", *got);
      	    got++;
      	 }
      }
   }

   /*
   ** now that s_hdr are fixed, process reloc entries
   */
   s_hdr_out = (Elf32_Shdr*)((uint32_t)e_hdr_out + e_hdr_out->e_shoff);
   for (i=0 ; i<e_hdr_out->e_shnum ; i++, s_hdr_out++)
   {
      if (s_hdr_out->sh_type != SHT_REL)
	 continue;

      printf("\\_reloc %s fix\n", &s_str_out[s_hdr_out->sh_name]);

      Elf32_Rel *rel = (Elf32_Rel*)((uint32_t)e_hdr_out + s_hdr_out->sh_offset);
      uint32_t	 nr  = s_hdr_out->sh_size/s_hdr_out->sh_entsize;
      int	 z;
      for (z=0 ; z<nr ; z++)
      {
	 rel->r_offset += over_sz;
	 printf(" \\_fix 0x%x\n", rel->r_offset);

	 if (ELF32_R_TYPE(rel->r_info) == R_386_RELATIVE)
	 {
	    uint32_t rfix = (uint32_t)e_hdr_out + rel->r_offset;
	    uint32_t diff = reloc_lookup_section(e_hdr_out, rel->r_offset);

	    if (diff)
	       rfix -= diff;

	    *(uint32_t*)rfix += over_sz;
	 }

	 rel++;
      }
   }

   munmap((void*)e_hdr_in, fd_in_sz);
   close(fd_in);
   munmap((void*)e_hdr_out, fd_out_sz);
   close(fd_out);
   return 0;
}
Example #2
0
list_t* do_prim_op(char *name, list_t *args)
{
	int i = 0;
	int j;
	int val = 0;
	list_t *l1;
	list_t* nl = c_malloc(sizeof(list_t));
	char *buf;

	if (!strcmp(name, "+")) {
		val = 0;
		for (i = 0; i < args->cc; ++i) {
			if (args->c[i]->type != NUMBER) {
				error_msg("+ expects numbers");
				code_error();
			}
			val += args->c[i]->val;
		}
		nl->type = NUMBER;
		nl->val = val;
		return nl;
	}

	if (!strcmp(name, "-")) {
		if (args->cc == 1) {
			/* single argument: unary minus sign */
			if (args->c[0]->type != NUMBER) {
				error_msg("- expects numbers");
				code_error();
			}
			val = -args->c[0]->val;
		} else {
			/* otherwise, standard N-ary subtraction */
			for (i = 0; i < args->cc; ++i) {
				if (args->c[i]->type != NUMBER) {
					error_msg("- expects numbers");
					code_error();
				}
				if (i == 0)
					val = args->c[i]->val;
				else
					val -= args->c[i]->val;
			}
		}
		nl->val = val;
		nl->type = NUMBER;
		return nl;
	}

	if (!strcmp(name, "*")) {
		val = 1;
		for (i = 0; i < args->cc; ++i) {
			if (args->c[i]->type != NUMBER) {
				error_msg("* expects numbers");
				code_error();
			}
			val *= args->c[i]->val;
		}
		nl->type = NUMBER;
		nl->val = val;
		return nl;
	}

	if (!strcmp(name, "remainder")) {
		if (args->cc != 2
		|| args->c[0]->type != NUMBER
		|| args->c[1]->type != NUMBER) {
			error_msg("`remainder' expects two numbers");
			code_error();
		}
		nl->type = NUMBER;
		nl->val = args->c[0]->val % args->c[1]->val;
		return nl;
	}

	if (!strcmp(name, "=")) {
		if (args->cc != 2
		|| args->c[0]->type != NUMBER
		|| args->c[1]->type != NUMBER) {
			error_msg("= expects two numbers");
			code_error();
		}
		return makebool(args->c[0]->val == args->c[1]->val);
	}

	if (!strcmp(name, ">")) {
		if (args->cc != 2
		|| args->c[0]->type != NUMBER
		|| args->c[1]->type != NUMBER) {
			error_msg("> expects two numbers");
			code_error();
		}
		return makebool(args->c[0]->val > args->c[1]->val);
	}

	if (!strcmp(name, "<")) {
		if (args->cc != 2
		|| args->c[0]->type != NUMBER
		|| args->c[1]->type != NUMBER) {
			error_msg("< expects two numbers");
			code_error();
		}
		return makebool(args->c[0]->val < args->c[1]->val);
	}

	if (!strcmp(name, "<=")) {
		if (args->cc != 2
		|| args->c[0]->type != NUMBER
		|| args->c[1]->type != NUMBER) {
			error_msg("<= expects two numbers");
			code_error();
		}
		return makebool(args->c[0]->val <= args->c[1]->val);
	}

	if (!strcmp(name, ">=")) {
		if (args->cc != 2
		|| args->c[0]->type != NUMBER
		|| args->c[1]->type != NUMBER) {
			error_msg(">= expects two numbers");
			code_error();
		}
		return makebool(args->c[0]->val >= args->c[1]->val);
	}

	if (!strcmp(name, "not")) {
		val = 0;
		if (args->cc != 1) {
				error_msg("`not' expects one argument");
				code_error();
		}
		/* r6rs.pdf section 11.8, page 47 */
		val = args->c[0]->type == BOOL && !args->c[i]->val;
		return makebool(val);
	}


	if (!strcmp(name, "cons")) {
		if (args->cc != 2) {
			error_msg("`cons' expects 2 arguments");
			code_error();
		}
		/* just return the list as-is for now */
		memcpy(nl, args, sizeof(list_t));
		nl->type = CONS;
		return nl;
	}

	if (!strcmp(name, "car")) {
		if (args->cc != 1) {
			error_msg("`car' expects 1 argument");
			code_error();
		}
		if (args->c[0]->type != CONS) {
			error_msg("`car' expects a linked-list");
			code_error();
		}
		if (args->c[0]->cc < 1) {
			error_msg("`car' has failed");
			code_error();
		}
		return args->c[0]->c[0];
	}

	if (!strcmp(name, "cdr")) {
		if (args->cc != 1) {
			error_msg("`cdr' expects 1 argument");
			code_error();
		}
		if (args->c[0]->type != CONS) {
			error_msg("`cdr' expects a linked-list");
			code_error();
		}
		if (args->c[0]->cc < 2) {
			error_msg("`cdr' has failed");
			code_error();
		}
		return args->c[0]->c[1];
	}

	if (!strcmp(name, "null?")) {
		return makebool(args->cc == 1 
			&& (
				((args->c[0]->type == SYMBOL && !strcmp(args->c[0]->head, "NIL"))
				|| (args->c[0]->type == CONS && args->c[0]->cc == 0))));
	}

	if (!strcmp(name, "display")) {
		buf = malloc(LINEBUFSIZ);
		if (!buf) {
			error_msg("malloc failed");
			code_error();
		}
		*buf = 0;
		printout(args->c[0], buf);
#ifdef JS_GUI
		c_writeback(buf);
#else
		printf("%s", buf);
#endif
		free(buf);
		return args->c[0];
	}

	if (!strcmp(name, "pair?")) {
		/* check for null first */
		j = args->cc == 1 
		&& (
			((args->c[0]->type == SYMBOL && !strcmp(args->c[0]->head, "NIL"))
			|| (args->c[0]->type == CONS && args->c[0]->cc == 0)));
		return makebool(!j  /* not null, then the rest */
			&& args->cc == 1 && args->c[0]->type == CONS);
	}

	/* the following bit deals with (eq? A B) --
	 * apparently, eq? checks if two things evaluate
	 * to the same memory pointer. but further hackery
	 * is sufficient to deal with the case (eq? 'foo 'foo) */
	if (!strcmp(name, "eq?")) {
		if (args->cc != 2) {
			error_msg("`eq?' expects two arguments");
			code_error();
		}
		return makebool(args->c[0] == args->c[1]
			|| (args->c[0]->type == SYMBOL 
				&& args->c[1]->type == SYMBOL
				&& !strcmp(args->c[0]->head, args->c[1]->head))
			/* (eq? 'NIL '()) => #t */
			|| (args->c[0]->type == SYMBOL && !strcmp(args->c[0]->head, "NIL")
			    && args->c[1]->type == CONS && args->c[1]->cc == 0)
			/* (eq? '() 'NIL) => #t */
			|| (args->c[1]->type == SYMBOL && !strcmp(args->c[1]->head, "NIL")
			    && args->c[0]->type == CONS && args->c[0]->cc == 0)
			/* (eq? '() '()) => #t */
			|| (args->c[0]->type == CONS && args->c[0]->cc == 0
			    && args->c[1]->type == CONS && args->c[1]->cc == 0));
	}

	if (!strcmp(name, "symbol?")) {
		return makebool(args->cc == 1 
			&& args->c[0]->type == SYMBOL);
	}

	if (!strcmp(name, "number?")) {
		return makebool(args->cc == 1 
			&& args->c[0]->type == NUMBER);
	}

	if (!strcmp(name, "newline")) {
#ifdef JS_GUI
		c_writeback_nl("");
#else
		puts("");
#endif
		return mksym("NIL");
	}

	if (!strcmp(name, "save-to")) {
		if (save_mode) {
			return mksym("NIL");
		}
		save_file = fopen(args->c[0]->head, "w");
		if (!save_file) {
			error_msg("failed to open file for writing");
			code_error();
		}
		save_mode = 1;
		return mksym("savefile-ok");
	}

	if (!strcmp(name, "load")) {
		buf = malloc(strlen(args->c[0]->head) + 1);
		if (!buf) {
			error_msg("malloc failed");
			code_error();
		}
		strcpy(buf, args->c[0]->head);
		load_code_from_file(buf);
		free(buf);
		return mksym("HERP-DERP");
	}

	if (!strcmp(name, "cons2list")) {
		return cons2list(args->c[0]);
	}

	if (!strcmp(name, "debuglog")) {
		stacktracer_barf();
		return mksym("herp-derp");
	}

	if (!strcmp(name, "reverse")) {
		/* r6rs.pdf, page 48 */
		if (args->c[0]->type == CONS)
			l1 = cons2list(args->c[0]);
		else if (args->c[0]->type == LIST)
			l1 = args->c[0];
		else return mksym("NIL");

		if (l1->cc == 0)
			return mksym("NIL");

		nl = new_list();
		nl->type = LIST;
		for (i = l1->cc - 1; i >= 0; --i)
			add_child(nl, l1->c[i]);
		return makelist(nl);
	}

	return NULL;
}