1 /*
2
3 american fuzzy lop - extract tokens passed to strcmp / memcmp
4 -------------------------------------------------------------
5
6 Written and maintained by Michal Zalewski <lcamtuf@google.com>
7
8 Copyright 2016 Google Inc. All rights reserved.
9
10 Licensed under the Apache License, Version 2.0 (the "License");
11 you may not use this file except in compliance with the License.
12 You may obtain a copy of the License at:
13
14 http://www.apache.org/licenses/LICENSE-2.0
15
16 This Linux-only companion library allows you to instrument strcmp(),
17 memcmp(), and related functions to automatically extract tokens.
18 See README.tokencap for more info.
19
20 */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <ctype.h>
25
26 #include "../types.h"
27 #include "../config.h"
28
29 #ifndef __linux__
30 # error "Sorry, this library is Linux-specific for now!"
31 #endif /* !__linux__ */
32
33
34 /* Mapping data and such */
35
36 #define MAX_MAPPINGS 1024
37
38 static struct mapping {
39 void *st, *en;
40 } __tokencap_ro[MAX_MAPPINGS];
41
42 static u32 __tokencap_ro_cnt;
43 static u8 __tokencap_ro_loaded;
44 static FILE* __tokencap_out_file;
45
46
47 /* Identify read-only regions in memory. Only parameters that fall into these
48 ranges are worth dumping when passed to strcmp() and so on. Read-write
49 regions are far more likely to contain user input instead. */
50
__tokencap_load_mappings(void)51 static void __tokencap_load_mappings(void) {
52
53 u8 buf[MAX_LINE];
54 FILE* f = fopen("/proc/self/maps", "r");
55
56 __tokencap_ro_loaded = 1;
57
58 if (!f) return;
59
60 while (fgets(buf, MAX_LINE, f)) {
61
62 u8 rf, wf;
63 void* st, *en;
64
65 if (sscanf(buf, "%p-%p %c%c", &st, &en, &rf, &wf) != 4) continue;
66 if (wf == 'w' || rf != 'r') continue;
67
68 __tokencap_ro[__tokencap_ro_cnt].st = (void*)st;
69 __tokencap_ro[__tokencap_ro_cnt].en = (void*)en;
70
71 if (++__tokencap_ro_cnt == MAX_MAPPINGS) break;
72
73 }
74
75 fclose(f);
76
77 }
78
79
80 /* Check an address against the list of read-only mappings. */
81
__tokencap_is_ro(const void * ptr)82 static u8 __tokencap_is_ro(const void* ptr) {
83
84 u32 i;
85
86 if (!__tokencap_ro_loaded) __tokencap_load_mappings();
87
88 for (i = 0; i < __tokencap_ro_cnt; i++)
89 if (ptr >= __tokencap_ro[i].st && ptr <= __tokencap_ro[i].en) return 1;
90
91 return 0;
92
93 }
94
95
96 /* Dump an interesting token to output file, quoting and escaping it
97 properly. */
98
__tokencap_dump(const u8 * ptr,size_t len,u8 is_text)99 static void __tokencap_dump(const u8* ptr, size_t len, u8 is_text) {
100
101 u8 buf[MAX_AUTO_EXTRA * 4 + 1];
102 u32 i;
103 u32 pos = 0;
104
105 if (len < MIN_AUTO_EXTRA || len > MAX_AUTO_EXTRA || !__tokencap_out_file)
106 return;
107
108 for (i = 0; i < len; i++) {
109
110 if (is_text && !ptr[i]) break;
111
112 switch (ptr[i]) {
113
114 case 0 ... 31:
115 case 127 ... 255:
116 case '\"':
117 case '\\':
118
119 sprintf(buf + pos, "\\x%02x", ptr[i]);
120 pos += 4;
121 break;
122
123 default:
124
125 buf[pos++] = ptr[i];
126
127 }
128
129 }
130
131 buf[pos] = 0;
132
133 fprintf(__tokencap_out_file, "\"%s\"\n", buf);
134
135 }
136
137
138 /* Replacements for strcmp(), memcmp(), and so on. Note that these will be used
139 only if the target is compiled with -fno-builtins and linked dynamically. */
140
141 #undef strcmp
142
strcmp(const char * str1,const char * str2)143 int strcmp(const char* str1, const char* str2) {
144
145 if (__tokencap_is_ro(str1)) __tokencap_dump(str1, strlen(str1), 1);
146 if (__tokencap_is_ro(str2)) __tokencap_dump(str2, strlen(str2), 1);
147
148 while (1) {
149
150 unsigned char c1 = *str1, c2 = *str2;
151
152 if (c1 != c2) return (c1 > c2) ? 1 : -1;
153 if (!c1) return 0;
154 str1++; str2++;
155
156 }
157
158 }
159
160
161 #undef strncmp
162
strncmp(const char * str1,const char * str2,size_t len)163 int strncmp(const char* str1, const char* str2, size_t len) {
164
165 if (__tokencap_is_ro(str1)) __tokencap_dump(str1, len, 1);
166 if (__tokencap_is_ro(str2)) __tokencap_dump(str2, len, 1);
167
168 while (len--) {
169
170 unsigned char c1 = *str1, c2 = *str2;
171
172 if (!c1) return 0;
173 if (c1 != c2) return (c1 > c2) ? 1 : -1;
174 str1++; str2++;
175
176 }
177
178 return 0;
179
180 }
181
182
183 #undef strcasecmp
184
strcasecmp(const char * str1,const char * str2)185 int strcasecmp(const char* str1, const char* str2) {
186
187 if (__tokencap_is_ro(str1)) __tokencap_dump(str1, strlen(str1), 1);
188 if (__tokencap_is_ro(str2)) __tokencap_dump(str2, strlen(str2), 1);
189
190 while (1) {
191
192 unsigned char c1 = tolower(*str1), c2 = tolower(*str2);
193
194 if (c1 != c2) return (c1 > c2) ? 1 : -1;
195 if (!c1) return 0;
196 str1++; str2++;
197
198 }
199
200 }
201
202
203 #undef strncasecmp
204
strncasecmp(const char * str1,const char * str2,size_t len)205 int strncasecmp(const char* str1, const char* str2, size_t len) {
206
207 if (__tokencap_is_ro(str1)) __tokencap_dump(str1, len, 1);
208 if (__tokencap_is_ro(str2)) __tokencap_dump(str2, len, 1);
209
210 while (len--) {
211
212 unsigned char c1 = tolower(*str1), c2 = tolower(*str2);
213
214 if (!c1) return 0;
215 if (c1 != c2) return (c1 > c2) ? 1 : -1;
216 str1++; str2++;
217
218 }
219
220 return 0;
221
222 }
223
224
225 #undef memcmp
226
memcmp(const void * mem1,const void * mem2,size_t len)227 int memcmp(const void* mem1, const void* mem2, size_t len) {
228
229 if (__tokencap_is_ro(mem1)) __tokencap_dump(mem1, len, 0);
230 if (__tokencap_is_ro(mem2)) __tokencap_dump(mem2, len, 0);
231
232 while (len--) {
233
234 unsigned char c1 = *(const char*)mem1, c2 = *(const char*)mem2;
235 if (c1 != c2) return (c1 > c2) ? 1 : -1;
236 mem1++; mem2++;
237
238 }
239
240 return 0;
241
242 }
243
244
245 #undef strstr
246
strstr(const char * haystack,const char * needle)247 char* strstr(const char* haystack, const char* needle) {
248
249 if (__tokencap_is_ro(haystack))
250 __tokencap_dump(haystack, strlen(haystack), 1);
251
252 if (__tokencap_is_ro(needle))
253 __tokencap_dump(needle, strlen(needle), 1);
254
255 do {
256 const char* n = needle;
257 const char* h = haystack;
258
259 while(*n && *h && *n == *h) n++, h++;
260
261 if(!*n) return (char*)haystack;
262
263 } while (*(haystack++));
264
265 return 0;
266
267 }
268
269
270 #undef strcasestr
271
strcasestr(const char * haystack,const char * needle)272 char* strcasestr(const char* haystack, const char* needle) {
273
274 if (__tokencap_is_ro(haystack))
275 __tokencap_dump(haystack, strlen(haystack), 1);
276
277 if (__tokencap_is_ro(needle))
278 __tokencap_dump(needle, strlen(needle), 1);
279
280 do {
281
282 const char* n = needle;
283 const char* h = haystack;
284
285 while(*n && *h && tolower(*n) == tolower(*h)) n++, h++;
286
287 if(!*n) return (char*)haystack;
288
289 } while(*(haystack++));
290
291 return 0;
292
293 }
294
295
296 /* Init code to open the output file (or default to stderr). */
297
__tokencap_init(void)298 __attribute__((constructor)) void __tokencap_init(void) {
299
300 u8* fn = getenv("AFL_TOKEN_FILE");
301 if (fn) __tokencap_out_file = fopen(fn, "a");
302 if (!__tokencap_out_file) __tokencap_out_file = stderr;
303
304 }
305
306