-
Notifications
You must be signed in to change notification settings - Fork 7
/
ptrace.c
155 lines (138 loc) · 3.99 KB
/
ptrace.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include "ptrace.h"
#include "utils.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <linux/elf.h>
#include <linux/uio.h>
#include <time.h>
int remote_call(pid_t pid, struct user_regs_struct* regs, uintptr_t func_addr, int argc, const uintptr_t* argv,
uintptr_t return_addr) {
if (argc >= 1) regs->REG_ARG0 = argv[0];
if (argc >= 2) regs->REG_ARG1 = argv[1];
if (argc >= 3) regs->REG_ARG2 = argv[2];
if (argc >= 4) regs->REG_ARG3 = argv[3];
if (argc >= 5) regs->REG_ARG4 = argv[4];
if (argc >= 6) regs->REG_ARG5 = argv[5];
regs->REG_IP = func_addr;
#ifdef __x86_64__
regs->REG_SP -= sizeof(long);
ptrace_write(pid, regs->REG_SP, &return_addr, sizeof(return_addr));
#elif defined(__aarch64__)
regs->regs[30] = return_addr;
#else
# error "Not supported"
#endif
if (ptrace_setregs(pid, regs)) return -1;
if (ptrace_continue(pid)) return -1;
if (remote_wait(pid)) return -1;
if (ptrace_getregs(pid, regs)) return -1;
return 0;
}
int remote_wait(pid_t pid) {
while (1) {
int status;
pid_t err = waitpid(pid, &status, __WALL);
if (err == -1) {
if (errno == EINTR) continue;
printf("waitpid(%d) failed: %s(%d)\n", pid, strerror(errno), errno);
return -1;
}
if (!WIFSTOPPED(status)) {
printf("target process not stopped\n");
return -1;
}
return 0;
}
}
int ptrace_attach(pid_t pid) {
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) {
printf("ptrace(PTRACE_ATTACH) failed: %s(%d)\n", strerror(errno), errno);
return -1;
}
return 0;
}
int ptrace_detach(pid_t pid) {
if (ptrace(PTRACE_DETACH, pid, NULL, NULL) == -1) {
printf("ptrace(PTRACE_DETACH) failed: %s(%d)\n", strerror(errno), errno);
return -1;
}
return 0;
}
int ptrace_getregs(pid_t pid, struct user_regs_struct* regs) {
#ifdef __x86_64__
if (ptrace(PTRACE_GETREGS, pid, NULL, regs) == -1) {
printf("ptrace(PTRACE_GETREGS) failed: %s(%d)\n", strerror(errno), errno);
return -1;
}
#elif defined(__aarch64__)
struct iovec iov;
iov.iov_base = regs;
iov.iov_len = sizeof(struct user_regs_struct);
if (ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, &iov) == -1) {
printf("ptrace(PTRACE_GETREGSET) failed: %s(%d)\n", strerror(errno), errno);
return -1;
}
#endif
return 0;
}
int ptrace_setregs(pid_t pid, struct user_regs_struct* regs) {
#ifdef __x86_64__
if (ptrace(PTRACE_SETREGS, pid, NULL, regs) == -1) {
fprintf(stderr, "ptrace(PTRACE_SETREGS) failed: %s(%d)\n", strerror(errno), errno);
return false;
}
#elif defined(__aarch64__)
struct iovec iov;
iov.iov_base = regs;
iov.iov_len = sizeof(*regs);
if (ptrace(PTRACE_SETREGSET, pid, (void*)NT_PRSTATUS, &iov) == -1) {
printf("ptrace(PTRACE_SETREGSET) failed: %s(%d)\n", strerror(errno), errno);
return -1;
}
#endif
return 0;
}
int ptrace_continue(pid_t pid) {
if (ptrace(PTRACE_CONT, pid, NULL, NULL) == -1) {
printf("ptrace(PTRACE_CONT) failed: %s(%d)\n", strerror(errno), errno);
return -1;
}
return 0;
}
int ptrace_read(pid_t pid, uintptr_t addr, void* vptr, int len) {
int count = 0;
int i = 0;
long word = 0;
long* ptr = (long*)vptr;
while (count < len) {
errno = 0;
word = ptrace(PTRACE_PEEKTEXT, pid, addr + count, NULL);
if (unlikely(errno)) {
printf("ptrace(PTRACE_PEEKTEXT) failed: %s(%d)\n", strerror(errno), errno);
return -1;
}
count += sizeof(word);
if (unlikely(count > len))
memcpy(ptr + i, &word, sizeof(word) - (count - len));
else
ptr[i++] = word;
}
return 0;
}
int ptrace_write(pid_t pid, uintptr_t addr, const void* vptr, int len) {
int count = 0;
long word = 0;
// TODO:
// assert(!(len % sizeof(word)));
while (count < len) {
memcpy(&word, (const char*)vptr + count, sizeof(word));
word = ptrace(PTRACE_POKETEXT, pid, addr + count, word);
if (unlikely(word == -1)) {
printf("ptrace(PTRACE_POKETEXT) failed: %s(%d)\n", strerror(errno), errno);
return -1;
}
count += sizeof(word);
}
return 0;
}