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
|
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include "procfs.h"
int procfs_open(pid_t pid) {
char path[2048];
sprintf(path, "/proc/%d/mem", pid);
return open(path, O_RDWR);
}
ssize_t procfs_maps(pid_t pid, struct procfs_map **maps) {
char path[2048];
sprintf(path, "/proc/%d/maps", pid);
FILE *f = fopen(path, "r");
if (!f) return -1;
int n = 0;
int capacity = 2;
if (*maps) {
free(*maps);
}
*maps = calloc(capacity, sizeof(**maps));
if (!*maps) return -1;
while (1) {
void *base, *max;
char prot_str[4];
char name[4096] = {0};
void *unused;
int matches = fscanf(
f, "%p-%p %4c %p %p:%p %d",
&base, &max, &prot_str, &unused, &unused, &unused, &unused
);
if (matches == EOF) goto eof;
if (matches < 7) goto err;
int c = ' ';
while (c == ' ') {
c = fgetc(f);
}
if (c == EOF) goto err;
ungetc(c, f);
if (fgets(name, 4096, f) == NULL) goto err;
name[strlen(name) - 1] = '\0'; // remove newline
int prot = 0;
for (int i = 0; i < 4; i++) {
switch (prot_str[i]) {
case 'r':
prot |= PROT_READ;
break;
case 'w':
prot |= PROT_WRITE;
break;
case 'x':
prot |= PROT_EXEC;
break;
default:
break;
}
}
if (prot == 0) prot = PROT_NONE;
if (n > 0) {
procfs_map *prev = *maps + (n - 1);
if ((strlen(name) == 0 || strncmp(prev->name, name, 1024) == 0) &&
prev->max == (uintptr_t)base) {
prev->max = (uintptr_t)max;
continue;
}
}
n++;
if (n > capacity) {
capacity <<= 1;
struct procfs_map *r = reallocarray(*maps, capacity, sizeof(*r));
if (!r) goto err;
*maps = r;
}
procfs_map *new = *maps + (n - 1);
new->base = (uintptr_t)base;
new->max = (uintptr_t)max;
new->prot = prot;
strncpy(new->name, name, sizeof(new->name) - 1);
}
eof:
if (ferror(f)) goto err;
fclose(f);
if (n == 0) {
free(*maps);
*maps = NULL;
}
return n;
err:
fclose(f);
free(*maps);
*maps = NULL;
return -1;
}
// mmap does not work on /proc/pid/mem, so we issue reads/writes instead
int read_mem(int fd, uintptr_t addr, uint8_t *data, size_t size) {
if (lseek(fd, addr, SEEK_SET) == -1) return -1;
size_t n = 0;
while (n < size) {
ssize_t result = read(fd, data + n, size - n);
if (result <= 0) return -1;
n += result;
}
return 0;
}
int write_mem(int fd, uintptr_t addr, uint8_t *data, size_t size) {
if (lseek(fd, addr, SEEK_SET) == -1) return -1;
size_t n = 0;
while (n < size) {
ssize_t result = write(fd, data + n, size - n);
if (result <= 0) return -1;
n += result;
}
return 0;
}
|