mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-08 16:21:32 +00:00
commit
00a53a870d
1
.gitignore
vendored
1
.gitignore
vendored
@ -82,3 +82,4 @@ libAFLDriver.a
|
||||
libAFLQemuDriver.a
|
||||
test/.afl_performance
|
||||
gmon.out
|
||||
afl-frida-trace.so
|
||||
|
11
afl-cmin
11
afl-cmin
@ -106,6 +106,7 @@ function usage() {
|
||||
" -f file - location read by the fuzzed program (stdin)\n" \
|
||||
" -m megs - memory limit for child process ("mem_limit" MB)\n" \
|
||||
" -t msec - run time limit for child process (none)\n" \
|
||||
" -O - use binary-only instrumentation (FRIDA mode)\n" \
|
||||
" -Q - use binary-only instrumentation (QEMU mode)\n" \
|
||||
" -U - use unicorn-based instrumentation (unicorn mode)\n" \
|
||||
"\n" \
|
||||
@ -140,7 +141,7 @@ 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:eCQU?")) != -1) {
|
||||
while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eCOQU?")) != -1) {
|
||||
if (_go_c == "i") {
|
||||
if (!Optarg) usage()
|
||||
if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
@ -180,6 +181,12 @@ BEGIN {
|
||||
extra_par = extra_par " -e"
|
||||
continue
|
||||
} else
|
||||
if (_go_c == "O") {
|
||||
if (frida_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
extra_par = extra_par " -O"
|
||||
frida_mode = 1
|
||||
continue
|
||||
} else
|
||||
if (_go_c == "Q") {
|
||||
if (qemu_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"}
|
||||
extra_par = extra_par " -Q"
|
||||
@ -275,7 +282,7 @@ BEGIN {
|
||||
target_bin = tnew
|
||||
}
|
||||
|
||||
if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !unicorn_mode) {
|
||||
if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !frida_mode && !unicorn_mode) {
|
||||
if (0 != system( "grep -q __AFL_SHM_ID "target_bin )) {
|
||||
print "[-] Error: binary '"target_bin"' doesn't appear to be instrumented." > "/dev/stderr"
|
||||
exit 1
|
||||
|
@ -53,7 +53,7 @@ unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \
|
||||
|
||||
export AFL_QUIET=1
|
||||
|
||||
while getopts "+i:o:f:m:t:eQUCh" opt; do
|
||||
while getopts "+i:o:f:m:t:eOQUCh" opt; do
|
||||
|
||||
case "$opt" in
|
||||
|
||||
@ -83,6 +83,10 @@ while getopts "+i:o:f:m:t:eQUCh" opt; do
|
||||
"C")
|
||||
export AFL_CMIN_CRASHES_ONLY=1
|
||||
;;
|
||||
"O")
|
||||
EXTRA_PAR="$EXTRA_PAR -O"
|
||||
FRIDA_MODE=1
|
||||
;;
|
||||
"Q")
|
||||
EXTRA_PAR="$EXTRA_PAR -Q"
|
||||
QEMU_MODE=1
|
||||
@ -118,6 +122,7 @@ 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)
|
||||
-O - use binary-only instrumentation (FRIDA mode)
|
||||
-Q - use binary-only instrumentation (QEMU mode)
|
||||
-U - use unicorn-based instrumentation (Unicorn mode)
|
||||
|
||||
@ -209,7 +214,7 @@ if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then
|
||||
|
||||
fi
|
||||
|
||||
if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$UNICORN_MODE" = "" ]; then
|
||||
if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$FRIDA_MODE" = "" -a "$UNICORN_MODE" = "" ]; then
|
||||
|
||||
if ! grep -qF "__AFL_SHM_ID" "$TARGET_BIN"; then
|
||||
echo "[-] Error: binary '$TARGET_BIN' doesn't appear to be instrumented." 1>&2
|
||||
|
5
frida_mode/.gitignore
vendored
Normal file
5
frida_mode/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
build/
|
||||
frida_test.dat
|
||||
qemu_test.dat
|
||||
frida_out/**
|
||||
qemu_out/**
|
350
frida_mode/Makefile
Normal file
350
frida_mode/Makefile
Normal file
@ -0,0 +1,350 @@
|
||||
PWD:=$(shell pwd)/
|
||||
INC_DIR:=$(PWD)inc/
|
||||
SRC_DIR:=$(PWD)src/
|
||||
INCLUDES:=$(wildcard $(INC_DIR)*.h)
|
||||
SOURCES:=$(wildcard $(SRC_DIR)*.c)
|
||||
BUILD_DIR:=$(PWD)build/
|
||||
CFLAGS:= $(CFLAGS) \
|
||||
-fPIC \
|
||||
-D_GNU_SOURCE
|
||||
|
||||
FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/
|
||||
FRIDA_TRACE:=$(FRIDA_BUILD_DIR)afl-frida-trace.so
|
||||
|
||||
ARCH=$(shell uname -m)
|
||||
ifeq "$(ARCH)" "aarch64"
|
||||
ARCH:=arm64
|
||||
TESTINSTR_BASE:=0x0000aaaaaaaaa000
|
||||
endif
|
||||
|
||||
ifeq "$(ARCH)" "x86_64"
|
||||
TESTINSTR_BASE:=0x0000555555554000
|
||||
endif
|
||||
|
||||
ifeq "$(shell uname)" "Darwin"
|
||||
OS:=macos
|
||||
AFL_FRIDA_INST_RANGES=0x0000000000001000-0xFFFFFFFFFFFFFFFF
|
||||
CFLAGS:=$(CFLAGS) -Wno-deprecated-declarations
|
||||
TEST_LDFLAGS:=-undefined dynamic_lookup
|
||||
endif
|
||||
ifeq "$(shell uname)" "Linux"
|
||||
OS:=linux
|
||||
AFL_FRIDA_INST_RANGES=$(shell $(PWD)test/testinstr.py -f $(BUILD_DIR)testinstr -s .testinstr -b $(TESTINSTR_BASE))
|
||||
CFLAGS:=$(CFLAGS) -Wno-prio-ctor-dtor
|
||||
TEST_LDFLAGS:=
|
||||
endif
|
||||
|
||||
ifndef OS
|
||||
$(error "Operating system unsupported")
|
||||
endif
|
||||
|
||||
VERSION=14.2.13
|
||||
GUM_DEVKIT_FILENAME=frida-gum-devkit-$(VERSION)-$(OS)-$(ARCH).tar.xz
|
||||
GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(VERSION)/$(GUM_DEVKIT_FILENAME)"
|
||||
GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME)
|
||||
GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gum.a
|
||||
GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gum.h
|
||||
|
||||
TEST_BUILD_DIR:=$(BUILD_DIR)test/
|
||||
|
||||
LIBPNG_FILE:=$(TEST_BUILD_DIR)libpng-1.2.56.tar.gz
|
||||
LIBPNG_URL:=https://downloads.sourceforge.net/project/libpng/libpng12/older-releases/1.2.56/libpng-1.2.56.tar.gz
|
||||
LIBPNG_DIR:=$(TEST_BUILD_DIR)libpng-1.2.56/
|
||||
LIBPNG_MAKEFILE:=$(LIBPNG_DIR)Makefile
|
||||
LIBPNG_LIB:=$(LIBPNG_DIR).libs/libpng12.a
|
||||
|
||||
HARNESS_FILE:=$(TEST_BUILD_DIR)StandaloneFuzzTargetMain.c
|
||||
HARNESS_OBJ:=$(TEST_BUILD_DIR)StandaloneFuzzTargetMain.o
|
||||
HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c"
|
||||
|
||||
PNGTEST_FILE:=$(TEST_BUILD_DIR)target.cc
|
||||
PNGTEST_OBJ:=$(TEST_BUILD_DIR)target.o
|
||||
PNGTEST_URL:="https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/libpng-1.2.56/target.cc"
|
||||
|
||||
TEST_BIN:=$(TEST_BUILD_DIR)pngtest
|
||||
|
||||
TESTINSTBIN:=$(BUILD_DIR)testinstr
|
||||
TESTINSTSRC:=$(PWD)test/testinstr.c
|
||||
|
||||
TEST_DATA_DIR:=$(PWD)build/test/libpng-1.2.56/contrib/pngsuite/
|
||||
|
||||
TESTINSTR_DATA_DIR:=$(BUILD_DIR)testinstr_in/
|
||||
TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)test.dat
|
||||
FRIDA_OUT:=$(PWD)frida_out
|
||||
QEMU_OUT:=$(PWD)qemu_out
|
||||
|
||||
.PHONY: all frida test clean format test_frida test_qemu compare testinstr test_testinstr standalone
|
||||
|
||||
all: $(FRIDA_TRACE)
|
||||
|
||||
frida: $(FRIDA_TRACE)
|
||||
|
||||
$(BUILD_DIR):
|
||||
mkdir -p $(BUILD_DIR)
|
||||
|
||||
############################# FRIDA ############################################
|
||||
$(FRIDA_BUILD_DIR): | $(BUILD_DIR)
|
||||
mkdir -p $@
|
||||
|
||||
$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR)
|
||||
wget -O $@ $(GUM_DEVKIT_URL)
|
||||
|
||||
$(GUM_DEVIT_LIBRARY): | $(GUM_DEVKIT_TARBALL)
|
||||
tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR)
|
||||
|
||||
$(GUM_DEVIT_HEADER): | $(GUM_DEVKIT_TARBALL)
|
||||
tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR)
|
||||
|
||||
$(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(SOURCES) Makefile | $(FRIDA_BUILD_DIR)
|
||||
$(CC) -shared \
|
||||
$(CFLAGS) \
|
||||
-o $@ $(SOURCES) \
|
||||
$(GUM_DEVIT_LIBRARY) \
|
||||
-I $(FRIDA_BUILD_DIR) \
|
||||
-I .. \
|
||||
-I ../include \
|
||||
-I $(INC_DIR) \
|
||||
../instrumentation/afl-compiler-rt.o.c \
|
||||
-lpthread -ldl -lresolv
|
||||
|
||||
cp -v $(FRIDA_TRACE) ../
|
||||
|
||||
############################# TEST #############################################
|
||||
|
||||
test: $(TEST_BIN)
|
||||
|
||||
$(TEST_BUILD_DIR): $(BUILD_DIR)
|
||||
mkdir -p $@
|
||||
|
||||
$(HARNESS_FILE): | $(TEST_BUILD_DIR)
|
||||
wget -O $@ $(HARNESS_URL)
|
||||
|
||||
$(HARNESS_OBJ): $(HARNESS_FILE)
|
||||
$(CC) -o $@ -c $<
|
||||
|
||||
$(PNGTEST_FILE): | $(TEST_BUILD_DIR)
|
||||
wget -O $@ $(PNGTEST_URL)
|
||||
|
||||
$(PNGTEST_OBJ): $(PNGTEST_FILE) | $(LIBPNG_DIR)
|
||||
$(CXX) -std=c++11 -I $(LIBPNG_DIR) -o $@ -c $<
|
||||
|
||||
$(LIBPNG_FILE): | $(TEST_BUILD_DIR)
|
||||
wget -O $@ $(LIBPNG_URL)
|
||||
|
||||
$(LIBPNG_DIR): $(LIBPNG_FILE)
|
||||
tar zxvf $(LIBPNG_FILE) -C $(TEST_BUILD_DIR)
|
||||
|
||||
$(LIBPNG_MAKEFILE): | $(LIBPNG_DIR)
|
||||
cd $(LIBPNG_DIR) && ./configure
|
||||
|
||||
$(LIBPNG_LIB): $(LIBPNG_MAKEFILE)
|
||||
make -C $(LIBPNG_DIR)
|
||||
|
||||
$(TEST_BIN): $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB)
|
||||
$(CXX) \
|
||||
-o $@ \
|
||||
$(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) \
|
||||
-lz \
|
||||
$(TEST_LDFLAGS)
|
||||
|
||||
############################# TESTINSR #########################################
|
||||
$(TESTINSTR_DATA_DIR): | $(BUILD_DIR)
|
||||
mkdir -p $@
|
||||
|
||||
$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR)
|
||||
echo -n "000" > $@
|
||||
|
||||
$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR)
|
||||
$(CC) -o $@ $<
|
||||
|
||||
testinstr: $(TESTINSTBIN)
|
||||
|
||||
############################# CLEAN ############################################
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR)
|
||||
|
||||
############################# FORMAT ###########################################
|
||||
format:
|
||||
cd .. && echo $(SOURCES) | xargs -L1 ./.custom-format.py -i
|
||||
cd .. && echo $(INCLUDES) | xargs -L1 ./.custom-format.py -i
|
||||
cd .. && ./.custom-format.py -i $(TESTINSTSRC)
|
||||
|
||||
############################# RUN #############################################
|
||||
|
||||
# Add the environment variable AFL_DEBUG_CHILD=1 to show printf's from the target
|
||||
|
||||
png_frida: $(FRIDA_TRACE) $(TEST_BIN)
|
||||
make -C ..
|
||||
cd .. && \
|
||||
./afl-fuzz \
|
||||
-O \
|
||||
-i $(TEST_DATA_DIR) \
|
||||
-o $(FRIDA_OUT) \
|
||||
-- \
|
||||
$(TEST_BIN) @@
|
||||
|
||||
png_qemu: $(TEST_BIN)
|
||||
make -C ..
|
||||
cd .. && \
|
||||
./afl-fuzz \
|
||||
-Q \
|
||||
-i $(TEST_DATA_DIR) \
|
||||
-o $(QEMU_OUT) \
|
||||
-- \
|
||||
$(TEST_BIN) @@
|
||||
|
||||
compare: $(FRIDA_TRACE) $(TEST_BIN)
|
||||
cd .. && \
|
||||
./afl-fuzz \
|
||||
-V30 \
|
||||
-O \
|
||||
-i $(TEST_DATA_DIR) \
|
||||
-o $(FRIDA_OUT) \
|
||||
-- \
|
||||
$(TEST_BIN) @@
|
||||
cd .. && \
|
||||
./afl-fuzz \
|
||||
-V30 \
|
||||
-Q \
|
||||
-i $(TEST_DATA_DIR) \
|
||||
-o $(QEMU_OUT) \
|
||||
-- \
|
||||
$(TEST_BIN) @@
|
||||
cat frida_out/default/fuzzer_stats
|
||||
cat qemu_out/default/fuzzer_stats
|
||||
|
||||
testinstr_qemu: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
|
||||
make -C ..
|
||||
cd .. && \
|
||||
AFL_QEMU_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \
|
||||
./afl-fuzz \
|
||||
-Q \
|
||||
-i $(TESTINSTR_DATA_DIR) \
|
||||
-o $(QEMU_OUT) \
|
||||
-- \
|
||||
$(TESTINSTBIN) @@
|
||||
|
||||
testinstr_frida: $(FRIDA_TRACE) $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
|
||||
make -C ..
|
||||
cd .. && \
|
||||
AFL_FRIDA_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \
|
||||
AFL_FRIDA_INST_NO_OPTIMIZE=1 \
|
||||
AFL_FRIDA_INST_NO_PREFETCH=1 \
|
||||
AFL_FRIDA_INST_STRICT=1 \
|
||||
./afl-fuzz \
|
||||
-O \
|
||||
-i $(TESTINSTR_DATA_DIR) \
|
||||
-o $(FRIDA_OUT) \
|
||||
-- \
|
||||
$(TESTINSTBIN) @@
|
||||
|
||||
standalone: $(FRIDA_TRACE) $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
|
||||
cd .. && \
|
||||
AFL_FRIDA_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \
|
||||
AFL_DEBUG_CHILD=1 \
|
||||
AFL_FRIDA_DEBUG_MAPS=1 \
|
||||
AFL_FRIDA_INST_NO_OPTIMIZE=1 \
|
||||
AFL_FRIDA_INST_NO_PREFETCH=1 \
|
||||
AFL_FRIDA_INST_TRACE=1 \
|
||||
AFL_FRIDA_INST_STRICT=1 \
|
||||
LD_PRELOAD=$(FRIDA_TRACE) \
|
||||
DYLD_INSERT_LIBRARIES=$(FRIDA_TRACE) \
|
||||
$(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
|
||||
|
||||
tmin_qemu: $(TEST_BIN)
|
||||
make -C ..
|
||||
cd .. && \
|
||||
./afl-tmin \
|
||||
-Q \
|
||||
-i $(TEST_DATA_DIR)basn0g01.png \
|
||||
-o $(QEMU_OUT)/qemu-min-basn0g01.png \
|
||||
-- \
|
||||
$(TEST_BIN) @@
|
||||
|
||||
tmin_frida: $(TEST_BIN)
|
||||
make -C ..
|
||||
cd .. && \
|
||||
./afl-tmin \
|
||||
-O \
|
||||
-i $(TEST_DATA_DIR)basn0g01.png \
|
||||
-o $(FRIDA_OUT)/qemu-min-basn0g01.png \
|
||||
-- \
|
||||
$(TEST_BIN)
|
||||
|
||||
showmap_qemu: $(TEST_BIN)
|
||||
make -C ..
|
||||
cd .. && \
|
||||
./afl-showmap \
|
||||
-Q \
|
||||
-i $(TEST_DATA_DIR) \
|
||||
-o $(QEMU_OUT) \
|
||||
-- \
|
||||
$(TEST_BIN) @@
|
||||
|
||||
showmap_frida: $(TEST_BIN)
|
||||
make -C ..
|
||||
cd .. && \
|
||||
./afl-showmap \
|
||||
-O \
|
||||
-i $(TEST_DATA_DIR) \
|
||||
-o $(FRIDA_OUT) \
|
||||
-- \
|
||||
$(TEST_BIN) @@
|
||||
|
||||
analyze_qemu: $(TEST_BIN)
|
||||
make -C ..
|
||||
cd .. && \
|
||||
./afl-analyze \
|
||||
-Q \
|
||||
-i $(TEST_DATA_DIR)basn0g01.png \
|
||||
-- \
|
||||
$(TEST_BIN) @@
|
||||
|
||||
analyze_frida: $(TEST_BIN)
|
||||
make -C ..
|
||||
cd .. && \
|
||||
./afl-analyze \
|
||||
-O \
|
||||
-i $(TEST_DATA_DIR)basn0g01.png \
|
||||
-- \
|
||||
$(TEST_BIN) @@
|
||||
|
||||
cmin_qemu: $(TEST_BIN)
|
||||
make -C ..
|
||||
cd .. && \
|
||||
./afl-cmin \
|
||||
-Q \
|
||||
-i $(TEST_DATA_DIR) \
|
||||
-o $(QEMU_OUT) \
|
||||
-- \
|
||||
$(TEST_BIN) @@
|
||||
|
||||
cmin_frida: $(TEST_BIN)
|
||||
make -C ..
|
||||
cd .. && \
|
||||
./afl-cmin \
|
||||
-O \
|
||||
-i $(TEST_DATA_DIR) \
|
||||
-o $(FRIDA_OUT) \
|
||||
-- \
|
||||
$(TEST_BIN) @@
|
||||
|
||||
cmin_bash_qemu: $(TEST_BIN)
|
||||
make -C ..
|
||||
cd .. && \
|
||||
./afl-cmin.bash \
|
||||
-Q \
|
||||
-i $(TEST_DATA_DIR) \
|
||||
-o $(QEMU_OUT) \
|
||||
-- \
|
||||
$(TEST_BIN) @@
|
||||
|
||||
cmin_bash_frida: $(TEST_BIN)
|
||||
make -C ..
|
||||
cd .. && \
|
||||
./afl-cmin.bash \
|
||||
-O \
|
||||
-i $(TEST_DATA_DIR) \
|
||||
-o $(FRIDA_OUT) \
|
||||
-- \
|
||||
$(TEST_BIN) @@
|
135
frida_mode/README.md
Normal file
135
frida_mode/README.md
Normal file
@ -0,0 +1,135 @@
|
||||
# FRIDA MODE
|
||||
The purpose of FRIDA mode is to provide an alternative binary only fuzzer for AFL
|
||||
just like that provided by QEMU mode. The intention is to provide a very similar
|
||||
user experience, right down to the options provided through environment variables.
|
||||
|
||||
Whilst AFLplusplus already has some support for running on FRIDA [here](https://github.com/AFLplusplus/AFLplusplus/tree/stable/utils/afl_frida)
|
||||
this requires the code to be fuzzed to be provided as a shared library, it
|
||||
cannot be used to fuzz executables. Additionally, it requires the user to write
|
||||
a small harness around their target code of interest, FRIDA mode instead takes a
|
||||
different approach to avoid these limitations.
|
||||
|
||||
# Current Progress
|
||||
As FRIDA mode is new, it is missing a lot of features. Most importantly,
|
||||
persistent mode. The design is such that it should be possible to add these
|
||||
features in a similar manner to QEMU mode and perhaps leverage some of its
|
||||
design and implementation.
|
||||
|
||||
| Feature/Instrumentation | frida-mode |
|
||||
| -------------------------|:----------:|
|
||||
| NeverZero | |
|
||||
| Persistent Mode | |
|
||||
| LAF-Intel / CompCov | |
|
||||
| CmpLog | |
|
||||
| Selective Instrumentation| x |
|
||||
| Non-Colliding Coverage | |
|
||||
| Ngram prev_loc Coverage | |
|
||||
| Context Coverage | |
|
||||
| Auto Dictionary | |
|
||||
| Snapshot LKM Support | |
|
||||
|
||||
# Compatibility
|
||||
Currently FRIDA mode supports Linux and macOS targets on both x86/x64
|
||||
architecture and aarch64. Later releases may add support for aarch32 and Windows
|
||||
targets as well as embedded linux environments.
|
||||
|
||||
FRIDA has been used on various embedded targets using both uClibc and musl C
|
||||
runtime libraries, so porting should be possible. However, the current build
|
||||
system does not support cross compilation.
|
||||
|
||||
## Getting Started
|
||||
To build everything run `make`.
|
||||
|
||||
To run the benchmark sample with qemu run `make png_qemu`.
|
||||
To run the benchmark sample with frida run `make png_frida`.
|
||||
|
||||
## Usage
|
||||
FRIDA mode requires some small modifications to the afl-fuzz and similar tools
|
||||
in AFLplusplus. The intention is that it behaves identically to QEMU, but uses
|
||||
the 'O' switch rather than 'Q'. Whilst the options 'f', 'F', 's' or 'S' may have
|
||||
made more sense for a mode powered by FRIDA Stalker, they were all taken, so
|
||||
instead we use 'O' in homage to the [author](https://github.com/oleavr) of
|
||||
FRIDA.
|
||||
|
||||
Similarly, the intention is to mimic the use of environment variables used by
|
||||
QEMU where possible (although replacing `s/QEMU/FRIDA/g`). Accodingly, the
|
||||
following options are currently supported.
|
||||
|
||||
* `AFL_FRIDA_DEBUG_MAPS` - See `AFL_QEMU_DEBUG_MAPS`
|
||||
* `AFL_FRIDA_EXCLUDE_RANGES` - See `AFL_QEMU_EXCLUDE_RANGES`
|
||||
* `AFL_FRIDA_INST_RANGES` - See `AFL_QEMU_INST_RANGES`
|
||||
|
||||
# Performance
|
||||
|
||||
Additionally, the intention is to be able to make a direct performance
|
||||
comparison between the two approaches. Accordingly, FRIDA mode includes a test
|
||||
target based on the [libpng](https://libpng.sourceforge.io/) benchmark used by
|
||||
[fuzzbench](https://google.github.io/fuzzbench/) and integrated with the
|
||||
[StandaloneFuzzTargetMain](https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c)
|
||||
from the llvm project. This is built and linked without any special
|
||||
modifications to suit FRIDA or QEMU. We use the test data provided with libpng
|
||||
as our corpus.
|
||||
|
||||
Whilst not much performance tuning has been completed to date, performance is
|
||||
around 30-50% of that of QEMU mode, however, this gap may reduce with the
|
||||
introduction of persistent mode. Performance can be tested by running
|
||||
`make compare`, albeit a longer time measurement may be required for move
|
||||
accurate results.
|
||||
|
||||
Whilst [afl_frida](https://github.com/AFLplusplus/AFLplusplus/tree/stable/utils/afl_frida)
|
||||
claims a 5-10x performance increase over QEMU, it has not been possible to
|
||||
reproduce these claims. However, the number of executions per second can vary
|
||||
dramatically as a result of the randomization of the fuzzer input. Some inputs
|
||||
may traverse relatively few paths before being rejected as invalid whilst others
|
||||
may be valid inputs or be subject to much more processing before rejection.
|
||||
Accordingly, it is recommended that testing be carried out over prolongued
|
||||
periods to gather timings which are more than indicative.
|
||||
|
||||
# Design
|
||||
FRIDA mode is supported by using `LD_PRELOAD` (`DYLD_INSERT_LIBRARIES` on macOS)
|
||||
to inject a shared library (`afl-frida-trace.so`) into the target. This shared
|
||||
library is built using the [frida-gum](https://github.com/frida/frida-gum)
|
||||
devkit from the [FRIDA](https://github.com/frida/frida) project. One of the
|
||||
components of frida-gum is [Stalker](https://medium.com/@oleavr/anatomy-of-a-code-tracer-b081aadb0df8),
|
||||
this allows the dynamic instrumentation of running code for AARCH32, AARCH64,
|
||||
x86 and x64 architectutes. Implementation details can be found
|
||||
[here](https://frida.re/docs/stalker/).
|
||||
|
||||
Dynamic instrumentation is used to augment the target application with similar
|
||||
coverage information to that inserted by `afl-gcc` or `afl-clang`. The shared
|
||||
library is also linked to the `compiler-rt` component of AFLplusplus to feedback
|
||||
this coverage information to AFL and also provide a fork server. It also makes
|
||||
use of the FRIDA [prefetch](https://github.com/frida/frida-gum/blob/56dd9ba3ee9a5511b4b0c629394bf122775f1ab7/gum/gumstalker.h#L115)
|
||||
support to feedback instrumented blocks from the child to the parent using a
|
||||
shared memory region to avoid the need to regenerate instrumented blocks on each
|
||||
fork.
|
||||
|
||||
Whilst FRIDA allows for a normal C function to be used to augment instrumented
|
||||
code, to minimize the costs of storing and restoring all of the registers, FRIDA
|
||||
mode instead makes use of optimized assembly instead on AARCH64 and x86/64
|
||||
targets.
|
||||
|
||||
# Advanced configuration options
|
||||
* `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_NO_PREFETCH` - Disable prefetching. By default the child will
|
||||
report instrumented blocks back to the parent so that it can also instrument
|
||||
them and they be inherited by the next child on fork.
|
||||
* `AFL_FRIDA_INST_STRICT` - Under certain conditions, Stalker may encroach into
|
||||
excluded regions and generate both instrumented blocks and coverage data (e.g.
|
||||
indirect calls on x86). The excluded block is generally honoured as soon as
|
||||
another function is called within the excluded region and so such encroachment
|
||||
is usually of little consequence. This detail may however, hinder you when
|
||||
checking that the correct number of paths are found for testing purposes or
|
||||
similar. There is a performance penatly for this option during block compilation
|
||||
where we check the block isn't in a list of excluded ranges.
|
||||
* `AFL_FRIDA_INST_TRACE` - Generate some logging when running instrumented code.
|
||||
Requires `AFL_FRIDA_INST_NO_OPTIMIZE`.
|
||||
|
||||
# TODO
|
||||
As can be seen from the progress section above, there are a number of features
|
||||
which are missing in its currently form. Chief amongst which is persistent mode.
|
||||
The intention is to achieve feature parity with QEMU mode in due course.
|
||||
Contributions are welcome, but please get in touch to ensure that efforts are
|
||||
deconflicted.
|
7
frida_mode/inc/instrument.h
Normal file
7
frida_mode/inc/instrument.h
Normal file
@ -0,0 +1,7 @@
|
||||
#include "frida-gum.h"
|
||||
|
||||
void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output,
|
||||
gpointer user_data);
|
||||
|
||||
void instrument_init();
|
||||
|
4
frida_mode/inc/interceptor.h
Normal file
4
frida_mode/inc/interceptor.h
Normal file
@ -0,0 +1,4 @@
|
||||
#include "frida-gum.h"
|
||||
|
||||
void intercept(void *address, gpointer replacement, gpointer user_data);
|
||||
|
5
frida_mode/inc/prefetch.h
Normal file
5
frida_mode/inc/prefetch.h
Normal file
@ -0,0 +1,5 @@
|
||||
void prefetch_init();
|
||||
void prefetch_start(GumStalker *stalker);
|
||||
void prefetch_write(void *addr);
|
||||
void prefetch_read(GumStalker *stalker);
|
||||
|
6
frida_mode/inc/ranges.h
Normal file
6
frida_mode/inc/ranges.h
Normal file
@ -0,0 +1,6 @@
|
||||
#include "frida-gum.h"
|
||||
|
||||
void ranges_init(GumStalker *stalker);
|
||||
|
||||
gboolean range_is_excluded(gpointer address);
|
||||
|
265
frida_mode/src/instrument.c
Normal file
265
frida_mode/src/instrument.c
Normal file
@ -0,0 +1,265 @@
|
||||
#include "frida-gum.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "prefetch.h"
|
||||
#include "ranges.h"
|
||||
#include "unistd.h"
|
||||
|
||||
extern uint8_t *__afl_area_ptr;
|
||||
extern u32 __afl_map_size;
|
||||
|
||||
uint64_t __thread previous_pc = 0;
|
||||
GumAddress current_log_impl = GUM_ADDRESS(0);
|
||||
|
||||
static gboolean tracing = false;
|
||||
static gboolean optimize = false;
|
||||
static gboolean strict = false;
|
||||
|
||||
#if defined(__x86_64__)
|
||||
static const guint8 afl_log_code[] = {
|
||||
|
||||
0x9c, /* pushfq */
|
||||
0x50, /* push rax */
|
||||
0x51, /* push rcx */
|
||||
0x52, /* push rdx */
|
||||
|
||||
0x48, 0x8d, 0x05, 0x27,
|
||||
0x00, 0x00, 0x00, /* lea rax, sym._afl_area_ptr_ptr */
|
||||
0x48, 0x8b, 0x00, /* mov rax, qword [rax] */
|
||||
0x48, 0x8b, 0x00, /* mov rax, qword [rax] */
|
||||
0x48, 0x8d, 0x0d, 0x22,
|
||||
0x00, 0x00, 0x00, /* lea rcx, sym.previous_pc */
|
||||
0x48, 0x8b, 0x11, /* mov rdx, qword [rcx] */
|
||||
0x48, 0x8b, 0x12, /* mov rdx, qword [rdx] */
|
||||
0x48, 0x31, 0xfa, /* xor rdx, rdi */
|
||||
0xfe, 0x04, 0x10, /* inc byte [rax + rdx] */
|
||||
0x48, 0xd1, 0xef, /* shr rdi, 1 */
|
||||
0x48, 0x8b, 0x01, /* mov rax, qword [rcx] */
|
||||
0x48, 0x89, 0x38, /* mov qword [rax], rdi */
|
||||
|
||||
0x5a, /* pop rdx */
|
||||
0x59, /* pop rcx */
|
||||
0x58, /* pop rax */
|
||||
0x9d, /* popfq */
|
||||
|
||||
0xc3, /* ret */
|
||||
|
||||
/* Read-only data goes here: */
|
||||
/* uint8_t** afl_area_ptr_ptr */
|
||||
/* uint64_t* afl_prev_loc_ptr */
|
||||
|
||||
};
|
||||
|
||||
void instrument_coverage_optimize(const cs_insn * instr,
|
||||
GumStalkerOutput *output) {
|
||||
|
||||
guint64 current_pc = instr->address;
|
||||
guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8);
|
||||
area_offset &= MAP_SIZE - 1;
|
||||
GumX86Writer *cw = output->writer.x86;
|
||||
|
||||
if (current_log_impl == 0 ||
|
||||
!gum_x86_writer_can_branch_directly_between(cw->pc, current_log_impl) ||
|
||||
!gum_x86_writer_can_branch_directly_between(cw->pc + 128,
|
||||
current_log_impl)) {
|
||||
|
||||
gconstpointer after_log_impl = cw->code + 1;
|
||||
|
||||
gum_x86_writer_put_jmp_near_label(cw, after_log_impl);
|
||||
|
||||
current_log_impl = cw->pc;
|
||||
gum_x86_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code));
|
||||
|
||||
uint8_t **afl_area_ptr_ptr = &__afl_area_ptr;
|
||||
uint64_t *afl_prev_loc_ptr = &previous_pc;
|
||||
gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr,
|
||||
sizeof(afl_area_ptr_ptr));
|
||||
gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr,
|
||||
sizeof(afl_prev_loc_ptr));
|
||||
|
||||
gum_x86_writer_put_label(cw, after_log_impl);
|
||||
|
||||
}
|
||||
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
|
||||
-GUM_RED_ZONE_SIZE);
|
||||
gum_x86_writer_put_push_reg(cw, GUM_REG_RDI);
|
||||
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDI, area_offset);
|
||||
gum_x86_writer_put_call_address(cw, current_log_impl);
|
||||
gum_x86_writer_put_pop_reg(cw, GUM_REG_RDI);
|
||||
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
|
||||
GUM_RED_ZONE_SIZE);
|
||||
|
||||
}
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
static const guint8 afl_log_code[] = {
|
||||
|
||||
// __afl_area_ptr[current_pc ^ previous_pc]++;
|
||||
// previous_pc = current_pc >> 1;
|
||||
0xE1, 0x0B, 0xBF, 0xA9, // stp x1, x2, [sp, -0x10]!
|
||||
0xE3, 0x13, 0xBF, 0xA9, // stp x3, x4, [sp, -0x10]!
|
||||
|
||||
// x0 = current_pc
|
||||
0xc1, 0x01, 0x00, 0x58, // ldr x1, #0x38, =&__afl_area_ptr
|
||||
0x21, 0x00, 0x40, 0xf9, // ldr x1, [x1] (=__afl_area_ptr)
|
||||
|
||||
0xc2, 0x01, 0x00, 0x58, // ldr x2, #0x38, =&previous_pc
|
||||
0x42, 0x00, 0x40, 0xf9, // ldr x2, [x2] (=previous_pc)
|
||||
|
||||
// __afl_area_ptr[current_pc ^ previous_pc]++;
|
||||
0x42, 0x00, 0x00, 0xca, // eor x2, x2, x0
|
||||
0x23, 0x68, 0x62, 0xf8, // ldr x3, [x1, x2]
|
||||
0x63, 0x04, 0x00, 0x91, // add x3, x3, #1
|
||||
0x23, 0x68, 0x22, 0xf8, // str x3, [x1, x2]
|
||||
|
||||
// previous_pc = current_pc >> 1;
|
||||
0xe0, 0x07, 0x40, 0x8b, // add x0, xzr, x0, LSR #1
|
||||
0xe2, 0x00, 0x00, 0x58, // ldr x2, #0x1c, =&previous_pc
|
||||
0x40, 0x00, 0x00, 0xf9, // str x0, [x2]
|
||||
|
||||
0xE3, 0x13, 0xc1, 0xA8, // ldp x3, x4, [sp], #0x10
|
||||
0xE1, 0x0B, 0xc1, 0xA8, // ldp x1, x2, [sp], #0x10
|
||||
0xC0, 0x03, 0x5F, 0xD6, // ret
|
||||
|
||||
// &afl_area_ptr_ptr
|
||||
// &afl_prev_loc_ptr
|
||||
|
||||
};
|
||||
|
||||
void instrument_coverage_optimize(const cs_insn * instr,
|
||||
GumStalkerOutput *output) {
|
||||
|
||||
guint64 current_pc = instr->address;
|
||||
guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8);
|
||||
area_offset &= MAP_SIZE - 1;
|
||||
GumArm64Writer *cw = output->writer.arm64;
|
||||
|
||||
if (current_log_impl == 0 ||
|
||||
!gum_arm64_writer_can_branch_directly_between(cw, cw->pc,
|
||||
current_log_impl) ||
|
||||
!gum_arm64_writer_can_branch_directly_between(cw, cw->pc + 128,
|
||||
current_log_impl)) {
|
||||
|
||||
gconstpointer after_log_impl = cw->code + 1;
|
||||
|
||||
gum_arm64_writer_put_b_label(cw, after_log_impl);
|
||||
|
||||
current_log_impl = cw->pc;
|
||||
gum_arm64_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code));
|
||||
|
||||
uint8_t **afl_area_ptr_ptr = &__afl_area_ptr;
|
||||
uint64_t *afl_prev_loc_ptr = &previous_pc;
|
||||
gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr,
|
||||
sizeof(afl_area_ptr_ptr));
|
||||
gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr,
|
||||
sizeof(afl_prev_loc_ptr));
|
||||
|
||||
gum_arm64_writer_put_label(cw, after_log_impl);
|
||||
|
||||
}
|
||||
|
||||
gum_arm64_writer_put_stp_reg_reg_reg_offset(
|
||||
cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, -(16 + GUM_RED_ZONE_SIZE),
|
||||
GUM_INDEX_PRE_ADJUST);
|
||||
gum_arm64_writer_put_ldr_reg_u64(cw, ARM64_REG_X0, area_offset);
|
||||
gum_arm64_writer_put_bl_imm(cw, current_log_impl);
|
||||
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
|
||||
cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, 16 + GUM_RED_ZONE_SIZE,
|
||||
GUM_INDEX_POST_ADJUST);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void on_basic_block(GumCpuContext *context, gpointer user_data) {
|
||||
|
||||
/* Avoid stack operations in potentially performance critical code */
|
||||
static char buffer[200];
|
||||
int len;
|
||||
guint64 current_pc = (guint64)user_data;
|
||||
if (tracing) {
|
||||
|
||||
/* Avoid any functions which may cause an allocation since the target app
|
||||
* may already be running inside malloc and it isn't designed to be
|
||||
* re-entrant on a single thread */
|
||||
len = snprintf(buffer, sizeof(buffer),
|
||||
"current_pc: 0x%016" G_GINT64_MODIFIER
|
||||
"x, previous_pc: 0x%016" G_GINT64_MODIFIER "x\n",
|
||||
current_pc, previous_pc);
|
||||
|
||||
write(STDOUT_FILENO, buffer, len + 1);
|
||||
|
||||
}
|
||||
|
||||
current_pc = (current_pc >> 4) ^ (current_pc << 8);
|
||||
current_pc &= MAP_SIZE - 1;
|
||||
|
||||
__afl_area_ptr[current_pc ^ previous_pc]++;
|
||||
previous_pc = current_pc >> 1;
|
||||
|
||||
}
|
||||
|
||||
void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output,
|
||||
gpointer user_data) {
|
||||
|
||||
const cs_insn *instr;
|
||||
gboolean begin = TRUE;
|
||||
while (gum_stalker_iterator_next(iterator, &instr)) {
|
||||
|
||||
if (begin) {
|
||||
|
||||
prefetch_write((void *)instr->address);
|
||||
if (!strict || !range_is_excluded((void *)instr->address)) {
|
||||
|
||||
if (optimize) {
|
||||
|
||||
instrument_coverage_optimize(instr, output);
|
||||
|
||||
} else {
|
||||
|
||||
gum_stalker_iterator_put_callout(iterator, on_basic_block,
|
||||
(gpointer)instr->address, NULL);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
begin = FALSE;
|
||||
|
||||
}
|
||||
|
||||
gum_stalker_iterator_keep(iterator);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void instrument_init() {
|
||||
|
||||
optimize = (getenv("AFL_FRIDA_INST_NO_OPTIMIZE") == NULL);
|
||||
tracing = (getenv("AFL_FRIDA_INST_TRACE") != NULL);
|
||||
strict = (getenv("AFL_FRIDA_INST_STRICT") != NULL);
|
||||
|
||||
#if !defined(__x86_64__) && !defined(__aarch64__)
|
||||
optimize = false;
|
||||
#endif
|
||||
|
||||
OKF("Instrumentation - optimize [%c]", optimize ? 'X' : ' ');
|
||||
OKF("Instrumentation - tracing [%c]", tracing ? 'X' : ' ');
|
||||
OKF("Instrumentation - strict [%c]", strict ? 'X' : ' ');
|
||||
|
||||
if (tracing && optimize) {
|
||||
|
||||
FATAL("AFL_FRIDA_INST_OPTIMIZE and AFL_FRIDA_INST_TRACE are incompatible");
|
||||
|
||||
}
|
||||
|
||||
if (__afl_map_size != 0x10000) {
|
||||
|
||||
FATAL("Bad map size: 0x%08x", __afl_map_size);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
16
frida_mode/src/interceptor.c
Normal file
16
frida_mode/src/interceptor.c
Normal file
@ -0,0 +1,16 @@
|
||||
#include "frida-gum.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include "interceptor.h"
|
||||
|
||||
void intercept(void *address, gpointer replacement, gpointer user_data) {
|
||||
|
||||
GumInterceptor *interceptor = gum_interceptor_obtain();
|
||||
gum_interceptor_begin_transaction(interceptor);
|
||||
GumReplaceReturn ret =
|
||||
gum_interceptor_replace(interceptor, address, replacement, user_data);
|
||||
if (ret != GUM_ATTACH_OK) { FATAL("gum_interceptor_attach: %d", ret); }
|
||||
gum_interceptor_end_transaction(interceptor);
|
||||
|
||||
}
|
||||
|
149
frida_mode/src/main.c
Normal file
149
frida_mode/src/main.c
Normal file
@ -0,0 +1,149 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach/mach.h>
|
||||
#include <mach-o/dyld_images.h>
|
||||
#else
|
||||
#include <sys/wait.h>
|
||||
#include <sys/personality.h>
|
||||
#endif
|
||||
|
||||
#include "frida-gum.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include "interceptor.h"
|
||||
#include "instrument.h"
|
||||
#include "prefetch.h"
|
||||
#include "ranges.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
extern mach_port_t mach_task_self();
|
||||
extern GumAddress gum_darwin_find_entrypoint(mach_port_t task);
|
||||
#else
|
||||
extern int __libc_start_main(int *(main)(int, char **, char **), int argc,
|
||||
char **ubp_av, void (*init)(void),
|
||||
void (*fini)(void), void (*rtld_fini)(void),
|
||||
void(*stack_end));
|
||||
#endif
|
||||
|
||||
typedef int *(*main_fn_t)(int argc, char **argv, char **envp);
|
||||
|
||||
static main_fn_t main_fn = NULL;
|
||||
static GumStalker * stalker = NULL;
|
||||
static GumMemoryRange code_range = {0};
|
||||
|
||||
extern void __afl_manual_init();
|
||||
extern __thread uint64_t previous_pc;
|
||||
|
||||
static int on_fork() {
|
||||
|
||||
prefetch_read(stalker);
|
||||
return fork();
|
||||
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
static void on_main_os(int argc, char **argv, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
static void on_main_os(int argc, char **argv, char **envp) {
|
||||
|
||||
/* Personality doesn't affect the current process, it only takes effect on
|
||||
* evec */
|
||||
int persona = personality(ADDR_NO_RANDOMIZE);
|
||||
if ((persona & ADDR_NO_RANDOMIZE) == 0) { execvpe(argv[0], argv, envp); }
|
||||
|
||||
GumInterceptor *interceptor = gum_interceptor_obtain();
|
||||
|
||||
gum_interceptor_begin_transaction(interceptor);
|
||||
gum_interceptor_revert(interceptor, __libc_start_main);
|
||||
gum_interceptor_end_transaction(interceptor);
|
||||
gum_interceptor_flush(interceptor);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int *on_main(int argc, char **argv, char **envp) {
|
||||
|
||||
on_main_os(argc, argv, envp);
|
||||
|
||||
stalker = gum_stalker_new();
|
||||
if (stalker == NULL) { FATAL("Failed to initialize stalker"); }
|
||||
|
||||
gum_stalker_set_trust_threshold(stalker, 0);
|
||||
|
||||
GumStalkerTransformer *transformer =
|
||||
gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL);
|
||||
|
||||
instrument_init();
|
||||
prefetch_init();
|
||||
ranges_init(stalker);
|
||||
|
||||
intercept(fork, on_fork, stalker);
|
||||
|
||||
gum_stalker_follow_me(stalker, transformer, NULL);
|
||||
gum_stalker_deactivate(stalker);
|
||||
|
||||
__afl_manual_init();
|
||||
|
||||
/* Child here */
|
||||
previous_pc = 0;
|
||||
prefetch_start(stalker);
|
||||
main_fn(argc, argv, envp);
|
||||
_exit(0);
|
||||
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
static void intercept_main() {
|
||||
|
||||
mach_port_t task = mach_task_self();
|
||||
OKF("Task Id: %u", task);
|
||||
GumAddress entry = gum_darwin_find_entrypoint(task);
|
||||
OKF("Entry Point: 0x%016" G_GINT64_MODIFIER "x", entry);
|
||||
void *main = GSIZE_TO_POINTER(entry);
|
||||
main_fn = main;
|
||||
intercept(main, on_main, NULL);
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
static int on_libc_start_main(int *(main)(int, char **, char **), int argc,
|
||||
char **ubp_av, void (*init)(void),
|
||||
void (*fini)(void), void (*rtld_fini)(void),
|
||||
void(*stack_end)) {
|
||||
|
||||
main_fn = main;
|
||||
intercept(main, on_main, NULL);
|
||||
return __libc_start_main(main, argc, ubp_av, init, fini, rtld_fini,
|
||||
stack_end);
|
||||
|
||||
}
|
||||
|
||||
static void intercept_main() {
|
||||
|
||||
intercept(__libc_start_main, on_libc_start_main, NULL);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
__attribute__((constructor)) static void init() {
|
||||
|
||||
gum_init_embedded();
|
||||
if (!gum_stalker_is_supported()) {
|
||||
|
||||
gum_deinit_embedded();
|
||||
FATAL("Failed to initialize embedded");
|
||||
|
||||
}
|
||||
|
||||
intercept_main();
|
||||
|
||||
}
|
||||
|
121
frida_mode/src/prefetch.c
Normal file
121
frida_mode/src/prefetch.c
Normal file
@ -0,0 +1,121 @@
|
||||
#include <errno.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "frida-gum.h"
|
||||
#include "prefetch.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define TRUST 0
|
||||
#define PREFETCH_SIZE 65536
|
||||
#define PREFETCH_ENTRIES ((PREFETCH_SIZE - sizeof(size_t)) / sizeof(void *))
|
||||
|
||||
typedef struct {
|
||||
|
||||
size_t count;
|
||||
void * entry[PREFETCH_ENTRIES];
|
||||
|
||||
} prefetch_data_t;
|
||||
|
||||
static prefetch_data_t *prefetch_data = NULL;
|
||||
|
||||
static int prefetch_shm_id = -1;
|
||||
|
||||
/*
|
||||
* We do this from the transformer since we need one anyway for coverage, this
|
||||
* saves the need to use an event sink.
|
||||
*/
|
||||
void prefetch_write(void *addr) {
|
||||
|
||||
/* Bail if we aren't initialized */
|
||||
if (prefetch_data == NULL) return;
|
||||
|
||||
/*
|
||||
* Our shared memory IPC is large enough for about 1000 entries, we can fine
|
||||
* tune this if we need to. But if we have more new blocks that this in a
|
||||
* single run then we ignore them and we'll pick them up next time.
|
||||
*/
|
||||
if (prefetch_data->count >= PREFETCH_ENTRIES) return;
|
||||
|
||||
/*
|
||||
* Write the block address to the SHM IPC and increment the number of entries.
|
||||
*/
|
||||
|
||||
prefetch_data->entry[prefetch_data->count] = addr;
|
||||
prefetch_data->count++;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the IPC region one block at the time and prefetch it
|
||||
*/
|
||||
void prefetch_read(GumStalker *stalker) {
|
||||
|
||||
if (prefetch_data == NULL) return;
|
||||
|
||||
for (size_t i = 0; i < prefetch_data->count; i++) {
|
||||
|
||||
void *addr = prefetch_data->entry[i];
|
||||
gum_stalker_prefetch(stalker, addr, 1);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the entry count to indicate we have finished with it and it can be
|
||||
* refilled by the child.
|
||||
*/
|
||||
prefetch_data->count = 0;
|
||||
|
||||
}
|
||||
|
||||
void prefetch_init() {
|
||||
|
||||
g_assert_cmpint(sizeof(prefetch_data_t), ==, PREFETCH_SIZE);
|
||||
gboolean prefetch = (getenv("AFL_FRIDA_INST_NO_PREFETCH") == NULL);
|
||||
|
||||
OKF("Instrumentation - prefetch [%c]", prefetch ? 'X' : ' ');
|
||||
|
||||
if (!prefetch) { return; }
|
||||
/*
|
||||
* Make our shared memory, we can attach before we fork, just like AFL does
|
||||
* with the coverage bitmap region and fork will take care of ensuring both
|
||||
* the parent and child see the same consistent memory region.
|
||||
*/
|
||||
prefetch_shm_id =
|
||||
shmget(IPC_PRIVATE, sizeof(prefetch_data_t), IPC_CREAT | IPC_EXCL | 0600);
|
||||
if (prefetch_shm_id < 0) {
|
||||
|
||||
FATAL("prefetch_shm_id < 0 - errno: %d\n", errno);
|
||||
|
||||
}
|
||||
|
||||
prefetch_data = shmat(prefetch_shm_id, NULL, 0);
|
||||
g_assert(prefetch_data != MAP_FAILED);
|
||||
|
||||
/*
|
||||
* Configure the shared memory region to be removed once the process dies.
|
||||
*/
|
||||
if (shmctl(prefetch_shm_id, IPC_RMID, NULL) < 0) {
|
||||
|
||||
FATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno);
|
||||
|
||||
}
|
||||
|
||||
/* Clear it, not sure it's necessary, just seems like good practice */
|
||||
memset(prefetch_data, '\0', sizeof(prefetch_data_t));
|
||||
|
||||
}
|
||||
|
||||
__attribute__((noinline)) static void prefetch_activation() {
|
||||
|
||||
asm volatile("");
|
||||
|
||||
}
|
||||
|
||||
void prefetch_start(GumStalker *stalker) {
|
||||
|
||||
gum_stalker_activate(stalker, prefetch_activation);
|
||||
prefetch_activation();
|
||||
|
||||
}
|
||||
|
395
frida_mode/src/ranges.c
Normal file
395
frida_mode/src/ranges.c
Normal file
@ -0,0 +1,395 @@
|
||||
// 0x123-0x321
|
||||
// module.so
|
||||
|
||||
#include "ranges.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define MAX_RANGES 20
|
||||
|
||||
typedef struct {
|
||||
|
||||
gchar * suffix;
|
||||
GumMemoryRange *range;
|
||||
gboolean done;
|
||||
|
||||
} convert_name_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
GumStalker *stalker;
|
||||
GArray * array;
|
||||
|
||||
} include_range_ctx_t;
|
||||
|
||||
GArray * ranges = NULL;
|
||||
gboolean exclude_ranges = false;
|
||||
|
||||
static void convert_address_token(gchar *token, GumMemoryRange *range) {
|
||||
|
||||
gchar **tokens;
|
||||
int token_count;
|
||||
tokens = g_strsplit(token, "-", 2);
|
||||
for (token_count = 0; tokens[token_count] != NULL; token_count++)
|
||||
;
|
||||
|
||||
if (token_count != 2) {
|
||||
|
||||
FATAL("Invalid range (should have two addresses seperated by a '-'): %s\n",
|
||||
token);
|
||||
|
||||
}
|
||||
|
||||
gchar *from_str = tokens[0];
|
||||
gchar *to_str = tokens[1];
|
||||
|
||||
if (!g_str_has_prefix(from_str, "0x")) {
|
||||
|
||||
FATAL("Invalid range: %s - Start address should have 0x prefix: %s\n",
|
||||
token, from_str);
|
||||
|
||||
}
|
||||
|
||||
if (!g_str_has_prefix(to_str, "0x")) {
|
||||
|
||||
FATAL("Invalid range: %s - End address should have 0x prefix: %s\n", token,
|
||||
to_str);
|
||||
|
||||
}
|
||||
|
||||
from_str = &from_str[2];
|
||||
to_str = &to_str[2];
|
||||
|
||||
for (char *c = from_str; *c != '\0'; c++) {
|
||||
|
||||
if (!g_ascii_isxdigit(*c)) {
|
||||
|
||||
FATAL("Invalid range: %s - Start address not formed of hex digits: %s\n",
|
||||
token, from_str);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (char *c = to_str; *c != '\0'; c++) {
|
||||
|
||||
if (!g_ascii_isxdigit(*c)) {
|
||||
|
||||
FATAL("Invalid range: %s - End address not formed of hex digits: %s\n",
|
||||
token, to_str);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
guint64 from = g_ascii_strtoull(from_str, NULL, 16);
|
||||
if (from == 0) {
|
||||
|
||||
FATAL("Invalid range: %s - Start failed hex conversion: %s\n", token,
|
||||
from_str);
|
||||
|
||||
}
|
||||
|
||||
guint64 to = g_ascii_strtoull(to_str, NULL, 16);
|
||||
if (to == 0) {
|
||||
|
||||
FATAL("Invalid range: %s - End failed hex conversion: %s\n", token, to_str);
|
||||
|
||||
}
|
||||
|
||||
if (from >= to) {
|
||||
|
||||
FATAL("Invalid range: %s - Start (0x%016" G_GINT64_MODIFIER
|
||||
"x) must be less than end "
|
||||
"(0x%016" G_GINT64_MODIFIER "x)\n",
|
||||
token, from, to);
|
||||
|
||||
}
|
||||
|
||||
range->base_address = from;
|
||||
range->size = to - from;
|
||||
|
||||
g_strfreev(tokens);
|
||||
|
||||
}
|
||||
|
||||
static gboolean convert_name_token_for_module(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
convert_name_ctx_t *ctx = (convert_name_ctx_t *)user_data;
|
||||
if (details->path == NULL) { return true; };
|
||||
|
||||
if (!g_str_has_suffix(details->path, ctx->suffix)) { return true; };
|
||||
|
||||
OKF("Found module - prefix: %s, 0x%016" G_GINT64_MODIFIER
|
||||
"x-0x%016" G_GINT64_MODIFIER "x %s",
|
||||
ctx->suffix, details->range->base_address,
|
||||
details->range->base_address + details->range->size, details->path);
|
||||
|
||||
*ctx->range = *details->range;
|
||||
ctx->done = true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
static void convert_name_token(gchar *token, GumMemoryRange *range) {
|
||||
|
||||
gchar * suffix = g_strconcat("/", token, NULL);
|
||||
convert_name_ctx_t ctx = {.suffix = suffix, .range = range, .done = false};
|
||||
|
||||
gum_process_enumerate_modules(convert_name_token_for_module, &ctx);
|
||||
if (!ctx.done) { FATAL("Failed to resolve module: %s\n", token); }
|
||||
g_free(suffix);
|
||||
|
||||
}
|
||||
|
||||
static void convert_token(gchar *token, GumMemoryRange *range) {
|
||||
|
||||
if (g_strrstr(token, "-")) {
|
||||
|
||||
convert_address_token(token, range);
|
||||
|
||||
} else {
|
||||
|
||||
convert_name_token(token, range);
|
||||
|
||||
}
|
||||
|
||||
OKF("Converted token: %s -> 0x%016" G_GINT64_MODIFIER
|
||||
"x-0x%016" G_GINT64_MODIFIER "x\n",
|
||||
token, range->base_address, range->base_address + range->size);
|
||||
|
||||
}
|
||||
|
||||
static gboolean include_ranges(const GumRangeDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
include_range_ctx_t *ctx = (include_range_ctx_t *)user_data;
|
||||
GArray * array = (GArray *)ctx->array;
|
||||
GumAddress base = details->range->base_address;
|
||||
GumAddress limit = details->range->base_address + details->range->size;
|
||||
|
||||
OKF("Range for inclusion 0x%016" G_GINT64_MODIFIER
|
||||
"x-0x%016" G_GINT64_MODIFIER "x",
|
||||
base, limit);
|
||||
|
||||
for (int i = 0; i < array->len; i++) {
|
||||
|
||||
GumMemoryRange *range = &g_array_index(array, GumMemoryRange, i);
|
||||
GumAddress range_base = range->base_address;
|
||||
GumAddress range_limit = range->base_address + range->size;
|
||||
|
||||
/* Before the region */
|
||||
if (range_limit < base) { continue; }
|
||||
|
||||
/* After the region */
|
||||
if (range_base > limit) {
|
||||
|
||||
GumMemoryRange exclude = {.base_address = base, .size = limit - base};
|
||||
OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER
|
||||
"x",
|
||||
base, limit);
|
||||
gum_stalker_exclude(ctx->stalker, &exclude);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/* Overlap the start of the region */
|
||||
if (range_base < base) {
|
||||
|
||||
/* Range contains the region */
|
||||
if (range_limit > limit) {
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
base = range_limit;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
/* Overlap the end of the region */
|
||||
|
||||
} else {
|
||||
|
||||
GumMemoryRange exclude = {.base_address = base,
|
||||
.size = range_base - base};
|
||||
OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER
|
||||
"x",
|
||||
base, range_base);
|
||||
gum_stalker_exclude(ctx->stalker, &exclude);
|
||||
/* Extend past the end of the region */
|
||||
if (range_limit >= limit) {
|
||||
|
||||
return true;
|
||||
|
||||
/* Contained within the region */
|
||||
|
||||
} else {
|
||||
|
||||
base = range_limit;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GumMemoryRange exclude = {.base_address = base, .size = limit - base};
|
||||
OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER "x",
|
||||
base, limit);
|
||||
gum_stalker_exclude(ctx->stalker, &exclude);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
gint range_sort(gconstpointer a, gconstpointer b) {
|
||||
|
||||
return ((GumMemoryRange *)a)->base_address -
|
||||
((GumMemoryRange *)b)->base_address;
|
||||
|
||||
}
|
||||
|
||||
static gboolean print_ranges(const GumRangeDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
if (details->file == NULL) {
|
||||
|
||||
OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER "X",
|
||||
details->range->base_address,
|
||||
details->range->base_address + details->range->size);
|
||||
|
||||
} else {
|
||||
|
||||
OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER
|
||||
"X %s(0x%016" G_GINT64_MODIFIER "x)",
|
||||
details->range->base_address,
|
||||
details->range->base_address + details->range->size,
|
||||
details->file->path, details->file->offset);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void ranges_init(GumStalker *stalker) {
|
||||
|
||||
char * showmaps;
|
||||
char * include;
|
||||
char * exclude;
|
||||
char * list;
|
||||
gchar ** tokens;
|
||||
int token_count;
|
||||
GumMemoryRange range;
|
||||
|
||||
int i;
|
||||
|
||||
showmaps = getenv("AFL_FRIDA_DEBUG_MAPS");
|
||||
include = getenv("AFL_FRIDA_INST_RANGES");
|
||||
exclude = getenv("AFL_FRIDA_EXCLUDE_RANGES");
|
||||
|
||||
if (showmaps) {
|
||||
|
||||
gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges, NULL);
|
||||
|
||||
}
|
||||
|
||||
if (include != NULL && exclude != NULL) {
|
||||
|
||||
FATAL(
|
||||
"Cannot specifify both AFL_FRIDA_INST_RANGES and "
|
||||
"AFL_FRIDA_EXCLUDE_RANGES");
|
||||
|
||||
}
|
||||
|
||||
if (include == NULL && exclude == NULL) { return; }
|
||||
|
||||
list = include == NULL ? exclude : include;
|
||||
exclude_ranges = include == NULL ? true : false;
|
||||
|
||||
tokens = g_strsplit(list, ",", MAX_RANGES);
|
||||
|
||||
for (token_count = 0; tokens[token_count] != NULL; token_count++)
|
||||
;
|
||||
|
||||
ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), token_count);
|
||||
|
||||
for (i = 0; i < token_count; i++) {
|
||||
|
||||
convert_token(tokens[i], &range);
|
||||
g_array_append_val(ranges, range);
|
||||
|
||||
}
|
||||
|
||||
g_array_sort(ranges, range_sort);
|
||||
|
||||
/* Check for overlaps */
|
||||
for (i = 1; i < token_count; i++) {
|
||||
|
||||
GumMemoryRange *prev = &g_array_index(ranges, GumMemoryRange, i - 1);
|
||||
GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i);
|
||||
GumAddress prev_limit = prev->base_address + prev->size;
|
||||
GumAddress curr_limit = curr->base_address + curr->size;
|
||||
if (prev_limit > curr->base_address) {
|
||||
|
||||
FATAL("OVerlapping ranges 0x%016" G_GINT64_MODIFIER
|
||||
"x-0x%016" G_GINT64_MODIFIER "x 0x%016" G_GINT64_MODIFIER
|
||||
"x-0x%016" G_GINT64_MODIFIER "x",
|
||||
prev->base_address, prev_limit, curr->base_address, curr_limit);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < token_count; i++) {
|
||||
|
||||
GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i);
|
||||
GumAddress curr_limit = curr->base_address + curr->size;
|
||||
OKF("Range %3d - 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER "x",
|
||||
i, curr->base_address, curr_limit);
|
||||
|
||||
}
|
||||
|
||||
if (include == NULL) {
|
||||
|
||||
for (i = 0; i < token_count; i++) {
|
||||
|
||||
gum_stalker_exclude(stalker, &g_array_index(ranges, GumMemoryRange, i));
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
include_range_ctx_t ctx = {.stalker = stalker, .array = ranges};
|
||||
gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, include_ranges, &ctx);
|
||||
|
||||
}
|
||||
|
||||
g_strfreev(tokens);
|
||||
|
||||
}
|
||||
|
||||
gboolean range_is_excluded(gpointer address) {
|
||||
|
||||
int i;
|
||||
GumAddress test = GUM_ADDRESS(address);
|
||||
|
||||
if (ranges == NULL) { return false; }
|
||||
|
||||
for (i = 0; i < ranges->len; i++) {
|
||||
|
||||
GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i);
|
||||
GumAddress curr_limit = curr->base_address + curr->size;
|
||||
|
||||
if (test < curr->base_address) { return !exclude_ranges; }
|
||||
|
||||
if (test < curr_limit) { return exclude_ranges; }
|
||||
|
||||
}
|
||||
|
||||
return !exclude_ranges;
|
||||
|
||||
}
|
||||
|
105
frida_mode/test/testinstr.c
Normal file
105
frida_mode/test/testinstr.c
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
american fuzzy lop++ - a trivial program to test the build
|
||||
--------------------------------------------------------
|
||||
Originally written by Michal Zalewski
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 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:
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define TESTINSTR_SECTION
|
||||
#else
|
||||
#define TESTINSTR_SECTION __attribute__((section(".testinstr")))
|
||||
#endif
|
||||
|
||||
TESTINSTR_SECTION void testinstr(char *buf, int len) {
|
||||
|
||||
if (len < 1) return;
|
||||
buf[len] = 0;
|
||||
|
||||
// we support three input cases
|
||||
if (buf[0] == '0')
|
||||
printf("Looks like a zero to me!\n");
|
||||
else if (buf[0] == '1')
|
||||
printf("Pretty sure that is a one!\n");
|
||||
else
|
||||
printf("Neither one or zero? How quaint!\n");
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
char * file;
|
||||
int fd = -1;
|
||||
off_t len;
|
||||
char * buf = NULL;
|
||||
size_t n_read;
|
||||
int result = -1;
|
||||
|
||||
if (argc != 2) { return 1; }
|
||||
|
||||
do {
|
||||
|
||||
file = argv[1];
|
||||
|
||||
dprintf(STDERR_FILENO, "Running: %s\n", file);
|
||||
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
|
||||
perror("open");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
len = lseek(fd, 0, SEEK_END);
|
||||
if (len < 0) {
|
||||
|
||||
perror("lseek (SEEK_END)");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (lseek(fd, 0, SEEK_SET) != 0) {
|
||||
|
||||
perror("lseek (SEEK_SET)");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
buf = malloc(len);
|
||||
n_read = read(fd, buf, len);
|
||||
if (n_read != len) {
|
||||
|
||||
perror("read");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read);
|
||||
|
||||
testinstr(buf, len);
|
||||
dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read);
|
||||
|
||||
result = 0;
|
||||
|
||||
} while (false);
|
||||
|
||||
if (buf != NULL) { free(buf); }
|
||||
|
||||
if (fd != -1) { close(fd); }
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
32
frida_mode/test/testinstr.py
Executable file
32
frida_mode/test/testinstr.py
Executable file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/python3
|
||||
import argparse
|
||||
from elftools.elf.elffile import ELFFile
|
||||
|
||||
def process_file(file, section, base):
|
||||
with open(file, 'rb') as f:
|
||||
for sect in ELFFile(f).iter_sections():
|
||||
if (sect.name == section):
|
||||
start = base + sect.header['sh_offset']
|
||||
end = start + sect.header['sh_size']
|
||||
print ("0x%016x-0x%016x" % (start, end))
|
||||
return
|
||||
|
||||
print ("Section '%s' not found in '%s'" % (section, file))
|
||||
|
||||
def hex_value(x):
|
||||
return int(x, 16)
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Process some integers.')
|
||||
parser.add_argument('-f', '--file', dest='file', type=str,
|
||||
help='elf file name', required=True)
|
||||
parser.add_argument('-s', '--section', dest='section', type=str,
|
||||
help='elf section name', required=True)
|
||||
parser.add_argument('-b', '--base', dest='base', type=hex_value,
|
||||
help='elf base address', required=True)
|
||||
|
||||
args = parser.parse_args()
|
||||
process_file (args.file, args.section, args.base)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -50,6 +50,13 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_EXIT_WHEN_DONE",
|
||||
"AFL_FAST_CAL",
|
||||
"AFL_FORCE_UI",
|
||||
"AFL_FRIDA_DEBUG_MAPS",
|
||||
"AFL_FRIDA_EXCLUDE_RANGES",
|
||||
"AFL_FRIDA_INST_NO_OPTIMIZE",
|
||||
"AFL_FRIDA_INST_NO_PREFETCH",
|
||||
"AFL_FRIDA_INST_RANGES",
|
||||
"AFL_FRIDA_INST_STRICT",
|
||||
"AFL_FRIDA_INST_TRACE",
|
||||
"AFL_FUZZER_ARGS", // oss-fuzz
|
||||
"AFL_GDB",
|
||||
"AFL_GCC_ALLOWLIST",
|
||||
|
@ -77,6 +77,8 @@ typedef struct afl_forkserver {
|
||||
|
||||
bool qemu_mode; /* if running in qemu mode or not */
|
||||
|
||||
bool frida_mode; /* if running in frida mode or not */
|
||||
|
||||
bool use_stdin; /* use stdin for sending data */
|
||||
|
||||
bool no_unlink; /* do not unlink cur_input */
|
||||
|
@ -83,6 +83,7 @@ static volatile u8 stop_soon, /* Ctrl-C pressed? */
|
||||
child_timed_out; /* Child timed out? */
|
||||
|
||||
static u8 *target_path;
|
||||
static u8 frida_mode;
|
||||
static u8 qemu_mode;
|
||||
static u32 map_size = MAP_SIZE;
|
||||
|
||||
@ -717,9 +718,11 @@ static void handle_stop_sig(int sig) {
|
||||
|
||||
/* Do basic preparations - persistent fds, filenames, etc. */
|
||||
|
||||
static void set_up_environment(void) {
|
||||
static void set_up_environment(char **argv) {
|
||||
|
||||
u8 *x;
|
||||
u8 * x;
|
||||
char *afl_preload;
|
||||
char *frida_afl_preload = NULL;
|
||||
|
||||
dev_null_fd = open("/dev/null", O_RDWR);
|
||||
if (dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
|
||||
@ -824,6 +827,25 @@ static void set_up_environment(void) {
|
||||
|
||||
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
|
||||
|
||||
} else if (frida_mode) {
|
||||
|
||||
afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
if (afl_preload) {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
|
||||
|
||||
} else {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s", frida_binary);
|
||||
|
||||
}
|
||||
|
||||
ck_free(frida_binary);
|
||||
|
||||
setenv("LD_PRELOAD", frida_afl_preload, 1);
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
|
||||
|
||||
} else {
|
||||
|
||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||
@ -831,8 +853,17 @@ static void set_up_environment(void) {
|
||||
|
||||
}
|
||||
|
||||
} else if (frida_mode) {
|
||||
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
setenv("LD_PRELOAD", frida_binary, 1);
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
|
||||
ck_free(frida_binary);
|
||||
|
||||
}
|
||||
|
||||
if (frida_afl_preload) { ck_free(frida_afl_preload); }
|
||||
|
||||
}
|
||||
|
||||
/* Setup signal handlers, duh. */
|
||||
@ -872,6 +903,7 @@ static void usage(u8 *argv0) {
|
||||
" -f file - input file read by the tested program (stdin)\n"
|
||||
" -t msec - timeout for each run (%u ms)\n"
|
||||
" -m megs - memory limit for child process (%u MB)\n"
|
||||
" -O - use binary-only instrumentation (FRIDA mode)\n"
|
||||
" -Q - use binary-only instrumentation (QEMU mode)\n"
|
||||
" -U - use unicorn-based instrumentation (Unicorn mode)\n"
|
||||
" -W - use qemu-based instrumentation with Wine (Wine "
|
||||
@ -914,7 +946,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
SAYF(cCYA "afl-analyze" VERSION cRST " by Michal Zalewski\n");
|
||||
|
||||
while ((opt = getopt(argc, argv, "+i:f:m:t:eQUWh")) > 0) {
|
||||
while ((opt = getopt(argc, argv, "+i:f:m:t:eOQUWh")) > 0) {
|
||||
|
||||
switch (opt) {
|
||||
|
||||
@ -1008,6 +1040,14 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
break;
|
||||
|
||||
case 'O': /* FRIDA mode */
|
||||
|
||||
if (frida_mode) { FATAL("Multiple -O options not supported"); }
|
||||
|
||||
frida_mode = 1;
|
||||
|
||||
break;
|
||||
|
||||
case 'Q':
|
||||
|
||||
if (qemu_mode) { FATAL("Multiple -Q options not supported"); }
|
||||
@ -1062,7 +1102,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
atexit(at_exit_handler);
|
||||
setup_signal_handlers();
|
||||
|
||||
set_up_environment();
|
||||
set_up_environment(argv);
|
||||
|
||||
target_path = find_binary(argv[optind]);
|
||||
detect_file_args(argv + optind, prog_in, &use_stdin);
|
||||
|
@ -2692,7 +2692,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
|
||||
|
||||
#endif /* ^!__APPLE__ */
|
||||
|
||||
if (!afl->fsrv.qemu_mode && !afl->unicorn_mode &&
|
||||
if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode && !afl->unicorn_mode &&
|
||||
!afl->non_instrumented_mode &&
|
||||
!memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
|
||||
|
||||
@ -2720,7 +2720,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
|
||||
|
||||
}
|
||||
|
||||
if ((afl->fsrv.qemu_mode) &&
|
||||
if ((afl->fsrv.qemu_mode || afl->fsrv.frida_mode) &&
|
||||
memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
@ -2757,7 +2757,8 @@ void check_binary(afl_state_t *afl, u8 *fname) {
|
||||
|
||||
}
|
||||
|
||||
if (memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
|
||||
if (afl->fsrv.frida_mode ||
|
||||
memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
|
||||
|
||||
OKF(cPIN "Deferred forkserver binary detected.");
|
||||
setenv(DEFER_ENV_VAR, "1", 1);
|
||||
|
@ -109,6 +109,7 @@ static void usage(u8 *argv0, int more_help) {
|
||||
"maximum.\n"
|
||||
" -m megs - memory limit for child process (%u MB, 0 = no limit "
|
||||
"[default])\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"
|
||||
" -W - use qemu-based instrumentation with Wine (Wine "
|
||||
@ -329,6 +330,8 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
u8 *extras_dir[4];
|
||||
u8 mem_limit_given = 0, exit_1 = 0, debug = 0,
|
||||
extras_dir_cnt = 0 /*, have_p = 0*/;
|
||||
char * afl_preload;
|
||||
char * frida_afl_preload = NULL;
|
||||
char **use_argv;
|
||||
|
||||
struct timeval tv;
|
||||
@ -372,7 +375,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
while ((opt = getopt(
|
||||
argc, argv,
|
||||
"+b:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNo:p:RQs:S:t:T:UV:Wx:Z")) > 0) {
|
||||
"+b:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNOo:p:RQs:S:t:T:UV:Wx:Z")) > 0) {
|
||||
|
||||
switch (opt) {
|
||||
|
||||
@ -764,6 +767,18 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
afl->use_banner = optarg;
|
||||
break;
|
||||
|
||||
case 'O': /* FRIDA mode */
|
||||
|
||||
if (afl->fsrv.frida_mode) {
|
||||
|
||||
FATAL("Multiple -O options not supported");
|
||||
|
||||
}
|
||||
|
||||
afl->fsrv.frida_mode = 1;
|
||||
|
||||
break;
|
||||
|
||||
case 'Q': /* QEMU mode */
|
||||
|
||||
if (afl->fsrv.qemu_mode) { FATAL("Multiple -Q options not supported"); }
|
||||
@ -1118,6 +1133,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
if (afl->non_instrumented_mode) {
|
||||
|
||||
if (afl->crash_mode) { FATAL("-C and -n are mutually exclusive"); }
|
||||
if (afl->fsrv.frida_mode) { FATAL("-O and -n are mutually exclusive"); }
|
||||
if (afl->fsrv.qemu_mode) { FATAL("-Q and -n are mutually exclusive"); }
|
||||
if (afl->unicorn_mode) { FATAL("-U and -n are mutually exclusive"); }
|
||||
|
||||
@ -1322,6 +1338,25 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
|
||||
|
||||
} else if (afl->fsrv.frida_mode) {
|
||||
|
||||
afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
if (afl_preload) {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
|
||||
|
||||
} else {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s", frida_binary);
|
||||
|
||||
}
|
||||
|
||||
ck_free(frida_binary);
|
||||
|
||||
setenv("LD_PRELOAD", frida_afl_preload, 1);
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
|
||||
|
||||
} else {
|
||||
|
||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||
@ -1329,6 +1364,13 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
} else if (afl->fsrv.frida_mode) {
|
||||
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
setenv("LD_PRELOAD", frida_binary, 1);
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
|
||||
ck_free(frida_binary);
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LD_PRELOAD")) {
|
||||
@ -1512,7 +1554,8 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (!afl->fsrv.qemu_mode && !afl->non_instrumented_mode) {
|
||||
if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode &&
|
||||
!afl->non_instrumented_mode) {
|
||||
|
||||
check_binary(afl, afl->cmplog_binary);
|
||||
|
||||
@ -1563,7 +1606,8 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->non_instrumented_mode || afl->fsrv.qemu_mode || afl->unicorn_mode) {
|
||||
if (afl->non_instrumented_mode || afl->fsrv.qemu_mode ||
|
||||
afl->fsrv.frida_mode || afl->unicorn_mode) {
|
||||
|
||||
map_size = afl->fsrv.map_size = MAP_SIZE;
|
||||
afl->virgin_bits = ck_realloc(afl->virgin_bits, map_size);
|
||||
@ -2124,6 +2168,8 @@ stop_fuzzing:
|
||||
|
||||
}
|
||||
|
||||
if (frida_afl_preload) { ck_free(frida_afl_preload); }
|
||||
|
||||
fclose(afl->fsrv.plot_file);
|
||||
destroy_queue(afl);
|
||||
destroy_extras(afl);
|
||||
|
@ -555,8 +555,10 @@ static void handle_stop_sig(int sig) {
|
||||
|
||||
/* Do basic preparations - persistent fds, filenames, etc. */
|
||||
|
||||
static void set_up_environment(afl_forkserver_t *fsrv) {
|
||||
static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
|
||||
|
||||
char *afl_preload;
|
||||
char *frida_afl_preload = NULL;
|
||||
setenv("ASAN_OPTIONS",
|
||||
"abort_on_error=1:"
|
||||
"detect_leaks=0:"
|
||||
@ -600,6 +602,25 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
|
||||
|
||||
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
|
||||
|
||||
} else if (fsrv->frida_mode) {
|
||||
|
||||
afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
if (afl_preload) {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
|
||||
|
||||
} else {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s", frida_binary);
|
||||
|
||||
}
|
||||
|
||||
ck_free(frida_binary);
|
||||
|
||||
setenv("LD_PRELOAD", frida_afl_preload, 1);
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
|
||||
|
||||
} else {
|
||||
|
||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||
@ -607,8 +628,17 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
|
||||
|
||||
}
|
||||
|
||||
} else if (fsrv->frida_mode) {
|
||||
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
setenv("LD_PRELOAD", frida_binary, 1);
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
|
||||
ck_free(frida_binary);
|
||||
|
||||
}
|
||||
|
||||
if (frida_afl_preload) { ck_free(frida_afl_preload); }
|
||||
|
||||
}
|
||||
|
||||
/* Setup signal handlers, duh. */
|
||||
@ -655,6 +685,7 @@ static void usage(u8 *argv0) {
|
||||
"Execution control settings:\n"
|
||||
" -t msec - timeout for each run (none)\n"
|
||||
" -m megs - memory limit for child process (%u MB)\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"
|
||||
" -W - use qemu-based instrumentation with Wine (Wine mode)\n"
|
||||
@ -723,7 +754,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
if (getenv("AFL_QUIET") != NULL) { be_quiet = 1; }
|
||||
|
||||
while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZQUWbcrsh")) > 0) {
|
||||
while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZOQUWbcrsh")) > 0) {
|
||||
|
||||
switch (opt) {
|
||||
|
||||
@ -857,6 +888,14 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
at_file = optarg;
|
||||
break;
|
||||
|
||||
case 'O': /* FRIDA mode */
|
||||
|
||||
if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); }
|
||||
|
||||
fsrv->frida_mode = 1;
|
||||
|
||||
break;
|
||||
|
||||
case 'Q':
|
||||
|
||||
if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); }
|
||||
@ -943,7 +982,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
shm.cmplog_mode = 0;
|
||||
setup_signal_handlers();
|
||||
|
||||
set_up_environment(fsrv);
|
||||
set_up_environment(fsrv, argv);
|
||||
|
||||
fsrv->target_path = find_binary(argv[optind]);
|
||||
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
|
||||
|
@ -640,9 +640,11 @@ static void handle_stop_sig(int sig) {
|
||||
|
||||
/* Do basic preparations - persistent fds, filenames, etc. */
|
||||
|
||||
static void set_up_environment(afl_forkserver_t *fsrv) {
|
||||
static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
|
||||
|
||||
u8 *x;
|
||||
u8 * x;
|
||||
char *afl_preload;
|
||||
char *frida_afl_preload = NULL;
|
||||
|
||||
fsrv->dev_null_fd = open("/dev/null", O_RDWR);
|
||||
if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
|
||||
@ -755,6 +757,25 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
|
||||
|
||||
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
|
||||
|
||||
} else if (fsrv->frida_mode) {
|
||||
|
||||
afl_preload = getenv("AFL_PRELOAD");
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
if (afl_preload) {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
|
||||
|
||||
} else {
|
||||
|
||||
frida_afl_preload = alloc_printf("%s", frida_binary);
|
||||
|
||||
}
|
||||
|
||||
ck_free(frida_binary);
|
||||
|
||||
setenv("LD_PRELOAD", frida_afl_preload, 1);
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
|
||||
|
||||
} else {
|
||||
|
||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||
@ -762,8 +783,17 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
|
||||
|
||||
}
|
||||
|
||||
} else if (fsrv->frida_mode) {
|
||||
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
setenv("LD_PRELOAD", frida_binary, 1);
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
|
||||
ck_free(frida_binary);
|
||||
|
||||
}
|
||||
|
||||
if (frida_afl_preload) { ck_free(frida_afl_preload); }
|
||||
|
||||
}
|
||||
|
||||
/* Setup signal handlers, duh. */
|
||||
@ -804,6 +834,7 @@ static void usage(u8 *argv0) {
|
||||
" -f file - input file read by the tested program (stdin)\n"
|
||||
" -t msec - timeout for each run (%u ms)\n"
|
||||
" -m megs - memory limit for child process (%u MB)\n"
|
||||
" -O - use binary-only instrumentation (FRIDA mode)\n"
|
||||
" -Q - use binary-only instrumentation (QEMU mode)\n"
|
||||
" -U - use unicorn-based instrumentation (Unicorn mode)\n"
|
||||
" -W - use qemu-based instrumentation with Wine (Wine "
|
||||
@ -859,7 +890,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n");
|
||||
|
||||
while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeQUWHh")) > 0) {
|
||||
while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeOQUWHh")) > 0) {
|
||||
|
||||
switch (opt) {
|
||||
|
||||
@ -971,6 +1002,14 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
break;
|
||||
|
||||
case 'O': /* FRIDA mode */
|
||||
|
||||
if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); }
|
||||
|
||||
fsrv->frida_mode = 1;
|
||||
|
||||
break;
|
||||
|
||||
case 'Q':
|
||||
|
||||
if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); }
|
||||
@ -1054,7 +1093,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
atexit(at_exit_handler);
|
||||
setup_signal_handlers();
|
||||
|
||||
set_up_environment(fsrv);
|
||||
set_up_environment(fsrv, argv);
|
||||
|
||||
fsrv->target_path = find_binary(argv[optind]);
|
||||
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user