1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <sys/types.h> 5 #include <sys/wait.h> 6 #include <sys/ptrace.h> 7 #include <sys/user.h> 8 #include <sys/syscall.h> 9 #include <netinet/in.h> 10 #include <netinet/ip.h> 11 #include <errno.h> 12 13 #include <set> 14 using namespace std; 15 16 #define exiterr(err, msg) do{ if(err<0) { perror(msg); exit(1); }} while(0) 17 18 19 // TODO: should load vip<->rips maps somewhere 20 unsigned int vip4 = 0x28282828; 21 unsigned int rip4s[] = { 22 0x50112ac, 23 0x40112ac, 24 0x30112ac, 25 }; 26 27 int main(int argc, char *argv[]) { 28 int pid, err, status, x; 29 unsigned long cpid; 30 struct user_regs_struct regs; 31 if (argc<2) { printf("need pid\n"); return 1; } 32 pid = atoi(argv[1]); 33 if (pid<=0) { printf("invalid pid %s\n", argv[1]); return 1; } 34 err = ptrace(PTRACE_ATTACH, pid, 0, 0); 35 exiterr(err, "fail to attach"); 36 printf("attached with %d\n", pid); 37 x = waitpid(-1, &status, __WALL); 38 if (x != pid) { 39 printf("expect pid %d, got %d\n", pid, x); 40 return 1; 41 } 42 // set opts 43 err = ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACECLONE|PTRACE_O_TRACEFORK|PTRACE_O_TRACEVFORK|PTRACE_O_TRACESYSGOOD); 44 exiterr(err, "fail to set trace options"); 45 // resume 46 err = ptrace(PTRACE_SYSCALL, pid, 0, 0); 47 exiterr(err, "fail to resume tracee"); 48 // loop 49 while(1) { 50 x = waitpid(-1, &status, __WALL); 51 exiterr(x, "fail to wait for tracee event"); 52 if (WSTOPSIG(status)==(SIGTRAP|0x80)) { 53 // syscalls 54 err = ptrace(PTRACE_GETREGS, x, 0, ®s); 55 if (err<0) { 56 perror("fail to copy process registers"); 57 continue; 58 } 59 // printf("syscall(%d) %lld(%llx, %llx, %llx)\n", x, regs.orig_rax, regs.rdi, regs.rsi, regs.rdx); 60 switch(regs.orig_rax) { 61 case SYS_connect: 62 // on x86, rax == -ENOSYS in syscall-enter-stop 63 if (regs.rax == -ENOSYS) { 64 // change 65 struct sockaddr_in *p; 66 unsigned long w = ptrace(PTRACE_PEEKDATA, x, regs.rsi, 0); 67 // 64bit enough for ipv4 68 p = (struct sockaddr_in*)&w; 69 if (p->sin_family == AF_INET) { 70 // printf("ipv4 connect to %x\n", p->sin_addr.s_addr); 71 if (p->sin_addr.s_addr == vip4) { 72 p->sin_addr.s_addr = rip4s[rand()%(sizeof(rip4s)/sizeof(rip4s[0]))]; 73 // write back 74 ptrace(PTRACE_POKEDATA, x, regs.rsi, w); 75 } 76 } 77 } 78 ptrace(PTRACE_SYSCALL, x, 0, 0); 79 break; 80 default: 81 err = ptrace(PTRACE_SYSCALL, x, 0, 0); 82 // exiterr(err, "fail to resume tracee after a syscall event"); 83 } 84 } else if (WIFSTOPPED(status)) { 85 // mostly signal 86 if (WSTOPSIG(status) != SIGSTOP&&WSTOPSIG(status) != SIGTRAP) ptrace(PTRACE_SYSCALL, x, 0, WSTOPSIG(status)); 87 else ptrace(PTRACE_SYSCALL, x, 0, 0); 88 } else { 89 // others 90 ptrace(PTRACE_SYSCALL, x, 0, 0); 91 } 92 } 93 // no need to deattach if exit? 94 return 0; 95 } 96