• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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