1 /*
2 american fuzzy lop++ - file format analyzer
3 -------------------------------------------
4
5 Originally written by Michal Zalewski
6
7 Now maintained by Marc Heuse <mh@mh-sec.de>,
8 Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
9 Andrea Fioraldi <andreafioraldi@gmail.com>
10
11 Copyright 2016, 2017 Google Inc. All rights reserved.
12 Copyright 2019-2022 AFLplusplus Project. All rights reserved.
13
14 Licensed under the Apache License, Version 2.0 (the "License");
15 you may not use this file except in compliance with the License.
16 You may obtain a copy of the License at:
17
18 https://www.apache.org/licenses/LICENSE-2.0
19
20 A nifty utility that grabs an input file and takes a stab at explaining
21 its structure by observing how changes to it affect the execution path.
22
23 If the output scrolls past the edge of the screen, pipe it to 'less -r'.
24
25 */
26
27 #define AFL_MAIN
28
29 #include "config.h"
30 #include "types.h"
31 #include "debug.h"
32 #include "alloc-inl.h"
33 #include "hash.h"
34 #include "sharedmem.h"
35 #include "common.h"
36 #include "forkserver.h"
37
38 #include <stdio.h>
39 #include <unistd.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <time.h>
43 #include <errno.h>
44 #include <signal.h>
45 #include <dirent.h>
46 #include <fcntl.h>
47 #include <ctype.h>
48
49 #include <sys/wait.h>
50 #include <sys/time.h>
51 #ifndef USEMMAP
52 #include <sys/shm.h>
53 #endif
54 #include <sys/stat.h>
55 #include <sys/types.h>
56 #include <sys/resource.h>
57
58 static u8 *in_file; /* Analyzer input test case */
59
60 static u8 *in_data; /* Input data for analysis */
61
62 static u32 in_len, /* Input data length */
63 total_execs, /* Total number of execs */
64 exec_hangs, /* Total number of hangs */
65 exec_tmout = EXEC_TIMEOUT; /* Exec timeout (ms) */
66
67 static u64 orig_cksum; /* Original checksum */
68
69 static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
70
71 static bool edges_only, /* Ignore hit counts? */
72 use_hex_offsets, /* Show hex offsets? */
73 use_stdin = true; /* Use stdin for program input? */
74
75 static volatile u8 stop_soon; /* Ctrl-C pressed? */
76
77 static u8 *target_path;
78 static u8 frida_mode;
79 static u8 qemu_mode;
80 static u8 cs_mode;
81 static u32 map_size = MAP_SIZE;
82
83 static afl_forkserver_t fsrv = {0}; /* The forkserver */
84
85 /* Constants used for describing byte behavior. */
86
87 #define RESP_NONE 0x00 /* Changing byte is a no-op. */
88 #define RESP_MINOR 0x01 /* Some changes have no effect. */
89 #define RESP_VARIABLE 0x02 /* Changes produce variable paths. */
90 #define RESP_FIXED 0x03 /* Changes produce fixed patterns. */
91
92 #define RESP_LEN 0x04 /* Potential length field */
93 #define RESP_CKSUM 0x05 /* Potential checksum */
94 #define RESP_SUSPECT 0x06 /* Potential "suspect" blob */
95
96 /* Classify tuple counts. This is a slow & naive version, but good enough here.
97 */
98
99 static u8 count_class_lookup[256] = {
100
101 [0] = 0,
102 [1] = 1,
103 [2] = 2,
104 [3] = 4,
105 [4 ... 7] = 8,
106 [8 ... 15] = 16,
107 [16 ... 31] = 32,
108 [32 ... 127] = 64,
109 [128 ... 255] = 128
110
111 };
112
kill_child()113 static void kill_child() {
114
115 if (fsrv.child_pid > 0) {
116
117 kill(fsrv.child_pid, fsrv.kill_signal);
118 fsrv.child_pid = -1;
119
120 }
121
122 }
123
classify_counts(u8 * mem)124 static void classify_counts(u8 *mem) {
125
126 u32 i = map_size;
127
128 if (edges_only) {
129
130 while (i--) {
131
132 if (*mem) { *mem = 1; }
133 mem++;
134
135 }
136
137 } else {
138
139 while (i--) {
140
141 *mem = count_class_lookup[*mem];
142 mem++;
143
144 }
145
146 }
147
148 }
149
150 /* See if any bytes are set in the bitmap. */
151
anything_set(void)152 static inline u8 anything_set(void) {
153
154 u32 *ptr = (u32 *)fsrv.trace_bits;
155 u32 i = (map_size >> 2);
156
157 while (i--) {
158
159 if (*(ptr++)) { return 1; }
160
161 }
162
163 return 0;
164
165 }
166
167 /* Get rid of temp files (atexit handler). */
168
at_exit_handler(void)169 static void at_exit_handler(void) {
170
171 unlink(fsrv.out_file); /* Ignore errors */
172
173 }
174
175 /* Read initial file. */
176
read_initial_file(void)177 static void read_initial_file(void) {
178
179 struct stat st;
180 s32 fd = open(in_file, O_RDONLY);
181
182 if (fd < 0) { PFATAL("Unable to open '%s'", in_file); }
183
184 if (fstat(fd, &st) || !st.st_size) { FATAL("Zero-sized input file."); }
185
186 if (st.st_size >= TMIN_MAX_FILE) {
187
188 FATAL("Input file is too large (%ld MB max)", TMIN_MAX_FILE / 1024 / 1024);
189
190 }
191
192 in_len = st.st_size;
193 in_data = ck_alloc_nozero(in_len);
194
195 ck_read(fd, in_data, in_len, in_file);
196
197 close(fd);
198
199 OKF("Read %u byte%s from '%s'.", in_len, in_len == 1 ? "" : "s", in_file);
200
201 }
202
203 /* Execute target application. Returns exec checksum, or 0 if program
204 times out. */
205
analyze_run_target(u8 * mem,u32 len,u8 first_run)206 static u32 analyze_run_target(u8 *mem, u32 len, u8 first_run) {
207
208 afl_fsrv_write_to_testcase(&fsrv, mem, len);
209 fsrv_run_result_t ret = afl_fsrv_run_target(&fsrv, exec_tmout, &stop_soon);
210
211 if (ret == FSRV_RUN_ERROR) {
212
213 FATAL("Error in forkserver");
214
215 } else if (ret == FSRV_RUN_NOINST) {
216
217 FATAL("Target not instrumented");
218
219 } else if (ret == FSRV_RUN_NOBITS) {
220
221 FATAL("Failed to run target");
222
223 }
224
225 classify_counts(fsrv.trace_bits);
226 total_execs++;
227
228 if (stop_soon) {
229
230 SAYF(cRST cLRD "\n+++ Analysis aborted by user +++\n" cRST);
231 exit(1);
232
233 }
234
235 /* Always discard inputs that time out. */
236
237 if (fsrv.last_run_timed_out) {
238
239 exec_hangs++;
240 return 0;
241
242 }
243
244 u64 cksum = hash64(fsrv.trace_bits, fsrv.map_size, HASH_CONST);
245
246 if (ret == FSRV_RUN_CRASH) {
247
248 /* We don't actually care if the target is crashing or not,
249 except that when it does, the checksum should be different. */
250
251 cksum ^= 0xffffffff;
252
253 }
254
255 if (first_run) { orig_cksum = cksum; }
256
257 return cksum;
258
259 }
260
261 #ifdef USE_COLOR
262
263 /* Helper function to display a human-readable character. */
264
show_char(u8 val)265 static void show_char(u8 val) {
266
267 switch (val) {
268
269 case 0 ... 32:
270 case 127 ... 255:
271 SAYF("#%02x", val);
272 break;
273
274 default:
275 SAYF(" %c ", val);
276
277 }
278
279 }
280
281 /* Show the legend */
282
show_legend(void)283 static void show_legend(void) {
284
285 SAYF(" " cLGR bgGRA " 01 " cRST " - no-op block " cBLK bgLGN
286 " 01 " cRST
287 " - suspected length field\n"
288 " " cBRI bgGRA " 01 " cRST " - superficial content " cBLK bgYEL
289 " 01 " cRST
290 " - suspected cksum or magic int\n"
291 " " cBLK bgCYA " 01 " cRST " - critical stream " cBLK bgLRD
292 " 01 " cRST
293 " - suspected checksummed block\n"
294 " " cBLK bgMGN " 01 " cRST " - \"magic value\" section\n\n");
295
296 }
297
298 #endif /* USE_COLOR */
299
300 /* Interpret and report a pattern in the input file. */
301
dump_hex(u32 len,u8 * b_data)302 static void dump_hex(u32 len, u8 *b_data) {
303
304 u32 i;
305
306 for (i = 0; i < len; i++) {
307
308 #ifdef USE_COLOR
309 u32 rlen = 1, off;
310 #else
311 u32 rlen = 1;
312 #endif /* ^USE_COLOR */
313
314 u8 rtype = b_data[i] & 0x0f;
315
316 /* Look ahead to determine the length of run. */
317
318 while (i + rlen < len && (b_data[i] >> 7) == (b_data[i + rlen] >> 7)) {
319
320 if (rtype < (b_data[i + rlen] & 0x0f)) {
321
322 rtype = b_data[i + rlen] & 0x0f;
323
324 }
325
326 rlen++;
327
328 }
329
330 /* Try to do some further classification based on length & value. */
331
332 if (rtype == RESP_FIXED) {
333
334 switch (rlen) {
335
336 case 2: {
337
338 u16 val = *(u16 *)(in_data + i);
339
340 /* Small integers may be length fields. */
341
342 if (val && (val <= in_len || SWAP16(val) <= in_len)) {
343
344 rtype = RESP_LEN;
345 break;
346
347 }
348
349 /* Uniform integers may be checksums. */
350
351 if (val && abs(in_data[i] - in_data[i + 1]) > 32) {
352
353 rtype = RESP_CKSUM;
354 break;
355
356 }
357
358 break;
359
360 }
361
362 case 4: {
363
364 u32 val = *(u32 *)(in_data + i);
365
366 /* Small integers may be length fields. */
367
368 if (val && (val <= in_len || SWAP32(val) <= in_len)) {
369
370 rtype = RESP_LEN;
371 break;
372
373 }
374
375 /* Uniform integers may be checksums. */
376
377 if (val && (in_data[i] >> 7 != in_data[i + 1] >> 7 ||
378 in_data[i] >> 7 != in_data[i + 2] >> 7 ||
379 in_data[i] >> 7 != in_data[i + 3] >> 7)) {
380
381 rtype = RESP_CKSUM;
382 break;
383
384 }
385
386 break;
387
388 }
389
390 case 1:
391 case 3:
392 case 5 ... MAX_AUTO_EXTRA - 1:
393 break;
394
395 default:
396 rtype = RESP_SUSPECT;
397
398 }
399
400 }
401
402 /* Print out the entire run. */
403
404 #ifdef USE_COLOR
405
406 for (off = 0; off < rlen; off++) {
407
408 /* Every 16 digits, display offset. */
409
410 if (!((i + off) % 16)) {
411
412 if (off) { SAYF(cRST cLCY ">"); }
413
414 if (use_hex_offsets) {
415
416 SAYF(cRST cGRA "%s[%06x] " cRST, (i + off) ? "\n" : "", i + off);
417
418 } else {
419
420 SAYF(cRST cGRA "%s[%06u] " cRST, (i + off) ? "\n" : "", i + off);
421
422 }
423
424 }
425
426 switch (rtype) {
427
428 case RESP_NONE:
429 SAYF(cLGR bgGRA);
430 break;
431 case RESP_MINOR:
432 SAYF(cBRI bgGRA);
433 break;
434 case RESP_VARIABLE:
435 SAYF(cBLK bgCYA);
436 break;
437 case RESP_FIXED:
438 SAYF(cBLK bgMGN);
439 break;
440 case RESP_LEN:
441 SAYF(cBLK bgLGN);
442 break;
443 case RESP_CKSUM:
444 SAYF(cBLK bgYEL);
445 break;
446 case RESP_SUSPECT:
447 SAYF(cBLK bgLRD);
448 break;
449
450 }
451
452 show_char(in_data[i + off]);
453
454 if (off != rlen - 1 && (i + off + 1) % 16) {
455
456 SAYF(" ");
457
458 } else {
459
460 SAYF(cRST " ");
461
462 }
463
464 }
465
466 #else
467
468 if (use_hex_offsets)
469 SAYF(" Offset %x, length %u: ", i, rlen);
470 else
471 SAYF(" Offset %u, length %u: ", i, rlen);
472
473 switch (rtype) {
474
475 case RESP_NONE:
476 SAYF("no-op block\n");
477 break;
478 case RESP_MINOR:
479 SAYF("superficial content\n");
480 break;
481 case RESP_VARIABLE:
482 SAYF("critical stream\n");
483 break;
484 case RESP_FIXED:
485 SAYF("\"magic value\" section\n");
486 break;
487 case RESP_LEN:
488 SAYF("suspected length field\n");
489 break;
490 case RESP_CKSUM:
491 SAYF("suspected cksum or magic int\n");
492 break;
493 case RESP_SUSPECT:
494 SAYF("suspected checksummed block\n");
495 break;
496
497 }
498
499 #endif /* ^USE_COLOR */
500
501 i += rlen - 1;
502
503 }
504
505 #ifdef USE_COLOR
506 SAYF(cRST "\n");
507 #endif /* USE_COLOR */
508
509 }
510
511 /* Actually analyze! */
512
analyze()513 static void analyze() {
514
515 u32 i;
516 u32 boring_len = 0, prev_xff = 0, prev_x01 = 0, prev_s10 = 0, prev_a10 = 0;
517
518 u8 *b_data = ck_alloc(in_len + 1);
519 u8 seq_byte = 0;
520
521 b_data[in_len] = 0xff; /* Intentional terminator. */
522
523 ACTF("Analyzing input file (this may take a while)...\n");
524
525 #ifdef USE_COLOR
526 show_legend();
527 #endif /* USE_COLOR */
528
529 for (i = 0; i < in_len; i++) {
530
531 u32 xor_ff, xor_01, sub_10, add_10;
532 u8 xff_orig, x01_orig, s10_orig, a10_orig;
533
534 /* Perform walking byte adjustments across the file. We perform four
535 operations designed to elicit some response from the underlying
536 code. */
537
538 in_data[i] ^= 0xff;
539 xor_ff = analyze_run_target(in_data, in_len, 0);
540
541 in_data[i] ^= 0xfe;
542 xor_01 = analyze_run_target(in_data, in_len, 0);
543
544 in_data[i] = (in_data[i] ^ 0x01) - 0x10;
545 sub_10 = analyze_run_target(in_data, in_len, 0);
546
547 in_data[i] += 0x20;
548 add_10 = analyze_run_target(in_data, in_len, 0);
549 in_data[i] -= 0x10;
550
551 /* Classify current behavior. */
552
553 xff_orig = (xor_ff == orig_cksum);
554 x01_orig = (xor_01 == orig_cksum);
555 s10_orig = (sub_10 == orig_cksum);
556 a10_orig = (add_10 == orig_cksum);
557
558 if (xff_orig && x01_orig && s10_orig && a10_orig) {
559
560 b_data[i] = RESP_NONE;
561 boring_len++;
562
563 } else if (xff_orig || x01_orig || s10_orig || a10_orig) {
564
565 b_data[i] = RESP_MINOR;
566 boring_len++;
567
568 } else if (xor_ff == xor_01 && xor_ff == sub_10 && xor_ff == add_10) {
569
570 b_data[i] = RESP_FIXED;
571
572 } else {
573
574 b_data[i] = RESP_VARIABLE;
575
576 }
577
578 /* When all checksums change, flip most significant bit of b_data. */
579
580 if (prev_xff != xor_ff && prev_x01 != xor_01 && prev_s10 != sub_10 &&
581 prev_a10 != add_10) {
582
583 seq_byte ^= 0x80;
584
585 }
586
587 b_data[i] |= seq_byte;
588
589 prev_xff = xor_ff;
590 prev_x01 = xor_01;
591 prev_s10 = sub_10;
592 prev_a10 = add_10;
593
594 }
595
596 dump_hex(in_len, b_data);
597
598 SAYF("\n");
599
600 OKF("Analysis complete. Interesting bits: %0.02f%% of the input file.",
601 100.0 - ((double)boring_len * 100) / in_len);
602
603 if (exec_hangs) {
604
605 WARNF(cLRD "Encountered %u timeouts - results may be skewed." cRST,
606 exec_hangs);
607
608 }
609
610 ck_free(b_data);
611
612 }
613
614 /* Handle Ctrl-C and the like. */
615
handle_stop_sig(int sig)616 static void handle_stop_sig(int sig) {
617
618 (void)sig;
619 stop_soon = 1;
620
621 afl_fsrv_killall();
622
623 }
624
625 /* Do basic preparations - persistent fds, filenames, etc. */
626
set_up_environment(char ** argv)627 static void set_up_environment(char **argv) {
628
629 u8 * x;
630 char *afl_preload;
631 char *frida_afl_preload = NULL;
632
633 fsrv.dev_null_fd = open("/dev/null", O_RDWR);
634 if (fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
635
636 if (!fsrv.out_file) {
637
638 u8 *use_dir = ".";
639
640 if (access(use_dir, R_OK | W_OK | X_OK)) {
641
642 use_dir = get_afl_env("TMPDIR");
643 if (!use_dir) { use_dir = "/tmp"; }
644
645 }
646
647 fsrv.out_file =
648 alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid());
649
650 }
651
652 unlink(fsrv.out_file);
653 fsrv.out_fd =
654 open(fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
655
656 if (fsrv.out_fd < 0) { PFATAL("Unable to create '%s'", fsrv.out_file); }
657
658 /* Set sane defaults... */
659
660 x = get_afl_env("ASAN_OPTIONS");
661
662 if (x) {
663
664 if (!strstr(x, "abort_on_error=1")) {
665
666 FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!");
667
668 }
669
670 #ifndef ASAN_BUILD
671 if (!getenv("AFL_DEBUG") && !strstr(x, "symbolize=0")) {
672
673 FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!");
674
675 }
676
677 #endif
678
679 }
680
681 x = get_afl_env("MSAN_OPTIONS");
682
683 if (x) {
684
685 if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) {
686
687 FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY(
688 MSAN_ERROR) " - please fix!");
689
690 }
691
692 if (!strstr(x, "symbolize=0")) {
693
694 FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
695
696 }
697
698 }
699
700 x = get_afl_env("LSAN_OPTIONS");
701
702 if (x) {
703
704 if (!strstr(x, "symbolize=0")) {
705
706 FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!");
707
708 }
709
710 }
711
712 setenv("ASAN_OPTIONS",
713 "abort_on_error=1:"
714 "detect_leaks=0:"
715 "allocator_may_return_null=1:"
716 "detect_odr_violation=0:"
717 "symbolize=0:"
718 "handle_segv=0:"
719 "handle_sigbus=0:"
720 "handle_abort=0:"
721 "handle_sigfpe=0:"
722 "handle_sigill=0",
723 0);
724
725 setenv("UBSAN_OPTIONS",
726 "halt_on_error=1:"
727 "abort_on_error=1:"
728 "malloc_context_size=0:"
729 "allocator_may_return_null=1:"
730 "symbolize=0:"
731 "handle_segv=0:"
732 "handle_sigbus=0:"
733 "handle_abort=0:"
734 "handle_sigfpe=0:"
735 "handle_sigill=0",
736 0);
737
738 setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
739 "abort_on_error=1:"
740 "msan_track_origins=0"
741 "allocator_may_return_null=1:"
742 "symbolize=0:"
743 "handle_segv=0:"
744 "handle_sigbus=0:"
745 "handle_abort=0:"
746 "handle_sigfpe=0:"
747 "handle_sigill=0", 0);
748
749 setenv("LSAN_OPTIONS",
750 "exitcode=" STRINGIFY(LSAN_ERROR) ":"
751 "fast_unwind_on_malloc=0:"
752 "symbolize=0:"
753 "print_suppressions=0",
754 0);
755
756 if (get_afl_env("AFL_PRELOAD")) {
757
758 if (qemu_mode) {
759
760 /* afl-qemu-trace takes care of converting AFL_PRELOAD. */
761
762 } else if (frida_mode) {
763
764 afl_preload = getenv("AFL_PRELOAD");
765 u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
766 if (afl_preload) {
767
768 frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
769
770 } else {
771
772 frida_afl_preload = alloc_printf("%s", frida_binary);
773
774 }
775
776 ck_free(frida_binary);
777
778 setenv("LD_PRELOAD", frida_afl_preload, 1);
779 setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
780
781 } else {
782
783 /* CoreSight mode uses the default behavior. */
784
785 setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
786 setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
787
788 }
789
790 } else if (frida_mode) {
791
792 u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
793 setenv("LD_PRELOAD", frida_binary, 1);
794 setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
795 ck_free(frida_binary);
796
797 }
798
799 if (frida_afl_preload) { ck_free(frida_afl_preload); }
800
801 }
802
803 /* Setup signal handlers, duh. */
804
setup_signal_handlers(void)805 static void setup_signal_handlers(void) {
806
807 struct sigaction sa;
808
809 sa.sa_handler = NULL;
810 sa.sa_flags = SA_RESTART;
811 sa.sa_sigaction = NULL;
812
813 sigemptyset(&sa.sa_mask);
814
815 /* Various ways of saying "stop". */
816
817 sa.sa_handler = handle_stop_sig;
818 sigaction(SIGHUP, &sa, NULL);
819 sigaction(SIGINT, &sa, NULL);
820 sigaction(SIGTERM, &sa, NULL);
821
822 }
823
824 /* Display usage hints. */
825
usage(u8 * argv0)826 static void usage(u8 *argv0) {
827
828 SAYF(
829 "\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
830
831 "Required parameters:\n"
832
833 " -i file - input test case to be analyzed by the tool\n\n"
834
835 "Execution control settings:\n"
836
837 " -f file - input file read by the tested program (stdin)\n"
838 " -t msec - timeout for each run (%u ms)\n"
839 " -m megs - memory limit for child process (%u MB)\n"
840 #if defined(__linux__) && defined(__aarch64__)
841 " -A - use binary-only instrumentation (ARM CoreSight mode)\n"
842 #endif
843 " -O - use binary-only instrumentation (FRIDA mode)\n"
844 #if defined(__linux__)
845 " -Q - use binary-only instrumentation (QEMU mode)\n"
846 " -U - use unicorn-based instrumentation (Unicorn mode)\n"
847 " -W - use qemu-based instrumentation with Wine (Wine "
848 "mode)\n"
849 #endif
850 "\n"
851
852 "Analysis settings:\n"
853
854 " -e - look for edge coverage only, ignore hit counts\n\n"
855
856 "For additional tips, please consult %s/README.md.\n\n"
857
858 "Environment variables used:\n"
859 "TMPDIR: directory to use for temporary input files\n"
860 "ASAN_OPTIONS: custom settings for ASAN\n"
861 " (must contain abort_on_error=1 and symbolize=0)\n"
862 "MSAN_OPTIONS: custom settings for MSAN\n"
863 " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
864 "AFL_ANALYZE_HEX: print file offsets in hexadecimal instead of decimal\n"
865 "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
866 " the target was compiled for\n"
867 "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
868 "AFL_SKIP_BIN_CHECK: skip checking the location of and the target\n"
869
870 , argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
871
872 exit(1);
873
874 }
875
876 /* Main entry point */
877
main(int argc,char ** argv_orig,char ** envp)878 int main(int argc, char **argv_orig, char **envp) {
879
880 s32 opt;
881 u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0;
882 char **use_argv;
883 char **argv = argv_cpy_dup(argc, argv_orig);
884
885 doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
886
887 SAYF(cCYA "afl-analyze" VERSION cRST " by Michal Zalewski\n");
888
889 afl_fsrv_init(&fsrv);
890
891 while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWh")) > 0) {
892
893 switch (opt) {
894
895 case 'i':
896
897 if (in_file) { FATAL("Multiple -i options not supported"); }
898 in_file = optarg;
899 break;
900
901 case 'f':
902
903 if (fsrv.out_file) { FATAL("Multiple -f options not supported"); }
904 fsrv.use_stdin = 0;
905 fsrv.out_file = ck_strdup(optarg);
906 break;
907
908 case 'e':
909
910 if (edges_only) { FATAL("Multiple -e options not supported"); }
911 edges_only = 1;
912 break;
913
914 case 'm': {
915
916 u8 suffix = 'M';
917
918 if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
919 mem_limit_given = 1;
920
921 if (!optarg) { FATAL("Wrong usage of -m"); }
922
923 if (!strcmp(optarg, "none")) {
924
925 mem_limit = 0;
926 fsrv.mem_limit = 0;
927 break;
928
929 }
930
931 if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
932 optarg[0] == '-') {
933
934 FATAL("Bad syntax used for -m");
935
936 }
937
938 switch (suffix) {
939
940 case 'T':
941 mem_limit *= 1024 * 1024;
942 break;
943 case 'G':
944 mem_limit *= 1024;
945 break;
946 case 'k':
947 mem_limit /= 1024;
948 break;
949 case 'M':
950 break;
951
952 default:
953 FATAL("Unsupported suffix or bad syntax for -m");
954
955 }
956
957 if (mem_limit < 5) { FATAL("Dangerously low value of -m"); }
958
959 if (sizeof(rlim_t) == 4 && mem_limit > 2000) {
960
961 FATAL("Value of -m out of range on 32-bit systems");
962
963 }
964
965 fsrv.mem_limit = mem_limit;
966
967 }
968
969 break;
970
971 case 't':
972
973 if (timeout_given) { FATAL("Multiple -t options not supported"); }
974 timeout_given = 1;
975
976 if (!optarg) { FATAL("Wrong usage of -t"); }
977
978 exec_tmout = atoi(optarg);
979
980 if (exec_tmout < 10 || optarg[0] == '-') {
981
982 FATAL("Dangerously low value of -t");
983
984 }
985
986 fsrv.exec_tmout = exec_tmout;
987
988 break;
989
990 case 'A': /* CoreSight mode */
991
992 #if !defined(__aarch64__) || !defined(__linux__)
993 FATAL("-A option is not supported on this platform");
994 #endif
995
996 if (cs_mode) { FATAL("Multiple -A options not supported"); }
997
998 cs_mode = 1;
999 fsrv.cs_mode = cs_mode;
1000 break;
1001
1002 case 'O': /* FRIDA mode */
1003
1004 if (frida_mode) { FATAL("Multiple -O options not supported"); }
1005
1006 frida_mode = 1;
1007 fsrv.frida_mode = frida_mode;
1008 setenv("AFL_FRIDA_INST_SEED", "1", 1);
1009
1010 break;
1011
1012 case 'Q':
1013
1014 if (qemu_mode) { FATAL("Multiple -Q options not supported"); }
1015 if (!mem_limit_given) { mem_limit = MEM_LIMIT_QEMU; }
1016
1017 qemu_mode = 1;
1018 fsrv.mem_limit = mem_limit;
1019 fsrv.qemu_mode = qemu_mode;
1020 break;
1021
1022 case 'U':
1023
1024 if (unicorn_mode) { FATAL("Multiple -U options not supported"); }
1025 if (!mem_limit_given) { mem_limit = MEM_LIMIT_UNICORN; }
1026
1027 unicorn_mode = 1;
1028 fsrv.mem_limit = mem_limit;
1029 break;
1030
1031 case 'W': /* Wine+QEMU mode */
1032
1033 if (use_wine) { FATAL("Multiple -W options not supported"); }
1034 qemu_mode = 1;
1035 use_wine = 1;
1036
1037 if (!mem_limit_given) { mem_limit = 0; }
1038 fsrv.qemu_mode = qemu_mode;
1039 fsrv.mem_limit = mem_limit;
1040
1041 break;
1042
1043 case 'h':
1044 usage(argv[0]);
1045 return -1;
1046 break;
1047
1048 default:
1049 usage(argv[0]);
1050
1051 }
1052
1053 }
1054
1055 if (optind == argc || !in_file) { usage(argv[0]); }
1056
1057 map_size = get_map_size();
1058 fsrv.map_size = map_size;
1059
1060 use_hex_offsets = !!get_afl_env("AFL_ANALYZE_HEX");
1061
1062 check_environment_vars(envp);
1063
1064 sharedmem_t shm = {0};
1065
1066 /* initialize cmplog_mode */
1067 shm.cmplog_mode = 0;
1068
1069 atexit(at_exit_handler);
1070 setup_signal_handlers();
1071
1072 set_up_environment(argv);
1073
1074 fsrv.target_path = find_binary(argv[optind]);
1075 fsrv.trace_bits = afl_shm_init(&shm, map_size, 0);
1076 detect_file_args(argv + optind, fsrv.out_file, &use_stdin);
1077 signal(SIGALRM, kill_child);
1078
1079 if (qemu_mode) {
1080
1081 if (use_wine) {
1082
1083 use_argv =
1084 get_wine_argv(argv[0], &target_path, argc - optind, argv + optind);
1085
1086 } else {
1087
1088 use_argv =
1089 get_qemu_argv(argv[0], &target_path, argc - optind, argv + optind);
1090
1091 }
1092
1093 } else if (cs_mode) {
1094
1095 use_argv = get_cs_argv(argv[0], &target_path, argc - optind, argv + optind);
1096
1097 } else {
1098
1099 use_argv = argv + optind;
1100
1101 }
1102
1103 SAYF("\n");
1104
1105 if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
1106
1107 s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
1108 if (forksrv_init_tmout < 1) {
1109
1110 FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT");
1111
1112 }
1113
1114 fsrv.init_tmout = (u32)forksrv_init_tmout;
1115
1116 }
1117
1118 fsrv.kill_signal =
1119 parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL);
1120
1121 read_initial_file();
1122 (void)check_binary_signatures(fsrv.target_path);
1123
1124 ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...",
1125 mem_limit, exec_tmout, edges_only ? ", edges only" : "");
1126
1127 afl_fsrv_start(&fsrv, use_argv, &stop_soon, false);
1128 analyze_run_target(in_data, in_len, 1);
1129
1130 if (fsrv.last_run_timed_out) {
1131
1132 FATAL("Target binary times out (adjusting -t may help).");
1133
1134 }
1135
1136 if (get_afl_env("AFL_SKIP_BIN_CHECK") == NULL && !anything_set()) {
1137
1138 FATAL("No instrumentation detected.");
1139
1140 }
1141
1142 analyze();
1143
1144 OKF("We're done here. Have a nice day!\n");
1145
1146 afl_shm_deinit(&shm);
1147 afl_fsrv_deinit(&fsrv);
1148 if (fsrv.target_path) { ck_free(fsrv.target_path); }
1149 if (in_data) { ck_free(in_data); }
1150
1151 exit(0);
1152
1153 }
1154
1155