Beispiel #1
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;    
}    
Beispiel #2
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 #3
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 #4
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 #5
0
static VALUE
ptrace_cont(int argc, VALUE *argv, VALUE self)
{
    VALUE data = INT2FIX(0);
    if (argc == 1) {
	data = argv[0];
    }
    return ptrace_continue(self, PT_CONTINUE, data);
}
Beispiel #6
0
static VALUE
ptrace_singlestep(int argc, VALUE *argv, VALUE self)
{
    VALUE data = INT2FIX(0);
    if (argc == 1) {
	data = argv[0];
    }
    return ptrace_continue(self, PT_STEP, data);
}
Beispiel #7
0
//------------------------------------------------------------------------------
// Name: resume
// Desc:
//------------------------------------------------------------------------------
void DebuggerCore::resume(edb::EVENT_STATUS status) {
	// TODO: assert that we are paused

	if(attached()) {
		if(status != edb::DEBUG_STOP) {
			const edb::tid_t tid = active_thread();
			const int code = (status == edb::DEBUG_EXCEPTION_NOT_HANDLED) ? resume_code(threads_[tid].status) : 0;
			ptrace_continue(tid, code);

			// resume the other threads passing the signal they originally reported had
			for(auto it = threads_.begin(); it != threads_.end(); ++it) {
				if(waited_threads_.contains(it.key())) {
					ptrace_continue(it.key(), resume_code(it->status));
				}
			}
		}
	}
}
Beispiel #8
0
// waits until the ATTACH has stopped the process
// by signal SIGSTOP
static bool ptrace_waitpid(pid_t pid) {
  int ret;
  int status;
  while (true) {
    // Wait for debuggee to stop.
    ret = waitpid(pid, &status, 0);
    if (ret == -1 && errno == ECHILD) {
      // try cloned process.
      ret = waitpid(pid, &status, __WALL);
    }
    if (ret >= 0) {
      if (WIFSTOPPED(status)) {
        // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP
        // will still be pending and delivered when the process is DETACHED and the process
        // will go to sleep.
        if (WSTOPSIG(status) == SIGSTOP) {
          // Debuggee stopped by SIGSTOP.
          return true;
        }
        if (!ptrace_continue(pid, WSTOPSIG(status))) {
          print_error("Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status));
          return false;
        }
      } else {
        print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status);
        return false;
      }
    } else {
      switch (errno) {
        case EINTR:
          continue;
          break;
        case ECHILD:
          print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid);
          break;
        case EINVAL:
          print_debug("waitpid() failed. Invalid options argument.\n");
          break;
        default:
          print_debug("waitpid() failed. Unexpected error %d\n",errno);
          break;
      }
      return false;
    }
  }
}
Beispiel #9
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 #10
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 #11
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 #12
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 #13
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;
}
//------------------------------------------------------------------------------
// Name: handle_event
// Desc:
//------------------------------------------------------------------------------
IDebugEvent::const_pointer DebuggerCore::handle_event(edb::tid_t tid, int status) {

	// note that we have waited on this thread
	waited_threads_.insert(tid);

	// was it a thread exit event?
	if(WIFEXITED(status)) {
		threads_.remove(tid);
		waited_threads_.remove(tid);

		// if this was the last thread, return true
		// so we report it to the user.
		// if this wasn't, then we should silently
		// procceed.
		if(!threads_.empty()) {
			return nullptr;
		}
	}

	// was it a thread create event?
	if(is_clone_event(status)) {

		unsigned long new_tid;
		if(ptrace_get_event_message(tid, &new_tid) != -1) {

			auto newThread     = std::make_shared<PlatformThread>(this, process_, new_tid);
			newThread->status_ = 0;
			newThread->state_  = PlatformThread::Stopped;

			threads_.insert(new_tid, newThread);

			int thread_status = 0;
			if(!waited_threads_.contains(new_tid)) {
				if(native::waitpid(new_tid, &thread_status, __WALL) > 0) {
					waited_threads_.insert(new_tid);
				}
			}

			if(!WIFSTOPPED(thread_status) || WSTOPSIG(thread_status) != SIGSTOP) {
				qDebug("[warning] new thread [%d] received an event besides SIGSTOP", static_cast<int>(new_tid));
			}
			
			newThread->status_ = thread_status;

			// TODO: what the heck do we do if this isn't a SIGSTOP?
			newThread->resume();
		}

		ptrace_continue(tid, 0);
		return nullptr;
	}

	// normal event


	auto e = std::make_shared<PlatformEvent>();

	e->pid_    = pid();
	e->tid_    = tid;
	e->status_ = status;
	if(ptrace_getsiginfo(tid, &e->siginfo_) == -1) {
		// TODO: handle no info?
	}

	active_thread_ = tid;
	
	auto it = threads_.find(tid);
	if(it != threads_.end()) {
		it.value()->status_ = status;
	}

	stop_threads();
	return e;
}