1 /*
2 american fuzzy lop++ - afl-untracer skeleton example
3 ---------------------------------------------------
4
5 Written by Marc Heuse <[email protected]>
6
7 Copyright 2019-2024 AFLplusplus Project. All rights reserved.
8
9 Licensed under the Apache License, Version 2.0 (the "License");
10 you may not use this file except in compliance with the License.
11 You may obtain a copy of the License at:
12
13 http://www.apache.org/licenses/LICENSE-2.0
14
15
16 HOW-TO
17 ======
18
19 You only need to change the following:
20
21 1. decide if you want to receive data from stdin [DEFAULT] or file(name)
22 -> use_stdin = 0 if via file, and what the maximum input size is
23 2. dl load the library you want to fuzz, lookup the functions you need
24 and setup the calls to these
25 3. in the while loop you call the functions in the necessary order -
26 incl the cleanup. the cleanup is important!
27
28 Just look these steps up in the code, look for "// STEP x:"
29
30
31 */
32
33 #define __USE_GNU
34 #define _GNU_SOURCE
35
36 #ifdef __ANDROID__
37 #include "android-ashmem.h"
38 #endif
39 #include "config.h"
40 #include "types.h"
41 #include "debug.h"
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <signal.h>
46 #include <unistd.h>
47 #include <string.h>
48 #include <assert.h>
49 #include <stdint.h>
50 #include <errno.h>
51 #include <dlfcn.h>
52 #include <fcntl.h>
53 #include <pthread.h>
54
55 #include <sys/mman.h>
56 #if !defined(__HAIKU__)
57 #include <sys/shm.h>
58 #endif
59 #include <sys/wait.h>
60 #include <sys/types.h>
61
62 #if defined(__linux__)
63 #include <sys/personality.h>
64 #include <sys/ucontext.h>
65 #elif defined(__APPLE__) && defined(__LP64__)
66 #include <mach-o/dyld_images.h>
67 #elif defined(__FreeBSD__)
68 #include <sys/sysctl.h>
69 #include <sys/user.h>
70 #include <sys/procctl.h>
71 #elif defined(__HAIKU__)
72 #include <kernel/OS.h>
73 #include <kernel/image.h>
74 #else
75 #error "Unsupported platform"
76 #endif
77
78 #define MEMORY_MAP_DECREMENT 0x200000000000
79 #define MAX_LIB_COUNT 128
80
81 // STEP 1:
82
83 /* here you need to specify the parameter for the target function */
84 static void *(*o_function)(u8 *buf, int len);
85
86 /* use stdin (1) or a file on the commandline (0) */
87 static u32 use_stdin = 1;
88
89 /* This is were the testcase data is written into */
90 static u8 buf[10000]; // this is the maximum size for a test case! set it!
91
92 /* If you want to have debug output set this to 1, can also be set with
93 AFL_DEBUG */
94 static u32 debug = 0;
95
96 // END STEP 1
97
98 typedef struct library_list {
99
100 u8 *name;
101 u64 addr_start, addr_end;
102
103 } library_list_t;
104
105 #ifdef __ANDROID__
106 u32 __afl_map_size = MAP_SIZE;
107 u32 do_exit;
108 #else
109 __thread u32 __afl_map_size = MAP_SIZE;
110 __thread u32 do_exit;
111 #endif
112
113 static pid_t pid = 65537;
114 static pthread_t __afl_thread;
115 static u8 __afl_dummy[MAP_SIZE];
116 static u8 *__afl_area_ptr = __afl_dummy;
117 static u8 *inputfile; // this will point to argv[1]
118 static u32 len;
119
120 static library_list_t liblist[MAX_LIB_COUNT];
121 static u32 liblist_cnt;
122
123 static void sigtrap_handler(int signum, siginfo_t *si, void *context);
124 static void fuzz(void);
125
126 /* read the library information */
read_library_information(void)127 void read_library_information(void) {
128
129 #if defined(__linux__)
130 FILE *f;
131 u8 buf[1024], *b, *m, *e, *n;
132
133 if ((f = fopen("/proc/self/maps", "r")) == NULL)
134 FATAL("cannot open /proc/self/maps");
135
136 if (debug) fprintf(stderr, "Library list:\n");
137 while (fgets(buf, sizeof(buf), f)) {
138
139 if (strstr(buf, " r-x")) {
140
141 if (liblist_cnt >= MAX_LIB_COUNT) {
142
143 WARNF("too many libraries to old, maximum count of %d reached",
144 liblist_cnt);
145 return;
146
147 }
148
149 b = buf;
150 m = index(buf, '-');
151 e = index(buf, ' ');
152 if ((n = strrchr(buf, '/')) == NULL) n = strrchr(buf, ' ');
153 if (n &&
154 ((*n >= '0' && *n <= '9') || *n == '[' || *n == '{' || *n == '('))
155 n = NULL;
156 else
157 n++;
158 if (b && m && e && n && *n) {
159
160 *m++ = 0;
161 *e = 0;
162 if (n[strlen(n) - 1] == '\n') n[strlen(n) - 1] = 0;
163
164 liblist[liblist_cnt].name = (u8 *)strdup((char *)n);
165 liblist[liblist_cnt].addr_start = strtoull(b, NULL, 16);
166 liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16);
167 if (debug)
168 fprintf(
169 stderr, "%s:%llx (%llx-%llx)\n", liblist[liblist_cnt].name,
170 liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start,
171 liblist[liblist_cnt].addr_start,
172 liblist[liblist_cnt].addr_end - 1);
173 liblist_cnt++;
174
175 }
176
177 }
178
179 }
180
181 if (debug) fprintf(stderr, "\n");
182
183 #elif defined(__FreeBSD__)
184 int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()};
185 char *buf, *start, *end;
186 size_t miblen = sizeof(mib) / sizeof(mib[0]);
187 size_t len;
188
189 if (debug) fprintf(stderr, "Library list:\n");
190 if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) { return; }
191
192 len = len * 4 / 3;
193
194 buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
195 if (buf == MAP_FAILED) { return; }
196
197 if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) {
198
199 munmap(buf, len);
200 return;
201
202 }
203
204 start = buf;
205 end = buf + len;
206
207 while (start < end) {
208
209 struct kinfo_vmentry *region = (struct kinfo_vmentry *)start;
210 size_t size = region->kve_structsize;
211
212 if (size == 0) { break; }
213
214 if ((region->kve_protection & KVME_PROT_READ) &&
215 !(region->kve_protection & KVME_PROT_EXEC)) {
216
217 liblist[liblist_cnt].name =
218 region->kve_path[0] != '\0' ? (u8 *)strdup(region->kve_path) : 0;
219 liblist[liblist_cnt].addr_start = region->kve_start;
220 liblist[liblist_cnt].addr_end = region->kve_end;
221
222 if (debug) {
223
224 fprintf(stderr, "%s:%lx (%lx-%lx)\n", liblist[liblist_cnt].name,
225 (unsigned long)(liblist[liblist_cnt].addr_end -
226 liblist[liblist_cnt].addr_start),
227 (unsigned long)liblist[liblist_cnt].addr_start,
228 (unsigned long)(liblist[liblist_cnt].addr_end - 1));
229
230 }
231
232 liblist_cnt++;
233
234 }
235
236 start += size;
237
238 }
239
240 #elif defined(__HAIKU__)
241 image_info ii;
242 int32 c = 0;
243
244 while (get_next_image_info(0, &c, &ii) == B_OK) {
245
246 liblist[liblist_cnt].name = (u8 *)strdup(ii.name);
247 liblist[liblist_cnt].addr_start = (u64)ii.text;
248 liblist[liblist_cnt].addr_end = (u64)((char *)ii.text + ii.text_size);
249
250 if (debug) {
251
252 fprintf(stderr, "%s:%lx (%lx-%lx)\n", liblist[liblist_cnt].name,
253 (unsigned long)(liblist[liblist_cnt].addr_end -
254 liblist[liblist_cnt].addr_start),
255 (unsigned long)liblist[liblist_cnt].addr_start,
256 (unsigned long)(liblist[liblist_cnt].addr_end - 1));
257
258 }
259
260 liblist_cnt++;
261
262 }
263
264 #endif
265
266 }
267
find_library(char * name)268 library_list_t *find_library(char *name) {
269
270 #if defined(__linux__)
271 u32 i;
272
273 for (i = 0; i < liblist_cnt; i++)
274 if (strncmp(liblist[i].name, name, strlen(name)) == 0) return &liblist[i];
275 #elif defined(__APPLE__) && defined(__LP64__)
276 kern_return_t err;
277 static library_list_t lib;
278
279 // get the list of all loaded modules from dyld
280 // the task_info mach API will get the address of the dyld all_image_info
281 // struct for the given task from which we can get the names and load
282 // addresses of all modules
283 task_dyld_info_data_t task_dyld_info;
284 mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
285 err = task_info(mach_task_self(), TASK_DYLD_INFO,
286 (task_info_t)&task_dyld_info, &count);
287
288 const struct dyld_all_image_infos *all_image_infos =
289 (const struct dyld_all_image_infos *)task_dyld_info.all_image_info_addr;
290 const struct dyld_image_info *image_infos = all_image_infos->infoArray;
291
292 for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) {
293
294 const char *image_name = image_infos[i].imageFilePath;
295 mach_vm_address_t image_load_address =
296 (mach_vm_address_t)image_infos[i].imageLoadAddress;
297 if (strstr(image_name, name)) {
298
299 lib.name = name;
300 lib.addr_start = (u64)image_load_address;
301 lib.addr_end = 0;
302 return &lib;
303
304 }
305
306 }
307
308 #endif
309
310 return NULL;
311
312 }
313
314 /* for having an easy breakpoint location after loading the shared library */
315 // this seems to work for clang too. nice :) requires gcc 4.4+
316 #pragma GCC push_options
317 #pragma GCC optimize("O0")
breakpoint(void)318 void breakpoint(void) {
319
320 if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n");
321
322 }
323
324 #pragma GCC pop_options
325
326 /* Error reporting to forkserver controller */
327
send_forkserver_error(int error)328 void send_forkserver_error(int error) {
329
330 u32 status;
331 if (!error || error > 0xffff) return;
332 status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
333 if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
334
335 }
336
337 /* SHM setup. */
338
__afl_map_shm(void)339 static void __afl_map_shm(void) {
340
341 char *id_str = getenv(SHM_ENV_VAR);
342 char *ptr;
343
344 if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) {
345
346 u32 val = atoi(ptr);
347 if (val > 0) __afl_map_size = val;
348
349 }
350
351 if (__afl_map_size > MAP_SIZE) {
352
353 if (__afl_map_size > FS_OPT_MAX_MAPSIZE) {
354
355 fprintf(stderr,
356 "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to "
357 "be able to run this instrumented program!\n",
358 __afl_map_size);
359 if (id_str) {
360
361 send_forkserver_error(FS_ERROR_MAP_SIZE);
362 exit(-1);
363
364 }
365
366 } else {
367
368 fprintf(stderr,
369 "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to "
370 "be able to run this instrumented program!\n",
371 __afl_map_size);
372
373 }
374
375 }
376
377 if (id_str) {
378
379 #ifdef USEMMAP
380 const char *shm_file_path = id_str;
381 int shm_fd = -1;
382 unsigned char *shm_base = NULL;
383
384 /* create the shared memory segment as if it was a file */
385 shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
386 if (shm_fd == -1) {
387
388 fprintf(stderr, "shm_open() failed\n");
389 send_forkserver_error(FS_ERROR_SHM_OPEN);
390 exit(1);
391
392 }
393
394 /* map the shared memory segment to the address space of the process */
395 shm_base =
396 mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
397
398 if (shm_base == MAP_FAILED) {
399
400 close(shm_fd);
401 shm_fd = -1;
402
403 fprintf(stderr, "mmap() failed\n");
404 send_forkserver_error(FS_ERROR_MMAP);
405 exit(2);
406
407 }
408
409 __afl_area_ptr = shm_base;
410 #else
411 u32 shm_id = atoi(id_str);
412
413 __afl_area_ptr = shmat(shm_id, 0, 0);
414
415 #endif
416
417 if (__afl_area_ptr == (void *)-1) {
418
419 send_forkserver_error(FS_ERROR_SHMAT);
420 exit(1);
421
422 }
423
424 /* Write something into the bitmap so that the parent doesn't give up */
425
426 __afl_area_ptr[0] = 1;
427
428 }
429
430 }
431
432 /* Fork server logic. */
__afl_start_forkserver(void)433 inline static void __afl_start_forkserver(void) {
434
435 u8 tmp[4] = {0, 0, 0, 0};
436 u32 status = 0;
437
438 if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
439 status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
440 if (status) status |= (FS_OPT_ENABLED);
441 memcpy(tmp, &status, 4);
442
443 /* Phone home and tell the parent that we're OK. */
444 if (write(FORKSRV_FD + 1, tmp, 4) != 4) do_exit = 1;
445 // fprintf(stderr, "write0 %d\n", do_exit);
446
447 }
448
__afl_next_testcase(u8 * buf,u32 max_len)449 inline static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
450
451 s32 status;
452
453 /* Wait for parent by reading from the pipe. Abort if read fails. */
454 if (read(FORKSRV_FD, &status, 4) != 4) do_exit = 1;
455 // fprintf(stderr, "read %d\n", do_exit);
456
457 /* we have a testcase - read it if we read from stdin */
458 if (use_stdin) {
459
460 if ((status = read(0, buf, max_len)) <= 0) exit(-1);
461
462 } else
463
464 status = 1;
465 // fprintf(stderr, "stdin: %d %d\n", use_stdin, status);
466
467 /* report that we are starting the target */
468 if (write(FORKSRV_FD + 1, &pid, 4) != 4) do_exit = 1;
469 // fprintf(stderr, "write1 %d\n", do_exit);
470
471 __afl_area_ptr[0] = 1; // put something in the map
472
473 return status;
474
475 }
476
__afl_end_testcase(int status)477 inline static void __afl_end_testcase(int status) {
478
479 if (write(FORKSRV_FD + 1, &status, 4) != 4) do_exit = 1;
480 // fprintf(stderr, "write2 %d\n", do_exit);
481 if (do_exit) exit(0);
482
483 }
484
485 #ifdef __aarch64__
486 #define SHADOW(addr) \
487 ((uint64_t *)(((uintptr_t)addr & 0xfffffffffffffff8) - \
488 MEMORY_MAP_DECREMENT - \
489 ((uintptr_t)addr & 0x7) * 0x10000000000))
490 #else
491 #define SHADOW(addr) \
492 ((uint32_t *)(((uintptr_t)addr & 0xfffffffffffffffc) - \
493 MEMORY_MAP_DECREMENT - \
494 ((uintptr_t)addr & 0x3) * 0x10000000000))
495 #endif
496
setup_trap_instrumentation(void)497 void setup_trap_instrumentation(void) {
498
499 library_list_t *lib_base = NULL;
500 size_t lib_size = 0;
501 u8 *lib_addr;
502 char *line = NULL;
503 size_t nread, len = 0;
504 char *filename = getenv("AFL_UNTRACER_FILE");
505 if (!filename) filename = getenv("TRAPFUZZ_FILE");
506 if (!filename) FATAL("AFL_UNTRACER_FILE environment variable not set");
507
508 FILE *patches = fopen(filename, "r");
509 if (!patches) FATAL("Couldn't open AFL_UNTRACER_FILE file %s", filename);
510
511 // Index into the coverage bitmap for the current trap instruction.
512 #ifdef __aarch64__
513 uint64_t bitmap_index = 0;
514 #ifdef __APPLE__
515 pthread_jit_write_protect_np(0);
516 #endif
517 #else
518 uint32_t bitmap_index = 0;
519 #endif
520
521 #if defined(__FreeBSD__) && __FreeBSD_version >= 1301000
522 // We try to allow W/X pages despite kern.elf32/64.allow_wx system settings
523 int allow_wx = PROC_WX_MAPPINGS_PERMIT;
524 (void)procctl(P_PID, 0, PROC_WXMAP_CTL, &allow_wx);
525 #endif
526
527 while ((nread = getline(&line, &len, patches)) != -1) {
528
529 char *end = line + len;
530
531 char *col = strchr(line, ':');
532 if (col) {
533
534 // It's a library:size pair
535 *col++ = 0;
536
537 lib_base = find_library(line);
538 if (!lib_base) FATAL("Library %s does not appear to be loaded", line);
539
540 // we ignore the defined lib_size
541 lib_size = strtoul(col, NULL, 16);
542 #if (__linux__)
543 if (lib_size < lib_base->addr_end - lib_base->addr_start)
544 lib_size = lib_base->addr_end - lib_base->addr_start;
545 #endif
546 if (lib_size % 0x1000 != 0)
547 WARNF("Invalid library size 0x%zx. Must be multiple of 0x1000",
548 lib_size);
549
550 lib_addr = (u8 *)lib_base->addr_start;
551 // Make library code writable.
552 if (mprotect((void *)lib_addr, lib_size,
553 PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
554 FATAL("Failed to mprotect library %s writable", line);
555
556 // Create shadow memory.
557 #ifdef __aarch64__
558 for (int i = 0; i < 8; i++) {
559
560 #else
561 for (int i = 0; i < 4; i++) {
562
563 #endif
564
565 void *shadow_addr = SHADOW(lib_addr + i);
566 void *shadow = mmap(shadow_addr, lib_size, PROT_READ | PROT_WRITE,
567 MAP_PRIVATE | MAP_ANON | MAP_FIXED, 0, 0);
568 if (debug)
569 fprintf(stderr, "Shadow: %s %d = %p-%p for %p\n", line, i, shadow,
570 shadow + lib_size - 1, lib_addr);
571 if (shadow == MAP_FAILED) FATAL("Failed to mmap shadow memory");
572
573 }
574
575 // Done, continue with next line.
576 continue;
577
578 }
579
580 // It's an offset, parse it and do the patching.
581 unsigned long offset = strtoul(line, NULL, 16);
582
583 if (offset > lib_size)
584 FATAL("Invalid offset: 0x%lx. Current library is 0x%zx bytes large",
585 offset, lib_size);
586
587 if (bitmap_index >= __afl_map_size)
588 FATAL("Too many basic blocks to instrument");
589
590 #ifdef __arch64__
591 uint64_t
592 #else
593 uint32_t
594 #endif
595 *shadow = SHADOW(lib_addr + offset);
596 if (*shadow != 0) continue; // skip duplicates
597
598 // Make lookup entry in shadow memory.
599
600 #if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__) || \
601 defined(__i386__))
602
603 // this is for Intel x64
604
605 uint8_t orig_byte = lib_addr[offset];
606 *shadow = (bitmap_index << 8) | orig_byte;
607 lib_addr[offset] = 0xcc; // replace instruction with debug trap
608 if (debug)
609 fprintf(stderr,
610 "Patch entry: %p[%lx] = %p = %02x -> SHADOW(%p) #%d -> %08x\n",
611 lib_addr, offset, lib_addr + offset, orig_byte, shadow,
612 bitmap_index, *shadow);
613
614 #elif defined(__aarch64__)
615
616 // this is for aarch64
617
618 uint32_t *patch_bytes = (uint32_t *)(lib_addr + offset);
619 uint32_t orig_bytes = *patch_bytes;
620 *shadow = (bitmap_index << 32) | orig_bytes;
621 *patch_bytes = 0xd4200000; // replace instruction with debug trap
622 if (debug)
623 fprintf(stderr,
624 "Patch entry: %p[%lx] = %p = %02x -> SHADOW(%p) #%d -> %016x\n",
625 lib_addr, offset, lib_addr + offset, orig_bytes, shadow,
626 bitmap_index, *shadow);
627
628 #else
629 // this will be ARM and AARCH64
630 // for ARM we will need to identify if the code is in thumb or ARM
631 #error "non x86_64/aarch64 not supported yet"
632 //__arm__:
633 // linux thumb: 0xde01
634 // linux arm: 0xe7f001f0
635 //__aarch64__:
636 // linux aarch64: 0xd4200000
637 #endif
638
639 bitmap_index++;
640
641 }
642
643 free(line);
644 fclose(patches);
645
646 // Install signal handler for SIGTRAP.
647 struct sigaction s;
648 s.sa_flags = SA_SIGINFO;
649 s.sa_sigaction = sigtrap_handler;
650 sigemptyset(&s.sa_mask);
651 sigaction(SIGTRAP, &s, 0);
652
653 if (debug) fprintf(stderr, "Patched %u locations.\n", bitmap_index);
654 __afl_map_size = bitmap_index;
655 if (__afl_map_size % 8) __afl_map_size = (((__afl_map_size + 7) >> 3) << 3);
656
657 }
658
659 /* the signal handler for the traps / debugging interrupts
660 No debug output here because this would cost speed */
661 static void sigtrap_handler(int signum, siginfo_t *si, void *context) {
662
663 uint64_t addr;
664 // Must re-execute the instruction, so decrement PC by one instruction.
665 ucontext_t *ctx = (ucontext_t *)context;
666 #if defined(__APPLE__) && defined(__LP64__)
667 #if defined(__x86_64__)
668 ctx->uc_mcontext->__ss.__rip -= 1;
669 addr = ctx->uc_mcontext->__ss.__rip;
670 #else
671 ctx->uc_mcontext->__ss.__pc -= 4;
672 addr = ctx->uc_mcontext->__ss.__pc;
673 #endif
674 #elif defined(__linux__)
675 #if defined(__x86_64__) || defined(__i386__)
676 ctx->uc_mcontext.gregs[REG_RIP] -= 1;
677 addr = ctx->uc_mcontext.gregs[REG_RIP];
678 #elif defined(__aarch64__)
679 ctx->uc_mcontext.pc -= 4;
680 addr = ctx->uc_mcontext.pc;
681 #else
682 #error "Unsupported processor"
683 #endif
684 #elif defined(__FreeBSD__) && defined(__LP64__)
685 ctx->uc_mcontext.mc_rip -= 1;
686 addr = ctx->uc_mcontext.mc_rip;
687 #elif defined(__HAIKU__) && defined(__x86_64__)
688 ctx->uc_mcontext.rip -= 1;
689 addr = ctx->uc_mcontext.rip;
690 #else
691 #error "Unsupported platform"
692 #endif
693
694 // fprintf(stderr, "TRAP at context addr = %lx, fault addr = %lx\n", addr,
695 // si->si_addr);
696
697 // If the trap didn't come from our instrumentation, then we probably will
698 // just segfault here
699 uint8_t *faultaddr;
700 if (unlikely(si->si_addr))
701 faultaddr = (u8 *)si->si_addr - 1;
702 else
703 faultaddr = (u8 *)addr;
704 // if (debug) fprintf(stderr, "Shadow location: %p\n", SHADOW(faultaddr));
705 uint32_t shadow = *SHADOW(faultaddr);
706 uint8_t orig_byte = shadow & 0xff;
707 uint32_t index = shadow >> 8;
708
709 // if (debug) fprintf(stderr, "shadow data: %x, orig_byte %02x, index %d\n",
710 // shadow, orig_byte, index);
711
712 // Index zero is invalid so that it is still possible to catch actual trap
713 // instructions in instrumented libraries.
714 if (unlikely(index == 0)) abort();
715
716 // Restore original instruction
717 *faultaddr = orig_byte;
718
719 __afl_area_ptr[index] = 128;
720
721 }
722
723 /* the MAIN function */
724 int main(int argc, char *argv[]) {
725
726 #if defined(__linux__)
727 (void)personality(ADDR_NO_RANDOMIZE); // disable ASLR
728 #elif defined(__FreeBSD__) && __FreeBSD_version >= 1200000
729 int no_randomize = PROC_ASLR_FORCE_DISABLE;
730 (void)procctl(P_PID, 0, PROC_ASLR_CTL, &no_randomize);
731 #endif
732
733 pid = getpid();
734 if (getenv("AFL_DEBUG")) debug = 1;
735
736 /* by default we use stdin, but also a filename can be passed, in this
737 case the input is argv[1] and we have to disable stdin */
738 if (argc > 1) {
739
740 use_stdin = 0;
741 inputfile = (u8 *)argv[1];
742
743 }
744
745 // STEP 2: load the library you want to fuzz and lookup the functions,
746 // inclusive of the cleanup functions
747 // NOTE: above the main() you have to define the functions!
748
749 void *dl = dlopen("./libtestinstr.so", RTLD_LAZY);
750 if (!dl) FATAL("could not find target library");
751 o_function = dlsym(dl, "testinstr");
752 if (!o_function) FATAL("could not resolve target function from library");
753 if (debug) fprintf(stderr, "Function address: %p\n", o_function);
754
755 // END STEP 2
756
757 /* setup instrumentation, shared memory and forkserver */
758 breakpoint();
759 read_library_information();
760 setup_trap_instrumentation();
761 __afl_map_shm();
762 __afl_start_forkserver();
763
764 while (1) {
765
766 // instead of fork() we could also use the snapshot lkm or do our own mini
767 // snapshot feature like in https://github.com/marcinguy/fuzzer
768 // -> snapshot.c
769 if ((pid = fork()) == -1) PFATAL("fork failed");
770
771 if (pid) {
772
773 u32 status;
774 if (waitpid(pid, (int *)&status, 0) < 0) exit(1);
775 /* report the test case is done and wait for the next */
776 __afl_end_testcase(status);
777
778 } else {
779
780 pid = getpid();
781 while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) {
782
783 // in this function the fuzz magic happens, this is STEP 3
784 fuzz();
785
786 // we can use _exit which is faster because our target library
787 // was loaded via dlopen and therefore cannot have deconstructors
788 // registered.
789 _exit(0);
790
791 }
792
793 }
794
795 }
796
797 return 0;
798
799 }
800
801 #ifndef _DEBUG
802 inline
803 #endif
804 static void
805 fuzz(void) {
806
807 // STEP 3: call the function to fuzz, also the functions you might
808 // need to call to prepare the function and - important! -
809 // to clean everything up
810
811 // in this example we use the input file, not stdin!
812 (*o_function)(buf, len);
813
814 // normally you also need to cleanup
815 //(*o_LibFree)(foo);
816
817 // END STEP 3
818
819 }
820
821