source: neercs/trunk/src/grab.c @ 2444

Last change on this file since 2444 was 2444, checked in by jylam, 7 years ago
  • Changed command line parsing to sam's mygetopt.c
  • Property svn:eol-style set to native
File size: 7.0 KB
Line 
1#include <errno.h>
2#include <fcntl.h>
3#include <signal.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <termios.h>
8#include <unistd.h>
9
10#include <sys/ioctl.h>
11#include <sys/ptrace.h>
12#include <sys/stat.h>
13#include <sys/syscall.h>
14#include <sys/user.h>
15#include <sys/wait.h>
16
17#include "neercs.h"
18int grab_process(pid_t pid, char *ptyname, int ptyfd);
19
20static int memcpy_from_target(pid_t pid, void* dest, void* src, size_t n)
21{
22    unsigned int i;
23    long *d, *s;
24    d = (long*) dest;
25    s = (long*) src;
26    n /= sizeof(long);
27    for (i = 0; i < n; i++) {
28        d[i] = ptrace(PTRACE_PEEKTEXT, pid, s+i, 0);
29        if (errno) {
30            perror("ptrace(PTRACE_PEEKTEXT)");
31            return -1;
32        }
33    }
34    return 0;
35}
36
37static int memcpy_into_target(pid_t pid, void* dest, void* src, size_t n)
38{
39    unsigned int i;
40    long *d, *s;
41    d = (long*) dest;
42    s = (long*) src;
43    for (i = 0; i < n / sizeof(long); i++) {
44        if (ptrace(PTRACE_POKETEXT, pid, d+i, s[i]) == -1) {
45            perror("ptrace(PTRACE_POKETEXT)");
46            return -1;
47        }
48    }
49    return 0;
50}
51
52static int do_syscall(pid_t pid, struct user_regs_struct *regs)
53{
54
55    struct user_regs_struct oregs;
56    long oinst;
57
58    if(ptrace(PTRACE_GETREGS, pid, NULL, &oregs) < 0)
59    {
60        return errno;
61    }
62
63    regs->esp -= 4;
64
65    oinst = ptrace(PTRACE_PEEKTEXT, pid, regs->esp, 0);
66    if (errno) {
67        fprintf(stderr, "PTRACE_PEEKTEXT failed\n");
68        return errno;
69    }
70
71    if (ptrace(PTRACE_POKETEXT, pid, regs->esp, 0x80cd) < 0) { /* int 0x80 */
72        fprintf(stderr, "PTRACE_POKETEXT failed\n");
73        return errno;
74    }
75
76    regs->eip = regs->esp;
77    if(ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0)
78    {
79        return errno;
80    }
81
82    if(ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0)
83    {
84        return errno;
85    }
86    waitpid(pid, NULL, 0);
87
88    if(ptrace(PTRACE_SETREGS, pid, NULL, &oregs) < 0)
89    {
90        return errno;
91    }
92
93    if(ptrace(PTRACE_POKETEXT, pid, oregs.esp-4 , oinst) < 0)
94    {
95        return errno;
96    }
97
98    return 0;
99}
100
101static int do_close(pid_t pid, int fd)
102{
103    struct user_regs_struct regs;
104    if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
105    {
106        fprintf(stderr, "PTRACE_GETREGS failed\n");
107        return errno;
108    }
109
110    regs.eax = SYS_close;
111    regs.ebx = fd;
112
113    return do_syscall(pid, &regs);
114}
115
116static int do_dup2(pid_t pid, int oldfd, int newfd)
117{
118    struct user_regs_struct regs;
119    if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
120    {
121        fprintf(stderr, "PTRACE_GETREGS failed\n");
122        return errno;
123    }
124
125    regs.eax = SYS_dup2;
126    regs.ebx = oldfd;
127    regs.ecx = newfd;
128
129    return do_syscall(pid, &regs);
130}
131
132static int do_open(pid_t pid, char *path, int mode, int *fd)
133{
134    struct user_regs_struct regs;
135    void *backup_page;
136    void *target_page = (void*)(0x08048000);
137    size_t size = (1<<12); /* 4K */
138    int ret;
139
140    /* Backup the page that we will use */
141    backup_page = malloc(size);
142    if (memcpy_from_target(pid, backup_page, target_page, size) < 0)
143        return -1;
144
145    if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
146    {
147        fprintf(stderr, "PTRACE_GETREGS failed\n");
148        return errno;
149    }
150
151    /* +4 because it's trcuncated on a multiple of 4 and we need 1 */
152    memcpy_into_target(pid, target_page, path, strlen(path)+4);
153
154    regs.eax = SYS_open;
155    regs.ebx = (long)target_page;
156    regs.ecx = O_RDWR;
157    regs.edx = 0755;
158
159    if((ret = do_syscall(pid, &regs)) < 0)
160    {
161        return ret;
162    }
163
164    /* Restore the pages */
165    memcpy_into_target(pid, target_page, backup_page, size);
166
167    *fd  = regs.eax;
168
169    return 0;
170}
171
172static int do_get_termios(pid_t pid, int fd, struct termios *t) {
173    struct user_regs_struct regs;
174    void *backup_page;
175    void *target_page = (void*)(0x08048000);
176    size_t size = (1<<12)*2; /* 8K */
177    int ret;
178
179    /* Backup the pages that we will use */
180    backup_page = malloc(size);
181    if (memcpy_from_target(pid, backup_page, target_page, size) < 0)
182        return -1;
183
184    if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
185    {
186        fprintf(stderr, "PTRACE_GETREGS failed\n");
187        return errno;
188    }
189
190    regs.eax = SYS_ioctl;
191    regs.ebx = fd;
192    regs.ecx = TCGETS;
193    regs.edx = ((long)target_page);
194
195    if((ret = do_syscall(pid, &regs)) < 0)
196    {
197        return ret;
198    }
199
200    if (regs.eax < 0) {
201        fprintf(stderr, "ioctl failed\n");
202        return (-regs.eax);
203    }
204
205    memcpy_from_target(pid, t, (void*)(target_page), sizeof(struct termios));
206
207    /* Restore the pages */
208    memcpy_into_target(pid, target_page, backup_page, size);
209
210    return 0;
211}
212
213static int do_setpgrp(pid_t pid, int fd) {
214    struct user_regs_struct regs;
215    void *backup_page;
216    void *target_page = (void*)(0x08048000);
217    size_t size = (1<<12)*2; /* 8K */
218    int ret, pgrp;
219
220    /* Backup the pages that we will use */
221    backup_page = malloc(size);
222    if (memcpy_from_target(pid, backup_page, target_page, size) < 0)
223        return -1;
224
225    if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
226    {
227        fprintf(stderr, "PTRACE_GETREGS failed\n");
228        return errno;
229    }
230
231    pgrp = getpgrp();
232
233    memcpy_into_target(pid, target_page, &getpgrp, 4);
234
235    regs.eax = SYS_ioctl;
236    regs.ebx = fd;
237    regs.ecx = TIOCSPGRP;
238    regs.edx = (long)(target_page);
239    do_syscall(pid, &regs);
240
241
242    if((ret = do_syscall(pid, &regs)) < 0)
243    {
244        return ret;
245    }
246
247    if (regs.eax < 0) {
248        fprintf(stderr, "ioctl failed\n");
249        return (-regs.eax);
250    }
251
252    /* Restore the pages */
253    memcpy_into_target(pid, target_page, backup_page, size);
254
255    return 0;
256}
257
258int grab_process(pid_t pid, char *ptyname, int ptyfd)
259{
260    struct termios t;
261    int i, fd = 0, mode, ret;
262    char fdstr[1024];
263    struct stat stat_buf;
264
265    debug("pty is %s", ptyname);
266
267    if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0)
268    {
269        fprintf(stderr, "Cannot access process %d\n", pid);
270        return errno;
271    }
272    waitpid(pid, NULL, 0);
273
274    for(i=0; i<=2; i++)
275    {
276        snprintf(fdstr, sizeof(fdstr), "/proc/%d/fd/%d", pid, i);
277        lstat(fdstr, &stat_buf);
278        if ((stat_buf.st_mode & S_IRUSR) && (stat_buf.st_mode & S_IWUSR))
279            mode = O_RDWR;
280        else if (stat_buf.st_mode & S_IWUSR)
281            mode = O_WRONLY;
282        else
283            mode = O_RDONLY;
284
285        if (stat(fdstr, &stat_buf) < 0)
286            continue;
287        if (!S_ISCHR(stat_buf.st_mode)) //FIXME How to know for sure this is the pty and not /dev/null ?
288            continue;
289
290        debug("fd %d is a pty", i);
291        if((ret = do_get_termios(pid, i, &t)))
292        {
293            fprintf(stderr, "do_get_termios %s\n", strerror(ret));
294        }
295        if((ret = do_close(pid, i)))
296        {
297            fprintf(stderr, "do_close %s\n", strerror(ret));
298        }
299        if((ret = do_open(pid, ptyname, mode, &fd)))
300        {
301            fprintf(stderr, "do_open %s\n", strerror(ret));
302        }
303        if((ret = do_dup2(pid, fd, i)))
304        {
305            fprintf(stderr, "do_dup2 %s\n", strerror(ret));
306        }
307        if((ret = do_setpgrp(pid, i)))
308        {
309            fprintf(stderr, "do_setpgrp %s\n", strerror(ret));
310        }
311    }
312
313    kill(pid, SIGWINCH);
314
315    ptrace(PTRACE_DETACH, pid, 0, 0);
316
317    return 0;
318}
Note: See TracBrowser for help on using the repository browser.