You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
AFLplusplus/src%2FAFLplusplus-stable%2Fsrc/afl-analyze.c

1151 lines
28 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
american fuzzy lop++ - file format analyzer
-------------------------------------------
Originally written by Michal Zalewski
Now maintained by Marc Heuse <mh@mh-sec.de>,
Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2024 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
https://www.apache.org/licenses/LICENSE-2.0
A nifty utility that grabs an input file and takes a stab at explaining
its structure by observing how changes to it affect the execution path.
If the output scrolls past the edge of the screen, pipe it to 'less -r'.
*/
#define AFL_MAIN
#include "config.h"
#include "types.h"
#include "debug.h"
#include "alloc-inl.h"
#include "hash.h"
#include "sharedmem.h"
#include "common.h"
#include "forkserver.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
#include <dirent.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/wait.h>
#include <sys/time.h>
#ifndef USEMMAP
#include <sys/shm.h>
#endif
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/resource.h>
static u8 *in_file; /* Analyzer input test case */
static u8 *in_data; /* Input data for analysis */
static u32 in_len, /* Input data length */
total_execs, /* Total number of execs */
exec_hangs, /* Total number of hangs */
exec_tmout = EXEC_TIMEOUT; /* Exec timeout (ms) */
static u64 orig_cksum; /* Original checksum */
static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
static bool edges_only, /* Ignore hit counts? */
use_hex_offsets, /* Show hex offsets? */
use_stdin = true; /* Use stdin for program input? */
static volatile u8 stop_soon; /* Ctrl-C pressed? */
static u8 *target_path;
static u8 frida_mode;
static u8 qemu_mode;
static u8 cs_mode;
static u32 map_size = MAP_SIZE;
static afl_forkserver_t fsrv = {0}; /* The forkserver */
/* Constants used for describing byte behavior. */
#define RESP_NONE 0x00 /* Changing byte is a no-op. */
#define RESP_MINOR 0x01 /* Some changes have no effect. */
#define RESP_VARIABLE 0x02 /* Changes produce variable paths. */
#define RESP_FIXED 0x03 /* Changes produce fixed patterns. */
#define RESP_LEN 0x04 /* Potential length field */
#define RESP_CKSUM 0x05 /* Potential checksum */
#define RESP_SUSPECT 0x06 /* Potential "suspect" blob */
/* Classify tuple counts. This is a slow & naive version, but good enough here.
*/
//<2F><>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD><EFBFBD>ԵĴ<D4B5><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>й鲢<D0B9><E9B2A2><EFBFBD>ڲ<EFBFBD><DAB2><EFBFBD><EFBFBD><EFBFBD>̫<EFBFBD><CCAB>Ӱ<EFBFBD><D3B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E3A1A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
static u8 count_class_lookup[256] = {
[0] = 0,
[1] = 1,
[2] = 2,
[3] = 4,
[4 ... 7] = 8,
[8 ... 15] = 16,
[16 ... 31] = 32,
[32 ... 127] = 64,
[128 ... 255] = 128
};
//<2F><><EFBFBD><EFBFBD><EFBFBD>ӽ<EFBFBD><D3BD><EFBFBD>
static void kill_child() {
if (fsrv.child_pid > 0) {
//kill<6C><6C><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɱ<EFBFBD><C9B1><EFBFBD><EFBFBD>Ӧpid<69><64><EFBFBD>ӽ<EFBFBD><D3BD>̣<EFBFBD><CCA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־λ<D6BE><CEBB>Ϊ1
kill(fsrv.child_pid, fsrv.child_kill_signal);
//<2F><><EFBFBD>ӽ<EFBFBD><D3BD>̵<EFBFBD>pid<69><64>Ϊ-1<><31><EFBFBD><EFBFBD><EFBFBD>޷<EFBFBD>ѡ<EFBFBD><D1A1>
fsrv.child_pid = -1;
}
}
//<2F><><EFBFBD>ڴ<EFBFBD><DAB4>е<EFBFBD><D0B5>ֽڽ<D6BD><DABD>з<EFBFBD><D0B7>࣬ͨ<E0A3AC><CDA8>Ԥ<EFBFBD><D4A4><EFBFBD><EFBFBD>count_class_lookup<75><70><EFBFBD><EFBFBD>ʵ<EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7>
static void classify_counts(u8 *mem, u32 mem_size) {
u32 i = mem_size;
//<2F><><EFBFBD><EFBFBD>ֻ<EFBFBD>Ա<EFBFBD>Ե̽<D4B5><CCBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>ֻ<EFBFBD><D6BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊbool<6F><6C><EFBFBD><EFBFBD>
if (edges_only) {
while (i--) {
if (*mem) { *mem = 1; }
mem++;
}
} else {
while (i--) {
*mem = count_class_lookup[*mem];
mem++;
}
}
}
/* See if any bytes are set in the bitmap. */
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>bitmap<61><70><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD>bitmap<61><70><EFBFBD><EFBFBD><E6B1BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
static inline u8 anything_set(void) {
//ʹ<><CAB9>fsrv.trace_bitsģ<73><C4A3>bitmap
u32 *ptr = (u32 *)fsrv.trace_bits;
//map_size<7A>Ĵ<EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD>4<EFBFBD><34><EFBFBD><EFBFBD>Ϊ<EFBFBD>ǰ<EFBFBD><C7B0>ֽڽ<D6BD><DABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
u32 i = (map_size >> 2);
while (i--) {
if (*(ptr++)) { return 1; }
}
return 0;
}
/* Get rid of temp files (atexit handler). */
//<2F>ں<EFBFBD><DABA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>ã<EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD>ʱ<EFBFBD>ļ<EFBFBD>
static void at_exit_handler(void) {
unlink(fsrv.out_file); /* Ignore errors */
}
/* Read initial file. */
//<2F><>ȡ<EFBFBD><C8A1>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD>ʼ״̬
static void read_initial_file(void) {
struct stat st;
s32 fd = open(in_file, O_RDONLY);
//<2F>޷<EFBFBD><DEB7><EFBFBD>ȡ<EFBFBD><C8A1>֧
if (fd < 0) { PFATAL("Unable to open '%s'", in_file); }
//<2F><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>շ<EFBFBD>֧
if (fstat(fd, &st) || !st.st_size) { FATAL("Zero-sized input file."); }
//<2F><>ȡ<EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ݳ<EFBFBD><DDB3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>֧
if (st.st_size >= TMIN_MAX_FILE) {
FATAL("Input file is too large (%ld MB max)", TMIN_MAX_FILE / 1024 / 1024);
}
in_len = st.st_size;
in_data = ck_alloc_nozero(in_len);
ck_read(fd, in_data, in_len, in_file);
close(fd);
OKF("Read %u byte%s from '%s'.", in_len, in_len == 1 ? "" : "s", in_file);
}
/* Execute target application. Returns exec checksum, or 0 if program
times out. */
//<2F><>һ<EFBFBD><D2BB>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ľ<EFBFBD><C4BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̣<EFBFBD><CCA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>õ<EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD>¶Գ<C2B6><D4B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
static u64 analyze_run_target(u8 *mem, u32 len, u8 first_run) {
//<2F><><EFBFBD>ó<EFBFBD><C3B3><EFBFBD><EFBFBD>ľ<EFBFBD><C4BE><EFBFBD><EFBFBD><EFBFBD>ַд<D6B7><EFBFBD><EBB5BD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB>
afl_fsrv_write_to_testcase(&fsrv, mem, len);
//ʹ<><CAB9>afl_fsrv_run_target<65><74><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>о<EFBFBD><D0BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̣<EFBFBD><CCA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD>fsrv_run_result_t<5F><74><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
fsrv_run_result_t ret = afl_fsrv_run_target(&fsrv, exec_tmout, &stop_soon);
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD>ܷ<EFBFBD>֧
if (ret == FSRV_RUN_ERROR) {
FATAL("Error in forkserver");
}
//<2F><><EFBFBD>о<EFBFBD><D0BE><EFBFBD>ȱʧ<C8B1><CAA7>֧
else if (ret == FSRV_RUN_NOINST) {
FATAL("Target not instrumented");
}
//<2F><><EFBFBD>б<EFBFBD><D0B1><EFBFBD><EFBFBD><EFBFBD>֧
else if (ret == FSRV_RUN_NOBITS) {
FATAL("Failed to run target");
}
//<2F><><EFBFBD><EFBFBD>classify_counts<74><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Բ<EFBFBD><D4B2>Խ<EFBFBD><D4BD><EFBFBD><EFBFBD>ڴ<EFBFBD><DAB4>е<EFBFBD><D0B5>ֽڽ<D6BD><DABD>з<EFBFBD><D0B7><EFBFBD><E0A3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
classify_counts(fsrv.trace_bits, fsrv.map_size);
//ȫ<>ֱ<EFBFBD><D6B1><EFBFBD><EFBFBD><EFBFBD>total_execs<63><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Բ<EFBFBD><D4B2>Գ<EFBFBD><D4B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>м<EFBFBD>¼
total_execs++;
if (stop_soon) {
//<2F>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˳<EFBFBD><CBB3><EFBFBD>Ctrl+C<><43><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˳<EFBFBD>ʾ<EFBFBD><CABE>
SAYF(cRST cLRD "\n+++ Analysis aborted by user +++\n" cRST);
exit(1);
}
/* Always discard inputs that time out. */
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>г<EFBFBD>ʱ<EFBFBD><CAB1>ȫ<EFBFBD>ֱ<EFBFBD><D6B1><EFBFBD><EFBFBD><EFBFBD>exec_hangs<67><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Բ<EFBFBD><D4B2>Գ<EFBFBD><D4B3><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD>м<EFBFBD>¼
if (fsrv.last_run_timed_out) {
exec_hangs++;
return 0;
}
//У<><D0A3><EFBFBD><EFBFBD>
u64 cksum = hash64(fsrv.trace_bits, fsrv.map_size, HASH_CONST);
if (ret == FSRV_RUN_CRASH) {
/* We don't actually care if the target is crashing or not,
except that when it does, the checksum should be different. */
//У<><D0A3><EFBFBD><EFBFBD>ȫ1<C8AB><31><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ÿλȡ<CEBB><C8A1>
cksum ^= 0xffffffff;
}
//<2F><>¼<EFBFBD><C2BC>ʼУ<CABC><D0A3><EFBFBD><EFBFBD>
if (first_run) { orig_cksum = cksum; }
return cksum;
}
#ifdef USE_COLOR
/* Helper function to display a human-readable character. */
//<2F><><EFBFBD>ڴ<EFBFBD><DAB4><EFBFBD><EFBFBD>ֽڴ<D6BD>ӡ<EFBFBD><D3A1><EFBFBD>û<EFBFBD><C3BB>ɶ<EFBFBD><C9B6>ַ<EFBFBD>
static void show_char(u8 val) {
switch (val) {
case 0 ... 32:
case 127 ... 255:
//ͨ<><CDA8><EFBFBD><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5>
SAYF("#%02x", val);
break;
default:
SAYF(" %c ", val);
}
}
/* Show the legend */
//<2F><><EFBFBD>ڴ<EFBFBD><DAB4>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>ͬ<EFBFBD><CDAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD>
static void show_legend(void) {
SAYF(" " cLGR bgGRA " 01 " cRST " - no-op block " cBLK bgLGN
" 01 " cRST
" - suspected length field\n"
" " cBRI bgGRA " 01 " cRST " - superficial content " cBLK bgYEL
" 01 " cRST
" - suspected cksum or magic int\n"
" " cBLK bgCYA " 01 " cRST " - critical stream " cBLK bgLRD
" 01 " cRST
" - suspected checksummed block\n"
" " cBLK bgMGN " 01 " cRST " - \"magic value\" section\n\n");
}
#endif /* USE_COLOR */
/* Interpret and report a pattern in the input file. */
//<2F><>16<31><36><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD>Ϊ
static void dump_hex(u32 len, u8 *b_data) {
u32 i;
for (i = 0; i < len; i++) {
#ifdef USE_COLOR
u32 rlen = 1, off;
#else
u32 rlen = 1;
#endif /* ^USE_COLOR */
u8 rtype = b_data[i] & 0x0f;
/* Look ahead to determine the length of run. */
//ȷ<><C8B7><EFBFBD><EFBFBD><EFBFBD>г<EFBFBD><D0B3><EFBFBD>
while (i + rlen < len && (b_data[i] >> 7) == (b_data[i + rlen] >> 7)) {
if (rtype < (b_data[i + rlen] & 0x0f)) {
rtype = b_data[i + rlen] & 0x0f;
}
rlen++;
}
/* Try to do some further classification based on length & value. */
//<2F><><EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD>ͽ<EFBFBD><CDBD>з<EFBFBD><D0B7><EFBFBD>
if (rtype == RESP_FIXED) {
switch (rlen) {
case 2: {
u16 val = *(u16 *)(in_data + i);
/* Small integers may be length fields. */
if (val && (val <= in_len || SWAP16(val) <= in_len)) {
//<2F>ж<EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD>г<EFBFBD><D0B3><EFBFBD>
rtype = RESP_LEN;
break;
}
/* Uniform integers may be checksums. */
if (val && abs(in_data[i] - in_data[i + 1]) > 32) {
//<2F>ж<EFBFBD>ΪУ<CEAA><D0A3><EFBFBD><EFBFBD>
rtype = RESP_CKSUM;
break;
}
break;
}
case 4: {
//ͬ<><CDAC>
u32 val = *(u32 *)(in_data + i);
/* Small integers may be length fields. */
if (val && (val <= in_len || SWAP32(val) <= in_len)) {
rtype = RESP_LEN;
break;
}
/* Uniform integers may be checksums. */
if (val && (in_data[i] >> 7 != in_data[i + 1] >> 7 ||
in_data[i] >> 7 != in_data[i + 2] >> 7 ||
in_data[i] >> 7 != in_data[i + 3] >> 7)) {
rtype = RESP_CKSUM;
break;
}
break;
}
case 1:
case 3:
case 5 ... MAX_AUTO_EXTRA - 1:
break;
default:
rtype = RESP_SUSPECT;
}
}
/* Print out the entire run. */
#ifdef USE_COLOR
for (off = 0; off < rlen; off++) {
/* Every 16 digits, display offset. */
//ÿ4<C3BF><34><EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD>Ϊһ<CEAA><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (!((i + off) % 16)) {
if (off) { SAYF(cRST cLCY ">"); }
if (use_hex_offsets) {
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
SAYF(cRST cGRA "%s[%06x] " cRST, (i + off) ? "\n" : "", i + off);
} else {
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
SAYF(cRST cGRA "%s[%06u] " cRST, (i + off) ? "\n" : "", i + off);
}
}
switch (rtype) {
//<2F><><EFBFBD><EFBFBD>rtype<70><65><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD>ͬ<EFBFBD><CDAC><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD>в<EFBFBD>ͬ<EFBFBD><CDAC><EFBFBD><EFBFBD>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD>
case RESP_NONE:
SAYF(cLGR bgGRA);
break;
case RESP_MINOR:
SAYF(cBRI bgGRA);
break;
case RESP_VARIABLE:
SAYF(cBLK bgCYA);
break;
case RESP_FIXED:
SAYF(cBLK bgMGN);
break;
case RESP_LEN:
SAYF(cBLK bgLGN);
break;
case RESP_CKSUM:
SAYF(cBLK bgYEL);
break;
case RESP_SUSPECT:
SAYF(cBLK bgLRD);
break;
}
//<2F><><EFBFBD><EFBFBD>
show_char(in_data[i + off]);
if (off != rlen - 1 && (i + off + 1) % 16) {
//<2F><><EFBFBD><EFBFBD>
SAYF(" ");
} else {
SAYF(cRST " ");
}
}
#else
//<2F><><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><C3BB>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD>16<31><36><EFBFBD>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD>
if (use_hex_offsets)
SAYF(" Offset %x, length %u: ", i, rlen);
else
SAYF(" Offset %u, length %u: ", i, rlen);
switch (rtype) {
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Է<EFBFBD><D4B7><EFBFBD><EFBFBD>õ<EFBFBD><C3B5><EFBFBD><EFBFBD><EFBFBD>Ϣ
case RESP_NONE:
SAYF("no-op block\n");
break;
case RESP_MINOR:
SAYF("superficial content\n");
break;
case RESP_VARIABLE:
SAYF("critical stream\n");
break;
case RESP_FIXED:
SAYF("\"magic value\" section\n");
break;
case RESP_LEN:
SAYF("suspected length field\n");
break;
case RESP_CKSUM:
SAYF("suspected cksum or magic int\n");
break;
case RESP_SUSPECT:
SAYF("suspected checksummed block\n");
break;
}
#endif /* ^USE_COLOR */
i += rlen - 1;
}
#ifdef USE_COLOR
SAYF(cRST "\n");
#endif /* USE_COLOR */
}
/* Actually analyze! */
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
static void analyze() {
//<2F><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
u32 i;
u32 boring_len = 0, prev_xff = 0, prev_x01 = 0, prev_s10 = 0, prev_a10 = 0;
u8 *b_data = ck_alloc(in_len + 1);
u8 seq_byte = 0;
b_data[in_len] = 0xff; /* Intentional terminator. */
ACTF("Analyzing input file (this may take a while)...\n");
#ifdef USE_COLOR
show_legend();
#endif /* USE_COLOR */
for (i = 0; i < in_len; i++) {
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ÿһ<C3BF><D2BB><EFBFBD>ֽ<EFBFBD>
u64 xor_ff, xor_01, sub_10, add_10;
u8 xff_orig, x01_orig, s10_orig, a10_orig;
/* Perform walking byte adjustments across the file. We perform four
operations designed to elicit some response from the underlying
code. */
//<2F>Գ<EFBFBD><D4B3><EFBFBD><EFBFBD><EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD>ֽڽ<D6BD><DABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0xff<66><66><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0x01<30><31><EFBFBD><EFBFBD>0x10<31><30><EFBFBD><EFBFBD>0x20<32><30><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȼ<EFBFBD><C8BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>з<EFBFBD><D0B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD>Գ<EFBFBD><D4B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>в<EFBFBD><D0B2><EFBFBD>Ӱ<EFBFBD><D3B0>
in_data[i] ^= 0xff;
xor_ff = analyze_run_target(in_data, in_len, 0);
in_data[i] ^= 0xfe;
xor_01 = analyze_run_target(in_data, in_len, 0);
in_data[i] = (in_data[i] ^ 0x01) - 0x10;
sub_10 = analyze_run_target(in_data, in_len, 0);
in_data[i] += 0x20;
add_10 = analyze_run_target(in_data, in_len, 0);
in_data[i] -= 0x10;
/* Classify current behavior. */
//<2F><>¼У<C2BC><D0A3><EFBFBD>ͣ<EFBFBD><CDA3>Թ۲<D4B9><DBB2>Ƿ<EFBFBD><C7B7><EFBFBD>Ӱ<EFBFBD><D3B0>
xff_orig = (xor_ff == orig_cksum);
x01_orig = (xor_01 == orig_cksum);
s10_orig = (sub_10 == orig_cksum);
a10_orig = (add_10 == orig_cksum);
if (xff_orig && x01_orig && s10_orig && a10_orig) {
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>򽫸<EFBFBD><F2BDABB8>ֽڱ<D6BD><DAB1><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
b_data[i] = RESP_NONE;
boring_len++;
} else if (xff_orig || x01_orig || s10_orig || a10_orig) {
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
b_data[i] = RESP_MINOR;
boring_len++;
} else if (xor_ff == xor_01 && xor_ff == sub_10 && xor_ff == add_10) {
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD><CDAC>ʽ<EFBFBD>޸ĺ<DEB8><C4BA><EFBFBD>У<EFBFBD><D0A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȣ<EFBFBD><C8A3>򽫸<EFBFBD><F2BDABB8>ֽڱ<D6BD><DAB1><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD>޸<EFBFBD><DEB8><EFBFBD>
b_data[i] = RESP_FIXED;
} else {
//<2F><><EFBFBD><EFBFBD><EFBFBD>򽫸<EFBFBD><F2BDABB8>ֽڱ<D6BD><DAB1><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
b_data[i] = RESP_VARIABLE;
}
/* When all checksums change, flip most significant bit of b_data. */
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD><D0B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ֽڵIJ<DAB5><C4B2>Բ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD>λ
if (prev_xff != xor_ff && prev_x01 != xor_01 && prev_s10 != sub_10 &&
prev_a10 != add_10) {
seq_byte ^= 0x80;
}
b_data[i] |= seq_byte;
prev_xff = xor_ff;
prev_x01 = xor_01;
prev_s10 = sub_10;
prev_a10 = add_10;
}
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
dump_hex(in_len, b_data);
SAYF("\n");
OKF("Analysis complete. Interesting bits: %0.02f%% of the input file.",
100.0 - ((double)boring_len * 100) / in_len);
if (exec_hangs) {
WARNF(cLRD "Encountered %u timeouts - results may be skewed." cRST,
exec_hangs);
}
ck_free(b_data);
}
/* Handle Ctrl-C and the like. */
//<2F>û<EFBFBD><C3BB>Գ<EFBFBD><D4B3><EFBFBD>ֹ<EFBFBD><D6B9><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
static void handle_stop_sig(int sig) {
(void)sig;
stop_soon = 1;
afl_fsrv_killall();
}
/* Do basic preparations - persistent fds, filenames, etc. */
//<2F><><EFBFBD>ò<EFBFBD><C3B2>Ի<EFBFBD><D4BB><EFBFBD>
static void set_up_environment(char **argv) {
u8 *x;
char *afl_preload;
char *frida_afl_preload = NULL;
fsrv.dev_null_fd = open("/dev/null", O_RDWR);
if (fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
if (!fsrv.out_file) {
u8 *use_dir = ".";
if (access(use_dir, R_OK | W_OK | X_OK)) {
use_dir = get_afl_env("TMPDIR");
if (!use_dir) { use_dir = "/tmp"; }
}
fsrv.out_file =
alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid());
}
unlink(fsrv.out_file);
fsrv.out_fd =
open(fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fsrv.out_fd < 0) { PFATAL("Unable to create '%s'", fsrv.out_file); }
/* Set sane defaults... */
x = get_afl_env("MSAN_OPTIONS");
if (x) {
if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) {
FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY(
MSAN_ERROR) " - please fix!");
}
}
set_sanitizer_defaults();
if (get_afl_env("AFL_PRELOAD")) {
if (qemu_mode) {
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
} else if (frida_mode) {
afl_preload = getenv("AFL_PRELOAD");
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
if (afl_preload) {
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
} else {
frida_afl_preload = alloc_printf("%s", frida_binary);
}
ck_free(frida_binary);
setenv("LD_PRELOAD", frida_afl_preload, 1);
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
} else {
/* CoreSight mode uses the default behavior. */
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
}
} else if (frida_mode) {
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
setenv("LD_PRELOAD", frida_binary, 1);
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
ck_free(frida_binary);
}
if (frida_afl_preload) { ck_free(frida_afl_preload); }
}
/* Setup signal handlers, duh. */
//<2F><><EFBFBD><EFBFBD><EFBFBD>źŴ<C5BA><C5B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>򣬽<EFBFBD><F2A3ACBD>г<EFBFBD>ʼ<EFBFBD><CABC>
static void setup_signal_handlers(void) {
struct sigaction sa;
sa.sa_handler = NULL;
#ifdef SA_RESTART
sa.sa_flags = SA_RESTART;
#else
sa.sa_flags = 0;
#endif
sa.sa_sigaction = NULL;
sigemptyset(&sa.sa_mask);
/* Various ways of saying "stop". */
sa.sa_handler = handle_stop_sig;
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
}
/* Display usage hints. */
//<2F><><EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD>-hʱ<68><CAB1><EFBFBD>ô˺<C3B4><CBBA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ըù<D4B8><C3B9>ߵ<EFBFBD>ʹ<EFBFBD>÷<EFBFBD><C3B7><EFBFBD>
static void usage(u8 *argv0) {
SAYF(
"\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
"Required parameters:\n"
" -i file - input test case to be analyzed by the tool\n\n"
"Execution control settings:\n"
" -f file - input file read by the tested program (stdin)\n"
" -t msec - timeout for each run (%u ms)\n"
" -m megs - memory limit for child process (%u MB)\n"
#if defined(__linux__) && defined(__aarch64__)
" -A - use binary-only instrumentation (ARM CoreSight mode)\n"
#endif
" -O - use binary-only instrumentation (FRIDA mode)\n"
#if defined(__linux__)
" -Q - use binary-only instrumentation (QEMU mode)\n"
" -U - use unicorn-based instrumentation (Unicorn mode)\n"
" -W - use qemu-based instrumentation with Wine (Wine "
"mode)\n"
" -X - use Nyx mode\n"
#endif
"\n"
"Analysis settings:\n"
" -e - look for edge coverage only, ignore hit counts\n\n"
"For additional tips, please consult %s/README.md.\n\n"
"Environment variables used:\n"
"TMPDIR: directory to use for temporary input files\n"
"ASAN_OPTIONS: custom settings for ASAN\n"
" (must contain abort_on_error=1 and symbolize=0)\n"
"MSAN_OPTIONS: custom settings for MSAN\n"
" (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
"AFL_ANALYZE_HEX: print file offsets in hexadecimal instead of decimal\n"
"AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc.\n"
" (default: SIGKILL)\n"
"AFL_FORK_SERVER_KILL_SIGNAL: Kill signal for the fork server on termination\n"
" (default: SIGTERM). If unset and AFL_KILL_SIGNAL is\n"
" set, that value will be used.\n"
"AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
" the target was compiled for\n"
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
"AFL_SKIP_BIN_CHECK: skip checking the location of and the target\n"
, argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
exit(1);
}
/* Main entry point */
//main<69><6E><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD>ʹ<EFBFBD>õ<EFBFBD>ʵ<EFBFBD>ʽӿ<CABD>
int main(int argc, char **argv_orig, char **envp) {
s32 opt;
u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0;
char **use_argv;
char **argv = argv_cpy_dup(argc, argv_orig);
doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
SAYF(cCYA "afl-analyze" VERSION cRST " by Michal Zalewski\n");
afl_fsrv_init(&fsrv);
while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWXYh")) > 0) {
switch (opt) {
case 'i':
if (in_file) { FATAL("Multiple -i options not supported"); }
in_file = optarg;
break;
case 'f':
if (fsrv.out_file) { FATAL("Multiple -f options not supported"); }
fsrv.use_stdin = 0;
fsrv.out_file = ck_strdup(optarg);
break;
case 'e':
if (edges_only) { FATAL("Multiple -e options not supported"); }
edges_only = 1;
break;
case 'm': {
u8 suffix = 'M';
if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
mem_limit_given = 1;
if (!optarg) { FATAL("Wrong usage of -m"); }
if (!strcmp(optarg, "none")) {
mem_limit = 0;
fsrv.mem_limit = 0;
break;
}
if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
optarg[0] == '-') {
FATAL("Bad syntax used for -m");
}
switch (suffix) {
case 'T':
mem_limit *= 1024 * 1024;
break;
case 'G':
mem_limit *= 1024;
break;
case 'k':
mem_limit /= 1024;
break;
case 'M':
break;
default:
FATAL("Unsupported suffix or bad syntax for -m");
}
if (mem_limit < 5) { FATAL("Dangerously low value of -m"); }
if (sizeof(rlim_t) == 4 && mem_limit > 2000) {
FATAL("Value of -m out of range on 32-bit systems");
}
fsrv.mem_limit = mem_limit;
}
break;
case 't':
if (timeout_given) { FATAL("Multiple -t options not supported"); }
timeout_given = 1;
if (!optarg) { FATAL("Wrong usage of -t"); }
exec_tmout = atoi(optarg);
if (exec_tmout < 10 || optarg[0] == '-') {
FATAL("Dangerously low value of -t");
}
fsrv.exec_tmout = exec_tmout;
break;
case 'A': /* CoreSight mode */
#if !defined(__aarch64__) || !defined(__linux__)
FATAL("-A option is not supported on this platform");
#endif
if (cs_mode) { FATAL("Multiple -A options not supported"); }
cs_mode = 1;
fsrv.cs_mode = cs_mode;
break;
case 'O': /* FRIDA mode */
if (frida_mode) { FATAL("Multiple -O options not supported"); }
frida_mode = 1;
fsrv.frida_mode = frida_mode;
setenv("AFL_FRIDA_INST_SEED", "1", 1);
break;
case 'Q':
if (qemu_mode) { FATAL("Multiple -Q options not supported"); }
if (!mem_limit_given) { mem_limit = MEM_LIMIT_QEMU; }
qemu_mode = 1;
fsrv.mem_limit = mem_limit;
fsrv.qemu_mode = qemu_mode;
break;
case 'U':
if (unicorn_mode) { FATAL("Multiple -U options not supported"); }
if (!mem_limit_given) { mem_limit = MEM_LIMIT_UNICORN; }
unicorn_mode = 1;
fsrv.mem_limit = mem_limit;
break;
case 'W': /* Wine+QEMU mode */
if (use_wine) { FATAL("Multiple -W options not supported"); }
qemu_mode = 1;
use_wine = 1;
if (!mem_limit_given) { mem_limit = 0; }
fsrv.qemu_mode = qemu_mode;
fsrv.mem_limit = mem_limit;
break;
case 'Y': // fallthough
#ifdef __linux__
case 'X': /* NYX mode */
if (fsrv.nyx_mode) { FATAL("Multiple -X options not supported"); }
fsrv.nyx_mode = 1;
fsrv.nyx_parent = true;
fsrv.nyx_standalone = true;
break;
#else
case 'X':
FATAL("Nyx mode is only availabe on linux...");
break;
#endif
case 'h':
usage(argv[0]);
return -1;
break;
default:
usage(argv[0]);
}
}
if (optind == argc || !in_file) { usage(argv[0]); }
map_size = get_map_size();
fsrv.map_size = map_size;
use_hex_offsets = !!get_afl_env("AFL_ANALYZE_HEX");
check_environment_vars(envp);
sharedmem_t shm = {0};
/* initialize cmplog_mode */
shm.cmplog_mode = 0;
atexit(at_exit_handler);
setup_signal_handlers();
set_up_environment(argv);
#ifdef __linux__
if (!fsrv.nyx_mode) {
fsrv.target_path = find_binary(argv[optind]);
} else {
fsrv.target_path = ck_strdup(argv[optind]);
}
#else
fsrv.target_path = find_binary(argv[optind]);
#endif
fsrv.trace_bits = afl_shm_init(&shm, map_size, 0);
detect_file_args(argv + optind, fsrv.out_file, &use_stdin);
signal(SIGALRM, kill_child);
if (qemu_mode) {
if (use_wine) {
use_argv =
get_wine_argv(argv[0], &target_path, argc - optind, argv + optind);
} else {
use_argv =
get_qemu_argv(argv[0], &target_path, argc - optind, argv + optind);
}
} else if (cs_mode) {
use_argv = get_cs_argv(argv[0], &target_path, argc - optind, argv + optind);
#ifdef __linux__
} else if (fsrv.nyx_mode) {
fsrv.nyx_id = 0;
u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so");
fsrv.nyx_handlers = afl_load_libnyx_plugin(libnyx_binary);
if (fsrv.nyx_handlers == NULL) {
FATAL("failed to initialize libnyx.so...");
}
fsrv.nyx_use_tmp_workdir = true;
fsrv.nyx_bind_cpu_id = 0;
use_argv = argv + optind;
#endif
} else {
use_argv = argv + optind;
}
SAYF("\n");
if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
if (forksrv_init_tmout < 1) {
FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT");
}
fsrv.init_tmout = (u32)forksrv_init_tmout;
}
configure_afl_kill_signals(
&fsrv, NULL, NULL, (fsrv.qemu_mode || unicorn_mode) ? SIGKILL : SIGTERM);
read_initial_file();
#ifdef __linux__
if (!fsrv.nyx_mode) { (void)check_binary_signatures(fsrv.target_path); }
#else
(void)check_binary_signatures(fsrv.target_path);
#endif
ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...",
mem_limit, exec_tmout, edges_only ? ", edges only" : "");
afl_fsrv_start(&fsrv, use_argv, &stop_soon, false);
analyze_run_target(in_data, in_len, 1);
if (fsrv.last_run_timed_out) {
FATAL("Target binary times out (adjusting -t may help).");
}
if (get_afl_env("AFL_SKIP_BIN_CHECK") == NULL && !anything_set()) {
FATAL("No instrumentation detected.");
}
analyze();
OKF("We're done here. Have a nice day!\n");
afl_shm_deinit(&shm);
afl_fsrv_deinit(&fsrv);
if (fsrv.target_path) { ck_free(fsrv.target_path); }
if (in_data) { ck_free(in_data); }
exit(0);
}