Merge pull request #1 from AFLplusplus/stable

sync
This commit is contained in:
Alexander Shvedov
2023-05-05 23:27:13 +03:00
committed by GitHub
204 changed files with 7006 additions and 2685 deletions

View File

@ -3,10 +3,10 @@
# american fuzzy lop++ - custom code formatter
# --------------------------------------------
#
# Written and maintaned by Andrea Fioraldi <andreafioraldi@gmail.com>
# Written and maintained by Andrea Fioraldi <andreafioraldi@gmail.com>
#
# Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
# Copyright 2019-2023 AFLplusplus Project. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -18,24 +18,57 @@
import subprocess
import sys
import os
import re
# import re # TODO: for future use
import shutil
import importlib.metadata
# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # future use
with open(".clang-format") as f:
fmt = f.read()
# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # TODO: for future use
CURRENT_LLVM = os.getenv('LLVM_VERSION', 14)
CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN", "")
def check_clang_format_pip_version():
"""
Check if the correct version of clang-format is installed via pip.
Returns:
bool: True if the correct version of clang-format is installed,
False otherwise.
"""
# Check if clang-format is installed
if importlib.util.find_spec('clang_format'):
# Check if the installed version is the expected LLVM version
if importlib.metadata.version('clang-format')\
.startswith(str(CURRENT_LLVM)+'.'):
return True
else:
# Return False, because the clang-format version does not match
return False
else:
# If the 'clang_format' package isn't installed, return False
return False
with open(".clang-format") as f:
fmt = f.read()
CLANG_FORMAT_PIP = check_clang_format_pip_version()
if shutil.which(CLANG_FORMAT_BIN) is None:
CLANG_FORMAT_BIN = f"clang-format-{CURRENT_LLVM}"
if shutil.which(CLANG_FORMAT_BIN) is None:
if shutil.which(CLANG_FORMAT_BIN) is None \
and CLANG_FORMAT_PIP is False:
print(f"[!] clang-format-{CURRENT_LLVM} is needed. Aborted.")
print(f"Run `pip3 install \"clang-format=={CURRENT_LLVM}.*\"` \
to install via pip.")
exit(1)
if CLANG_FORMAT_PIP:
CLANG_FORMAT_BIN = shutil.which("clang-format")
COLUMN_LIMIT = 80
for line in fmt.split("\n"):
line = line.split(":")

View File

@ -14,7 +14,7 @@ jobs:
runs-on: "${{ matrix.os }}"
strategy:
matrix:
os: [ubuntu-22.04, ubuntu-20.04, ubuntu-18.04]
os: [ubuntu-22.04, ubuntu-20.04]
env:
AFL_SKIP_CPUFREQ: 1
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
@ -23,15 +23,17 @@ jobs:
- name: debug
run: apt-cache search plugin-dev | grep gcc-; echo; apt-cache search clang-format- | grep clang-format-
- name: update
run: sudo apt-get update && sudo apt-get upgrade -y
run: sudo apt-get update
# && sudo apt-get upgrade -y
- name: install packages
run: sudo apt-get install -y -m -f --install-suggests build-essential git libtool libtool-bin automake bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build
#run: sudo apt-get install -y -m -f --install-suggests build-essential git libtool libtool-bin automake bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build python3-pip
run: sudo apt-get install -y -m -f build-essential git libtool libtool-bin automake flex bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build python3-pip
- name: compiler installed
run: gcc -v; echo; clang -v
- name: install gcc plugin
run: sudo apt-get install -y -m -f --install-suggests $(readlink /usr/bin/gcc)-plugin-dev
- name: build afl++
run: make distrib ASAN_BUILD=1
run: make distrib ASAN_BUILD=1 NO_NYX=1
- name: run tests
run: sudo -E ./afl-system-config; make tests
macos:

131
.gitignore vendored
View File

@ -1,100 +1,107 @@
.test
.test2
.sync_tmp
.vscode
!coresight_mode
!coresight_mode/coresight-trace
*.dSYM
*.o
*.o.tmp
*.pyc
*.so
*.swp
*.pyc
*.dSYM
as
a.out
ld
in
out
core*
compile_commands.json
.sync_tmp
.test
.test2
.vscode
afl-analyze
afl-analyze.8
afl-as
afl-as.8
afl-c++
afl-c++.8
afl-cc
afl-cc.8
afl-clang
afl-clang++
afl-clang-fast
afl-clang-fast++
afl-clang-lto
afl-clang-lto++
afl-fuzz
afl-g++
afl-gcc
afl-gcc-fast
afl-g++-fast
afl-gotcpu
afl-ld
afl-ld-lto
afl-cs-proxy
afl-qemu-trace
afl-showmap
afl-tmin
afl-analyze.8
afl-as.8
afl-clang-fast++.8
afl-clang-fast.8
afl-clang-lto.8
afl-clang-lto
afl-clang-lto++
afl-clang-lto++.8
afl-clang-lto.8
afl-cmin.8
afl-cmin.bash.8
afl-cs-proxy
afl-frida-trace.so
afl-fuzz
afl-fuzz.8
afl-c++.8
afl-cc.8
afl-gcc.8
afl-g++
afl-g++.8
afl-gcc
afl-gcc.8
afl-gcc-fast
afl-gcc-fast.8
afl-g++-fast
afl-g++-fast.8
afl-gotcpu
afl-gotcpu.8
afl-plot.8
afl-showmap.8
afl-system-config.8
afl-tmin.8
afl-whatsup.8
afl-persistent-config.8
afl-c++
afl-cc
afl-ld
afl-ld-lto
afl-lto
afl-lto++
afl-lto++.8
afl-lto.8
afl-persistent-config.8
afl-plot.8
afl-qemu-trace
afl-showmap
afl-showmap.8
afl-system-config.8
afl-tmin
afl-tmin.8
afl-whatsup.8
a.out
as
compile_commands.json
core*
examples/afl_frida/afl-frida
examples/afl_frida/frida-gum-example.c
examples/afl_frida/frida-gum.h
examples/afl_frida/libtestinstr.so
examples/afl_network_proxy/afl-network-client
examples/afl_network_proxy/afl-network-server
examples/aflpp_driver/libAFLDriver.a
examples/aflpp_driver/libAFLQemuDriver.a
gmon.out
in
ld
libAFLDriver.a
libAFLQemuDriver.a
out
qemu_mode/libcompcov/compcovtest
qemu_mode/qemu-*
qemu_mode/qemuafl
unicorn_mode/samples/*/\.test-*
unicorn_mode/samples/*/output/
test/.afl_performance
test-instr
test/output
test/test-c
test/test-cmplog
test/test-compcov
test/test-instr.ts
test/test-persistent
test/unittests/unit_hash
test/unittests/unit_list
test/unittests/unit_maybe_alloc
test/unittests/unit_preallocable
test/unittests/unit_list
test/unittests/unit_rand
test/unittests/unit_hash
examples/afl_network_proxy/afl-network-server
examples/afl_network_proxy/afl-network-client
examples/afl_frida/afl-frida
examples/afl_frida/libtestinstr.so
examples/afl_frida/frida-gum-example.c
examples/afl_frida/frida-gum.h
examples/aflpp_driver/libAFLDriver.a
examples/aflpp_driver/libAFLQemuDriver.a
libAFLDriver.a
libAFLQemuDriver.a
test/.afl_performance
gmon.out
afl-frida-trace.so
unicorn_mode/samples/*/output/
unicorn_mode/samples/*/\.test-*
utils/afl_network_proxy/afl-network-client
utils/afl_network_proxy/afl-network-server
utils/plot_ui/afl-plot-ui
*.o.tmp
utils/afl_proxy/afl-proxy
utils/optimin/build
utils/optimin/optimin
utils/persistent_mode/persistent_demo
utils/persistent_mode/persistent_demo_new
utils/persistent_mode/test-instr
!coresight_mode
!coresight_mode/coresight-trace
utils/plot_ui/afl-plot-ui
vuln_prog

View File

@ -39,7 +39,7 @@ RUN apt-get update && \
apt-get -y install --no-install-recommends \
make cmake automake meson ninja-build bison flex \
git xz-utils bzip2 wget jupp nano bash-completion less vim joe ssh psmisc \
python3 python3-dev python3-setuptools python-is-python3 \
python3 python3-dev python3-pip python-is-python3 \
libtool libtool-bin libglib2.0-dev \
apt-transport-https gnupg dialog \
gnuplot-nox libpixman-1-dev \
@ -47,7 +47,7 @@ RUN apt-get update && \
clang-${LLVM_VERSION} clang-tools-${LLVM_VERSION} libc++1-${LLVM_VERSION} \
libc++-${LLVM_VERSION}-dev libc++abi1-${LLVM_VERSION} libc++abi-${LLVM_VERSION}-dev \
libclang1-${LLVM_VERSION} libclang-${LLVM_VERSION}-dev \
libclang-common-${LLVM_VERSION}-dev libclang-cpp${LLVM_VERSION} \
libclang-common-${LLVM_VERSION}-dev libclang-rt-${LLVM_VERSION}-dev libclang-cpp${LLVM_VERSION} \
libclang-cpp${LLVM_VERSION}-dev liblld-${LLVM_VERSION} \
liblld-${LLVM_VERSION}-dev liblldb-${LLVM_VERSION} liblldb-${LLVM_VERSION}-dev \
libllvm${LLVM_VERSION} libomp-${LLVM_VERSION}-dev libomp5-${LLVM_VERSION} \
@ -67,6 +67,8 @@ RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_VERSION} 0
RUN wget -qO- https://sh.rustup.rs | CARGO_HOME=/etc/cargo sh -s -- -y -q --no-modify-path
ENV PATH=$PATH:/etc/cargo/bin
RUN apt clean -y
ENV LLVM_CONFIG=llvm-config-${LLVM_VERSION}
ENV AFL_SKIP_CPUFREQ=1
ENV AFL_TRY_AFFINITY=1
@ -92,4 +94,4 @@ RUN sed -i.bak 's/^ -/ /g' GNUmakefile && \
RUN echo "set encoding=utf-8" > /root/.vimrc && \
echo ". /etc/bash_completion" >> ~/.bashrc && \
echo 'alias joe="joe --wordwrap --joe_state -nobackup"' >> ~/.bashrc && \
echo "export PS1='"'[afl++ \h] \w$(__git_ps1) \$ '"'" >> ~/.bashrc
echo "export PS1='"'[afl++ \h] \w \$ '"'" >> ~/.bashrc

View File

@ -91,9 +91,8 @@ ifneq "$(SYS)" "Darwin"
#ifeq "$(HAVE_MARCHNATIVE)" "1"
# SPECIAL_PERFORMANCE += -march=native
#endif
# OS X does not like _FORTIFY_SOURCE=2
ifndef DEBUG
CFLAGS_OPT += -D_FORTIFY_SOURCE=2
CFLAGS_OPT += -D_FORTIFY_SOURCE=1
endif
else
# On some odd MacOS system configurations, the Xcode sdk path is not set correctly
@ -103,7 +102,7 @@ endif
ifeq "$(SYS)" "SunOS"
CFLAGS_OPT += -Wno-format-truncation
LDFLAGS = -lkstat -lrt
LDFLAGS = -lkstat -lrt -lsocket -lnsl
endif
ifdef STATIC
@ -197,7 +196,7 @@ ifeq "$(PYTHON_INCLUDE)" ""
ifneq "$(shell command -v python3-config 2>/dev/null)" ""
PYTHON_INCLUDE ?= $(shell python3-config --includes)
PYTHON_VERSION ?= $(strip $(shell python3 --version 2>&1))
# Starting with python3.8, we need to pass the `embed` flag. Earier versions didn't know this flag.
# Starting with python3.8, we need to pass the `embed` flag. Earlier versions didn't know this flag.
ifeq "$(shell python3-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1"
PYTHON_LIB ?= $(shell python3-config --libs --embed --ldflags)
else
@ -287,6 +286,8 @@ ifeq "$(shell command -v svn >/dev/null && svn proplist . 2>/dev/null && echo 1
IN_REPO=1
endif
CCVER=$(shell cc -v 2>&1|tail -n 1)
ifeq "$(shell echo 'int main() { return 0;}' | $(CC) $(CFLAGS) -fsanitize=address -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
@ -313,9 +314,9 @@ all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_bu
@echo
@echo Build Summary:
@test -e afl-fuzz && echo "[+] afl-fuzz and supporting tools successfully built" || echo "[-] afl-fuzz could not be built, please set CC to a working compiler"
@test -e afl-llvm-pass.so && echo "[+] LLVM basic mode successfully built" || echo "[-] LLVM mode could not be build, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md"
@test -e SanitizerCoveragePCGUARD.so && echo "[+] LLVM mode successfully built" || echo "[-] LLVM mode could not be build, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md"
@test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode successfully built" || echo "[-] LLVM LTO mode could not be build, it is optional, if you want it, please install LLVM 11-14. More information at instrumentation/README.lto.md on how to build it"
@test -e afl-llvm-pass.so && echo "[+] LLVM basic mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md"
@test -e SanitizerCoveragePCGUARD.so && echo "[+] LLVM mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md"
@test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode successfully built" || echo "[-] LLVM LTO mode could not be built, it is optional, if you want it, please install LLVM 11-14. More information at instrumentation/README.lto.md on how to build it"
ifneq "$(SYS)" "Darwin"
@test -e afl-gcc-pass.so && echo "[+] gcc_mode successfully built" || echo "[-] gcc_mode could not be built, it is optional, install gcc-VERSION-plugin-dev to enable this"
endif
@ -389,6 +390,7 @@ help:
@echo NO_NYX - disable building nyx mode dependencies
@echo "NO_CORESIGHT - disable building coresight (arm64 only)"
@echo NO_UNICORN_ARM64 - disable building unicorn on arm64
@echo "WAFL_MODE - enable for WASM fuzzing with https://github.com/fgsect/WAFL"
@echo AFL_NO_X86 - if compiling on non-intel/amd platforms
@echo "LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g., Debian)"
@echo "=========================================="
@ -431,7 +433,7 @@ endif
.PHONY: ready
ready:
@echo "[+] Everything seems to be working, ready to compile."
@echo "[+] Everything seems to be working, ready to compile. ($(CCVER))"
afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
@ -453,7 +455,7 @@ afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) -lm
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS)
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
@ -547,8 +549,8 @@ ifndef AFL_NO_X86
test_build: afl-cc afl-gcc afl-as afl-showmap
@echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..."
@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c $(LDFLAGS) -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 )
ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
-ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -q -m none -o .test-instr0 ./test-instr < /dev/null
-echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
@rm -f test-instr
@cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-cc does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi
@echo
@ -629,9 +631,9 @@ distrib: all
-$(MAKE) -j$(nproc) -f GNUmakefile.llvm
ifneq "$(SYS)" "Darwin"
-$(MAKE) -f GNUmakefile.gcc_plugin
endif
-$(MAKE) -C utils/libdislocator
-$(MAKE) -C utils/libtokencap
endif
-$(MAKE) -C utils/afl_network_proxy
-$(MAKE) -C utils/socket_fuzzing
-$(MAKE) -C utils/argv_fuzzing
@ -660,8 +662,10 @@ endif
.PHONY: binary-only
binary-only: test_shm test_python ready $(PROGS)
ifneq "$(SYS)" "Darwin"
-$(MAKE) -C utils/libdislocator
-$(MAKE) -C utils/libtokencap
endif
-$(MAKE) -C utils/afl_network_proxy
-$(MAKE) -C utils/socket_fuzzing
-$(MAKE) -C utils/argv_fuzzing
@ -718,9 +722,9 @@ source-only: all
-$(MAKE) -j$(nproc) -f GNUmakefile.llvm
ifneq "$(SYS)" "Darwin"
-$(MAKE) -f GNUmakefile.gcc_plugin
endif
-$(MAKE) -C utils/libdislocator
-$(MAKE) -C utils/libtokencap
endif
# -$(MAKE) -C utils/plot_ui
ifeq "$(SYS)" "Linux"
ifndef NO_NYX
@ -731,9 +735,9 @@ endif
@echo
@echo Build Summary:
@test -e afl-fuzz && echo "[+] afl-fuzz and supporting tools successfully built" || echo "[-] afl-fuzz could not be built, please set CC to a working compiler"
@test -e afl-llvm-pass.so && echo "[+] LLVM basic mode successfully built" || echo "[-] LLVM mode could not be build, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md"
@test -e SanitizerCoveragePCGUARD.so && echo "[+] LLVM mode successfully built" || echo "[-] LLVM mode could not be build, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md"
@test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode successfully built" || echo "[-] LLVM LTO mode could not be build, it is optional, if you want it, please install LLVM 11-14. More information at instrumentation/README.lto.md on how to build it"
@test -e afl-llvm-pass.so && echo "[+] LLVM basic mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md"
@test -e SanitizerCoveragePCGUARD.so && echo "[+] LLVM mode successfully built" || echo "[-] LLVM mode could not be built, please install at least llvm-11 and clang-11 or newer, see docs/INSTALL.md"
@test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode successfully built" || echo "[-] LLVM LTO mode could not be built, it is optional, if you want it, please install LLVM 11-14. More information at instrumentation/README.lto.md on how to build it"
ifneq "$(SYS)" "Darwin"
test -e afl-gcc-pass.so && echo "[+] gcc_mode successfully built" || echo "[-] gcc_mode could not be built, it is optional, install gcc-VERSION-plugin-dev to enable this"
endif

View File

@ -11,7 +11,7 @@
# from Laszlo Szekeres.
#
# Copyright 2015 Google Inc. All rights reserved.
# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
# Copyright 2019-2023 AFLplusplus Project. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -28,14 +28,14 @@ MAN_PATH ?= $(PREFIX)/share/man/man8
VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2)
CFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
CFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=1
CFLAGS_SAFE := -Wall -Iinclude -Wno-pointer-sign \
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
-DGCC_VERSION=\"$(GCCVER)\" -DGCC_BINDIR=\"$(GCCBINDIR)\" \
-Wno-unused-function
override CFLAGS += $(CFLAGS_SAFE)
CXXFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=2
CXXFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=1
CXXEFLAGS := $(CXXFLAGS) -Wall -std=c++11
CC ?= gcc

View File

@ -48,6 +48,7 @@ LLVM_MINOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/.*\.//' | sed
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^[0-2]\.|^3.[0-7]\.' && echo 1 || echo 0 )
LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[5-9]' && echo 1 || echo 0 )
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[0-9]' && echo 1 || echo 0 )
LLVM_NEWER_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[6-9]' && echo 1 || echo 0 )
LLVM_10_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[1-9]|^10\.[1-9]|^10\.0.[1-9]' && echo 1 || echo 0 )
LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[1-9]' && echo 1 || echo 0 )
LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
@ -81,6 +82,11 @@ ifeq "$(LLVM_NEW_API)" "1"
LLVM_TOO_OLD=0
endif
ifeq "$(LLVM_NEWER_API)" "1"
$(info [+] llvm_mode detected llvm 16+, enabling c++17)
LLVM_STDCXX = c++17
endif
ifeq "$(LLVM_TOO_OLD)" "1"
$(info [!] llvm_mode detected an old version of llvm, upgrade to at least 9 or preferable 11!)
$(shell sleep 1)
@ -254,7 +260,7 @@ else
AFL_CLANG_DEBUG_PREFIX =
endif
CFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=2
CFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=1
CFLAGS_SAFE := -Wall -g -Wno-cast-qual -Wno-variadic-macros -Wno-pointer-sign \
-I ./include/ -I ./instrumentation/ \
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
@ -274,9 +280,9 @@ ifdef AFL_TRACE_PC
$(info Compile option AFL_TRACE_PC is deprecated, just set AFL_LLVM_INSTRUMENT=PCGUARD to activate when compiling targets )
endif
CXXFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=2
CXXFLAGS ?= -O3 -funroll-loops -fPIC -D_FORTIFY_SOURCE=1
override CXXFLAGS += -Wall -g -I ./include/ \
-DVERSION=\"$(VERSION)\" -Wno-variadic-macros \
-DVERSION=\"$(VERSION)\" -Wno-variadic-macros -Wno-deprecated-copy-with-dtor \
-DLLVM_MINOR=$(LLVM_MINOR) -DLLVM_MAJOR=$(LLVM_MAJOR)
ifneq "$(shell $(LLVM_CONFIG) --includedir) 2> /dev/null" ""
@ -288,6 +294,11 @@ endif
CLANG_CPPFL = `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC $(CXXFLAGS) -Wno-deprecated-declarations
CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS)
# wasm fuzzing: disable thread-local storage and unset LLVM debug flag
ifdef WAFL_MODE
$(info Compiling libraries for use with WAVM)
CLANG_CPPFL += -DNDEBUG -DNO_TLS
endif
# User teor2345 reports that this is required to make things work on MacOS X.
ifeq "$(SYS)" "Darwin"

View File

@ -2,9 +2,9 @@
<img align="right" src="https://raw.githubusercontent.com/AFLplusplus/Website/master/static/aflpp_bg.svg" alt="AFL++ logo" width="250" heigh="250">
Release version: [4.04c](https://github.com/AFLplusplus/AFLplusplus/releases)
Release version: [4.06c](https://github.com/AFLplusplus/AFLplusplus/releases)
GitHub version: 4.05a
GitHub version: 4.07a
Repository:
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
@ -228,6 +228,7 @@ Thank you! (For people sending pull requests - please add yourself to this list
Thomas Rooijakkers David Carlier
Ruben ten Hove Joey Jiao
fuzzah @intrigus-lgtm
Yaakov Saxon
```
</details>

View File

@ -2,18 +2,19 @@
## Should
- better documentation for custom mutators
- splicing selection weighted?
- support persistent and deferred fork server in afl-showmap?
- better autodetection of shifting runtime timeout values
- Update afl->pending_not_fuzzed for MOpt
- afl-plot to support multiple plot_data
- parallel builds for source-only targets
- get rid of check_binary, replace with more forkserver communication
- first fuzzer should be a main automatically? not sure.
## Maybe
- forkserver tells afl-fuzz if cmplog is supported and if so enable
it by default, with AFL_CMPLOG_NO=1 (?) set to skip?
- afl_custom_fuzz_splice_optin()
- afl_custom_splice()
- cmdline option from-to range for mutations

131
afl-cmin
View File

@ -103,12 +103,14 @@ function usage() {
" -o dir - output directory for minimized files\n" \
"\n" \
"Execution control settings:\n" \
" -T tasks - how many parallel tasks to run (default: 1, all=nproc)\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 (default: none)\n" \
" -t msec - run time limit for child process (default: 5000)\n" \
" -O - use binary-only instrumentation (FRIDA mode)\n" \
" -Q - use binary-only instrumentation (QEMU mode)\n" \
" -U - use unicorn-based instrumentation (unicorn mode)\n" \
" -X - use Nyx mode\n" \
"\n" \
"Minimization settings:\n" \
" -A - allow crashes and timeouts (not recommended)\n" \
@ -118,20 +120,21 @@ function usage() {
"For additional tips, please consult README.md\n" \
"\n" \
"Environment variables used:\n" \
"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \
"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \
"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up\n" \
"AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \
"AFL_KILL_SIGNAL: Signal delivered to child processes on timeout (default: SIGKILL)\n" \
"AFL_FORK_SERVER_KILL_SIGNAL: Signal delivered to fork server processes on termination\n" \
" (default: SIGTERM). If this is not set and AFL_KILL_SIGNAL is set,\n" \
" this will be set to the same value as AFL_KILL_SIGNAL.\n" \
"AFL_FORK_SERVER_KILL_SIGNAL: Signal delivered to fork server processes on\n" \
" termination (default: SIGTERM). If this is not set and AFL_KILL_SIGNAL is\n" \
" set, this will be set to the same value as AFL_KILL_SIGNAL.\n" \
"AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n" \
"AFL_CMIN_ALLOW_ANY: write tuples for crashing inputs also\n" \
"AFL_PATH: path for the afl-showmap binary if not found anywhere in PATH\n" \
"AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \
"printed to stdout\n" \
"AFL_SKIP_BIN_CHECK: skip afl instrumentation checks for target binary\n"
"AFL_CUSTOM_MUTATOR_LIBRARY: custom mutator library (post_process and send)\n"
"AFL_PYTHON_MODULE: custom mutator library (post_process and send)\n"
exit 1
}
@ -156,13 +159,19 @@ BEGIN {
# process options
Opterr = 1 # default is to diagnose
Optind = 1 # skip ARGV[0]
while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQU?")) != -1) {
while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQUXYT:?")) != -1) {
if (_go_c == "i") {
if (!Optarg) usage()
if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
in_dir = Optarg
continue
} else
if (_go_c == "T") {
if (!Optarg) usage()
if (threads) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
threads = Optarg
continue
} else
if (_go_c == "o") {
if (!Optarg) usage()
if (out_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
@ -218,6 +227,12 @@ BEGIN {
unicorn_mode = 1
continue
} else
if (_go_c == "X" || _go_c == "Y") {
if (nyx_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
extra_par = extra_par " -X"
nyx_mode = 1
continue
} else
if (_go_c == "?") {
exit 1
} else
@ -225,7 +240,7 @@ BEGIN {
} # while options
if (!mem_limit) mem_limit = "none"
if (!timeout) timeout = "none"
if (!timeout) timeout = "5000"
# get program args
i = 0
@ -244,21 +259,30 @@ BEGIN {
# Do a sanity check to discourage the use of /tmp, since we can't really
# handle this safely from an awk script.
if (!ENVIRON["AFL_ALLOW_TMP"]) {
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]
#if (!ENVIRON["AFL_ALLOW_TMP"]) {
# 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]
#
# if (dir ~ /^(\/var)?\/tmp/) {
# print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr"
# exit 1
# }
# }
# delete dirlist
#}
if (dir ~ /^(\/var)?\/tmp/) {
print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr"
if (threads && stdin_file) {
print "[-] Error: -T and -f cannot be used together." > "/dev/stderr"
exit 1
}
}
delete dirlist
if (!threads && !stdin_file && !nyx_mode) {
print "[*] Are you aware of the '-T all' parallelize option that improves the speed for large/slow corpuses?"
}
# If @@ is specified, but there's no -f, let's come up with a temporary input
@ -291,7 +315,8 @@ BEGIN {
exit 1
}
if (target_bin && !exists_and_is_executable(target_bin)) {
if (!nyx_mode && target_bin && !exists_and_is_executable(target_bin)) {
"command -v "target_bin" 2>/dev/null" | getline tnew
if (!tnew || !exists_and_is_executable(tnew)) {
@ -311,7 +336,7 @@ BEGIN {
}
}
if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !frida_mode && !unicorn_mode) {
if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !frida_mode && !unicorn_mode && !nyx_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
@ -340,6 +365,18 @@ BEGIN {
exit 1
}
if (threads) {
"nproc" | getline nproc
if (threads == "all") {
threads = nproc
} else {
if (!(threads > 1 && threads <= nproc)) {
print "[-] Error: -T option must be between 1 and "nproc" or \"all\"." > "/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"
@ -449,9 +486,59 @@ BEGIN {
# STEP 1: Collecting traces #
#############################
if (threads) {
inputsperfile = in_count / threads
if (in_count % threads) {
inputsperfile++;
}
cnt = 0;
tmpfile=out_dir "/.filelist"
for (instance = 1; instance < threads; instance++) {
for (i = 0; i < inputsperfile; i++) {
print in_dir"/"infilesSmallToBigFull[cnt] >> tmpfile"."instance
cnt++
}
}
for (; cnt < in_count; cnt++) {
print in_dir"/"infilesSmallToBigFull[cnt] >> tmpfile"."threads
}
}
print "[*] Obtaining traces for "in_count" input files in '"in_dir"'."
cur = 0;
if (threads > 1) {
print "[*] Creating " threads " parallel tasks with about " inputsperfile " each."
for (i = 1; i <= threads; i++) {
if (!stdin_file) {
# print " { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -- \""target_bin"\" "prog_args_string"; > "tmpfile"."i".done ; } &"
retval = system(" { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -- \""target_bin"\" "prog_args_string"; > "tmpfile"."i".done ; } &")
} else {
stdin_file=tmpfile"."i".stdin"
# print " { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null; > "tmpfile"."i".done ; } &"
retval = system(" { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null; > "tmpfile"."i".done ; } &")
}
}
print "[*] Waiting for parallel tasks to complete ..."
# wait for all processes to finish
ok=0
while (ok < threads) {
ok=0
for (i = 1; i <= threads; i++) {
if (system("test -f "tmpfile"."i".done") == 0) {
ok++
}
}
}
print "[*] Done!"
system("rm -f "tmpfile"*")
} else {
if (!stdin_file) {
print " Processing "in_count" files (forkserver mode)..."
# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string
@ -472,6 +559,8 @@ BEGIN {
exit retval
}
}
#######################################################
# STEP 2: register smallest input file for each tuple #
# STEP 3: copy that file (at most once) #

View File

@ -7,6 +7,8 @@
#
# Copyright 2014, 2015 Google Inc. All rights reserved.
#
# Copyright 2019-2023 AFLplusplus
#
# 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:
@ -36,7 +38,7 @@
# array sizes.
#
echo "corpus minimization tool for afl-fuzz by Michal Zalewski"
echo "corpus minimization tool for afl-fuzz"
echo
#########
@ -46,14 +48,14 @@ echo
# Process command-line options...
MEM_LIMIT=none
TIMEOUT=none
TIMEOUT=5000
unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \
AFL_CMIN_CRASHES_ONLY AFL_CMIN_ALLOW_ANY QEMU_MODE UNICORN_MODE
unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN F_ARG \
AFL_CMIN_CRASHES_ONLY AFL_CMIN_ALLOW_ANY QEMU_MODE UNICORN_MODE T_ARG
export AFL_QUIET=1
while getopts "+i:o:f:m:t:eOQUACh" opt; do
while getopts "+i:o:f:m:t:T:eOQUAChXY" opt; do
case "$opt" in
@ -69,6 +71,7 @@ while getopts "+i:o:f:m:t:eOQUACh" opt; do
;;
"f")
STDIN_FILE="$OPTARG"
F_ARG=1
;;
"m")
MEM_LIMIT="$OPTARG"
@ -94,10 +97,21 @@ while getopts "+i:o:f:m:t:eOQUACh" opt; do
EXTRA_PAR="$EXTRA_PAR -Q"
QEMU_MODE=1
;;
"Y")
EXTRA_PAR="$EXTRA_PAR -X"
NYX_MODE=1
;;
"X")
EXTRA_PAR="$EXTRA_PAR -X"
NYX_MODE=1
;;
"U")
EXTRA_PAR="$EXTRA_PAR -U"
UNICORN_MODE=1
;;
"T")
T_ARG="$OPTARG"
;;
"?")
exit 1
;;
@ -122,12 +136,14 @@ Required parameters:
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)
-T tasks - how many parallel processes to create (default=1, "all"=nproc)
-f file - location read by the fuzzed program (default: stdin)
-m megs - memory limit for child process (default=$MEM_LIMIT MB)
-t msec - run time limit for child process (default: 5000ms)
-O - use binary-only instrumentation (FRIDA mode)
-Q - use binary-only instrumentation (QEMU mode)
-U - use unicorn-based instrumentation (Unicorn mode)
-X - use Nyx mode
Minimization settings:
@ -142,6 +158,8 @@ AFL_KEEP_TRACES: leave the temporary <out_dir>\.traces directory
AFL_NO_FORKSRV: run target via execve instead of using the forkserver
AFL_PATH: last resort location to find the afl-showmap binary
AFL_SKIP_BIN_CHECK: skip check for target binary
AFL_CUSTOM_MUTATOR_LIBRARY: custom mutator library (post_process and send)
AFL_PYTHON_MODULE: custom mutator library (post_process and send)
_EOF_
exit 1
fi
@ -188,6 +206,11 @@ fi
# Check for obvious errors.
if [ ! "$T_ARG" = "" -a ! "$F_ARG" = "" -a ! "$NYX_MODE" == 1 ]; then
echo "[-] Error: -T and -f can not be used together." 1>&2
exit 1
fi
if [ ! "$MEM_LIMIT" = "none" ]; then
if [ "$MEM_LIMIT" -lt "5" ]; then
@ -206,6 +229,7 @@ if [ ! "$TIMEOUT" = "none" ]; then
fi
if [ "$NYX_MODE" = "" ]; then
if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then
TNEW="`which "$TARGET_BIN" 2>/dev/null`"
@ -219,7 +243,9 @@ if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then
fi
grep -aq AFL_DUMP_MAP_SIZE "./$TARGET_BIN" && {
fi
grep -aq AFL_DUMP_MAP_SIZE "$TARGET_BIN" && {
echo "[!] Trying to obtain the map size of the target ..."
MAPSIZE=`AFL_DUMP_MAP_SIZE=1 "./$TARGET_BIN" 2>/dev/null`
test -n "$MAPSIZE" && {
@ -228,7 +254,7 @@ grep -aq AFL_DUMP_MAP_SIZE "./$TARGET_BIN" && {
}
}
if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$FRIDA_MODE" = "" -a "$UNICORN_MODE" = "" ]; then
if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$FRIDA_MODE" = "" -a "$UNICORN_MODE" = "" -a "$NYX_MODE" = "" ]; then
if ! grep -qF "__AFL_SHM_ID" "$TARGET_BIN"; then
echo "[-] Error: binary '$TARGET_BIN' doesn't appear to be instrumented." 1>&2
@ -285,14 +311,34 @@ if [ ! -x "$SHOWMAP" ]; then
exit 1
fi
THREADS=
if [ ! "$T_ARG" = "" ]; then
if [ "$T_ARG" = "all" ]; then
THREADS=$(nproc)
else
if [ "$T_ARG" -gt 1 -a "$T_ARG" -le "$(nproc)" ]; then
THREADS=$T_ARG
else
echo "[-] Error: -T parameter must between 2 and $(nproc) or \"all\"." 1>&2
fi
fi
else
if [ "$F_ARG" = ""]; then
echo "[*] Are you aware of the '-T all' parallelize option that massively improves the speed?"
fi
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."
echo "[-] Hmm, no inputs in the target directory. Nothing to be done."
rm -rf "$TRACE_DIR"
exit 1
fi
echo "[*] Are you aware that afl-cmin is faster than this afl-cmin.bash script?"
echo "[+] Found $IN_COUNT files for minimizing."
FIRST_FILE=`ls "$IN_DIR" | head -1`
# Make sure that we're not dealing with a directory.
@ -341,6 +387,18 @@ else
fi
TMPFILE=$OUT_DIR/.list.$$
if [ ! "$THREADS" = "" ]; then
ls -- "$IN_DIR" > $TMPFILE 2>/dev/null
IN_COUNT=$(cat $TMPFILE | wc -l)
SPLIT=$(($IN_COUNT / $THREADS))
if [ "$(($IN_COUNT % $THREADS))" -gt 0 ]; then
SPLIT=$(($SPLIT + 1))
fi
echo "[+] Splitting workload into $THREADS tasks with $SPLIT items on average each."
split -l $SPLIT $TMPFILE $TMPFILE.
fi
# Let's roll!
#############################
@ -349,6 +407,7 @@ fi
echo "[*] Obtaining traces for input files in '$IN_DIR'..."
if [ "$THREADS" = "" ]; then
(
CUR=0
@ -372,17 +431,58 @@ echo "[*] Obtaining traces for input files in '$IN_DIR'..."
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 -H "$STDIN_FILE" -- "$@" </dev/null
done
fi
echo
)
echo
else
PIDS=
CNT=0
for inputs in $(ls ${TMPFILE}.*); do
(
if [ "$STDIN_FILE" = "" ]; then
cat $inputs | while read -r fn; do
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -- "$@" <"$IN_DIR/$fn"
done
else
STDIN_FILE="$inputs.$$"
cat $inputs | while read -r fn; do
cp "$IN_DIR/$fn" "$STDIN_FILE"
"$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -H "$STDIN_FILE" -- "$@" </dev/null
done
fi
) &
PIDS="$PIDS $!"
done
echo "[+] Waiting for running tasks IDs:$PIDS"
wait
echo "[+] all $THREADS running tasks completed."
rm -f ${TMPFILE}*
echo trace dir files: $(ls $TRACE_DIR/*|wc -l)
fi
##########################
# STEP 2: SORTING TUPLES #

View File

@ -287,7 +287,7 @@ $PLOT_EG
_EOF_
) | gnuplot
) | gnuplot || echo "Note: if you see errors concerning 'unknown or ambiguous terminal type' then you need to use a gnuplot that has png support compiled in."
echo "[?] You can also use -g flag to view the plots in an GUI window, and interact with the plots (if you have built afl-plot-ui). Run \"afl-plot -h\" to know more."

View File

@ -6,7 +6,7 @@
# Originally written by Michal Zalewski
#
# Copyright 2015 Google Inc. All rights reserved.
# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
# Copyright 2019-2023 AFLplusplus Project. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -70,10 +70,10 @@ if [ -d queue ]; then
fi
RED=`tput setaf 9 1 1`
GREEN=`tput setaf 2 1 1`
BLUE=`tput setaf 4 1 1`
YELLOW=`tput setaf 11 1 1`
RED=`tput setaf 9 1 1 2>/dev/null`
GREEN=`tput setaf 2 1 1 2>/dev/null`
BLUE=`tput setaf 4 1 1 2>/dev/null`
YELLOW=`tput setaf 11 1 1 2>/dev/null`
NC=`tput sgr0`
RESET="$NC"
@ -141,7 +141,8 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
sed 's/^command_line.*$/_skip:1/;s/[ ]*:[ ]*/="/;s/$/"/' "$i" >"$TMP"
. "$TMP"
DIR=$(dirname "$i")
DIR=${DIR##*/}
RUN_UNIX=$run_time
RUN_DAYS=$((RUN_UNIX / 60 / 60 / 24))
RUN_HRS=$(((RUN_UNIX / 60 / 60) % 24))
@ -154,7 +155,7 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
if [ "$SUMMARY_ONLY" = "" ]; then
echo ">>> $afl_banner ($RUN_DAYS days, $RUN_HRS hrs) fuzzer PID: $fuzzer_pid <<<"
echo ">>> $afl_banner instance: $DIR ($RUN_DAYS days, $RUN_HRS hrs) fuzzer PID: $fuzzer_pid <<<"
echo
fi

View File

@ -11,19 +11,6 @@ The `./examples` folder contains examples for custom mutators in python and C.
In `./rust`, you will find rust bindings, including a simple example in `./rust/example` and an example for structured fuzzing, based on lain, in`./rust/example_lain`.
## The AFL++ Grammar Mutator
If you use git to clone AFL++, then the following will incorporate our
excellent grammar custom mutator:
```sh
git submodule update --init
```
Read the README in the [Grammar-Mutator] repository on how to use it.
[Grammar-Mutator]: https://github.com/AFLplusplus/Grammar-Mutator
## Production-Ready Custom Mutators
This directory holds ready to use custom mutators.
@ -37,6 +24,42 @@ and add `AFL_CUSTOM_MUTATOR_ONLY=1` if you only want to use the custom mutator.
Multiple custom mutators can be used by separating their paths with `:` in the environment variable.
### The AFL++ grammar agnostic grammar mutator
In `./autotokens` you find a token-level fuzzer that does not need to know
anything about the grammar of an input as long as it is in ascii and allows
whitespace.
It is very fast and effective.
If you are looking for an example of how to effectively create a custom
mutator take a look at this one.
### The AFL++ Grammar Mutator
If you use git to clone AFL++, then the following will incorporate our
excellent grammar custom mutator:
```sh
git submodule update --init
```
Read the README in the [Grammar-Mutator] repository on how to use it.
[Grammar-Mutator]: https://github.com/AFLplusplus/Grammar-Mutator
Note that this custom mutator is not very good though!
### Other Mutators
atnwalk and gramatron are grammar custom mutators. Example grammars are
provided.
honggfuzz, libfuzzer and libafl are partial implementations based on the
mutator implementations of the respective fuzzers.
More for playing than serious usage.
radamsa is slow and not very good.
## 3rd Party Custom Mutators
### Superion Mutators

View File

@ -0,0 +1,7 @@
all: atnwalk.so
atnwalk.so: atnwalk.c
$(CC) -I ../../include/ -shared -fPIC -O3 -o atnwalk.so atnwalk.c
clean:
rm -f *.so *.o *~ core

View File

@ -0,0 +1,43 @@
# ATNwalk: Grammar-Based Fuzzing using Only Bit-Mutations
This is a custom mutator integration of ATNwalk that works by communicating via UNIX domain sockets.
Refer to [https://github.com/atnwalk/testbed](https://github.com/atnwalk/testbed) for detailed instructions on how to get ATNwalk running.
## Build
Just type `make` to build `atnwalk.so`.
## Run
**NOTE:** The commands below just demonstrate an example how running ATNwalk looks like and require a working [testbed](https://github.com/atnwalk/testbed)
```bash
# create the required a random seed first
mkdir -p ~/campaign/example/seeds
cd ~/campaign/example/seeds
head -c1 /dev/urandom | ~/atnwalk/build/javascript/bin/decode -wb > seed.decoded 2> seed.encoded
# create the required atnwalk directory and copy the seed
cd ../
mkdir -p atnwalk/in
cp ./seeds/seed.encoded atnwalk/in/seed
cd atnwalk
# assign to a single core when benchmarking it, change the CPU number as required
CPU_ID=0
# start the ATNwalk server
nohup taskset -c ${CPU_ID} ${HOME}/atnwalk/build/javascript/bin/server 100 > server.log 2>&1 &
# start AFL++ with ATNwalk
AFL_SKIP_CPUFREQ=1 \
AFL_DISABLE_TRIM=1 \
AFL_CUSTOM_MUTATOR_ONLY=1 \
AFL_CUSTOM_MUTATOR_LIBRARY=${HOME}/AFLplusplus/custom_mutators/atnwalk/atnwalk.so \
AFL_POST_PROCESS_KEEP_ORIGINAL=1 \
~/AFLplusplus/afl-fuzz -t 100 -i in/ -o out -b ${CPU_ID} -- ~/jerryscript/build/bin/jerry
# make sure to kill the ATNwalk server process after you're done
kill "$(cat atnwalk.pid)"
```

View File

@ -0,0 +1,539 @@
#include "afl-fuzz.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define BUF_SIZE_INIT 4096
#define SOCKET_NAME "./atnwalk.socket"
// how many errors (e.g. timeouts) to tolerate until moving on to the next queue
// entry
#define ATNWALK_ERRORS_MAX 1
// how many execution timeouts to tolerate until moving on to the next queue
// entry
#define EXEC_TIMEOUT_MAX 2
// handshake constants
const uint8_t SERVER_ARE_YOU_ALIVE = 213;
const uint8_t SERVER_YES_I_AM_ALIVE = 42;
// control bits
const uint8_t SERVER_CROSSOVER_BIT = 0b00000001;
const uint8_t SERVER_MUTATE_BIT = 0b00000010;
const uint8_t SERVER_DECODE_BIT = 0b00000100;
const uint8_t SERVER_ENCODE_BIT = 0b00001000;
typedef struct atnwalk_mutator {
afl_state_t *afl;
uint8_t atnwalk_error_count;
uint64_t prev_timeouts;
uint32_t prev_hits;
uint32_t stage_havoc_cur;
uint32_t stage_havoc_max;
uint32_t stage_splice_cur;
uint32_t stage_splice_max;
uint8_t *fuzz_buf;
size_t fuzz_size;
uint8_t *post_process_buf;
size_t post_process_size;
} atnwalk_mutator_t;
int read_all(int fd, uint8_t *buf, size_t buf_size) {
int n;
size_t offset = 0;
while (offset < buf_size) {
n = read(fd, buf + offset, buf_size - offset);
if (n == -1) { return 0; }
offset += n;
}
return 1;
}
int write_all(int fd, uint8_t *buf, size_t buf_size) {
int n;
size_t offset = 0;
while (offset < buf_size) {
n = write(fd, buf + offset, buf_size - offset);
if (n == -1) { return 0; }
offset += n;
}
return 1;
}
void put_uint32(uint8_t *buf, uint32_t val) {
buf[0] = (uint8_t)(val >> 24);
buf[1] = (uint8_t)((val & 0x00ff0000) >> 16);
buf[2] = (uint8_t)((val & 0x0000ff00) >> 8);
buf[3] = (uint8_t)(val & 0x000000ff);
}
uint32_t to_uint32(uint8_t *buf) {
uint32_t val = 0;
val |= (((uint32_t)buf[0]) << 24);
val |= (((uint32_t)buf[1]) << 16);
val |= (((uint32_t)buf[2]) << 8);
val |= ((uint32_t)buf[3]);
return val;
}
void put_uint64(uint8_t *buf, uint64_t val) {
buf[0] = (uint8_t)(val >> 56);
buf[1] = (uint8_t)((val & 0x00ff000000000000) >> 48);
buf[2] = (uint8_t)((val & 0x0000ff0000000000) >> 40);
buf[3] = (uint8_t)((val & 0x000000ff00000000) >> 32);
buf[4] = (uint8_t)((val & 0x00000000ff000000) >> 24);
buf[5] = (uint8_t)((val & 0x0000000000ff0000) >> 16);
buf[6] = (uint8_t)((val & 0x000000000000ff00) >> 8);
buf[7] = (uint8_t)(val & 0x00000000000000ff);
}
/**
* Initialize this custom mutator
*
* @param[in] afl a pointer to the internal state object. Can be ignored for
* now.
* @param[in] seed A seed for this mutator - the same seed should always mutate
* in the same way.
* @return Pointer to the data object this custom mutator instance should use.
* There may be multiple instances of this mutator in one afl-fuzz run!
* Return NULL on error.
*/
atnwalk_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
srand(seed);
atnwalk_mutator_t *data =
(atnwalk_mutator_t *)malloc(sizeof(atnwalk_mutator_t));
if (!data) {
perror("afl_custom_init alloc");
return NULL;
}
data->afl = afl;
data->prev_hits = 0;
data->fuzz_buf = (uint8_t *)malloc(BUF_SIZE_INIT);
data->fuzz_size = BUF_SIZE_INIT;
data->post_process_buf = (uint8_t *)malloc(BUF_SIZE_INIT);
data->post_process_size = BUF_SIZE_INIT;
return data;
}
unsigned int afl_custom_fuzz_count(atnwalk_mutator_t *data,
const unsigned char *buf, size_t buf_size) {
// afl_custom_fuzz_count is called exactly once before entering the
// 'stage-loop' for the current queue entry thus, we use it to reset the error
// count and to initialize stage variables (somewhat not intended by the API,
// but still better than rewriting the whole thing to have a custom mutator
// stage)
data->atnwalk_error_count = 0;
data->prev_timeouts = data->afl->total_tmouts;
// it might happen that on the last execution of the splice stage a new path
// is found we need to fix that here and count it
if (data->prev_hits) {
data->afl->stage_finds[STAGE_SPLICE] +=
data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
}
data->prev_hits = data->afl->queued_items + data->afl->saved_crashes;
data->stage_havoc_cur = 0;
data->stage_splice_cur = 0;
// 50% havoc, 50% splice
data->stage_havoc_max = data->afl->stage_max >> 1;
if (data->stage_havoc_max < HAVOC_MIN) { data->stage_havoc_max = HAVOC_MIN; }
data->stage_splice_max = data->stage_havoc_max;
return data->stage_havoc_max + data->stage_splice_max;
}
size_t fail_fatal(int fd_socket, uint8_t **out_buf) {
if (fd_socket != -1) { close(fd_socket); }
*out_buf = NULL;
return 0;
}
size_t fail_gracefully(int fd_socket, atnwalk_mutator_t *data, uint8_t *buf,
size_t buf_size, uint8_t **out_buf) {
if (fd_socket != -1) { close(fd_socket); }
data->atnwalk_error_count++;
if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) {
data->afl->stage_max = data->afl->stage_cur;
}
*out_buf = buf;
return buf_size;
}
/**
* Perform custom mutations on a given input
*
* (Optional for now. Required in the future)
*
* @param[in] data pointer returned in afl_custom_init for this fuzz case
* @param[in] buf Pointer to input data to be mutated
* @param[in] buf_size Size of input data
* @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on
* error.
* @param[in] add_buf Buffer containing the additional test case
* @param[in] add_buf_size Size of the additional test case
* @param[in] max_size Maximum size of the mutated output. The mutation must not
* produce data larger than max_size.
* @return Size of the mutated output.
*/
size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size,
uint8_t **out_buf, uint8_t *add_buf, size_t add_buf_size,
size_t max_size) {
struct sockaddr_un addr;
int fd_socket;
uint8_t ctrl_buf[8];
uint8_t wanted;
// let's display what's going on in a nice way
if (data->stage_havoc_cur == 0) {
data->afl->stage_name = (uint8_t *)"atnwalk - havoc";
}
if (data->stage_havoc_cur == data->stage_havoc_max) {
data->afl->stage_name = (uint8_t *)"atnwalk - splice";
}
// increase the respective havoc or splice counters
if (data->stage_havoc_cur < data->stage_havoc_max) {
data->stage_havoc_cur++;
data->afl->stage_cycles[STAGE_HAVOC]++;
} else {
// if there is nothing to splice, continue with havoc and skip splicing this
// time
if (data->afl->ready_for_splicing_count < 1) {
data->stage_havoc_max = data->afl->stage_max;
data->stage_havoc_cur++;
data->afl->stage_cycles[STAGE_HAVOC]++;
} else {
data->stage_splice_cur++;
data->afl->stage_cycles[STAGE_SPLICE]++;
}
}
// keep track of found new corpus seeds per stage
if (data->afl->queued_items + data->afl->saved_crashes > data->prev_hits) {
if (data->stage_splice_cur <= 1) {
data->afl->stage_finds[STAGE_HAVOC] +=
data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
} else {
data->afl->stage_finds[STAGE_SPLICE] +=
data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
}
}
data->prev_hits = data->afl->queued_items + data->afl->saved_crashes;
// check whether this input produces a lot of timeouts, if it does then
// abandon this queue entry
if (data->afl->total_tmouts - data->prev_timeouts >= EXEC_TIMEOUT_MAX) {
data->afl->stage_max = data->afl->stage_cur;
return fail_gracefully(-1, data, buf, buf_size, out_buf);
}
// initialize the socket
fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd_socket == -1) { return fail_fatal(fd_socket, out_buf); }
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
return fail_fatal(fd_socket, out_buf);
}
// ask whether the server is alive
ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
if (!write_all(fd_socket, ctrl_buf, 1)) {
return fail_fatal(fd_socket, out_buf);
}
// see whether the server replies as expected
if (!read_all(fd_socket, ctrl_buf, 1) ||
ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
return fail_fatal(fd_socket, out_buf);
}
// tell the server what we want to do
wanted = SERVER_MUTATE_BIT | SERVER_ENCODE_BIT;
// perform a crossover if we are splicing
if (data->stage_splice_cur > 0) { wanted |= SERVER_CROSSOVER_BIT; }
// tell the server what we want and how much data will be sent
ctrl_buf[0] = wanted;
put_uint32(ctrl_buf + 1, (uint32_t)buf_size);
if (!write_all(fd_socket, ctrl_buf, 5)) {
return fail_fatal(fd_socket, out_buf);
}
// send the data to mutate and encode
if (!write_all(fd_socket, buf, buf_size)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
if (wanted & SERVER_CROSSOVER_BIT) {
// since we requested crossover, we will first tell how much additional data
// is to be expected
put_uint32(ctrl_buf, (uint32_t)add_buf_size);
if (!write_all(fd_socket, ctrl_buf, 4)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
// send the additional data for crossover
if (!write_all(fd_socket, add_buf, add_buf_size)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
// lastly, a seed is required for crossover so send one
put_uint64(ctrl_buf, (uint64_t)rand());
if (!write_all(fd_socket, ctrl_buf, 8)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
}
// since we requested mutation, we need to provide a seed for that
put_uint64(ctrl_buf, (uint64_t)rand());
if (!write_all(fd_socket, ctrl_buf, 8)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
// obtain the required buffer size for the data that will be returned
if (!read_all(fd_socket, ctrl_buf, 4)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
size_t new_size = (size_t)to_uint32(ctrl_buf);
// if the data is too large then we ignore this round
if (new_size > max_size) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
if (new_size > buf_size) {
// buf is too small, need to use data->fuzz_buf, let's see whether we need
// to reallocate
if (new_size > data->fuzz_size) {
data->fuzz_size = new_size << 1;
data->fuzz_buf = (uint8_t *)realloc(data->fuzz_buf, data->fuzz_size);
}
*out_buf = data->fuzz_buf;
} else {
// new_size fits into buf, so re-use it
*out_buf = buf;
}
// obtain the encoded data
if (!read_all(fd_socket, *out_buf, new_size)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
close(fd_socket);
return new_size;
}
/**
* A post-processing function to use right before AFL writes the test case to
* disk in order to execute the target.
*
* (Optional) If this functionality is not needed, simply don't define this
* function.
*
* @param[in] data pointer returned in afl_custom_init for this fuzz case
* @param[in] buf Buffer containing the test case to be executed
* @param[in] buf_size Size of the test case
* @param[out] out_buf Pointer to the buffer containing the test case after
* processing. External library should allocate memory for out_buf.
* The buf pointer may be reused (up to the given buf_size);
* @return Size of the output buffer after processing or the needed amount.
* A return of 0 indicates an error.
*/
size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf,
size_t buf_size, uint8_t **out_buf) {
struct sockaddr_un addr;
int fd_socket;
uint8_t ctrl_buf[8];
// initialize the socket
fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd_socket == -1) { return fail_fatal(fd_socket, out_buf); }
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
return fail_fatal(fd_socket, out_buf);
}
// ask whether the server is alive
ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
if (!write_all(fd_socket, ctrl_buf, 1)) {
return fail_fatal(fd_socket, out_buf);
}
// see whether the server replies as expected
if (!read_all(fd_socket, ctrl_buf, 1) ||
ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
return fail_fatal(fd_socket, out_buf);
}
// tell the server what we want and how much data will be sent
ctrl_buf[0] = SERVER_DECODE_BIT;
put_uint32(ctrl_buf + 1, (uint32_t)buf_size);
if (!write_all(fd_socket, ctrl_buf, 5)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
// send the data to decode
if (!write_all(fd_socket, buf, buf_size)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
// obtain the required buffer size for the data that will be returned
if (!read_all(fd_socket, ctrl_buf, 4)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
size_t new_size = (size_t)to_uint32(ctrl_buf);
// need to use data->post_process_buf, let's see whether we need to reallocate
if (new_size > data->post_process_size) {
data->post_process_size = new_size << 1;
data->post_process_buf =
(uint8_t *)realloc(data->post_process_buf, data->post_process_size);
}
*out_buf = data->post_process_buf;
// obtain the decoded data
if (!read_all(fd_socket, *out_buf, new_size)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
}
close(fd_socket);
return new_size;
}
/**
* Deinitialize everything
*
* @param data The data ptr from afl_custom_init
*/
void afl_custom_deinit(atnwalk_mutator_t *data) {
free(data->fuzz_buf);
free(data->post_process_buf);
free(data);
}

View File

@ -0,0 +1,26 @@
ifdef debug
CPPLAGS += -fsanitize=address
CXXFLAGS += -Wall
CC := clang
CXX := clang++
endif
ifdef DEBUG
CPPFLAGS += -fsanitize=address
CXXFLAGS += -Wall
CC := clang
CXX := clang++
endif
all: autotokens.so
afl-fuzz-queue.o: ../../src/afl-fuzz-queue.c
$(CC) -D_STANDALONE_MODULE=1 -I../../include -g -O3 $(CPPFLAGS) -fPIC -c -o ./afl-fuzz-queue.o ../../src/afl-fuzz-queue.c
afl-common.o: ../../src/afl-common.c
$(CC) -I../../include -g -O3 $(CPPFLAGS) -DBIN_PATH=\"dummy\" -Wno-pointer-sign -fPIC -c -o ./afl-common.o ../../src/afl-common.c
autotokens.so: afl-fuzz-queue.o afl-common.o autotokens.cpp
$(CXX) -Wno-deprecated -g -O3 $(CXXFLAGS) $(CPPFLAGS) -shared -fPIC -o autotokens.so -I../../include autotokens.cpp ./afl-fuzz-queue.o ../../src/afl-performance.o ./afl-common.o
clean:
rm -f autotokens.so *.o *~ core

View File

@ -0,0 +1,34 @@
# Autotokens
This implements an improved autotoken grammar fuzzing idea presented in
[Token-Level Fuzzing][https://www.usenix.org/system/files/sec21-salls.pdf].
It is a grammar fuzzer without actually knowing the grammar, but only works
with text based inputs.
It is recommended to run with together in an instance with `CMPLOG`.
If you have a dictionary (`-x`) this improves this custom grammar mutator.
If **not** running with `CMPLOG`, it is possible to set
`AFL_CUSTOM_MUTATOR_ONLY` to concentrate on grammar bug classes.
Do **not** set `AFL_DISABLE_TRIM` with this custom mutator!
## Configuration via environment variables
`AUTOTOKENS_ONLY_FAV` - only use this mutator on favorite queue items
`AUTOTOKENS_COMMENT` - what character or string starts a comment which will be
removed. Default: `/* ... */`
`AUTOTOKENS_FUZZ_COUNT_SHIFT` - reduce the number of fuzzing performed, shifting
the value by this number, e.g. 1.
`AUTOTOKENS_AUTO_DISABLE` - disable this module if the seeds are not ascii
(or no input and no (ascii) dictionary)
`AUTOTOKENS_LEARN_DICT` - learn from dictionaries?
0 = none
1 = only -x or autodict
2 = -x, autodict and `CMPLOG`
`AUTOTOKENS_CHANGE_MIN` - minimum number of mutations (1-256, default 8)
`AUTOTOKENS_CHANGE_MAX` - maximum number of mutations (1-4096, default 64)
`AUTOTOKENS_CREATE_FROM_THIN_AIR` - if only one small start file is present and
a dictionary loaded then create one initial
structure based on the dictionary.

File diff suppressed because it is too large Load Diff

View File

@ -1,342 +0,0 @@
#ifndef CUSTOM_MUTATOR_HELPERS
#define CUSTOM_MUTATOR_HELPERS
#include "config.h"
#include "types.h"
#include <stdlib.h>
#define INITIAL_GROWTH_SIZE (64)
#define RAND_BELOW(limit) (rand() % (limit))
/* Use in a struct: creates a name_buf and a name_size variable. */
#define BUF_VAR(type, name) \
type * name##_buf; \
size_t name##_size;
/* this fills in `&structptr->something_buf, &structptr->something_size`. */
#define BUF_PARAMS(struct, name) \
(void **)&struct->name##_buf, &struct->name##_size
typedef struct {
} afl_t;
static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
static s8 interesting_8[] = {INTERESTING_8};
static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
switch (RAND_BELOW(12)) {
case 0: {
/* Flip a single bit somewhere. Spooky! */
s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8);
out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7);
break;
}
case 1: {
/* Set byte to interesting value. */
u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))];
out_buf[(RAND_BELOW(end - begin) + begin)] = val;
break;
}
case 2: {
/* Set word to interesting value, randomly choosing endian. */
if (end - begin < 2) break;
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
if (byte_idx >= end - 1) break;
switch (RAND_BELOW(2)) {
case 0:
*(u16 *)(out_buf + byte_idx) =
interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)];
break;
case 1:
*(u16 *)(out_buf + byte_idx) =
SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]);
break;
}
break;
}
case 3: {
/* Set dword to interesting value, randomly choosing endian. */
if (end - begin < 4) break;
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
if (byte_idx >= end - 3) break;
switch (RAND_BELOW(2)) {
case 0:
*(u32 *)(out_buf + byte_idx) =
interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
break;
case 1:
*(u32 *)(out_buf + byte_idx) =
SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
break;
}
break;
}
case 4: {
/* Set qword to interesting value, randomly choosing endian. */
if (end - begin < 8) break;
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
if (byte_idx >= end - 7) break;
switch (RAND_BELOW(2)) {
case 0:
*(u64 *)(out_buf + byte_idx) =
(s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
break;
case 1:
*(u64 *)(out_buf + byte_idx) = SWAP64(
(s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
break;
}
break;
}
case 5: {
/* Randomly subtract from byte. */
out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX);
break;
}
case 6: {
/* Randomly add to byte. */
out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX);
break;
}
case 7: {
/* Randomly subtract from word, random endian. */
if (end - begin < 2) break;
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
if (byte_idx >= end - 1) break;
if (RAND_BELOW(2)) {
*(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
} else {
u16 num = 1 + RAND_BELOW(ARITH_MAX);
*(u16 *)(out_buf + byte_idx) =
SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num);
}
break;
}
case 8: {
/* Randomly add to word, random endian. */
if (end - begin < 2) break;
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
if (byte_idx >= end - 1) break;
if (RAND_BELOW(2)) {
*(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
} else {
u16 num = 1 + RAND_BELOW(ARITH_MAX);
*(u16 *)(out_buf + byte_idx) =
SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num);
}
break;
}
case 9: {
/* Randomly subtract from dword, random endian. */
if (end - begin < 4) break;
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
if (byte_idx >= end - 3) break;
if (RAND_BELOW(2)) {
*(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
} else {
u32 num = 1 + RAND_BELOW(ARITH_MAX);
*(u32 *)(out_buf + byte_idx) =
SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num);
}
break;
}
case 10: {
/* Randomly add to dword, random endian. */
if (end - begin < 4) break;
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
if (byte_idx >= end - 3) break;
if (RAND_BELOW(2)) {
*(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
} else {
u32 num = 1 + RAND_BELOW(ARITH_MAX);
*(u32 *)(out_buf + byte_idx) =
SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num);
}
break;
}
case 11: {
/* Just set a random byte to a random value. Because,
why not. We use XOR with 1-255 to eliminate the
possibility of a no-op. */
out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255);
break;
}
}
}
/* This function calculates the next power of 2 greater or equal its argument.
@return The rounded up power of 2 (if no overflow) or 0 on overflow.
*/
static inline size_t next_pow2(size_t in) {
if (in == 0 || in > (size_t)-1)
return 0; /* avoid undefined behaviour under-/overflow */
size_t out = in - 1;
out |= out >> 1;
out |= out >> 2;
out |= out >> 4;
out |= out >> 8;
out |= out >> 16;
return out + 1;
}
/* This function makes sure *size is > size_needed after call.
It will realloc *buf otherwise.
*size will grow exponentially as per:
https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/
Will return NULL and free *buf if size_needed is <1 or realloc failed.
@return For convenience, this function returns *buf.
*/
static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) {
/* No need to realloc */
if (likely(size_needed && *size >= size_needed)) return *buf;
/* No initial size was set */
if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE;
/* grow exponentially */
size_t next_size = next_pow2(size_needed);
/* handle overflow */
if (!next_size) { next_size = size_needed; }
/* alloc */
*buf = realloc(*buf, next_size);
*size = *buf ? next_size : 0;
return *buf;
}
/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */
static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2,
size_t *size2) {
void * scratch_buf = *buf1;
size_t scratch_size = *size1;
*buf1 = *buf2;
*size1 = *size2;
*buf2 = scratch_buf;
*size2 = scratch_size;
}
#undef INITIAL_GROWTH_SIZE
#endif

View File

@ -1,9 +1,14 @@
//
// This is an example on how to use afl_custom_send
// It writes each mutated data set to /tmp/foo
// You can modify this to send to IPC, shared memory, etc.
//
// cc -O3 -fPIC -shared -g -o custom_send.so -I../../include custom_send.c
// cd ../..
// afl-cc -o test-instr test-instr.c
// AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/examples/custom_send.so \
// afl-fuzz -i in -o out -- ./test-instr -f /tmp/foo
#include "custom_mutator_helpers.h"
//
#include <stdio.h>
#include <stdint.h>
@ -11,13 +16,15 @@
#include <unistd.h>
#include <fcntl.h>
#include "afl-fuzz.h"
typedef struct my_mutator {
afl_t *afl;
afl_state_t *afl;
} my_mutator_t;
my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
if (!data) {

View File

@ -6,8 +6,8 @@
Dominik Maier <mail@dmnk.co>
*/
// You need to use -I /path/to/AFLplusplus/include
#include "custom_mutator_helpers.h"
// You need to use -I/path/to/AFLplusplus/include -I.
#include "afl-fuzz.h"
#include <stdint.h>
#include <stdlib.h>
@ -26,19 +26,14 @@ static const char *commands[] = {
typedef struct my_mutator {
afl_t *afl;
afl_state_t *afl;
// any additional data here!
size_t trim_size_current;
int trimmming_steps;
int cur_step;
// Reused buffers:
BUF_VAR(u8, fuzz);
BUF_VAR(u8, data);
BUF_VAR(u8, havoc);
BUF_VAR(u8, trim);
BUF_VAR(u8, post_process);
u8 *mutated_out, *post_process_buf, *trim_buf;
} my_mutator_t;
@ -53,7 +48,7 @@ typedef struct my_mutator {
* There may be multiple instances of this mutator in one afl-fuzz run!
* Return NULL on error.
*/
my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
srand(seed); // needed also by surgical_havoc_mutate()
@ -65,6 +60,27 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
}
if ((data->mutated_out = (u8 *)malloc(MAX_FILE)) == NULL) {
perror("afl_custom_init malloc");
return NULL;
}
if ((data->post_process_buf = (u8 *)malloc(MAX_FILE)) == NULL) {
perror("afl_custom_init malloc");
return NULL;
}
if ((data->trim_buf = (u8 *)malloc(MAX_FILE)) == NULL) {
perror("afl_custom_init malloc");
return NULL;
}
data->afl = afl;
return data;
@ -96,29 +112,14 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
// the fuzzer
size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size;
// maybe_grow is optimized to be quick for reused buffers.
u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size);
if (!mutated_out) {
*out_buf = NULL;
perror("custom mutator allocation (maybe_grow)");
return 0; /* afl-fuzz will very likely error out after this. */
}
memcpy(data->mutated_out, buf, buf_size);
// Randomly select a command string to add as a header to the packet
memcpy(mutated_out, commands[rand() % 3], 3);
memcpy(data->mutated_out, commands[rand() % 3], 3);
// Mutate the payload of the packet
int i;
for (i = 0; i < 8; ++i) {
if (mutated_size > max_size) { mutated_size = max_size; }
// Randomly perform one of the (no len modification) havoc mutations
surgical_havoc_mutate(mutated_out, 3, mutated_size);
}
*out_buf = mutated_out;
*out_buf = data->mutated_out;
return mutated_size;
}
@ -142,24 +143,16 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf,
size_t buf_size, uint8_t **out_buf) {
uint8_t *post_process_buf =
maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5);
if (!post_process_buf) {
if (buf_size + 5 > MAX_FILE) { buf_size = MAX_FILE - 5; }
perror("custom mutator realloc failed.");
*out_buf = NULL;
return 0;
memcpy(data->post_process_buf + 5, buf, buf_size);
data->post_process_buf[0] = 'A';
data->post_process_buf[1] = 'F';
data->post_process_buf[2] = 'L';
data->post_process_buf[3] = '+';
data->post_process_buf[4] = '+';
}
memcpy(post_process_buf + 5, buf, buf_size);
post_process_buf[0] = 'A';
post_process_buf[1] = 'F';
post_process_buf[2] = 'L';
post_process_buf[3] = '+';
post_process_buf[4] = '+';
*out_buf = post_process_buf;
*out_buf = data->post_process_buf;
return buf_size + 5;
@ -195,13 +188,6 @@ int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf,
data->cur_step = 0;
if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) {
perror("init_trim grow");
return -1;
}
memcpy(data->trim_buf, buf, buf_size);
data->trim_size_current = buf_size;
@ -282,27 +268,11 @@ int32_t afl_custom_post_trim(my_mutator_t *data, int success) {
size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size,
u8 **out_buf, size_t max_size) {
if (buf_size == 0) {
*out_buf = buf; // in-place mutation
*out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1);
if (!*out_buf) {
if (buf_size <= sizeof(size_t)) { return buf_size; }
perror("custom havoc: maybe_grow");
return 0;
}
**out_buf = rand() % 256;
buf_size = 1;
} else {
// We reuse buf here. It's legal and faster.
*out_buf = buf;
}
size_t victim = rand() % buf_size;
size_t victim = rand() % (buf_size - sizeof(size_t));
(*out_buf)[victim] += rand() % 10;
return buf_size;
@ -369,9 +339,7 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t *data,
void afl_custom_deinit(my_mutator_t *data) {
free(data->post_process_buf);
free(data->havoc_buf);
free(data->data_buf);
free(data->fuzz_buf);
free(data->mutated_out);
free(data->trim_buf);
free(data);

View File

@ -45,9 +45,8 @@
1) If you don't want to modify the test case, simply set `*out_buf = in_buf`
and return the original `len`.
NOTE: the following is currently NOT true, we abort in this case!
2) If you want to skip this test case altogether and have AFL generate a
new one, return 0 or set `*out_buf = NULL`.
new one, return 0.
Use this sparingly - it's faster than running the target program
with patently useless inputs, but still wastes CPU time.
@ -59,8 +58,6 @@
Note that the buffer will *not* be freed for you. To avoid memory leaks,
you need to free it or reuse it on subsequent calls (as shown below).
*** Feel free to reuse the original 'in_buf' BUFFER and return it. ***
Alright. The example below shows a simple postprocessor that tries to make
sure that all input files start with "GIF89a".
@ -72,7 +69,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "alloc-inl.h"
#include "afl-fuzz.h"
/* Header that must be present at the beginning of every test case: */
@ -80,7 +77,6 @@
typedef struct post_state {
unsigned char *buf;
size_t size;
} post_state_t;
@ -95,15 +91,6 @@ void *afl_custom_init(void *afl) {
}
state->buf = calloc(sizeof(unsigned char), 4096);
if (!state->buf) {
free(state);
perror("calloc");
return NULL;
}
return state;
}
@ -113,6 +100,10 @@ void *afl_custom_init(void *afl) {
size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
unsigned int len, unsigned char **out_buf) {
/* we do in-place modification as we do not increase the size */
*out_buf = in_buf;
/* Skip execution altogether for buffers shorter than 6 bytes (just to
show how it's done). We can trust len to be sane. */
@ -120,34 +111,7 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
/* Do nothing for buffers that already start with the expected header. */
if (!memcmp(in_buf, HEADER, strlen(HEADER))) {
*out_buf = in_buf;
return len;
}
/* Allocate memory for new buffer, reusing previous allocation if
possible. Note we have to use afl-fuzz's own realloc!
Note that you should only do this if you need to grow the buffer,
otherwise work with in_buf, and assign it to *out_buf instead. */
*out_buf = afl_realloc(out_buf, len);
/* If we're out of memory, the most graceful thing to do is to return the
original buffer and give up on modifying it. Let AFL handle OOM on its
own later on. */
if (!*out_buf) {
*out_buf = in_buf;
return len;
}
if (len > strlen(HEADER))
memcpy(*out_buf + strlen(HEADER), in_buf + strlen(HEADER),
len - strlen(HEADER));
if (!memcmp(in_buf, HEADER, strlen(HEADER))) { return len; }
/* Insert the new header. */
@ -162,7 +126,6 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
/* Gets called afterwards */
void afl_custom_deinit(post_state_t *data) {
free(data->buf);
free(data);
}

View File

@ -30,7 +30,7 @@
#include <string.h>
#include <zlib.h>
#include <arpa/inet.h>
#include "alloc-inl.h"
#include "afl-fuzz.h"
/* A macro to round an integer up to 4 kB. */
@ -53,7 +53,7 @@ void *afl_custom_init(void *afl) {
}
state->buf = calloc(sizeof(unsigned char), 4096);
state->buf = calloc(sizeof(unsigned char), MAX_FILE);
if (!state->buf) {
free(state);
@ -80,21 +80,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
}
/* This is not a good way to do it, if you do not need to grow the buffer
then just work with in_buf instead for speed reasons.
But we want to show how to grow a buffer, so this is how it's done: */
unsigned int pos = 8;
unsigned char *new_buf = afl_realloc(out_buf, UP4K(len));
if (!new_buf) {
*out_buf = in_buf;
return len;
}
memcpy(new_buf, in_buf, len);
/* Minimum size of a zero-length PNG chunk is 12 bytes; if we
don't have that, we can bail out. */
@ -124,7 +110,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
if (real_cksum != file_cksum) {
*(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum;
*(uint32_t *)(data->buf + pos + 8 + chunk_len) = real_cksum;
}
@ -134,7 +120,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
}
*out_buf = new_buf;
*out_buf = data->buf;
return len;
}

View File

@ -1,6 +1,6 @@
// This simple example just creates random buffer <= 100 filled with 'A'
// needs -I /path/to/AFLplusplus/include
#include "custom_mutator_helpers.h"
#include "afl-fuzz.h"
#include <stdint.h>
#include <stdlib.h>
@ -13,14 +13,14 @@
typedef struct my_mutator {
afl_t *afl;
afl_state_t *afl;
// Reused buffers:
BUF_VAR(u8, fuzz);
u8 *fuzz_buf;
} my_mutator_t;
my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
srand(seed);
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
@ -31,6 +31,14 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
}
data->fuzz_buf = (u8 *)malloc(MAX_FILE);
if (!data->fuzz_buf) {
perror("afl_custom_init malloc");
return NULL;
}
data->afl = afl;
return data;
@ -44,18 +52,10 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
int size = (rand() % 100) + 1;
if (size > max_size) size = max_size;
u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), size);
if (!mutated_out) {
*out_buf = NULL;
perror("custom mutator allocation (maybe_grow)");
return 0; /* afl-fuzz will very likely error out after this. */
memset(data->fuzz_buf, _FIXED_CHAR, size);
}
memset(mutated_out, _FIXED_CHAR, size);
*out_buf = mutated_out;
*out_buf = data->fuzz_buf;
return size;
}

View File

@ -11,7 +11,7 @@
# Adapted for AFLplusplus by Dominik Maier <mail@dmnk.co>
#
# Copyright 2017 Battelle Memorial Institute. All rights reserved.
# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
# Copyright 2019-2023 AFLplusplus Project. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -14,7 +14,7 @@
# <andreafioraldi@gmail.com>
#
# Copyright 2017 Battelle Memorial Institute. All rights reserved.
# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
# Copyright 2019-2023 AFLplusplus Project. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,22 +0,0 @@
#ifndef CUSTOM_MUTATOR_HELPERS
#define CUSTOM_MUTATOR_HELPERS
#include "config.h"
#include "types.h"
#include "afl-fuzz.h"
#include <stdlib.h>
#define INITIAL_GROWTH_SIZE (64)
/* Use in a struct: creates a name_buf and a name_size variable. */
#define BUF_VAR(type, name) \
type * name##_buf; \
size_t name##_size;
/* this filles in `&structptr->something_buf, &structptr->something_size`. */
#define BUF_PARAMS(struct, name) \
(void **)&struct->name##_buf, &struct->name##_size
#undef INITIAL_GROWTH_SIZE
#endif

View File

@ -3,7 +3,7 @@
#include <stdlib.h>
#include <string.h>
#include "custom_mutator_helpers.h"
#include "afl-fuzz.h"
#include "mangle.h"
#define NUMBER_OF_MUTATIONS 5
@ -65,7 +65,7 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
/* When a new queue entry is added we check if there are new dictionary
entries to add to honggfuzz structure */
uint8_t afl_custom_queue_new_entry(my_mutator_t * data,
void afl_custom_queue_new_entry(my_mutator_t *data,
const uint8_t *filename_new_queue,
const uint8_t *filename_orig_queue) {
@ -97,7 +97,7 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t * data,
}
return 0;
return;
}

View File

@ -40,10 +40,15 @@
#include "libhfcommon/util.h"
static inline size_t mangle_LenLeft(run_t *run, size_t off) {
if (off >= run->dynfile->size) {
LOG_F("Offset is too large: off:%zu >= len:%zu", off, run->dynfile->size);
}
return (run->dynfile->size - off - 1);
}
/*
@ -51,46 +56,46 @@ static inline size_t mangle_LenLeft(run_t* run, size_t off) {
* Based on an idea by https://twitter.com/gamozolabs
*/
static inline size_t mangle_getLen(size_t max) {
if (max > _HF_INPUT_MAX_SIZE) {
LOG_F("max (%zu) > _HF_INPUT_MAX_SIZE (%zu)", max, (size_t)_HF_INPUT_MAX_SIZE);
}
if (max == 0) {
LOG_F("max == 0");
}
if (max == 1) {
return 1;
LOG_F("max (%zu) > _HF_INPUT_MAX_SIZE (%zu)", max,
(size_t)_HF_INPUT_MAX_SIZE);
}
if (max == 0) { LOG_F("max == 0"); }
if (max == 1) { return 1; }
/* Give 50% chance the the uniform distribution */
if (util_rnd64() & 1) {
return (size_t)util_rndGet(1, max);
}
if (util_rnd64() & 1) { return (size_t)util_rndGet(1, max); }
/* effectively exprand() */
return (size_t)util_rndGet(1, util_rndGet(1, max));
}
/* Prefer smaller values here, so use mangle_getLen() */
static inline size_t mangle_getOffSet(run_t *run) {
return mangle_getLen(run->dynfile->size) - 1;
}
/* Offset which can be equal to the file size */
static inline size_t mangle_getOffSetPlus1(run_t *run) {
size_t reqlen = HF_MIN(run->dynfile->size + 1, _HF_INPUT_MAX_SIZE);
return mangle_getLen(reqlen) - 1;
}
static inline void mangle_Move(run_t* run, size_t off_from, size_t off_to, size_t len) {
if (off_from >= run->dynfile->size) {
return;
}
if (off_to >= run->dynfile->size) {
return;
}
if (off_from == off_to) {
return;
}
static inline void mangle_Move(run_t *run, size_t off_from, size_t off_to,
size_t len) {
if (off_from >= run->dynfile->size) { return; }
if (off_to >= run->dynfile->size) { return; }
if (off_from == off_to) { return; }
size_t len_from = run->dynfile->size - off_from;
len = HF_MIN(len, len_from);
@ -99,65 +104,79 @@ static inline void mangle_Move(run_t* run, size_t off_from, size_t off_to, size_
len = HF_MIN(len, len_to);
memmove(&run->dynfile->data[off_to], &run->dynfile->data[off_from], len);
}
static inline void mangle_Overwrite(
run_t* run, size_t off, const uint8_t* src, size_t len, bool printable) {
if (len == 0) {
return;
}
static inline void mangle_Overwrite(run_t *run, size_t off, const uint8_t *src,
size_t len, bool printable) {
if (len == 0) { return; }
size_t maxToCopy = run->dynfile->size - off;
if (len > maxToCopy) {
len = maxToCopy;
}
if (len > maxToCopy) { len = maxToCopy; }
memmove(&run->dynfile->data[off], src, len);
if (printable) {
util_turnToPrintable(&run->dynfile->data[off], len);
}
if (printable) { util_turnToPrintable(&run->dynfile->data[off], len); }
}
static inline size_t mangle_Inflate(run_t* run, size_t off, size_t len, bool printable) {
if (run->dynfile->size >= run->global->mutate.maxInputSz) {
return 0;
}
static inline size_t mangle_Inflate(run_t *run, size_t off, size_t len,
bool printable) {
if (run->dynfile->size >= run->global->mutate.maxInputSz) { return 0; }
if (len > (run->global->mutate.maxInputSz - run->dynfile->size)) {
len = run->global->mutate.maxInputSz - run->dynfile->size;
}
input_setSize(run, run->dynfile->size + len);
mangle_Move(run, off, off + len, run->dynfile->size);
if (printable) {
memset(&run->dynfile->data[off], ' ', len);
}
if (printable) { memset(&run->dynfile->data[off], ' ', len); }
return len;
}
static inline void mangle_Insert(
run_t* run, size_t off, const uint8_t* val, size_t len, bool printable) {
static inline void mangle_Insert(run_t *run, size_t off, const uint8_t *val,
size_t len, bool printable) {
len = mangle_Inflate(run, off, len, printable);
mangle_Overwrite(run, off, val, len, printable);
}
static inline void mangle_UseValue(run_t* run, const uint8_t* val, size_t len, bool printable) {
static inline void mangle_UseValue(run_t *run, const uint8_t *val, size_t len,
bool printable) {
if (util_rnd64() & 1) {
mangle_Overwrite(run, mangle_getOffSet(run), val, len, printable);
} else {
mangle_Insert(run, mangle_getOffSetPlus1(run), val, len, printable);
}
}
static inline void mangle_UseValueAt(
run_t* run, size_t off, const uint8_t* val, size_t len, bool printable) {
if (util_rnd64() & 1) {
mangle_Overwrite(run, off, val, len, printable);
} else {
mangle_Insert(run, off, val, len, printable);
}
static inline void mangle_UseValueAt(run_t *run, size_t off, const uint8_t *val,
size_t len, bool printable) {
if (util_rnd64() & 1) {
mangle_Overwrite(run, off, val, len, printable);
} else {
mangle_Insert(run, off, val, len, printable);
}
}
static void mangle_MemSwap(run_t *run, bool printable HF_ATTR_UNUSED) {
/* No big deal if those two are overlapping */
size_t off1 = mangle_getOffSet(run);
size_t maxlen1 = run->dynfile->size - off1;
@ -165,82 +184,105 @@ static void mangle_MemSwap(run_t* run, bool printable HF_ATTR_UNUSED) {
size_t maxlen2 = run->dynfile->size - off2;
size_t len = mangle_getLen(HF_MIN(maxlen1, maxlen2));
if (off1 == off2) {
return;
}
if (off1 == off2) { return; }
for (size_t i = 0; i < (len / 2); i++) {
/*
* First - from the head, next from the tail. Don't worry about layout of the overlapping
* part - there's no good solution to that, and it can be left somewhat scrambled,
* while still preserving the entropy
* First - from the head, next from the tail. Don't worry about layout of
* the overlapping part - there's no good solution to that, and it can be
* left somewhat scrambled, while still preserving the entropy
*/
const uint8_t tmp1 = run->dynfile->data[off2 + i];
run->dynfile->data[off2 + i] = run->dynfile->data[off1 + i];
run->dynfile->data[off1 + i] = tmp1;
const uint8_t tmp2 = run->dynfile->data[off2 + (len - 1) - i];
run->dynfile->data[off2 + (len - 1) - i] = run->dynfile->data[off1 + (len - 1) - i];
run->dynfile->data[off2 + (len - 1) - i] =
run->dynfile->data[off1 + (len - 1) - i];
run->dynfile->data[off1 + (len - 1) - i] = tmp2;
}
}
static void mangle_MemCopy(run_t *run, bool printable HF_ATTR_UNUSED) {
size_t off = mangle_getOffSet(run);
size_t len = mangle_getLen(run->dynfile->size - off);
/* Use a temp buf, as Insert/Inflate can change source bytes */
uint8_t *tmpbuf = (uint8_t *)util_Malloc(len);
defer {
free(tmpbuf);
};
memmove(tmpbuf, &run->dynfile->data[off], len);
mangle_UseValue(run, tmpbuf, len, printable);
}
static void mangle_Bytes(run_t *run, bool printable) {
uint16_t buf;
if (printable) {
util_rndBufPrintable((uint8_t *)&buf, sizeof(buf));
} else {
buf = util_rnd64();
}
/* Overwrite with random 1-2-byte values */
size_t toCopy = util_rndGet(1, 2);
mangle_UseValue(run, (const uint8_t *)&buf, toCopy, printable);
}
static void mangle_ByteRepeat(run_t *run, bool printable) {
size_t off = mangle_getOffSet(run);
size_t destOff = off + 1;
size_t maxSz = run->dynfile->size - destOff;
/* No space to repeat */
if (!maxSz) {
mangle_Bytes(run, printable);
return;
}
size_t len = mangle_getLen(maxSz);
if (util_rnd64() & 0x1) {
len = mangle_Inflate(run, destOff, len, printable);
}
memset(&run->dynfile->data[destOff], run->dynfile->data[off], len);
}
static void mangle_Bit(run_t *run, bool printable) {
size_t off = mangle_getOffSet(run);
run->dynfile->data[off] ^= (uint8_t)(1U << util_rndGet(0, 7));
if (printable) {
util_turnToPrintable(&(run->dynfile->data[off]), 1);
}
if (printable) { util_turnToPrintable(&(run->dynfile->data[off]), 1); }
}
static const struct {
const uint8_t val[8];
const size_t size;
} mangleMagicVals[] = {
/* 1B - No endianness */
{"\x00\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x01\x00\x00\x00\x00\x00\x00\x00", 1},
@ -472,160 +514,206 @@ static const struct {
{"\x00\x00\x00\x00\x00\x00\x00\x80", 8},
{"\x01\x00\x00\x00\x00\x00\x00\x80", 8},
{"\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
};
static void mangle_Magic(run_t *run, bool printable) {
uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleMagicVals) - 1);
mangle_UseValue(run, mangleMagicVals[choice].val, mangleMagicVals[choice].size, printable);
mangle_UseValue(run, mangleMagicVals[choice].val,
mangleMagicVals[choice].size, printable);
}
static void mangle_StaticDict(run_t *run, bool printable) {
if (run->global->mutate.dictionaryCnt == 0) {
mangle_Bytes(run, printable);
return;
}
uint64_t choice = util_rndGet(0, run->global->mutate.dictionaryCnt - 1);
mangle_UseValue(run, run->global->mutate.dictionary[choice].val,
run->global->mutate.dictionary[choice].len, printable);
}
static inline const uint8_t *mangle_FeedbackDict(run_t *run, size_t *len) {
if (!run->global->feedback.cmpFeedback) {
return NULL;
}
if (!run->global->feedback.cmpFeedback) { return NULL; }
cmpfeedback_t *cmpf = run->global->feedback.cmpFeedbackMap;
uint32_t cnt = ATOMIC_GET(cmpf->cnt);
if (cnt == 0) {
return NULL;
}
if (cnt > ARRAYSIZE(cmpf->valArr)) {
cnt = ARRAYSIZE(cmpf->valArr);
}
if (cnt == 0) { return NULL; }
if (cnt > ARRAYSIZE(cmpf->valArr)) { cnt = ARRAYSIZE(cmpf->valArr); }
uint32_t choice = util_rndGet(0, cnt - 1);
*len = (size_t)ATOMIC_GET(cmpf->valArr[choice].len);
if (*len == 0) {
return NULL;
}
if (*len == 0) { return NULL; }
return cmpf->valArr[choice].val;
}
static void mangle_ConstFeedbackDict(run_t *run, bool printable) {
size_t len;
const uint8_t *val = mangle_FeedbackDict(run, &len);
if (val == NULL) {
mangle_Bytes(run, printable);
return;
}
mangle_UseValue(run, val, len, printable);
}
static void mangle_MemSet(run_t *run, bool printable) {
size_t off = mangle_getOffSet(run);
size_t len = mangle_getLen(run->dynfile->size - off);
int val = printable ? (int)util_rndPrintable() : (int)util_rndGet(0, UINT8_MAX);
int val =
printable ? (int)util_rndPrintable() : (int)util_rndGet(0, UINT8_MAX);
if (util_rnd64() & 1) {
len = mangle_Inflate(run, off, len, printable);
}
if (util_rnd64() & 1) { len = mangle_Inflate(run, off, len, printable); }
memset(&run->dynfile->data[off], val, len);
}
static void mangle_MemClr(run_t *run, bool printable) {
size_t off = mangle_getOffSet(run);
size_t len = mangle_getLen(run->dynfile->size - off);
int val = printable ? ' ' : 0;
if (util_rnd64() & 1) {
len = mangle_Inflate(run, off, len, printable);
}
if (util_rnd64() & 1) { len = mangle_Inflate(run, off, len, printable); }
memset(&run->dynfile->data[off], val, len);
}
static void mangle_RandomBuf(run_t *run, bool printable) {
size_t off = mangle_getOffSet(run);
size_t len = mangle_getLen(run->dynfile->size - off);
if (util_rnd64() & 1) {
len = mangle_Inflate(run, off, len, printable);
}
if (util_rnd64() & 1) { len = mangle_Inflate(run, off, len, printable); }
if (printable) {
util_rndBufPrintable(&run->dynfile->data[off], len);
} else {
util_rndBuf(&run->dynfile->data[off], len);
}
}
static inline void mangle_AddSubWithRange(
run_t* run, size_t off, size_t varLen, uint64_t range, bool printable) {
}
static inline void mangle_AddSubWithRange(run_t *run, size_t off, size_t varLen,
uint64_t range, bool printable) {
int64_t delta = (int64_t)util_rndGet(0, range * 2) - (int64_t)range;
switch (varLen) {
case 1: {
run->dynfile->data[off] += delta;
break;
}
case 2: {
int16_t val;
memcpy(&val, &run->dynfile->data[off], sizeof(val));
if (util_rnd64() & 0x1) {
val += delta;
} else {
/* Foreign endianess */
val = __builtin_bswap16(val);
val += delta;
val = __builtin_bswap16(val);
}
mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable);
break;
}
case 4: {
int32_t val;
memcpy(&val, &run->dynfile->data[off], sizeof(val));
if (util_rnd64() & 0x1) {
val += delta;
} else {
/* Foreign endianess */
val = __builtin_bswap32(val);
val += delta;
val = __builtin_bswap32(val);
}
mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable);
break;
}
case 8: {
int64_t val;
memcpy(&val, &run->dynfile->data[off], sizeof(val));
if (util_rnd64() & 0x1) {
val += delta;
} else {
/* Foreign endianess */
val = __builtin_bswap64(val);
val += delta;
val = __builtin_bswap64(val);
}
mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable);
break;
}
default: {
LOG_F("Unknown variable length size: %zu", varLen);
}
}
}
static void mangle_AddSub(run_t *run, bool printable) {
size_t off = mangle_getOffSet(run);
/* 1,2,4,8 */
size_t varLen = 1U << util_rndGet(0, 3);
if ((run->dynfile->size - off) < varLen) {
varLen = 1;
}
if ((run->dynfile->size - off) < varLen) { varLen = 1; }
uint64_t range;
switch (varLen) {
case 1:
range = 16;
break;
@ -640,107 +728,140 @@ static void mangle_AddSub(run_t* run, bool printable) {
break;
default:
LOG_F("Invalid operand size: %zu", varLen);
}
mangle_AddSubWithRange(run, off, varLen, range, printable);
}
static void mangle_IncByte(run_t *run, bool printable) {
size_t off = mangle_getOffSet(run);
if (printable) {
run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 1) % 95 + 32;
} else {
run->dynfile->data[off] += (uint8_t)1UL;
}
}
static void mangle_DecByte(run_t *run, bool printable) {
size_t off = mangle_getOffSet(run);
if (printable) {
run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 94) % 95 + 32;
} else {
run->dynfile->data[off] -= (uint8_t)1UL;
}
}
static void mangle_NegByte(run_t *run, bool printable) {
size_t off = mangle_getOffSet(run);
if (printable) {
run->dynfile->data[off] = 94 - (run->dynfile->data[off] - 32) + 32;
} else {
run->dynfile->data[off] = ~(run->dynfile->data[off]);
}
}
static void mangle_Expand(run_t *run, bool printable) {
size_t off = mangle_getOffSet(run);
size_t len;
if (util_rnd64() % 16) {
len = mangle_getLen(HF_MIN(16, run->global->mutate.maxInputSz - off));
} else {
len = mangle_getLen(run->global->mutate.maxInputSz - off);
}
mangle_Inflate(run, off, len, printable);
}
static void mangle_Shrink(run_t *run, bool printable HF_ATTR_UNUSED) {
if (run->dynfile->size <= 2U) {
return;
}
if (run->dynfile->size <= 2U) { return; }
size_t off_start = mangle_getOffSet(run);
size_t len = mangle_LenLeft(run, off_start);
if (len == 0) {
return;
}
if (len == 0) { return; }
if (util_rnd64() % 16) {
len = mangle_getLen(HF_MIN(16, len));
} else {
len = mangle_getLen(len);
}
size_t off_end = off_start + len;
size_t len_to_move = run->dynfile->size - off_end;
mangle_Move(run, off_end, off_start, len_to_move);
input_setSize(run, run->dynfile->size - len);
}
static void mangle_ASCIINum(run_t *run, bool printable) {
size_t len = util_rndGet(2, 8);
char buf[20];
snprintf(buf, sizeof(buf), "%-19" PRId64, (int64_t)util_rnd64());
mangle_UseValue(run, (const uint8_t *)buf, len, printable);
}
static void mangle_ASCIINumChange(run_t *run, bool printable) {
size_t off = mangle_getOffSet(run);
/* Find a digit */
for (; off < run->dynfile->size; off++) {
if (isdigit(run->dynfile->data[off])) {
break;
}
if (isdigit(run->dynfile->data[off])) { break; }
}
size_t left = run->dynfile->size - off;
if (left == 0) {
return;
}
if (left == 0) { return; }
size_t len = 0;
uint64_t val = 0;
/* 20 is maximum lenght of a string representing a 64-bit unsigned value */
for (len = 0; (len < 20) && (len < left); len++) {
char c = run->dynfile->data[off + len];
if (!isdigit(c)) {
break;
}
if (!isdigit(c)) { break; }
val *= 10;
val += (c - '0');
}
switch (util_rndGet(0, 7)) {
case 0:
val++;
break;
@ -767,43 +888,56 @@ static void mangle_ASCIINumChange(run_t* run, bool printable) {
break;
default:
LOG_F("Invalid choice");
};
char buf[20];
snprintf(buf, sizeof(buf), "%-19" PRIu64, val);
mangle_UseValueAt(run, off, (const uint8_t *)buf, len, printable);
}
static void mangle_Splice(run_t *run, bool printable) {
if (run->global->feedback.dynFileMethod == _HF_DYNFILE_NONE) {
mangle_Bytes(run, printable);
return;
}
size_t sz = 0;
const uint8_t *buf = input_getRandomInputAsBuf(run, &sz);
if (!buf) {
LOG_E("input_getRandomInputAsBuf() returned no input");
mangle_Bytes(run, printable);
return;
}
if (!sz) {
mangle_Bytes(run, printable);
return;
}
size_t remoteOff = mangle_getLen(sz) - 1;
size_t len = mangle_getLen(sz - remoteOff);
mangle_UseValue(run, &buf[remoteOff], len, printable);
}
static void mangle_Resize(run_t *run, bool printable) {
ssize_t oldsz = run->dynfile->size;
ssize_t newsz = 0;
uint64_t choice = util_rndGet(0, 32);
switch (choice) {
case 0: /* Set new size arbitrarily */
newsz = (ssize_t)util_rndGet(1, run->global->mutate.maxInputSz);
break;
@ -825,83 +959,98 @@ static void mangle_Resize(run_t* run, bool printable) {
default:
LOG_F("Illegal value from util_rndGet: %" PRIu64, choice);
break;
}
if (newsz < 1) {
newsz = 1;
}
if (newsz < 1) { newsz = 1; }
if (newsz > (ssize_t)run->global->mutate.maxInputSz) {
newsz = run->global->mutate.maxInputSz;
}
input_setSize(run, (size_t)newsz);
if (newsz > oldsz) {
if (printable) {
memset(&run->dynfile->data[oldsz], ' ', newsz - oldsz);
}
if (printable) { memset(&run->dynfile->data[oldsz], ' ', newsz - oldsz); }
}
}
void mangle_mangleContent(run_t *run, int speed_factor) {
static void (*const mangleFuncs[])(run_t * run, bool printable) = {
mangle_Shrink,
mangle_Expand,
mangle_Bit,
mangle_IncByte,
mangle_DecByte,
mangle_NegByte,
mangle_AddSub,
mangle_MemSet,
mangle_MemClr,
mangle_MemSwap,
mangle_MemCopy,
mangle_Bytes,
mangle_ASCIINum,
mangle_ASCIINumChange,
mangle_ByteRepeat,
mangle_Magic,
mangle_StaticDict,
mangle_ConstFeedbackDict,
mangle_RandomBuf,
mangle_Splice,
mangle_Shrink, mangle_Expand, mangle_Bit,
mangle_IncByte, mangle_DecByte, mangle_NegByte,
mangle_AddSub, mangle_MemSet, mangle_MemClr,
mangle_MemSwap, mangle_MemCopy, mangle_Bytes,
mangle_ASCIINum, mangle_ASCIINumChange, mangle_ByteRepeat,
mangle_Magic, mangle_StaticDict, mangle_ConstFeedbackDict,
mangle_RandomBuf, mangle_Splice,
};
if (run->mutationsPerRun == 0U) {
return;
}
if (run->mutationsPerRun == 0U) { return; }
if (run->dynfile->size == 0U) {
mangle_Resize(run, /* printable= */ run->global->cfg.only_printable);
}
uint64_t changesCnt = run->global->mutate.mutationsPerRun;
if (speed_factor < 5) {
changesCnt = util_rndGet(1, run->global->mutate.mutationsPerRun);
} else if (speed_factor < 10) {
changesCnt = run->global->mutate.mutationsPerRun;
} else {
changesCnt = HF_MIN(speed_factor, 10);
changesCnt = HF_MAX(changesCnt, (run->global->mutate.mutationsPerRun * 5));
}
/* If last coverage acquisition was more than 5 secs ago, use splicing more frequently */
/* If last coverage acquisition was more than 5 secs ago, use splicing more
* frequently */
if ((time(NULL) - ATOMIC_GET(run->global->timing.lastCovUpdate)) > 5) {
if (util_rnd64() & 0x1) {
mangle_Splice(run, run->global->cfg.only_printable);
}
}
for (uint64_t x = 0; x < changesCnt; x++) {
if (run->global->feedback.cmpFeedback && (util_rnd64() & 0x1)) {
/*
* mangle_ConstFeedbackDict() is quite powerful if the dynamic feedback dictionary
* exists. If so, give it 50% chance of being used among all mangling functions.
* mangle_ConstFeedbackDict() is quite powerful if the dynamic feedback
* dictionary exists. If so, give it 50% chance of being used among all
* mangling functions.
*/
mangle_ConstFeedbackDict(run, /* printable= */ run->global->cfg.only_printable);
mangle_ConstFeedbackDict(
run, /* printable= */ run->global->cfg.only_printable);
} else {
uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleFuncs) - 1);
mangleFuncs[choice](run, /* printable= */ run->global->cfg.only_printable);
mangleFuncs[choice](run,
/* printable= */ run->global->cfg.only_printable);
}
}
wmb();
}

View File

@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "62614ce1016c86e3f00f35b56399292ceabd486b" }
libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "266677bb88abe75165430f34e7de897c35560504" }
custom_mutator = { path = "../rust/custom_mutator", features = ["afl_internals"] }
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib

View File

@ -1,5 +1,4 @@
#![cfg(unix)]
#![allow(unused_variables)]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{
@ -18,10 +17,12 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens},
Mutator,
},
state::{HasCorpus, HasMaxSize, HasMetadata, HasRand, State},
prelude::UsesInput,
state::{HasCorpus, HasMaxSize, HasMetadata, HasRand, State, UsesState},
Error,
};
#[allow(clippy::identity_op)]
const MAX_FILE: usize = 1 * 1024 * 1024;
static mut AFL: Option<&'static afl_state> = None;
@ -64,24 +65,32 @@ impl<'de> Deserialize<'de> for AFLCorpus {
}
}
impl Corpus<BytesInput> for AFLCorpus {
impl UsesState for AFLCorpus {
type State = AFLState;
}
impl Corpus for AFLCorpus {
#[inline]
fn count(&self) -> usize {
afl().queued_items as usize
}
#[inline]
fn add(&mut self, testcase: Testcase<BytesInput>) -> Result<usize, Error> {
fn add(&mut self, _testcase: Testcase<BytesInput>) -> Result<usize, Error> {
unimplemented!();
}
#[inline]
fn replace(&mut self, idx: usize, testcase: Testcase<BytesInput>) -> Result<(), Error> {
fn replace(
&mut self,
_idx: usize,
_testcase: Testcase<BytesInput>,
) -> Result<Testcase<Self::Input>, Error> {
unimplemented!();
}
#[inline]
fn remove(&mut self, idx: usize) -> Result<Option<Testcase<BytesInput>>, Error> {
fn remove(&mut self, _idx: usize) -> Result<Option<Testcase<BytesInput>>, Error> {
unimplemented!();
}
@ -92,7 +101,7 @@ impl Corpus<BytesInput> for AFLCorpus {
entries.entry(idx).or_insert_with(|| {
let queue_buf = std::slice::from_raw_parts_mut(afl().queue_buf, self.count());
let entry = queue_buf[idx].as_mut().unwrap();
let fname = CStr::from_ptr((entry.fname as *mut i8).as_ref().unwrap())
let fname = CStr::from_ptr((entry.fname.cast::<i8>()).as_ref().unwrap())
.to_str()
.unwrap()
.to_owned();
@ -127,9 +136,10 @@ pub struct AFLState {
}
impl AFLState {
#[must_use]
pub fn new(seed: u32) -> Self {
Self {
rand: StdRand::with_seed(seed as u64),
rand: StdRand::with_seed(u64::from(seed)),
corpus: AFLCorpus::default(),
metadata: SerdeAnyMap::new(),
max_size: MAX_FILE,
@ -153,7 +163,11 @@ impl HasRand for AFLState {
}
}
impl HasCorpus<BytesInput> for AFLState {
impl UsesInput for AFLState {
type Input = BytesInput;
}
impl HasCorpus for AFLState {
type Corpus = AFLCorpus;
#[inline]
@ -208,7 +222,7 @@ impl CustomMutator for LibAFLBaseCustomMutator {
tokens.push(data.to_vec());
}
if !tokens.is_empty() {
state.add_metadata(Tokens::new(tokens));
state.add_metadata(Tokens::from(tokens));
}
Ok(Self {
state,
@ -220,7 +234,7 @@ impl CustomMutator for LibAFLBaseCustomMutator {
fn fuzz<'b, 's: 'b>(
&'s mut self,
buffer: &'b mut [u8],
add_buff: Option<&[u8]>,
_add_buff: Option<&[u8]>,
max_size: usize,
) -> Result<Option<&'b [u8]>, Self::Error> {
self.state.set_max_size(max_size);

View File

@ -1 +0,0 @@
../examples/custom_mutator_helpers.h

View File

@ -1,6 +1,5 @@
// This simple example just creates random buffer <= 100 filled with 'A'
// needs -I /path/to/AFLplusplus/include
//#include "custom_mutator_helpers.h"
#include <stdint.h>
#include <stdlib.h>
@ -8,19 +7,17 @@
#include <stdio.h>
#include "radamsa.h"
#include "custom_mutator_helpers.h"
#include "afl-fuzz.h"
typedef struct my_mutator {
afl_t *afl;
afl_state_t *afl;
u8 *mutator_buf;
unsigned int seed;
} my_mutator_t;
my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
srand(seed);
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));

View File

@ -1,12 +1,12 @@
[package]
name = "custom_mutator-sys"
version = "0.1.0"
version = "0.1.1"
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
edition = "2018"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[build-dependencies]
bindgen = "0.56"
bindgen = "0.63"

View File

@ -15,8 +15,8 @@ fn main() {
// The input header we would like to generate
// bindings for.
.header("wrapper.h")
.whitelist_type("afl_state_t")
.blacklist_type(r"u\d+")
.allowlist_type("afl_state_t")
.blocklist_type(r"u\d+")
.opaque_type(r"_.*")
.opaque_type("FILE")
.opaque_type("in_addr(_t)?")

View File

@ -1,5 +1,7 @@
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(clippy::too_many_lines)]
#![allow(clippy::used_underscore_binding)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

View File

@ -2,7 +2,7 @@
name = "custom_mutator"
version = "0.1.0"
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
edition = "2018"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -20,7 +20,7 @@
//! This binding is panic-safe in that it will prevent panics from unwinding into AFL++. Any panic will `abort` at the boundary between the custom mutator and AFL++.
//!
//! # Access to AFL++ internals
//! This crate has an optional feature "afl_internals", which gives access to AFL++'s internal state.
//! This crate has an optional feature "`afl_internals`", which gives access to AFL++'s internal state.
//! The state is passed to [`CustomMutator::init`], when the feature is activated.
//!
//! _This is completely unsafe and uses automatically generated types extracted from the AFL++ source._
@ -115,7 +115,7 @@ pub mod wrappers {
impl<M: RawCustomMutator> FFIContext<M> {
fn from(ptr: *mut c_void) -> ManuallyDrop<Box<Self>> {
assert!(!ptr.is_null());
ManuallyDrop::new(unsafe { Box::from_raw(ptr as *mut Self) })
ManuallyDrop::new(unsafe { Box::from_raw(ptr.cast::<Self>()) })
}
fn into_ptr(self: Box<Self>) -> *const c_void {
@ -141,27 +141,28 @@ pub mod wrappers {
}
/// panic handler called for every panic
fn panic_handler(method: &str, panic_info: Box<dyn Any + Send + 'static>) -> ! {
fn panic_handler(method: &str, panic_info: &Box<dyn Any + Send + 'static>) -> ! {
use std::ops::Deref;
let cause = panic_info
.downcast_ref::<String>()
.map(String::deref)
.unwrap_or_else(|| {
let cause = panic_info.downcast_ref::<String>().map_or_else(
|| {
panic_info
.downcast_ref::<&str>()
.copied()
.unwrap_or("<cause unknown>")
});
eprintln!("A panic occurred at {}: {}", method, cause);
},
String::deref,
);
eprintln!("A panic occurred at {method}: {cause}");
abort()
}
/// Internal function used in the macro
#[cfg(not(feature = "afl_internals"))]
#[must_use]
pub fn afl_custom_init_<M: RawCustomMutator>(seed: u32) -> *const c_void {
match catch_unwind(|| FFIContext::<M>::new(seed).into_ptr()) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_init", err),
Err(err) => panic_handler("afl_custom_init", &err),
}
}
@ -176,7 +177,7 @@ pub mod wrappers {
FFIContext::<M>::new(afl, seed).into_ptr()
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_init", err),
Err(err) => panic_handler("afl_custom_init", &err),
}
}
@ -196,32 +197,27 @@ pub mod wrappers {
) -> usize {
match catch_unwind(|| {
let mut context = FFIContext::<M>::from(data);
if buf.is_null() {
panic!("null buf passed to afl_custom_fuzz")
}
if out_buf.is_null() {
panic!("null out_buf passed to afl_custom_fuzz")
}
assert!(!buf.is_null(), "null buf passed to afl_custom_fuzz");
assert!(!out_buf.is_null(), "null out_buf passed to afl_custom_fuzz");
let buff_slice = slice::from_raw_parts_mut(buf, buf_size);
let add_buff_slice = if add_buf.is_null() {
None
} else {
Some(slice::from_raw_parts(add_buf, add_buf_size))
};
match context.mutator.fuzz(buff_slice, add_buff_slice, max_size) {
Some(buffer) => {
if let Some(buffer) = context.mutator.fuzz(buff_slice, add_buff_slice, max_size) {
*out_buf = buffer.as_ptr();
buffer.len()
}
None => {
} else {
// return the input buffer with 0-length to let AFL skip this mutation attempt
*out_buf = buf;
0
}
}
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_fuzz", err),
Err(err) => panic_handler("afl_custom_fuzz", &err),
}
}
@ -237,9 +233,8 @@ pub mod wrappers {
) -> u32 {
match catch_unwind(|| {
let mut context = FFIContext::<M>::from(data);
if buf.is_null() {
panic!("null buf passed to afl_custom_fuzz")
}
assert!(!buf.is_null(), "null buf passed to afl_custom_fuzz");
let buf_slice = slice::from_raw_parts(buf, buf_size);
// see https://doc.rust-lang.org/nomicon/borrow-splitting.html
let ctx = &mut **context;
@ -247,37 +242,39 @@ pub mod wrappers {
mutator.fuzz_count(buf_slice)
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_fuzz_count", err),
Err(err) => panic_handler("afl_custom_fuzz_count", &err),
}
}
/// Internal function used in the macro
pub fn afl_custom_queue_new_entry_<M: RawCustomMutator>(
pub unsafe fn afl_custom_queue_new_entry_<M: RawCustomMutator>(
data: *mut c_void,
filename_new_queue: *const c_char,
filename_orig_queue: *const c_char,
) -> bool {
match catch_unwind(|| {
let mut context = FFIContext::<M>::from(data);
if filename_new_queue.is_null() {
panic!("received null filename_new_queue in afl_custom_queue_new_entry");
}
assert!(
!filename_new_queue.is_null(),
"received null filename_new_queue in afl_custom_queue_new_entry"
);
let filename_new_queue = Path::new(OsStr::from_bytes(
unsafe { CStr::from_ptr(filename_new_queue) }.to_bytes(),
));
let filename_orig_queue = if !filename_orig_queue.is_null() {
let filename_orig_queue = if filename_orig_queue.is_null() {
None
} else {
Some(Path::new(OsStr::from_bytes(
unsafe { CStr::from_ptr(filename_orig_queue) }.to_bytes(),
)))
} else {
None
};
context
.mutator
.queue_new_entry(filename_new_queue, filename_orig_queue)
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_queue_new_entry", err),
Err(err) => panic_handler("afl_custom_queue_new_entry", &err),
}
}
@ -292,7 +289,7 @@ pub mod wrappers {
ManuallyDrop::into_inner(FFIContext::<M>::from(data));
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_deinit", err),
Err(err) => panic_handler("afl_custom_deinit", &err),
}
}
@ -306,13 +303,13 @@ pub mod wrappers {
buf.extend_from_slice(res.as_bytes());
buf.push(0);
// unwrapping here, as the error case should be extremely rare
CStr::from_bytes_with_nul(&buf).unwrap().as_ptr()
CStr::from_bytes_with_nul(buf).unwrap().as_ptr()
} else {
null()
}
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_introspection", err),
Err(err) => panic_handler("afl_custom_introspection", &err),
}
}
@ -329,18 +326,18 @@ pub mod wrappers {
buf.extend_from_slice(res.as_bytes());
buf.push(0);
// unwrapping here, as the error case should be extremely rare
CStr::from_bytes_with_nul(&buf).unwrap().as_ptr()
CStr::from_bytes_with_nul(buf).unwrap().as_ptr()
} else {
null()
}
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_describe", err),
Err(err) => panic_handler("afl_custom_describe", &err),
}
}
/// Internal function used in the macro
pub fn afl_custom_queue_get_<M: RawCustomMutator>(
pub unsafe fn afl_custom_queue_get_<M: RawCustomMutator>(
data: *mut c_void,
filename: *const c_char,
) -> u8 {
@ -348,12 +345,12 @@ pub mod wrappers {
let mut context = FFIContext::<M>::from(data);
assert!(!filename.is_null());
context.mutator.queue_get(Path::new(OsStr::from_bytes(
u8::from(context.mutator.queue_get(Path::new(OsStr::from_bytes(
unsafe { CStr::from_ptr(filename) }.to_bytes(),
))) as u8
))))
}) {
Ok(ret) => ret,
Err(err) => panic_handler("afl_custom_queue_get", err),
Err(err) => panic_handler("afl_custom_queue_get", &err),
}
}
}
@ -373,7 +370,7 @@ macro_rules! _define_afl_custom_init {
};
}
/// An exported macro to defined afl_custom_init meant for insternal usage
/// An exported macro to defined `afl_custom_init` meant for internal usage
#[cfg(not(feature = "afl_internals"))]
#[macro_export]
macro_rules! _define_afl_custom_init {
@ -444,7 +441,7 @@ macro_rules! export_mutator {
}
#[no_mangle]
pub extern "C" fn afl_custom_queue_new_entry(
pub unsafe extern "C" fn afl_custom_queue_new_entry(
data: *mut ::std::os::raw::c_void,
filename_new_queue: *const ::std::os::raw::c_char,
filename_orig_queue: *const ::std::os::raw::c_char,
@ -457,7 +454,7 @@ macro_rules! export_mutator {
}
#[no_mangle]
pub extern "C" fn afl_custom_queue_get(
pub unsafe extern "C" fn afl_custom_queue_get(
data: *mut ::std::os::raw::c_void,
filename: *const ::std::os::raw::c_char,
) -> u8 {
@ -520,9 +517,10 @@ mod sanity_test {
export_mutator!(ExampleMutator);
}
#[allow(unused_variables)]
/// A custom mutator.
/// [`CustomMutator::handle_error`] will be called in case any method returns an [`Result::Err`].
#[allow(unused_variables)]
#[allow(clippy::missing_errors_doc)]
pub trait CustomMutator {
/// The error type. All methods must return the same error type.
type Error: Debug;
@ -537,7 +535,7 @@ pub trait CustomMutator {
.map(|v| !v.is_empty())
.unwrap_or(false)
{
eprintln!("Error in custom mutator: {:?}", err)
eprintln!("Error in custom mutator: {err:?}");
}
}
@ -759,8 +757,7 @@ mod truncate_test {
let actual_output = truncate_str_unicode_safe(input, *max_len);
assert_eq!(
&actual_output, expected_output,
"{:#?} truncated to {} bytes should be {:#?}, but is {:#?}",
input, max_len, expected_output, actual_output
"{input:#?} truncated to {max_len} bytes should be {expected_output:#?}, but is {actual_output:#?}"
);
}
}

View File

@ -2,7 +2,7 @@
name = "example_mutator"
version = "0.1.0"
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
edition = "2018"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -2,7 +2,7 @@
name = "example_lain"
version = "0.1.0"
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
edition = "2018"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -3,15 +3,75 @@
This is the list of all noteworthy changes made in every public
release of the tool. See README.md for the general instruction manual.
### Version ++4.05a (dev)
### Version ++4.07a (dev)
- afl-fuzz:
- reverse reading the seeds only on restarts (increases performance)
- new env `AFL_POST_PROCESS_KEEP_ORIGINAL` to keep the orignal
data before post process on finds (for atnwalk custom mutator)
- new env `AFL_IGNORE_PROBLEMS_COVERAGE` to ignore coverage from
loaded libs after forkserver initialization (required by Mozilla)
- afl-cc:
- new env `AFL_LLVM_LTO_SKIPINIT` to support the AFL++ based WASM
(https://github.com/fgsect/WAFL) project
- afl-showmap:
- added custom mutator post_process and send support
- add `-I filelist` option, an alternative to `-i in_dir`
- afl-cmin + afl-cmin.bash:
- `-T threads` parallel task support, can be a huge speedup!
- a new grammar custom mutator atnwalk was submitted by @voidptr127 !
### Version ++4.06c (release)
- afl-fuzz:
- ensure temporary file descriptor is closed when not used
- added `AFL_NO_WARN_INSTABILITY`
- added time_wo_finds to fuzzer_stats
- fixed a crash in pizza (1st april easter egg) mode. Sorry for
everyone who was affected!
- allow pizza mode to be disabled when AFL_PIZZA_MODE is set to -1
- option `-p mmopt` now also selects new queue items more often
- fix bug in post_process custom mutator implementation
- print name of custom mutator in UI
- slight changes that improve fuzzer performance
- afl-cc:
- add CFI sanitizer variant to gcc targets
- llvm 16 + 17 support (thanks to @devnexen!)
- support llvm 15 native pcguard changes
- support for LLVMFuzzerTestOneInput -1 return
- LTO autoken and llvm_mode: added AFL_LLVM_DICT2FILE_NO_MAIN support
- qemu_mode:
- fix _RANGES envs to allow hyphens in the filenames
- basic riscv support
- frida_mode:
- added `AFL_FRIDA_STATS_INTERVAL`
- fix issue on MacOS
- unicorn_mode:
- updated and minor issues fixed
- nyx_mode support for all tools
- better sanitizer default options support for all tools
- new custom module: autotoken, a grammar free fuzzer for text inputs
- fixed custom mutator C examples
- more minor fixes and cross-platform support
### Version ++4.05c (release)
- MacOS: libdislocator, libtokencap etc. do not work with modern
MacOS anymore, but could be patched to work, see this issue if you
want to make the effort and send a PR:
https://github.com/AFLplusplus/AFLplusplus/issues/1594
- afl-fuzz:
- added afl_custom_fuzz_send custom mutator feature. Now your can
send fuzz data to the target as you need, e.g. via IPC.
- cmplog mode now has -l R option for random colorization, thanks
- cmplog mode now has a -l R option for random colorization, thanks
to guyf2010 for the PR!
- queue statistics are written every 30 minutes to
out/NAME/queue_data if compiled with INTROSPECTION
- new env: AFL_FORK_SERVER_KILL_SIGNAL
- afl-showmap/afl-cmin
- -t none now translates to -t 120000 (120 seconds)
- `-t none` now translates to `-t 120000` (120 seconds)
- unicorn_mode updated
- updated rust custom mutator dependencies and LibAFL custom mutator
- overall better sanitizer default setting handling
- several minor bugfixes
### Version ++4.04c (release)
- fix gramatron and grammar_mutator build scripts

View File

@ -229,7 +229,8 @@ If you find an interesting or important question missing, submit it via
If this is not a viable option, you can set `AFL_IGNORE_PROBLEMS=1` but then
the existing map will be used also for the newly loaded libraries, which
allows it to work, however, the efficiency of the fuzzing will be partially
degraded.
degraded. Note that there is additionally `AFL_IGNORE_PROBLEMS_COVERAGE` to
additionally tell AFL++ to ignore any coverage from the late loaded libaries.
</p></details>
<details>

View File

@ -483,6 +483,7 @@ directory. This includes:
- `fuzzer_pid` - PID of the fuzzer process
- `cycles_done` - queue cycles completed so far
- `cycles_wo_finds` - number of cycles without any new paths found
- `time_wo_finds` - longest time in seconds no new path was found
- `execs_done` - number of execve() calls attempted
- `execs_per_sec` - overall number of execs per second
- `corpus_count` - total number of entries in the queue

View File

@ -48,6 +48,7 @@ C/C++:
```c
void *afl_custom_init(afl_state_t *afl, unsigned int seed);
unsigned int afl_custom_fuzz_count(void *data, const unsigned char *buf, size_t buf_size);
void afl_custom_splice_optout(void *data);
size_t afl_custom_fuzz(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf, unsigned char *add_buf, size_t add_buf_size, size_t max_size);
const char *afl_custom_describe(void *data, size_t max_description_len);
size_t afl_custom_post_process(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf);
@ -72,6 +73,9 @@ def init(seed):
def fuzz_count(buf):
return cnt
def splice_optout()
pass
def fuzz(buf, add_buf, max_size):
return mutated_out
@ -114,7 +118,7 @@ def deinit(): # optional for Python
### Custom Mutation
- `init`:
- `init` (optional in Python):
This method is called when AFL++ starts up and is used to seed RNG and set
up buffers and state.
@ -132,6 +136,13 @@ def deinit(): # optional for Python
for a specific queue entry, use this function. This function is most useful
if `AFL_CUSTOM_MUTATOR_ONLY` is **not** used.
- `splice_optout` (optional):
If this function is present, no splicing target is passed to the `fuzz`
function. This saves time if splicing data is not needed by the custom
fuzzing function.
This function is never called, just needs to be present to activate.
- `fuzz` (optional):
This method performs custom mutations on a given input. It also accepts an
@ -139,6 +150,7 @@ def deinit(): # optional for Python
sense to use it. You would only skip this if `post_process` is used to fix
checksums etc. so if you are using it, e.g., as a post processing library.
Note that a length > 0 *must* be returned!
The returned output buffer is under **your** memory management!
- `describe` (optional):
@ -172,6 +184,11 @@ def deinit(): # optional for Python
to the target, e.g. if it is too short, too corrupted, etc. If so,
return a NULL buffer and zero length (or a 0 length string in Python).
NOTE: Do not make any random changes to the data in this function!
PERFORMANCE for C/C++: If possible make the changes in-place (so modify
the `*data` directly, and return it as `*outbuf = data`.
- `fuzz_send` (optional):
This method can be used if you want to send data to the target yourself,
@ -190,7 +207,7 @@ def deinit(): # optional for Python
discovered if compiled with INTROSPECTION. The custom mutator can then
return a string (const char *) that reports the exact mutations used.
- `deinit`:
- `deinit` (optional in Python):
The last method to be called, deinitializing the state.

View File

@ -129,6 +129,9 @@ subset of the settings discussed in section 1, with the exception of:
write all constant string comparisons to this file to be used later with
afl-fuzz' `-x` option.
- An option to `AFL_LLVM_DICT2FILE` is `AFL_LLVM_DICT2FILE_NO_MAIN=1` which
skill not parse `main()`.
- `TMPDIR` and `AFL_KEEP_ASSEMBLY`, since no temporary assembly files are
created.
@ -153,7 +156,7 @@ Available options:
- LTO - LTO instrumentation
- NATIVE - clang's original pcguard based instrumentation
- NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16)
- PCGUARD - our own pcgard based instrumentation (default)
- PCGUARD - our own pcguard based instrumentation (default)
#### CMPLOG
@ -237,7 +240,9 @@ combined.
the default `0x10000`. A value of 0 or empty sets the map address to be
dynamic (the original AFL way, which is slower).
- `AFL_LLVM_MAP_DYNAMIC` sets the shared memory address to be dynamic.
- `AFL_LLVM_LTO_SKIPINIT` skips adding initialization code. Some global vars
(e.g. the highest location ID) are not injected. Needed to instrument with
[WAFL](https://github.com/fgsect/WAFL.git).
For more information, see
[instrumentation/README.lto.md](../instrumentation/README.lto.md).
@ -354,6 +359,9 @@ checks or alter some of the more exotic semantics of the tool:
- Setting `AFL_KEEP_TIMEOUTS` will keep longer running inputs if they reach
new coverage
- On the contrary, if you are not interested in any timeouts, you can set
`AFL_IGNORE_TIMEOUTS` to get a bit of speed instead.
- `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behavior which
does not allow crashes or timeout seeds in the initial -i corpus.
@ -378,10 +386,10 @@ checks or alter some of the more exotic semantics of the tool:
valid terminal was detected (for virtual consoles).
- Setting `AFL_FORKSRV_INIT_TMOUT` allows you to specify a different timeout
to wait for the forkserver to spin up. The default is the `-t` value times
`FORK_WAIT_MULT` from `config.h` (usually 10), so for a `-t 100`, the
default would wait for `1000` milliseconds. Setting a different time here is
useful if the target has a very slow startup time, for example, when doing
to wait for the forkserver to spin up. The specified value is the new timeout, in milliseconds.
The default is the `-t` value times `FORK_WAIT_MULT` from `config.h` (usually 10), so for a `-t 100`, the default would wait for `1000` milliseconds.
The `AFL_FORKSRV_INIT_TMOUT` value does not get multiplied. It overwrites the initial timeout afl-fuzz waits for the target to come up with a constant time.
Setting a different time here is useful if the target has a very slow startup time, for example, when doing
full-system fuzzing or emulation, but you don't want the actual runs to wait
too long for timeouts.
@ -398,7 +406,8 @@ checks or alter some of the more exotic semantics of the tool:
- If afl-fuzz encounters an incorrect fuzzing setup during a fuzzing session
(not at startup), it will terminate. If you do not want this, then you can
set `AFL_IGNORE_PROBLEMS`.
set `AFL_IGNORE_PROBLEMS`. If you additionally want to also ignore coverage
from late loaded libraries, you can set `AFL_IGNORE_PROBLEMS_COVERAGE`.
- When running in the `-M` or `-S` mode, setting `AFL_IMPORT_FIRST` causes the
fuzzer to import test cases from other instances before doing anything else.
@ -474,7 +483,10 @@ checks or alter some of the more exotic semantics of the tool:
output from afl-fuzz is redirected to a file or to a pipe.
- Setting `AFL_NO_STARTUP_CALIBRATION` will skip the initial calibration
of all starting seeds, and start fuzzing at once.
of all starting seeds, and start fuzzing at once. Use with care, this
degrades the fuzzing performance!
- Setting `AFL_NO_WARN_INSTABILITY` will suppress instability warnings.
- In QEMU mode (-Q) and FRIDA mode (-O), `AFL_PATH` will be searched for
afl-qemu-trace and afl-frida-trace.so.
@ -572,9 +584,15 @@ checks or alter some of the more exotic semantics of the tool:
constructors in your target, you can set `AFL_EARLY_FORKSERVER`.
Note that this is not a compile time option but a runtime option :-)
- Set `AFL_PIZZA_MODE` to 1 to enable the April 1st stats menu, set to 0
- Set `AFL_PIZZA_MODE` to 1 to enable the April 1st stats menu, set to -1
to disable although it is 1st of April.
- If you need a specific interval to update fuzzer_stats file, you can
set `AFL_FUZZER_STATS_UPDATE_INTERVAL` to the interval in seconds you'd
the file to be updated.
Note that will not be exact and with slow targets it can take seconds
until there is a slice for the time test.
## 5) Settings for afl-qemu-trace
The QEMU wrapper used to instrument binary-only code supports several settings:
@ -662,6 +680,8 @@ support.
* `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled
code. Code is considered to be JIT if the executable segment is not backed by
a file.
* `AFL_FRIDA_INST_NO_DYNAMIC_LOAD` - Don't instrument the code loaded late at
runtime. Strictly limits instrumentation to what has been included.
* `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage
instrumentation (the default where available). Required to use
`AFL_FRIDA_INST_TRACE`.

View File

@ -201,10 +201,10 @@ afl-clang-fast's.
### RetroWrite
RetroWrite is a static binary rewriter that can be combined with AFL++. If you
have an x86_64 binary that still has its symbols (i.e., not stripped binary), is
compiled with position independent code (PIC/PIE), and does not contain C++
exceptions, then the RetroWrite solution might be for you. It decompiles to ASM
files which can then be instrumented with afl-gcc.
have an x86_64 or arm64 binary that does not contain C++ exceptions and - if
x86_64 - still has it's symbols and compiled with position independent code
(PIC/PIE), then the RetroWrite solution might be for you.
It decompiles to ASM files which can then be instrumented with afl-gcc.
Binaries that are statically instrumented for fuzzing using RetroWrite are close
in performance to compiler-instrumented binaries and outperform the QEMU-based

View File

@ -534,6 +534,8 @@ dictionaries/FORMAT.dict`.
* With `afl-clang-fast`, you can set
`AFL_LLVM_DICT2FILE=/full/path/to/new/file.dic` to automatically generate a
dictionary during target compilation.
Adding `AFL_LLVM_DICT2FILE_NO_MAIN=1` to not parse main (usually command line
parameter parsing) is often a good idea too.
* You also have the option to generate a dictionary yourself during an
independent run of the target, see
[utils/libtokencap/README.md](../utils/libtokencap/README.md).
@ -628,7 +630,8 @@ If you have a large corpus, a corpus from a previous run or are fuzzing in a CI,
then also set `export AFL_CMPLOG_ONLY_NEW=1` and `export AFL_FAST_CAL=1`.
If the queue in the CI is huge and/or the execution time is slow then you can
also add `AFL_NO_STARTUP_CALIBRATION=1` to skip the initial queue calibration
phase and start fuzzing at once.
phase and start fuzzing at once - but only do this if the calibration phase
would be too long for your fuzz run time.
You can also use different fuzzers. If you are using AFL spinoffs or AFL
conforming fuzzers, then just use the same -o directory and give it a unique
@ -900,6 +903,13 @@ then color-codes the input based on which sections appear to be critical and
which are not; while not bulletproof, it can often offer quick insights into
complex file formats.
`casr-afl` from [CASR](https://github.com/ispras/casr) tools provides
comfortable triaging for crashes found by AFL++. Reports are clustered and
contain severity and other information.
```shell
casr-afl -i /path/to/afl/out/dir -o /path/to/casr/out/dir
```
## 5. CI fuzzing
Some notes on continuous integration (CI) fuzzing - this fuzzing is different to
@ -907,7 +917,8 @@ normal fuzzing campaigns as these are much shorter runnings.
If the queue in the CI is huge and/or the execution time is slow then you can
also add `AFL_NO_STARTUP_CALIBRATION=1` to skip the initial queue calibration
phase and start fuzzing at once.
phase and start fuzzing at once. But only do that if the calibration time is
too long for your overall available fuzz run time.
1. Always:
* LTO has a much longer compile time which is diametrical to short fuzzing -
@ -928,7 +939,7 @@ phase and start fuzzing at once.
3. Also randomize the afl-fuzz runtime options, e.g.:
* 65% for `AFL_DISABLE_TRIM`
* 50% for `AFL_KEEP_TIMEOUTS`
* 50% use a dictionary generated by `AFL_LLVM_DICT2FILE`
* 50% use a dictionary generated by `AFL_LLVM_DICT2FILE` + `AFL_LLVM_DICT2FILE_NO_MAIN=1`
* 40% use MOpt (`-L 0`)
* 40% for `AFL_EXPAND_HAVOC_NOW`
* 20% for old queue processing (`-Z`)

View File

@ -3,6 +3,8 @@
In the following, we describe a variety of ideas that could be implemented for
future AFL++ versions.
**NOTE:** Our GSoC participation is concerning [libafl](https://github.com/AFLplusplus/libafl), not AFL++.
## Analysis software
Currently analysis is done by using afl-plot, which is rather outdated. A GTK or
@ -16,17 +18,6 @@ and Y axis, zoom factor, log scaling on-off, etc.
Mentor: vanhauser-thc
## WASM Instrumentation
Currently, AFL++ can be used for source code fuzzing and traditional binaries.
With the rise of WASM as a compile target, however, a novel way of
instrumentation needs to be implemented for binaries compiled to Webassembly.
This can either be done by inserting instrumentation directly into the WASM AST,
or by patching feedback into a WASM VM of choice, similar to the current Unicorn
instrumentation.
Mentor: any
## Support other programming languages
Other programming languages also use llvm hence they could be (easily?)

View File

@ -1,5 +1,10 @@
# Tools that help fuzzing with AFL++
## AFL++ and other development languages
* [afl-rs](https://github.com/rust-fuzz/afl.rs) - AFL++ for RUST
* [WASM](https://github.com/fgsect/WAFL) - AFL++ for WASM
## Speeding up fuzzing
* [libfiowrapper](https://github.com/marekzmyslowski/libfiowrapper) - if the
@ -62,3 +67,5 @@
generates builds of debian packages suitable for AFL.
* [afl-fid](https://github.com/FoRTE-Research/afl-fid) - a set of tools for
working with input data.
* [CASR](https://github.com/ispras/casr) - a set of tools for crash triage and
analysis.

View File

@ -54,4 +54,5 @@
"__sanitizer_cov_trace_pc_guard";
"__sanitizer_cov_trace_pc_guard_init";
"__sanitizer_cov_trace_switch";
"LLVMFuzzerTestOneInput";
};

View File

@ -1,3 +1,4 @@
PWD:=$(shell pwd)/
ROOT:=$(PWD)../
INC_DIR:=$(PWD)include/
@ -98,6 +99,25 @@ ifeq "$(shell uname)" "Darwin"
OS:=macos
AFL_CFLAGS:=$(AFL_CFLAGS) -Wno-deprecated-declarations
GUM_ARCH:=""
ifeq "$(ARCH)" "arm64"
TARGET_CC= \
"clang" \
"-target" \
"arm64-apple-macos10.9"
TARGET_CXX= \
"clang++" \
"-target" \
"arm64-apple-macos10.9"
else
TARGET_CC= \
"clang" \
"-target" \
"x86_64-apple-macos10.9"
TARGET_CXX= \
"clang++" \
"-target" \
"x86_64-apple-macos10.9"
endif
else
ifdef DEBUG
AFL_CFLAGS:=$(AFL_CFLAGS) -Wno-prio-ctor-dtor
@ -145,7 +165,7 @@ ifndef OS
$(error "Operating system unsupported")
endif
GUM_DEVKIT_VERSION=16.0.1
GUM_DEVKIT_VERSION=16.0.11
GUM_DEVKIT_FILENAME=frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz
GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)"
@ -191,6 +211,9 @@ all: $(FRIDA_TRACE) $(FRIDA_TRACE_LIB) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QE
32:
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
arm:
CFLAGS="-marm" LDFLAGS="-marm" ARCH="armhf" TARGET_CC=arm-linux-gnueabihf-gcc TARGET_CXX=arm-linux-gnueabihf-g++ make all
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)

View File

@ -178,11 +178,13 @@ Default is 256Mb.
* `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled
code. Code is considered to be JIT if the executable segment is not backed by
a file.
* `AFL_FRIDA_INST_NO_DYNAMIC_LOAD` - Don't instrument the code loaded late at
runtime. Strictly limits instrumentation to what has been included.
* `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage
instrumentation (the default where available). Required to use
`AFL_FRIDA_INST_TRACE`.
* `AFL_FRIDA_INST_REGS_FILE` - File to write raw register contents at the start
of each block.
`AFL_FRIDA_INST_TRACE`.
* `AFL_FRIDA_INST_NO_CACHE` - Don't use a look-up table to cache real to
instrumented address block translations.
* `AFL_FRIDA_INST_NO_PREFETCH` - Disable prefetching. By default, the child will
@ -193,6 +195,13 @@ instrumented address block translations.
backpatching information. By default, the child will report applied
backpatches to the parent so that they can be applied and then be inherited by
the next child on fork.
* `AFL_FRIDA_INST_NO_SUPPRESS` - Disable deterministic branch suppression.
Deterministic branch suppression skips the preamble which generates coverage
information at the start of each block, if the block is reached by a
deterministic branch. This reduces map polution, and may improve performance
when all the executing blocks have been prefetched and backpatching applied.
However, in the event that backpatching is incomplete, this may incur a
performance penatly as branch instructions are disassembled on each branch.
* `AFL_FRIDA_INST_SEED` - Sets the initial seed for the hash function used to
generate block (and hence edge) IDs. Setting this to a constant value may be
useful for debugging purposes, e.g., investigating unstable edges.

View File

@ -390,7 +390,7 @@ Consider the [following](test/js/test2.c) test code...
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
@ -844,6 +844,12 @@ class Afl {
static setInstrumentLibraries() {
Afl.jsApiSetInstrumentLibraries();
}
/**
* See `AFL_FRIDA_INST_NO_DYNAMIC_LOAD`
*/
static setInstrumentNoDynamicLoad() {
Afl.jsApiSetInstrumentNoDynamicLoad();
}
/**
* See `AFL_FRIDA_INST_NO_OPTIMIZE`
*/

View File

@ -19,9 +19,11 @@
js_api_set_instrument_jit;
js_api_set_instrument_libraries;
js_api_set_instrument_instructions;
js_api_set_instrument_no_dynamic_load;
js_api_set_instrument_no_optimize;
js_api_set_instrument_regs_file;
js_api_set_instrument_seed;
js_api_set_instrument_suppress_disable;
js_api_set_instrument_trace;
js_api_set_instrument_trace_unique;
js_api_set_instrument_unstable_coverage_file;

View File

@ -15,6 +15,7 @@ extern guint64 instrument_hash_zero;
extern char *instrument_coverage_unstable_filename;
extern gboolean instrument_coverage_insn;
extern char *instrument_regs_filename;
extern gboolean instrument_suppress;
extern gboolean instrument_use_fixed_seed;
extern guint64 instrument_fixed_seed;

View File

@ -6,6 +6,7 @@
extern gboolean ranges_debug_maps;
extern gboolean ranges_inst_libs;
extern gboolean ranges_inst_jit;
extern gboolean ranges_inst_dynamic_load;
void ranges_config(void);
void ranges_init(void);

View File

@ -204,10 +204,7 @@ static void cmplog_handle_cmp_sub(GumCpuContext *context, gsize operand1,
gsize address = context->pc;
register uintptr_t k = (uintptr_t)address;
k = (k >> 4) ^ (k << 8);
k &= CMP_MAP_W - 1;
register uintptr_t k = instrument_get_offset_hash(GUM_ADDRESS(address));
if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS)
__afl_cmp_map->headers[k].hits = 0;

View File

@ -188,10 +188,7 @@ static void cmplog_handle_cmp_sub(GumCpuContext *context, gsize operand1,
gsize address = ctx_read_reg(context, X86_REG_RIP);
register uintptr_t k = (uintptr_t)address;
k = (k >> 4) ^ (k << 8);
k &= CMP_MAP_W - 7;
register uintptr_t k = instrument_get_offset_hash(GUM_ADDRESS(address));
if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS)
__afl_cmp_map->headers[k].hits = 0;

View File

@ -193,10 +193,7 @@ static void cmplog_handle_cmp_sub(GumCpuContext *context, gsize operand1,
gsize address = ctx_read_reg(context, X86_REG_EIP);
register uintptr_t k = (uintptr_t)address;
k = (k >> 4) ^ (k << 8);
k &= CMP_MAP_W - 1;
register uintptr_t k = instrument_get_offset_hash(GUM_ADDRESS(address));
if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS)
__afl_cmp_map->headers[k].hits = 0;

View File

@ -27,6 +27,7 @@ gboolean instrument_optimize = false;
gboolean instrument_unique = false;
guint64 instrument_hash_zero = 0;
guint64 instrument_hash_seed = 0;
gboolean instrument_suppress = false;
gboolean instrument_use_fixed_seed = FALSE;
guint64 instrument_fixed_seed = 0;
@ -290,6 +291,7 @@ void instrument_config(void) {
(getenv("AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE"));
instrument_coverage_insn = (getenv("AFL_FRIDA_INST_INSN") != NULL);
instrument_regs_filename = getenv("AFL_FRIDA_INST_REGS_FILE");
instrument_suppress = (getenv("AFL_FRIDA_INST_NO_SUPPRESS") == NULL);
instrument_debug_config();
instrument_coverage_config();
@ -321,6 +323,9 @@ void instrument_init(void) {
FOKF(cBLU "Instrumentation" cRST " - " cGRN "instructions:" cYEL " [%c]",
instrument_coverage_insn ? 'X' : ' ');
FOKF(cBLU "Instrumentation" cRST " - " cGRN "suppression:" cYEL " [%c]",
instrument_suppress ? 'X' : ' ');
if (instrument_tracing && instrument_optimize) {
WARNF("AFL_FRIDA_INST_TRACE implies AFL_FRIDA_INST_NO_OPTIMIZE");

View File

@ -273,7 +273,19 @@ void instrument_flush(GumStalkerOutput *output) {
gpointer instrument_cur(GumStalkerOutput *output) {
return gum_arm_writer_cur(output->writer.arm);
gpointer curr = NULL;
if (output->encoding == GUM_INSTRUCTION_SPECIAL) {
curr = gum_thumb_writer_cur(output->writer.thumb);
} else {
curr = gum_arm_writer_cur(output->writer.arm);
}
return curr;
}

View File

@ -196,6 +196,14 @@ static void instrument_coverage_switch(GumStalkerObserver *self,
insn = instrument_disassemble(from_insn);
deterministic = instrument_is_deterministic(insn);
cs_free(insn, 1);
/*
* If the branch is deterministic, then we should start execution at the
* begining of the block. From here, we will branch and skip the coverage
* code and jump right to the target code of the instrumented block.
* Otherwise, if the branch is non-deterministic, then we need to branch
* part way into the block to where the coverage instrumentation starts.
*/
if (deterministic) { return; }
/*
@ -305,7 +313,7 @@ void instrument_coverage_optimize(const cs_insn *instr,
// gum_arm64_writer_put_brk_imm(cw, 0x0);
instrument_coverage_suppress_init();
if (instrument_suppress) { instrument_coverage_suppress_init(); }
code_addr = cw->pc;
@ -325,12 +333,16 @@ void instrument_coverage_optimize(const cs_insn *instr,
block_start =
GSIZE_TO_POINTER(GUM_ADDRESS(cw->code) - GUM_RESTORATION_PROLOG_SIZE);
if (instrument_suppress) {
if (!g_hash_table_add(coverage_blocks, block_start)) {
FATAL("Failed - g_hash_table_add");
}
}
code.code = template;
/*
@ -363,8 +375,18 @@ void instrument_coverage_optimize(const cs_insn *instr,
code.code.mov_x1_curr_loc_shr_1 |= (area_offset_ror << 5);
if (instrument_suppress) {
gum_arm64_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
} else {
size_t offset = offsetof(afl_log_code, code.stp_x0_x1);
gum_arm64_writer_put_bytes(cw, &code.bytes[offset],
sizeof(afl_log_code) - offset);
}
}
void instrument_coverage_optimize_insn(const cs_insn *instr,

View File

@ -380,6 +380,8 @@ void instrument_coverage_optimize(const cs_insn *instr,
}
if (instrument_suppress) {
instrument_coverage_suppress_init();
if (!g_hash_table_add(coverage_blocks, GSIZE_TO_POINTER(cw->code))) {
@ -388,6 +390,8 @@ void instrument_coverage_optimize(const cs_insn *instr,
}
}
instrument_coverage_write(GUM_ADDRESS(instr->address), output);
}

View File

@ -203,6 +203,8 @@ void instrument_coverage_optimize(const cs_insn *instr,
code.code = template;
if (instrument_suppress) {
instrument_coverage_suppress_init();
// gum_x86_writer_put_breakpoint(cw);
@ -213,6 +215,8 @@ void instrument_coverage_optimize(const cs_insn *instr,
}
}
gssize prev_loc_value_offset2 =
offsetof(afl_log_code, code.mov_eax_prev_loc) +
sizeof(code.code.mov_eax_prev_loc) - sizeof(gint);

View File

@ -150,6 +150,12 @@ class Afl {
static setInstrumentLibraries() {
Afl.jsApiSetInstrumentLibraries();
}
/**
* See `AFL_FRIDA_INST_NO_DYNAMIC_LOAD`
*/
static setInstrumentNoDynamicLoad() {
Afl.jsApiSetInstrumentNoDynamicLoad();
}
/**
* See `AFL_FRIDA_INST_NO_OPTIMIZE`
*/
@ -170,6 +176,12 @@ class Afl {
static setInstrumentSeed(seed) {
Afl.jsApiSetInstrumentSeed(seed);
}
/*
* See `AFL_FRIDA_INST_NO_SUPPRESS`
*/
static setInstrumentSuppressDisable() {
Afl.jsApiSetInstrumentSuppressDisable();
}
/**
* See `AFL_FRIDA_INST_TRACE_UNIQUE`.
*/
@ -336,9 +348,11 @@ Afl.jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction("js_api_set_instrument_de
Afl.jsApiSetInstrumentInstructions = Afl.jsApiGetFunction("js_api_set_instrument_instructions", "void", []);
Afl.jsApiSetInstrumentJit = Afl.jsApiGetFunction("js_api_set_instrument_jit", "void", []);
Afl.jsApiSetInstrumentLibraries = Afl.jsApiGetFunction("js_api_set_instrument_libraries", "void", []);
Afl.jsApiSetInstrumentNoDynamicLoad = Afl.jsApiGetFunction("js_api_set_instrument_no_dynamic_load", "void", []);
Afl.jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction("js_api_set_instrument_no_optimize", "void", []);
Afl.jsApiSetInstrumentRegsFile = Afl.jsApiGetFunction("js_api_set_instrument_regs_file", "void", ["pointer"]);
Afl.jsApiSetInstrumentSeed = Afl.jsApiGetFunction("js_api_set_instrument_seed", "void", ["uint64"]);
Afl.jsApiSetInstrumentSuppressDisable = Afl.jsApiGetFunction("js_api_set_instrument_suppress_disable", "void", []);
Afl.jsApiSetInstrumentTrace = Afl.jsApiGetFunction("js_api_set_instrument_trace", "void", []);
Afl.jsApiSetInstrumentTraceUnique = Afl.jsApiGetFunction("js_api_set_instrument_trace_unique", "void", []);
Afl.jsApiSetInstrumentUnstableCoverageFile = Afl.jsApiGetFunction("js_api_set_instrument_unstable_coverage_file", "void", ["pointer"]);

View File

@ -156,6 +156,13 @@ __attribute__((visibility("default"))) void js_api_set_instrument_instructions(
}
__attribute__((visibility("default"))) void
js_api_set_instrument_no_dynamic_load(void) {
ranges_inst_dynamic_load = FALSE;
}
__attribute__((visibility("default"))) void js_api_set_instrument_no_optimize(
void) {
@ -289,6 +296,13 @@ __attribute__((visibility("default"))) void js_api_set_instrument_cache_size(
}
__attribute__((visibility("default"))) void
js_api_set_instrument_suppress_disable(void) {
instrument_suppress = false;
}
__attribute__((visibility("default"))) void js_api_set_js_main_hook(
const js_main_hook_t hook) {

View File

@ -18,6 +18,7 @@ typedef struct {
gboolean ranges_debug_maps = FALSE;
gboolean ranges_inst_libs = FALSE;
gboolean ranges_inst_jit = FALSE;
gboolean ranges_inst_dynamic_load = TRUE;
static GArray *module_ranges = NULL;
static GArray *libs_ranges = NULL;
@ -25,6 +26,7 @@ static GArray *jit_ranges = NULL;
static GArray *include_ranges = NULL;
static GArray *exclude_ranges = NULL;
static GArray *ranges = NULL;
static GArray *whole_memory_ranges = NULL;
static void convert_address_token(gchar *token, GumMemoryRange *range) {
@ -387,6 +389,21 @@ static GArray *collect_jit_ranges(void) {
}
static GArray *collect_whole_mem_ranges(void) {
GArray *result;
GumMemoryRange range;
result = g_array_new(false, false, sizeof(GumMemoryRange));
range.base_address = 0;
range.size = G_MAXULONG;
g_array_append_val(result, range);
return result;
}
static gboolean intersect_range(GumMemoryRange *rr, GumMemoryRange *ra,
GumMemoryRange *rb) {
@ -574,11 +591,17 @@ void ranges_config(void) {
if (getenv("AFL_FRIDA_DEBUG_MAPS") != NULL) { ranges_debug_maps = TRUE; }
if (getenv("AFL_INST_LIBS") != NULL) { ranges_inst_libs = TRUE; }
if (getenv("AFL_FRIDA_INST_JIT") != NULL) { ranges_inst_jit = TRUE; }
if (getenv("AFL_FRIDA_INST_NO_DYNAMIC_LOAD") != NULL) {
ranges_inst_dynamic_load = FALSE;
}
if (ranges_debug_maps) { ranges_print_debug_maps(); }
include_ranges = collect_ranges("AFL_FRIDA_INST_RANGES");
exclude_ranges = collect_ranges("AFL_FRIDA_EXCLUDE_RANGES");
whole_memory_ranges = collect_whole_mem_ranges();
}
@ -628,10 +651,20 @@ void ranges_init(void) {
print_ranges("step4", step4);
/*
* After step4, we have the total ranges to be instrumented, we now subtract
* that from the original ranges of the modules to configure stalker.
* After step 4 we have the total ranges to be instrumented, we now subtract
* that either from the original ranges of the modules or from the whole
* memory if AFL_INST_NO_DYNAMIC_LOAD to configure the stalker.
*/
if (ranges_inst_dynamic_load) {
step5 = subtract_ranges(module_ranges, step4);
} else {
step5 = subtract_ranges(whole_memory_ranges, step4);
}
print_ranges("step5", step5);
ranges = merge_ranges(step5);

View File

@ -2,8 +2,9 @@ PWD:=$(shell pwd)/
ROOT:=$(PWD)../../../
BUILD_DIR:=$(PWD)build/
TEST_CMPLOG_BASENAME=compcovtest
TEST_CMPLOG_SRC=$(PWD)cmplog.c
TEST_CMPLOG_OBJ=$(BUILD_DIR)compcovtest
TEST_CMPLOG_OBJ=$(BUILD_DIR)$(TEST_CMPLOG_BASENAME)
TEST_BIN:=$(PWD)../../build/test
@ -13,7 +14,7 @@ CMP_LOG_INPUT:=$(TEST_DATA_DIR)in
QEMU_OUT:=$(BUILD_DIR)qemu-out
FRIDA_OUT:=$(BUILD_DIR)frida-out
.PHONY: all 32 clean qemu frida frida-nocmplog format
.PHONY: all 32 clean qemu frida frida-nocmplog frida-unprefixedpath format
all: $(TEST_CMPLOG_OBJ)
make -C $(ROOT)frida_mode/
@ -64,6 +65,18 @@ frida-nocmplog: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT)
-- \
$(TEST_CMPLOG_OBJ) @@
frida-unprefixedpath: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT)
PATH=$(BUILD_DIR) $(ROOT)afl-fuzz \
-O \
-i $(TEST_DATA_DIR) \
-o $(FRIDA_OUT) \
-c 0 \
-l 3AT \
-Z \
-- \
$(TEST_CMPLOG_BASENAME) @@
debug: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT)
gdb \
--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \

View File

@ -19,6 +19,9 @@ frida:
frida-nocmplog:
@gmake frida-nocmplog
frida-unprefixedpath:
@gmake frida-unprefixedpath
format:
@gmake format

View File

@ -2,7 +2,7 @@
//
// Author: Mateusz Jurczyk (mjurczyk@google.com)
//
// Copyright 2019-2022 Google LLC
// Copyright 2019-2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -3,7 +3,7 @@
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:

View File

@ -3,7 +3,7 @@
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:

View File

@ -3,7 +3,7 @@
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:

View File

@ -3,7 +3,7 @@
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:

View File

@ -3,7 +3,7 @@
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:

View File

@ -3,7 +3,7 @@
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:

View File

@ -3,7 +3,7 @@
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:

View File

@ -3,7 +3,7 @@
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:

View File

@ -3,7 +3,7 @@
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:

View File

@ -7,10 +7,10 @@ LIBPNG_BUILD_DIR:=$(BUILD_DIR)libpng/
HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/
PNGTEST_BUILD_DIR:=$(BUILD_DIR)pngtest/
LIBZ_FILE:=$(LIBZ_BUILD_DIR)zlib-1.2.12.tar.gz
LIBZ_URL:=http://www.zlib.net/zlib-1.2.12.tar.gz
LIBZ_DIR:=$(LIBZ_BUILD_DIR)zlib-1.2.12/
LIBZ_PC:=$(ZLIB_DIR)zlib.pc
LIBZ_FILE:=$(LIBZ_BUILD_DIR)zlib-1.2.13.tar.gz
LIBZ_URL:=http://www.zlib.net/zlib-1.2.13.tar.gz
LIBZ_DIR:=$(LIBZ_BUILD_DIR)zlib-1.2.13/
LIBZ_PC:=$(LIBZ_DIR)zlib.pc
LIBZ_LIB:=$(LIBZ_DIR)libz.a
LIBPNG_FILE:=$(LIBPNG_BUILD_DIR)libpng-1.2.56.tar.gz
@ -25,7 +25,7 @@ HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-
PNGTEST_FILE:=$(PNGTEST_BUILD_DIR)target.cc
PNGTEST_OBJ:=$(PNGTEST_BUILD_DIR)target.o
PNGTEST_URL:="https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/libpng-1.2.56/target.cc"
PNGTEST_URL:="https://raw.githubusercontent.com/google/fuzzbench/e0c4a994b6999bae46e8dec5bcea9a73251b8dba/benchmarks/libpng-1.2.56/target.cc"
TEST_BIN:=$(BUILD_DIR)test
ifeq "$(shell uname)" "Darwin"
@ -48,7 +48,7 @@ all: $(TEST_BIN)
CFLAGS="-m32" LDFLAGS="-m32" make $(TEST_BIN)
arm:
ARCH="arm" CC="arm-linux-gnueabihf-gcc" CXX="arm-linux-gnueabihf-g++" make $(TEST_BIN)
CFLAGS="-marm" LDFLAGS="-marm" CC="arm-linux-gnueabihf-gcc" CXX="arm-linux-gnueabihf-g++" make $(TEST_BIN)
$(BUILD_DIR):
mkdir -p $@
@ -96,7 +96,7 @@ $(LIBZ_PC): | $(LIBZ_DIR)
--static \
--archs="$(ARCH)"
$(LIBZ_LIB): $(LIBZ_PC)
$(LIBZ_LIB): | $(LIBZ_PC)
CFLAGS="$(CFLAGS) -fPIC" \
make \
-C $(LIBZ_DIR) \
@ -133,7 +133,7 @@ png: $(LIBPNG_LIB)
######### TEST ########
$(TEST_BIN): $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB)
$(TEST_BIN): $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) $(LIBZ_LIB)
$(CXX) \
$(CFLAGS) \
$(LDFLAGS) \

View File

@ -18,6 +18,9 @@ all: $(TESTINSTBIN)
32:
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
arm:
CFLAGS="-marm" LDFLAGS="-marm" CC="arm-linux-gnueabihf-gcc" CXX="arm-linux-gnueabihf-g++" make $(TESTINSTBIN)
$(BUILD_DIR):
mkdir -p $@

View File

@ -3,7 +3,7 @@
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:

View File

@ -3,7 +3,7 @@
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:

View File

@ -178,6 +178,13 @@ class Afl {
Afl.jsApiSetInstrumentLibraries();
}
/**
* See `AFL_FRIDA_INST_NO_DYNAMIC_LOAD`
*/
public static setInstrumentNoDynamicLoad(): void {
Afl.jsApiSetInstrumentNoDynamicLoad();
}
/**
* See `AFL_FRIDA_INST_NO_OPTIMIZE`
*/
@ -201,6 +208,13 @@ class Afl {
Afl.jsApiSetInstrumentSeed(seed);
}
/*
* See `AFL_FRIDA_INST_NO_SUPPRESS`
*/
public static setInstrumentSuppressDisable(): void{
Afl.jsApiSetInstrumentSuppressDisable();
}
/**
* See `AFL_FRIDA_INST_TRACE_UNIQUE`.
*/
@ -436,6 +450,11 @@ class Afl {
"void",
[]);
private static readonly jsApiSetInstrumentNoDynamicLoad = Afl.jsApiGetFunction(
"js_api_set_instrument_no_dynamic_load",
"void",
[]);
private static readonly jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction(
"js_api_set_instrument_no_optimize",
"void",
@ -451,6 +470,11 @@ class Afl {
"void",
["uint64"]);
private static readonly jsApiSetInstrumentSuppressDisable = Afl.jsApiGetFunction(
"js_api_set_instrument_suppress_disable",
"void",
[]);
private static readonly jsApiSetInstrumentTrace = Afl.jsApiGetFunction(
"js_api_set_instrument_trace",
"void",

View File

@ -1,11 +1,433 @@
{
"requires": true,
"name": "@worksbutnottested/aflplusplus-frida",
"version": "1.0.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"tsc": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/tsc/-/tsc-2.0.3.tgz",
"integrity": "sha512-SN+9zBUtrpUcOpaUO7GjkEHgWtf22c7FKbKCA4e858eEM7Qz86rRDpgOU2lBIDf0fLCsEg65ms899UMUIB2+Ow==",
"@babel/code-frame": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
"integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
"dev": true,
"requires": {
"@babel/highlight": "^7.18.6"
}
},
"@babel/helper-validator-identifier": {
"version": "7.19.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
"dev": true
},
"@babel/highlight": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
"integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.18.6",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
}
},
"@types/frida-gum": {
"version": "16.5.1",
"resolved": "https://registry.npmjs.org/@types/frida-gum/-/frida-gum-16.5.1.tgz",
"integrity": "sha512-t+2HZG6iBO2cEKtb2KvtP33m/7TGmzSd42YqznToA34+TkS97NttsFZ9OY2s0hPyDQOg+hZTjR1QggRkEL/Ovg=="
},
"@types/node": {
"version": "14.18.36",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.36.tgz",
"integrity": "sha512-FXKWbsJ6a1hIrRxv+FoukuHnGTgEzKYGi7kilfMae96AL9UNkPFNWJEEYWzdRI9ooIkbr4AKldyuSTLql06vLQ==",
"dev": true
},
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
},
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true,
"requires": {
"sprintf-js": "~1.0.2"
}
},
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"builtin-modules": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
"integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==",
"dev": true
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"dev": true
},
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
},
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
"dev": true
},
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"get-caller-file": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
"integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
"dev": true
},
"glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
"requires": {
"function-bind": "^1.1.1"
}
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dev": true,
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"is-core-module": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
"integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true
},
"js-yaml": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"dev": true,
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
}
},
"minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
"integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
"dev": true
},
"mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
"dev": true,
"requires": {
"minimist": "^1.2.6"
}
},
"mock-require": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/mock-require/-/mock-require-3.0.3.tgz",
"integrity": "sha512-lLzfLHcyc10MKQnNUCv7dMcoY/2Qxd6wJfbqCcVk3LDb8An4hF6ohk5AztrvgKhJCqj36uyzi/p5se+tvyD+Wg==",
"dev": true,
"requires": {
"get-caller-file": "^1.0.2",
"normalize-path": "^2.1.1"
}
},
"normalize-path": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
"integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
"dev": true,
"requires": {
"remove-trailing-separator": "^1.0.1"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true,
"requires": {
"wrappy": "1"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true
},
"path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"remove-trailing-separator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
"integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==",
"dev": true
},
"resolve": {
"version": "1.22.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
"integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
"dev": true,
"requires": {
"is-core-module": "^2.9.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
}
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true
},
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
"dev": true
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
},
"supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true
},
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
"tslint": {
"version": "6.1.3",
"resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz",
"integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
"builtin-modules": "^1.1.1",
"chalk": "^2.3.0",
"commander": "^2.12.1",
"diff": "^4.0.1",
"glob": "^7.1.1",
"js-yaml": "^3.13.1",
"minimatch": "^3.0.4",
"mkdirp": "^0.5.3",
"resolve": "^1.3.2",
"semver": "^5.3.0",
"tslib": "^1.13.0",
"tsutils": "^2.29.0"
}
},
"tsutils": {
"version": "2.29.0",
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
"integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
"dev": true,
"requires": {
"tslib": "^1.8.1"
}
},
"typescript": {
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"dev": true
},
"typescript-tslint-plugin": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/typescript-tslint-plugin/-/typescript-tslint-plugin-0.5.5.tgz",
"integrity": "sha512-tR5igNQP+6FhxaPJYRlUBVsEl0n5cSuXRbg7L1y80mL4B1jUHb8uiIcbQBJ9zWyypJEdFYFUccpXxvMwZR8+AA==",
"dev": true,
"requires": {
"minimatch": "^3.0.4",
"mock-require": "^3.0.3",
"vscode-languageserver": "^5.2.1"
}
},
"vscode-jsonrpc": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz",
"integrity": "sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg==",
"dev": true
},
"vscode-languageserver": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-5.2.1.tgz",
"integrity": "sha512-GuayqdKZqAwwaCUjDvMTAVRPJOp/SLON3mJ07eGsx/Iq9HjRymhKWztX41rISqDKhHVVyFM+IywICyZDla6U3A==",
"dev": true,
"requires": {
"vscode-languageserver-protocol": "3.14.1",
"vscode-uri": "^1.0.6"
}
},
"vscode-languageserver-protocol": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz",
"integrity": "sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g==",
"dev": true,
"requires": {
"vscode-jsonrpc": "^4.0.0",
"vscode-languageserver-types": "3.14.0"
}
},
"vscode-languageserver-types": {
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz",
"integrity": "sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A==",
"dev": true
},
"vscode-uri": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.8.tgz",
"integrity": "sha512-obtSWTlbJ+a+TFRYGaUumtVwb+InIUVI0Lu0VBUAPmj2cU5JutEXg3xUE0c2J5Tcy7h2DEKVJBFi+Y9ZSFzzPQ==",
"dev": true
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
}
}

View File

@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -169,12 +169,22 @@ struct queue_entry {
u32 bitmap_size, /* Number of bits set in bitmap */
fuzz_level, /* Number of fuzzing iterations */
n_fuzz_entry; /* offset in n_fuzz */
n_fuzz_entry /* offset in n_fuzz */
#ifdef INTROSPECTION
,
stats_selected, /* stats: how often selected */
stats_skipped, /* stats: how often skipped */
stats_finds, /* stats: # of saved finds */
stats_crashes, /* stats: # of saved crashes */
stats_tmouts /* stats: # of saved timeouts */
#endif
;
u64 exec_us, /* Execution time (us) */
handicap, /* Number of queue cycles behind */
depth, /* Path depth */
exec_cksum; /* Checksum of the execution trace */
exec_cksum, /* Checksum of the execution trace */
stats_mutated; /* stats: # of mutations performed */
u8 *trace_mini; /* Trace bytes, if kept */
u32 tc_ref; /* Trace bytes ref count */
@ -334,6 +344,7 @@ enum {
/* 12 */ PY_FUNC_INTROSPECTION,
/* 13 */ PY_FUNC_DESCRIBE,
/* 14 */ PY_FUNC_FUZZ_SEND,
/* 15 */ PY_FUNC_SPLICE_OPTOUT,
PY_FUNC_COUNT
};
@ -387,8 +398,9 @@ typedef struct afl_env_vars {
afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast,
afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new,
afl_exit_on_seed_issues, afl_try_affinity, afl_ignore_problems,
afl_keep_timeouts, afl_pizza_mode, afl_no_crash_readme,
afl_no_startup_calibration;
afl_keep_timeouts, afl_no_crash_readme, afl_ignore_timeouts,
afl_no_startup_calibration, afl_no_warn_instability,
afl_post_process_keep_original;
u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path,
*afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload,
@ -397,6 +409,8 @@ typedef struct afl_env_vars {
*afl_testcache_entries, *afl_child_kill_signal, *afl_fsrv_kill_signal,
*afl_target_env, *afl_persistent_record, *afl_exit_on_time;
s32 afl_pizza_mode;
} afl_env_vars_t;
struct afl_pass_stat {
@ -485,6 +499,7 @@ typedef struct afl_state {
no_unlink, /* do not unlink cur_input */
debug, /* Debug mode */
custom_only, /* Custom mutator only mode */
custom_splice_optout, /* Custom mutator no splice buffer */
is_main_node, /* if this is the main node */
is_secondary_node, /* if this is a secondary instance */
pizza_is_served; /* pizza mode */
@ -579,6 +594,7 @@ typedef struct afl_state {
last_find_time, /* Time for most recent path (ms) */
last_crash_time, /* Time for most recent crash (ms) */
last_hang_time, /* Time for most recent hang (ms) */
longest_find_time, /* Longest time taken for a find */
exit_on_time, /* Delay to exit if no new paths */
sync_time; /* Sync time (ms) */
@ -681,12 +697,14 @@ typedef struct afl_state {
/* statistics file */
double last_bitmap_cvg, last_stability, last_eps;
u64 stats_file_update_freq_msecs; /* Stats update frequency (msecs) */
/* plot file saves from last run */
u32 plot_prev_qp, plot_prev_pf, plot_prev_pnf, plot_prev_ce, plot_prev_md;
u64 plot_prev_qc, plot_prev_uc, plot_prev_uh, plot_prev_ed;
u64 stats_last_stats_ms, stats_last_plot_ms, stats_last_ms, stats_last_execs;
u64 stats_last_stats_ms, stats_last_plot_ms, stats_last_queue_ms,
stats_last_ms, stats_last_execs;
/* StatsD */
u64 statsd_last_send_ms;
@ -818,17 +836,29 @@ struct custom_mutator {
u32 (*afl_custom_fuzz_count)(void *data, const u8 *buf, size_t buf_size);
/**
* Perform custom mutations on a given input
* Opt-out of a splicing input for the fuzz mutator
*
* (Optional for now. Required in the future)
* Empty dummy function. It's presence tells afl-fuzz not to pass a
* splice data pointer and len.
*
* @param data pointer returned in afl_custom_init by this custom mutator
* @noreturn
*/
void (*afl_custom_splice_optout)(void *data);
/**
* Perform custom mutations on a given input
*
* (Optional)
*
* Getting an add_buf can be skipped by using afl_custom_splice_optout().
*
* @param[in] data Pointer returned in afl_custom_init by this custom mutator
* @param[in] buf Pointer to the input data to be mutated and the mutated
* output
* @param[in] buf_size Size of the input/output data
* @param[out] out_buf the new buffer. We may reuse *buf if large enough.
* *out_buf = NULL is treated as FATAL.
* @param[in] add_buf Buffer containing the additional test case
* @param[out] out_buf The new buffer, under your memory mgmt.
* @param[in] add_buf Buffer containing an additional test case (splicing)
* @param[in] add_buf_size Size of the additional test case
* @param[in] max_size Maximum size of the mutated output. The mutation must
* not produce data larger than max_size.
@ -856,14 +886,19 @@ struct custom_mutator {
* A post-processing function to use right before AFL writes the test case to
* disk in order to execute the target.
*
* (Optional) If this functionality is not needed, simply don't define this
* NOTE: Do not do any random changes to the data in this function!
*
* PERFORMANCE: If you can modify the data in-place you will have a better
* performance. Modify *data and set `*out_buf = data`.
*
* (Optional) If this functionality is not needed, simply do not define this
* function.
*
* @param[in] data pointer returned in afl_custom_init by this custom mutator
* @param[in] buf Buffer containing the test case to be executed
* @param[in] buf_size Size of the test case
* @param[out] out_buf Pointer to the buffer storing the test case after
* processing. External library should allocate memory for out_buf.
* processing. The external library should allocate memory for out_buf.
* It can chose to alter buf in-place, if the space is large enough.
* @return Size of the output buffer.
*/
@ -1046,6 +1081,7 @@ u8 havoc_mutation_probability_py(void *);
u8 queue_get_py(void *, const u8 *);
const char *introspection_py(void *);
u8 queue_new_entry_py(void *, const u8 *, const u8 *);
void splice_optout(void *);
void deinit_py(void *);
#endif
@ -1068,7 +1104,6 @@ u32 count_bits(afl_state_t *, u8 *);
u32 count_bytes(afl_state_t *, u8 *);
u32 count_non_255_bytes(afl_state_t *, u8 *);
void simplify_trace(afl_state_t *, u8 *);
void classify_counts(afl_forkserver_t *);
#ifdef WORD_SIZE_64
void discover_word(u8 *ret, u64 *current, u64 *virgin);
#else
@ -1082,6 +1117,9 @@ u8 *describe_op(afl_state_t *, u8, size_t);
u8 save_if_interesting(afl_state_t *, void *, u32, u8);
u8 has_new_bits(afl_state_t *, u8 *);
u8 has_new_bits_unclassified(afl_state_t *, u8 *);
#ifndef AFL_SHOWMAP
void classify_counts(afl_forkserver_t *);
#endif
/* Extras */
@ -1101,6 +1139,7 @@ void load_stats_file(afl_state_t *);
void write_setup_file(afl_state_t *, u32, char **);
void write_stats_file(afl_state_t *, u32, double, double, double);
void maybe_update_plot_file(afl_state_t *, u32, double, double);
void write_queue_stats(afl_state_t *);
void show_stats(afl_state_t *);
void show_stats_normal(afl_state_t *);
void show_stats_pizza(afl_state_t *);
@ -1156,11 +1195,13 @@ void fix_up_sync(afl_state_t *);
void check_asan_opts(afl_state_t *);
void check_binary(afl_state_t *, u8 *);
void check_if_tty(afl_state_t *);
void setup_signal_handlers(void);
void save_cmdline(afl_state_t *, u32, char **);
void read_foreign_testcases(afl_state_t *, int);
void write_crash_readme(afl_state_t *afl);
u8 check_if_text_buf(u8 *buf, u32 len);
#ifndef AFL_SHOWMAP
void setup_signal_handlers(void);
#endif
/* CmpLog */

View File

@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -12,7 +12,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -43,6 +43,7 @@ u32 check_binary_signatures(u8 *fn);
void detect_file_args(char **argv, u8 *prog_in, bool *use_stdin);
void print_suggested_envs(char *mispelled_env);
void check_environment_vars(char **env);
void set_sanitizer_defaults();
char **argv_cpy_dup(int argc, char **argv);
void argv_cpy_free(char **argv);
@ -142,5 +143,15 @@ FILE *create_ffile(u8 *fn);
/* create a file */
s32 create_file(u8 *fn);
/* memmem implementation as not all platforms support this */
void *afl_memmem(const void *haystack, size_t haystacklen, const void *needle,
size_t needlelen);
#ifdef __linux__
/* Nyx helper functions to create and remove tmp workdirs */
char *create_nyx_tmp_workdir(void);
void remove_nyx_tmp_workdir(afl_forkserver_t *fsrv, char *nyx_out_dir_path);
#endif
#endif

View File

@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -26,7 +26,7 @@
/* Version string: */
// c = release, a = volatile github dev, e = experimental branch
#define VERSION "++4.05a"
#define VERSION "++4.07a"
/******************************************************
* *
@ -290,10 +290,11 @@
#define UI_TARGET_HZ 5
/* Fuzzer stats file and plot update intervals (sec): */
/* Fuzzer stats file, queue stats and plot update intervals (sec): */
#define STATS_UPDATE_SEC 60
#define PLOT_UPDATE_SEC 5
#define QUEUE_UPDATE_SEC 1800
/* Smoothing divisor for CPU load and exec speed stats (1 - no smoothing). */
@ -363,9 +364,9 @@
* *
***********************************************************/
/* Call count interval between reseeding the libc PRNG from /dev/urandom: */
/* Call count interval between reseeding the PRNG from /dev/urandom: */
#define RESEED_RNG 100000
#define RESEED_RNG 2500000
/* The default maximum testcase cache size in MB, 0 = disable.
A value between 50 and 250 is a good default value. Note that the
@ -490,10 +491,14 @@
#define AFL_TXT_MIN_LEN 12
/* Maximum length of a queue input to be evaluated for "is_ascii"? */
#define AFL_TXT_MAX_LEN 65535
/* What is the minimum percentage of ascii characters present to be classifed
as "is_ascii"? */
#define AFL_TXT_MIN_PERCENT 94
#define AFL_TXT_MIN_PERCENT 99
/* How often to perform ASCII mutations 0 = disable, 1-8 are good values */

View File

@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -65,9 +65,11 @@ static char *afl_environment_variables[] = {
"AFL_FRIDA_INST_INSN",
"AFL_FRIDA_INST_JIT",
"AFL_FRIDA_INST_NO_CACHE",
"AFL_FRIDA_INST_NO_DYNAMIC_LOAD",
"AFL_FRIDA_INST_NO_OPTIMIZE",
"AFL_FRIDA_INST_NO_PREFETCH",
"AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH",
"AFL_FRIDA_INST_NO_SUPPRESS"
"AFL_FRIDA_INST_RANGES",
"AFL_FRIDA_INST_REGS_FILE",
"AFL_FRIDA_INST_SEED",
@ -90,6 +92,7 @@ static char *afl_environment_variables[] = {
"AFL_FRIDA_TRACEABLE",
"AFL_FRIDA_VERBOSE",
"AFL_FUZZER_ARGS", // oss-fuzz
"AFL_FUZZER_STATS_UPDATE_INTERVAL",
"AFL_GDB",
"AFL_GCC_ALLOWLIST",
"AFL_GCC_DENYLIST",
@ -103,6 +106,8 @@ static char *afl_environment_variables[] = {
"AFL_HARDEN",
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES",
"AFL_IGNORE_PROBLEMS",
"AFL_IGNORE_PROBLEMS_COVERAGE",
"AFL_IGNORE_TIMEOUTS",
"AFL_IGNORE_UNKNOWN_ENVS",
"AFL_IMPORT_FIRST",
"AFL_INPUT_LEN_MIN",
@ -124,12 +129,15 @@ static char *afl_environment_variables[] = {
"AFL_LLVM_ALLOWLIST",
"AFL_LLVM_DENYLIST",
"AFL_LLVM_BLOCKLIST",
"AFL_CMPLOG",
"AFL_LLVM_CMPLOG",
"AFL_GCC_CMPLOG",
"AFL_LLVM_INSTRIM",
"AFL_LLVM_CALLER",
"AFL_LLVM_CTX",
"AFL_LLVM_CTX_K",
"AFL_LLVM_DICT2FILE",
"AFL_LLVM_DICT2FILE_NO_MAIN",
"AFL_LLVM_DOCUMENT_IDS",
"AFL_LLVM_INSTRIM_LOOPHEAD",
"AFL_LLVM_INSTRUMENT",
@ -153,8 +161,9 @@ static char *afl_environment_variables[] = {
"AFL_LLVM_SKIP_NEVERZERO",
"AFL_NO_AFFINITY",
"AFL_TRY_AFFINITY",
"AFL_LLVM_LTO_STARTID",
"AFL_LLVM_LTO_DONTWRITEID",
"AFL_LLVM_LTO_SKIPINIT"
"AFL_LLVM_LTO_STARTID",
"AFL_NO_ARITH",
"AFL_NO_AUTODICT",
"AFL_NO_BUILTIN",
@ -168,6 +177,7 @@ static char *afl_environment_variables[] = {
"AFL_NO_UI",
"AFL_NO_PYTHON",
"AFL_NO_STARTUP_CALIBRATION",
"AFL_NO_WARN_INSTABILITY",
"AFL_UNTRACER_FILE",
"AFL_LLVM_USE_TRACE_PC",
"AFL_MAP_SIZE",
@ -179,6 +189,7 @@ static char *afl_environment_variables[] = {
"AFL_PATH",
"AFL_PERFORMANCE_FILE",
"AFL_PERSISTENT_RECORD",
"AFL_POST_PROCESS_KEEP_ORIGINAL",
"AFL_PRELOAD",
"AFL_TARGET_ENV",
"AFL_PYTHON_MODULE",

View File

@ -12,7 +12,7 @@
Dominik Maier <mail@dmnk.co>>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -43,7 +43,7 @@ typedef enum NyxReturnValue {
Normal,
Crash,
Asan,
Timout,
Timeout,
InvalidWriteToPayload,
Error,
IoError,
@ -51,16 +51,28 @@ typedef enum NyxReturnValue {
} NyxReturnValue;
typedef enum NyxProcessRole {
StandAlone,
Parent,
Child,
} NyxProcessRole;
typedef struct {
void *(*nyx_new)(const char *sharedir, const char *workdir, uint32_t cpu_id,
uint32_t input_buffer_size,
bool input_buffer_write_protection);
void *(*nyx_new_parent)(const char *sharedir, const char *workdir,
uint32_t cpu_id, uint32_t input_buffer_size,
bool input_buffer_write_protection);
void *(*nyx_new_child)(const char *sharedir, const char *workdir,
uint32_t cpu_id, uint32_t worker_id);
void *(*nyx_config_load)(const char *sharedir);
void (*nyx_config_set_workdir_path)(void *config, const char *workdir);
void (*nyx_config_set_input_buffer_size)(void *config,
uint32_t input_buffer_size);
void (*nyx_config_set_input_buffer_write_protection)(
void *config, bool input_buffer_write_protection);
void (*nyx_config_set_hprintf_fd)(void *config, int32_t hprintf_fd);
void (*nyx_config_set_process_role)(void *config, enum NyxProcessRole role);
void (*nyx_config_set_reuse_snapshot_path)(void *config,
const char *reuse_snapshot_path);
void *(*nyx_new)(void *config, uint32_t worker_id);
void (*nyx_shutdown)(void *qemu_process);
void (*nyx_option_set_reload_mode)(void *qemu_process, bool enable);
void (*nyx_option_set_timeout)(void *qemu_process, uint8_t timeout_sec,
@ -73,8 +85,13 @@ typedef struct {
uint32_t (*nyx_get_aux_string)(void *nyx_process, uint8_t *buffer,
uint32_t size);
bool (*nyx_remove_work_dir)(const char *workdir);
} nyx_plugin_handler_t;
/* Imports helper functions to enable Nyx mode (Linux only )*/
nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary);
#endif
typedef struct afl_forkserver {
@ -178,6 +195,8 @@ typedef struct afl_forkserver {
u32 nyx_id; /* nyx runner id (0 -> master) */
u32 nyx_bind_cpu_id; /* nyx runner cpu id */
char *nyx_aux_string;
bool nyx_use_tmp_workdir;
char *nyx_tmp_workdir_path;
#endif
} afl_forkserver_t;

View File

@ -15,7 +15,7 @@
Other code written by Michal Zalewski
Copyright 2016 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -12,7 +12,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2022 AFLplusplus Project. All rights reserved.
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

Some files were not shown because too many files have changed in this diff Show More