Beispiel #1
0
/* x86_64     rdi    rsi    rdx    r10    r8     r9      -    */
static register_t inject_syscall(pid_t pid, int nb_args, register_t syscallid,
                                 ...) {

  /* If we have more than 6 arguments, we must put them on the stack */
  /* For the moment, we don't handle this case  */
  assert(NB_MAX_ARGS >= nb_args);

  /* We do the backup of registers */
  long r;
  register_t ret;
  struct user_regs_struct regs, regs_backup;

  ptrace_getregs(pid, &regs);
  regs_backup = regs;

  /* We get back arguments and adequately put them in registers */

  int i = 0;
  va_list vargs;
  va_start(vargs, syscallid);

  long long unsigned *regs_ptr[NB_MAX_ARGS] = {&(regs.rdi), &(regs.rsi),
                                               &(regs.rdx), &(regs.r10),
                                               &(regs.r8),  &(regs.r9)};

  regs.rip = (register_t)tracer_buff->syscall;
  regs.rax = syscallid;

  if (syscallid == SYS_unprotect_protect) {
    regs.rip = (register_t)tracer_buff->unprotect_protect;
    regs.rax = SYS_mprotect;
    regs.r12 = SYS_mprotect;
    regs_ptr[3] = &(regs.r13);
    regs_ptr[4] = &(regs.r14);
    regs_ptr[5] = &(regs.r15);
  }

  for (i = 0; i < nb_args; i++) {
    *(regs_ptr[i]) = va_arg(vargs, long long unsigned);

  }
  va_end(vargs);

  ptrace_setregs(pid, &regs);

  ptrace_cont(pid);
  wait_event(pid);
  ptrace_getregs(pid, &regs);
  ret = regs.rax;

  ptrace_setregs(pid, &regs_backup);

  return ret;
}
Beispiel #2
0
void do_exec(int old_pid, int new_pid)
{
	unsigned long regs[FRAME_SIZE];
	int err;

	if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) ||
	   (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0))
		tracer_panic("do_exec failed to attach proc - errno = %d",
			     errno);

	CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED));
	if (err < 0)
		tracer_panic("do_exec failed to attach proc in waitpid - errno = %d",
			     errno);

	if(ptrace_getregs(old_pid, regs) < 0)
		tracer_panic("do_exec failed to get registers - errno = %d",
			     errno);

	kill(old_pid, SIGKILL);

	if(ptrace_setregs(new_pid, regs) < 0)
		tracer_panic("do_exec failed to start new proc - errno = %d",
			     errno);
}
Beispiel #3
0
void do_exec(int old_pid, int new_pid)
{
	unsigned long regs[FRAME_SIZE];
	int err;

	if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) ||
	   (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0))
		tracer_panic("do_exec failed to attach proc - errno = %d",
			     errno);

	CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED));
	if (err < 0)
		tracer_panic("do_exec failed to attach proc in waitpid - errno = %d",
			     errno);

	if(ptrace_getregs(old_pid, regs) < 0)
		tracer_panic("do_exec failed to get registers - errno = %d",
			     errno);

	os_kill_ptraced_process(old_pid, 0);

	if (ptrace(PTRACE_OLDSETOPTIONS, new_pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
		tracer_panic("do_exec: PTRACE_SETOPTIONS failed, errno = %d", errno);

	if(ptrace_setregs(new_pid, regs) < 0)
		tracer_panic("do_exec failed to start new proc - errno = %d",
			     errno);
}
Beispiel #4
0
long ptrace_call(pid_t pid, uint32_t addr, long *params, uint32_t num_params, struct user_regs_struct * regs)    
{    
	regs->esp -= (num_params) * sizeof(long) ;    
	ptrace_writedata(pid, (void *)regs->esp, (uint8_t *)params, (num_params) * sizeof(long));    

	long tmp_addr = 0x00;    
	regs->esp -= sizeof(long);    
	ptrace_writedata(pid, regs->esp, (char *)&tmp_addr, sizeof(tmp_addr));     

	regs->eip = addr;    

	if (ptrace_setregs(pid, regs) == -1     
		|| ptrace_continue( pid) == -1) {    
			printf("error\n");    
			return -1;    
	}    

	int stat = 0;  
	waitpid(pid, &stat, WUNTRACED);  
	while (stat != 0xb7f) {  
		if (ptrace_continue(pid) == -1) {  
			printf("error\n");  
			return -1;  
		}  
		waitpid(pid, &stat, WUNTRACED);  
	}  

	return 0;    
}    
void restore_remote(pid_t pid) {
   ptrace_setregs(pid, &_regs_backup);

#ifndef DEBUG
   if (_launcher_mode)
      // Detach and let injected child continue orphanaged
      ptrace_detach(victim_pid);
#endif
}
Beispiel #6
0
void inject_restore_socketcall(struct tracedump *td, struct pid *sp)
{
	struct user_regs_struct regs2;

	/* prepare */
	_prepare(sp);
	memcpy(&regs2, &sp->regs, sizeof regs2);
	regs2.eax = sp->regs.orig_eax;
	regs2.eip = sp->vdso_addr;

	/* exec */
	ptrace_setregs(sp, &regs2);
	ptrace_cont_syscall(sp, 0, true);
	ptrace_cont_syscall(sp, 0, true);

	/* rewrite the return code */
	ptrace_getregs(sp, &regs2);
	sp->regs.eax = regs2.eax;

	/* restore */
	ptrace_setregs(sp, &sp->regs);
}
Beispiel #7
0
int ptrace_call(pid_t pid, uint32_t addr, long *params, uint32_t num_params, struct pt_regs* regs)
{
    uint32_t i;
    // 前面4个参数存放到寄存器里
    for (i = 0; i < num_params && i < 4; i ++) {
        regs->uregs[i] = params[i];
    }

    //
    // push remain params into stack
    //
    if (i < num_params) {
    	// 栈顶指针sp往低地址移动,减去剩余参数的地址数(栈顶往“上”挪以容下剩余参数)
        regs->ARM_sp -= (num_params - i) * sizeof(long);
        // 往tracee的栈写入剩余参数
        ptrace_writedata(pid, (void *)regs->ARM_sp, (uint8_t *)&params[i], (num_params - i) * sizeof(long));
    }

    // 将PC寄存器指向目标函数, PS: 与x86不同,ARM中IP不是指令计数器,而是通用寄存器
    regs->ARM_pc = addr;
    if (regs->ARM_pc & 1) {
        /* 16位的thumb格式 */
        regs->ARM_pc &= (~1u);
        regs->ARM_cpsr |= CPSR_T_MASK;
    } else {
        /* arm格式 */
        regs->ARM_cpsr &= ~CPSR_T_MASK;
    }

    regs->ARM_lr = 0;

    // 将构造好的寄存器内容写入目标进程寄存器
    if (ptrace_setregs(pid, regs) == -1
    		// 恢复目标进程执行,将从调用函数地址即addr开始执行,参数为新赋值过来的寄存器内容
            || ptrace_continue(pid) == -1) {
        printf("error\n");
        return -1;
    }

    int stat = 0;
    waitpid(pid, &stat, WUNTRACED);
    while (stat != 0xb7f) {
        if (ptrace_continue(pid) == -1) {
            printf("error\n");
            return -1;
        }
        waitpid(pid, &stat, WUNTRACED);
    }

    return 0;
}
Beispiel #8
0
void inject_restore_socketcall(struct tracedump *td, struct pid *sp)
{
	/* int 0x80, int3 */
	unsigned char code[4] = { 0xcd, 0x80, 0xcc, 0 };
	char backup[4];
	struct user_regs_struct regs2;

	/* backup */
	ptrace_read(sp, sp->regs.eip, backup, 4);

	/* exec */
	sp->regs.eax = sp->regs.orig_eax;
	ptrace_setregs(sp, &sp->regs);
	ptrace_write(sp, sp->regs.eip, code, 4);
	ptrace_cont(sp, 0, true);

	/* read the return code */
	ptrace_getregs(sp, &regs2);
	sp->regs.eax = regs2.eax;

	/* restore */
	ptrace_setregs(sp, &sp->regs);
	ptrace_write(sp, sp->regs.eip, backup, 4);
}
Beispiel #9
0
static int
_restore_state(int pid)
{
  if (!target_state) return 1;
  CHECK(ptrace_setregs(pid, &target_state->regs),
	"Failed to set registers of target process");
  dprintf("Restored registers");
  CHECK(ptrace_writemem(pid, (void*)EIP(&target_state->regs), target_state->mem, target_state->mem_len),
	"Failed to write %ld bytes of memory to target process instruction pointer",
	target_state->mem_len);
  dprintf("Restored %ld bytes to EIP %p", target_state->mem_len, target_state->mem);
  free(target_state);
  target_state = NULL;
  return 1;
error:
  return 0;
}
Beispiel #10
0
void inject_escape_socketcall(struct tracedump *td, struct pid *sp)
{
	struct user_regs_struct regs;

	/* make backup */
	ptrace_getregs(sp, &regs);
	memcpy(&sp->regs, &regs, sizeof regs);

	/* update EBX so it is invalid */
	regs.ebx = 0;
	ptrace_setregs(sp, &regs);

	/* run the invalid socketcall and wait */
	ptrace_cont_syscall(sp, 0, true);

	/* -> now the process is in user mode */
}
Beispiel #11
0
int ptrace_call(pid_t pid, uint32_t addr, long *params, uint32_t num_params, struct pt_regs* regs)    
{    
	uint32_t i;    
	for (i = 0; i < num_params && i < 4; i ++) {    
		regs->uregs[i] = params[i];    
	}    

	//    
	// push remained params onto stack    
	//    
	if (i < num_params) {    
		regs->ARM_sp -= (num_params - i) * sizeof(long) ;    
		ptrace_writedata(pid, (void *)regs->ARM_sp, (uint8_t *)&params[i], (num_params - i) * sizeof(long));    
	}    

	regs->ARM_pc = addr;    
	if (regs->ARM_pc & 1) {    
		/* thumb */    
		regs->ARM_pc &= (~1u);    
		regs->ARM_cpsr |= CPSR_T_MASK;    
	} else {    
		/* arm */    
		regs->ARM_cpsr &= ~CPSR_T_MASK;    
	}    

	regs->ARM_lr = 0;        

	if (ptrace_setregs(pid, regs) == -1     
		|| ptrace_continue(pid) == -1) {    
			printf("error\n");    
			return -1;    
	}    

	int stat = 0;  
	waitpid(pid, &stat, WUNTRACED);  
	while (stat != 0xb7f) {  
		if (ptrace_continue(pid) == -1) {  
			printf("error\n");  
			return -1;  
		}  
		waitpid(pid, &stat, WUNTRACED);  
	}  

	return 0;    
}    
Beispiel #12
0
int ptrace_call( pid_t pid, uint32_t addr, long *params, uint32_t num_params, struct pt_regs* regs )
{
    uint32_t i;

    // put the first 4 parameters into r0-r3
    for ( i = 0; i < num_params && i < 4; i ++ )
    {
        regs->uregs[i] = params[i];
    }

    // push remained params into stack
    if ( i < num_params )
    {
        regs->ARM_sp -= (num_params - i) * sizeof(long) ;
        ptrace_writedata( pid, (void *)regs->ARM_sp, (uint8_t *)params[i], (num_params - i) * sizeof(long) );
    }
    // set the pc to func <e.g: mmap> that will be executed
    regs->ARM_pc = addr;
    if ( regs->ARM_pc & 1 )
    {
        /* thumb */
        regs->ARM_pc &= (~1u);
        regs->ARM_cpsr |= CPSR_T_MASK;
    }
    else
    {
        /* arm */
        regs->ARM_cpsr &= ~CPSR_T_MASK;
    }

    // when finish this func, pid will stop
    regs->ARM_lr = 0;   

    // set the regsister and start to execute
    if ( ptrace_setregs( pid, regs ) == -1 
            || ptrace_continue( pid ) == -1 )
    {
        return -1;
    }

    // wait pid finish work and stop
    waitpid( pid, NULL, WUNTRACED );

    return 0;
}
Beispiel #13
0
int ptrace_call(pid_t pid, uint32_t addr, const long *params, uint32_t num_params, struct pt_regs* regs)
{
    uint32_t i;
    //前面四个参数用寄存器传递
    for (i = 0; i < num_params && i < 4; i ++) {
        regs->uregs[i] = params[i];
    }

    //后面参数放到栈里
    if (i < num_params) {
        regs->ARM_sp -= (num_params - i) * sizeof(long) ;
        ptrace_writedata(pid, (void *)regs->ARM_sp, (uint8_t *)&params[i], (num_params - i) * sizeof(long));
    }

    //PC指向要执行的函数地址
    regs->ARM_pc = addr;

    if (regs->ARM_pc & 1) {
        /* thumb */
        regs->ARM_pc &= (~1u);
        regs->ARM_cpsr |= CPSR_T_MASK;
    } else {
        /* arm */
        regs->ARM_cpsr &= ~CPSR_T_MASK;
    }

    //把返回地址设为0,这样目标进程执行完返回时会出现地址错误,这样目标进程将被挂起,控制权会回到调试进程手中
    regs->ARM_lr = 0;

    //设置目标进程的寄存器,让目标进程继续运行
    if (ptrace_setregs(pid, regs) == -1 || ptrace_continue(pid) == -1) {
        return -1;
    }
    //等待目标进程结束
    int stat = 0;
    waitpid(pid, &stat, WUNTRACED);
    while (stat != 0xb7f) {
        if (ptrace_continue(pid) == -1) {
            return -1;
        }
        waitpid(pid, &stat, WUNTRACED);
    }

    return 0;
}
Beispiel #14
0
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
    int ret;

    switch (request) {
    /* Read the word at location addr in the child process */
    case PTRACE_PEEKTEXT:
    case PTRACE_PEEKDATA:
        ret = generic_ptrace_peekdata(child, addr, data);
        break;

    case PTRACE_PEEKUSR:
        ret = ptrace_read_user(child, addr,
                               (unsigned long __user *)data);
        break;

    /* Write the word in data at location addr */
    case PTRACE_POKETEXT:
    case PTRACE_POKEDATA:
        ret = generic_ptrace_pokedata(child, addr, data);
        break;

    case PTRACE_POKEUSR:
        ret = ptrace_write_user(child, addr, data);
        break;

    case PTRACE_GETREGS:
        ret = ptrace_getregs(child, (void __user *)data);
        break;

    case PTRACE_SETREGS:
        ret = ptrace_setregs(child, (const void __user *)data);
        break;

    default:
        ret = ptrace_request(child, request, addr, data);
        break;
    }

    return ret;
}
Beispiel #15
0
/**
 * call function at addr in target process
 * pid 			pid of target process
 * addr	    	address of the function you want to call
 * num_params 	the number of parameters
 * regs			registers' status
 */
int ptrace_call( pid_t pid, uint32_t addr, long *params, uint32_t num_params, struct pt_regs* regs )
{
	uint32_t i;

	for ( i = 0; i < num_params && i < 4; i ++ ) // ?? 
	{
		regs->uregs[i] = params[i];
	}

	//
	// push remained params into stack
	//
	if ( i < num_params )
	{
		regs->ARM_sp -= (num_params - i) * sizeof(long) ;
		ptrace_writedata( pid, (void *)regs->ARM_sp, (uint8_t *)&params[i], (num_params - i) * sizeof(long) );
	}

	regs->ARM_pc = addr;
	if ( regs->ARM_pc & 1 ) // thumb
	{
		regs->ARM_pc &= (~1u);
		regs->ARM_cpsr |= CPSR_T_MASK;
	}
	else  // arm 
	{		
		regs->ARM_cpsr &= ~CPSR_T_MASK;
	}

	regs->ARM_lr = 0;	// ??

	if ( ptrace_setregs( pid, regs ) == -1 || ptrace_continue( pid ) == -1 )
	{
		return -1;
	}


	waitpid( pid, NULL, WUNTRACED );

	return 0;
}
Beispiel #16
0
int ptrace_call(pid_t pid, unsigned int addr, long *params, unsigned int num_params, struct pt_regs* regs){

	unsigned int i;
	for (i = 0; i < num_params && i < 4; i++){
		regs->uregs[i] = params[i];
	}
	//
	// push remained params onto stack
	//
	if (i < num_params){
		regs->ARM_sp-= (num_params - i)* sizeof(long);
		ptrace_writedata(pid, (unsigned char *)regs->ARM_sp, (unsigned char*)&params[i], (num_params - i)* sizeof(long));
	}

	regs->ARM_pc= addr;
	if (regs->ARM_pc& 1)
	{
		/* thumb */
		regs->ARM_pc &= (~1u);
		regs->ARM_cpsr |= CPSR_T_MASK;
	}
	else
	{
		/* arm */
		regs->ARM_cpsr &= ~CPSR_T_MASK;
	}

	regs->ARM_lr= 0;

	if (ptrace_setregs(pid, regs)== -1 || ptrace_continue(pid)== -1){
		printf("[-] failed to call function: %s", strerror(errno));
		exit(Error_Ptrace_Call);
	}
	waitpid(pid, NULL, WUNTRACED);
	return 0;
}
Beispiel #17
0
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
	unsigned long tmp;
	int ret;

	pr_debug("arch_ptrace(%ld, %d, %#lx, %#lx)\n",
		 request, child->pid, addr, data);

	pr_debug("ptrace: Enabling monitor mode...\n");
	__mtdr(DBGREG_DC, __mfdr(DBGREG_DC) | DC_MM | DC_DBE);

	switch (request) {
	/* Read the word at location addr in the child process */
	case PTRACE_PEEKTEXT:
	case PTRACE_PEEKDATA:
		ret = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
		if (ret == sizeof(tmp))
			ret = put_user(tmp, (unsigned long __user *)data);
		else
			ret = -EIO;
		break;

	case PTRACE_PEEKUSR:
		ret = ptrace_read_user(child, addr,
				       (unsigned long __user *)data);
		break;

	/* Write the word in data at location addr */
	case PTRACE_POKETEXT:
	case PTRACE_POKEDATA:
		ret = access_process_vm(child, addr, &data, sizeof(data), 1);
		if (ret == sizeof(data))
			ret = 0;
		else
			ret = -EIO;
		break;

	case PTRACE_POKEUSR:
		ret = ptrace_write_user(child, addr, data);
		break;

	/* continue and stop at next (return from) syscall */
	case PTRACE_SYSCALL:
	/* restart after signal */
	case PTRACE_CONT:
		ret = -EIO;
		if (!valid_signal(data))
			break;
		if (request == PTRACE_SYSCALL)
			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		else
			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		child->exit_code = data;
		/* XXX: Are we sure no breakpoints are active here? */
		wake_up_process(child);
		ret = 0;
		break;

	/*
	 * Make the child exit. Best I can do is send it a
	 * SIGKILL. Perhaps it should be put in the status that it
	 * wants to exit.
	 */
	case PTRACE_KILL:
		ret = 0;
		if (child->exit_state == EXIT_ZOMBIE)
			break;
		child->exit_code = SIGKILL;
		wake_up_process(child);
		break;

	/*
	 * execute single instruction.
	 */
	case PTRACE_SINGLESTEP:
		ret = -EIO;
		if (!valid_signal(data))
			break;
		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		ptrace_single_step(child);
		child->exit_code = data;
		wake_up_process(child);
		ret = 0;
		break;

	/* Detach a process that was attached */
	case PTRACE_DETACH:
		ret = ptrace_detach(child, data);
		break;

	case PTRACE_GETREGS:
		ret = ptrace_getregs(child, (void __user *)data);
		break;

	case PTRACE_SETREGS:
		ret = ptrace_setregs(child, (const void __user *)data);
		break;

	default:
		ret = ptrace_request(child, request, addr, data);
		break;
	}

	pr_debug("sys_ptrace returning %d (DC = 0x%08lx)\n", ret, __mfdr(DBGREG_DC));
	return ret;
}
void gain_code_exec(pid_t remote_pid) {
   malloc_stub();

   ptrace_detach(remote_pid);
   exit(1);
 
   int status;

   // Find remote function adresses for malloc, free, __libc_dlopen_mode
   unsigned long remote_malloc_addr = find_remote_function("libc", find_libc_function("malloc"), remote_pid);
   unsigned long remote_free_addr = find_remote_function("libc", find_libc_function("free"), remote_pid);
   unsigned long remote_dlopen_addr = find_remote_function("libc", find_libc_function("__libc_dlopen_mode"), remote_pid);
   
   // Initialize global regs structs variables
   memset(&_regs_backup, 0, sizeof(struct user_regs_struct));
   memset(&_regs_fiddle, 0, sizeof(struct user_regs_struct));
   ptrace_getregs(remote_pid, &_regs_backup);
   reset_regs_fiddle();

   // Get Addr to write our initial stub to:
   unsigned long free_space_addr = find_free_space_addr(remote_pid);
   
   // Set RIP to addr start (2 byte long start instruction)
   _regs_fiddle.rip = free_space_addr + 2;
   
   // TODO TMP
   // Setup parameters in registers (see malloc_stub definition)
   _regs_fiddle.rbx = 1073741824; // exactly one GB
   _regs_fiddle.rax = remote_malloc_addr;
   
   // Upload registers
   printf("Uploading payload regs\n");
   ptrace_setregs(remote_pid, &_regs_fiddle);
   
   // Figure out stub size
   size_t stub_size = (intptr_t)malloc_stub_end - (intptr_t)malloc_stub;
   
   // Create buffer holdig our stub
   printf("Crafting payload stub\n");
   char* stub_code = malloc(stub_size * sizeof(char));
   memset(stub_code, 0, stub_size * sizeof(char));
   memcpy(stub_code, malloc_stub, stub_size);

   // Backup everything that we'll overwrite in target location
   printf("Backing up data\n");
   char* backup = malloc(stub_size * sizeof(char));
   read_data(remote_pid, free_space_addr, backup, stub_size);
   
   // Write our code to target location
   printf("Uploading payload\n");
   write_data(remote_pid, free_space_addr, stub_code, stub_size);
   
   // Continue execution and wait for int3
   printf("Code injection successfull, executing\n"); 
   ptrace_cont(remote_pid);
   sleep(1);
   printf("Pid returned ... probably\n");
   
   // Reupload old data
   printf("Reuploading old data\n");
   write_data(remote_pid, free_space_addr, backup, stub_size);
   ptrace_setregs(remote_pid, &_regs_backup);
   printf("Reset execution flow, continuing execution");
   
   ptrace_cont(remote_pid);
   
   free(backup);
   free(stub_code);
   
   printf("TMP; HALTING FOR 30 seconds\n");
   sleep(30);
}
Beispiel #19
0
int32_t inject_socketcall(struct tracedump *td, struct pid *sp, uint32_t sc_code, ...)
{
	/* int 0x80, int3 */
	unsigned char code[4] = { 0xcd, 0x80, 0xcc, 0 };
	char backup[4];
	struct user_regs_struct regs, regs2;
	int ss_vals, ss_mem, ss;
	va_list vl;
	enum arg_type type;
	uint32_t sv;
	void *ptr;
	uint8_t *stack, *stack_mem;
	uint32_t *stack32;
	int i, j;

	/*
	 * get the required amount of stack space
	 */
	ss_vals = 0;
	ss_mem = 0;
	va_start(vl, sc_code);
	do {
		type = va_arg(vl, enum arg_type);
		if (type == AT_LAST) break;
		sv  = va_arg(vl, uint32_t);

		/* each socketcall argument takes 4 bytes */
		ss_vals += 4;

		/* if its memory, it takes additional sv bytes */
		if (type == AT_MEM_IN || type == AT_MEM_INOUT) {
			ss_mem += sv;
			ptr = va_arg(vl, void *);
		}
	} while (true);
	va_end(vl);
	ss = ss_vals + ss_mem;

	/*
	 * backup
	 */
	ptrace_getregs(sp, &regs);
	memcpy(&regs2, &regs, sizeof regs);
	ptrace_read(sp, regs.eip, backup, sizeof backup);

	/*
	 * write the stack
	 */
	stack = mmatic_zalloc(td->mm, ss);
	stack32 = (uint32_t *) stack;
	stack_mem = stack + ss_vals;

	va_start(vl, sc_code);
	i = 0; j = 0;
	do {
		type = va_arg(vl, enum arg_type);
		if (type == AT_LAST) break;

		sv  = va_arg(vl, uint32_t);

		if (type == AT_VALUE) {
			stack32[i++] = sv;
		} else { /* i.e. its a memory arg */
			stack32[i++] = regs.esp - ss_mem + j;

			/* copy the memory */
			ptr = va_arg(vl, void *);
			memcpy(stack_mem + j, ptr, sv);
			j += sv;
		}
	} while (true);
	va_end(vl);

	ptrace_write(sp, regs.esp - ss, stack, ss);

	/*
	 * write the code and run
	 */
	regs2.eax = 102; // socketcall
	regs2.ebx = sc_code;
	regs2.ecx = regs.esp - ss;

	ptrace_write(sp, regs.eip, code, sizeof code);
	ptrace_setregs(sp, &regs2);
	ptrace_cont(sp, 0, true);

	/*
	 * read back
	 */
	ptrace_getregs(sp, &regs2);
	ptrace_read(sp, regs.esp - ss_mem, stack_mem, ss_mem);

	va_start(vl, sc_code);
	do {
		type = va_arg(vl, enum arg_type);
		if (type == AT_LAST) break;

		sv = va_arg(vl, uint32_t);
		if (type == AT_VALUE) continue;

		ptr = va_arg(vl, void *);
		if (type == AT_MEM_IN) continue;

		memcpy(ptr, stack_mem, sv);
		stack_mem += sv;
	} while (true);
	va_end(vl);

	/* restore */
	ptrace_write(sp, regs.eip, backup, sizeof backup);
	ptrace_setregs(sp, &regs);

	mmatic_free(stack);

	return regs2.eax;
}
Beispiel #20
0
int32_t inject_socketcall(struct tracedump *td, struct pid *sp, uint32_t sc_code, ...)
{
	struct user_regs_struct regs, regs2;
	int ss_vals, ss_mem, ss;
	va_list vl;
	enum arg_type type;
	uint32_t sv;
	void *ptr;
	uint8_t *stack, *stack_mem;
	uint32_t *stack32;
	int i, j;

	/*
	 * get the required amount of stack space
	 */
	ss_vals = 0;  // stack space for immediate values
	ss_mem = 0;   // stack space for pointer values
	va_start(vl, sc_code);
	do {
		type = va_arg(vl, enum arg_type);
		if (type == AT_LAST) break;
		sv  = va_arg(vl, uint32_t);

		/* each socketcall argument takes 4 bytes */
		ss_vals += 4;

		/* if its memory, it takes additional sv bytes */
		if (type == AT_MEM_IN || type == AT_MEM_INOUT) {
			ss_mem += sv;
			ptr = va_arg(vl, void *);
		}
	} while (true);
	va_end(vl);
	ss = ss_vals + ss_mem;

	/*
	 * backup
	 */
	ptrace_getregs(sp, &regs);
	memcpy(&regs2, &regs, sizeof regs);

	/*
	 * write the stack
	 */
	stack = mmatic_zalloc(td->mm, ss); // stack area for immediate values
	stack32 = (uint32_t *) stack;
	stack_mem = stack + ss_vals;       // stack area for pointer values

	va_start(vl, sc_code);
	i = 0; j = 0;
	do {
		type = va_arg(vl, enum arg_type);
		if (type == AT_LAST) break;

		sv  = va_arg(vl, uint32_t);

		if (type == AT_VALUE) {
			stack32[i++] = sv;
		} else { /* i.e. its a memory arg */
			stack32[i++] = regs.esp - ss_mem + j;

			/* copy the memory */
			ptr = va_arg(vl, void *);
			memcpy(stack_mem + j, ptr, sv);
			j += sv;
		}
	} while (true);
	va_end(vl);

	ptrace_write(sp, regs.esp - ss, stack, ss);

	/*
	 * write the code and run
	 */
	_prepare(sp);

	regs2.eax = 102;            // socketcall
	regs2.ebx = sc_code;
	regs2.ecx = regs.esp - ss;
	regs2.eip = sp->vdso_addr;  // gateway to int3

	ptrace_setregs(sp, &regs2);
	ptrace_cont_syscall(sp, 0, true);   // enter...
	ptrace_cont_syscall(sp, 0, true);   // ...and exit

	/*
	 * read back
	 */
	ptrace_getregs(sp, &regs2);
	ptrace_read(sp, regs.esp - ss_mem, stack_mem, ss_mem);

	va_start(vl, sc_code);
	do {
		type = va_arg(vl, enum arg_type);
		if (type == AT_LAST) break;

		sv = va_arg(vl, uint32_t);
		if (type == AT_VALUE) continue;

		ptr = va_arg(vl, void *);
		if (type == AT_MEM_IN) continue;

		memcpy(ptr, stack_mem, sv);
		stack_mem += sv;
	} while (true);
	va_end(vl);

	/* restore */
	ptrace_setregs(sp, &regs);
	mmatic_free(stack);

	return regs2.eax;
}
Beispiel #21
0
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
	int ret;

	switch (request) {
	/* when I and D space are separate, these will need to be fixed. */
	case PTRACE_PEEKTEXT: /* read word at location addr. */
	case PTRACE_PEEKDATA:
		ret = generic_ptrace_peekdata(child, addr, data);
		break;

	/* Read the word at location addr in the USER area. */
	case PTRACE_PEEKUSR: {
		struct pt_regs *regs;
		unsigned long tmp = 0;

		regs = task_pt_regs(child);
		ret = 0;  /* Default return value. */

		switch (addr) {
		case 0 ... 31:
			tmp = regs->regs[addr];
			break;
		case PC:
			tmp = regs->cp0_epc;
			break;
		case CAUSE:
			tmp = regs->cp0_cause;
			break;
		case BADVADDR:
			tmp = regs->cp0_badvaddr;
			break;
		case MMHI:
			tmp = regs->hi;
			break;
		case MMLO:
			tmp = regs->lo;
			break;
		default:
			tmp = 0;
			ret = -EIO;
			goto out;
		}
		ret = put_user(tmp, (unsigned long __user *) data);
		break;
	}

	/* when I and D space are separate, this will have to be fixed. */
	case PTRACE_POKETEXT: /* write the word at location addr. */
	case PTRACE_POKEDATA:
		ret = generic_ptrace_pokedata(child, addr, data);
		break;

	case PTRACE_POKEUSR: {
		struct pt_regs *regs;
		ret = 0;
		regs = task_pt_regs(child);

		switch (addr) {
		case 0 ... 31:
			regs->regs[addr] = data;
			break;
		case PC:
			regs->cp0_epc = data;
			break;
		case MMHI:
			regs->hi = data;
			break;
		case MMLO:
			regs->lo = data;
			break;
		default:
			/* The rest are not allowed. */
			ret = -EIO;
			break;
		}
		break;
		}

	case PTRACE_GETREGS:
		ret = ptrace_getregs(child, (__s64 __user *) data);
		break;

	case PTRACE_SETREGS:
		ret = ptrace_setregs(child, (__s64 __user *) data);
		break;

	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
	case PTRACE_CONT: { /* restart after signal. */
		ret = -EIO;
		if (!valid_signal(data))
			break;
		if (request == PTRACE_SYSCALL) {
			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		}
		else {
			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		}
		child->exit_code = data;
		wake_up_process(child);
		ret = 0;
		break;
	}

	/*
	 * make the child exit.  Best I can do is send it a sigkill.
	 * perhaps it should be put in the status that it wants to
	 * exit.
	 */
	case PTRACE_KILL:
		ret = 0;
		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
			break;
		child->exit_code = SIGKILL;
		wake_up_process(child);
		break;

	case PTRACE_GET_THREAD_AREA:
		ret = put_user(task_thread_info(child)->tp_value,
				(unsigned long __user *) data);
		break;

	default:
		ret = ptrace_request(child, request, addr, data);
		break;
	}
 out:
	return ret;
}
Beispiel #22
0
static int
_mmap_data(int pid, size_t len, void *base_address, int protections, int flags, void **out)
{
  int ret = 0;
  unsigned char *shellcode = NULL;
  
  FILE *f = fopen(MMAP_ASM, "rb");
  CHECK(f, "Error opening " MMAP_ASM);
  CHECK(fseek(f, 0, SEEK_END) == 0, "fseek error");
  long shellcode_len = ftell(f);
  CHECK(shellcode_len > 0, "ftell error");
  // align shellcode size to 32/64-bit boundary
  long shellcode_len_aligned = shellcode_len + (sizeof(void*) - (shellcode_len % sizeof(void*)));
  CHECK(fseek(f, 0, SEEK_SET) == 0, "fseek error");
  shellcode = malloc(shellcode_len_aligned);
  memset(shellcode, 0x90, shellcode_len_aligned); // fill with NOPs
  CHECK(shellcode, "malloc error");
  size_t r = fread(shellcode, 1, shellcode_len, f);
  CHECK(r == (size_t)shellcode_len, "fread error: %ld %ld", r, shellcode_len);
  fclose(f);
  
  // get current registers
  struct user_regs_struct orig_regs, regs = {0};
  CHECK(ptrace_getregs(pid, &regs),
	"Failed to get registers of target process");
  orig_regs = regs;
  
  // put our arguments in the proper registers (see mmap{64,32}.asm)
#ifdef __i386__
  regs.ebx = (long)base_address;
  regs.ecx = (long)len;
  regs.edx = (long)((protections) ? protections : MMAP_PROTS);
  regs.esi = (long)((flags) ? flags : MMAP_FLAGS);
#elif defined(__x86_64__)
  regs.rdi = (unsigned long long)base_address;
  regs.rsi = (unsigned long long)len;
  regs.rdx = (unsigned long long)((protections) ? protections : MMAP_PROTS);
  regs.r10 = (unsigned long long)((flags) ? flags : MMAP_FLAGS);
#endif
  CHECK(ptrace_setregs(pid, &regs),
	"Failed to set registers of target process");
  dprintf("Wrote our shellcode parameters into process registers");
  
  // write mmap code to target process EIP
  CHECK(ptrace_writemem(pid, (void*)EIP(&regs), shellcode, shellcode_len_aligned),
	"Failed to write mmap code to target process");
  dprintf("Wrote mmap code to EIP %p", (void*)EIP(&regs));
  
  // run mmap code and check return value
  CHECK(ptrace_continue(pid, 0), "Failed to execute mmap code");
  CHECK(_wait_trap(pid), "Error waiting for interrupt");
  dprintf("Mmap() finished execution");
  
  // get return value from mmap()
  CHECK(ptrace_getregs(pid, &regs),
	"Failed to get registers of target process");
  *out = (void*)EAX(&regs);
  dprintf("Mmap() returned %p", *out);
  CHECK(*out != MAP_FAILED, "Mmap() returned error");
  
  // restore registers
  CHECK(ptrace_setregs(pid, &orig_regs),
	"Failed to restore registers of target process");
  dprintf("Restored registers of target process");
  
  ret = 1;
error:
  if (shellcode)
    free(shellcode);
  return ret;
}
Beispiel #23
0
static int
_launch_payload(int pid, void *code_cave, size_t code_cave_size, void *stack_address, size_t stack_size, void *payload_address, size_t payload_len, void *payload_param, int flags)
{
  int ret = 0;
  unsigned char *shellcode = NULL;
  FILE *f = fopen(CLONE_ASM, "rb");
  CHECK(f, "Error opening " CLONE_ASM);
  CHECK(fseek(f, 0, SEEK_END) == 0, "fseek error");
  long shellcode_len = ftell(f);
  CHECK(shellcode_len > 0, "ftell error");
  CHECK(shellcode_len <= code_cave_size, "Shellcode is too big (%ld) for allocated code cave", shellcode_len);
  CHECK(fseek(f, 0, SEEK_SET) == 0, "fseek error");
  shellcode = malloc(code_cave_size);
  CHECK(shellcode, "malloc error");
  memset(shellcode, 0x90, code_cave_size); // fill with NOPs
  size_t r = fread(shellcode, 1, shellcode_len, f);
  CHECK(r == (size_t)shellcode_len, "fread error: %ld %ld", r, shellcode_len);
  fclose(f);
  
  // get current registers
  struct user_regs_struct regs = {0};
  CHECK(ptrace_getregs(pid, &regs),
	"Failed to get registers of target process");
  
  // put our arguments in the proper registers (see clone{64,32}.asm)
#ifdef __i386__
  regs.eax = (long)code_cave_size;
  regs.ebx = (long)((flags) ? flags : CLONE_FLAGS);
  regs.ecx = (long)stack_address;
  regs.edx = (long)stack_size;
  regs.esi = (long)payload_address;
  regs.edi = (long)payload_len;
  regs.ebp = (long)payload_param;
#elif defined(__x86_64__)
  regs.rax = (unsigned long long)code_cave_size;
  regs.rdi = (unsigned long long)((flags) ? flags : CLONE_FLAGS);
  regs.rsi = (unsigned long long)stack_address;
  regs.rdx = (unsigned long long)stack_size;
  regs.rcx = (unsigned long long)payload_address;
  regs.r8  = (unsigned long long)payload_len;
  regs.r9  = (unsigned long long)payload_param;
#endif
  // move EIP to our code cave
  EIP(&regs) = ADDR2INT(code_cave);
  CHECK(ptrace_setregs(pid, &regs),
	"Failed to set registers of target process");
  dprintf("Wrote our shellcode parameters into process registers. EIP: %p", code_cave);
  
  // write shellcode to target process code cave
  CHECK(ptrace_writemem(pid, code_cave, shellcode, code_cave_size),
	"Failed to write clone trampoline code to target process");
  dprintf("Wrote clone trampoline code to address %p", code_cave);
  
  // run shellcode and check return value
  CHECK(ptrace_continue(pid, code_cave), "Failed to execute clone trampoline code");
  CHECK(_wait_trap(pid), "Error waiting for interrupt");
  dprintf("Clone() finished execution");
  CHECK(ptrace_getregs(pid, &regs),
	"Failed to get registers of target process");
  dprintf("New thread ID: %lld", EAX(&regs));
  CHECK((int)EAX(&regs) != -1, "Clone() returned error");
  
  // no need to restore registers, as we're about to call _restore_state()
  
  dprintf("Successfully launched payload");
  
  ret = 1;
error:
  if (ret == 0)
    dprintf("Failed to launch payload");
  if (shellcode)
    free(shellcode);
  return ret;
}
Beispiel #24
0
int inject_remote_process_new(pid_t target_pid, const char *library_path, const char *function_name, const char *param, size_t param_size)
{    
	int ret = -1;    
	void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr;    
	void *local_handle, *remote_handle, *dlhandle;    
	uint8_t *map_base = 0;    
	uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr;    

	struct pt_regs regs, original_regs;    
	extern uint32_t _dlopen_addr_s, _dlopen_param1_s, _dlopen_param2_s, _dlsym_addr_s, \    
		_dlsym_param2_s, _dlclose_addr_s, _inject_start_s, _inject_end_s, _inject_function_param_s, \    
		_saved_cpsr_s, _saved_r0_pc_s;    

	uint32_t code_length;    
	long parameters[10];    

	DEBUG_PRINT("[+] Injecting process: %d\n", target_pid);    

	if (ptrace_attach(target_pid) == -1)    
		goto exit;    

	if (ptrace_getregs(target_pid, &regs) == -1)    
		goto exit;    

	/* save original registers */    
	memcpy(&original_regs, &regs, sizeof(regs));    

	mmap_addr = get_remote_addr(target_pid, libc_path, (void *)mmap);    
	DEBUG_PRINT("[+] Remote mmap address: %x\n", mmap_addr);    

	/* call mmap */    
	parameters[0] = 0;  // addr    
	parameters[1] = 0x4000; // size    
	parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC;  // prot    
	parameters[3] =  MAP_ANONYMOUS | MAP_PRIVATE; // flags    
	parameters[4] = 0; //fd    
	parameters[5] = 0; //offset    

	if (ptrace_call_wrapper(target_pid, "mmap", mmap_addr, parameters, 6, &regs) == -1)    
		goto exit;    

	map_base = ptrace_retval(&regs);    

	dlopen_addr = get_remote_addr( target_pid, linker_path, (void *)dlopen );    
	dlsym_addr = get_remote_addr( target_pid, linker_path, (void *)dlsym );    
	dlclose_addr = get_remote_addr( target_pid, linker_path, (void *)dlclose );    
	dlerror_addr = get_remote_addr( target_pid, linker_path, (void *)dlerror );    

	DEBUG_PRINT("[+] Get imports: dlopen: %x, dlsym: %x, dlclose: %x, dlerror: %x\n",    
		dlopen_addr, dlsym_addr, dlclose_addr, dlerror_addr);    

	printf("library path = %s\n", library_path);    
	ptrace_writedata(target_pid, map_base, library_path, strlen(library_path) + 1);    

	parameters[0] = map_base;       
	parameters[1] = RTLD_NOW| RTLD_GLOBAL;     

	if (ptrace_call_wrapper(target_pid, "dlopen", dlopen_addr, parameters, 2, &regs) == -1)    
		goto exit;    

	void * sohandle = ptrace_retval(&regs);    

#define FUNCTION_NAME_ADDR_OFFSET       0x100    
	ptrace_writedata(target_pid, map_base + FUNCTION_NAME_ADDR_OFFSET, function_name, strlen(function_name) + 1);    
	parameters[0] = sohandle;       
	parameters[1] = map_base + FUNCTION_NAME_ADDR_OFFSET;     

	if (ptrace_call_wrapper(target_pid, "dlsym", dlsym_addr, parameters, 2, &regs) == -1)    
		goto exit;    

	void * hook_entry_addr = ptrace_retval(&regs);    
	DEBUG_PRINT("hook_entry_addr = %p\n", hook_entry_addr);    

#define FUNCTION_PARAM_ADDR_OFFSET      0x200    
	ptrace_writedata(target_pid, map_base + FUNCTION_PARAM_ADDR_OFFSET, param, strlen(param) + 1);    
	parameters[0] = map_base + FUNCTION_PARAM_ADDR_OFFSET;      

	if (ptrace_call_wrapper(target_pid, "hook_entry", hook_entry_addr, parameters, 1, &regs) == -1)    
		goto exit;        

	printf("Press enter to dlclose and detach\n");    
	getchar();    
	parameters[0] = sohandle;       

	if (ptrace_call_wrapper(target_pid, "dlclose", dlclose, parameters, 1, &regs) == -1)    
		goto exit;    

	/* restore */    
	ptrace_setregs(target_pid, &original_regs);    
	ptrace_detach(target_pid);    
	ret = 0;    

exit:    
	return ret;    
}    
Beispiel #25
0
/* write the assembler code into target proc,
 * and invoke it to execute
 */
int writecode_to_targetproc( 
        pid_t target_pid, // target process pid
        const char *library_path, // the path of .so that will be 
        // upload to target process 
        const char *function_name, // .so init fucntion e.g. hook_init
        void *param, // the parameters of init function
        size_t param_size ) // number of parameters 
{
    int ret = -1;
    void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr;
    void *local_handle, *remote_handle, *dlhandle;
    uint8_t *map_base;
    uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr;

    struct pt_regs regs, original_regs;

    // extern global variable in the assembler code 
    extern uint32_t _dlopen_addr_s, _dlopen_param1_s, _dlopen_param2_s, \
        _dlsym_addr_s, _dlsym_param2_s, _dlclose_addr_s, \
        _inject_start_s, _inject_end_s, _inject_function_param_s, \
        _saved_cpsr_s, _saved_r0_pc_s;

    uint32_t code_length;

    long parameters[10];

    // make target_pid as its child process and stop
    if ( ptrace_attach( target_pid ) == -1 )
        return -1;

    // get the values of 18 registers from target_pid
    if ( ptrace_getregs( target_pid, &regs ) == -1 )
        goto exit;

    // save original registers 
    memcpy( &original_regs, @regs, sizeof(regs) );

    // get mmap address from target_pid
    // the mmap is the address of mmap in the cur process
    mmap_addr = get_remote_addr( target_pid, "/system/lib/libc.so", (void *)mmap );

    // set mmap parameters
    parameters[0] = 0;  // addr
    parameters[1] = 0x4000; // size
    parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC;  // prot
    parameters[3] =  MAP_ANONYMOUS | MAP_PRIVATE; // flags
    parameters[4] = 0; //fd
    parameters[5] = 0; //offset

    // execute the mmap in target_pid
    if ( ptrace_call( target_pid, (uint32_t)mmap_addr, parameters, 6, &regs) == -1 )
        goto exit;

    // get the return values of mmap <in r0>
    if ( ptrace_getregs( target_pid, &regs) == -1 )
        goto exit;

    // get the start address for assembler code
    map_base = (uint8_t *)regs.ARM_r0;

    // get the address of dlopen, dlsym and dlclose in target process
    dlopen_addr = get_remote_addr( target_pid, "/system/bin/linker", (void *)dlopen );
    dlsym_addr = get_remote_addr( target_pid, "/system/bin/linker", (void *)dlsym );
    dlclose_addr = get_remote_addr( target_pid, "/system/bin/linker", (void *)dlclose );

    // set the start address for assembler code in target process
    remote_code_ptr = map_base + 0x3C00;

    // set the start address for assembler code in cur process
    local_code_ptr = (uint8_t *)&_inject_start_s;

    // set global variable of assembler code
    // and these address is in the target process
    _dlopen_addr_s = (uint32_t)dlopen_addr;
    _dlsym_addr_s = (uint32_t)dlsym_addr;
    _dlclose_addr_s = (uint32_t)dlclose_addr;

    code_length = (uint32_t)&_inject_end_s - (uint32_t)&_inject_start_s;

    dlopen_param1_ptr = local_code_ptr + code_length + 0x20;
    dlsym_param2_ptr = dlopen_param1_ptr + MAX_PATH;
    saved_r0_pc_ptr = dlsym_param2_ptr + MAX_PATH;
    inject_param_ptr = saved_r0_pc_ptr + MAX_PATH;


    // save library path to assembler code global variable
    strcpy( dlopen_param1_ptr, library_path );
    _dlopen_param1_s = REMOTE_ADDR( dlopen_param1_ptr, local_code_ptr, remote_code_ptr );


    // save function name to assembler code global variable
    strcpy( dlsym_param2_ptr, function_name );
    _dlsym_param2_s = REMOTE_ADDR( dlsym_param2_ptr, local_code_ptr, remote_code_ptr );

    // save cpsr to assembler code global variable
    _saved_cpsr_s = original_regs.ARM_cpsr;

    // save r0-r15 to assembler code global variable
    memcpy( saved_r0_pc_ptr, &(original_regs.ARM_r0), 16 * 4 ); // r0 ~ r15
    _saved_r0_pc_s = REMOTE_ADDR( saved_r0_pc_ptr, local_code_ptr, remote_code_ptr );

    // save function parameters to assembler code global variable
    memcpy( inject_param_ptr, param, param_size );
    _inject_function_param_s = REMOTE_ADDR( inject_param_ptr, local_code_ptr, remote_code_ptr );

    // write the assembler code into target process
    // now the values of global variable is in the target process space
    ptrace_writedata( target_pid, remote_code_ptr, local_code_ptr, 0x400 );

    memcpy( &regs, &original_regs, sizeof(regs) );

    // set sp and pc to the start address of assembler code
    regs.ARM_sp = (long)remote_code_ptr;
    regs.ARM_pc = (long)remote_code_ptr;

    // set registers for target process
    ptrace_setregs( target_pid, &regs );

    // make the target_pid is not a child process of cur process
    // and make target_pid continue to running
    ptrace_detach( target_pid );

    // now finish it successfully
    ret = 0;

exit:
    return ret;
}
Beispiel #26
0
long arch_ptrace(struct task_struct *child, long request, unsigned long addr,
	unsigned long data)
{
	unsigned long tmp = 0;

	switch (request) {
	/* Read the word at location addr in the USER area. */
	case PTRACE_PEEKUSR: {


		switch (addr) {
		case 0 ... 31:
			tmp = *(((unsigned long *)task_pt_regs(child)) + addr);
			break;
		case PT_TEXT_ADDR:
			tmp = child->mm->start_code;
			break;
		case PT_TEXT_END_ADDR:
			tmp = child->mm->end_code;
			break;
		case PT_DATA_ADDR:
			tmp = child->mm->start_data;
			break;
		default:
			printk("ptrace attempted to PEEKUSR at %lx\n", addr);
			return -EIO;
		}
		return put_user(tmp, (unsigned long __user *)data);
	}
	case PTRACE_POKEUSR:
		switch (addr) {
		case 0 ... 31:
			*(((unsigned long *)task_pt_regs(child)) + addr) = data;
			break;
		default:
			printk("ptrace attempted to POKEUSR at %lx\n", addr);
			return -EIO;
		}
		break;

	/* when I and D space are separate, this will have to be fixed. */
	case PTRACE_POKETEXT: /* write the word at location addr. */
	case PTRACE_POKEDATA:
		//printk("PTRACE_POKE* [%s] *0x%lx = 0x%lx\n", child->comm, addr, data);
		if (access_process_vm(child, addr, &data, sizeof(data), 1)
		    != sizeof(data))
			return -EIO;
		asm volatile("nop");
		asm volatile("nop");
		asm volatile("nop");
		asm volatile("nop");
		asm volatile("wcsr ICC, r0");
		asm volatile("nop");
		asm volatile("nop");
		asm volatile("nop");
		asm volatile("nop");
		asm volatile("wcsr DCC, r0");
		asm volatile("nop");
		asm volatile("nop");
		asm volatile("nop");
		asm volatile("nop");
		break;

	/* TODO: Implement regset and use the generic PTRACE_{GET,SET}REGS instead */
	case PTRACE_GETREGS:
		return ptrace_getregs (child, (unsigned long __user *) data);
	case PTRACE_SETREGS:
		return ptrace_setregs (child, (unsigned long __user *) data);
	default:
		return ptrace_request(child, request, addr, data);
	}

	return 0;
}
Beispiel #27
0
/**
 * inject shared library to target process
 */
int inject_remote_process( pid_t target_pid, const char *library_path, const char *function_name, void *param, size_t param_size )
{
	int ret = -1;
	void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr;
	void *local_handle, *remote_handle, *dlhandle;
	uint8_t *map_base;
	uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr;

	struct pt_regs regs, original_regs;
	
	// declared in shellcode.s
	extern uint32_t _dlopen_addr_s, _dlopen_param1_s, _dlopen_param2_s, _dlsym_addr_s, \
			_dlsym_param2_s, _dlclose_addr_s, _inject_start_s, _inject_end_s, _inject_function_param_s, \
			_saved_cpsr_s, _saved_r0_pc_s, _hook_entry_addr_s;

	uint32_t code_length;

	long parameters[10];

	DEBUG_PRINT( "[+] Injecting process: %d\n", target_pid );

	
	if ( ptrace_attach( target_pid ) == -1 )
		return EXIT_SUCCESS;


	if ( ptrace_getregs( target_pid, &regs ) == -1 )
		goto exit;

	/* save original registers */
	memcpy( &original_regs, &regs, sizeof(regs) );

	mmap_addr = get_remote_addr( target_pid, "/system/lib/libc.so", (void *)mmap );

	DEBUG_PRINT( "[+] Remote mmap address: %x\n", mmap_addr );

	/* call mmap */
	parameters[0] = 0;	// addr
	parameters[1] = 0x4000; // size
	parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC;  // prot
	parameters[3] =  MAP_ANONYMOUS | MAP_PRIVATE; // flags
	parameters[4] = 0; //fd
	parameters[5] = 0; //offset

	DEBUG_PRINT( "[+] Calling mmap in target process.\n" );

	if ( ptrace_call( target_pid, (uint32_t)mmap_addr, parameters, 6, &regs ) == -1 )
		goto exit;

	if ( ptrace_getregs( target_pid, &regs ) == -1 )
		goto exit;

	DEBUG_PRINT( "[+] Target process returned from mmap, return value=%x, pc=%x \n", regs.ARM_r0, regs.ARM_pc );

	map_base = (uint8_t *)regs.ARM_r0;

	// get address of dlopen(), dlsym() and dlclose() in target process
	dlopen_addr = get_remote_addr( target_pid, linker_path, (void *)dlopen );
	dlsym_addr = get_remote_addr( target_pid, linker_path, (void *)dlsym );
	dlclose_addr = get_remote_addr( target_pid, linker_path, (void *)dlclose );

	DEBUG_PRINT( "[+] Get imports: dlopen: %x, dlsym: %x, dlclose: %x\n", dlopen_addr, dlsym_addr, dlclose_addr );


	remote_code_ptr = map_base + 0x3C00;
	local_code_ptr = (uint8_t *)&_inject_start_s;


	_dlopen_addr_s = (uint32_t)dlopen_addr;
	_dlsym_addr_s = (uint32_t)dlsym_addr;
	_dlclose_addr_s = (uint32_t)dlclose_addr;

	DEBUG_PRINT( "[+] Inject code start: %x, end: %x\n", local_code_ptr, &_inject_end_s );

	code_length = (uint32_t)&_inject_end_s - (uint32_t)&_inject_start_s;
	dlopen_param1_ptr = local_code_ptr + code_length + 0x20; // 0x20 == 32
	dlsym_param2_ptr = dlopen_param1_ptr + MAX_PATH;
	saved_r0_pc_ptr = dlsym_param2_ptr + MAX_PATH;
	inject_param_ptr = saved_r0_pc_ptr + MAX_PATH;

	/* dlopen parameter 1: library name */
	strcpy( dlopen_param1_ptr, library_path );
	_dlopen_param1_s = REMOTE_ADDR( dlopen_param1_ptr, local_code_ptr, remote_code_ptr );
	DEBUG_PRINT( "[+] _dlopen_param1_s: %x\n", _dlopen_param1_s );

	/* dlsym parameter 2: function name */
	strcpy( dlsym_param2_ptr, function_name );
	_dlsym_param2_s = REMOTE_ADDR( dlsym_param2_ptr, local_code_ptr, remote_code_ptr );
	DEBUG_PRINT( "[+] _dlsym_param2_s: %x\n", _dlsym_param2_s );

	/* saved cpsr */
	_saved_cpsr_s = original_regs.ARM_cpsr;

	/* saved r0-pc */
	memcpy( saved_r0_pc_ptr, &(original_regs.ARM_r0), 16 * 4 ); // r0 ~ r15
	_saved_r0_pc_s = REMOTE_ADDR( saved_r0_pc_ptr, local_code_ptr, remote_code_ptr );
	DEBUG_PRINT( "[+] _saved_r0_pc_s: %x\n", _saved_r0_pc_s );

	/* Inject function parameter */
	memcpy( inject_param_ptr, param, param_size );
	_inject_function_param_s = REMOTE_ADDR( inject_param_ptr, local_code_ptr, remote_code_ptr );
	DEBUG_PRINT( "[+] _inject_function_param_s: %x\n", _inject_function_param_s );

	DEBUG_PRINT( "[+] Remote shellcode address: %x\n", remote_code_ptr );
	ptrace_writedata( target_pid, remote_code_ptr, local_code_ptr, 0x400 );

	memcpy( &regs, &original_regs, sizeof(regs) );
	regs.ARM_sp = (long)remote_code_ptr;
	
	// change pc to execute instructions at remote_code_ptr
	regs.ARM_pc = (long)remote_code_ptr;
	
	DEBUG_PRINT( "[+] hook_entry address: %x\n", _hook_entry_addr_s);

	ptrace_setregs( target_pid, &regs );

	ptrace_detach( target_pid );

	// inject succeeded
	ret = 0;

exit:
	return ret;
}
/* Start debugger and get it to attach to this process.  Called if the
   user requests this service after an error has been shown, so she can
   poke around and look at parameters, memory, etc.  You can't
   meaningfully get the debugger to continue the program, though; to
   continue, quit the debugger.  */
void VG_(start_debugger) ( ThreadId tid )
{
#  define N_BUF 4096
   Int pid, rc;

   pid = VG_(fork)();

   if (pid == 0) {
      /* child */
      VG_(set_ptracer)();
      rc = VG_(ptrace)(VKI_PTRACE_TRACEME, 0, NULL, NULL);
      vg_assert(rc == 0);
      rc = VG_(kill)(VG_(getpid)(), VKI_SIGSTOP);
      vg_assert(rc == 0);

   } else if (pid > 0) {
      /* parent */
      Int status;
      Int res;

      if ((res = VG_(waitpid)(pid, &status, 0)) == pid &&
          WIFSTOPPED(status) && WSTOPSIG(status) == VKI_SIGSTOP &&
          ptrace_setregs(pid, &(VG_(threads)[tid].arch.vex)) == 0 &&
          VG_(kill)(pid, VKI_SIGSTOP) == 0 &&
          VG_(ptrace)(VKI_PTRACE_DETACH, pid, NULL, 0) == 0)
      {
         HChar pidbuf[15];
         HChar file[50];
         HChar buf[N_BUF];
         HChar *bufptr;
         const HChar *cmdptr;
         
         VG_(sprintf)(pidbuf, "%d", pid);
         VG_(sprintf)(file, "/proc/%d/fd/%d", pid, VG_(cl_exec_fd));
 
         bufptr = buf;
         cmdptr = VG_(clo_db_command);
         
         while (*cmdptr) {
            /* each iteration can advance bufptr by at most the length
               of file[], so the following assertion is generously
               over-paranoid. */
            vg_assert(bufptr - buf < N_BUF-15-50-10/*paranoia*/);
            switch (*cmdptr) {
               case '%':
                  switch (*++cmdptr) {
                     case 'f':
                        VG_(memcpy)(bufptr, file, VG_(strlen)(file));
                        bufptr += VG_(strlen)(file);
                        cmdptr++;
                        break;
                     case 'p':
                        VG_(memcpy)(bufptr, pidbuf, VG_(strlen)(pidbuf));
                        bufptr += VG_(strlen)(pidbuf);
                        cmdptr++;
                        break;
                     default:
                        *bufptr++ = *cmdptr++;
                        break;
                  }
                  break;
               default:
                  *bufptr++ = *cmdptr++;
                  break;
            }
            vg_assert(bufptr - buf < N_BUF-15-50-10/*paranoia*/);
         }
         
         *bufptr++ = '\0';
  
         VG_(message)(Vg_UserMsg, "starting debugger with cmd: %s\n", buf);
         res = VG_(system)(buf);
         if (res == 0) {      
            VG_(message)(Vg_UserMsg, "\n");
            VG_(message)(Vg_UserMsg, 
                         "Debugger has detached.  Valgrind regains control."
                         "  We continue.\n");
         } else {
            VG_(message)(Vg_UserMsg, 
                         "Warning: Debugger attach failed! (sys_system)\n");
            VG_(message)(Vg_UserMsg, "\n");
         }
      } else {
         VG_(message)(Vg_UserMsg, 
                      "Warning: Debugger attach failed! (ptrace problem?)\n");
         VG_(message)(Vg_UserMsg, "\n");
      }

      VG_(kill)(pid, VKI_SIGKILL);
      VG_(waitpid)(pid, &status, 0);
   }
#  undef N_BUF
}
Beispiel #29
0
/* 实现核心功能--注入 */
int inject_remote_process(pid_t target_pid, const char *library_path,
		const char *function_name, const char *param, size_t param_size)
{
    int ret = -1;
    // 存放目标进程地址
    void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr;
    void *local_handle, *remote_handle, *dlhandle;
    uint8_t *map_base = 0; // 存放目标进程mmap获取的内存块地址,mmap将一个文件或者其它对象映射进内存
    uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr;

    struct pt_regs regs, original_regs;
    extern uint32_t _dlopen_addr_s, _dlopen_param1_s, _dlopen_param2_s, _dlsym_addr_s, \
        _dlsym_param2_s, _dlclose_addr_s, _inject_start_s, _inject_end_s, _inject_function_param_s, \
        _saved_cpsr_s, _saved_r0_pc_s;

    uint32_t code_length;
    long parameters[10];

    DEBUG_PRINT("[+] Injecting process: %d\n", target_pid);

    // step 1. attach到目标进程
    if (ptrace_attach(target_pid) == -1)
        goto exit;

    // step 2. save context, 保存目标进程被注入前的寄存器内容
    // 方便注入完成后恢复
    if (ptrace_getregs(target_pid, &regs) == -1)
        goto exit;

    /* save original registers */
    memcpy(&original_regs, &regs, sizeof(regs));

    /* step 3. 获取目标进程存放mmap()代码的地址,执行mmap调用,
     * 在目标进程分配一块地址,用于存放后面要注入的库路径和相关函数地址等
     * mmap()会开辟一块内存,用于将一个文件或者其它对象映射进内存
     */
    // 寻找目标进程mmap的地址
    // libc为c语音标准库,一般进程都会加载;libc.so包含mmap函数
    mmap_addr = get_remote_addr(target_pid, libc_path, (void *)mmap);
    DEBUG_PRINT("[+] Remote mmap address: %x\n", mmap_addr);

    parameters[0] = 0;  // addr
    parameters[1] = 0x4000; // size
    parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC;  // prot
    parameters[3] =  MAP_ANONYMOUS | MAP_PRIVATE; // flags
    parameters[4] = 0; //fd
    parameters[5] = 0; //offset

    // 目标进程执行mmap
    if (ptrace_call_wrapper(target_pid, "mmap", mmap_addr, parameters, 6, &regs) == -1)
        goto exit;

    map_base = ptrace_retval(&regs);// mmap调用后返回值存入regs内的ax寄存器,syscall之前ax存调用号,调用后存返回值

    // step 4. 获取目标进程动态库的几个函数,并将要注入的so的路径写入刚刚申请的内存初始地址
    // dlopen()函数以指定模式打开指定的动态链接库文件,并返回一个句柄给dlsym()的调用进程。使用dlclose()来卸载打开的库。
    dlopen_addr = get_remote_addr(target_pid, linker_path, (void *)dlopen); // 找到dlopen()的地址
    dlsym_addr = get_remote_addr(target_pid, linker_path, (void *)dlsym); // 找到dlsys()地址
    dlclose_addr = get_remote_addr(target_pid, linker_path, (void *)dlclose); // 找到dlclose()地址
    dlerror_addr = get_remote_addr(target_pid, linker_path, (void *)dlerror); // 找到dlerror()地址

    DEBUG_PRINT("[+] Get imports: dlopen: %x, dlsym: %x, dlclose: %x, dlerror: %x\n",
            dlopen_addr, dlsym_addr, dlclose_addr, dlerror_addr);

    printf("library path = %s\n", library_path);
    // 将要注入的so的路径写入刚刚申请的内存初始地址,作为即将要调用的dlopen函数的参数parameters[0]
    ptrace_writedata(target_pid, map_base, library_path, strlen(library_path) + 1);

    // step 5. 在目标进程内调用dlopen函数加载要注入的so
    // 完成后so已经被注入目标进程的地址空间内了
    // 当库被装入后,可以把 dlopen() 返回的句柄作为给 dlsym() 的第一个参数,以获得符号在库中的地址。
    // 使用这个地址,就可以获得库中特定函数的指针,并且调用装载库中的相应函数。
    parameters[0] = map_base;
    parameters[1] = RTLD_NOW| RTLD_GLOBAL;

    if (ptrace_call_wrapper(target_pid, "dlopen", dlopen_addr, parameters, 2, &regs) == -1)
        goto exit;

    // step 6. 在目标进程内调用dlsym函数获取刚刚注入的so里的hook函数
    void * sohandle = ptrace_retval(&regs);

#define FUNCTION_NAME_ADDR_OFFSET       0x100
    ptrace_writedata(target_pid, map_base + FUNCTION_NAME_ADDR_OFFSET, function_name, strlen(function_name) + 1);
    parameters[0] = sohandle;
    parameters[1] = map_base + FUNCTION_NAME_ADDR_OFFSET;

    if (ptrace_call_wrapper(target_pid, "dlsym", dlsym_addr, parameters, 2, &regs) == -1)
        goto exit;

    // step 7. 在目标进程内调用hook函数
    void * hook_entry_addr = ptrace_retval(&regs); // dlsys()返回hook函数地址
    DEBUG_PRINT("hook_entry_addr = %p\n", hook_entry_addr);

#define FUNCTION_PARAM_ADDR_OFFSET      0x200
    ptrace_writedata(target_pid, map_base + FUNCTION_PARAM_ADDR_OFFSET, param, strlen(param) + 1);
    parameters[0] = map_base + FUNCTION_PARAM_ADDR_OFFSET;
    function_name
    if (ptrace_call_wrapper(target_pid, "hook_entry", hook_entry_addr, parameters, 1, &regs) == -1)
        goto exit;

    printf("Press enter to dlclose and detach\n");
    getchar();
    parameters[0] = sohandle;

    if (ptrace_call_wrapper(target_pid, "dlclose", dlclose, parameters, 1, &regs) == -1)
        goto exit;

    /* restore */
    // step 8. 恢复目标进程的寄存器,detach ptrace
    ptrace_setregs(target_pid, &original_regs);
    ptrace_detach(target_pid);
    ret = 0;

exit:
    return ret;
}
Beispiel #30
0
long arch_ptrace(struct task_struct *child, long request,
		 unsigned long addr, unsigned long data)
{
	int ret;
	void __user *addrp = (void __user *) addr;
	void __user *datavp = (void __user *) data;
	unsigned long __user *datalp = (void __user *) data;

	switch (request) {
	/* when I and D space are separate, these will need to be fixed. */
	case PTRACE_PEEKTEXT: /* read word at location addr. */
	case PTRACE_PEEKDATA:
		ret = generic_ptrace_peekdata(child, addr, data);
		break;

	/* Read the word at location addr in the USER area. */
	case PTRACE_PEEKUSR: {
		struct pt_regs *regs;
		union fpureg *fregs;
		unsigned long tmp = 0;

		regs = task_pt_regs(child);
		ret = 0;  /* Default return value. */

		switch (addr) {
		case 0 ... 31:
			tmp = regs->regs[addr];
			break;
		case FPR_BASE ... FPR_BASE + 31:
			if (!tsk_used_math(child)) {
				/* FP not yet used */
				tmp = -1;
				break;
			}
			fregs = get_fpu_regs(child);

#ifdef CONFIG_32BIT
			if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) {
				/*
				 * The odd registers are actually the high
				 * order bits of the values stored in the even
				 * registers.
				 */
				tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE],
						addr & 1);
				break;
			}
#endif
			tmp = get_fpr64(&fregs[addr - FPR_BASE], 0);
			break;
		case PC:
			tmp = regs->cp0_epc;
			break;
		case CAUSE:
			tmp = regs->cp0_cause;
			break;
		case BADVADDR:
			tmp = regs->cp0_badvaddr;
			break;
		case MMHI:
			tmp = regs->hi;
			break;
		case MMLO:
			tmp = regs->lo;
			break;
#ifdef CONFIG_CPU_HAS_SMARTMIPS
		case ACX:
			tmp = regs->acx;
			break;
#endif
		case FPC_CSR:
			tmp = child->thread.fpu.fcr31;
			break;
		case FPC_EIR:
			/* implementation / version register */
			tmp = boot_cpu_data.fpu_id;
			break;
		case DSP_BASE ... DSP_BASE + 5: {
			dspreg_t *dregs;

			if (!cpu_has_dsp) {
				tmp = 0;
				ret = -EIO;
				goto out;
			}
			dregs = __get_dsp_regs(child);
			tmp = dregs[addr - DSP_BASE];
			break;
		}
		case DSP_CONTROL:
			if (!cpu_has_dsp) {
				tmp = 0;
				ret = -EIO;
				goto out;
			}
			tmp = child->thread.dsp.dspcontrol;
			break;
		default:
			tmp = 0;
			ret = -EIO;
			goto out;
		}
		ret = put_user(tmp, datalp);
		break;
	}

	/* when I and D space are separate, this will have to be fixed. */
	case PTRACE_POKETEXT: /* write the word at location addr. */
	case PTRACE_POKEDATA:
		ret = generic_ptrace_pokedata(child, addr, data);
		break;

	case PTRACE_POKEUSR: {
		struct pt_regs *regs;
		ret = 0;
		regs = task_pt_regs(child);

		switch (addr) {
		case 0 ... 31:
			regs->regs[addr] = data;
			/* System call number may have been changed */
			if (addr == 2)
				mips_syscall_update_nr(child, regs);
			else if (addr == 4 &&
				 mips_syscall_is_indirect(child, regs))
				mips_syscall_update_nr(child, regs);
			break;
		case FPR_BASE ... FPR_BASE + 31: {
			union fpureg *fregs = get_fpu_regs(child);

			init_fp_ctx(child);
#ifdef CONFIG_32BIT
			if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) {
				/*
				 * The odd registers are actually the high
				 * order bits of the values stored in the even
				 * registers.
				 */
				set_fpr32(&fregs[(addr & ~1) - FPR_BASE],
					  addr & 1, data);
				break;
			}
#endif
			set_fpr64(&fregs[addr - FPR_BASE], 0, data);
			break;
		}
		case PC:
			regs->cp0_epc = data;
			break;
		case MMHI:
			regs->hi = data;
			break;
		case MMLO:
			regs->lo = data;
			break;
#ifdef CONFIG_CPU_HAS_SMARTMIPS
		case ACX:
			regs->acx = data;
			break;
#endif
		case FPC_CSR:
			init_fp_ctx(child);
			ptrace_setfcr31(child, data);
			break;
		case DSP_BASE ... DSP_BASE + 5: {
			dspreg_t *dregs;

			if (!cpu_has_dsp) {
				ret = -EIO;
				break;
			}

			dregs = __get_dsp_regs(child);
			dregs[addr - DSP_BASE] = data;
			break;
		}
		case DSP_CONTROL:
			if (!cpu_has_dsp) {
				ret = -EIO;
				break;
			}
			child->thread.dsp.dspcontrol = data;
			break;
		default:
			/* The rest are not allowed. */
			ret = -EIO;
			break;
		}
		break;
		}

	case PTRACE_GETREGS:
		ret = ptrace_getregs(child, datavp);
		break;

	case PTRACE_SETREGS:
		ret = ptrace_setregs(child, datavp);
		break;

	case PTRACE_GETFPREGS:
		ret = ptrace_getfpregs(child, datavp);
		break;

	case PTRACE_SETFPREGS:
		ret = ptrace_setfpregs(child, datavp);
		break;

	case PTRACE_GET_THREAD_AREA:
		ret = put_user(task_thread_info(child)->tp_value, datalp);
		break;

	case PTRACE_GET_WATCH_REGS:
		ret = ptrace_get_watch_regs(child, addrp);
		break;

	case PTRACE_SET_WATCH_REGS:
		ret = ptrace_set_watch_regs(child, addrp);
		break;

	default:
		ret = ptrace_request(child, request, addr, data);
		break;
	}
 out:
	return ret;
}