/*
 * m_rev
 * Linux 2.6 x86/x86-64 ptrace()-based argv[] cloaking utility by
 * ernie@ernie
 * 
 * Any feedback to ernie.at.ernie@gmail.com
 *
 * Brief description how this thing works in steps:
 * 1. Process forks a child.
 * 2. Child begins to ptrace the parent process.
 * 3. Parent performs a "syscall slide" and then executes given target binary.
 * 4. Child parses parents stack (ENVV/AUXV), just after return from execve.
 * 5. Child saves the entry point code block of newly created process.
 * 6. Places stage one code to the entry point location. Stage one code
 *    consists of:
 *    - INT3 trap 
 *    - stack space allocation
 *    - mprotect this space to be executable
 *    - INT3
 *    - prctl PR_SET_NAME syscall
 *    - INT3
 * 7. Goes through all INT3 traps and reaches end of the stage one code.
 * 8. Places target arguments/environment on the stack.
 * 9. Places stage two code on the stack. Stage two code consists of:
 *    - waitpid/wait4 syscall
 *    - jump back to the entry point
 * 10. Recovers the entry point code block.
 * 11. Child exits.
 * 12. Parent continues with target arguments.
 *
 * FAQ:
 * Q: Why does child ptrace parent?
 * A: To preserve session. (Is there a better way to do that? Tell me about it.)
 *
 * Compilation (you need Linux kernel headers):
 * make m_rev 
 * or for 64-bit
 * make CFLAGS=-DBIT64 m_rev
 * 
 * Example:
 * $ m_rev
 * usage: ./m_rev_new [[args] --] runthis -t this -a args -- fakethis -f faked -
 * a args
 *        [args]
 *        sleep - sleep 15 seconds before exit
 *        clearenv - clear environment
 * $ m_rev sleep 64 -- zZzZ -z -Z
 * $ ps xf
 *   2607 ?        S      0:00 sshd: nh@pts/1
 *   2608 pts/1    Ss     0:00  \_ -bash
 *   2650 pts/1    S+     0:00      \_ zZzZ -z -Z
 * 
 * TODO: 
 * - mv (obsfucation for real location)
 * - Major code clean-up (i.e. merge logic of main 32/64-bit code parts).
 * - More overflow checks.
 * - Test with grsec.
 * - Check out portability possibilities (*BSD anyone?).
 * - setsid option
 *
 * Changelog:
 * ver 0.2 (2008-01-25)
 * - ENV pointer array fix
 * - prctl() (embedded in the first stage code)
 * - ET_DYN/auxv processing
 *
 * ver 0.1 (2008-01-16) 
 * - initial release
 *
 *
 * Keywords: hide hidden arguments args cloak command cmd line linux x86 x86-64 
 *           argv prctl cover mask ptrace
 *
 */


#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <syscall.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/user.h>
#include <unistd.h>
#include <errno.h>
#include <elf.h>

#ifndef BIT64
#define BIT32
#define BITSIZE     4
#else
#define BITSIZE     8
#endif

#define VECTORSPACE 0x64 * BITSIZE
#define DEBUG
#define HELP
#define SEARCHPATH

#define ALIGN(x,a) (((x)+(a)-1)&~((a)-1))


int
copy_from_debugee(pid_t pid, void *addr, void *to, size_t len)
{
#ifdef BIT32
	__u32           data;
#else
	__u64           data;
#endif

	if (len < BITSIZE || len % BITSIZE)
		return -1;

	while (len) {
		data = ptrace(PTRACE_PEEKDATA, pid, addr, NULL);
		if (errno != 0)
			return -1;

		len -= BITSIZE;
		addr += BITSIZE;
		memcpy(to, &data, BITSIZE);
		to += BITSIZE;
	}

	return 0;
}

int
copy_to_debugee(pid_t pid, void *addr, void *from, size_t len)
{
	int             ret;
#ifdef BIT32
	__u32           data;
#else
	__u64           data;
#endif

	if (len < BITSIZE || len % BITSIZE)
		return -1;

	while (len) {
		memcpy(&data, from, BITSIZE);

		ret = ptrace(PTRACE_POKEDATA, pid, addr, data);
		if (ret)
			return -1;

		len -= BITSIZE;
		addr += BITSIZE;
		from += BITSIZE;
	}

	return 0;
}

int
copy_qw_to_debugee(pid_t pid, void *addr, void *from)
{
	return copy_to_debugee(pid, addr, from, BITSIZE);
}

void           *
get_entry_point(char *path)
{
	FILE           *bin;
	int             ret;
#ifdef BIT32
	Elf32_Ehdr      elfh;
#else
	Elf64_Ehdr      elfh;
#endif

#ifdef SEARCHPATH
	char           *pathenv = getenv("PATH");
	char            pathm[1024],
	               *pp;
	struct stat     st;

	if (pathenv && strlen(pathenv) < 16384 && strchr(path, '/') == NULL) {
		pp = pathenv = strdup(pathenv);
		if (pp == NULL)
			err("assert");

		do {
			if (*pp == ':') {
				*pp++ = '\0';
			}
		} while (*pp++);

		while (pathenv < pp) {
			if (snprintf(pathm, sizeof(pathm) - 1, "%s/%s", pathenv, path)
					< 0) {
				err("die");
			}

			if (!stat(pathm, &st)) {
				chdir(pathenv);
				break;
			}
			pathenv += strlen(pathenv) + 1;
		}
	}

	/*
	 * We are not free()-ing pathenv, but we know about it, right? 
	 */
#endif

	bin = fopen(path, "rb");
	if (bin == NULL)
		return NULL;

	ret = fread(&elfh, sizeof(elfh), 1, bin);

	if (ret != 1) {
		fclose(bin);
		return NULL;
	}

	/*
	 * More ELF checks here. 
	 */

	fclose(bin);

	/*
	 * Dirty sexy money. 
	 */
	if (elfh.e_type & ET_DYN && !(elfh.e_type & ET_EXEC))
		return (elfh.e_entry + ((0x555555554AAA - /* vaddr */ 0) & ~4095));

	return elfh.e_entry;
}

int
test_print(unsigned char *addr, size_t len)
{
	int             i;

	for (i = 0; i < len; i++)
		printf("%02x ", addr[i]);

	printf("\n");
	return 0;
}


void
err(char *reason)
{
#ifdef DEBUG
	fprintf(stderr, "err: %s\n", reason);
#endif
	exit(1);
}


void
usage(char *p)
{
#ifdef HELP
	printf("usage: %s [[args] --] runthis -t this -a args"
				 " -- fakethis -f faked -a args\n", p);
	printf("       [args]\n");
	printf("       sleep - sleep 15 seconds before exit\n");
	printf("       clearenv - clear environment\n");
#endif

	exit(1);
}

void
dump_stack(pid_t pid)
{
#ifdef BIT32
	__u32           storage;
#else
	__u64           storage;
#endif
	void           *sp;
	struct user_regs_struct regs;

	if (ptrace(PTRACE_GETREGS, pid, 0, &regs))
		err("dump_stack");

#ifdef BIT32
	sp = regs.esp;
#else
	sp = regs.rsp;
#endif

	while (1) {
		storage = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
		if (errno)
			return;

		printf("%p: %p\n", sp, storage);
		sp += BITSIZE;
	}
}


#define VECTOR_AUX 0
#define VECTOR_ENV 1

void           *
get_ivs(pid_t pid, int vector)
{
#ifdef BIT32
	Elf32_auxv_t    auxie;
	__u32           storage;
#else
	Elf64_auxv_t    auxie;
	__u64           storage;
#endif
	struct user_regs_struct regs;
	void           *sp,
	               *sp_env;

	if (ptrace(PTRACE_GETREGS, pid, 0, &regs))
		err("get_auxv_entry");

#ifdef BIT32
	sp = regs.esp;
#else
	sp = regs.rsp;
#endif

	storage = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
	if (errno)
		err("get_auxv_entry");

	sp += storage * BITSIZE + BITSIZE;
	storage = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
	if (errno)
		err("get_auxv_entry - PTRACE_PEEKDATA");
	if (storage) {
		dump_stack(pid);
		err("get_auxv_entry - stack is bORken");
	}

	sp += BITSIZE;
	sp_env = sp;
	while (storage = ptrace(PTRACE_PEEKDATA, pid, sp, 0)) {
		if (errno)
			err("get_auxv_entry - PTRACE_PEEKDATA");

		sp += BITSIZE;
	}
	sp += BITSIZE;

	if (vector == VECTOR_ENV) {
		char           *p = malloc(sp - sp_env + BITSIZE);
		if (p == NULL)
			err("get_auxv_entry - malloc");

		if (copy_from_debugee(pid, sp_env, p, sp - sp_env))
			err("get_auxv_entry - copy_from_debugee");

		return p;
	}

	/*
	 * Here we are, the AUXV. 
	 */
	while (1) {
		if (copy_from_debugee(pid, sp, &auxie, sizeof(auxie)))
			err("get_auxv_entry - copy_from_debugee");

		if (auxie.a_type == AT_ENTRY)
			return (void *) auxie.a_un.a_val;
		else if (auxie.a_type == AT_NULL)
			return (void *) 0;

		sp += sizeof(auxie);
	}

	/*
	 * Reach this. 
	 */
}

int
main(int nc, char **na)
{
	int             wait_val;
	pid_t           pid,
	                parent_pid;
	int             i,
	                targetargc,
	                envc,
	                sep[3],
	                ret;
	FILE           *targetbin;
	char          **targetargs,
	              **fakeargs,
	              **envv,
	              **etmp;
	void           *e_entry,
	               *at_entry,
	               *execareastart,
	               *esp_argv,
	               *sp,
	               *ep;
	__u32           dw;
	__u64           qw;
	struct user_regs_struct regs;
	unsigned char   save[1024];
	unsigned char  *argvblock,
	               *avp;
	unsigned int    len;
	int             sleepydoo = 0,
			clearenvdoo = 0;
	extern char   **environ;
#ifdef BIT32
	/*
	 * 32-bit first stage code 
	 * 8048080:       cc                      int3
	 * 8048081:       81 ec ff 13 00 00       sub    $0x13ff,%esp
	 * 8048087:       b8 7d 00 00 00          mov    $0x7d,%eax
	 * 804808c:       89 e3                   mov    %esp,%ebx
	 * 804808e:       81 c3 ff 0f 00 00       add    $0xfff,%ebx
	 * 8048094:       81 e3 00 f0 ff ff       and    $0xfffff000,%ebx
	 * 804809a:       b9 00 10 00 00          mov    $0x1000,%ecx
	 * 804809f:       ba 07 00 00 00          mov    $0x7,%edx
	 * 80480a4:       cd 80                   int    $0x80
	 * 80480a6:       cc                      int3
	 * 80480a7:       b8 ac 00 00 00          mov    $0xac,%eax
	 * 80480ac:       bb 0f 00 00 00          mov    $0xf,%ebx
	 * 80480b1:       89 e1                   mov    %esp,%ecx
	 * 80480b3:       31 d2                   xor    %edx,%edx
	 * 80480b5:       cd 80                   int    $0x80
	 * 80480b7:       cc                      int3
	 *
	 * +- padding instructions 
	 */
	unsigned char   nsh[] =
			"\xcc\x81\xec\xff\x13\x00\x00\xb8\x7d\x00\x00\x00"
			"\x89\xe3\x81\xc3\xff\x0f\x00\x00\x81\xe3\x00\xf0"
			"\xff\xff\xb9\x00\x10\x00\x00\xba\x07\x00\x00\x00"
			"\xcd\x80\xcc\xb8\xac\x00\x00\x00\xbb\x0f\x00\x00"
			"\x00\x89\xe1\x31\xd2\xcd\x80\xcc";

	/*
	 * 32-bit second stage code 
	 * 8048080:       b8 07 00 00 00          mov    $0x7,%eax
	 * 8048085:       bb ff ff ff ff          mov    $0xffffffff,%ebx
	 * 804808a:       31 c9                   xor    %ecx,%ecx
	 * 804808c:       31 d2                   xor    %edx,%edx
	 * 804808e:       cd 80                   int    $0x80
	 * 8048090:       8d 84 24 cc 07 00 00    lea    0x7cc(%esp),%eax
	 * 8048097:       ff 20                   jmp    *(%eax)
	 */
	unsigned char   secondstage[] =
			"\x90\x90\x90\x90\xb8\x07\x00\x00\x00\xbb\xff\xff"
			"\xff\xff\x31\xc9\x31\xd2\xcd\x80\x8d\x84\x24\xcc"
			"\x07\x00\x00\xff\x20\xcc\x90\x90";
#else
	/*
	 * 64-bit first stage code
	 *  400078:       cc                      int3
	 *  400079:       48 81 ec ff 13 00 00    sub    $0x13ff,%rsp
	 *  400080:       48 c7 c0 0a 00 00 00    mov    $0xa,%rax
	 *  400087:       48 89 e7                mov    %rsp,%rdi
	 *  40008a:       48 81 c7 ff 0f 00 00    add    $0xfff,%rdi
	 *  400091:       48 81 e7 00 f0 ff ff    and    $0xfffffffffffff000,%rdi
	 *  400098:       48 c7 c6 00 10 00 00    mov    $0x1000,%rsi
	 *  40009f:       48 c7 c2 07 00 00 00    mov    $0x7,%rdx
	 *  4000a6:       0f 05                   syscall
	 *  4000a8:       cc                      int3
	 *  4000a9:       48 c7 c0 9d 00 00 00    mov    $0x9d,%rax
	 *  4000b0:       48 c7 c7 0f 00 00 00    mov    $0xf,%rdi
	 *  4000b7:       48 89 e6                mov    %rsp,%rsi
	 *  4000ba:       48 31 d2                xor    %rdx,%rdx
	 *  4000bd:       0f 05                   syscall
	 *  4000bf:       cc                      int3
	 *
	 */
	unsigned char   nsh[] =
			"\xcc\x48\x81\xec\xff\x13\x00\x00\x48\xc7\xc0\x0a"
			"\x00\x00\x00\x48\x89\xe7\x48\x81\xc7\xff\x0f\x00"
			"\x00\x48\x81\xe7\x00\xf0\xff\xff\x48\xc7\xc6\x00"
			"\x10\x00\x00\x48\xc7\xc2\x07\x00\x00\x00\x0f\x05"
			"\xcc\x48\xc7\xc0\x9d\x00\x00\x00\x48\xc7\xc7\x0f"
			"\x00\x00\x00\x48\x89\xe6\x48\x31\xd2\x0f\x05\xcc"
			"\x90\x90\x90\x90\x90\x90\x90\x90";

	/*
	 * 64-bit second stage code 
	 *  400078:       48 c7 c0 3d 00 00 00    mov    $0x3d,%rax
	 *  40007f:       48 31 f6                xor    %rsi,%rsi
	 *  400082:       48 c7 c7 ff ff ff ff    mov    $0xffffffffffffffff,%rdi
	 *  400089:       48 31 d2                xor    %rdx,%rdx
	 *  40008c:       4d 31 d2                xor    %r10,%r10
	 *  40008f:       0f 05                   syscall
	 *  400091:       48 8d 84 24 c8 07 00    lea    0x7c8(%rsp),%rax
	 *  400098:       00
	 *  400099:       ff 20                   jmpq   *(%rax)
	 */
	unsigned char   secondstage[] =
			"\x48\xc7\xc0\x3d\x00\x00\x00\x48\x31\xf6\x48\xc7"
			"\xc7\xff\xff\xff\xff\x48\x31\xd2\x4d\x31\xd2\x0f"
			"\x05\x48\x8d\x84\x24\xc8\x07\x00\x00\xff\x20\x90"
			"\x90\x90\x90\x90";
#endif

#if 0
	void            (*f) () = &secondstage;
	f();
#endif

	if (nc < 2)
		usage(na[0]);

	for (i = 1, sep[0] = 0; i < nc; i++) {
		if (!strcmp("--", na[i])) {
			if (sep[0]++ > 2 || i == 1)
				usage(na[0]);
			else
				sep[sep[0]] = i;
		}
	}

	if (!sep[0] || (sep[0] == 1 && nc < 4) || (sep[0] == 2 && nc < 6))
		usage(na[0]);

	if (sep[0] == 1) {
		if (sep[1] == nc - 1) {
			err("-- as the last argument?");
		} else {
			targetargs = &na[1];
			targetargc = sep[1] - 1;
			fakeargs = &na[sep[1] + 1];
		}
	} else {
		if (sep[1] == sep[2] - 1)
			err("Two separators in row.");

		if (sep[2] == nc - 1) {
			err("-- as the last argument?");
		} else {
			targetargs = &na[sep[1] + 1];
			targetargc = sep[2] - sep[1] - 1;
			fakeargs = &na[sep[2] + 1];
		}

		i = 1;
		do {
			printf("my arg %d: %s\n", i, na[i]);
			if (!strcmp(na[i], "sleep"))
				sleepydoo = 1;
			else if (!strcmp(na[i], "clearenv"))
				clearenvdoo = 1;
		} while (++i != sep[1]);
	}

	if ((sizeof(nsh) - 1) % BITSIZE)
		err("invalid alignment of the stage one code");

	envc = 0;
	envv = environ;
	while (*envv) {
		envv++;
		envc++;
	}
	printf("envc %d\n", envc);

	if ((targetargc + envc) * BITSIZE > (VECTORSPACE - BITSIZE * 8)) {
		err("potential overflow detected, increase the limit");
	}

	for (i = 0, len = 0; i < targetargc; i++)
		len += strlen(targetargs[i]) + 1;
	if (len > 1024)
		err("this will overflow either, fix it, please");

	if ((e_entry = get_entry_point(targetargs[0])) == NULL) {
		err("Cannot obtain the entry point.");
	}

	switch (pid = fork()) {
	case -1:
		perror("fork");
		break;
	case 0:
		pid = getppid();
		ret = ptrace(PTRACE_ATTACH, pid, 0, 0);
		printf("%d ret ptrace parent\n", ret);
		wait(&wait_val);

		while (1) {
			if (ptrace(PTRACE_SYSCALL, pid, 0, 0) == -1)
				err("SYSCALL");
			wait(&wait_val);
			ptrace(PTRACE_GETREGS, pid, NULL, &regs);

#ifdef BIT32
			if (regs.orig_eax == 11)
				break;
#else
			if (regs.orig_rax == 59)
				break;
#endif
		}

		ptrace(PTRACE_SYSCALL, pid, 0, 0);
		wait(&wait_val);
		/*
		 * Mkey, this is after return from execve. 
		 */

		at_entry = get_ivs(pid, VECTOR_AUX);
		/*
		 * Free me my dear fag. 
		 */
		envv = get_ivs(pid, VECTOR_ENV);

		printf("AT_ENTRY == %p\n", at_entry);
		envc = 0;
		etmp = envv;
		do {
			/*
			 * printf("%p env\n", *etmp); 
			 */
			envc++;
		} while (*etmp++);

		if (at_entry && e_entry != at_entry)
			e_entry = at_entry;
		printf("real entry %p\n", e_entry);
		printf("PAGESIZE %d\n", sysconf(_SC_PAGESIZE));

		/*
		 * Save the entry point block. 
		 */
		if (copy_from_debugee
				(pid, e_entry, (void *) &save, sizeof(nsh) - 1) == -1) {
			perror("copy_from_debugee EPB");
			printf("SAVE cfd failed || DETACHING\n");
			ptrace(PTRACE_DETACH, pid, 0, 0);
			err("EP block copy is critical for our nation.\n");
		}
		/*
		 * test_print(save, sizeof(nsh) - 1 + 4);
		 */

		/*
		 * Copy there stage one code.
		 */
		if (copy_to_debugee(pid, e_entry, nsh, (sizeof(nsh) - 1)) == -1)
			printf("ctd failed\n");

		/*
		 * Continue.
		 */
		for (i = 0; i < 3; i++) {
			if (ptrace(PTRACE_CONT, pid, 0, 0) != 0)
				perror("PTRACE_CONT");

			wait(&wait_val);

			ptrace(PTRACE_GETREGS, pid, NULL, &regs);
#ifdef BIT32
			printf("TRAP: %p\n", regs.eip);
			sp = regs.esp;
#else
			printf("TRAP: %p\n", regs.rip);
			sp = regs.rsp;
#endif
		}

		/*
		 * Mkey, stack space allocated, prctl call follows. 
		 * Let's pray. 
		 */
		if (copy_to_debugee
				(pid, sp, fakeargs[0], ALIGN(strlen(fakeargs[0]), BITSIZE)) == -1)
			printf("prctl ctd failed\n");

		if (ptrace(PTRACE_CONT, pid, 0, 0) != 0)
			perror("ass");
		wait(&wait_val);


		/*
		 * char buf[1024]; sprintf(buf, "cat /proc/%d/maps", pid);
		 * system(buf); 
		 */

		/*
		 * FINAL TRAP HIT 
		 */
#ifdef BIT32
		esp_argv = regs.esp + VECTORSPACE;
		dw = targetargc;

		printf("BITSIZE %d\n", BITSIZE);
		if (ptrace(PTRACE_POKEDATA, pid, regs.esp, dw) == -1)
			printf("fatal error\n");

		for (i = 0; i < targetargc; i++) {
			if (ptrace(PTRACE_POKEDATA,
								 pid, regs.esp + 4 + (4 * i), esp_argv) == -1)
				printf("fatal error\n");
			printf("DBG: adding targetargs[%d] <%s>\n", i, targetargs[i]);
			esp_argv += strlen(targetargs[i]) + 1;
		}

		dw = 0;
		ep = regs.esp + (targetargc * BITSIZE) + BITSIZE;
		if (ptrace(PTRACE_POKEDATA, pid, ep, dw) == -1)
			printf("fatal error\n");

		ep += BITSIZE;
		for (i = 0; i < envc; i++) {
			dw = envv[i];
			if (ptrace(PTRACE_POKEDATA, pid, ep, dw) == -1)
				printf("fatal error\n");
			printf("DBG: adding env %p\n", envv[i]);
			ep += BITSIZE;
		}
		dw = 0;
		if (ptrace(PTRACE_POKEDATA, pid, ep, dw) == -1)
			printf("fatal error\n");

		argvblock = malloc((len = esp_argv - (regs.esp + VECTORSPACE) + 8));
		len = ALIGN(len, BITSIZE);
		for (i = 0, avp = argvblock; i < targetargc; i++) {
			memcpy(avp, targetargs[i], strlen(targetargs[i]) + 1);
			avp += strlen(targetargs[i]) + 1;
		}

		if (copy_to_debugee(pid, regs.esp + VECTORSPACE, argvblock, len)) {
			printf("fatal error\n");
		}

		execareastart = (regs.esp + 4095) & ~(4095) + 2000;

		if (ptrace(PTRACE_POKEDATA, pid, regs.esp + 1996, e_entry))
			perror("PTRACE_POKEDATA");
		printf("trampoline %p\n", regs.esp + 1996);
		if (copy_to_debugee
				(pid, execareastart, secondstage, sizeof(secondstage) - 1))
			printf("copy_to_debugee failed\n");
		printf("%p exec area\n", execareastart);
		regs.eip = execareastart;
#else
		esp_argv = regs.rsp + VECTORSPACE;

		qw = targetargc;
		if (copy_qw_to_debugee(pid, regs.rsp, &qw))
			printf("fatal error\n");

		for (i = 0; i < targetargc; i++) {
			qw = (__u64) esp_argv;
			if (copy_qw_to_debugee(pid, regs.rsp + 8 + (8 * i), &qw) == -1)
				printf("fatal error\n");
			printf("DBG: adding targetargs[%d] <%s>\n", i, targetargs[i]);
			esp_argv += strlen(targetargs[i]) + 1;
		}
		qw = 0;
		copy_qw_to_debugee(pid, regs.rsp + 8 + targetargc * 8, &qw);

		for (i = 0, ep = regs.rsp + 16 + (targetargc * 8); i < envc; i++) {
			qw = (__u64) envv[i];
			if (copy_qw_to_debugee(pid, ep + (8 * i), &qw) == -1)
				printf("fatal error\n");
			printf("DBG: adding env %p\n", envv[i]);
		}
		qw = 0;
		copy_qw_to_debugee(pid, ep + (envc * 8), &qw);

		printf("occupied space %d\n", envc * 8 + targetargc * 8 + 24);
		len = esp_argv - (regs.rsp + VECTORSPACE) + 16;
		argvblock = malloc(len);
		if (argvblock == NULL)
			err("fatal");

		len = ALIGN(len, 8);
		for (i = 0, avp = argvblock; i < targetargc; i++) {
			memcpy(avp, targetargs[i], strlen(targetargs[i]) + 1);
			avp += strlen(targetargs[i]) + 1;
		}
		if (copy_to_debugee(pid, regs.rsp + VECTORSPACE, argvblock, len)) {
			printf("fatal error\n");
		}

		execareastart = (regs.rsp + 4095) & ~(4095) + 2000;
		qw = (__u64) e_entry;
		copy_qw_to_debugee(pid, regs.rsp + 1992, &qw);
		printf("trampoline %p\n", (__u64) (regs.rsp + 1992));
		if (copy_to_debugee
				(pid, execareastart, secondstage, sizeof(secondstage) - 1))
			printf("ctd failed\n");

		printf("%p exec area\n", execareastart);

		regs.rip = execareastart;
#endif
		/*
		 * dump_stack(pid); 
		 */

		ptrace(PTRACE_SETREGS, pid, NULL, &regs);
		if (copy_to_debugee
				(pid, (void *) e_entry, save, sizeof(nsh) - 1) == -1)
			printf("ctd failed\n");

		if (ptrace(PTRACE_DETACH, pid, 0, 0) == -1)
			perror("detach");

		printf("childpid %d, parentpid %d\n", getpid(), getppid());

		if (sleepydoo)
			sleep(0xf);

		printf("Emil se louci.\n");

		/*
		 * He he..
		 */
		free(envv);

		break;
	default:
		printf("Parent: %s\n", targetargs[0]);

		if (clearenvdoo)
			clearenv();

		/*
		 * Let's perform a syscall slide before execve.
		 */
		i = 0xf;
		while (i--)
			uname(save);

		/*
		 * Whoa, nice slide, man.
		 */
		execv(targetargs[0], fakeargs);
	}

	return 0;
}

/*
 * vim: set ts=2 
 */
