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
main(int argc,char * argv[])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