
// makepkt1.c
// $ gcc -Wall makepkt1.c -o makepkt

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/user.h>
#include <sys/syscall.h>

#define TEXT_ADDRESS  0x400e70
#define FUNC_ADDRESS  0x401e9e

unsigned char g_request[0x28] = {
	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
	0xaa, 0xaa, 0x61, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
};

void err(char *str)
{
	fprintf(stderr, "ERROR: %s\n", str);
}

void target(char *argv[], char *argp[])
{
	if(ptrace(PTRACE_TRACEME, 0, NULL, NULL) != -1)
		execve(argv[0], argv, NULL);
	else
		err("PTRACE_TRACEME");
	exit(0);
}

void print_data(void)
{
	int i;
	for(i=0; i < 0x28; i++){
		if(i != 0 && i % 8 == 0)
			printf("\n");
		printf("%02x ", g_request[i]);
	}
	printf("\n");
}

void read_data(int pid, unsigned long addr, unsigned long *data, int len)
{
	int i;
	for(i=0; i < len; i++)
		data[i] = ptrace(PTRACE_PEEKDATA, pid, addr + (i * 8), NULL);
}

void write_data(int pid, unsigned long addr, unsigned long data)
{
	ptrace(PTRACE_POKEDATA, pid, addr, data);
}

void write_data2(int pid, unsigned long addr, unsigned long *data, int len)
{
	int i;
	for(i=0; i < len; i++)
		ptrace(PTRACE_POKEDATA, pid, addr + (i * 8), data[i]);
}

int control(int pid)
{
	int status;
	struct user_regs_struct regs;
	unsigned long flag = 0;

	while(1){
		waitpid(pid, &status, 0);
		if(WIFEXITED(status))
			break;
		ptrace(PTRACE_GETREGS, pid, 0, &regs);
		if(TEXT_ADDRESS == regs.rip){
			switch(flag)
			{
			case 0:
				flag = 1;
				write_data(pid, regs.rsp, TEXT_ADDRESS);
				write_data2(pid, regs.rsp + 8, (unsigned long *)g_request, 5);
				regs.rdi = regs.rsp + 8;
				regs.rsi = 8;
				regs.rdx = regs.rsp + 0x18;
				regs.rcx = regs.rsp + 0x18;
				regs.r8  = 0x14;
				regs.rip = FUNC_ADDRESS;
				ptrace(PTRACE_SETREGS, pid, 0, &regs);
				break;
			case 1:
				flag = 2;
				regs.rsp -= 8;
				read_data(pid, regs.rsp + 8, (unsigned long *)g_request, 5);
				// print_data();
				write_data(pid, regs.rsp, TEXT_ADDRESS);
				write_data2(pid, regs.rsp + 8, (unsigned long *)g_request, 5);
				regs.rdi = regs.rsp + 8 + 2;
				regs.rsi = 4;
				regs.rdx = regs.rsp + 0x0e;
				regs.rcx = regs.rsp + 0x0e;
				regs.r8  = 0x1e;
				regs.rip = FUNC_ADDRESS;
				ptrace(PTRACE_SETREGS, pid, 0, &regs);
				break; 
			case 2:
				regs.rsp -= 8;
				read_data(pid, regs.rsp + 8, (unsigned long *)g_request, 5);
				print_data();
				return 0;
			}
		}
		ptrace(PTRACE_SINGLESTEP, pid, 0, NULL);
	}

	return 0;
}

int exec_prog(char *argv[], char *argp[])
{
	int pid;

	switch(pid = fork())
	{
	case 0:
		target(argv, argp);
		break;
	case -1:
		err("ERROR");
		break;
	default:
		control(pid);
		break;
	}
	return 0;
}

int main(int argc, char *argv[], char *argp[])
{
	if(argc < 2){
		fprintf(stderr, "%s <args>\n", argv[0]);
		return 1;
	}
	argv++;
	exec_prog(argv, argp);
	return 0;
}

