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

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