mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-14 02:58:08 +00:00
Merge branch 'master' of github.com:vanhauser-thc/AFLplusplus
This commit is contained in:
13
Dockerfile
13
Dockerfile
@ -9,6 +9,9 @@ RUN apt-get update && apt-get install -y \
|
|||||||
clang \
|
clang \
|
||||||
clang-9 \
|
clang-9 \
|
||||||
flex \
|
flex \
|
||||||
|
git \
|
||||||
|
python3.7 \
|
||||||
|
python3.7-dev \
|
||||||
gcc-9 \
|
gcc-9 \
|
||||||
gcc-9-plugin-dev \
|
gcc-9-plugin-dev \
|
||||||
gcc-9-multilib \
|
gcc-9-multilib \
|
||||||
@ -23,10 +26,12 @@ RUN apt-get update && apt-get install -y \
|
|||||||
ca-certificates \
|
ca-certificates \
|
||||||
libpixman-1-dev \
|
libpixman-1-dev \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
ARG CC=gcc-9
|
ARG CC=gcc-9
|
||||||
ARG CXX=g++-9
|
ARG CXX=g++-9
|
||||||
ARG LLVM_CONFIG=llvm-config-9
|
ARG LLVM_CONFIG=llvm-config-9
|
||||||
COPY . /app
|
|
||||||
RUN cd /app && make clean && make distrib && \
|
RUN git clone https://github.com/vanhauser-thc/AFLplusplus
|
||||||
make install && cd .. && rm -rf /app
|
|
||||||
WORKDIR /work
|
RUN cd AFLplusplus && make clean && make distrib && \
|
||||||
|
make install && cd .. && rm -rf AFLplusplus
|
||||||
|
60
Makefile
60
Makefile
@ -29,27 +29,51 @@ VERSION = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2)
|
|||||||
# PROGS intentionally omit afl-as, which gets installed elsewhere.
|
# PROGS intentionally omit afl-as, which gets installed elsewhere.
|
||||||
|
|
||||||
PROGS = afl-gcc afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
|
PROGS = afl-gcc afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
|
||||||
SH_PROGS = afl-plot afl-cmin afl-whatsup afl-system-config
|
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-system-config
|
||||||
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8)
|
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8)
|
||||||
|
|
||||||
CFLAGS ?= -O3 -funroll-loops
|
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||||
CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign -I include/ \
|
CFLAGS_FLTO ?= -flto=full
|
||||||
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
|
else
|
||||||
|
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||||
|
CFLAGS_FLTO ?= -flto=thin
|
||||||
|
else
|
||||||
|
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||||
|
CFLAGS_FLTO ?= -flto
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||||
|
CFLAGS_OPT = -march=native
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq "$(shell uname -m)" "x86_64"
|
||||||
|
ifneq "$(shell uname -m)" "i386"
|
||||||
|
ifneq "$(shell uname -m)" "amd64"
|
||||||
|
AFL_NO_X86=1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
|
||||||
|
CFLAGS += -Wall -g -Wno-pointer-sign -I include/ \
|
||||||
|
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
|
||||||
-DDOC_PATH=\"$(DOC_PATH)\" -Wno-unused-function
|
-DDOC_PATH=\"$(DOC_PATH)\" -Wno-unused-function
|
||||||
|
|
||||||
AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
|
AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c)
|
||||||
|
|
||||||
ifneq "($filter %3.7m, $(shell python3.7m-config --includes 2>/dev/null)" ""
|
ifneq "$(filter %3.7m, $(shell python3.7m-config --includes 2>/dev/null))" ""
|
||||||
PYTHON_INCLUDE ?= $(shell python3.7m-config --includes)
|
PYTHON_INCLUDE ?= $(shell python3.7m-config --includes)
|
||||||
PYTHON_LIB ?= $(shell python3.7m-config --ldflags)
|
PYTHON_LIB ?= $(shell python3.7m-config --ldflags)
|
||||||
PYTHON_VERSION = 3.7m
|
PYTHON_VERSION = 3.7m
|
||||||
else
|
else
|
||||||
ifneq "($filter %3.7, $(shell python3.7-config --includes) 2> /dev/null" ""
|
ifneq "$(filter %3.7, $(shell python3.7-config --includes 2>/dev/null))" ""
|
||||||
PYTHON_INCLUDE ?= $(shell python3.7-config --includes)
|
PYTHON_INCLUDE ?= $(shell python3.7-config --includes)
|
||||||
PYTHON_LIB ?= $(shell python3.7-config --ldflags)
|
PYTHON_LIB ?= $(shell python3.7-config --ldflags)
|
||||||
PYTHON_VERSION = 3.7
|
PYTHON_VERSION = 3.7
|
||||||
else
|
else
|
||||||
ifneq "($filter %2.7, $(shell python2.7-config --includes) 2> /dev/null" ""
|
ifneq "$(filter %2.7, $(shell python2.7-config --includes 2>/dev/null))" ""
|
||||||
PYTHON_INCLUDE ?= $(shell python2.7-config --includes)
|
PYTHON_INCLUDE ?= $(shell python2.7-config --includes)
|
||||||
PYTHON_LIB ?= $(shell python2.7-config --ldflags)
|
PYTHON_LIB ?= $(shell python2.7-config --ldflags)
|
||||||
PYTHON_VERSION = 2.7
|
PYTHON_VERSION = 2.7
|
||||||
@ -61,14 +85,14 @@ PYTHON_INCLUDE ?= $(shell test -e /usr/include/python3.7m && echo /usr/include/p
|
|||||||
PYTHON_INCLUDE ?= $(shell test -e /usr/include/python3.7 && echo /usr/include/python3.7)
|
PYTHON_INCLUDE ?= $(shell test -e /usr/include/python3.7 && echo /usr/include/python3.7)
|
||||||
PYTHON_INCLUDE ?= $(shell test -e /usr/include/python2.7 && echo /usr/include/python2.7)
|
PYTHON_INCLUDE ?= $(shell test -e /usr/include/python2.7 && echo /usr/include/python2.7)
|
||||||
|
|
||||||
ifneq "($filter %3.7m, $(PYTHON_INCLUDE))" ""
|
ifneq "$(filter %3.7m, $(PYTHON_INCLUDE))" ""
|
||||||
PYTHON_VERSION ?= 3.7m
|
PYTHON_VERSION ?= 3.7m
|
||||||
PYTHON_LIB ?= -lpython3.7m
|
PYTHON_LIB ?= -lpython3.7m
|
||||||
else
|
else
|
||||||
ifneq "($filter %3.7, $(PYTHON_INCLUDE))" ""
|
ifneq "$(filter %3.7, $(PYTHON_INCLUDE))" ""
|
||||||
PYTHON_VERSION ?= 3.7
|
PYTHON_VERSION ?= 3.7
|
||||||
else
|
else
|
||||||
ifneq "($filter %2.7, $(PYTHON_INCLUDE))" ""
|
ifneq "$(filter %2.7, $(PYTHON_INCLUDE))" ""
|
||||||
PYTHON_VERSION ?= 2.7
|
PYTHON_VERSION ?= 2.7
|
||||||
PYTHON_LIB ?= -lpython2.7
|
PYTHON_LIB ?= -lpython2.7
|
||||||
else
|
else
|
||||||
@ -229,31 +253,31 @@ afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
|
|||||||
ln -sf afl-as as
|
ln -sf afl-as as
|
||||||
|
|
||||||
src/afl-common.o : src/afl-common.c include/common.h
|
src/afl-common.o : src/afl-common.c include/common.h
|
||||||
$(CC) $(CFLAGS) -c src/afl-common.c -o src/afl-common.o
|
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-common.c -o src/afl-common.o
|
||||||
|
|
||||||
src/afl-forkserver.o : src/afl-forkserver.c include/forkserver.h
|
src/afl-forkserver.o : src/afl-forkserver.c include/forkserver.h
|
||||||
$(CC) $(CFLAGS) -c src/afl-forkserver.c -o src/afl-forkserver.o
|
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-forkserver.c -o src/afl-forkserver.o
|
||||||
|
|
||||||
src/afl-sharedmem.o : src/afl-sharedmem.c include/sharedmem.h
|
src/afl-sharedmem.o : src/afl-sharedmem.c include/sharedmem.h
|
||||||
$(CC) $(CFLAGS) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
|
$(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
|
||||||
|
|
||||||
radamsa: src/third_party/libradamsa/libradamsa.so
|
radamsa: src/third_party/libradamsa/libradamsa.so
|
||||||
cp src/third_party/libradamsa/libradamsa.so .
|
cp src/third_party/libradamsa/libradamsa.so .
|
||||||
|
|
||||||
src/third_party/libradamsa/libradamsa.so: src/third_party/libradamsa/libradamsa.c src/third_party/libradamsa/radamsa.h
|
src/third_party/libradamsa/libradamsa.so: src/third_party/libradamsa/libradamsa.c src/third_party/libradamsa/radamsa.h
|
||||||
$(MAKE) -C src/third_party/libradamsa/
|
$(MAKE) -C src/third_party/libradamsa/ CFLAGS="$(CFLAGS)"
|
||||||
|
|
||||||
afl-fuzz: include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
|
afl-fuzz: include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
|
||||||
$(CC) $(CFLAGS) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(PYFLAGS) $(LDFLAGS)
|
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(PYFLAGS) $(LDFLAGS)
|
||||||
|
|
||||||
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o $(COMM_HDR) | test_x86
|
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o $(COMM_HDR) | test_x86
|
||||||
$(CC) $(CFLAGS) src/$@.c src/afl-common.o src/afl-sharedmem.o -o $@ $(LDFLAGS)
|
$(CC) $(CFLAGS) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
|
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86
|
||||||
$(CC) $(CFLAGS) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
|
$(CC) $(CFLAGS) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o $(COMM_HDR) | test_x86
|
afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o $(COMM_HDR) | test_x86
|
||||||
$(CC) $(CFLAGS) src/$@.c src/afl-common.o src/afl-sharedmem.o -o $@ $(LDFLAGS)
|
$(CC) $(CFLAGS) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
afl-gotcpu: src/afl-gotcpu.c $(COMM_HDR) | test_x86
|
afl-gotcpu: src/afl-gotcpu.c $(COMM_HDR) | test_x86
|
||||||
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
|
||||||
|
6
TODO
6
TODO
@ -2,6 +2,12 @@
|
|||||||
Roadmap 2.61+:
|
Roadmap 2.61+:
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
Makefile:
|
||||||
|
- -march=native -Ofast -flto=full
|
||||||
|
|
||||||
|
afl-fuzz:
|
||||||
|
- sync_fuzzers(): only masters sync from all, slaves only sync from master
|
||||||
|
|
||||||
gcc_plugin:
|
gcc_plugin:
|
||||||
- laf-intel
|
- laf-intel
|
||||||
- better instrumentation
|
- better instrumentation
|
||||||
|
864
afl-cmin
864
afl-cmin
@ -1,470 +1,464 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env sh
|
||||||
|
THISPATH=`dirname ${0}`
|
||||||
|
export PATH=${THISPATH}:$PATH
|
||||||
|
awk -f - -- ${@+"$@"} <<'EOF'
|
||||||
|
#!/usr/bin/awk -f
|
||||||
|
|
||||||
|
# awk script to minimize a test corpus of input files
|
||||||
#
|
#
|
||||||
# american fuzzy lop++ - corpus minimization tool
|
# based on afl-cmin bash script written by Michal Zalewski
|
||||||
# ---------------------------------------------
|
# rewritten by Heiko Eißfeldt (hexcoder-)
|
||||||
|
# tested with:
|
||||||
|
# gnu awk (x86 Linux)
|
||||||
|
# bsd awk (x86 *BSD)
|
||||||
|
# mawk (arm32 raspbian)
|
||||||
#
|
#
|
||||||
# Originally written by Michal Zalewski
|
# uses getopt.awk package from Arnold Robbins
|
||||||
#
|
|
||||||
# Copyright 2014, 2015 Google Inc. 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:
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# This tool tries to find the smallest subset of files in the input directory
|
|
||||||
# that still trigger the full range of instrumentation data points seen in
|
|
||||||
# the starting corpus. This has two uses:
|
|
||||||
#
|
|
||||||
# - Screening large corpora of input files before using them as a seed for
|
|
||||||
# afl-fuzz. The tool will remove functionally redundant files and likely
|
|
||||||
# leave you with a much smaller set.
|
|
||||||
#
|
|
||||||
# (In this case, you probably also want to consider running afl-tmin on
|
|
||||||
# the individual files later on to reduce their size.)
|
|
||||||
#
|
|
||||||
# - Minimizing the corpus generated organically by afl-fuzz, perhaps when
|
|
||||||
# planning to feed it to more resource-intensive tools. The tool achieves
|
|
||||||
# this by removing all entries that used to trigger unique behaviors in the
|
|
||||||
# past, but have been made obsolete by later finds.
|
|
||||||
#
|
|
||||||
# Note that the tool doesn't modify the files themselves. For that, you want
|
|
||||||
# afl-tmin.
|
|
||||||
#
|
|
||||||
# This script must use bash because other shells may have hardcoded limits on
|
|
||||||
# array sizes.
|
|
||||||
#
|
#
|
||||||
|
# external tools used by this script:
|
||||||
|
# test
|
||||||
|
# grep
|
||||||
|
# rm
|
||||||
|
# mkdir
|
||||||
|
# ln
|
||||||
|
# cp
|
||||||
|
# pwd
|
||||||
|
# which
|
||||||
|
# cd
|
||||||
|
# find
|
||||||
|
# stat
|
||||||
|
# sort
|
||||||
|
# cut
|
||||||
|
# and afl-showmap from this project :-)
|
||||||
|
|
||||||
echo "corpus minimization tool for afl-fuzz by Michal Zalewski"
|
# getopt.awk --- Do C library getopt(3) function in awk
|
||||||
echo
|
|
||||||
|
|
||||||
#########
|
# External variables:
|
||||||
# SETUP #
|
# Optind -- index in ARGV of first nonoption argument
|
||||||
#########
|
# Optarg -- string value of argument to current option
|
||||||
|
# Opterr -- if nonzero, print our own diagnostic
|
||||||
|
# Optopt -- current option letter
|
||||||
|
|
||||||
# Process command-line options...
|
# Returns:
|
||||||
|
# -1 at end of options
|
||||||
|
# "?" for unrecognized option
|
||||||
|
# <c> a character representing the current option
|
||||||
|
|
||||||
MEM_LIMIT=200
|
# Private Data:
|
||||||
TIMEOUT=none
|
# _opti -- index in multiflag option, e.g., -abc
|
||||||
|
|
||||||
unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \
|
function getopt(argc, argv, options, thisopt, i)
|
||||||
AFL_CMIN_CRASHES_ONLY AFL_CMIN_ALLOW_ANY QEMU_MODE UNICORN_MODE
|
{
|
||||||
|
if (length(options) == 0) # no options given
|
||||||
|
return -1
|
||||||
|
|
||||||
while getopts "+i:o:f:m:t:eQUCh" opt; do
|
if (argv[Optind] == "--") { # all done
|
||||||
|
Optind++
|
||||||
|
_opti = 0
|
||||||
|
return -1
|
||||||
|
} else if (argv[Optind] !~ /^-[^:\t ]/) {
|
||||||
|
_opti = 0
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if (_opti == 0)
|
||||||
|
_opti = 2
|
||||||
|
thisopt = substr(argv[Optind], _opti, 1)
|
||||||
|
Optopt = thisopt
|
||||||
|
i = index(options, thisopt)
|
||||||
|
if (i == 0) {
|
||||||
|
if (Opterr)
|
||||||
|
printf("%c -- invalid option\n", thisopt) > "/dev/stderr"
|
||||||
|
if (_opti >= length(argv[Optind])) {
|
||||||
|
Optind++
|
||||||
|
_opti = 0
|
||||||
|
} else
|
||||||
|
_opti++
|
||||||
|
return "?"
|
||||||
|
}
|
||||||
|
if (substr(options, i + 1, 1) == ":") {
|
||||||
|
# get option argument
|
||||||
|
if (length(substr(argv[Optind], _opti + 1)) > 0)
|
||||||
|
Optarg = substr(argv[Optind], _opti + 1)
|
||||||
|
else
|
||||||
|
Optarg = argv[++Optind]
|
||||||
|
_opti = 0
|
||||||
|
} else
|
||||||
|
Optarg = ""
|
||||||
|
if (_opti == 0 || _opti >= length(argv[Optind])) {
|
||||||
|
Optind++
|
||||||
|
_opti = 0
|
||||||
|
} else
|
||||||
|
_opti++
|
||||||
|
return thisopt
|
||||||
|
}
|
||||||
|
|
||||||
case "$opt" in
|
function usage() {
|
||||||
|
print \
|
||||||
|
"Usage: afl-cmin [ options ] -- /path/to/target_app [ ... ]\n" \
|
||||||
|
"\n" \
|
||||||
|
"Required parameters:\n" \
|
||||||
|
"\n" \
|
||||||
|
" -i dir - input directory with starting corpus\n" \
|
||||||
|
" -o dir - output directory for minimized files\n" \
|
||||||
|
"\n" \
|
||||||
|
"Execution control settings:\n" \
|
||||||
|
"\n" \
|
||||||
|
" -f file - location read by the fuzzed program (stdin)\n" \
|
||||||
|
" -m megs - memory limit for child process ("mem_limit" MB)\n" \
|
||||||
|
" -t msec - run time limit for child process (none)\n" \
|
||||||
|
" -Q - use binary-only instrumentation (QEMU mode)\n" \
|
||||||
|
" -U - use unicorn-based instrumentation (unicorn mode)\n" \
|
||||||
|
"\n" \
|
||||||
|
"Minimization settings:\n" \
|
||||||
|
" -C - keep crashing inputs, reject everything else\n" \
|
||||||
|
" -e - solve for edge coverage only, ignore hit counts\n" \
|
||||||
|
"\n" \
|
||||||
|
"For additional tips, please consult docs/README.md\n" \
|
||||||
|
"\n" \
|
||||||
|
> "/dev/stderr"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
"h")
|
function exists_and_is_executable(binarypath) {
|
||||||
;;
|
return 0 == system("test -f "binarypath" -a -x "binarypath)
|
||||||
|
}
|
||||||
|
|
||||||
"i")
|
BEGIN {
|
||||||
IN_DIR="$OPTARG"
|
print "corpus minimization tool for afl++ (awk version)\n"
|
||||||
;;
|
|
||||||
|
|
||||||
"o")
|
# defaults
|
||||||
OUT_DIR="$OPTARG"
|
extra_par = ""
|
||||||
;;
|
# process options
|
||||||
"f")
|
Opterr = 1 # default is to diagnose
|
||||||
STDIN_FILE="$OPTARG"
|
Optind = 1 # skip ARGV[0]
|
||||||
;;
|
while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eCQU?")) != -1) {
|
||||||
"m")
|
if (_go_c == "i") {
|
||||||
MEM_LIMIT="$OPTARG"
|
if (!Optarg) usage()
|
||||||
MEM_LIMIT_GIVEN=1
|
if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||||
;;
|
in_dir = Optarg
|
||||||
"t")
|
continue
|
||||||
TIMEOUT="$OPTARG"
|
} else
|
||||||
;;
|
if (_go_c == "o") {
|
||||||
"e")
|
if (!Optarg) usage()
|
||||||
EXTRA_PAR="$EXTRA_PAR -e"
|
if (out_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||||
;;
|
out_dir = Optarg
|
||||||
"C")
|
continue
|
||||||
export AFL_CMIN_CRASHES_ONLY=1
|
} else
|
||||||
;;
|
if (_go_c == "f") {
|
||||||
"Q")
|
if (!Optarg) usage()
|
||||||
EXTRA_PAR="$EXTRA_PAR -Q"
|
if (stdin_file) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||||
test "$MEM_LIMIT_GIVEN" = "" && MEM_LIMIT=250
|
stdin_file = Optarg
|
||||||
QEMU_MODE=1
|
continue
|
||||||
;;
|
} else
|
||||||
"U")
|
if (_go_c == "m") {
|
||||||
EXTRA_PAR="$EXTRA_PAR -U"
|
if (!Optarg) usage()
|
||||||
test "$MEM_LIMIT_GIVEN" = "" && MEM_LIMIT=250
|
if (mem_limit) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||||
UNICORN_MODE=1
|
mem_limit = Optarg
|
||||||
;;
|
mem_limit_given = 1
|
||||||
"?")
|
continue
|
||||||
exit 1
|
} else
|
||||||
;;
|
if (_go_c == "t") {
|
||||||
|
if (!Optarg) usage()
|
||||||
|
if (timeout) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||||
|
timeout = Optarg
|
||||||
|
continue
|
||||||
|
} else
|
||||||
|
if (_go_c == "C") {
|
||||||
|
ENVIRON["AFL_CMIN_CRASHES_ONLY"] = 1
|
||||||
|
continue
|
||||||
|
} else
|
||||||
|
if (_go_c == "e") {
|
||||||
|
extra_par = extra_par " -e"
|
||||||
|
continue
|
||||||
|
} else
|
||||||
|
if (_go_c == "Q") {
|
||||||
|
if (qemu_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||||
|
extra_par = extra_par " -Q"
|
||||||
|
if ( !mem_limit_given ) mem_limit = "250"
|
||||||
|
qemu_mode = 1
|
||||||
|
continue
|
||||||
|
} else
|
||||||
|
if (_go_c == "U") {
|
||||||
|
if (unicorn_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||||
|
extra_par = extra_par " -U"
|
||||||
|
if ( !mem_limit_given ) mem_limit = "250"
|
||||||
|
unicorn_mode = 1
|
||||||
|
continue
|
||||||
|
} else
|
||||||
|
if (_go_c == "?") {
|
||||||
|
exit 1
|
||||||
|
} else
|
||||||
|
usage()
|
||||||
|
} # while options
|
||||||
|
|
||||||
esac
|
if (!mem_limit) mem_limit = 200
|
||||||
|
if (!timeout) timeout = "none"
|
||||||
|
|
||||||
done
|
# get program args
|
||||||
|
i = 0
|
||||||
|
prog_args_string = ""
|
||||||
|
for (; Optind < ARGC; Optind++) {
|
||||||
|
prog_args[i++] = ARGV[Optind]
|
||||||
|
if (i > 1)
|
||||||
|
prog_args_string = prog_args_string" "ARGV[Optind]
|
||||||
|
}
|
||||||
|
|
||||||
shift $((OPTIND-1))
|
# sanity checks
|
||||||
|
if (!prog_args[0] || !in_dir || !out_dir) usage()
|
||||||
|
|
||||||
TARGET_BIN="$1"
|
target_bin = prog_args[0]
|
||||||
|
|
||||||
if [ "$TARGET_BIN" = "" -o "$IN_DIR" = "" -o "$OUT_DIR" = "" ]; then
|
# Do a sanity check to discourage the use of /tmp, since we can't really
|
||||||
|
# handle this safely from an awk script.
|
||||||
|
|
||||||
cat 1>&2 <<_EOF_
|
if (!ENVIRON["AFL_ALLOW_TMP"]) {
|
||||||
Usage: $0 [ options ] -- /path/to/target_app [ ... ]
|
dirlist[0] = in_dir
|
||||||
|
dirlist[1] = target_bin
|
||||||
|
dirlist[2] = out_dir
|
||||||
|
dirlist[3] = stdin_file
|
||||||
|
"pwd" | getline dirlist[4] # current directory
|
||||||
|
for (dirind in dirlist) {
|
||||||
|
dir = dirlist[dirind]
|
||||||
|
|
||||||
Required parameters:
|
if (dir ~ /^(\/var)?\/tmp/) {
|
||||||
|
print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete dirlist
|
||||||
|
}
|
||||||
|
|
||||||
-i dir - input directory with the starting corpus
|
# If @@ is specified, but there's no -f, let's come up with a temporary input
|
||||||
-o dir - output directory for minimized files
|
# file name.
|
||||||
|
|
||||||
Execution control settings:
|
trace_dir = out_dir "/.traces"
|
||||||
|
|
||||||
-f file - location read by the fuzzed program (stdin)
|
if (!stdin_file) {
|
||||||
-m megs - memory limit for child process ($MEM_LIMIT MB)
|
found_atat = 0
|
||||||
-t msec - run time limit for child process (none)
|
for (prog_args_ind in prog_args) {
|
||||||
-Q - use binary-only instrumentation (QEMU mode)
|
if ("@@" == prog_args[prog_args_ind]) {
|
||||||
-U - use unicorn-based instrumentation (Unicorn mode)
|
found_atat = 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found_atat) {
|
||||||
|
stdin_file = trace_dir "/.cur_input"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check for obvious errors.
|
||||||
|
|
||||||
|
if (mem_limit && mem_limit != "none" && mem_limit < 5) {
|
||||||
|
print "[-] Error: dangerously low memory limit." > "/dev/stderr"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout && timeout != "none" && timeout < 10) {
|
||||||
|
print "[-] Error: dangerously low timeout." > "/dev/stderr"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_bin && !exists_and_is_executable(target_bin)) {
|
||||||
|
|
||||||
|
"which "target_bin" 2>/dev/null" | getline tnew
|
||||||
|
if (!tnew || !exists_and_is_executable(tnew)) {
|
||||||
|
print "[-] Error: binary '"target_bin"' not found or not executable." > "/dev/stderr"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
target_bin = tnew
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !unicorn_mode) {
|
||||||
|
if (0 != system( "grep -q __AFL_SHM_ID "target_bin )) {
|
||||||
|
print "[-] Error: binary '"target_bin"' doesn't appear to be instrumented." > "/dev/stderr"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != system( "test -d "in_dir )) {
|
||||||
|
print "[-] Error: directory '"in_dir"' not found." > "/dev/stderr"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == system( "test -d "in_dir"/queue" )) {
|
||||||
|
in_dir = in_dir "/queue"
|
||||||
|
}
|
||||||
|
|
||||||
|
system("rm -rf "trace_dir" 2>/dev/null");
|
||||||
|
system("rm "out_dir"/id[:_]* 2>/dev/null")
|
||||||
|
|
||||||
|
if (0 == system( "test -d "out_dir" -a -e "out_dir"/*" )) {
|
||||||
|
print "[-] Error: directory '"out_dir"' exists and is not empty - delete it first." > "/dev/stderr"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check for the more efficient way to copy files...
|
||||||
|
if (0 != system("mkdir -p -m 0700 "trace_dir)) {
|
||||||
|
print "[-] Error: Cannot create directory "trace_dir > "/dev/stderr"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stdin_file) {
|
||||||
|
# truncate input file
|
||||||
|
printf "" > stdin_file
|
||||||
|
close( stdin_file )
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ENVIRON["AFL_PATH"]) {
|
||||||
|
if (0 == system("test -f afl-cmin")) {
|
||||||
|
showmap = "./afl-showmap"
|
||||||
|
} else {
|
||||||
|
"which afl-showmap 2>/dev/null" | getline showmap
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showmap = ENVIRON["AFL_PATH"] "/afl-showmap"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!showmap || 0 != system("test -x "showmap )) {
|
||||||
|
print "[-] Error: can't find 'afl-showmap' - please set AFL_PATH." > "/dev/stderr"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
Minimization settings:
|
# get list of input filenames sorted by size
|
||||||
|
i = 0
|
||||||
|
# yuck, gnu stat is option incompatible to bsd stat
|
||||||
|
# we use a heuristic to differentiate between
|
||||||
|
# GNU stat and other stats
|
||||||
|
"stat --version 2>/dev/null" | getline statversion
|
||||||
|
if (statversion ~ /GNU coreutils/) {
|
||||||
|
stat_format = "-c '%s %n'" # GNU
|
||||||
|
} else {
|
||||||
|
stat_format = "-f '%z %N'" # *BSD, MacOS
|
||||||
|
}
|
||||||
|
cmdline = "cd "in_dir" && find . -maxdepth 1 -type f -exec stat "stat_format" \\{\\} \\; | sort -n | cut -d' ' -f2-"
|
||||||
|
while (cmdline | getline) {
|
||||||
|
infilesSmallToBig[i++] = $0
|
||||||
|
}
|
||||||
|
in_count = i
|
||||||
|
|
||||||
-C - keep crashing inputs, reject everything else
|
first_file = infilesSmallToBig[0]
|
||||||
-e - solve for edge coverage only, ignore hit counts
|
|
||||||
|
# Make sure that we're not dealing with a directory.
|
||||||
|
|
||||||
For additional tips, please consult docs/README.
|
if (0 == system("test -d "in_dir"/"first_file)) {
|
||||||
|
print "[-] Error: The input directory contains subdirectories - please fix." > "/dev/stderr"
|
||||||
_EOF_
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Do a sanity check to discourage the use of /tmp, since we can't really
|
|
||||||
# handle this safely from a shell script.
|
|
||||||
|
|
||||||
if [ "$AFL_ALLOW_TMP" = "" ]; then
|
|
||||||
|
|
||||||
echo "$IN_DIR" | grep -qE '^(/var)?/tmp/'
|
|
||||||
T1="$?"
|
|
||||||
|
|
||||||
echo "$TARGET_BIN" | grep -qE '^(/var)?/tmp/'
|
|
||||||
T2="$?"
|
|
||||||
|
|
||||||
echo "$OUT_DIR" | grep -qE '^(/var)?/tmp/'
|
|
||||||
T3="$?"
|
|
||||||
|
|
||||||
echo "$STDIN_FILE" | grep -qE '^(/var)?/tmp/'
|
|
||||||
T4="$?"
|
|
||||||
|
|
||||||
echo "$PWD" | grep -qE '^(/var)?/tmp/'
|
|
||||||
T5="$?"
|
|
||||||
|
|
||||||
if [ "$T1" = "0" -o "$T2" = "0" -o "$T3" = "0" -o "$T4" = "0" -o "$T5" = "0" ]; then
|
|
||||||
echo "[-] Error: do not use this script in /tmp or /var/tmp." 1>&2
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
}
|
||||||
|
|
||||||
fi
|
if (0 == system("ln "in_dir"/"first_file" "trace_dir"/.link_test")) {
|
||||||
|
cp_tool = "ln"
|
||||||
|
} else {
|
||||||
|
cp_tool = "cp"
|
||||||
|
}
|
||||||
|
|
||||||
# If @@ is specified, but there's no -f, let's come up with a temporary input
|
# Make sure that we can actually get anything out of afl-showmap before we
|
||||||
# file name.
|
# waste too much time.
|
||||||
|
|
||||||
TRACE_DIR="$OUT_DIR/.traces"
|
print "[*] Testing the target binary..."
|
||||||
|
|
||||||
if [ "$STDIN_FILE" = "" ]; then
|
if (!stdin_file) {
|
||||||
|
system( "AFL_CMIN_ALLOW_ANY=1 \""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -- \""target_bin"\" "prog_args_string" <\""in_dir"/"first_file"\"")
|
||||||
|
} else {
|
||||||
|
system("cp "in_dir"/"first_file" "stdin_file)
|
||||||
|
system( "AFL_CMIN_ALLOW_ANY=1 \""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/.run_test\" -Z "extra_par" -A \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
|
||||||
|
}
|
||||||
|
|
||||||
if echo "$*" | grep -qF '@@'; then
|
first_count = 0
|
||||||
STDIN_FILE="$TRACE_DIR/.cur_input"
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
runtest = trace_dir"/.run_test"
|
||||||
|
while ((getline < runtest) > 0) {
|
||||||
|
++first_count
|
||||||
|
}
|
||||||
|
|
||||||
# Check for obvious errors.
|
if (first_count) {
|
||||||
|
print "[+] OK, "first_count" tuples recorded."
|
||||||
if [ ! "$MEM_LIMIT" = "none" ]; then
|
} else {
|
||||||
|
print "[-] Error: no instrumentation output detected (perhaps crash or timeout)." > "/dev/stderr"
|
||||||
if [ "$MEM_LIMIT" -lt "5" ]; then
|
if (!ENVIRON["AFL_KEEP_TRACES"]) {
|
||||||
echo "[-] Error: dangerously low memory limit." 1>&2
|
system("rm -rf "trace_dir" 2>/dev/null")
|
||||||
|
}
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
}
|
||||||
|
|
||||||
fi
|
# Let's roll!
|
||||||
|
|
||||||
if [ ! "$TIMEOUT" = "none" ]; then
|
#############################
|
||||||
|
# STEP 1: Collecting traces #
|
||||||
if [ "$TIMEOUT" -lt "10" ]; then
|
#############################
|
||||||
echo "[-] Error: dangerously low timeout." 1>&2
|
|
||||||
exit 1
|
print "[*] Obtaining traces for "in_count" input files in '"in_dir"'."
|
||||||
fi
|
|
||||||
|
cur = 0;
|
||||||
fi
|
if (!stdin_file) {
|
||||||
|
while (cur < in_count) {
|
||||||
if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then
|
fn = infilesSmallToBig[cur]
|
||||||
|
++cur;
|
||||||
TNEW="`which "$TARGET_BIN" 2>/dev/null`"
|
printf "\r Processing file "cur"/"in_count
|
||||||
|
system( "AFL_CMIN_ALLOW_ANY=1 \""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/"fn"\" -Z "extra_par" -- \""target_bin"\" "prog_args_string" <\""in_dir"/"fn"\"")
|
||||||
if [ ! -f "$TNEW" -o ! -x "$TNEW" ]; then
|
}
|
||||||
echo "[-] Error: binary '$TARGET_BIN' not found or not executable." 1>&2
|
} else {
|
||||||
exit 1
|
while (cur < in_count) {
|
||||||
fi
|
fn = infilesSmallToBig[cur]
|
||||||
|
++cur
|
||||||
TARGET_BIN="$TNEW"
|
printf "\r Processing file "cur"/"in_count
|
||||||
|
system("cp "in_dir"/"fn" "stdin_file)
|
||||||
fi
|
system( "AFL_CMIN_ALLOW_ANY=1 \""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"/"fn"\" -Z "extra_par" -A \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null")
|
||||||
|
}
|
||||||
if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$UNICORN_MODE" = "" ]; then
|
}
|
||||||
|
|
||||||
if ! grep -qF "__AFL_SHM_ID" "$TARGET_BIN"; then
|
print ""
|
||||||
echo "[-] Error: binary '$TARGET_BIN' doesn't appear to be instrumented." 1>&2
|
|
||||||
exit 1
|
|
||||||
fi
|
#######################################################
|
||||||
|
# STEP 2: register smallest input file for each tuple #
|
||||||
fi
|
# STEP 3: copy that file (at most once) #
|
||||||
|
#######################################################
|
||||||
if [ ! -d "$IN_DIR" ]; then
|
|
||||||
echo "[-] Error: directory '$IN_DIR' not found." 1>&2
|
print "[*] Processing traces for input files in '"in_dir"'."
|
||||||
exit 1
|
|
||||||
fi
|
cur = 0
|
||||||
|
out_count = 0
|
||||||
test -d "$IN_DIR/queue" && IN_DIR="$IN_DIR/queue"
|
tuple_count = 0
|
||||||
|
|
||||||
find "$OUT_DIR" -name 'id[:_]*' -maxdepth 1 -exec rm -- {} \; 2>/dev/null
|
while (cur < in_count) {
|
||||||
rm -rf "$TRACE_DIR" 2>/dev/null
|
fn = infilesSmallToBig[cur]
|
||||||
|
++cur
|
||||||
rmdir "$OUT_DIR" 2>/dev/null
|
printf "\r Processing file "cur"/"in_count
|
||||||
|
# create path for the trace file from afl-showmap
|
||||||
if [ -d "$OUT_DIR" ]; then
|
tracefile_path = trace_dir"/"fn
|
||||||
echo "[-] Error: directory '$OUT_DIR' exists and is not empty - delete it first." 1>&2
|
# gather all keys, and count them
|
||||||
exit 1
|
while ((getline line < tracefile_path) > 0) {
|
||||||
fi
|
key = line
|
||||||
|
if (!(key in key_count)) {
|
||||||
mkdir -m 700 -p "$TRACE_DIR" || exit 1
|
++tuple_count
|
||||||
|
}
|
||||||
if [ ! "$STDIN_FILE" = "" ]; then
|
++key_count[key]
|
||||||
rm -f "$STDIN_FILE" || exit 1
|
if (! (key in best_file)) {
|
||||||
touch "$STDIN_FILE" || exit 1
|
# this is the best file for this key
|
||||||
fi
|
best_file[key] = fn
|
||||||
|
# copy file unless already done
|
||||||
if [ "$AFL_PATH" = "" ]; then
|
if (! (fn in file_already_copied)) {
|
||||||
SHOWMAP="${0%/afl-cmin}/afl-showmap"
|
system(cp_tool" "in_dir"/"fn" "out_dir"/"fn)
|
||||||
else
|
file_already_copied[fn] = ""
|
||||||
SHOWMAP="$AFL_PATH/afl-showmap"
|
++out_count
|
||||||
fi
|
}
|
||||||
|
}
|
||||||
if [ ! -x "$SHOWMAP" ]; then
|
}
|
||||||
echo "[-] Error: can't find 'afl-showmap' - please set AFL_PATH." 1>&2
|
close(tracefile_path)
|
||||||
rm -rf "$TRACE_DIR"
|
}
|
||||||
exit 1
|
|
||||||
fi
|
print ""
|
||||||
|
print "[+] Found "tuple_count" unique tuples across "in_count" files."
|
||||||
IN_COUNT=$((`ls -- "$IN_DIR" 2>/dev/null | wc -l`))
|
|
||||||
|
if (out_count == 1) {
|
||||||
if [ "$IN_COUNT" = "0" ]; then
|
print "[!] WARNING: All test cases had the same traces, check syntax!"
|
||||||
echo "[+] Hmm, no inputs in the target directory. Nothing to be done."
|
}
|
||||||
rm -rf "$TRACE_DIR"
|
print "[+] Narrowed down to "out_count" files, saved in '"out_dir"'."
|
||||||
exit 1
|
|
||||||
fi
|
if (!ENVIRON["AFL_KEEP_TRACES"]) {
|
||||||
|
system("rm -rf "trace_dir" 2>/dev/null")
|
||||||
FIRST_FILE=`ls "$IN_DIR" | head -1`
|
}
|
||||||
|
|
||||||
# Make sure that we're not dealing with a directory.
|
exit 0
|
||||||
|
}
|
||||||
if [ -d "$IN_DIR/$FIRST_FILE" ]; then
|
EOF
|
||||||
echo "[-] Error: The target directory contains subdirectories - please fix." 1>&2
|
|
||||||
rm -rf "$TRACE_DIR"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check for the more efficient way to copy files...
|
|
||||||
|
|
||||||
if ln "$IN_DIR/$FIRST_FILE" "$TRACE_DIR/.link_test" 2>/dev/null; then
|
|
||||||
CP_TOOL=ln
|
|
||||||
else
|
|
||||||
CP_TOOL=cp
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Make sure that we can actually get anything out of afl-showmap before we
|
|
||||||
# waste too much time.
|
|
||||||
|
|
||||||
echo "[*] Testing the target binary..."
|
|
||||||
|
|
||||||
if [ "$STDIN_FILE" = "" ]; then
|
|
||||||
|
|
||||||
AFL_CMIN_ALLOW_ANY=1 "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/.run_test" -Z $EXTRA_PAR -- "$@" <"$IN_DIR/$FIRST_FILE"
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
cp "$IN_DIR/$FIRST_FILE" "$STDIN_FILE"
|
|
||||||
AFL_CMIN_ALLOW_ANY=1 "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/.run_test" -Z $EXTRA_PAR -A "$STDIN_FILE" -- "$@" </dev/null
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
FIRST_COUNT=$((`grep -c . "$TRACE_DIR/.run_test"`))
|
|
||||||
|
|
||||||
if [ "$FIRST_COUNT" -gt "0" ]; then
|
|
||||||
|
|
||||||
echo "[+] OK, $FIRST_COUNT tuples recorded."
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
echo "[-] Error: no instrumentation output detected (perhaps crash or timeout)." 1>&2
|
|
||||||
test "$AFL_KEEP_TRACES" = "" && rm -rf "$TRACE_DIR"
|
|
||||||
exit 1
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Let's roll!
|
|
||||||
|
|
||||||
#############################
|
|
||||||
# STEP 1: COLLECTING TRACES #
|
|
||||||
#############################
|
|
||||||
|
|
||||||
echo "[*] Obtaining traces for input files in '$IN_DIR'..."
|
|
||||||
|
|
||||||
(
|
|
||||||
|
|
||||||
CUR=0
|
|
||||||
|
|
||||||
if [ "$STDIN_FILE" = "" ]; then
|
|
||||||
|
|
||||||
ls "$IN_DIR" | while read -r fn; do
|
|
||||||
|
|
||||||
CUR=$((CUR+1))
|
|
||||||
printf "\\r Processing file $CUR/$IN_COUNT... "
|
|
||||||
|
|
||||||
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -- "$@" <"$IN_DIR/$fn"
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
ls "$IN_DIR" | while read -r fn; do
|
|
||||||
|
|
||||||
CUR=$((CUR+1))
|
|
||||||
printf "\\r Processing file $CUR/$IN_COUNT... "
|
|
||||||
|
|
||||||
cp "$IN_DIR/$fn" "$STDIN_FILE"
|
|
||||||
|
|
||||||
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -A "$STDIN_FILE" -- "$@" </dev/null
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
echo
|
|
||||||
|
|
||||||
##########################
|
|
||||||
# STEP 2: SORTING TUPLES #
|
|
||||||
##########################
|
|
||||||
|
|
||||||
# With this out of the way, we sort all tuples by popularity across all
|
|
||||||
# datasets. The reasoning here is that we won't be able to avoid the files
|
|
||||||
# that trigger unique tuples anyway, so we will want to start with them and
|
|
||||||
# see what's left.
|
|
||||||
|
|
||||||
echo "[*] Sorting trace sets (this may take a while)..."
|
|
||||||
|
|
||||||
ls "$IN_DIR" | sed "s#^#$TRACE_DIR/#" | tr '\n' '\0' | xargs -0 -n 1 cat | \
|
|
||||||
sort | uniq -c | sort -k 1,1 -n >"$TRACE_DIR/.all_uniq"
|
|
||||||
|
|
||||||
TUPLE_COUNT=$((`grep -c . "$TRACE_DIR/.all_uniq"`))
|
|
||||||
|
|
||||||
echo "[+] Found $TUPLE_COUNT unique tuples across $IN_COUNT files."
|
|
||||||
|
|
||||||
#####################################
|
|
||||||
# STEP 3: SELECTING CANDIDATE FILES #
|
|
||||||
#####################################
|
|
||||||
|
|
||||||
# The next step is to find the best candidate for each tuple. The "best"
|
|
||||||
# part is understood simply as the smallest input that includes a particular
|
|
||||||
# tuple in its trace. Empirical evidence suggests that this produces smaller
|
|
||||||
# datasets than more involved algorithms that could be still pulled off in
|
|
||||||
# a shell script.
|
|
||||||
|
|
||||||
echo "[*] Finding best candidates for each tuple..."
|
|
||||||
|
|
||||||
CUR=0
|
|
||||||
|
|
||||||
ls -rS "$IN_DIR" | while read -r fn; do
|
|
||||||
|
|
||||||
CUR=$((CUR+1))
|
|
||||||
printf "\\r Processing file $CUR/$IN_COUNT... "
|
|
||||||
|
|
||||||
sed "s#\$# $fn#" "$TRACE_DIR/$fn" >>"$TRACE_DIR/.candidate_list"
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
||||||
echo
|
|
||||||
|
|
||||||
##############################
|
|
||||||
# STEP 4: LOADING CANDIDATES #
|
|
||||||
##############################
|
|
||||||
|
|
||||||
# At this point, we have a file of tuple-file pairs, sorted by file size
|
|
||||||
# in ascending order (as a consequence of ls -rS). By doing sort keyed
|
|
||||||
# only by tuple (-k 1,1) and configured to output only the first line for
|
|
||||||
# every key (-s -u), we end up with the smallest file for each tuple.
|
|
||||||
|
|
||||||
echo "[*] Sorting candidate list (be patient)..."
|
|
||||||
|
|
||||||
sort -k1,1 -s -u "$TRACE_DIR/.candidate_list" | \
|
|
||||||
sed 's/^/BEST_FILE[/;s/ /]="/;s/$/"/' >"$TRACE_DIR/.candidate_script"
|
|
||||||
|
|
||||||
if [ ! -s "$TRACE_DIR/.candidate_script" ]; then
|
|
||||||
echo "[-] Error: no traces obtained from test cases, check syntax!" 1>&2
|
|
||||||
test "$AFL_KEEP_TRACES" = "" && rm -rf "$TRACE_DIR"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# The sed command converted the sorted list to a shell script that populates
|
|
||||||
# BEST_FILE[tuple]="fname". Let's load that!
|
|
||||||
|
|
||||||
. "$TRACE_DIR/.candidate_script"
|
|
||||||
|
|
||||||
##########################
|
|
||||||
# STEP 5: WRITING OUTPUT #
|
|
||||||
##########################
|
|
||||||
|
|
||||||
# The final trick is to grab the top pick for each tuple, unless said tuple is
|
|
||||||
# already set due to the inclusion of an earlier candidate; and then put all
|
|
||||||
# tuples associated with the newly-added file to the "already have" list. The
|
|
||||||
# loop works from least popular tuples and toward the most common ones.
|
|
||||||
|
|
||||||
echo "[*] Processing candidates and writing output files..."
|
|
||||||
|
|
||||||
CUR=0
|
|
||||||
|
|
||||||
touch "$TRACE_DIR/.already_have"
|
|
||||||
|
|
||||||
while read -r cnt tuple; do
|
|
||||||
|
|
||||||
CUR=$((CUR+1))
|
|
||||||
printf "\\r Processing tuple $CUR/$TUPLE_COUNT... "
|
|
||||||
|
|
||||||
# If we already have this tuple, skip it.
|
|
||||||
|
|
||||||
grep -q "^$tuple\$" "$TRACE_DIR/.already_have" && continue
|
|
||||||
|
|
||||||
FN=${BEST_FILE[tuple]}
|
|
||||||
|
|
||||||
$CP_TOOL "$IN_DIR/$FN" "$OUT_DIR/$FN"
|
|
||||||
|
|
||||||
if [ "$((CUR % 5))" = "0" ]; then
|
|
||||||
sort -u "$TRACE_DIR/$FN" "$TRACE_DIR/.already_have" >"$TRACE_DIR/.tmp"
|
|
||||||
mv -f "$TRACE_DIR/.tmp" "$TRACE_DIR/.already_have"
|
|
||||||
else
|
|
||||||
cat "$TRACE_DIR/$FN" >>"$TRACE_DIR/.already_have"
|
|
||||||
fi
|
|
||||||
|
|
||||||
done <"$TRACE_DIR/.all_uniq"
|
|
||||||
|
|
||||||
echo
|
|
||||||
|
|
||||||
OUT_COUNT=`ls -- "$OUT_DIR" | wc -l`
|
|
||||||
|
|
||||||
if [ "$OUT_COUNT" = "1" ]; then
|
|
||||||
echo "[!] WARNING: All test cases had the same traces, check syntax!"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "[+] Narrowed down to $OUT_COUNT files, saved in '$OUT_DIR'."
|
|
||||||
echo
|
|
||||||
|
|
||||||
test "$AFL_KEEP_TRACES" = "" && rm -rf "$TRACE_DIR"
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
|
470
afl-cmin.bash
Executable file
470
afl-cmin.bash
Executable file
@ -0,0 +1,470 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# american fuzzy lop++ - corpus minimization tool
|
||||||
|
# ---------------------------------------------
|
||||||
|
#
|
||||||
|
# Originally written by Michal Zalewski
|
||||||
|
#
|
||||||
|
# Copyright 2014, 2015 Google Inc. 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:
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# This tool tries to find the smallest subset of files in the input directory
|
||||||
|
# that still trigger the full range of instrumentation data points seen in
|
||||||
|
# the starting corpus. This has two uses:
|
||||||
|
#
|
||||||
|
# - Screening large corpora of input files before using them as a seed for
|
||||||
|
# afl-fuzz. The tool will remove functionally redundant files and likely
|
||||||
|
# leave you with a much smaller set.
|
||||||
|
#
|
||||||
|
# (In this case, you probably also want to consider running afl-tmin on
|
||||||
|
# the individual files later on to reduce their size.)
|
||||||
|
#
|
||||||
|
# - Minimizing the corpus generated organically by afl-fuzz, perhaps when
|
||||||
|
# planning to feed it to more resource-intensive tools. The tool achieves
|
||||||
|
# this by removing all entries that used to trigger unique behaviors in the
|
||||||
|
# past, but have been made obsolete by later finds.
|
||||||
|
#
|
||||||
|
# Note that the tool doesn't modify the files themselves. For that, you want
|
||||||
|
# afl-tmin.
|
||||||
|
#
|
||||||
|
# This script must use bash because other shells may have hardcoded limits on
|
||||||
|
# array sizes.
|
||||||
|
#
|
||||||
|
|
||||||
|
echo "corpus minimization tool for afl-fuzz by Michal Zalewski"
|
||||||
|
echo
|
||||||
|
|
||||||
|
#########
|
||||||
|
# SETUP #
|
||||||
|
#########
|
||||||
|
|
||||||
|
# Process command-line options...
|
||||||
|
|
||||||
|
MEM_LIMIT=200
|
||||||
|
TIMEOUT=none
|
||||||
|
|
||||||
|
unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \
|
||||||
|
AFL_CMIN_CRASHES_ONLY AFL_CMIN_ALLOW_ANY QEMU_MODE UNICORN_MODE
|
||||||
|
|
||||||
|
while getopts "+i:o:f:m:t:eQUCh" opt; do
|
||||||
|
|
||||||
|
case "$opt" in
|
||||||
|
|
||||||
|
"h")
|
||||||
|
;;
|
||||||
|
|
||||||
|
"i")
|
||||||
|
IN_DIR="$OPTARG"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"o")
|
||||||
|
OUT_DIR="$OPTARG"
|
||||||
|
;;
|
||||||
|
"f")
|
||||||
|
STDIN_FILE="$OPTARG"
|
||||||
|
;;
|
||||||
|
"m")
|
||||||
|
MEM_LIMIT="$OPTARG"
|
||||||
|
MEM_LIMIT_GIVEN=1
|
||||||
|
;;
|
||||||
|
"t")
|
||||||
|
TIMEOUT="$OPTARG"
|
||||||
|
;;
|
||||||
|
"e")
|
||||||
|
EXTRA_PAR="$EXTRA_PAR -e"
|
||||||
|
;;
|
||||||
|
"C")
|
||||||
|
export AFL_CMIN_CRASHES_ONLY=1
|
||||||
|
;;
|
||||||
|
"Q")
|
||||||
|
EXTRA_PAR="$EXTRA_PAR -Q"
|
||||||
|
test "$MEM_LIMIT_GIVEN" = "" && MEM_LIMIT=250
|
||||||
|
QEMU_MODE=1
|
||||||
|
;;
|
||||||
|
"U")
|
||||||
|
EXTRA_PAR="$EXTRA_PAR -U"
|
||||||
|
test "$MEM_LIMIT_GIVEN" = "" && MEM_LIMIT=250
|
||||||
|
UNICORN_MODE=1
|
||||||
|
;;
|
||||||
|
"?")
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
shift $((OPTIND-1))
|
||||||
|
|
||||||
|
TARGET_BIN="$1"
|
||||||
|
|
||||||
|
if [ "$TARGET_BIN" = "" -o "$IN_DIR" = "" -o "$OUT_DIR" = "" ]; then
|
||||||
|
|
||||||
|
cat 1>&2 <<_EOF_
|
||||||
|
Usage: $0 [ options ] -- /path/to/target_app [ ... ]
|
||||||
|
|
||||||
|
Required parameters:
|
||||||
|
|
||||||
|
-i dir - input directory with the starting corpus
|
||||||
|
-o dir - output directory for minimized files
|
||||||
|
|
||||||
|
Execution control settings:
|
||||||
|
|
||||||
|
-f file - location read by the fuzzed program (stdin)
|
||||||
|
-m megs - memory limit for child process ($MEM_LIMIT MB)
|
||||||
|
-t msec - run time limit for child process (none)
|
||||||
|
-Q - use binary-only instrumentation (QEMU mode)
|
||||||
|
-U - use unicorn-based instrumentation (Unicorn mode)
|
||||||
|
|
||||||
|
Minimization settings:
|
||||||
|
|
||||||
|
-C - keep crashing inputs, reject everything else
|
||||||
|
-e - solve for edge coverage only, ignore hit counts
|
||||||
|
|
||||||
|
For additional tips, please consult docs/README.
|
||||||
|
|
||||||
|
_EOF_
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Do a sanity check to discourage the use of /tmp, since we can't really
|
||||||
|
# handle this safely from a shell script.
|
||||||
|
|
||||||
|
if [ "$AFL_ALLOW_TMP" = "" ]; then
|
||||||
|
|
||||||
|
echo "$IN_DIR" | grep -qE '^(/var)?/tmp/'
|
||||||
|
T1="$?"
|
||||||
|
|
||||||
|
echo "$TARGET_BIN" | grep -qE '^(/var)?/tmp/'
|
||||||
|
T2="$?"
|
||||||
|
|
||||||
|
echo "$OUT_DIR" | grep -qE '^(/var)?/tmp/'
|
||||||
|
T3="$?"
|
||||||
|
|
||||||
|
echo "$STDIN_FILE" | grep -qE '^(/var)?/tmp/'
|
||||||
|
T4="$?"
|
||||||
|
|
||||||
|
echo "$PWD" | grep -qE '^(/var)?/tmp/'
|
||||||
|
T5="$?"
|
||||||
|
|
||||||
|
if [ "$T1" = "0" -o "$T2" = "0" -o "$T3" = "0" -o "$T4" = "0" -o "$T5" = "0" ]; then
|
||||||
|
echo "[-] Error: do not use this script in /tmp or /var/tmp." 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If @@ is specified, but there's no -f, let's come up with a temporary input
|
||||||
|
# file name.
|
||||||
|
|
||||||
|
TRACE_DIR="$OUT_DIR/.traces"
|
||||||
|
|
||||||
|
if [ "$STDIN_FILE" = "" ]; then
|
||||||
|
|
||||||
|
if echo "$*" | grep -qF '@@'; then
|
||||||
|
STDIN_FILE="$TRACE_DIR/.cur_input"
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for obvious errors.
|
||||||
|
|
||||||
|
if [ ! "$MEM_LIMIT" = "none" ]; then
|
||||||
|
|
||||||
|
if [ "$MEM_LIMIT" -lt "5" ]; then
|
||||||
|
echo "[-] Error: dangerously low memory limit." 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! "$TIMEOUT" = "none" ]; then
|
||||||
|
|
||||||
|
if [ "$TIMEOUT" -lt "10" ]; then
|
||||||
|
echo "[-] Error: dangerously low timeout." 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then
|
||||||
|
|
||||||
|
TNEW="`which "$TARGET_BIN" 2>/dev/null`"
|
||||||
|
|
||||||
|
if [ ! -f "$TNEW" -o ! -x "$TNEW" ]; then
|
||||||
|
echo "[-] Error: binary '$TARGET_BIN' not found or not executable." 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TARGET_BIN="$TNEW"
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$UNICORN_MODE" = "" ]; then
|
||||||
|
|
||||||
|
if ! grep -qF "__AFL_SHM_ID" "$TARGET_BIN"; then
|
||||||
|
echo "[-] Error: binary '$TARGET_BIN' doesn't appear to be instrumented." 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "$IN_DIR" ]; then
|
||||||
|
echo "[-] Error: directory '$IN_DIR' not found." 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
test -d "$IN_DIR/queue" && IN_DIR="$IN_DIR/queue"
|
||||||
|
|
||||||
|
find "$OUT_DIR" -name 'id[:_]*' -maxdepth 1 -exec rm -- {} \; 2>/dev/null
|
||||||
|
rm -rf "$TRACE_DIR" 2>/dev/null
|
||||||
|
|
||||||
|
rmdir "$OUT_DIR" 2>/dev/null
|
||||||
|
|
||||||
|
if [ -d "$OUT_DIR" ]; then
|
||||||
|
echo "[-] Error: directory '$OUT_DIR' exists and is not empty - delete it first." 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -m 700 -p "$TRACE_DIR" || exit 1
|
||||||
|
|
||||||
|
if [ ! "$STDIN_FILE" = "" ]; then
|
||||||
|
rm -f "$STDIN_FILE" || exit 1
|
||||||
|
touch "$STDIN_FILE" || exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$AFL_PATH" = "" ]; then
|
||||||
|
SHOWMAP="${0%/afl-cmin}/afl-showmap"
|
||||||
|
else
|
||||||
|
SHOWMAP="$AFL_PATH/afl-showmap"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -x "$SHOWMAP" ]; then
|
||||||
|
echo "[-] Error: can't find 'afl-showmap' - please set AFL_PATH." 1>&2
|
||||||
|
rm -rf "$TRACE_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
IN_COUNT=$((`ls -- "$IN_DIR" 2>/dev/null | wc -l`))
|
||||||
|
|
||||||
|
if [ "$IN_COUNT" = "0" ]; then
|
||||||
|
echo "[+] Hmm, no inputs in the target directory. Nothing to be done."
|
||||||
|
rm -rf "$TRACE_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
FIRST_FILE=`ls "$IN_DIR" | head -1`
|
||||||
|
|
||||||
|
# Make sure that we're not dealing with a directory.
|
||||||
|
|
||||||
|
if [ -d "$IN_DIR/$FIRST_FILE" ]; then
|
||||||
|
echo "[-] Error: The target directory contains subdirectories - please fix." 1>&2
|
||||||
|
rm -rf "$TRACE_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for the more efficient way to copy files...
|
||||||
|
|
||||||
|
if ln "$IN_DIR/$FIRST_FILE" "$TRACE_DIR/.link_test" 2>/dev/null; then
|
||||||
|
CP_TOOL=ln
|
||||||
|
else
|
||||||
|
CP_TOOL=cp
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make sure that we can actually get anything out of afl-showmap before we
|
||||||
|
# waste too much time.
|
||||||
|
|
||||||
|
echo "[*] Testing the target binary..."
|
||||||
|
|
||||||
|
if [ "$STDIN_FILE" = "" ]; then
|
||||||
|
|
||||||
|
AFL_CMIN_ALLOW_ANY=1 "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/.run_test" -Z $EXTRA_PAR -- "$@" <"$IN_DIR/$FIRST_FILE"
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
cp "$IN_DIR/$FIRST_FILE" "$STDIN_FILE"
|
||||||
|
AFL_CMIN_ALLOW_ANY=1 "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/.run_test" -Z $EXTRA_PAR -A "$STDIN_FILE" -- "$@" </dev/null
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
FIRST_COUNT=$((`grep -c . "$TRACE_DIR/.run_test"`))
|
||||||
|
|
||||||
|
if [ "$FIRST_COUNT" -gt "0" ]; then
|
||||||
|
|
||||||
|
echo "[+] OK, $FIRST_COUNT tuples recorded."
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
echo "[-] Error: no instrumentation output detected (perhaps crash or timeout)." 1>&2
|
||||||
|
test "$AFL_KEEP_TRACES" = "" && rm -rf "$TRACE_DIR"
|
||||||
|
exit 1
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Let's roll!
|
||||||
|
|
||||||
|
#############################
|
||||||
|
# STEP 1: COLLECTING TRACES #
|
||||||
|
#############################
|
||||||
|
|
||||||
|
echo "[*] Obtaining traces for input files in '$IN_DIR'..."
|
||||||
|
|
||||||
|
(
|
||||||
|
|
||||||
|
CUR=0
|
||||||
|
|
||||||
|
if [ "$STDIN_FILE" = "" ]; then
|
||||||
|
|
||||||
|
ls "$IN_DIR" | while read -r fn; do
|
||||||
|
|
||||||
|
CUR=$((CUR+1))
|
||||||
|
printf "\\r Processing file $CUR/$IN_COUNT... "
|
||||||
|
|
||||||
|
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -- "$@" <"$IN_DIR/$fn"
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
ls "$IN_DIR" | while read -r fn; do
|
||||||
|
|
||||||
|
CUR=$((CUR+1))
|
||||||
|
printf "\\r Processing file $CUR/$IN_COUNT... "
|
||||||
|
|
||||||
|
cp "$IN_DIR/$fn" "$STDIN_FILE"
|
||||||
|
|
||||||
|
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -A "$STDIN_FILE" -- "$@" </dev/null
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
echo
|
||||||
|
|
||||||
|
##########################
|
||||||
|
# STEP 2: SORTING TUPLES #
|
||||||
|
##########################
|
||||||
|
|
||||||
|
# With this out of the way, we sort all tuples by popularity across all
|
||||||
|
# datasets. The reasoning here is that we won't be able to avoid the files
|
||||||
|
# that trigger unique tuples anyway, so we will want to start with them and
|
||||||
|
# see what's left.
|
||||||
|
|
||||||
|
echo "[*] Sorting trace sets (this may take a while)..."
|
||||||
|
|
||||||
|
ls "$IN_DIR" | sed "s#^#$TRACE_DIR/#" | tr '\n' '\0' | xargs -0 -n 1 cat | \
|
||||||
|
sort | uniq -c | sort -k 1,1 -n >"$TRACE_DIR/.all_uniq"
|
||||||
|
|
||||||
|
TUPLE_COUNT=$((`grep -c . "$TRACE_DIR/.all_uniq"`))
|
||||||
|
|
||||||
|
echo "[+] Found $TUPLE_COUNT unique tuples across $IN_COUNT files."
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
# STEP 3: SELECTING CANDIDATE FILES #
|
||||||
|
#####################################
|
||||||
|
|
||||||
|
# The next step is to find the best candidate for each tuple. The "best"
|
||||||
|
# part is understood simply as the smallest input that includes a particular
|
||||||
|
# tuple in its trace. Empirical evidence suggests that this produces smaller
|
||||||
|
# datasets than more involved algorithms that could be still pulled off in
|
||||||
|
# a shell script.
|
||||||
|
|
||||||
|
echo "[*] Finding best candidates for each tuple..."
|
||||||
|
|
||||||
|
CUR=0
|
||||||
|
|
||||||
|
ls -rS "$IN_DIR" | while read -r fn; do
|
||||||
|
|
||||||
|
CUR=$((CUR+1))
|
||||||
|
printf "\\r Processing file $CUR/$IN_COUNT... "
|
||||||
|
|
||||||
|
sed "s#\$# $fn#" "$TRACE_DIR/$fn" >>"$TRACE_DIR/.candidate_list"
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
|
||||||
|
##############################
|
||||||
|
# STEP 4: LOADING CANDIDATES #
|
||||||
|
##############################
|
||||||
|
|
||||||
|
# At this point, we have a file of tuple-file pairs, sorted by file size
|
||||||
|
# in ascending order (as a consequence of ls -rS). By doing sort keyed
|
||||||
|
# only by tuple (-k 1,1) and configured to output only the first line for
|
||||||
|
# every key (-s -u), we end up with the smallest file for each tuple.
|
||||||
|
|
||||||
|
echo "[*] Sorting candidate list (be patient)..."
|
||||||
|
|
||||||
|
sort -k1,1 -s -u "$TRACE_DIR/.candidate_list" | \
|
||||||
|
sed 's/^/BEST_FILE[/;s/ /]="/;s/$/"/' >"$TRACE_DIR/.candidate_script"
|
||||||
|
|
||||||
|
if [ ! -s "$TRACE_DIR/.candidate_script" ]; then
|
||||||
|
echo "[-] Error: no traces obtained from test cases, check syntax!" 1>&2
|
||||||
|
test "$AFL_KEEP_TRACES" = "" && rm -rf "$TRACE_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The sed command converted the sorted list to a shell script that populates
|
||||||
|
# BEST_FILE[tuple]="fname". Let's load that!
|
||||||
|
|
||||||
|
. "$TRACE_DIR/.candidate_script"
|
||||||
|
|
||||||
|
##########################
|
||||||
|
# STEP 5: WRITING OUTPUT #
|
||||||
|
##########################
|
||||||
|
|
||||||
|
# The final trick is to grab the top pick for each tuple, unless said tuple is
|
||||||
|
# already set due to the inclusion of an earlier candidate; and then put all
|
||||||
|
# tuples associated with the newly-added file to the "already have" list. The
|
||||||
|
# loop works from least popular tuples and toward the most common ones.
|
||||||
|
|
||||||
|
echo "[*] Processing candidates and writing output files..."
|
||||||
|
|
||||||
|
CUR=0
|
||||||
|
|
||||||
|
touch "$TRACE_DIR/.already_have"
|
||||||
|
|
||||||
|
while read -r cnt tuple; do
|
||||||
|
|
||||||
|
CUR=$((CUR+1))
|
||||||
|
printf "\\r Processing tuple $CUR/$TUPLE_COUNT... "
|
||||||
|
|
||||||
|
# If we already have this tuple, skip it.
|
||||||
|
|
||||||
|
grep -q "^$tuple\$" "$TRACE_DIR/.already_have" && continue
|
||||||
|
|
||||||
|
FN=${BEST_FILE[tuple]}
|
||||||
|
|
||||||
|
$CP_TOOL "$IN_DIR/$FN" "$OUT_DIR/$FN"
|
||||||
|
|
||||||
|
if [ "$((CUR % 5))" = "0" ]; then
|
||||||
|
sort -u "$TRACE_DIR/$FN" "$TRACE_DIR/.already_have" >"$TRACE_DIR/.tmp"
|
||||||
|
mv -f "$TRACE_DIR/.tmp" "$TRACE_DIR/.already_have"
|
||||||
|
else
|
||||||
|
cat "$TRACE_DIR/$FN" >>"$TRACE_DIR/.already_have"
|
||||||
|
fi
|
||||||
|
|
||||||
|
done <"$TRACE_DIR/.all_uniq"
|
||||||
|
|
||||||
|
echo
|
||||||
|
|
||||||
|
OUT_COUNT=`ls -- "$OUT_DIR" | wc -l`
|
||||||
|
|
||||||
|
if [ "$OUT_COUNT" = "1" ]; then
|
||||||
|
echo "[!] WARNING: All test cases had the same traces, check syntax!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[+] Narrowed down to $OUT_COUNT files, saved in '$OUT_DIR'."
|
||||||
|
echo
|
||||||
|
|
||||||
|
test "$AFL_KEEP_TRACES" = "" && rm -rf "$TRACE_DIR"
|
||||||
|
|
||||||
|
exit 0
|
@ -1,6 +1,6 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
test "$1" = "-h" && {
|
test "$1" = "-h" && {
|
||||||
echo afl-system-config by Marc Heuse
|
echo 'afl-system-config by Marc Heuse <mh@mh-sec.de>'
|
||||||
echo
|
echo
|
||||||
echo $0
|
echo $0
|
||||||
echo
|
echo
|
||||||
@ -12,55 +12,72 @@ test "$1" = "-h" && {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DONE=
|
||||||
PLATFORM=`uname -s`
|
PLATFORM=`uname -s`
|
||||||
echo This reconfigures the system to have a better fuzzing performance
|
echo This reconfigures the system to have a better fuzzing performance.
|
||||||
if [ '!' "$EUID" = 0 ] && [ '!' `id -u` = 0 ] ; then
|
if [ '!' "$EUID" = 0 ] && [ '!' `id -u` = 0 ] ; then
|
||||||
echo Error you need to be root to run this
|
echo "Warning: you need to be root to run this!"
|
||||||
exit 1
|
# we do not exit as other mechanisms exist that allows to do this than
|
||||||
|
# being root. let the errors speak for themselves.
|
||||||
fi
|
fi
|
||||||
if [ "$PLATFORM" = "Linux" ] ; then
|
if [ "$PLATFORM" = "Linux" ] ; then
|
||||||
sysctl -w kernel.core_pattern=core
|
{
|
||||||
sysctl -w kernel.randomize_va_space=0
|
sysctl -w kernel.core_pattern=core
|
||||||
sysctl -w kernel.sched_child_runs_first=1
|
sysctl -w kernel.randomize_va_space=0
|
||||||
sysctl -w kernel.sched_autogroup_enabled=1
|
sysctl -w kernel.sched_child_runs_first=1
|
||||||
sysctl -w kernel.sched_migration_cost_ns=50000000
|
sysctl -w kernel.sched_autogroup_enabled=1
|
||||||
sysctl -w kernel.sched_latency_ns=250000000
|
sysctl -w kernel.sched_migration_cost_ns=50000000
|
||||||
echo never > /sys/kernel/mm/transparent_hugepage/enabled
|
sysctl -w kernel.sched_latency_ns=250000000
|
||||||
test -e /sys/devices/system/cpu/cpufreq/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/scaling_governor
|
echo never > /sys/kernel/mm/transparent_hugepage/enabled
|
||||||
test -e /sys/devices/system/cpu/cpufreq/policy0/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/policy*/scaling_governor
|
test -e /sys/devices/system/cpu/cpufreq/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/scaling_governor
|
||||||
test -e /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
|
test -e /sys/devices/system/cpu/cpufreq/policy0/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/policy*/scaling_governor
|
||||||
test -e /sys/devices/system/cpu/intel_pstate/no_turbo && echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo
|
test -e /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
|
||||||
test -e /sys/devices/system/cpu/cpufreq/boost && echo 1 > /sys/devices/system/cpu/cpufreq/boost
|
test -e /sys/devices/system/cpu/intel_pstate/no_turbo && echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo
|
||||||
echo
|
test -e /sys/devices/system/cpu/cpufreq/boost && echo 1 > /sys/devices/system/cpu/cpufreq/boost
|
||||||
echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this:
|
} > /dev/null
|
||||||
echo '/etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"'
|
echo Settings applied.
|
||||||
|
dmesg | egrep -q 'nospectre_v2|spectre_v2=off' || {
|
||||||
|
echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this:
|
||||||
|
echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"'
|
||||||
|
}
|
||||||
|
DONE=1
|
||||||
fi
|
fi
|
||||||
if [ "$PLATFORM" = "FreeBSD" ] ; then
|
if [ "$PLATFORM" = "FreeBSD" ] ; then
|
||||||
sysctl kern.elf32.aslr.enable=0
|
{
|
||||||
sysctl kern.elf64.aslr.enable=0
|
sysctl kern.elf32.aslr.enable=0
|
||||||
echo
|
sysctl kern.elf64.aslr.enable=0
|
||||||
echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this:
|
} > /dev/null
|
||||||
echo 'sysctl hw.ibrs_disable=1'
|
echo Settings applied.
|
||||||
echo
|
echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this:
|
||||||
echo 'Setting kern.pmap.pg_ps_enabled=0 into /boot/loader.conf might be helpful too.'
|
echo ' sysctl hw.ibrs_disable=1'
|
||||||
|
echo 'Setting kern.pmap.pg_ps_enabled=0 into /boot/loader.conf might be helpful too.'
|
||||||
|
DONE=1
|
||||||
fi
|
fi
|
||||||
if [ "$PLATFORM" = "OpenBSD" ] ; then
|
if [ "$PLATFORM" = "OpenBSD" ] ; then
|
||||||
echo
|
echo
|
||||||
echo 'System security features cannot be disabled on OpenBSD.'
|
echo 'System security features cannot be disabled on OpenBSD.'
|
||||||
|
DONE=1
|
||||||
fi
|
fi
|
||||||
if [ "$PLATFORM" = "NetBSD" ] ; then
|
if [ "$PLATFORM" = "NetBSD" ] ; then
|
||||||
echo
|
{
|
||||||
echo It is recommended to enable unprivileged users to set cpu affinity
|
#echo It is recommended to enable unprivileged users to set cpu affinity
|
||||||
echo to be able to use afl-gotcpu meaningfully.
|
#echo to be able to use afl-gotcpu meaningfully.
|
||||||
/sbin/sysctl -w security.models.extensions.user_set_cpu_affinity=1
|
/sbin/sysctl -w security.models.extensions.user_set_cpu_affinity=1
|
||||||
|
} > /dev/null
|
||||||
|
echo Settings applied.
|
||||||
|
DONE=1
|
||||||
fi
|
fi
|
||||||
if [ "$PLATFORM" = "Darwin" ] ; then
|
if [ "$PLATFORM" = "Darwin" ] ; then
|
||||||
if [ $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ] ; then
|
if [ $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ] ; then
|
||||||
echo We unload the default crash reporter here
|
echo We unload the default crash reporter here
|
||||||
SL=/System/Library; PL=com.apple.ReportCrash
|
SL=/System/Library; PL=com.apple.ReportCrash
|
||||||
launchctl unload -w ${SL}/LaunchAgents/${PL}.plist
|
launchctl unload -w ${SL}/LaunchAgents/${PL}.plist
|
||||||
sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist
|
sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist
|
||||||
|
echo Settings applied.
|
||||||
|
else
|
||||||
|
echo Nothing to do.
|
||||||
fi
|
fi
|
||||||
|
DONE=1
|
||||||
fi
|
fi
|
||||||
echo
|
test -z "$DONE" && echo Error: Unknown platform: $PLATFORM
|
||||||
echo Also use AFL_TMPDIR to use a tmpfs for the input file
|
test -z "$AFL_TMPDIR" && echo Also use AFL_TMPDIR and point it to a tmpfs for the input file caching
|
||||||
|
@ -17,10 +17,17 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
|
|||||||
Version ++2.60d (develop):
|
Version ++2.60d (develop):
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
- use -march=native if available
|
||||||
- afl-fuzz:
|
- afl-fuzz:
|
||||||
- now prints the real python version support compiled in
|
- now prints the real python version support compiled in
|
||||||
- afl-clang-fast now shows in the help output for which llvm version it
|
- set stronger performance compile options and little tweaks
|
||||||
was compiled for.
|
- afl-clang-fast:
|
||||||
|
- show in the help output for which llvm version it was compiled for
|
||||||
|
- now does not need to be recompiled between trace-pc and pass
|
||||||
|
instrumentation. compile normally and set AFL_LLVM_USE_TRACE_PC :)
|
||||||
|
- afl-cmin is now a sh script (invoking awk) instead of bash for portability
|
||||||
|
the original script is still present as afl-cmin.bash
|
||||||
|
- added blacklist and whitelisting function check in all modules of llvm_mode
|
||||||
- added fix from Debian project to compile libdislocator and libtokencap
|
- added fix from Debian project to compile libdislocator and libtokencap
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
|
#Fuzzing binary-only programs with afl++
|
||||||
Fuzzing binary-only programs with afl++
|
|
||||||
=======================================
|
|
||||||
|
|
||||||
afl++, libfuzzer and others are great if you have the source code, and
|
afl++, libfuzzer and others are great if you have the source code, and
|
||||||
it allows for very fast and coverage guided fuzzing.
|
it allows for very fast and coverage guided fuzzing.
|
||||||
|
|
||||||
However, if there is only the binary program and not source code available,
|
However, if there is only the binary program and no source code available,
|
||||||
then standard afl++ (dumb mode) is not effective.
|
then standard `afl-fuzz -n` (dumb mode) is not effective.
|
||||||
|
|
||||||
The following is a description of how these can be fuzzed with afl++
|
The following is a description of how these binaries can be fuzzed with afl++
|
||||||
|
|
||||||
!!!!!
|
!!!!!
|
||||||
TL;DR: try DYNINST with afl-dyninst. If it produces too many crashes then
|
TL;DR: try DYNINST with afl-dyninst. If it produces too many crashes then
|
||||||
@ -16,36 +14,42 @@ TL;DR: try DYNINST with afl-dyninst. If it produces too many crashes then
|
|||||||
!!!!!
|
!!!!!
|
||||||
|
|
||||||
|
|
||||||
QEMU
|
##QEMU
|
||||||
----
|
|
||||||
Qemu is the "native" solution to the program.
|
Qemu is the "native" solution to the program.
|
||||||
It is available in the ./qemu_mode/ directory and once compiled it can
|
It is available in the ./qemu_mode/ directory and once compiled it can
|
||||||
be accessed by the afl-fuzz -Q command line option.
|
be accessed by the afl-fuzz -Q command line option.
|
||||||
The speed decrease is at about 50%
|
The speed decrease is at about 50%
|
||||||
It is the easiest to use alternative and even works for cross-platform binaries.
|
It is the easiest to use alternative and even works for cross-platform binaries.
|
||||||
|
|
||||||
|
Note that there is also honggfuzz: [https://github.com/google/honggfuzz](https://github.com/google/honggfuzz)
|
||||||
|
which now has a qemu_mode, but its performance is just 1.5%!
|
||||||
|
|
||||||
As it is included in afl++ this needs no URL.
|
As it is included in afl++ this needs no URL.
|
||||||
|
|
||||||
WINE+QEMU
|
|
||||||
---------
|
##WINE+QEMU
|
||||||
Wine mode can run Win32 PE with the QEMU instrumentation.
|
Wine mode can run Win32 PE binaries with the QEMU instrumentation.
|
||||||
It needs Wine, python3 and the pefile python package installed.
|
It needs Wine, python3 and the pefile python package installed.
|
||||||
|
|
||||||
UNICORN
|
As it is included in afl++ this needs no URL.
|
||||||
-------
|
|
||||||
|
|
||||||
|
##UNICORN
|
||||||
Unicorn is a fork of QEMU. The instrumentation is, therefore, very similar.
|
Unicorn is a fork of QEMU. The instrumentation is, therefore, very similar.
|
||||||
In contrast to QEMU, Unicorn does not offer a full system or even userland emulation.
|
In contrast to QEMU, Unicorn does not offer a full system or even userland
|
||||||
Runtime environment and/or loaders have to be written from scratch, if needed.
|
emulation. Runtime environment and/or loaders have to be written from scratch,
|
||||||
On top, block chaining has been removed. This means the speed boost introduced in
|
if needed. On top, block chaining has been removed. This means the speed boost
|
||||||
to the patched QEMU Mode of afl++ cannot simply be ported over to Unicorn.
|
introduced in the patched QEMU Mode of afl++ cannot simply be ported over to
|
||||||
For further information, check out ./unicorn_mode.txt.
|
Unicorn. For further information, check out ./unicorn_mode.txt.
|
||||||
|
|
||||||
|
As it is included in afl++ this needs no URL.
|
||||||
|
|
||||||
|
|
||||||
DYNINST
|
##DYNINST
|
||||||
-------
|
|
||||||
Dyninst is a binary instrumentation framework similar to Pintool and Dynamorio
|
Dyninst is a binary instrumentation framework similar to Pintool and Dynamorio
|
||||||
(see far below). However whereas Pintool and Dynamorio work at runtime, dyninst
|
(see far below). However whereas Pintool and Dynamorio work at runtime, dyninst
|
||||||
instruments the target at load time, and then let it run.
|
instruments the target at load time, and then let it run - or save the
|
||||||
|
binary with the changes.
|
||||||
This is great for some things, e.g. fuzzing, and not so effective for others,
|
This is great for some things, e.g. fuzzing, and not so effective for others,
|
||||||
e.g. malware analysis.
|
e.g. malware analysis.
|
||||||
|
|
||||||
@ -53,9 +57,9 @@ So what we can do with dyninst is taking every basic block, and put afl's
|
|||||||
instrumention code in there - and then save the binary.
|
instrumention code in there - and then save the binary.
|
||||||
Afterwards we can just fuzz the newly saved target binary with afl-fuzz.
|
Afterwards we can just fuzz the newly saved target binary with afl-fuzz.
|
||||||
Sounds great? It is. The issue though - it is a non-trivial problem to
|
Sounds great? It is. The issue though - it is a non-trivial problem to
|
||||||
insert instructions, which change addresses in the process space, so
|
insert instructions, which change addresses in the process space, so that
|
||||||
everything is still working afterwards. Hence more often than not binaries
|
everything is still working afterwards. Hence more often than not binaries
|
||||||
crash when they are run (because of instrumentation).
|
crash when they are run.
|
||||||
|
|
||||||
The speed decrease is about 15-35%, depending on the optimization options
|
The speed decrease is about 15-35%, depending on the optimization options
|
||||||
used with afl-dyninst.
|
used with afl-dyninst.
|
||||||
@ -63,11 +67,10 @@ used with afl-dyninst.
|
|||||||
So if dyninst works, it is the best option available. Otherwise it just doesn't
|
So if dyninst works, it is the best option available. Otherwise it just doesn't
|
||||||
work well.
|
work well.
|
||||||
|
|
||||||
https://github.com/vanhauser-thc/afl-dyninst
|
[https://github.com/vanhauser-thc/afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst)
|
||||||
|
|
||||||
|
|
||||||
INTEL-PT
|
##INTEL-PT
|
||||||
--------
|
|
||||||
If you have a newer Intel CPU, you can make use of Intels processor trace.
|
If you have a newer Intel CPU, you can make use of Intels processor trace.
|
||||||
The big issue with Intel's PT is the small buffer size and the complex
|
The big issue with Intel's PT is the small buffer size and the complex
|
||||||
encoding of the debug information collected through PT.
|
encoding of the debug information collected through PT.
|
||||||
@ -77,30 +80,39 @@ the implementation and other factors).
|
|||||||
|
|
||||||
There are two afl intel-pt implementations:
|
There are two afl intel-pt implementations:
|
||||||
|
|
||||||
1. https://github.com/junxzm1990/afl-pt
|
1. [https://github.com/junxzm1990/afl-pt](https://github.com/junxzm1990/afl-pt)
|
||||||
=> this needs Ubuntu 14.04.05 without any updates and the 4.4 kernel.
|
=> this needs Ubuntu 14.04.05 without any updates and the 4.4 kernel.
|
||||||
|
|
||||||
2. https://github.com/hunter-ht-2018/ptfuzzer
|
2. [https://github.com/hunter-ht-2018/ptfuzzer](https://github.com/hunter-ht-2018/ptfuzzer)
|
||||||
=> this needs a 4.14 or 4.15 kernel. the "nopti" kernel boot option must
|
=> this needs a 4.14 or 4.15 kernel. the "nopti" kernel boot option must
|
||||||
be used. This one is faster than the other.
|
be used. This one is faster than the other.
|
||||||
|
|
||||||
|
Note that there is also honggfuzz: https://github.com/google/honggfuzz
|
||||||
|
But its IPT performance is just 6%!
|
||||||
|
|
||||||
CORESIGHT
|
|
||||||
---------
|
|
||||||
|
|
||||||
|
##CORESIGHT
|
||||||
Coresight is ARM's answer to Intel's PT.
|
Coresight is ARM's answer to Intel's PT.
|
||||||
There is no implementation so far which handle coresight and getting
|
There is no implementation so far which handle coresight and getting
|
||||||
it working on an ARM Linux is very difficult due to custom kernel building
|
it working on an ARM Linux is very difficult due to custom kernel building
|
||||||
on embedded systems is difficult. And finding one that has coresight in
|
on embedded systems is difficult. And finding one that has coresight in
|
||||||
the ARM chip is difficult too.
|
the ARM chip is difficult too.
|
||||||
My guess is that it is slower than Qemu, but faster than Intel PT.
|
My guess is that it is slower than Qemu, but faster than Intel PT.
|
||||||
|
|
||||||
If anyone finds any coresight implementation for afl please ping me:
|
If anyone finds any coresight implementation for afl please ping me:
|
||||||
vh@thc.org
|
vh@thc.org
|
||||||
|
|
||||||
|
|
||||||
PIN & DYNAMORIO
|
##FRIDA
|
||||||
---------------
|
Frida is a dynamic instrumentation engine like Pintool, Dyninst and Dynamorio.
|
||||||
|
What is special is that it is written Python, and scripted with Javascript.
|
||||||
|
It is mostly used to reverse binaries on mobile phones however can be used
|
||||||
|
everywhere.
|
||||||
|
|
||||||
|
There is a WIP fuzzer available at [https://github.com/andreafioraldi/frida-fuzzer](https://github.com/andreafioraldi/frida-fuzzer)
|
||||||
|
|
||||||
|
|
||||||
|
##PIN & DYNAMORIO
|
||||||
Pintool and Dynamorio are dynamic instrumentation engines, and they can be
|
Pintool and Dynamorio are dynamic instrumentation engines, and they can be
|
||||||
used for getting basic block information at runtime.
|
used for getting basic block information at runtime.
|
||||||
Pintool is only available for Intel x32/x64 on Linux, Mac OS and Windows
|
Pintool is only available for Intel x32/x64 on Linux, Mac OS and Windows
|
||||||
@ -115,30 +127,27 @@ Hence Dynamorio is the option to go for if everything fails, and Pintool
|
|||||||
only if Dynamorio fails too.
|
only if Dynamorio fails too.
|
||||||
|
|
||||||
Dynamorio solutions:
|
Dynamorio solutions:
|
||||||
https://github.com/vanhauser-thc/afl-dynamorio
|
* [https://github.com/vanhauser-thc/afl-dynamorio](https://github.com/vanhauser-thc/afl-dynamorio)
|
||||||
https://github.com/mxmssh/drAFL
|
* [https://github.com/mxmssh/drAFL](https://github.com/mxmssh/drAFL)
|
||||||
https://github.com/googleprojectzero/winafl/ <= very good but windows only
|
* [https://github.com/googleprojectzero/winafl/](https://github.com/googleprojectzero/winafl/) <= very good but windows only
|
||||||
|
|
||||||
Pintool solutions:
|
Pintool solutions:
|
||||||
https://github.com/vanhauser-thc/afl-pin
|
* [https://github.com/vanhauser-thc/afl-pin](https://github.com/vanhauser-thc/afl-pin)
|
||||||
https://github.com/mothran/aflpin
|
* [https://github.com/mothran/aflpin](https://github.com/mothran/aflpin)
|
||||||
https://github.com/spinpx/afl_pin_mode <= only old Pintool version supported
|
* [https://github.com/spinpx/afl_pin_mode](https://github.com/spinpx/afl_pin_mode) <= only old Pintool version supported
|
||||||
|
|
||||||
|
|
||||||
Non-AFL solutions
|
##Non-AFL solutions
|
||||||
-----------------
|
There are many binary-only fuzzing frameworks.
|
||||||
|
Some are great for CTFs but don't work with large binaries, others are very
|
||||||
|
slow but have good path discovery, some are very hard to set-up ...
|
||||||
|
|
||||||
There are many binary-only fuzzing frameworks. Some are great for CTFs but don't
|
* QSYM: [https://github.com/sslab-gatech/qsym](https://github.com/sslab-gatech/qsym)
|
||||||
work with large binaries, others are very slow but have good path discovery,
|
* Manticore: [https://github.com/trailofbits/manticore](https://github.com/trailofbits/manticore)
|
||||||
some are very hard to set-up ...
|
* S2E: [https://github.com/S2E](https://github.com/S2E)
|
||||||
|
* <please send me any missing that are good>
|
||||||
QSYM: https://github.com/sslab-gatech/qsym
|
|
||||||
Manticore: https://github.com/trailofbits/manticore
|
|
||||||
S2E: https://github.com/S2E
|
|
||||||
<please send me any missing that are good>
|
|
||||||
|
|
||||||
|
|
||||||
|
## Closing words
|
||||||
|
|
||||||
That's it!
|
That's it! News, corrections, updates? Send an email to vh@thc.org
|
||||||
News, corrections, updates?
|
|
||||||
Email vh@thc.org
|
|
@ -28,6 +28,9 @@ Here's a quick overview of the stuff you can find in this directory:
|
|||||||
mode to speed up certain fuzzing jobs.
|
mode to speed up certain fuzzing jobs.
|
||||||
|
|
||||||
- post_library - an example of how to build postprocessors for AFL.
|
- post_library - an example of how to build postprocessors for AFL.
|
||||||
|
|
||||||
|
- socket_fuzzing - a LD_PRELOAD library 'redirects' a socket to stdin
|
||||||
|
for fuzzing access with afl++
|
||||||
|
|
||||||
Note that the minimize_corpus.sh tool has graduated from the experimental/
|
Note that the minimize_corpus.sh tool has graduated from the experimental/
|
||||||
directory and is now available as ../afl-cmin. The LLVM mode has likewise
|
directory and is now available as ../afl-cmin. The LLVM mode has likewise
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
@ -61,12 +61,16 @@
|
|||||||
|
|
||||||
/* Default memory limit for child process (MB): */
|
/* Default memory limit for child process (MB): */
|
||||||
|
|
||||||
|
#ifndef __NetBSD__
|
||||||
#ifndef WORD_SIZE_64
|
#ifndef WORD_SIZE_64
|
||||||
#define MEM_LIMIT 25
|
#define MEM_LIMIT 25
|
||||||
#else
|
#else
|
||||||
#define MEM_LIMIT 50
|
#define MEM_LIMIT 50
|
||||||
#endif /* ^!WORD_SIZE_64 */
|
#endif /* ^!WORD_SIZE_64 */
|
||||||
|
#else /* NetBSD's kernel needs more space for stack, see discussion for issue \
|
||||||
|
#165 */
|
||||||
|
#define MEM_LIMIT 200
|
||||||
|
#endif
|
||||||
/* Default memory limit when running in QEMU mode (MB): */
|
/* Default memory limit when running in QEMU mode (MB): */
|
||||||
|
|
||||||
#define MEM_LIMIT_QEMU 200
|
#define MEM_LIMIT_QEMU 200
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -397,6 +397,29 @@ void* aligned_alloc(size_t align, size_t len) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* specific BSD api mainly checking possible overflow for the size */
|
||||||
|
|
||||||
|
void* reallocarray(void* ptr, size_t elem_len, size_t elem_cnt) {
|
||||||
|
|
||||||
|
const size_t elem_lim = 1UL << (sizeof(size_t) * 4);
|
||||||
|
const size_t elem_tot = elem_len * elem_cnt;
|
||||||
|
void* ret = NULL;
|
||||||
|
|
||||||
|
if ((elem_len >= elem_lim || elem_cnt >= elem_lim) && elem_len > 0 &&
|
||||||
|
elem_cnt > (SIZE_MAX / elem_len)) {
|
||||||
|
|
||||||
|
DEBUGF("reallocarray size overflow (%zu)", elem_tot);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
ret = realloc(ptr, elem_tot);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
__attribute__((constructor)) void __dislocator_init(void) {
|
__attribute__((constructor)) void __dislocator_init(void) {
|
||||||
|
|
||||||
u8* tmp = (u8*)getenv("AFL_LD_LIMIT_MB");
|
u8* tmp = (u8*)getenv("AFL_LD_LIMIT_MB");
|
||||||
|
@ -94,6 +94,28 @@ struct InsTrim : public ModulePass {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ripped from aflgo
|
||||||
|
static bool isBlacklisted(const Function *F) {
|
||||||
|
|
||||||
|
static const SmallVector<std::string, 4> Blacklist = {
|
||||||
|
|
||||||
|
"asan.",
|
||||||
|
"llvm.",
|
||||||
|
"sancov.",
|
||||||
|
"__ubsan_handle_",
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto const &BlacklistFunc : Blacklist) {
|
||||||
|
|
||||||
|
if (F->getName().startswith(BlacklistFunc)) { return true; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool runOnModule(Module &M) override {
|
bool runOnModule(Module &M) override {
|
||||||
|
|
||||||
char be_quiet = 0;
|
char be_quiet = 0;
|
||||||
@ -122,19 +144,6 @@ struct InsTrim : public ModulePass {
|
|||||||
// this is our default
|
// this is our default
|
||||||
MarkSetOpt = true;
|
MarkSetOpt = true;
|
||||||
|
|
||||||
/* // I dont think this makes sense to port into LLVMInsTrim
|
|
||||||
char* inst_ratio_str = getenv("AFL_INST_RATIO");
|
|
||||||
unsigned int inst_ratio = 100;
|
|
||||||
if (inst_ratio_str) {
|
|
||||||
|
|
||||||
if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || !inst_ratio ||
|
|
||||||
inst_ratio > 100) FATAL("Bad value of AFL_INST_RATIO (must be between 1
|
|
||||||
and 100)");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
LLVMContext &C = M.getContext();
|
LLVMContext &C = M.getContext();
|
||||||
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
|
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
|
||||||
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
|
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
|
||||||
@ -181,8 +190,7 @@ struct InsTrim : public ModulePass {
|
|||||||
|
|
||||||
if (instFilename.str().empty()) {
|
if (instFilename.str().empty()) {
|
||||||
|
|
||||||
/* If the original location is empty, try using the inlined location
|
/* If the original location is empty, try using the inlined location */
|
||||||
*/
|
|
||||||
DILocation *oDILoc = cDILoc->getInlinedAt();
|
DILocation *oDILoc = cDILoc->getInlinedAt();
|
||||||
if (oDILoc) {
|
if (oDILoc) {
|
||||||
|
|
||||||
@ -240,6 +248,8 @@ struct InsTrim : public ModulePass {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isBlacklisted(&F)) continue;
|
||||||
|
|
||||||
std::unordered_set<BasicBlock *> MS;
|
std::unordered_set<BasicBlock *> MS;
|
||||||
if (!MarkSetOpt) {
|
if (!MarkSetOpt) {
|
||||||
|
|
||||||
@ -408,28 +418,19 @@ struct InsTrim : public ModulePass {
|
|||||||
IRB.CreateStore(Incr, MapPtrIdx)
|
IRB.CreateStore(Incr, MapPtrIdx)
|
||||||
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||||
|
|
||||||
/* Set prev_loc to cur_loc >> 1 */
|
|
||||||
/*
|
|
||||||
StoreInst *Store = IRB.CreateStore(ConstantInt::get(Int32Ty, L >> 1),
|
|
||||||
OldPrev); Store->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C,
|
|
||||||
None));
|
|
||||||
*/
|
|
||||||
|
|
||||||
total_instr++;
|
total_instr++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OKF("Instrumented %u locations (%llu, %llu) (%s mode)\n" /*", ratio
|
OKF("Instrumented %u locations (%llu, %llu) (%s mode)\n",
|
||||||
%u%%)."*/
|
|
||||||
,
|
|
||||||
total_instr, total_rs, total_hs,
|
total_instr, total_rs, total_hs,
|
||||||
getenv("AFL_HARDEN")
|
getenv("AFL_HARDEN")
|
||||||
? "hardened"
|
? "hardened"
|
||||||
: ((getenv("AFL_USE_ASAN") || getenv("AFL_USE_MSAN"))
|
: ((getenv("AFL_USE_ASAN") || getenv("AFL_USE_MSAN"))
|
||||||
? "ASAN/MSAN"
|
? "ASAN/MSAN"
|
||||||
: "non-hardened") /*, inst_ratio*/);
|
: "non-hardened"));
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -65,16 +65,11 @@ void buildCFG(Function *F) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// uint32_t FakeID = 0;
|
|
||||||
for (auto S = F->begin(), E = F->end(); S != E; ++S) {
|
for (auto S = F->begin(), E = F->end(); S != E; ++S) {
|
||||||
|
|
||||||
BasicBlock *BB = &*S;
|
BasicBlock *BB = &*S;
|
||||||
uint32_t MyID = LMap[BB];
|
uint32_t MyID = LMap[BB];
|
||||||
// if (succ_begin(BB) == succ_end(BB)) {
|
|
||||||
|
|
||||||
// Succs[MyID].push_back(FakeID);
|
|
||||||
// Marked.insert(MyID);
|
|
||||||
//}
|
|
||||||
for (auto I = succ_begin(BB), E = succ_end(BB); I != E; ++I) {
|
for (auto I = succ_begin(BB), E = succ_end(BB); I != E; ++I) {
|
||||||
|
|
||||||
Succs[MyID].push_back(LMap[*I]);
|
Succs[MyID].push_back(LMap[*I]);
|
||||||
@ -113,7 +108,7 @@ void DFStree(size_t now_id) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void turnCFGintoDAG(Function *F) {
|
void turnCFGintoDAG() {
|
||||||
|
|
||||||
tSuccs = Succs;
|
tSuccs = Succs;
|
||||||
tag.resize(Blocks.size());
|
tag.resize(Blocks.size());
|
||||||
@ -176,7 +171,7 @@ void DFS(uint32_t now) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DominatorTree(Function *F) {
|
void DominatorTree() {
|
||||||
|
|
||||||
if (Blocks.empty()) return;
|
if (Blocks.empty()) return;
|
||||||
uint32_t s = start_point;
|
uint32_t s = start_point;
|
||||||
@ -390,7 +385,7 @@ void MarkSubGraph(uint32_t ss, uint32_t tt) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkVertice(Function *F) {
|
void MarkVertice() {
|
||||||
|
|
||||||
uint32_t s = start_point;
|
uint32_t s = start_point;
|
||||||
|
|
||||||
@ -411,8 +406,6 @@ void MarkVertice(Function *F) {
|
|||||||
|
|
||||||
timeStamp = 0;
|
timeStamp = 0;
|
||||||
uint32_t t = 0;
|
uint32_t t = 0;
|
||||||
// MarkSubGraph(s, t);
|
|
||||||
// return;
|
|
||||||
|
|
||||||
while (s != t) {
|
while (s != t) {
|
||||||
|
|
||||||
@ -432,9 +425,9 @@ std::pair<std::vector<BasicBlock *>, std::vector<BasicBlock *> > markNodes(
|
|||||||
reset();
|
reset();
|
||||||
labelEachBlock(F);
|
labelEachBlock(F);
|
||||||
buildCFG(F);
|
buildCFG(F);
|
||||||
turnCFGintoDAG(F);
|
turnCFGintoDAG();
|
||||||
DominatorTree::DominatorTree(F);
|
DominatorTree::DominatorTree();
|
||||||
MarkVertice(F);
|
MarkVertice();
|
||||||
|
|
||||||
std::vector<BasicBlock *> Result, ResultAbove;
|
std::vector<BasicBlock *> Result, ResultAbove;
|
||||||
for (uint32_t x : Markabove) {
|
for (uint32_t x : Markabove) {
|
||||||
|
@ -198,24 +198,23 @@ PS. Because there are task switches still involved, the mode isn't as fast as
|
|||||||
faster than the normal fork() model, and compared to in-process fuzzing,
|
faster than the normal fork() model, and compared to in-process fuzzing,
|
||||||
should be a lot more robust.
|
should be a lot more robust.
|
||||||
|
|
||||||
## 8) Bonus feature #3: new 'trace-pc-guard' mode
|
## 8) Bonus feature #3: 'trace-pc-guard' mode
|
||||||
|
|
||||||
Recent versions of LLVM are shipping with a built-in execution tracing feature
|
LLVM is shipping with a built-in execution tracing feature
|
||||||
that provides AFL with the necessary tracing data without the need to
|
that provides AFL with the necessary tracing data without the need to
|
||||||
post-process the assembly or install any compiler plugins. See:
|
post-process the assembly or install any compiler plugins. See:
|
||||||
|
|
||||||
http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards
|
http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards
|
||||||
|
|
||||||
If you have a sufficiently recent compiler and want to give it a try, build
|
If you have not an outdated compiler and want to give it a try, build
|
||||||
afl-clang-fast this way:
|
targets this way:
|
||||||
|
|
||||||
```
|
```
|
||||||
AFL_TRACE_PC=1 make clean all
|
libtarget-1.0 $ AFL_LLVM_USE_TRACE_PC=1 make
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that this mode is currently about 20% slower than "vanilla" afl-clang-fast,
|
Note that this mode is about 20% slower than "vanilla" afl-clang-fast,
|
||||||
and about 5-10% slower than afl-clang. This is likely because the
|
and about 5-10% slower than afl-clang. This is likely because the
|
||||||
instrumentation is not inlined, and instead involves a function call. On systems
|
instrumentation is not inlined, and instead involves a function call.
|
||||||
that support it, compiling your target with -flto should help.
|
On systems that support it, compiling your target with -flto can help
|
||||||
|
a bit.
|
||||||
|
|
||||||
|
@ -204,13 +204,24 @@ static void edit_params(u32 argc, char** argv) {
|
|||||||
// "-fsanitize-coverage=trace-cmp,trace-div,trace-gep";
|
// "-fsanitize-coverage=trace-cmp,trace-div,trace-gep";
|
||||||
// cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=0";
|
// cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=0";
|
||||||
#else
|
#else
|
||||||
cc_params[cc_par_cnt++] = "-Xclang";
|
if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") ||
|
||||||
cc_params[cc_par_cnt++] = "-load";
|
getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC")) {
|
||||||
cc_params[cc_par_cnt++] = "-Xclang";
|
|
||||||
if (getenv("AFL_LLVM_INSTRIM") != NULL || getenv("INSTRIM_LIB") != NULL)
|
cc_params[cc_par_cnt++] =
|
||||||
cc_params[cc_par_cnt++] = alloc_printf("%s/libLLVMInsTrim.so", obj_path);
|
"-fsanitize-coverage=trace-pc-guard"; // edge coverage by default
|
||||||
else
|
|
||||||
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path);
|
} else {
|
||||||
|
|
||||||
|
cc_params[cc_par_cnt++] = "-Xclang";
|
||||||
|
cc_params[cc_par_cnt++] = "-load";
|
||||||
|
cc_params[cc_par_cnt++] = "-Xclang";
|
||||||
|
if (getenv("AFL_LLVM_INSTRIM") != NULL || getenv("INSTRIM_LIB") != NULL)
|
||||||
|
cc_params[cc_par_cnt++] = alloc_printf("%s/libLLVMInsTrim.so", obj_path);
|
||||||
|
else
|
||||||
|
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* ^USE_TRACE_PC */
|
#endif /* ^USE_TRACE_PC */
|
||||||
|
|
||||||
cc_params[cc_par_cnt++] = "-Qunused-arguments";
|
cc_params[cc_par_cnt++] = "-Qunused-arguments";
|
||||||
@ -282,8 +293,10 @@ static void edit_params(u32 argc, char** argv) {
|
|||||||
|
|
||||||
#ifdef USE_TRACE_PC
|
#ifdef USE_TRACE_PC
|
||||||
|
|
||||||
if (getenv("AFL_INST_RATIO"))
|
if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") ||
|
||||||
FATAL("AFL_INST_RATIO not available at compile time with 'trace-pc'.");
|
getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC"))
|
||||||
|
if (getenv("AFL_INST_RATIO"))
|
||||||
|
FATAL("AFL_INST_RATIO not available at compile time with 'trace-pc'.");
|
||||||
|
|
||||||
#endif /* USE_TRACE_PC */
|
#endif /* USE_TRACE_PC */
|
||||||
|
|
||||||
@ -444,7 +457,8 @@ int main(int argc, char** argv) {
|
|||||||
"You can specify custom next-stage toolchain via AFL_CC and AFL_CXX. "
|
"You can specify custom next-stage toolchain via AFL_CC and AFL_CXX. "
|
||||||
"Setting\n"
|
"Setting\n"
|
||||||
"AFL_HARDEN enables hardening optimizations in the compiled code.\n\n"
|
"AFL_HARDEN enables hardening optimizations in the compiled code.\n\n"
|
||||||
"afl-clang-fast was built for llvm %s with the llvm binary path of \"%s\".\n\n",
|
"afl-clang-fast was built for llvm %s with the llvm binary path of "
|
||||||
|
"\"%s\".\n\n",
|
||||||
BIN_PATH, BIN_PATH, LLVM_VERSION, LLVM_BINDIR);
|
BIN_PATH, BIN_PATH, LLVM_VERSION, LLVM_BINDIR);
|
||||||
|
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -454,6 +468,8 @@ int main(int argc, char** argv) {
|
|||||||
#ifdef USE_TRACE_PC
|
#ifdef USE_TRACE_PC
|
||||||
SAYF(cCYA "afl-clang-fast" VERSION cRST
|
SAYF(cCYA "afl-clang-fast" VERSION cRST
|
||||||
" [tpcg] by <lszekeres@google.com>\n");
|
" [tpcg] by <lszekeres@google.com>\n");
|
||||||
|
#warning \
|
||||||
|
"You do not need to specifically compile with USE_TRACE_PC anymore, setting the environment variable AFL_LLVM_USE_TRACE_PC is enough."
|
||||||
#else
|
#else
|
||||||
SAYF(cCYA "afl-clang-fast" VERSION cRST " by <lszekeres@google.com>\n");
|
SAYF(cCYA "afl-clang-fast" VERSION cRST " by <lszekeres@google.com>\n");
|
||||||
#endif /* ^USE_TRACE_PC */
|
#endif /* ^USE_TRACE_PC */
|
||||||
|
@ -75,6 +75,28 @@ class AFLCoverage : public ModulePass {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ripped from aflgo
|
||||||
|
static bool isBlacklisted(const Function *F) {
|
||||||
|
|
||||||
|
static const SmallVector<std::string, 4> Blacklist = {
|
||||||
|
|
||||||
|
"asan.",
|
||||||
|
"llvm.",
|
||||||
|
"sancov.",
|
||||||
|
"__ubsan_handle_",
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto const &BlacklistFunc : Blacklist) {
|
||||||
|
|
||||||
|
if (F->getName().startswith(BlacklistFunc)) { return true; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool runOnModule(Module &M) override;
|
bool runOnModule(Module &M) override;
|
||||||
|
|
||||||
// StringRef getPassName() const override {
|
// StringRef getPassName() const override {
|
||||||
@ -156,13 +178,11 @@ bool AFLCoverage::runOnModule(Module &M) {
|
|||||||
|
|
||||||
/* Instrument all the things! */
|
/* Instrument all the things! */
|
||||||
|
|
||||||
const char *IntrinsicPrefix = "llvm.";
|
|
||||||
int inst_blocks = 0;
|
int inst_blocks = 0;
|
||||||
|
|
||||||
for (auto &F : M) {
|
for (auto &F : M) {
|
||||||
|
|
||||||
auto Fname = F.getName();
|
if (isBlacklisted(&F)) continue;
|
||||||
if (Fname.startswith(IntrinsicPrefix)) continue;
|
|
||||||
|
|
||||||
for (auto &BB : F) {
|
for (auto &BB : F) {
|
||||||
|
|
||||||
@ -377,6 +397,7 @@ bool AFLCoverage::runOnModule(Module &M) {
|
|||||||
inst_blocks++;
|
inst_blocks++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Say something nice. */
|
/* Say something nice. */
|
||||||
|
@ -18,7 +18,13 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
|
#include "llvm/IR/DebugInfo.h"
|
||||||
#include "llvm/IR/IRBuilder.h"
|
#include "llvm/IR/IRBuilder.h"
|
||||||
#include "llvm/IR/LegacyPassManager.h"
|
#include "llvm/IR/LegacyPassManager.h"
|
||||||
#include "llvm/IR/Module.h"
|
#include "llvm/IR/Module.h"
|
||||||
@ -42,6 +48,23 @@ class CompareTransform : public ModulePass {
|
|||||||
static char ID;
|
static char ID;
|
||||||
CompareTransform() : ModulePass(ID) {
|
CompareTransform() : ModulePass(ID) {
|
||||||
|
|
||||||
|
char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST");
|
||||||
|
if (instWhiteListFilename) {
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
std::ifstream fileStream;
|
||||||
|
fileStream.open(instWhiteListFilename);
|
||||||
|
if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST");
|
||||||
|
getline(fileStream, line);
|
||||||
|
while (fileStream) {
|
||||||
|
|
||||||
|
myWhitelist.push_back(line);
|
||||||
|
getline(fileStream, line);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool runOnModule(Module &M) override;
|
bool runOnModule(Module &M) override;
|
||||||
@ -57,6 +80,9 @@ class CompareTransform : public ModulePass {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::list<std::string> myWhitelist;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool transformCmps(Module &M, const bool processStrcmp,
|
bool transformCmps(Module &M, const bool processStrcmp,
|
||||||
const bool processMemcmp, const bool processStrncmp,
|
const bool processMemcmp, const bool processStrncmp,
|
||||||
@ -104,6 +130,74 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
|
|||||||
|
|
||||||
for (auto &BB : F) {
|
for (auto &BB : F) {
|
||||||
|
|
||||||
|
if (!myWhitelist.empty()) {
|
||||||
|
|
||||||
|
BasicBlock::iterator IP = BB.getFirstInsertionPt();
|
||||||
|
|
||||||
|
bool instrumentBlock = false;
|
||||||
|
|
||||||
|
/* Get the current location using debug information.
|
||||||
|
* For now, just instrument the block if we are not able
|
||||||
|
* to determine our location. */
|
||||||
|
DebugLoc Loc = IP->getDebugLoc();
|
||||||
|
if (Loc) {
|
||||||
|
|
||||||
|
DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
|
||||||
|
|
||||||
|
unsigned int instLine = cDILoc->getLine();
|
||||||
|
StringRef instFilename = cDILoc->getFilename();
|
||||||
|
|
||||||
|
if (instFilename.str().empty()) {
|
||||||
|
|
||||||
|
/* If the original location is empty, try using the inlined location
|
||||||
|
*/
|
||||||
|
DILocation *oDILoc = cDILoc->getInlinedAt();
|
||||||
|
if (oDILoc) {
|
||||||
|
|
||||||
|
instFilename = oDILoc->getFilename();
|
||||||
|
instLine = oDILoc->getLine();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)instLine;
|
||||||
|
|
||||||
|
/* Continue only if we know where we actually are */
|
||||||
|
if (!instFilename.str().empty()) {
|
||||||
|
|
||||||
|
for (std::list<std::string>::iterator it = myWhitelist.begin();
|
||||||
|
it != myWhitelist.end(); ++it) {
|
||||||
|
|
||||||
|
/* We don't check for filename equality here because
|
||||||
|
* filenames might actually be full paths. Instead we
|
||||||
|
* check that the actual filename ends in the filename
|
||||||
|
* specified in the list. */
|
||||||
|
if (instFilename.str().length() >= it->length()) {
|
||||||
|
|
||||||
|
if (instFilename.str().compare(
|
||||||
|
instFilename.str().length() - it->length(),
|
||||||
|
it->length(), *it) == 0) {
|
||||||
|
|
||||||
|
instrumentBlock = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Either we couldn't figure out our location or the location is
|
||||||
|
* not whitelisted, so we skip instrumentation. */
|
||||||
|
if (!instrumentBlock) continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
for (auto &IN : BB) {
|
for (auto &IN : BB) {
|
||||||
|
|
||||||
CallInst *callInst = nullptr;
|
CallInst *callInst = nullptr;
|
||||||
|
@ -15,7 +15,17 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include "llvm/Pass.h"
|
#include "llvm/Pass.h"
|
||||||
|
#include "llvm/IR/DebugInfo.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
#include "llvm/IR/LegacyPassManager.h"
|
#include "llvm/IR/LegacyPassManager.h"
|
||||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||||
@ -35,6 +45,41 @@ class SplitComparesTransform : public ModulePass {
|
|||||||
static char ID;
|
static char ID;
|
||||||
SplitComparesTransform() : ModulePass(ID) {
|
SplitComparesTransform() : ModulePass(ID) {
|
||||||
|
|
||||||
|
char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST");
|
||||||
|
if (instWhiteListFilename) {
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
std::ifstream fileStream;
|
||||||
|
fileStream.open(instWhiteListFilename);
|
||||||
|
if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST");
|
||||||
|
getline(fileStream, line);
|
||||||
|
while (fileStream) {
|
||||||
|
|
||||||
|
myWhitelist.push_back(line);
|
||||||
|
getline(fileStream, line);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isBlacklisted(const Function *F) {
|
||||||
|
|
||||||
|
static const SmallVector<std::string, 5> Blacklist = {
|
||||||
|
|
||||||
|
"asan.", "llvm.", "sancov.", "__ubsan_handle_", "ign."
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto const &BlacklistFunc : Blacklist) {
|
||||||
|
|
||||||
|
if (F->getName().startswith(BlacklistFunc)) { return true; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool runOnModule(Module &M) override;
|
bool runOnModule(Module &M) override;
|
||||||
@ -49,6 +94,9 @@ class SplitComparesTransform : public ModulePass {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::list<std::string> myWhitelist;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int enableFPSplit;
|
int enableFPSplit;
|
||||||
|
|
||||||
@ -77,8 +125,78 @@ bool SplitComparesTransform::simplifyCompares(Module &M) {
|
|||||||
* all integer comparisons with >= and <= predicates to the icomps vector */
|
* all integer comparisons with >= and <= predicates to the icomps vector */
|
||||||
for (auto &F : M) {
|
for (auto &F : M) {
|
||||||
|
|
||||||
|
if (isBlacklisted(&F)) continue;
|
||||||
|
|
||||||
for (auto &BB : F) {
|
for (auto &BB : F) {
|
||||||
|
|
||||||
|
if (!myWhitelist.empty()) {
|
||||||
|
|
||||||
|
bool instrumentBlock = false;
|
||||||
|
|
||||||
|
BasicBlock::iterator IP = BB.getFirstInsertionPt();
|
||||||
|
|
||||||
|
/* Get the current location using debug information.
|
||||||
|
* For now, just instrument the block if we are not able
|
||||||
|
* to determine our location. */
|
||||||
|
DebugLoc Loc = IP->getDebugLoc();
|
||||||
|
if (Loc) {
|
||||||
|
|
||||||
|
DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
|
||||||
|
|
||||||
|
unsigned int instLine = cDILoc->getLine();
|
||||||
|
StringRef instFilename = cDILoc->getFilename();
|
||||||
|
|
||||||
|
if (instFilename.str().empty()) {
|
||||||
|
|
||||||
|
/* If the original location is empty, try using the inlined location
|
||||||
|
*/
|
||||||
|
DILocation *oDILoc = cDILoc->getInlinedAt();
|
||||||
|
if (oDILoc) {
|
||||||
|
|
||||||
|
instFilename = oDILoc->getFilename();
|
||||||
|
instLine = oDILoc->getLine();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)instLine;
|
||||||
|
|
||||||
|
/* Continue only if we know where we actually are */
|
||||||
|
if (!instFilename.str().empty()) {
|
||||||
|
|
||||||
|
for (std::list<std::string>::iterator it = myWhitelist.begin();
|
||||||
|
it != myWhitelist.end(); ++it) {
|
||||||
|
|
||||||
|
/* We don't check for filename equality here because
|
||||||
|
* filenames might actually be full paths. Instead we
|
||||||
|
* check that the actual filename ends in the filename
|
||||||
|
* specified in the list. */
|
||||||
|
if (instFilename.str().length() >= it->length()) {
|
||||||
|
|
||||||
|
if (instFilename.str().compare(
|
||||||
|
instFilename.str().length() - it->length(),
|
||||||
|
it->length(), *it) == 0) {
|
||||||
|
|
||||||
|
instrumentBlock = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Either we couldn't figure out our location or the location is
|
||||||
|
* not whitelisted, so we skip instrumentation. */
|
||||||
|
if (!instrumentBlock) continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
for (auto &IN : BB) {
|
for (auto &IN : BB) {
|
||||||
|
|
||||||
CmpInst *selectcmpInst = nullptr;
|
CmpInst *selectcmpInst = nullptr;
|
||||||
|
@ -18,7 +18,13 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
|
#include "llvm/IR/DebugInfo.h"
|
||||||
#include "llvm/IR/IRBuilder.h"
|
#include "llvm/IR/IRBuilder.h"
|
||||||
#include "llvm/IR/LegacyPassManager.h"
|
#include "llvm/IR/LegacyPassManager.h"
|
||||||
#include "llvm/IR/Module.h"
|
#include "llvm/IR/Module.h"
|
||||||
@ -42,6 +48,41 @@ class SplitSwitchesTransform : public ModulePass {
|
|||||||
static char ID;
|
static char ID;
|
||||||
SplitSwitchesTransform() : ModulePass(ID) {
|
SplitSwitchesTransform() : ModulePass(ID) {
|
||||||
|
|
||||||
|
char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST");
|
||||||
|
if (instWhiteListFilename) {
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
std::ifstream fileStream;
|
||||||
|
fileStream.open(instWhiteListFilename);
|
||||||
|
if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST");
|
||||||
|
getline(fileStream, line);
|
||||||
|
while (fileStream) {
|
||||||
|
|
||||||
|
myWhitelist.push_back(line);
|
||||||
|
getline(fileStream, line);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isBlacklisted(const Function *F) {
|
||||||
|
|
||||||
|
static const SmallVector<std::string, 5> Blacklist = {
|
||||||
|
|
||||||
|
"asan.", "llvm.", "sancov.", "__ubsan_handle_", "ign."
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto const &BlacklistFunc : Blacklist) {
|
||||||
|
|
||||||
|
if (F->getName().startswith(BlacklistFunc)) { return true; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool runOnModule(Module &M) override;
|
bool runOnModule(Module &M) override;
|
||||||
@ -71,6 +112,9 @@ class SplitSwitchesTransform : public ModulePass {
|
|||||||
|
|
||||||
typedef std::vector<CaseExpr> CaseVector;
|
typedef std::vector<CaseExpr> CaseVector;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::list<std::string> myWhitelist;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool splitSwitches(Module &M);
|
bool splitSwitches(Module &M);
|
||||||
bool transformCmps(Module &M, const bool processStrcmp,
|
bool transformCmps(Module &M, const bool processStrcmp,
|
||||||
@ -268,10 +312,79 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
|
|||||||
* all switches to switches vector for later processing */
|
* all switches to switches vector for later processing */
|
||||||
for (auto &F : M) {
|
for (auto &F : M) {
|
||||||
|
|
||||||
|
if (isBlacklisted(&F)) continue;
|
||||||
|
|
||||||
for (auto &BB : F) {
|
for (auto &BB : F) {
|
||||||
|
|
||||||
SwitchInst *switchInst = nullptr;
|
SwitchInst *switchInst = nullptr;
|
||||||
|
|
||||||
|
if (!myWhitelist.empty()) {
|
||||||
|
|
||||||
|
bool instrumentBlock = false;
|
||||||
|
BasicBlock::iterator IP = BB.getFirstInsertionPt();
|
||||||
|
|
||||||
|
/* Get the current location using debug information.
|
||||||
|
* For now, just instrument the block if we are not able
|
||||||
|
* to determine our location. */
|
||||||
|
DebugLoc Loc = IP->getDebugLoc();
|
||||||
|
if (Loc) {
|
||||||
|
|
||||||
|
DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
|
||||||
|
|
||||||
|
unsigned int instLine = cDILoc->getLine();
|
||||||
|
StringRef instFilename = cDILoc->getFilename();
|
||||||
|
|
||||||
|
if (instFilename.str().empty()) {
|
||||||
|
|
||||||
|
/* If the original location is empty, try using the inlined location
|
||||||
|
*/
|
||||||
|
DILocation *oDILoc = cDILoc->getInlinedAt();
|
||||||
|
if (oDILoc) {
|
||||||
|
|
||||||
|
instFilename = oDILoc->getFilename();
|
||||||
|
instLine = oDILoc->getLine();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)instLine;
|
||||||
|
|
||||||
|
/* Continue only if we know where we actually are */
|
||||||
|
if (!instFilename.str().empty()) {
|
||||||
|
|
||||||
|
for (std::list<std::string>::iterator it = myWhitelist.begin();
|
||||||
|
it != myWhitelist.end(); ++it) {
|
||||||
|
|
||||||
|
/* We don't check for filename equality here because
|
||||||
|
* filenames might actually be full paths. Instead we
|
||||||
|
* check that the actual filename ends in the filename
|
||||||
|
* specified in the list. */
|
||||||
|
if (instFilename.str().length() >= it->length()) {
|
||||||
|
|
||||||
|
if (instFilename.str().compare(
|
||||||
|
instFilename.str().length() - it->length(),
|
||||||
|
it->length(), *it) == 0) {
|
||||||
|
|
||||||
|
instrumentBlock = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Either we couldn't figure out our location or the location is
|
||||||
|
* not whitelisted, so we skip instrumentation. */
|
||||||
|
if (!instrumentBlock) continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if ((switchInst = dyn_cast<SwitchInst>(BB.getTerminator()))) {
|
if ((switchInst = dyn_cast<SwitchInst>(BB.getTerminator()))) {
|
||||||
|
|
||||||
if (switchInst->getNumCases() < 1) continue;
|
if (switchInst->getNumCases() < 1) continue;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
@ -524,7 +524,12 @@ u8 save_if_interesting(char** argv, void* mem, u32 len, u8 fault) {
|
|||||||
struct queue_entry* q = queue;
|
struct queue_entry* q = queue;
|
||||||
while (q) {
|
while (q) {
|
||||||
|
|
||||||
if (q->exec_cksum == cksum) q->n_fuzz = q->n_fuzz + 1;
|
if (q->exec_cksum == cksum) {
|
||||||
|
|
||||||
|
q->n_fuzz = q->n_fuzz + 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
q = q->next;
|
q = q->next;
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
@ -334,9 +334,9 @@ void show_stats(void) {
|
|||||||
|
|
||||||
/* Lord, forgive me this. */
|
/* Lord, forgive me this. */
|
||||||
|
|
||||||
SAYF(SET_G1 bSTG bLT bH bSTOP cCYA
|
SAYF(SET_G1 bSTG bLT bH bSTOP cCYA
|
||||||
" process timing " bSTG bH30 bH5 bH bHB bH bSTOP cCYA
|
" process timing " bSTG bH30 bH5 bH bHB bH bSTOP cCYA
|
||||||
" overall results " bSTG bH2 bH2 bRT "\n");
|
" overall results " bSTG bH2 bH2 bRT "\n");
|
||||||
|
|
||||||
if (dumb_mode) {
|
if (dumb_mode) {
|
||||||
|
|
||||||
@ -413,9 +413,9 @@ void show_stats(void) {
|
|||||||
" uniq hangs : " cRST "%-6s" bSTG bV "\n",
|
" uniq hangs : " cRST "%-6s" bSTG bV "\n",
|
||||||
DTD(cur_ms, last_hang_time), tmp);
|
DTD(cur_ms, last_hang_time), tmp);
|
||||||
|
|
||||||
SAYF(bVR bH bSTOP cCYA
|
SAYF(bVR bH bSTOP cCYA
|
||||||
" cycle progress " bSTG bH10 bH5 bH2 bH2 bHB bH bSTOP cCYA
|
" cycle progress " bSTG bH10 bH5 bH2 bH2 bHB bH bSTOP cCYA
|
||||||
" map coverage " bSTG bH bHT bH20 bH2 bVL "\n");
|
" map coverage " bSTG bH bHT bH20 bH2 bVL "\n");
|
||||||
|
|
||||||
/* This gets funny because we want to print several variable-length variables
|
/* This gets funny because we want to print several variable-length variables
|
||||||
together, but then cram them into a fixed-width field - so we need to
|
together, but then cram them into a fixed-width field - so we need to
|
||||||
@ -443,9 +443,9 @@ void show_stats(void) {
|
|||||||
|
|
||||||
SAYF(bSTOP " count coverage : " cRST "%-21s" bSTG bV "\n", tmp);
|
SAYF(bSTOP " count coverage : " cRST "%-21s" bSTG bV "\n", tmp);
|
||||||
|
|
||||||
SAYF(bVR bH bSTOP cCYA
|
SAYF(bVR bH bSTOP cCYA
|
||||||
" stage progress " bSTG bH10 bH5 bH2 bH2 bX bH bSTOP cCYA
|
" stage progress " bSTG bH10 bH5 bH2 bH2 bX bH bSTOP cCYA
|
||||||
" findings in depth " bSTG bH10 bH5 bH2 bH2 bVL "\n");
|
" findings in depth " bSTG bH10 bH5 bH2 bH2 bVL "\n");
|
||||||
|
|
||||||
sprintf(tmp, "%s (%0.02f%%)", DI(queued_favored),
|
sprintf(tmp, "%s (%0.02f%%)", DI(queued_favored),
|
||||||
((double)queued_favored) * 100 / queued_paths);
|
((double)queued_favored) * 100 / queued_paths);
|
||||||
@ -514,7 +514,7 @@ void show_stats(void) {
|
|||||||
|
|
||||||
/* Aaaalmost there... hold on! */
|
/* Aaaalmost there... hold on! */
|
||||||
|
|
||||||
SAYF(bVR bH cCYA bSTOP
|
SAYF(bVR bH cCYA bSTOP
|
||||||
" fuzzing strategy yields " bSTG bH10 bHT bH10 bH5 bHB bH bSTOP cCYA
|
" fuzzing strategy yields " bSTG bH10 bHT bH10 bH5 bHB bH bSTOP cCYA
|
||||||
" path geometry " bSTG bH5 bH2 bVL "\n");
|
" path geometry " bSTG bH5 bH2 bVL "\n");
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Originally written by Michal Zalewski
|
Originally written by Michal Zalewski
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||||
|
|
||||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
|
||||||
|
12
src/third_party/libradamsa/Makefile
vendored
12
src/third_party/libradamsa/Makefile
vendored
@ -2,17 +2,23 @@ CUR_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
|||||||
|
|
||||||
all: libradamsa.so
|
all: libradamsa.so
|
||||||
|
|
||||||
|
# These can be overriden:
|
||||||
|
CFLAGS ?= -march=native $(CFLAGS_FLTO)
|
||||||
|
|
||||||
|
# These are required: (otherwise radamsa gets very very slooooow)
|
||||||
|
CFLAGS += -O3 -funroll-loops
|
||||||
|
|
||||||
libradamsa.so: libradamsa.a
|
libradamsa.so: libradamsa.a
|
||||||
$(CC) -O3 -shared libradamsa.a -o libradamsa.so
|
$(CC) $(CFLAGS) -shared libradamsa.a -o libradamsa.so
|
||||||
|
|
||||||
libradamsa.a: libradamsa.c radamsa.h
|
libradamsa.a: libradamsa.c radamsa.h
|
||||||
@echo " ***************************************************************"
|
@echo " ***************************************************************"
|
||||||
@echo " * Compiling libradamsa, wait some minutes (~3 on modern CPUs) *"
|
@echo " * Compiling libradamsa, wait some minutes (~3 on modern CPUs) *"
|
||||||
@echo " ***************************************************************"
|
@echo " ***************************************************************"
|
||||||
$(CC) -fPIC -O3 -I $(CUR_DIR) -o libradamsa.a -c libradamsa.c
|
$(CC) -fPIC $(CFLAGS) -I $(CUR_DIR) -o libradamsa.a -c libradamsa.c
|
||||||
|
|
||||||
test: libradamsa.a libradamsa-test.c
|
test: libradamsa.a libradamsa-test.c
|
||||||
cc -O3 -I $(CUR_DIR) -o libradamsa-test libradamsa-test.c libradamsa.a
|
$(CC) $(CFLAGS) -I $(CUR_DIR) -o libradamsa-test libradamsa-test.c libradamsa.a
|
||||||
./libradamsa-test libradamsa-test.c | grep "library test passed"
|
./libradamsa-test libradamsa-test.c | grep "library test passed"
|
||||||
rm /tmp/libradamsa-*.fuzz
|
rm /tmp/libradamsa-*.fuzz
|
||||||
|
|
||||||
|
25
test/test-unsigaction.c
Normal file
25
test/test-unsigaction.c
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include <signal.h> /* sigemptyset(), sigaction(), kill(), SIGUSR1 */
|
||||||
|
#include <stdlib.h> /* exit() */
|
||||||
|
#include <unistd.h> /* getpid() */
|
||||||
|
#include <errno.h> /* errno */
|
||||||
|
#include <stdio.h> /* fprintf() */
|
||||||
|
|
||||||
|
static void mysig_handler(int sig)
|
||||||
|
{
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
/* setup sig handler */
|
||||||
|
struct sigaction sa;
|
||||||
|
sa.sa_handler = mysig_handler;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = 0;
|
||||||
|
if (sigaction(SIGCHLD, &sa, NULL)) {
|
||||||
|
fprintf(stderr, "could not set signal handler %d, aborted\n", errno);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
kill(getpid(), SIGCHLD);
|
||||||
|
return 0;
|
||||||
|
}
|
115
test/test.sh
115
test/test.sh
@ -150,15 +150,15 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" && {
|
|||||||
}
|
}
|
||||||
echo 000000000000000000000000 > in/in2
|
echo 000000000000000000000000 > in/in2
|
||||||
mkdir -p in2
|
mkdir -p in2
|
||||||
../afl-cmin -i in -o in2 -- ./test-instr.plain > /dev/null 2>&1
|
../afl-cmin -i in -o in2 -- ./test-instr.plain > /dev/null
|
||||||
CNT=`ls in2/ | wc -l`
|
CNT=`ls in2/ | wc -l`
|
||||||
case "$CNT" in
|
case "$CNT" in
|
||||||
1| *1) $ECHO "$GREEN[+] afl-cmin correctly minimized testcase numbers" ;;
|
*1) $ECHO "$GREEN[+] afl-cmin correctly minimized the number of testcases" ;;
|
||||||
*) $ECHO "$RED[!] afl-cmin did not correctly minimize testcase numbers"
|
*) $ECHO "$RED[!] afl-cmin did not correctly minimize the number of testcases"
|
||||||
CODE=1
|
CODE=1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
../afl-tmin -m200 -i in/in2 -o in2/in2 -- ./test-instr.plain > /dev/null 2>&1
|
../afl-tmin -i in/in2 -o in2/in2 -- ./test-instr.plain > /dev/null 2>&1
|
||||||
SIZE=`ls -l in2/in2 2> /dev/null | awk '{print$5}'`
|
SIZE=`ls -l in2/in2 2> /dev/null | awk '{print$5}'`
|
||||||
test "$SIZE" = 1 && $ECHO "$GREEN[+] afl-tmin correctly minimized the testcase"
|
test "$SIZE" = 1 && $ECHO "$GREEN[+] afl-tmin correctly minimized the testcase"
|
||||||
test "$SIZE" = 1 || {
|
test "$SIZE" = 1 || {
|
||||||
@ -176,14 +176,16 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" && {
|
|||||||
$ECHO "$YELLOW[-] not an intel platform, cannot test afl-gcc"
|
$ECHO "$YELLOW[-] not an intel platform, cannot test afl-gcc"
|
||||||
}
|
}
|
||||||
|
|
||||||
$ECHO "$BLUE[*] Testing: llvm_mode"
|
$ECHO "$BLUE[*] Testing: llvm_mode, afl-showmap, afl-fuzz, afl-cmin and afl-tmin"
|
||||||
test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
|
test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
|
||||||
# on FreeBSD need to set AFL_CC
|
# on FreeBSD need to set AFL_CC
|
||||||
if which clang >/dev/null; then
|
test `uname -s` = 'FreeBSD' && {
|
||||||
export AFL_CC=`which clang`
|
if which clang >/dev/null; then
|
||||||
else
|
export AFL_CC=`which clang`
|
||||||
export AFL_CC=`$LLVM_CONFIG --bindir`/clang
|
else
|
||||||
fi
|
export AFL_CC=`$LLVM_CONFIG --bindir`/clang
|
||||||
|
fi
|
||||||
|
}
|
||||||
../afl-clang-fast -o test-instr.plain ../test-instr.c > /dev/null 2>&1
|
../afl-clang-fast -o test-instr.plain ../test-instr.c > /dev/null 2>&1
|
||||||
AFL_HARDEN=1 ../afl-clang-fast -o test-compcov.harden test-compcov.c > /dev/null 2>&1
|
AFL_HARDEN=1 ../afl-clang-fast -o test-compcov.harden test-compcov.c > /dev/null 2>&1
|
||||||
test -e test-instr.plain && {
|
test -e test-instr.plain && {
|
||||||
@ -251,6 +253,26 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
|
|||||||
$ECHO "$RED[!] afl-fuzz is not working correctly with llvm_mode"
|
$ECHO "$RED[!] afl-fuzz is not working correctly with llvm_mode"
|
||||||
CODE=1
|
CODE=1
|
||||||
}
|
}
|
||||||
|
test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" || {
|
||||||
|
echo 000000000000000000000000 > in/in2
|
||||||
|
mkdir -p in2
|
||||||
|
../afl-cmin -i in -o in2 -- ./test-instr.plain > /dev/null
|
||||||
|
CNT=`ls in2/ | wc -l`
|
||||||
|
case "$CNT" in
|
||||||
|
*1) $ECHO "$GREEN[+] afl-cmin correctly minimized the number of testcases" ;;
|
||||||
|
*) $ECHO "$RED[!] afl-cmin did not correctly minimize the number of testcases"
|
||||||
|
CODE=1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
../afl-tmin -i in/in2 -o in2/in2 -- ./test-instr.plain > /dev/null 2>&1
|
||||||
|
SIZE=`ls -l in2/in2 2> /dev/null | awk '{print$5}'`
|
||||||
|
test "$SIZE" = 1 && $ECHO "$GREEN[+] afl-tmin correctly minimized the testcase"
|
||||||
|
test "$SIZE" = 1 || {
|
||||||
|
$ECHO "$RED[!] afl-tmin did incorrectly minimize the testcase to $SIZE"
|
||||||
|
CODE=1
|
||||||
|
}
|
||||||
|
rm -rf in2
|
||||||
|
}
|
||||||
rm -rf in out errors
|
rm -rf in out errors
|
||||||
}
|
}
|
||||||
rm -f test-instr.plain
|
rm -f test-instr.plain
|
||||||
@ -334,7 +356,7 @@ test -e ../afl-gcc-fast -a -e ../afl-gcc-rt.o && {
|
|||||||
$ECHO "$GREEN[+] gcc_plugin run reported $TUPLES instrumented locations which is fine"
|
$ECHO "$GREEN[+] gcc_plugin run reported $TUPLES instrumented locations which is fine"
|
||||||
} || {
|
} || {
|
||||||
$ECHO "$RED[!] gcc_plugin instrumentation produces a weird number of instrumented locations: $TUPLES"
|
$ECHO "$RED[!] gcc_plugin instrumentation produces a weird number of instrumented locations: $TUPLES"
|
||||||
$ECHO "$YELLOW[-] the gcc_plugin instrumentation issue is not flagged as an error because travis builds would all fail otherwise :-("
|
$ECHO "$YELLOW[-] this is a known issue in gcc, not afl++. It is not flagged as an error because travis builds would all fail otherwise :-("
|
||||||
#CODE=1
|
#CODE=1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -457,6 +479,15 @@ test -e ../libdislocator.so && {
|
|||||||
}
|
}
|
||||||
rm -f test-compcov
|
rm -f test-compcov
|
||||||
test -e ../libradamsa.so && {
|
test -e ../libradamsa.so && {
|
||||||
|
# on FreeBSD need to set AFL_CC
|
||||||
|
|
||||||
|
test `uname -s` = 'FreeBSD' && {
|
||||||
|
if which clang >/dev/null; then
|
||||||
|
export AFL_CC=`which clang`
|
||||||
|
else
|
||||||
|
export AFL_CC=`$LLVM_CONFIG --bindir`/clang
|
||||||
|
fi
|
||||||
|
}
|
||||||
test -e test-instr.plain || ../afl-clang-fast -o test-instr.plain ../test-instr.c > /dev/null 2>&1
|
test -e test-instr.plain || ../afl-clang-fast -o test-instr.plain ../test-instr.c > /dev/null 2>&1
|
||||||
test -e test-instr.plain || ../afl-gcc-fast -o test-instr.plain ../test-instr.c > /dev/null 2>&1
|
test -e test-instr.plain || ../afl-gcc-fast -o test-instr.plain ../test-instr.c > /dev/null 2>&1
|
||||||
test -e test-instr.plain || ../${AFL_GCC} -o test-instr.plain ../test-instr.c > /dev/null 2>&1
|
test -e test-instr.plain || ../${AFL_GCC} -o test-instr.plain ../test-instr.c > /dev/null 2>&1
|
||||||
@ -560,8 +591,64 @@ test -e ../afl-qemu-trace && {
|
|||||||
CODE=1
|
CODE=1
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
$ECHO "$YELLOW[-] we need a test case for qemu_mode unsigaction library"
|
|
||||||
rm -rf in out errors
|
rm -rf in out errors
|
||||||
|
test -e ../qemu_mode/unsigaction/unsigaction32.so && {
|
||||||
|
${AFL_CC} -o test-unsigaction32 -m32 test-unsigaction.c >> errors 2>&1 && {
|
||||||
|
./test-unsigaction32
|
||||||
|
RETVAL_NORMAL32=$?
|
||||||
|
LD_PRELOAD=../qemu_mode/unsigaction/unsigaction32.so ./test-unsigaction32
|
||||||
|
RETVAL_LIBUNSIGACTION32=$?
|
||||||
|
test $RETVAL_NORMAL32 = "2" -a $RETVAL_LIBUNSIGACTION32 = "0" && {
|
||||||
|
$ECHO "$GREEN[+] qemu_mode unsigaction library (32 bit) ignores signals"
|
||||||
|
} || {
|
||||||
|
test $RETVAL_NORMAL32 != "2" && {
|
||||||
|
$ECHO "$RED[!] cannot trigger signal in test program (32 bit)"
|
||||||
|
}
|
||||||
|
test $RETVAL_LIBUNSIGACTION32 != "0" && {
|
||||||
|
$ECHO "$RED[!] signal in test program (32 bit) is not ignored with unsigaction"
|
||||||
|
}
|
||||||
|
CODE=1
|
||||||
|
}
|
||||||
|
} || {
|
||||||
|
echo CUT------------------------------------------------------------------CUT
|
||||||
|
cat errors
|
||||||
|
echo CUT------------------------------------------------------------------CUT
|
||||||
|
$ECHO "$RED[!] cannot compile test program (32 bit) for unsigaction library"
|
||||||
|
CODE=1
|
||||||
|
}
|
||||||
|
} || {
|
||||||
|
$ECHO "$YELLOW[-] we cannot test qemu_mode unsigaction library (32 bit) because it is not present"
|
||||||
|
INCOMPLETE=1
|
||||||
|
}
|
||||||
|
test -e ../qemu_mode/unsigaction/unsigaction64.so && {
|
||||||
|
${AFL_CC} -o test-unsigaction64 -m64 test-unsigaction.c >> errors 2>&1 && {
|
||||||
|
./test-unsigaction64
|
||||||
|
RETVAL_NORMAL64=$?
|
||||||
|
LD_PRELOAD=../qemu_mode/unsigaction/unsigaction64.so ./test-unsigaction64
|
||||||
|
RETVAL_LIBUNSIGACTION64=$?
|
||||||
|
test $RETVAL_NORMAL64 = "2" -a $RETVAL_LIBUNSIGACTION64 = "0" && {
|
||||||
|
$ECHO "$GREEN[+] qemu_mode unsigaction library (64 bit) ignores signals"
|
||||||
|
} || {
|
||||||
|
test $RETVAL_NORMAL64 != "2" && {
|
||||||
|
$ECHO "$RED[!] cannot trigger signal in test program (64 bit)"
|
||||||
|
}
|
||||||
|
test $RETVAL_LIBUNSIGACTION64 != "0" && {
|
||||||
|
$ECHO "$RED[!] signal in test program (64 bit) is not ignored with unsigaction"
|
||||||
|
}
|
||||||
|
CODE=1
|
||||||
|
}
|
||||||
|
} || {
|
||||||
|
echo CUT------------------------------------------------------------------CUT
|
||||||
|
cat errors
|
||||||
|
echo CUT------------------------------------------------------------------CUT
|
||||||
|
$ECHO "$RED[!] cannot compile test program (64 bit) for unsigaction library"
|
||||||
|
CODE=1
|
||||||
|
}
|
||||||
|
} || {
|
||||||
|
$ECHO "$YELLOW[-] we cannot test qemu_mode unsigaction library (64 bit) because it is not present"
|
||||||
|
INCOMPLETE=1
|
||||||
|
}
|
||||||
|
rm -rf errors test-unsigaction32 test-unsigaction64
|
||||||
}
|
}
|
||||||
} || {
|
} || {
|
||||||
$ECHO "$RED[!] gcc compilation of test targets failed - what is going on??"
|
$ECHO "$RED[!] gcc compilation of test targets failed - what is going on??"
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
Simple test harness for AFL++'s unicornafl c mode.
|
Simple test harness for AFL++'s unicornafl c mode.
|
||||||
|
|
||||||
This loads the simple_target.bin binary (precompiled as MIPS code) into
|
This loads the simple_target_x86_64 binary into
|
||||||
Unicorn's memory map for emulation, places the specified input into
|
Unicorn's memory map for emulation, places the specified input into
|
||||||
simple_target's buffer (hardcoded to be at 0x300000), and executes 'main()'.
|
argv[1], sets up argv, and argc and executes 'main()'.
|
||||||
If any crashes occur during emulation, this script throws a matching signal
|
If run inside AFL, afl_fuzz automatically does the "right thing"
|
||||||
to tell AFL that a crash occurred.
|
|
||||||
|
|
||||||
Run under AFL as follows:
|
Run under AFL as follows:
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user