Esempio n. 1
0
int inject_code(const struct process_hook *ph)
{
	char sbuf1[1024], sbuf2[1024];
	struct my_user_regs regs, saved_regs, aregs;
	int status;
	size_t v = 0;

	assert(ph);

	printf("[+] 64bit mode\n");

	if (ptrace(PTRACE_ATTACH, ph->pid, NULL, NULL) < 0)
		die("[-] ptrace");
	waitpid(ph->pid, &status, 0);
	if (ptrace(PTRACE_GETREGS, ph->pid, NULL, &regs) < 0)
		die("[-] ptrace");

	peek_text(ph->pid, regs.rsp + 1024, sbuf1, sizeof(sbuf1));
	peek_text(ph->pid, regs.rsp, sbuf2, sizeof(sbuf2));

	/* fake saved return address, triggering a SIGSEGV to catch */
	v = 0;
	poke_text(ph->pid, regs.rsp, (char *)&v, sizeof(v));
	poke_text(ph->pid, regs.rsp + 1024, ph->dso, strlen(ph->dso) + 1);

	memcpy(&saved_regs, &regs, sizeof(regs));
	printf("[+] rdi=0x%zx rsp=0x%zx rip=0x%zx\n", regs.rdi, regs.rsp, regs.rip);

	/* arguments to function we call */
	regs.rdi = regs.rsp + 1024;
	regs.rsi = RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE;
	regs.rip = (size_t)ph->dlopen_address;

	if (ptrace(PTRACE_SETREGS, ph->pid, NULL, &regs) < 0)
		die("[-] ptrace");
	if (ptrace(PTRACE_CONT, ph->pid, NULL, NULL) < 0)
		die("[-] ptrace");
	/* Should receive a SIGSEGV for return to 0 */
	waitpid(ph->pid, &status, 0);

	if (ptrace(PTRACE_GETREGS, ph->pid, NULL, &aregs) < 0)
		die("[-] ptrace");

	printf("[+] rdi=0x%zx rsp=0x%zx rip=0x%zx\n", aregs.rdi, aregs.rsp, aregs.rip);
	if (ptrace(PTRACE_SETREGS, ph->pid, 0, &saved_regs) < 0)
		die("[-] ptrace");

	poke_text(ph->pid, saved_regs.rsp + 1024, sbuf1, sizeof(sbuf1));
	poke_text(ph->pid, saved_regs.rsp, sbuf2, sizeof(sbuf2));

	if (ptrace(PTRACE_DETACH, ph->pid, NULL, NULL) < 0)
		die("[-] ptrace");
	if (aregs.rip != 0)
		printf("[-] dlopen in target may have failed (no clean NULL fault)\n");

	return 0;
}
Esempio n. 2
0
int inject_code(pid_t pid, size_t libc_addr, size_t dlopen_addr, char *dso)
{
	char sbuf1[1024], sbuf2[1024];
	struct user_regs_struct regs, saved_regs;
	int status;

	if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0)
		die("ptrace 1");
	waitpid(pid, &status, 0);
	if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
		die("ptrace 2");

	peek_text(pid, regs.rsp + 1024, sbuf1, sizeof(sbuf1));
	peek_text(pid, regs.rsp, sbuf2, sizeof(sbuf2));

	/* fake saved return address */
	libc_addr = 0x0;
	poke_text(pid, regs.rsp, (char *)&libc_addr, sizeof(libc_addr));
	poke_text(pid, regs.rsp + 1024, dso, strlen(dso) + 1); 

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

	/* pointer to &args */
	printf("rdi=%zx rsp=%zx rip=%zx\n", regs.rdi, regs.rsp, regs.rip);

	regs.rdi = regs.rsp + 1024;
	regs.rsi = RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE;
	regs.rip = dlopen_addr + 2;// kernel bug?! always need to add 2!

	if (ptrace(PTRACE_SETREGS, pid, NULL, &regs) < 0)
		die("ptrace 3");
	if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0)
		die("ptrace 4");

	/* Should receive a SIGSEGV */
	waitpid(pid, &status, 0);

	if (ptrace(PTRACE_SETREGS, pid, 0, &saved_regs) < 0)
		die("ptrace 5");

	poke_text(pid, saved_regs.rsp + 1024, sbuf1, sizeof(sbuf1));
	poke_text(pid, saved_regs.rsp, sbuf2, sizeof(sbuf2));

	if (ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0)
		die("ptrace 6");

	return 0;
}
int fprintf_process(pid_t pid) {
  // attach to the process
  if (ptrace(PTRACE_ATTACH, pid, NULL, NULL)) {
    perror("PTRACE_ATTACH");
    check_yama();
    return -1;
  }

  // wait for the process to actually stop
  if (waitpid(pid, 0, WSTOPPED) == -1) {
    perror("wait");
    return -1;
  }

  // save the register state of the remote process
  struct user_regs_struct oldregs;
  if (ptrace(PTRACE_GETREGS, pid, NULL, &oldregs)) {
    perror("PTRACE_GETREGS");
    ptrace(PTRACE_DETACH, pid, NULL, NULL);
    return -1;
  }
  void *rip = (void *)oldregs.rip;
  printf("their %%rip           %p\n", rip);

  // First, we are going to allocate some memory for ourselves so we don't
  // need
  // to stop on the remote process' memory. We will do this by directly
  // invoking
  // the mmap(2) system call and asking for a single page.
  struct user_regs_struct newregs;
  memmove(&newregs, &oldregs, sizeof(newregs));
  newregs.rax = 9;                           // mmap
  newregs.rdi = 0;                           // addr
  newregs.rsi = PAGE_SIZE;                   // length
  newregs.rdx = PROT_READ | PROT_EXEC;       // prot
  newregs.r10 = MAP_PRIVATE | MAP_ANONYMOUS; // flags
  newregs.r8 = -1;                           // fd
  newregs.r9 = 0;                            //  offset

  uint8_t old_word[8];
  uint8_t new_word[8];
  new_word[0] = 0x0f; // SYSCALL
  new_word[1] = 0x05; // SYSCALL
  new_word[2] = 0xff; // JMP %rax
  new_word[3] = 0xe0; // JMP %rax

  // insert the SYSCALL instruction into the process, and save the old word
  if (poke_text(pid, rip, new_word, old_word, sizeof(new_word))) {
    goto fail;
  }

  // set the new registers with our syscall arguments
  if (ptrace(PTRACE_SETREGS, pid, NULL, &newregs)) {
    perror("PTRACE_SETREGS");
    goto fail;
  }

  // invoke mmap(2)
  if (singlestep(pid)) {
    goto fail;
  }

  // read the new register state, so we can see where the mmap went
  if (ptrace(PTRACE_GETREGS, pid, NULL, &newregs)) {
    perror("PTRACE_GETREGS");
    return -1;
  }

  // this is the address of the memory we allocated
  void *mmap_memory = (void *)newregs.rax;
  if (mmap_memory == (void *)-1) {
    printf("failed to mmap\n");
    goto fail;
  }
  printf("allocated memory at  %p\n", mmap_memory);

  printf("executing jump to mmap region\n");
  if (singlestep(pid)) {
    goto fail;
  }

  if (ptrace(PTRACE_GETREGS, pid, NULL, &newregs)) {
    perror("PTRACE_GETREGS");
    goto fail;
  }
  if (newregs.rip == (long)mmap_memory) {
    printf("successfully jumped to mmap area\n");
  } else {
    printf("unexpectedly jumped to %p\n", (void *)newregs.rip);
    goto fail;
  }

  // Calculate the position of the fprintf routine in the other process'
  // address
  // space. This is a little bit tricky because of ASLR on Linux. What we do
  // is
  // we find the offset in memory that libc has been loaded in their process,
  // and then we find the offset in memory that libc has been loaded in our
  // process. Then we take the delta betwen our fprintf and our libc start,
  // and
  // assume that the same delta will apply to the other process.
  //
  // For this mechanism to work, this program must be compiled with -fPIC to
  // ensure that our fprintf has an address relative to the one in libc.
  //
  // Additionally, this could fail if libc has been updated since the remote
  // process has been restarted. This is a pretty unlikely situation, but if
  // the
  // remote process has been running for a long time and you update libc, the
  // offset of the symbols could have changed slightly.
  void *their_libc = find_library(pid, libc_string);
  void *our_libc = find_library(getpid(), libc_string);
  void *their_fprintf = their_libc + ((void *)fprintf - our_libc);
  FILE *their_stderr = their_libc + ((void *)stderr - our_libc);
  printf("their libc           %p\n", their_libc);
  printf("their fprintf        %p\n", their_libc);
  printf("their stderr         %p\n", their_stderr);

  // We want to make a call like:
  //
  //   fprintf(stderr, "instruction pointer = %p\n", rip);
  //
  // To do this we're going to do the following:
  //
  //   * put a CALL instruction into the mmap area that calls fprintf
  //   * put a TRAP instruction right after the CALL
  //   * put the format string right after the TRAP
  //   * use the TRAP to restore the original text/program state

  // memory we are going to copy into our mmap area
  uint8_t new_text[32];
  memset(new_text, 0, sizeof(new_text));

  // insert a CALL instruction
  size_t offset = 0;
  new_text[offset++] = 0xe8; // CALL rel32
  int32_t fprintf_delta = compute_jmp(mmap_memory, their_fprintf);
  memmove(new_text + offset, &fprintf_delta, sizeof(fprintf_delta));
  offset += sizeof(fprintf_delta);

  // insert a TRAP instruction
  new_text[offset++] = 0xcc;

  // copy our fprintf format string right after the TRAP instruction
  memmove(new_text + offset, format, strlen(format));

  // update the mmap area
  printf("inserting code/data into the mmap area at %p\n", mmap_memory);
  if (poke_text(pid, mmap_memory, new_text, NULL, sizeof(new_text))) {
    goto fail;
  }

  if (poke_text(pid, rip, new_word, NULL, sizeof(new_word))) {
    goto fail;
  }

  // set up our registers with the args to fprintf
  // memmove(&newregs, &oldregs, sizeof(newregs));
  newregs.rax = 0;                          // no vector registers are used
  newregs.rdi = (long)their_stderr;         // pointer to stderr in the caller
  newregs.rsi = (long)mmap_memory + offset; // pointer to the format string
  newregs.rdx = oldregs.rip;                // the integer we want to print

  printf("setting the registers of the remote process\n");
  if (ptrace(PTRACE_SETREGS, pid, NULL, &newregs)) {
    perror("PTRACE_SETREGS");
    goto fail;
  }

  // continue the program, and wait for the trap
  printf("continuing execution\n");
  ptrace(PTRACE_CONT, pid, NULL, NULL);
  if (do_wait("PTRACE_CONT")) {
    goto fail;
  }

  if (ptrace(PTRACE_GETREGS, pid, NULL, &newregs)) {
    perror("PTRACE_GETREGS");
    goto fail;
  }
  newregs.rax = (long)rip;
  if (ptrace(PTRACE_SETREGS, pid, NULL, &newregs)) {
    perror("PTRACE_SETREGS");
    goto fail;
  }

  new_word[0] = 0xff; // JMP %rax
  new_word[1] = 0xe0; // JMP %rax
  poke_text(pid, (void *)newregs.rip, new_word, NULL, sizeof(new_word));

  printf("jumping back to original rip\n");
  if (singlestep(pid)) {
    goto fail;
  }
  if (ptrace(PTRACE_GETREGS, pid, NULL, &newregs)) {
    perror("PTRACE_GETREGS");
    goto fail;
  }

  if (newregs.rip == (long)rip) {
    printf("successfully jumped back to original %%rip at %p\n", rip);
  } else {
    printf("unexpectedly jumped to %p (expected to be at %p)\n",
           (void *)newregs.rip, rip);
    goto fail;
  }

  // unmap the memory we allocated
  newregs.rax = 11;                // munmap
  newregs.rdi = (long)mmap_memory; // addr
  newregs.rsi = PAGE_SIZE;         // size
  if (ptrace(PTRACE_SETREGS, pid, NULL, &newregs)) {
    perror("PTRACE_SETREGS");
    goto fail;
  }

  // make the system call
  printf("making call to mmap\n");
  if (singlestep(pid)) {
    goto fail;
  }
  if (ptrace(PTRACE_GETREGS, pid, NULL, &newregs)) {
    perror("PTRACE_GETREGS");
    goto fail;
  }
  printf("munmap returned with status %llu\n", newregs.rax);

  printf("restoring old text at %p\n", rip);
  poke_text(pid, rip, old_word, NULL, sizeof(old_word));

  printf("restoring old registers\n");
  if (ptrace(PTRACE_SETREGS, pid, NULL, &oldregs)) {
    perror("PTRACE_SETREGS");
    goto fail;
  }

  // detach the process
  printf("detaching\n");
  if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) {
    perror("PTRACE_DETACH");
    goto fail;
  }
  return 0;

fail:
  poke_text(pid, rip, old_word, NULL, sizeof(old_word));
  if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) {
    perror("PTRACE_DETACH");
  }
  return 1;
}
Esempio n. 4
0
int inject_code(pid_t pid, size_t libc_addr, size_t dlopen_addr, char *dso_file)
{
	char sbuf1[1024], sbuf2[1024];
	struct my_user_regs regs, saved_regs, aregs;
	int status;
	char *dso = NULL;
	size_t v = 0;

	printf("32bit mode\n");
	dso = realpath(dso_file, NULL);
	if (!dso || access(dso, X_OK) < 0)
		die(dso ? dso : dso_file);
	printf("Using normalized path '%s' for injection.\n", dso);

	if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0)
		die("ptrace 1");
	waitpid(pid, &status, 0);
	if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
		die("ptrace 2");

	peek_text(pid, regs.esp + 1024, sbuf1, sizeof(sbuf1));
	peek_text(pid, regs.esp, sbuf2, sizeof(sbuf2));

	/* fake saved return address, triggering a SIGSEGV to catch */
	libc_addr = 0x0;
	poke_text(pid, regs.esp, (char *)&libc_addr, sizeof(libc_addr));
	poke_text(pid, regs.esp + 1024, dso, strlen(dso) + 1); 
	free(dso);

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

	printf("esp=0x%zx eip=0x%zx\n", regs.esp, regs.eip);

	/* arguments passed on stack this time (x86) */
	v = regs.esp + 1024;
	poke_text(pid, regs.esp + sizeof(size_t), &v, sizeof(v));
	v = RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE;
	poke_text(pid, regs.esp + 2*sizeof(size_t), &v, sizeof(v));

	/* kernel bug. always add 2; in -m32 mode on 64bit systems its
	 * not needed!!!
	 */
	regs.eip = dlopen_addr + 2;

	if (ptrace(PTRACE_SETREGS, pid, NULL, &regs) < 0)
		die("ptrace 3");
	if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0)
		die("ptrace 4");

	/* Should receive a SIGSEGV for return to 0 */
	waitpid(pid, &status, 0);

	if (ptrace(PTRACE_GETREGS, pid, NULL, &aregs) < 0)
		die("ptrace 5");

	printf("esp=0x%zx eip=0x%zx\n", aregs.esp, aregs.eip);

	if (ptrace(PTRACE_SETREGS, pid, 0, &saved_regs) < 0)
		die("ptrace 6");

	poke_text(pid, saved_regs.esp + 1024, sbuf1, sizeof(sbuf1));
	poke_text(pid, saved_regs.esp, sbuf2, sizeof(sbuf2));

	if (ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0)
		die("ptrace 7");
	if (aregs.eip != 0)
		printf("dlopen in target may failed (no clean NULL fault)!\n");

	return 0;
}
Esempio n. 5
0
int inject_code(pid_t pid, size_t libc_addr, size_t dlopen_addr, char *dso_file)
{
	char sbuf1[1024], sbuf2[1024];
	struct my_user_regs regs, saved_regs, aregs;
	int status;
	char *dso = NULL;

	printf("64bit mode\n");
	dso = realpath(dso_file, NULL);
	if (!dso || access(dso, X_OK) < 0)
		die(dso ? dso : dso_file);
	printf("Using normalized path '%s' for injection.\n", dso);

	if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0)
		die("ptrace 1");
	waitpid(pid, &status, 0);
	if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
		die("ptrace 2");

	peek_text(pid, regs.rsp + 1024, sbuf1, sizeof(sbuf1));
	peek_text(pid, regs.rsp, sbuf2, sizeof(sbuf2));

	/* fake saved return address, triggering a SIGSEGV to catch */
	libc_addr = 0x0;
	poke_text(pid, regs.rsp, (char *)&libc_addr, sizeof(libc_addr));
	poke_text(pid, regs.rsp + 1024, dso, strlen(dso) + 1); 
	free(dso);

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

	printf("rdi=0x%zx rsp=0x%zx rip=0x%zx\n", regs.rdi, regs.rsp, regs.rip);

	/* arguments to function we call */
	regs.rdi = regs.rsp + 1024;
	regs.rsi = RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE;
	regs.rip = dlopen_addr + 2;// kernel bug?! always need to add 2!

	if (ptrace(PTRACE_SETREGS, pid, NULL, &regs) < 0)
		die("ptrace 3");
	if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0)
		die("ptrace 4");

	/* Should receive a SIGSEGV for return to 0 */
	waitpid(pid, &status, 0);

	if (ptrace(PTRACE_GETREGS, pid, NULL, &aregs) < 0)
		die("ptrace 5");

	printf("rdi=0x%zx rsp=0x%zx rip=0x%zx\n", aregs.rdi, aregs.rsp, aregs.rip);

	if (ptrace(PTRACE_SETREGS, pid, 0, &saved_regs) < 0)
		die("ptrace 6");

	poke_text(pid, saved_regs.rsp + 1024, sbuf1, sizeof(sbuf1));
	poke_text(pid, saved_regs.rsp, sbuf2, sizeof(sbuf2));

	if (ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0)
		die("ptrace 7");
	if (aregs.rip != 0)
		printf("dlopen in target may failed (no clean NULL fault)!\n");

	return 0;
}