dff214dc7a8598e02f4793d815a7f23258886c0d
[tools.git] / strscan.c
1 // scans process memory for a given string, prints offsets of occurences
2 // will ignore matches where the match is split over a mapping boundary
3 #define _GNU_SOURCE
4 #include <unistd.h>
5 #include <stdio.h>
6 #include <assert.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <sys/wait.h>
10 #include <fcntl.h>
11 #include <jh.h>
12 #include <stdbool.h>
13 #include <string.h>
14 #include <sys/uio.h>
15
16 ssize_t getmem(pid_t pid, void *dst, void *src, size_t len) {
17   assert(len > 0);
18   struct iovec local = {.iov_base = dst, .iov_len = len};
19   struct iovec remote = {.iov_base = src, .iov_len = len};
20   return process_vm_readv(pid, &local, 1, &remote, 1, 0);
21 }
22
23 struct range {
24   void *a, *b;
25   char *line;
26   char readable;
27 };
28
29 struct range *mappings;
30 size_t mappings_used = 0;
31 #define FOR_EACH_MAPPING FOR_EACH_IN_ARRAY(mappings, mappings_used, mapping)
32
33 bool is_mapped(void *addr) {
34   FOR_EACH_MAPPING
35     if (mapping->a <= addr && mapping->b > addr) return true;
36   return false;
37 }
38
39 int main(int argc, char **argv) {
40   // init
41   if (argc != 3) xperror("invocation: anondump <pid> <searchstr>", 0);
42   TPRINTF(maps_path, "/proc/%s/maps", argv[1])
43   char *maps = CHK_PTR(slurp_file(maps_path, NULL, JH_SLURP_NO_STAT), "unable to read /proc/$pid/maps", 1);
44
45   pid_t target = atoi(argv[1]);
46
47   size_t n_mappings = count_char_occurences(maps, '\n');
48   mappings = CHK_PTR(calloc(n_mappings+1, sizeof(struct range)), "memory allocation failed", 1);
49
50   // do magic
51   for (char *line = strtok(maps, "\n"); line != NULL; line = strtok(NULL, "\n")) {
52     struct range *mapping = &mappings[mappings_used++];
53     mapping->line = CHK_PTR(strdup(line), "memory allocation failed", 1);
54     if (sscanf(line, "%p-%p %c", &mapping->a, &mapping->b, &mapping->readable) != 3) xperror("sscanf failed", 0);
55     assert(mapping->readable == 'r' || mapping->readable == '-');
56   }
57
58   FOR_EACH_MAPPING {
59     //fprintf(stderr, "%s\n", mapping->line);
60     if (mapping->readable == '-') continue; /* guard page */
61     if (strchr(mapping->line, '/') == NULL && strstr(mapping->line, "[vvar]") != NULL) continue; /* vvar mapping is weird */
62     size_t len = mapping->b - mapping->a;
63     //printf("a=0x%llx b=0x%llx len=0x%llx\n", (unsigned long long)mapping->a, (unsigned long long)mapping->b, (unsigned long long)len);
64     char *copy = CHK_PTR(malloc(len), "malloc failed", 1);
65     ssize_t read_res;
66     if ((read_res=getmem(target, copy, mapping->a, len)) != len) {
67       if (read_res == 0) {
68         fputs("warning: some read failed\n", stderr);
69         continue;
70       }
71       if (read_res == -1) {
72         perror("warning: some read failed");
73         continue;
74       }
75     }
76     size_t pos = 0;
77     while (1) {
78       char *ptr = memmem(copy + pos, len - pos, argv[2], strlen(argv[2]));
79       if (ptr == NULL) break;
80       pos = ptr - copy;
81       printf("at %p in %s\n", mapping->a + pos, mapping->line);
82       pos++;
83     }
84     free(copy);
85   }
86
87   return 0;
88 }