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