xref: /linux-tools/ptrace/syscall_connect_lb.cpp (revision c995a2d01ec016e07a0052d1d0b650e51fec4753)
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, &regs);
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