xref: /aosp_15_r20/external/AFLplusplus/src/afl-analyze.c (revision 08b48e0b10e97b33e7b60c5b6e2243bd915777f2)
1 /*
2    american fuzzy lop++ - file format analyzer
3    -------------------------------------------
4 
5    Originally written by Michal Zalewski
6 
7    Now maintained by Marc Heuse <[email protected]>,
8                         Heiko Eißfeldt <[email protected]> and
9                         Andrea Fioraldi <[email protected]>
10 
11    Copyright 2016, 2017 Google Inc. All rights reserved.
12    Copyright 2019-2024 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.child_kill_signal);
118     fsrv.child_pid = -1;
119 
120   }
121 
122 }
123 
classify_counts(u8 * mem,u32 mem_size)124 static void classify_counts(u8 *mem, u32 mem_size) {
125 
126   u32 i = mem_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 u64 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, fsrv.map_size);
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     u64 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   x = get_afl_env("MSAN_OPTIONS");
660 
661   if (x) {
662 
663     if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) {
664 
665       FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY(
666           MSAN_ERROR) " - please fix!");
667 
668     }
669 
670   }
671 
672   set_sanitizer_defaults();
673 
674   if (get_afl_env("AFL_PRELOAD")) {
675 
676     if (qemu_mode) {
677 
678       /* afl-qemu-trace takes care of converting AFL_PRELOAD. */
679 
680     } else if (frida_mode) {
681 
682       afl_preload = getenv("AFL_PRELOAD");
683       u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
684       if (afl_preload) {
685 
686         frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
687 
688       } else {
689 
690         frida_afl_preload = alloc_printf("%s", frida_binary);
691 
692       }
693 
694       ck_free(frida_binary);
695 
696       setenv("LD_PRELOAD", frida_afl_preload, 1);
697       setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
698 
699     } else {
700 
701       /* CoreSight mode uses the default behavior. */
702 
703       setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
704       setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
705 
706     }
707 
708   } else if (frida_mode) {
709 
710     u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
711     setenv("LD_PRELOAD", frida_binary, 1);
712     setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
713     ck_free(frida_binary);
714 
715   }
716 
717   if (frida_afl_preload) { ck_free(frida_afl_preload); }
718 
719 }
720 
721 /* Setup signal handlers, duh. */
722 
setup_signal_handlers(void)723 static void setup_signal_handlers(void) {
724 
725   struct sigaction sa;
726 
727   sa.sa_handler = NULL;
728 #ifdef SA_RESTART
729   sa.sa_flags = SA_RESTART;
730 #else
731   sa.sa_flags = 0;
732 #endif
733   sa.sa_sigaction = NULL;
734 
735   sigemptyset(&sa.sa_mask);
736 
737   /* Various ways of saying "stop". */
738 
739   sa.sa_handler = handle_stop_sig;
740   sigaction(SIGHUP, &sa, NULL);
741   sigaction(SIGINT, &sa, NULL);
742   sigaction(SIGTERM, &sa, NULL);
743 
744 }
745 
746 /* Display usage hints. */
747 
usage(u8 * argv0)748 static void usage(u8 *argv0) {
749 
750   SAYF(
751       "\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
752 
753       "Required parameters:\n"
754 
755       "  -i file       - input test case to be analyzed by the tool\n\n"
756 
757       "Execution control settings:\n"
758 
759       "  -f file       - input file read by the tested program (stdin)\n"
760       "  -t msec       - timeout for each run (%u ms)\n"
761       "  -m megs       - memory limit for child process (%u MB)\n"
762 #if defined(__linux__) && defined(__aarch64__)
763       "  -A            - use binary-only instrumentation (ARM CoreSight mode)\n"
764 #endif
765       "  -O            - use binary-only instrumentation (FRIDA mode)\n"
766 #if defined(__linux__)
767       "  -Q            - use binary-only instrumentation (QEMU mode)\n"
768       "  -U            - use unicorn-based instrumentation (Unicorn mode)\n"
769       "  -W            - use qemu-based instrumentation with Wine (Wine "
770       "mode)\n"
771       "  -X            - use Nyx mode\n"
772 #endif
773       "\n"
774 
775       "Analysis settings:\n"
776 
777       "  -e            - look for edge coverage only, ignore hit counts\n\n"
778 
779       "For additional tips, please consult %s/README.md.\n\n"
780 
781       "Environment variables used:\n"
782       "TMPDIR: directory to use for temporary input files\n"
783       "ASAN_OPTIONS: custom settings for ASAN\n"
784       "              (must contain abort_on_error=1 and symbolize=0)\n"
785       "MSAN_OPTIONS: custom settings for MSAN\n"
786       "              (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
787       "AFL_ANALYZE_HEX: print file offsets in hexadecimal instead of decimal\n"
788       "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc.\n"
789       "                 (default: SIGKILL)\n"
790       "AFL_FORK_SERVER_KILL_SIGNAL: Kill signal for the fork server on termination\n"
791       "                             (default: SIGTERM). If unset and AFL_KILL_SIGNAL is\n"
792       "                             set, that value will be used.\n"
793       "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
794       "              the target was compiled for\n"
795       "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
796       "AFL_SKIP_BIN_CHECK: skip checking the location of and the target\n"
797       , argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
798 
799   exit(1);
800 
801 }
802 
803 /* Main entry point */
804 
main(int argc,char ** argv_orig,char ** envp)805 int main(int argc, char **argv_orig, char **envp) {
806 
807   s32    opt;
808   u8     mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0;
809   char **use_argv;
810   char **argv = argv_cpy_dup(argc, argv_orig);
811 
812   doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
813 
814   SAYF(cCYA "afl-analyze" VERSION cRST " by Michal Zalewski\n");
815 
816   afl_fsrv_init(&fsrv);
817 
818   while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWXYh")) > 0) {
819 
820     switch (opt) {
821 
822       case 'i':
823 
824         if (in_file) { FATAL("Multiple -i options not supported"); }
825         in_file = optarg;
826         break;
827 
828       case 'f':
829 
830         if (fsrv.out_file) { FATAL("Multiple -f options not supported"); }
831         fsrv.use_stdin = 0;
832         fsrv.out_file = ck_strdup(optarg);
833         break;
834 
835       case 'e':
836 
837         if (edges_only) { FATAL("Multiple -e options not supported"); }
838         edges_only = 1;
839         break;
840 
841       case 'm': {
842 
843         u8 suffix = 'M';
844 
845         if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
846         mem_limit_given = 1;
847 
848         if (!optarg) { FATAL("Wrong usage of -m"); }
849 
850         if (!strcmp(optarg, "none")) {
851 
852           mem_limit = 0;
853           fsrv.mem_limit = 0;
854           break;
855 
856         }
857 
858         if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
859             optarg[0] == '-') {
860 
861           FATAL("Bad syntax used for -m");
862 
863         }
864 
865         switch (suffix) {
866 
867           case 'T':
868             mem_limit *= 1024 * 1024;
869             break;
870           case 'G':
871             mem_limit *= 1024;
872             break;
873           case 'k':
874             mem_limit /= 1024;
875             break;
876           case 'M':
877             break;
878 
879           default:
880             FATAL("Unsupported suffix or bad syntax for -m");
881 
882         }
883 
884         if (mem_limit < 5) { FATAL("Dangerously low value of -m"); }
885 
886         if (sizeof(rlim_t) == 4 && mem_limit > 2000) {
887 
888           FATAL("Value of -m out of range on 32-bit systems");
889 
890         }
891 
892         fsrv.mem_limit = mem_limit;
893 
894       }
895 
896       break;
897 
898       case 't':
899 
900         if (timeout_given) { FATAL("Multiple -t options not supported"); }
901         timeout_given = 1;
902 
903         if (!optarg) { FATAL("Wrong usage of -t"); }
904 
905         exec_tmout = atoi(optarg);
906 
907         if (exec_tmout < 10 || optarg[0] == '-') {
908 
909           FATAL("Dangerously low value of -t");
910 
911         }
912 
913         fsrv.exec_tmout = exec_tmout;
914 
915         break;
916 
917       case 'A':                                           /* CoreSight mode */
918 
919 #if !defined(__aarch64__) || !defined(__linux__)
920         FATAL("-A option is not supported on this platform");
921 #endif
922 
923         if (cs_mode) { FATAL("Multiple -A options not supported"); }
924 
925         cs_mode = 1;
926         fsrv.cs_mode = cs_mode;
927         break;
928 
929       case 'O':                                               /* FRIDA mode */
930 
931         if (frida_mode) { FATAL("Multiple -O options not supported"); }
932 
933         frida_mode = 1;
934         fsrv.frida_mode = frida_mode;
935         setenv("AFL_FRIDA_INST_SEED", "1", 1);
936 
937         break;
938 
939       case 'Q':
940 
941         if (qemu_mode) { FATAL("Multiple -Q options not supported"); }
942         if (!mem_limit_given) { mem_limit = MEM_LIMIT_QEMU; }
943 
944         qemu_mode = 1;
945         fsrv.mem_limit = mem_limit;
946         fsrv.qemu_mode = qemu_mode;
947         break;
948 
949       case 'U':
950 
951         if (unicorn_mode) { FATAL("Multiple -U options not supported"); }
952         if (!mem_limit_given) { mem_limit = MEM_LIMIT_UNICORN; }
953 
954         unicorn_mode = 1;
955         fsrv.mem_limit = mem_limit;
956         break;
957 
958       case 'W':                                           /* Wine+QEMU mode */
959 
960         if (use_wine) { FATAL("Multiple -W options not supported"); }
961         qemu_mode = 1;
962         use_wine = 1;
963 
964         if (!mem_limit_given) { mem_limit = 0; }
965         fsrv.qemu_mode = qemu_mode;
966         fsrv.mem_limit = mem_limit;
967 
968         break;
969 
970       case 'Y':  // fallthough
971 #ifdef __linux__
972       case 'X':                                                 /* NYX mode */
973 
974         if (fsrv.nyx_mode) { FATAL("Multiple -X options not supported"); }
975 
976         fsrv.nyx_mode = 1;
977         fsrv.nyx_parent = true;
978         fsrv.nyx_standalone = true;
979 
980         break;
981 #else
982       case 'X':
983         FATAL("Nyx mode is only availabe on linux...");
984         break;
985 #endif
986 
987       case 'h':
988         usage(argv[0]);
989         return -1;
990         break;
991 
992       default:
993         usage(argv[0]);
994 
995     }
996 
997   }
998 
999   if (optind == argc || !in_file) { usage(argv[0]); }
1000 
1001   map_size = get_map_size();
1002   fsrv.map_size = map_size;
1003 
1004   use_hex_offsets = !!get_afl_env("AFL_ANALYZE_HEX");
1005 
1006   check_environment_vars(envp);
1007 
1008   sharedmem_t shm = {0};
1009 
1010   /* initialize cmplog_mode */
1011   shm.cmplog_mode = 0;
1012 
1013   atexit(at_exit_handler);
1014   setup_signal_handlers();
1015 
1016   set_up_environment(argv);
1017 
1018 #ifdef __linux__
1019   if (!fsrv.nyx_mode) {
1020 
1021     fsrv.target_path = find_binary(argv[optind]);
1022 
1023   } else {
1024 
1025     fsrv.target_path = ck_strdup(argv[optind]);
1026 
1027   }
1028 
1029 #else
1030   fsrv.target_path = find_binary(argv[optind]);
1031 #endif
1032 
1033   fsrv.trace_bits = afl_shm_init(&shm, map_size, 0);
1034   detect_file_args(argv + optind, fsrv.out_file, &use_stdin);
1035   signal(SIGALRM, kill_child);
1036 
1037   if (qemu_mode) {
1038 
1039     if (use_wine) {
1040 
1041       use_argv =
1042           get_wine_argv(argv[0], &target_path, argc - optind, argv + optind);
1043 
1044     } else {
1045 
1046       use_argv =
1047           get_qemu_argv(argv[0], &target_path, argc - optind, argv + optind);
1048 
1049     }
1050 
1051   } else if (cs_mode) {
1052 
1053     use_argv = get_cs_argv(argv[0], &target_path, argc - optind, argv + optind);
1054 
1055 #ifdef __linux__
1056 
1057   } else if (fsrv.nyx_mode) {
1058 
1059     fsrv.nyx_id = 0;
1060 
1061     u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so");
1062     fsrv.nyx_handlers = afl_load_libnyx_plugin(libnyx_binary);
1063     if (fsrv.nyx_handlers == NULL) {
1064 
1065       FATAL("failed to initialize libnyx.so...");
1066 
1067     }
1068 
1069     fsrv.nyx_use_tmp_workdir = true;
1070     fsrv.nyx_bind_cpu_id = 0;
1071 
1072     use_argv = argv + optind;
1073 #endif
1074 
1075   } else {
1076 
1077     use_argv = argv + optind;
1078 
1079   }
1080 
1081   SAYF("\n");
1082 
1083   if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
1084 
1085     s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
1086     if (forksrv_init_tmout < 1) {
1087 
1088       FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT");
1089 
1090     }
1091 
1092     fsrv.init_tmout = (u32)forksrv_init_tmout;
1093 
1094   }
1095 
1096   configure_afl_kill_signals(
1097       &fsrv, NULL, NULL, (fsrv.qemu_mode || unicorn_mode) ? SIGKILL : SIGTERM);
1098 
1099   read_initial_file();
1100 #ifdef __linux__
1101   if (!fsrv.nyx_mode) { (void)check_binary_signatures(fsrv.target_path); }
1102 #else
1103   (void)check_binary_signatures(fsrv.target_path);
1104 #endif
1105 
1106   ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...",
1107        mem_limit, exec_tmout, edges_only ? ", edges only" : "");
1108 
1109   afl_fsrv_start(&fsrv, use_argv, &stop_soon, false);
1110   analyze_run_target(in_data, in_len, 1);
1111 
1112   if (fsrv.last_run_timed_out) {
1113 
1114     FATAL("Target binary times out (adjusting -t may help).");
1115 
1116   }
1117 
1118   if (get_afl_env("AFL_SKIP_BIN_CHECK") == NULL && !anything_set()) {
1119 
1120     FATAL("No instrumentation detected.");
1121 
1122   }
1123 
1124   analyze();
1125 
1126   OKF("We're done here. Have a nice day!\n");
1127 
1128   afl_shm_deinit(&shm);
1129   afl_fsrv_deinit(&fsrv);
1130   if (fsrv.target_path) { ck_free(fsrv.target_path); }
1131   if (in_data) { ck_free(in_data); }
1132 
1133   exit(0);
1134 
1135 }
1136 
1137