From 86a8ef168dda766d2f25f15c15c4d3ecf21d0667 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 16 Apr 2021 22:58:54 +0200 Subject: fix custom trim for increasing data --- src/afl-fuzz-mutators.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index a47b4f5f..c99d9a4d 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -397,8 +397,14 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, if (likely(retlen && cksum == q->exec_cksum)) { - q->len = retlen; + if (afl_realloc((void **)&in_buf, retlen) == NULL) { + + FATAL("can not allocate memory for trim"); + + } + memcpy(in_buf, retbuf, retlen); + q->len = retlen; /* Let's save a clean trace, which will be needed by update_bitmap_score once we're done with the trimming stuff. */ -- cgit 1.4.1 From 39ad3b89467d6de12cbb9d08ccd77d331c0d1f9e Mon Sep 17 00:00:00 2001 From: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Date: Wed, 28 Apr 2021 09:25:26 +0100 Subject: Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name --- frida_mode/GNUmakefile | 88 ++++ frida_mode/Makefile | 349 +--------------- frida_mode/README.md | 103 +++-- frida_mode/include/complog.h | 9 + frida_mode/include/instrument.h | 17 +- frida_mode/include/interceptor.h | 2 + frida_mode/include/lib.h | 8 + frida_mode/include/persistent.h | 26 ++ frida_mode/include/prefetch.h | 7 +- frida_mode/include/ranges.h | 2 +- frida_mode/include/stalker.h | 8 + frida_mode/include/util.h | 6 + frida_mode/src/complog/complog.c | 72 ++++ frida_mode/src/complog/complog_arm.c | 15 + frida_mode/src/complog/complog_arm64.c | 15 + frida_mode/src/complog/complog_x64.c | 363 ++++++++++++++++ frida_mode/src/complog/complog_x86.c | 15 + frida_mode/src/instrument.c | 271 ------------ frida_mode/src/instrument/instrument.c | 150 +++++++ frida_mode/src/instrument/instrument_arm32.c | 23 ++ frida_mode/src/instrument/instrument_arm64.c | 97 +++++ frida_mode/src/instrument/instrument_x64.c | 93 +++++ frida_mode/src/instrument/instrument_x86.c | 23 ++ frida_mode/src/interceptor.c | 19 + frida_mode/src/lib.c | 167 ++++++++ frida_mode/src/main.c | 59 +-- frida_mode/src/persistent/persistent.c | 68 +++ frida_mode/src/persistent/persistent_arm32.c | 70 ++++ frida_mode/src/persistent/persistent_arm64.c | 113 +++++ frida_mode/src/persistent/persistent_x64.c | 337 +++++++++++++++ frida_mode/src/persistent/persistent_x86.c | 53 +++ frida_mode/src/prefetch.c | 23 +- frida_mode/src/ranges.c | 457 ++++++++++++++------- frida_mode/src/stalker.c | 49 +++ frida_mode/src/util.c | 66 +++ frida_mode/test/cmplog/GNUmakefile | 66 +++ frida_mode/test/cmplog/Makefile | 12 + frida_mode/test/cmplog/get_section_addrs.py | 49 +++ frida_mode/test/png/GNUmakefile | 106 +++++ frida_mode/test/png/Makefile | 12 + frida_mode/test/png/persistent/GNUmakefile | 54 +++ frida_mode/test/png/persistent/Makefile | 12 + frida_mode/test/png/persistent/get_symbol_addr.py | 36 ++ frida_mode/test/png/persistent/hook/GNUmakefile | 70 ++++ frida_mode/test/png/persistent/hook/Makefile | 12 + frida_mode/test/testinstr.c | 112 ----- frida_mode/test/testinstr.py | 49 --- frida_mode/test/testinstr/GNUmakefile | 50 +++ frida_mode/test/testinstr/Makefile | 12 + frida_mode/test/testinstr/testinstr.c | 112 +++++ include/envs.h | 3 + instrumentation/afl-compiler-rt.o.c | 15 +- instrumentation/afl-llvm-lto-instrumentation.so.cc | 8 +- qemu_mode/qemuafl | 2 +- src/afl-forkserver.c | 3 +- src/afl-fuzz-cmplog.c | 2 +- src/afl-fuzz-init.c | 8 + src/afl-fuzz.c | 3 +- 58 files changed, 3023 insertions(+), 1028 deletions(-) create mode 100644 frida_mode/GNUmakefile create mode 100644 frida_mode/include/complog.h create mode 100644 frida_mode/include/lib.h create mode 100644 frida_mode/include/persistent.h create mode 100644 frida_mode/include/stalker.h create mode 100644 frida_mode/include/util.h create mode 100644 frida_mode/src/complog/complog.c create mode 100644 frida_mode/src/complog/complog_arm.c create mode 100644 frida_mode/src/complog/complog_arm64.c create mode 100644 frida_mode/src/complog/complog_x64.c create mode 100644 frida_mode/src/complog/complog_x86.c delete mode 100644 frida_mode/src/instrument.c create mode 100644 frida_mode/src/instrument/instrument.c create mode 100644 frida_mode/src/instrument/instrument_arm32.c create mode 100644 frida_mode/src/instrument/instrument_arm64.c create mode 100644 frida_mode/src/instrument/instrument_x64.c create mode 100644 frida_mode/src/instrument/instrument_x86.c create mode 100644 frida_mode/src/lib.c create mode 100644 frida_mode/src/persistent/persistent.c create mode 100644 frida_mode/src/persistent/persistent_arm32.c create mode 100644 frida_mode/src/persistent/persistent_arm64.c create mode 100644 frida_mode/src/persistent/persistent_x64.c create mode 100644 frida_mode/src/persistent/persistent_x86.c create mode 100644 frida_mode/src/stalker.c create mode 100644 frida_mode/src/util.c create mode 100644 frida_mode/test/cmplog/GNUmakefile create mode 100644 frida_mode/test/cmplog/Makefile create mode 100755 frida_mode/test/cmplog/get_section_addrs.py create mode 100644 frida_mode/test/png/GNUmakefile create mode 100644 frida_mode/test/png/Makefile create mode 100644 frida_mode/test/png/persistent/GNUmakefile create mode 100644 frida_mode/test/png/persistent/Makefile create mode 100755 frida_mode/test/png/persistent/get_symbol_addr.py create mode 100644 frida_mode/test/png/persistent/hook/GNUmakefile create mode 100644 frida_mode/test/png/persistent/hook/Makefile delete mode 100644 frida_mode/test/testinstr.c delete mode 100755 frida_mode/test/testinstr.py create mode 100644 frida_mode/test/testinstr/GNUmakefile create mode 100644 frida_mode/test/testinstr/Makefile create mode 100644 frida_mode/test/testinstr/testinstr.c (limited to 'src') diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile new file mode 100644 index 00000000..51107910 --- /dev/null +++ b/frida_mode/GNUmakefile @@ -0,0 +1,88 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)..)/ +INC_DIR:=$(PWD)include/ +SRC_DIR:=$(PWD)src/ +INCLUDES:=$(wildcard $(INC_DIR)*.h) +SOURCES:=$(wildcard $(SRC_DIR)**/*.c) $(wildcard $(SRC_DIR)*.c) +BUILD_DIR:=$(PWD)build/ +CFLAGS+=-fPIC -D_GNU_SOURCE -Wno-prio-ctor-dtor + +FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/ +FRIDA_TRACE:=$(BUILD_DIR)afl-frida-trace.so +FRIDA_TRACE_EMBEDDED:=$(BUILD_DIR)afl-frida-trace-embedded + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(shell uname)" "Darwin" + OS:=macos + CFLAGS:=$(CFLAGS) -Wno-deprecated-declarations +endif + +ifeq "$(shell uname)" "Linux" + OS:=linux +endif + +ifndef OS + $(error "Operating system unsupported") +endif + +GUM_DEVKIT_VERSION=14.2.17 +GUM_DEVKIT_FILENAME=frida-gum-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz +GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_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/ + + +.PHONY: all clean format + +############################# FRIDA ############################################ + +all: $(FRIDA_TRACE) + make -C $(ROOT) + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +$(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) $(QEMU_INC_API) Makefile | $(BUILD_DIR) + $(CC) -shared \ + $(CFLAGS) \ + -o $@ \ + $(SOURCES) \ + $(GUM_DEVIT_LIBRARY) \ + -I $(FRIDA_BUILD_DIR) \ + -I $(ROOT) \ + -I $(ROOT)include \ + -I $(INC_DIR) \ + $(ROOT)instrumentation/afl-compiler-rt.o.c \ + -lpthread -ldl -lresolv -lelf + + cp -v $(FRIDA_TRACE) $(ROOT) + +############################# CLEAN ############################################ +clean: + rm -rf $(BUILD_DIR) + +############################# FORMAT ########################################### +format: + cd $(ROOT) && echo $(SOURCES) | xargs -L1 ./.custom-format.py -i + cd $(ROOT) && echo $(INCLUDES) | xargs -L1 ./.custom-format.py -i + +############################# RUN ############################################# diff --git a/frida_mode/Makefile b/frida_mode/Makefile index 822f1c6a..b6d64bff 100644 --- a/frida_mode/Makefile +++ b/frida_mode/Makefile @@ -1,348 +1,9 @@ -PWD:=$(shell pwd)/ -INC_DIR:=$(PWD)include/ -SRC_DIR:=$(PWD)src/ -INCLUDES:=$(wildcard $(INC_DIR)*.h) -SOURCES:=$(wildcard $(SRC_DIR)*.c) -BUILD_DIR:=$(PWD)build/ -CFLAGS+=-fPIC -D_GNU_SOURCE +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake -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) + @gmake clean -############################# 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) @@ + @gmake format diff --git a/frida_mode/README.md b/frida_mode/README.md index 8abee0dd..0d655d0f 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -10,23 +10,23 @@ 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 | | +As FRIDA mode is new, it is missing a lot of features. 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 | Notes | + | -------------------------|:----------:|:---------------------------------------:| + | NeverZero | x | | + | Persistent Mode | x | (x64 only)(Only on function boundaries) | + | LAF-Intel / CompCov | - | (Superseded by CmpLog) | + | CmpLog | x | (x64 only) | + | Selective Instrumentation| x | | + | Non-Colliding Coverage | - | | + | Ngram prev_loc Coverage | - | | + | Context Coverage | - | | + | Auto Dictionary | - | | + | Snapshot LKM Support | - | | + | In-Memory Test Cases | x |(x64 only) | # Compatibility Currently FRIDA mode supports Linux and macOS targets on both x86/x64 @@ -40,8 +40,9 @@ 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`. +Various tests can be found in subfolders within the `test/` directory. To use +these, first run `make` to build any dependencies. Then run `make qemu` or +`make frida` to run on either QEMU of FRIDA mode respectively. ## Usage FRIDA mode requires some small modifications to `afl-fuzz` and similar tools @@ -58,32 +59,32 @@ 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` +* `AFL_FRIDA_PERSISTENT_ADDR` - See `AFL_QEMU_PERSISTENT_ADDR` +* `AFL_FRIDA_PERSISTENT_CNT` - See `AFL_QEMU_PERSISTENT_CNT` +* `AFL_FRIDA_PERSISTENT_HOOK` - See `AFL_QEMU_PERSISTENT_HOOK` + # 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 +comparison between the two approaches. Accordingly, FRIDA mode includes various +tests 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. +from the llvm project. These tests include basic fork-server support, persistent mode +and persistent mode with in-memory test-cases. These are built and linked without +any special modifications to suit FRIDA or QEMU. The test data provided with libpng +is used as the 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 more -accurate results. +The intention is to add support for FRIDA mode to the FuzzBench project and +perform a like-for-like comparison with QEMU mode to get an accurate +appreciation of its performance. 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. +reproduce these claims. It is thought that `afl_frida` was running a test case +in persistent mode, whereas the qemu test it was compared against was not and +this may account for the differences since it isn't a like-for-like comparison. # Design FRIDA mode is supported by using `LD_PRELOAD` (`DYLD_INSERT_LIBRARIES` on macOS) @@ -102,12 +103,19 @@ 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. +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. +code, FRIDA mode instead makes use of optimized assembly instead on AARCH64 and +x86/64 targets. By injecting these small snippets of assembly, we avoid having +to push and pop the full register context. Note that since this instrumentation +is used on every basic block to generate coverage, it has a large impact on +performance. + +CompLog support also adds code to the assembly, however, at present this code +makes use of a basic C function and is yet to be optimized. Since not all +instances run CompLog mode and instrumentation of the binary is less frequent +(only on CMP, SUB and CALL instructions) performance is not quite so critical. # Advanced configuration options * `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage @@ -116,20 +124,11 @@ instrumentation (the default where available). Required to use * `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. +The next features to be added are x86 support, integration with FuzzBench and +support for ASAN. 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. diff --git a/frida_mode/include/complog.h b/frida_mode/include/complog.h new file mode 100644 index 00000000..094b7b93 --- /dev/null +++ b/frida_mode/include/complog.h @@ -0,0 +1,9 @@ +extern struct cmp_map *__afl_cmp_map; + +void complog_init(void); + +/* Functions to be implemented by the different architectures */ +void complog_instrument(const cs_insn *instr, GumStalkerIterator *iterator); + +gboolean complog_is_readable(void *addr, size_t size); + diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h index ff71bed4..1b6c6bba 100644 --- a/frida_mode/include/instrument.h +++ b/frida_mode/include/instrument.h @@ -1,7 +1,18 @@ #include "frida-gum.h" -void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, - gpointer user_data); +#include "config.h" -void instrument_init(); +extern uint64_t __thread previous_pc; +extern uint8_t *__afl_area_ptr; +extern uint32_t __afl_map_size; + +void instrument_init(void); + +GumStalkerTransformer *instrument_get_transformer(void); + +/* Functions to be implemented by the different architectures */ +gboolean instrument_is_coverage_optimize_supported(void); + +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output); diff --git a/frida_mode/include/interceptor.h b/frida_mode/include/interceptor.h index 5ed3cf49..49c0630a 100644 --- a/frida_mode/include/interceptor.h +++ b/frida_mode/include/interceptor.h @@ -1,4 +1,6 @@ #include "frida-gum.h" void intercept(void *address, gpointer replacement, gpointer user_data); +void unintercept(void *address); +void unintercept_self(void); diff --git a/frida_mode/include/lib.h b/frida_mode/include/lib.h new file mode 100644 index 00000000..1dc426a2 --- /dev/null +++ b/frida_mode/include/lib.h @@ -0,0 +1,8 @@ +#include "frida-gum.h" + +void lib_init(void); + +guint64 lib_get_text_base(void); + +guint64 lib_get_text_limit(void); + diff --git a/frida_mode/include/persistent.h b/frida_mode/include/persistent.h new file mode 100644 index 00000000..14c8a268 --- /dev/null +++ b/frida_mode/include/persistent.h @@ -0,0 +1,26 @@ +#include "frida-gum.h" + +#include "config.h" + +typedef struct arch_api_regs api_regs; + +typedef void (*afl_persistent_hook_fn)(api_regs *regs, uint64_t guest_base, + uint8_t *input_buf, + uint32_t input_buf_len); + +extern int __afl_persistent_loop(unsigned int max_cnt); + +extern unsigned int * __afl_fuzz_len; +extern unsigned char *__afl_fuzz_ptr; + +guint64 persistent_start; +guint64 persistent_count; +afl_persistent_hook_fn hook; + +void persistent_init(void); + +/* Functions to be implemented by the different architectures */ +gboolean persistent_is_supported(void); + +void persistent_prologue(GumStalkerOutput *output); + diff --git a/frida_mode/include/prefetch.h b/frida_mode/include/prefetch.h index b7f25a97..110f717f 100644 --- a/frida_mode/include/prefetch.h +++ b/frida_mode/include/prefetch.h @@ -1,5 +1,6 @@ -void prefetch_init(); -void prefetch_start(GumStalker *stalker); +#include "frida-gum.h" + +void prefetch_init(void); void prefetch_write(void *addr); -void prefetch_read(GumStalker *stalker); +void prefetch_read(void); diff --git a/frida_mode/include/ranges.h b/frida_mode/include/ranges.h index b9394dbc..a021f35c 100644 --- a/frida_mode/include/ranges.h +++ b/frida_mode/include/ranges.h @@ -1,6 +1,6 @@ #include "frida-gum.h" -void ranges_init(GumStalker *stalker); +void ranges_init(void); gboolean range_is_excluded(gpointer address); diff --git a/frida_mode/include/stalker.h b/frida_mode/include/stalker.h new file mode 100644 index 00000000..1962eec9 --- /dev/null +++ b/frida_mode/include/stalker.h @@ -0,0 +1,8 @@ +#include "frida-gum.h" + +void stalker_init(void); +GumStalker *stalker_get(void); +void stalker_start(void); +void stalker_pause(void); +void stalker_resume(void); + diff --git a/frida_mode/include/util.h b/frida_mode/include/util.h new file mode 100644 index 00000000..5b4ea76b --- /dev/null +++ b/frida_mode/include/util.h @@ -0,0 +1,6 @@ +#include "frida-gum.h" + +guint64 util_read_address(char *key); + +guint64 util_read_num(char *key); + diff --git a/frida_mode/src/complog/complog.c b/frida_mode/src/complog/complog.c new file mode 100644 index 00000000..3b679a5c --- /dev/null +++ b/frida_mode/src/complog/complog.c @@ -0,0 +1,72 @@ +#include "frida-gum.h" + +#include "debug.h" +#include "cmplog.h" + +extern struct cmp_map *__afl_cmp_map; + +static GArray *complog_ranges = NULL; + +static gboolean complog_range(const GumRangeDetails *details, + gpointer user_data) { + + GumMemoryRange range = *details->range; + g_array_append_val(complog_ranges, range); + +} + +static gint complog_sort(gconstpointer a, gconstpointer b) { + + return ((GumMemoryRange *)b)->base_address - + ((GumMemoryRange *)a)->base_address; + +} + +void complog_init(void) { + + if (__afl_cmp_map != NULL) { OKF("CompLog mode enabled"); } + + complog_ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), 100); + gum_process_enumerate_ranges(GUM_PAGE_READ, complog_range, NULL); + g_array_sort(complog_ranges, complog_sort); + + for (guint i = 0; i < complog_ranges->len; i++) { + + GumMemoryRange *range = &g_array_index(complog_ranges, GumMemoryRange, i); + OKF("CompLog Range - 0x%016lX - 0x%016lX", range->base_address, + range->base_address + range->size); + + } + +} + +static gboolean complog_contains(GumAddress inner_base, GumAddress inner_limit, + GumAddress outer_base, + GumAddress outer_limit) { + + return (inner_base >= outer_base && inner_limit <= outer_limit); + +} + +gboolean complog_is_readable(void *addr, size_t size) { + + if (complog_ranges == NULL) FATAL("CompLog not initialized"); + + GumAddress inner_base = GUM_ADDRESS(addr); + GumAddress inner_limit = inner_base + size; + + for (guint i = 0; i < complog_ranges->len; i++) { + + GumMemoryRange *range = &g_array_index(complog_ranges, GumMemoryRange, i); + GumAddress outer_base = range->base_address; + GumAddress outer_limit = outer_base + range->size; + + if (complog_contains(inner_base, inner_limit, outer_base, outer_limit)) + return true; + + } + + return false; + +} + diff --git a/frida_mode/src/complog/complog_arm.c b/frida_mode/src/complog/complog_arm.c new file mode 100644 index 00000000..82cc2557 --- /dev/null +++ b/frida_mode/src/complog/complog_arm.c @@ -0,0 +1,15 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "complog.h" + +#if defined(__arm64__) +void complog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + FATAL("Complog mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/complog/complog_arm64.c b/frida_mode/src/complog/complog_arm64.c new file mode 100644 index 00000000..e4dbf322 --- /dev/null +++ b/frida_mode/src/complog/complog_arm64.c @@ -0,0 +1,15 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "complog.h" + +#if defined(__i386__) +void complog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + FATAL("Complog mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/complog/complog_x64.c b/frida_mode/src/complog/complog_x64.c new file mode 100644 index 00000000..253ec041 --- /dev/null +++ b/frida_mode/src/complog/complog_x64.c @@ -0,0 +1,363 @@ +#include "frida-gum.h" + +#include "debug.h" +#include "cmplog.h" + +#include "complog.h" + +#if defined(__x86_64__) + + #define X86_REG_8L(LABEL, REG) \ + case LABEL: { \ + \ + return REG & GUM_INT8_MASK; \ + \ + } + + #define X86_REG_8H(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK) >> 8; \ + \ + } + + #define X86_REG_16(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK); \ + \ + } + + #define X86_REG_32(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT32_MASK); \ + \ + } + + #define X86_REG_64(LABEL, REG) \ + case LABEL: { \ + \ + return (REG); \ + \ + } + +typedef struct { + + x86_op_type type; + uint8_t size; + + union { + + x86_op_mem mem; + x86_reg reg; + int64_t imm; + + }; + +} complog_ctx_t; + +typedef struct { + + complog_ctx_t operand1; + complog_ctx_t operand2; + +} complog_pair_ctx_t; + +static guint64 complog_read_reg(GumX64CpuContext *ctx, x86_reg reg) { + + switch (reg) { + + X86_REG_8L(X86_REG_AL, ctx->rax) + X86_REG_8L(X86_REG_BL, ctx->rbx) + X86_REG_8L(X86_REG_CL, ctx->rcx) + X86_REG_8L(X86_REG_DL, ctx->rdx) + X86_REG_8L(X86_REG_BPL, ctx->rbp) + X86_REG_8L(X86_REG_SIL, ctx->rsi) + X86_REG_8L(X86_REG_DIL, ctx->rdi) + + X86_REG_8H(X86_REG_AH, ctx->rax) + X86_REG_8H(X86_REG_BH, ctx->rbx) + X86_REG_8H(X86_REG_CH, ctx->rcx) + X86_REG_8H(X86_REG_DH, ctx->rdx) + + X86_REG_16(X86_REG_AX, ctx->rax) + X86_REG_16(X86_REG_BX, ctx->rbx) + X86_REG_16(X86_REG_CX, ctx->rcx) + X86_REG_16(X86_REG_DX, ctx->rdx) + X86_REG_16(X86_REG_DI, ctx->rdi) + X86_REG_16(X86_REG_SI, ctx->rsi) + X86_REG_16(X86_REG_BP, ctx->rbp) + + X86_REG_32(X86_REG_EAX, ctx->rax) + X86_REG_32(X86_REG_ECX, ctx->rcx) + X86_REG_32(X86_REG_EDX, ctx->rdx) + X86_REG_32(X86_REG_EBX, ctx->rbx) + X86_REG_32(X86_REG_ESP, ctx->rsp) + X86_REG_32(X86_REG_EBP, ctx->rbp) + X86_REG_32(X86_REG_ESI, ctx->rsi) + X86_REG_32(X86_REG_EDI, ctx->rdi) + X86_REG_32(X86_REG_R8D, ctx->r8) + X86_REG_32(X86_REG_R9D, ctx->r9) + X86_REG_32(X86_REG_R10D, ctx->r10) + X86_REG_32(X86_REG_R11D, ctx->r11) + X86_REG_32(X86_REG_R12D, ctx->r12) + X86_REG_32(X86_REG_R13D, ctx->r13) + X86_REG_32(X86_REG_R14D, ctx->r14) + X86_REG_32(X86_REG_R15D, ctx->r15) + X86_REG_32(X86_REG_EIP, ctx->rip) + + X86_REG_64(X86_REG_RAX, ctx->rax) + X86_REG_64(X86_REG_RCX, ctx->rcx) + X86_REG_64(X86_REG_RDX, ctx->rdx) + X86_REG_64(X86_REG_RBX, ctx->rbx) + X86_REG_64(X86_REG_RSP, ctx->rsp) + X86_REG_64(X86_REG_RBP, ctx->rbp) + X86_REG_64(X86_REG_RSI, ctx->rsi) + X86_REG_64(X86_REG_RDI, ctx->rdi) + X86_REG_64(X86_REG_R8, ctx->r8) + X86_REG_64(X86_REG_R9, ctx->r9) + X86_REG_64(X86_REG_R10, ctx->r10) + X86_REG_64(X86_REG_R11, ctx->r11) + X86_REG_64(X86_REG_R12, ctx->r12) + X86_REG_64(X86_REG_R13, ctx->r13) + X86_REG_64(X86_REG_R14, ctx->r14) + X86_REG_64(X86_REG_R15, ctx->r15) + X86_REG_64(X86_REG_RIP, ctx->rip) + + default: + FATAL("Failed to read register: %d", reg); + return 0; + + } + +} + +static guint64 complog_read_mem(GumX64CpuContext *ctx, x86_op_mem *mem) { + + guint64 base = 0; + guint64 index = 0; + guint64 address; + + if (mem->base != X86_REG_INVALID) base = complog_read_reg(ctx, mem->base); + + if (mem->index != X86_REG_INVALID) index = complog_read_reg(ctx, mem->index); + + address = base + (index * mem->scale) + mem->disp; + return address; + +} + +static void complog_handle_call(GumCpuContext *context, guint64 target) { + + guint64 address = complog_read_reg(context, X86_REG_RIP); + guint64 rdi = complog_read_reg(context, X86_REG_RDI); + guint64 rsi = complog_read_reg(context, X86_REG_RSI); + + void *ptr1 = GSIZE_TO_POINTER(rdi); + void *ptr2 = GSIZE_TO_POINTER(rsi); + + if (!complog_is_readable(ptr1, 32) || !complog_is_readable(ptr2, 32)) return; + + uintptr_t k = address; + + k = (k >> 4) ^ (k << 8); + k &= CMP_MAP_W - 1; + + __afl_cmp_map->headers[k].type = CMP_TYPE_RTN; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + + __afl_cmp_map->headers[k].shape = 31; + + hits &= CMP_MAP_RTN_H - 1; + gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0, ptr1, + 32); + gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v1, ptr2, + 32); + +} + +static guint64 cmplog_get_operand_value(GumCpuContext *context, + complog_ctx_t *ctx) { + + switch (ctx->type) { + + case X86_OP_REG: + return complog_read_reg(context, ctx->reg); + case X86_OP_IMM: + return ctx->imm; + case X86_OP_MEM: + return complog_read_mem(context, &ctx->mem); + default: + FATAL("Invalid operand type: %d\n", ctx->type); + + } + +} + +static void complog_call_callout(GumCpuContext *context, gpointer user_data) { + + complog_ctx_t *ctx = (complog_ctx_t *)user_data; + + guint64 target = cmplog_get_operand_value(context, ctx); + complog_handle_call(context, target); + +} + +static void complog_instrument_put_operand(complog_ctx_t *ctx, + cs_x86_op * operand) { + + ctx->type = operand->type; + ctx->size = operand->size; + switch (operand->type) { + + case X86_OP_REG: + gum_memcpy(&ctx->reg, &operand->reg, sizeof(x86_reg)); + break; + case X86_OP_IMM: + gum_memcpy(&ctx->imm, &operand->imm, sizeof(int64_t)); + break; + case X86_OP_MEM: + gum_memcpy(&ctx->mem, &operand->mem, sizeof(x86_op_mem)); + break; + default: + FATAL("Invalid operand type: %d\n", operand->type); + + } + +} + +static void complog_instrument_call_put_callout(GumStalkerIterator *iterator, + cs_x86_op * operand) { + + complog_ctx_t *ctx = g_malloc(sizeof(complog_ctx_t)); + if (ctx == NULL) return; + + complog_instrument_put_operand(ctx, operand); + + gum_stalker_iterator_put_callout(iterator, complog_call_callout, ctx, g_free); + +} + +static void complog_instrument_call(const cs_insn * instr, + GumStalkerIterator *iterator) { + + cs_x86 x86 = instr->detail->x86; + cs_x86_op *operand; + + if (instr->id != X86_INS_CALL) return; + + if (x86.op_count != 1) return; + + operand = &x86.operands[0]; + + if (operand->type == X86_OP_INVALID) return; + if (operand->type == X86_OP_MEM && operand->mem.segment != X86_REG_INVALID) + return; + + complog_instrument_call_put_callout(iterator, operand); + +} + +static void complog_handle_cmp_sub(GumCpuContext *context, guint64 operand1, + guint64 operand2, uint8_t size) { + + guint64 address = complog_read_reg(context, X86_REG_RIP); + + register uintptr_t k = (uintptr_t)address; + + k = (k >> 4) ^ (k << 8); + k &= CMP_MAP_W - 1; + + __afl_cmp_map->headers[k].type = CMP_TYPE_INS; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + + __afl_cmp_map->headers[k].shape = (size - 1); + + hits &= CMP_MAP_H - 1; + __afl_cmp_map->log[k][hits].v0 = operand1; + __afl_cmp_map->log[k][hits].v1 = operand2; + +} + +static void complog_cmp_sub_callout(GumCpuContext *context, + gpointer user_data) { + + complog_pair_ctx_t *ctx = (complog_pair_ctx_t *)user_data; + + if (ctx->operand1.size != ctx->operand2.size) FATAL("Operand size mismatch"); + + guint64 operand1 = cmplog_get_operand_value(context, &ctx->operand1); + guint64 operand2 = cmplog_get_operand_value(context, &ctx->operand2); + + complog_handle_cmp_sub(context, operand1, operand2, ctx->operand1.size); + +} + +static void complog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator, + cs_x86_op * operand1, + cs_x86_op *operand2) { + + complog_pair_ctx_t *ctx = g_malloc(sizeof(complog_pair_ctx_t)); + if (ctx == NULL) return; + + complog_instrument_put_operand(&ctx->operand1, operand1); + complog_instrument_put_operand(&ctx->operand2, operand2); + + gum_stalker_iterator_put_callout(iterator, complog_cmp_sub_callout, ctx, + g_free); + +} + +static void complog_instrument_cmp_sub(const cs_insn * instr, + GumStalkerIterator *iterator) { + + cs_x86 x86 = instr->detail->x86; + cs_x86_op *operand1; + cs_x86_op *operand2; + + switch (instr->id) { + + case X86_INS_CMP: + case X86_INS_SUB: + break; + default: + return; + + } + + if (x86.op_count != 2) return; + + operand1 = &x86.operands[0]; + operand2 = &x86.operands[1]; + + if (operand1->type == X86_OP_INVALID) return; + if (operand2->type == X86_OP_INVALID) return; + + if ((operand1->type == X86_OP_MEM) && + (operand1->mem.segment != X86_REG_INVALID)) + return; + + if ((operand2->type == X86_OP_MEM) && + (operand2->mem.segment != X86_REG_INVALID)) + return; + + complog_instrument_cmp_sub_put_callout(iterator, operand1, operand2); + +} + +void complog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + if (__afl_cmp_map == NULL) return; + + complog_instrument_call(instr, iterator); + complog_instrument_cmp_sub(instr, iterator); + +} + +#endif + diff --git a/frida_mode/src/complog/complog_x86.c b/frida_mode/src/complog/complog_x86.c new file mode 100644 index 00000000..df7b7cc1 --- /dev/null +++ b/frida_mode/src/complog/complog_x86.c @@ -0,0 +1,15 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "complog.h" + +#if defined(__arm__) +void complog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + FATAL("Complog mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/instrument.c b/frida_mode/src/instrument.c deleted file mode 100644 index 22910062..00000000 --- a/frida_mode/src/instrument.c +++ /dev/null @@ -1,271 +0,0 @@ -#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) { - - /* - * This function is performance critical as it is called to instrument every - * basic block. By moving our print buffer to a global, we avoid it affecting - * the critical path with additional stack adjustments if tracing is not - * enabled. If tracing is enabled, then we're printing a load of diagnostic - * information so this overhead is unlikely to be noticeable. - */ - 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); - - } - -} - diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c new file mode 100644 index 00000000..81080bee --- /dev/null +++ b/frida_mode/src/instrument/instrument.c @@ -0,0 +1,150 @@ +#include + +#include "frida-gum.h" + +#include "config.h" +#include "debug.h" + +#include "complog.h" +#include "instrument.h" +#include "persistent.h" +#include "prefetch.h" +#include "ranges.h" +#include "stalker.h" + +static gboolean tracing = false; +static gboolean optimize = false; +static gboolean strict = false; +static GumStalkerTransformer *transformer = NULL; + +uint64_t __thread previous_pc = 0; + +__attribute__((hot)) static void on_basic_block(GumCpuContext *context, + gpointer user_data) { + + /* + * This function is performance critical as it is called to instrument every + * basic block. By moving our print buffer to a global, we avoid it affecting + * the critical path with additional stack adjustments if tracing is not + * enabled. If tracing is enabled, then we're printing a load of diagnostic + * information so this overhead is unlikely to be noticeable. + */ + static char buffer[200]; + int len; + guint64 current_pc = (guint64)user_data; + uint8_t * cursor; + uint64_t value; + if (unlikely(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; + + cursor = &__afl_area_ptr[current_pc ^ previous_pc]; + value = *cursor; + + if (value == 0xff) { + + value = 1; + + } else { + + value++; + + } + + *cursor = value; + previous_pc = current_pc >> 1; + +} + +static 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 (instr->address == persistent_start) { persistent_prologue(output); } + + if (begin) { + + prefetch_write((void *)instr->address); + if (!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; + + } + + if (!range_is_excluded((void *)instr->address)) { + + complog_instrument(instr, iterator); + + } + + gum_stalker_iterator_keep(iterator); + + } + +} + +void instrument_init(void) { + + optimize = (getenv("AFL_FRIDA_INST_NO_OPTIMIZE") == NULL); + tracing = (getenv("AFL_FRIDA_INST_TRACE") != NULL); + + if (!instrument_is_coverage_optimize_supported()) optimize = false; + + OKF("Instrumentation - optimize [%c]", optimize ? 'X' : ' '); + OKF("Instrumentation - tracing [%c]", tracing ? '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); + + } + + transformer = + gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL); + + complog_init(); + +} + +GumStalkerTransformer *instrument_get_transformer(void) { + + if (transformer == NULL) { FATAL("Instrumentation not initialized"); } + return transformer; + +} + diff --git a/frida_mode/src/instrument/instrument_arm32.c b/frida_mode/src/instrument/instrument_arm32.c new file mode 100644 index 00000000..c2d720a7 --- /dev/null +++ b/frida_mode/src/instrument/instrument_arm32.c @@ -0,0 +1,23 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "instrument.h" + +#if defined(__arm__) + +gboolean instrument_is_coverage_optimize_supported(void) { + + return false; + +} + +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output) { + + FATAL("Optimized coverage not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/instrument/instrument_arm64.c b/frida_mode/src/instrument/instrument_arm64.c new file mode 100644 index 00000000..fa3afb48 --- /dev/null +++ b/frida_mode/src/instrument/instrument_arm64.c @@ -0,0 +1,97 @@ +#include "frida-gum.h" + +#include "config.h" +#include "debug.h" + +#include "instrument.h" + +#if defined(__aarch64__) + +static GumAddress current_log_impl = GUM_ADDRESS(0); + +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 + 0xe1, 0x01, 0x00, 0x58, // ldr x1, #0x3c, =&__afl_area_ptr + 0x21, 0x00, 0x40, 0xf9, // ldr x1, [x1] (=__afl_area_ptr) + + 0xe2, 0x01, 0x00, 0x58, // ldr x2, #0x3c, =&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 + 0x63, 0x00, 0x1f, 0x9a, // adc x3, x3, xzr + 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 + +}; + +gboolean instrument_is_coverage_optimize_supported(void) { + + return true; + +} + +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 + diff --git a/frida_mode/src/instrument/instrument_x64.c b/frida_mode/src/instrument/instrument_x64.c new file mode 100644 index 00000000..901f3bd0 --- /dev/null +++ b/frida_mode/src/instrument/instrument_x64.c @@ -0,0 +1,93 @@ +#include "frida-gum.h" + +#include "config.h" + +#include "instrument.h" + +#if defined(__x86_64__) + +static GumAddress current_log_impl = GUM_ADDRESS(0); + +static const guint8 afl_log_code[] = { + + // 0xcc, + + 0x9c, /* pushfq */ + 0x51, /* push rcx */ + 0x52, /* push rdx */ + + 0x48, 0x8b, 0x0d, 0x28, + 0x00, 0x00, 0x00, /* mov rcx, sym.&previous_pc */ + 0x48, 0x8b, 0x11, /* mov rdx, qword [rcx] */ + 0x48, 0x31, 0xfa, /* xor rdx, rdi */ + + 0x48, 0x03, 0x15, 0x13, + 0x00, 0x00, 0x00, /* add rdx, sym._afl_area_ptr_ptr */ + + 0x80, 0x02, 0x01, /* add byte ptr [rdx], 1 */ + 0x80, 0x12, 0x00, /* adc byte ptr [rdx], 0 */ + 0x48, 0xd1, 0xef, /* shr rdi, 1 */ + 0x48, 0x89, 0x39, /* mov qword [rcx], rdi */ + + 0x5a, /* pop rdx */ + 0x59, /* pop rcx */ + 0x9d, /* popfq */ + + 0xc3, /* ret */ + 0x90, 0x90, 0x90 /* nop pad */ + + /* Read-only data goes here: */ + /* uint8_t* __afl_area_ptr */ + /* uint64_t* &previous_pc */ + +}; + +gboolean instrument_is_coverage_optimize_supported(void) { + + return true; + +} + +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)); + + uint64_t *afl_prev_loc_ptr = &previous_pc; + gum_x86_writer_put_bytes(cw, (const guint8 *)&__afl_area_ptr, + sizeof(__afl_area_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); + +} + +#endif + diff --git a/frida_mode/src/instrument/instrument_x86.c b/frida_mode/src/instrument/instrument_x86.c new file mode 100644 index 00000000..5b8cbbba --- /dev/null +++ b/frida_mode/src/instrument/instrument_x86.c @@ -0,0 +1,23 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "instrument.h" + +#if defined(__i386__) + +gboolean instrument_is_coverage_optimize_supported(void) { + + return false; + +} + +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output) { + + FATAL("Optimized coverage not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/interceptor.c b/frida_mode/src/interceptor.c index ba05a80a..8d41b075 100644 --- a/frida_mode/src/interceptor.c +++ b/frida_mode/src/interceptor.c @@ -1,4 +1,5 @@ #include "frida-gum.h" + #include "debug.h" #include "interceptor.h" @@ -14,3 +15,21 @@ void intercept(void *address, gpointer replacement, gpointer user_data) { } +void unintercept(void *address) { + + GumInterceptor *interceptor = gum_interceptor_obtain(); + + gum_interceptor_begin_transaction(interceptor); + gum_interceptor_revert(interceptor, address); + gum_interceptor_end_transaction(interceptor); + gum_interceptor_flush(interceptor); + +} + +void unintercept_self(void) { + + GumInvocationContext *ctx = gum_interceptor_get_current_invocation(); + unintercept(ctx->function); + +} + diff --git a/frida_mode/src/lib.c b/frida_mode/src/lib.c new file mode 100644 index 00000000..326d4819 --- /dev/null +++ b/frida_mode/src/lib.c @@ -0,0 +1,167 @@ +#include +#include +#include +#include +#include +#include + +#include "frida-gum.h" + +#include "debug.h" + +#include "lib.h" + +#if defined(__arm__) || defined(__i386__) + #define ELFCLASS ELFCLASS32 +typedef Elf32_Ehdr Elf_Ehdr; +typedef Elf32_Phdr Elf_Phdr; +typedef Elf32_Shdr Elf_Shdr; +#elif defined(__aarch64__) || defined(__x86_64__) + #define ELFCLASS ELFCLASS64 +typedef Elf64_Ehdr Elf_Ehdr; +typedef Elf64_Phdr Elf_Phdr; +typedef Elf64_Shdr Elf_Shdr; +#else + #error "Unsupported platform" +#endif + +typedef struct { + + gchar name[PATH_MAX + 1]; + gchar path[PATH_MAX + 1]; + GumAddress base_address; + gsize size; + +} lib_details_t; + +static guint64 text_base = 0; +static guint64 text_limit = 0; + +static gboolean lib_find_exe(const GumModuleDetails *details, + gpointer user_data) { + + lib_details_t *lib_details = (lib_details_t *)user_data; + + memcpy(lib_details->name, details->name, PATH_MAX); + memcpy(lib_details->path, details->path, PATH_MAX); + lib_details->base_address = details->range->base_address; + lib_details->size = details->range->size; + return FALSE; + +} + +static gboolean lib_is_little_endian(void) { + + int probe = 1; + return *(char *)&probe; + +} + +static void lib_validate_hdr(Elf_Ehdr *hdr) { + + if (hdr->e_ident[0] != ELFMAG0) FATAL("Invalid e_ident[0]"); + if (hdr->e_ident[1] != ELFMAG1) FATAL("Invalid e_ident[1]"); + if (hdr->e_ident[2] != ELFMAG2) FATAL("Invalid e_ident[2]"); + if (hdr->e_ident[3] != ELFMAG3) FATAL("Invalid e_ident[3]"); + if (hdr->e_ident[4] != ELFCLASS) FATAL("Invalid class"); + if (hdr->e_ident[5] != (lib_is_little_endian() ? ELFDATA2LSB : ELFDATA2MSB)) + FATAL("Invalid endian"); + if (hdr->e_ident[6] != EV_CURRENT) FATAL("Invalid version"); + if (hdr->e_type != ET_DYN) FATAL("Invalid type"); + if (hdr->e_version != EV_CURRENT) FATAL("Invalid e_version"); + if (hdr->e_phoff != sizeof(Elf_Ehdr)) FATAL("Invalid e_phoff"); + if (hdr->e_ehsize != sizeof(Elf_Ehdr)) FATAL("Invalid e_ehsize"); + if (hdr->e_phentsize != sizeof(Elf_Phdr)) FATAL("Invalid e_phentsize"); + if (hdr->e_shentsize != sizeof(Elf_Shdr)) FATAL("Invalid e_shentsize"); + +} + +static void lib_read_text_section(lib_details_t *lib_details, Elf_Ehdr *hdr) { + + Elf_Shdr *shdr; + Elf_Shdr *shstrtab; + char * shstr; + char * section_name; + Elf_Shdr *curr; + char text_name[] = ".text"; + + shdr = (Elf_Shdr *)((char *)hdr + hdr->e_shoff); + shstrtab = &shdr[hdr->e_shstrndx]; + shstr = (char *)hdr + shstrtab->sh_offset; + + OKF("shdr: %p", shdr); + OKF("shstrtab: %p", shstrtab); + OKF("shstr: %p", shstr); + + for (size_t i = 0; i < hdr->e_shnum; i++) { + + curr = &shdr[i]; + + if (curr->sh_name == 0) continue; + + section_name = &shstr[curr->sh_name]; + OKF("Section: %2lu - base: 0x%016lX size: 0x%016lX %s", i, curr->sh_addr, + curr->sh_size, section_name); + if (memcmp(section_name, text_name, sizeof(text_name)) == 0 && + text_base == 0) { + + text_base = lib_details->base_address + curr->sh_addr; + text_limit = lib_details->base_address + curr->sh_addr + curr->sh_size; + OKF("> text_addr: 0x%016lX", text_base); + OKF("> text_limit: 0x%016lX", text_limit); + + } + + } + +} + +static void lib_get_text_section(lib_details_t *details) { + + int fd = -1; + off_t len; + Elf_Ehdr *hdr; + + fd = open(details->path, O_RDONLY); + if (fd < 0) { FATAL("Failed to open %s", details->path); } + + len = lseek(fd, 0, SEEK_END); + + if (len == (off_t)-1) { FATAL("Failed to lseek %s", details->path); } + + OKF("len: %ld\n", len); + + hdr = (Elf_Ehdr *)mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); + if (hdr == MAP_FAILED) { FATAL("Failed to map %s", details->path); } + + lib_validate_hdr(hdr); + lib_read_text_section(details, hdr); + + munmap(hdr, len); + close(fd); + +} + +void lib_init(void) { + + lib_details_t lib_details; + gum_process_enumerate_modules(lib_find_exe, &lib_details); + OKF("Executable: 0x%016lx - %s", lib_details.base_address, lib_details.path); + lib_get_text_section(&lib_details); + +} + +guint64 lib_get_text_base(void) { + + if (text_base == 0) FATAL("Lib not initialized"); + return text_base; + +} + +guint64 lib_get_text_limit(void) { + + if (text_limit == 0) FATAL("Lib not initialized"); + return text_limit; + +} + diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c index 7505c2f9..f712a8c0 100644 --- a/frida_mode/src/main.c +++ b/frida_mode/src/main.c @@ -10,13 +10,17 @@ #endif #include "frida-gum.h" + #include "config.h" #include "debug.h" -#include "interceptor.h" #include "instrument.h" +#include "interceptor.h" +#include "lib.h" +#include "persistent.h" #include "prefetch.h" #include "ranges.h" +#include "stalker.h" #ifdef __APPLE__ extern mach_port_t mach_task_self(); @@ -30,16 +34,15 @@ extern int __libc_start_main(int *(main)(int, char **, char **), int argc, typedef int *(*main_fn_t)(int argc, char **argv, char **envp); -static main_fn_t main_fn = NULL; -static GumStalker * stalker = NULL; +static main_fn_t main_fn = NULL; + static GumMemoryRange code_range = {0}; -extern void __afl_manual_init(); -extern __thread uint64_t previous_pc; +extern void __afl_manual_init(); -static int on_fork() { +static int on_fork(void) { - prefetch_read(stalker); + prefetch_read(); return fork(); } @@ -70,37 +73,46 @@ static void on_main_os(int argc, char **argv, char **envp) { static int *on_main(int argc, char **argv, char **envp) { + void *fork_addr; on_main_os(argc, argv, envp); - stalker = gum_stalker_new(); - if (stalker == NULL) { FATAL("Failed to initialize stalker"); } + unintercept_self(); - gum_stalker_set_trust_threshold(stalker, 0); - - GumStalkerTransformer *transformer = - gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL); + stalker_init(); + lib_init(); instrument_init(); + persistent_init(); prefetch_init(); - ranges_init(stalker); + ranges_init(); - intercept(fork, on_fork, stalker); + fork_addr = GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork")); + intercept(fork_addr, on_fork, NULL); - gum_stalker_follow_me(stalker, transformer, NULL); - gum_stalker_deactivate(stalker); + stalker_start(); + stalker_pause(); __afl_manual_init(); /* Child here */ previous_pc = 0; - prefetch_start(stalker); + stalker_resume(); main_fn(argc, argv, envp); - _exit(0); } -#ifdef __APPLE__ -static void intercept_main() { +#if defined(EMBEDDED) +extern int *main(int argc, char **argv, char **envp); + +static void intercept_main(void) { + + main_fn = main; + intercept(main, on_main, NULL); + +} + +#elif defined(__APPLE__) +static void intercept_main(void) { mach_port_t task = mach_task_self(); OKF("Task Id: %u", task); @@ -119,13 +131,14 @@ static int on_libc_start_main(int *(main)(int, char **, char **), int argc, void(*stack_end)) { main_fn = main; + unintercept_self(); intercept(main, on_main, NULL); return __libc_start_main(main, argc, ubp_av, init, fini, rtld_fini, stack_end); } -static void intercept_main() { +static void intercept_main(void) { intercept(__libc_start_main, on_libc_start_main, NULL); @@ -133,7 +146,7 @@ static void intercept_main() { #endif -__attribute__((constructor)) static void init() { +__attribute__((constructor)) static void init(void) { gum_init_embedded(); if (!gum_stalker_is_supported()) { diff --git a/frida_mode/src/persistent/persistent.c b/frida_mode/src/persistent/persistent.c new file mode 100644 index 00000000..fe3a1d20 --- /dev/null +++ b/frida_mode/src/persistent/persistent.c @@ -0,0 +1,68 @@ +#include + +#include "frida-gum.h" + +#include "config.h" +#include "debug.h" + +#include "persistent.h" +#include "util.h" + +int __afl_sharedmem_fuzzing = 0; +afl_persistent_hook_fn hook = NULL; +guint64 persistent_start = 0; +guint64 persistent_count = 0; + +void persistent_init(void) { + + char *hook_name = getenv("AFL_FRIDA_PERSISTENT_HOOK"); + + persistent_start = util_read_address("AFL_FRIDA_PERSISTENT_ADDR"); + persistent_count = util_read_num("AFL_FRIDA_PERSISTENT_CNT"); + + if (persistent_count != 0 && persistent_start == 0) + FATAL( + "AFL_FRIDA_PERSISTENT_ADDR must be specified if " + "AFL_FRIDA_PERSISTENT_CNT is"); + + if (persistent_start != 0 && persistent_count == 0) persistent_count = 1000; + + if (persistent_count != 0 && persistent_count < 100) + WARNF("Persistent count out of recommended range (<100)"); + + if (persistent_count > 10000) + WARNF("Persistent count out of recommended range (<10000)"); + + if (persistent_start != 0 && !persistent_is_supported()) + FATAL("Persistent mode not supported on this architecture"); + + OKF("Instrumentation - persistent mode [%c] (0x%016lX)", + persistent_start == 0 ? ' ' : 'X', persistent_start); + OKF("Instrumentation - persistent count [%c] (%ld)", + persistent_start == 0 ? ' ' : 'X', persistent_count); + OKF("Instrumentation - hook [%s]", hook_name); + + if (hook_name != NULL) { + + void *hook_obj = dlopen(hook_name, RTLD_NOW); + if (hook_obj == NULL) + FATAL("Failed to load AFL_FRIDA_PERSISTENT_HOOK (%s)", hook_name); + + int (*afl_persistent_hook_init_ptr)(void) = + dlsym(hook_obj, "afl_persistent_hook_init"); + if (afl_persistent_hook_init_ptr == NULL) + FATAL("Failed to find afl_persistent_hook_init in %s", hook_name); + + if (afl_persistent_hook_init_ptr() == 0) + FATAL("afl_persistent_hook_init returned a failure"); + + hook = (afl_persistent_hook_fn)dlsym(hook_obj, "afl_persistent_hook"); + if (hook == NULL) + FATAL("Failed to find afl_persistent_hook in %s", hook_name); + + __afl_sharedmem_fuzzing = 1; + + } + +} + diff --git a/frida_mode/src/persistent/persistent_arm32.c b/frida_mode/src/persistent/persistent_arm32.c new file mode 100644 index 00000000..10dab3b2 --- /dev/null +++ b/frida_mode/src/persistent/persistent_arm32.c @@ -0,0 +1,70 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "persistent.h" + +#if defined(__arm__) + +struct arm_regs { + + uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10; + + union { + + uint32_t r11; + uint32_t fp; + + }; + + union { + + uint32_t r12; + uint32_t ip; + + }; + + union { + + uint32_t r13; + uint32_t sp; + + }; + + union { + + uint32_t r14; + uint32_t lr; + + }; + + union { + + uint32_t r15; + uint32_t pc; + + }; + + uint32_t cpsr; + + uint8_t vfp_zregs[32][16]; + uint32_t vfp_xregs[16]; + +}; + +typedef struct arm_regs arch_api_regs; + +gboolean persistent_is_supported(void) { + + return false; + +} + +void persistent_prologue(GumStalkerOutput *output) { + + FATAL("Persistent mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/persistent/persistent_arm64.c b/frida_mode/src/persistent/persistent_arm64.c new file mode 100644 index 00000000..5a18ac2c --- /dev/null +++ b/frida_mode/src/persistent/persistent_arm64.c @@ -0,0 +1,113 @@ +#include "frida-gum.h" + +#include "config.h" +#include "debug.h" + +#include "instrument.h" + +#if defined(__aarch64__) + +struct arm64_regs { + + uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10; + + union { + + uint64_t x11; + uint32_t fp_32; + + }; + + union { + + uint64_t x12; + uint32_t ip_32; + + }; + + union { + + uint64_t x13; + uint32_t sp_32; + + }; + + union { + + uint64_t x14; + uint32_t lr_32; + + }; + + union { + + uint64_t x15; + uint32_t pc_32; + + }; + + union { + + uint64_t x16; + uint64_t ip0; + + }; + + union { + + uint64_t x17; + uint64_t ip1; + + }; + + uint64_t x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28; + + union { + + uint64_t x29; + uint64_t fp; + + }; + + union { + + uint64_t x30; + uint64_t lr; + + }; + + union { + + uint64_t x31; + uint64_t sp; + + }; + + // the zero register is not saved here ofc + + uint64_t pc; + + uint32_t cpsr; + + uint8_t vfp_zregs[32][16 * 16]; + uint8_t vfp_pregs[17][32]; + uint32_t vfp_xregs[16]; + +}; + +typedef struct arm64_regs arch_api_regs; + +gboolean persistent_is_supported(void) { + + return false; + +} + +void persistent_prologue(GumStalkerOutput *output) { + + FATAL("Persistent mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/persistent/persistent_x64.c b/frida_mode/src/persistent/persistent_x64.c new file mode 100644 index 00000000..0cabbf24 --- /dev/null +++ b/frida_mode/src/persistent/persistent_x64.c @@ -0,0 +1,337 @@ +#include "frida-gum.h" + +#include "config.h" + +#include "instrument.h" +#include "persistent.h" + +#if defined(__x86_64__) + +struct x86_64_regs { + + uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14, + r15; + + union { + + uint64_t rip; + uint64_t pc; + + }; + + union { + + uint64_t rsp; + uint64_t sp; + + }; + + union { + + uint64_t rflags; + uint64_t flags; + + }; + + uint8_t zmm_regs[32][64]; + +}; + +typedef struct x86_64_regs arch_api_regs; + +static arch_api_regs saved_regs = {0}; +static void * saved_return = NULL; + +gboolean persistent_is_supported(void) { + + return true; + +} + +static void instrument_persitent_save_regs(GumX86Writer * cw, + struct x86_64_regs *regs) { + + GumAddress regs_address = GUM_ADDRESS(regs); + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -(GUM_RED_ZONE_SIZE)); + + /* Should be pushing FPU here, but meh */ + gum_x86_writer_put_pushfx(cw); + gum_x86_writer_put_push_reg(cw, GUM_REG_RAX); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, regs_address); + + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 1), + GUM_REG_RBX); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 2), + GUM_REG_RCX); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 3), + GUM_REG_RDX); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 4), + GUM_REG_RDI); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 5), + GUM_REG_RSI); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 6), + GUM_REG_RBP); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 7), + GUM_REG_R8); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 8), + GUM_REG_R9); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 9), + GUM_REG_R10); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 10), + GUM_REG_R11); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 11), + GUM_REG_R12); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 12), + GUM_REG_R13); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 13), + GUM_REG_R14); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 14), + GUM_REG_R15); + + /* Store RIP */ + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RBX, + GUM_ADDRESS(persistent_start)); + + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 15), + GUM_REG_RBX); + + /* Store adjusted RSP */ + gum_x86_writer_put_mov_reg_reg(cw, GUM_REG_RBX, GUM_REG_RSP); + + /* RED_ZONE + Saved flags, RAX, alignment */ + gum_x86_writer_put_add_reg_imm(cw, GUM_REG_RBX, + GUM_RED_ZONE_SIZE + (0x8 * 3)); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 16), + GUM_REG_RBX); + + /* Save the flags */ + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP, 0x8); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 17), + GUM_REG_RBX); + + /* Save the RAX */ + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP, 0x0); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 0), + GUM_REG_RBX); + + /* Pop the saved values */ + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, 0x10); + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + (GUM_RED_ZONE_SIZE)); + +} + +static void instrument_persitent_restore_regs(GumX86Writer * cw, + struct x86_64_regs *regs) { + + GumAddress regs_address = GUM_ADDRESS(regs); + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, regs_address); + + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RAX, + (0x8 * 2)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RAX, + (0x8 * 3)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDI, GUM_REG_RAX, + (0x8 * 4)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RSI, GUM_REG_RAX, + (0x8 * 5)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBP, GUM_REG_RAX, + (0x8 * 6)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R8, GUM_REG_RAX, + (0x8 * 7)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R9, GUM_REG_RAX, + (0x8 * 8)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R10, GUM_REG_RAX, + (0x8 * 9)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R11, GUM_REG_RAX, + (0x8 * 10)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R12, GUM_REG_RAX, + (0x8 * 11)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R13, GUM_REG_RAX, + (0x8 * 12)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R14, GUM_REG_RAX, + (0x8 * 13)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R15, GUM_REG_RAX, + (0x8 * 14)); + + /* Don't restore RIP or RSP */ + + /* Restore RBX, RAX & Flags */ + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -(GUM_RED_ZONE_SIZE)); + + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX, + (0x8 * 1)); + gum_x86_writer_put_push_reg(cw, GUM_REG_RBX); + + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX, + (0x8 * 0)); + gum_x86_writer_put_push_reg(cw, GUM_REG_RBX); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX, + (0x8 * 17)); + gum_x86_writer_put_push_reg(cw, GUM_REG_RBX); + + gum_x86_writer_put_popfx(cw); + gum_x86_writer_put_pop_reg(cw, GUM_REG_RAX); + gum_x86_writer_put_pop_reg(cw, GUM_REG_RBX); + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + (GUM_RED_ZONE_SIZE)); + +} + +static void instrument_save_ret(GumX86Writer *cw, void **saved_return_ptr) { + + GumAddress saved_return_address = GUM_ADDRESS(saved_return_ptr); + 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_RAX); + gum_x86_writer_put_push_reg(cw, GUM_REG_RBX); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, saved_return_address); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP, + GUM_RED_ZONE_SIZE + 0x10); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, 0, GUM_REG_RBX); + + gum_x86_writer_put_pop_reg(cw, GUM_REG_RBX); + gum_x86_writer_put_pop_reg(cw, GUM_REG_RAX); + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + (GUM_RED_ZONE_SIZE)); + +} + +static void instrument_jump_ret(GumX86Writer *cw, void **saved_return_ptr) { + + GumAddress saved_return_address = GUM_ADDRESS(saved_return_ptr); + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -(GUM_RED_ZONE_SIZE)); + + /* Place holder for ret */ + gum_x86_writer_put_push_reg(cw, GUM_REG_RAX); + gum_x86_writer_put_push_reg(cw, GUM_REG_RAX); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, saved_return_address); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RAX, GUM_REG_RAX, 0); + + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RSP, 0x8, GUM_REG_RAX); + gum_x86_writer_put_pop_reg(cw, GUM_REG_RAX); + gum_x86_writer_put_ret_imm(cw, GUM_RED_ZONE_SIZE); + +} + +static int instrument_afl_persistent_loop_func(void) { + + int ret = __afl_persistent_loop(persistent_count); + previous_pc = 0; + return ret; + +} + +static int instrument_afl_persistent_loop(GumX86Writer *cw) { + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -(GUM_RED_ZONE_SIZE)); + gum_x86_writer_put_call_address_with_arguments( + cw, GUM_CALL_CAPI, GUM_ADDRESS(instrument_afl_persistent_loop_func), 0); + gum_x86_writer_put_test_reg_reg(cw, GUM_REG_RAX, GUM_REG_RAX); + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + (GUM_RED_ZONE_SIZE)); + +} + +static void persistent_prologue_hook(GumX86Writer * cw, + struct x86_64_regs *regs) { + + if (hook == NULL) return; + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -(GUM_RED_ZONE_SIZE)); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RCX, + GUM_ADDRESS(__afl_fuzz_len)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RCX, 0); + gum_x86_writer_put_mov_reg_u64(cw, GUM_REG_RDI, 0xffffffff); + gum_x86_writer_put_and_reg_reg(cw, GUM_REG_RCX, GUM_REG_RDI); + + gum_x86_writer_put_call_address_with_arguments( + cw, GUM_CALL_CAPI, GUM_ADDRESS(hook), 4, GUM_ARG_ADDRESS, + GUM_ADDRESS(regs), GUM_ARG_ADDRESS, GUM_ADDRESS(0), GUM_ARG_ADDRESS, + GUM_ADDRESS(__afl_fuzz_ptr), GUM_ARG_REGISTER, GUM_REG_RCX); + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + (GUM_RED_ZONE_SIZE)); + +} + +void persistent_prologue(GumStalkerOutput *output) { + + /* + * SAVE REGS + * SAVE RET + * POP RET + * loop: + * CALL instrument_afl_persistent_loop + * TEST EAX, EAX + * JZ end: + * call hook (optionally) + * RESTORE REGS + * call original + * jmp loop: + * + * end: + * JMP SAVED RET + * + * original: + * INSTRUMENTED PERSISTENT FUNC + */ + + GumX86Writer *cw = output->writer.x86; + + gconstpointer loop = cw->code + 1; + // gum_x86_writer_put_breakpoint(cw); + + /* Stack must be 16-byte aligned per ABI */ + instrument_persitent_save_regs(cw, &saved_regs); + + /* Stash and pop the return value */ + instrument_save_ret(cw, &saved_return); + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, (8)); + + /* loop: */ + gum_x86_writer_put_label(cw, loop); + + /* call instrument_prologue_func */ + instrument_afl_persistent_loop(cw); + + /* jz done */ + gconstpointer done = cw->code + 1; + gum_x86_writer_put_jcc_near_label(cw, X86_INS_JE, done, GUM_UNLIKELY); + + /* Optionally call the persistent hook */ + persistent_prologue_hook(cw, &saved_regs); + + instrument_persitent_restore_regs(cw, &saved_regs); + gconstpointer original = cw->code + 1; + /* call original */ + gum_x86_writer_put_call_near_label(cw, original); + /* jmp loop */ + gum_x86_writer_put_jmp_near_label(cw, loop); + + /* done: */ + gum_x86_writer_put_label(cw, done); + + instrument_jump_ret(cw, &saved_return); + + /* original: */ + gum_x86_writer_put_label(cw, original); + + gum_x86_writer_flush(cw); + +} + +#endif + diff --git a/frida_mode/src/persistent/persistent_x86.c b/frida_mode/src/persistent/persistent_x86.c new file mode 100644 index 00000000..4daa61a9 --- /dev/null +++ b/frida_mode/src/persistent/persistent_x86.c @@ -0,0 +1,53 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "persistent.h" + +#if defined(__i386__) + +struct x86_regs { + + uint32_t eax, ebx, ecx, edx, edi, esi, ebp; + + union { + + uint32_t eip; + uint32_t pc; + + }; + + union { + + uint32_t esp; + uint32_t sp; + + }; + + union { + + uint32_t eflags; + uint32_t flags; + + }; + + uint8_t xmm_regs[8][16]; + +}; + +typedef struct x86_regs arch_api_regs; + +gboolean persistent_is_supported(void) { + + return false; + +} + +void persistent_prologue(GumStalkerOutput *output) { + + FATAL("Persistent mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/prefetch.c b/frida_mode/src/prefetch.c index 64633c1c..65c09fba 100644 --- a/frida_mode/src/prefetch.c +++ b/frida_mode/src/prefetch.c @@ -3,9 +3,12 @@ #include #include "frida-gum.h" -#include "prefetch.h" + #include "debug.h" +#include "prefetch.h" +#include "stalker.h" + #define TRUST 0 #define PREFETCH_SIZE 65536 #define PREFETCH_ENTRIES ((PREFETCH_SIZE - sizeof(size_t)) / sizeof(void *)) @@ -49,8 +52,9 @@ void prefetch_write(void *addr) { /* * Read the IPC region one block at the time and prefetch it */ -void prefetch_read(GumStalker *stalker) { +void prefetch_read(void) { + GumStalker *stalker = stalker_get(); if (prefetch_data == NULL) return; for (size_t i = 0; i < prefetch_data->count; i++) { @@ -68,7 +72,7 @@ void prefetch_read(GumStalker *stalker) { } -void prefetch_init() { +void prefetch_init(void) { g_assert_cmpint(sizeof(prefetch_data_t), ==, PREFETCH_SIZE); gboolean prefetch = (getenv("AFL_FRIDA_INST_NO_PREFETCH") == NULL); @@ -106,16 +110,3 @@ void prefetch_init() { } -__attribute__((noinline)) static void prefetch_activation() { - - asm volatile(""); - -} - -void prefetch_start(GumStalker *stalker) { - - gum_stalker_activate(stalker, prefetch_activation); - prefetch_activation(); - -} - diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c index 49ef5a62..6fcbd258 100644 --- a/frida_mode/src/ranges.c +++ b/frida_mode/src/ranges.c @@ -1,9 +1,11 @@ -// 0x123-0x321 -// module.so +#include "frida-gum.h" -#include "ranges.h" #include "debug.h" +#include "lib.h" +#include "ranges.h" +#include "stalker.h" + #define MAX_RANGES 20 typedef struct { @@ -14,15 +16,11 @@ typedef struct { } convert_name_ctx_t; -typedef struct { - - GumStalker *stalker; - GArray * array; - -} include_range_ctx_t; - -GArray * ranges = NULL; -gboolean exclude_ranges = false; +GArray *module_ranges = NULL; +GArray *libs_ranges = NULL; +GArray *include_ranges = NULL; +GArray *exclude_ranges = NULL; +GArray *ranges = NULL; static void convert_address_token(gchar *token, GumMemoryRange *range) { @@ -159,214 +157,395 @@ static void convert_token(gchar *token, GumMemoryRange *range) { } -static gboolean include_ranges(const GumRangeDetails *details, - gpointer user_data) { +gint range_sort(gconstpointer a, gconstpointer b) { - 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; + return ((GumMemoryRange *)a)->base_address - + ((GumMemoryRange *)b)->base_address; - 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++) { +static gboolean print_ranges_callback(const GumRangeDetails *details, + gpointer user_data) { - GumMemoryRange *range = &g_array_index(array, GumMemoryRange, i); - GumAddress range_base = range->base_address; - GumAddress range_limit = range->base_address + range->size; + if (details->file == NULL) { - /* Before the region */ - if (range_limit < base) { continue; } + 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); - /* After the region */ - if (range_base > limit) { + } else { - 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; + 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); - } + } - /* Overlap the start of the region */ - if (range_base < base) { + return true; - /* Range contains the region */ - if (range_limit > limit) { +} - return true; +static void print_ranges(char *key, GArray *ranges) { - } else { + OKF("Range: %s Length: %d", key, ranges->len); + for (int i = 0; i < ranges->len; i++) { - base = range_limit; - continue; + GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); + GumAddress curr_limit = curr->base_address + curr->size; + OKF("Range: %s Idx: %3d - 0x%016" G_GINT64_MODIFIER + "x-0x%016" G_GINT64_MODIFIER "x", + key, i, curr->base_address, curr_limit); - } + } - /* Overlap the end of the region */ +} - } else { +static gboolean collect_module_ranges_callback(const GumRangeDetails *details, + gpointer user_data) { - 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) { + GArray * ranges = (GArray *)user_data; + GumMemoryRange range = *details->range; + g_array_append_val(ranges, range); + return TRUE; - return true; +} - /* Contained within the region */ +static GArray *collect_module_ranges(void) { - } else { + GArray *result; + result = g_array_new(false, false, sizeof(GumMemoryRange)); + gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, + collect_module_ranges_callback, result); + print_ranges("Modules", result); + return result; - base = range_limit; - continue; +} - } +static GArray *collect_ranges(char *env_key) { - } + char * env_val; + gchar ** tokens; + int token_count; + GumMemoryRange range; + int i; + GArray * result; + + result = g_array_new(false, false, sizeof(GumMemoryRange)); + + env_val = getenv(env_key); + if (env_val == NULL) return result; + + tokens = g_strsplit(env_val, ",", MAX_RANGES); + + for (token_count = 0; tokens[token_count] != NULL; token_count++) + ; + + for (i = 0; i < token_count; i++) { + + convert_token(tokens[i], &range); + g_array_append_val(result, range); } - 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; + g_array_sort(result, range_sort); -} + /* Check for overlaps */ + for (i = 1; i < token_count; i++) { -gint range_sort(gconstpointer a, gconstpointer b) { + GumMemoryRange *prev = &g_array_index(result, GumMemoryRange, i - 1); + GumMemoryRange *curr = &g_array_index(result, GumMemoryRange, i); + GumAddress prev_limit = prev->base_address + prev->size; + GumAddress curr_limit = curr->base_address + curr->size; + if (prev_limit > curr->base_address) { - return ((GumMemoryRange *)a)->base_address - - ((GumMemoryRange *)b)->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); + + } + + } + + print_ranges(env_key, result); + + g_strfreev(tokens); + + return result; } -static gboolean print_ranges(const GumRangeDetails *details, - gpointer user_data) { +static GArray *collect_libs_ranges(void) { - if (details->file == NULL) { + GArray * result; + GumMemoryRange range; + result = g_array_new(false, false, sizeof(GumMemoryRange)); - 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); + if (getenv("AFL_INST_LIBS") == NULL) { + + range.base_address = lib_get_text_base(); + range.size = lib_get_text_limit() - lib_get_text_base(); } 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); + range.base_address = 0; + range.size = G_MAXULONG; } + g_array_append_val(result, range); + + print_ranges("AFL_INST_LIBS", result); + + return result; + +} + +static gboolean intersect_range(GumMemoryRange *rr, GumMemoryRange *ra, + GumMemoryRange *rb) { + + GumAddress rab = ra->base_address; + GumAddress ral = rab + ra->size; + + GumAddress rbb = rb->base_address; + GumAddress rbl = rbb + rb->size; + + GumAddress rrb = 0; + GumAddress rrl = 0; + + rr->base_address = 0; + rr->size = 0; + + /* ra is before rb */ + if (ral < rbb) { return false; } + + /* ra is after rb */ + if (rab > rbl) { return true; } + + /* The largest of the two base addresses */ + rrb = rab > rbb ? rab : rbb; + + /* The smallest of the two limits */ + rrl = ral < rbl ? ral : rbl; + + rr->base_address = rrb; + rr->size = rrl - rrb; return true; } -void ranges_init(GumStalker *stalker) { +static GArray *intersect_ranges(GArray *a, GArray *b) { - char * showmaps; - char * include; - char * exclude; - char * list; - gchar ** tokens; - int token_count; - GumMemoryRange range; + GArray * result; + GumMemoryRange *ra; + GumMemoryRange *rb; + GumMemoryRange ri; - int i; + result = g_array_new(false, false, sizeof(GumMemoryRange)); - showmaps = getenv("AFL_FRIDA_DEBUG_MAPS"); - include = getenv("AFL_FRIDA_INST_RANGES"); - exclude = getenv("AFL_FRIDA_EXCLUDE_RANGES"); + for (int i = 0; i < a->len; i++) { - if (showmaps) { + ra = &g_array_index(a, GumMemoryRange, i); + for (int j = 0; j < b->len; j++) { - gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges, NULL); + rb = &g_array_index(b, GumMemoryRange, j); - } + if (!intersect_range(&ri, ra, rb)) { break; } + + if (ri.size == 0) { continue; } - if (include != NULL && exclude != NULL) { + g_array_append_val(result, ri); - FATAL( - "Cannot specifify both AFL_FRIDA_INST_RANGES and " - "AFL_FRIDA_EXCLUDE_RANGES"); + } } - if (include == NULL && exclude == NULL) { return; } + return result; - list = include == NULL ? exclude : include; - exclude_ranges = include == NULL ? true : false; +} - tokens = g_strsplit(list, ",", MAX_RANGES); +static GArray *subtract_ranges(GArray *a, GArray *b) { - for (token_count = 0; tokens[token_count] != NULL; token_count++) - ; + GArray * result; + GumMemoryRange *ra; + GumAddress ral; + GumMemoryRange *rb; + GumMemoryRange ri; + GumMemoryRange rs; - ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), token_count); + result = g_array_new(false, false, sizeof(GumMemoryRange)); - for (i = 0; i < token_count; i++) { + for (int i = 0; i < a->len; i++) { - convert_token(tokens[i], &range); - g_array_append_val(ranges, range); + ra = &g_array_index(a, GumMemoryRange, i); + ral = ra->base_address + ra->size; + for (int j = 0; j < b->len; j++) { + + rb = &g_array_index(b, GumMemoryRange, j); + + /* + * If rb is after ra, we have no more possible intersections and we can + * simply keep the remaining range + */ + if (!intersect_range(&ri, ra, rb)) { break; } + + /* + * If there is no intersection, then rb must be before ra, so we must + * continue + */ + if (ri.size == 0) { continue; } + + /* + * If the intersection is part way through the range, then we keep the + * start of the range + */ + if (ra->base_address < ri.base_address) { + + rs.base_address = ra->base_address; + rs.size = ri.base_address - ra->base_address; + g_array_append_val(result, rs); + + } + + /* + * If the intersection extends past the limit of the range, then we should + * continue with the next range + */ + if ((ri.base_address + ri.size) > ral) { + + ra->base_address = ral; + ra->size = 0; + break; + + } + + /* + * Otherwise we advance the base of the range to the end of the + * intersection and continue with the remainder of the range + */ + ra->base_address = ri.base_address + ri.size; + ra->size = ral - ra->base_address; + + } + + /* + * When we have processed all the possible intersections, we add what is + * left + */ + if (ra->size != 0) g_array_append_val(result, *ra); } - g_array_sort(ranges, range_sort); + return result; - /* 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) { +static GArray *merge_ranges(GArray *a) { - 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); + GArray * result; + GumMemoryRange rp; + GumMemoryRange *r; + + result = g_array_new(false, false, sizeof(GumMemoryRange)); + if (a->len == 0) return result; + + rp = g_array_index(a, GumMemoryRange, 0); + + for (int i = 1; i < a->len; i++) { + + r = &g_array_index(a, GumMemoryRange, i); + + if (rp.base_address + rp.size == r->base_address) { + + rp.size += r->size; + + } else { + + g_array_append_val(result, rp); + rp.base_address = r->base_address; + rp.size = r->size; + continue; } } - for (i = 0; i < token_count; i++) { + g_array_append_val(result, rp); - 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); + return result; + +} + +void ranges_init(void) { + + GumMemoryRange ri; + GArray * step1; + GArray * step2; + GArray * step3; + GArray * step4; + GumMemoryRange *r; + GumStalker * stalker; + + if (getenv("AFL_FRIDA_DEBUG_MAPS") != NULL) { + + gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges_callback, + NULL); } - if (include == NULL) { + module_ranges = collect_module_ranges(); + libs_ranges = collect_libs_ranges(); + include_ranges = collect_ranges("AFL_FRIDA_INST_RANGES"); - for (i = 0; i < token_count; i++) { + /* If include ranges is empty, then assume everything is included */ + if (include_ranges->len == 0) { - gum_stalker_exclude(stalker, &g_array_index(ranges, GumMemoryRange, i)); + ri.base_address = 0; + ri.size = G_MAXULONG; + g_array_append_val(include_ranges, ri); - } + } - } else { + exclude_ranges = collect_ranges("AFL_FRIDA_EXCLUDE_RANGES"); - include_range_ctx_t ctx = {.stalker = stalker, .array = ranges}; - gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, include_ranges, &ctx); + /* Intersect with .text section of main executable unless AFL_INST_LIBS */ + step1 = intersect_ranges(module_ranges, libs_ranges); + print_ranges("step1", step1); + + /* Intersect with AFL_FRIDA_INST_RANGES */ + step2 = intersect_ranges(step1, include_ranges); + print_ranges("step2", step2); + + /* Subtract AFL_FRIDA_EXCLUDE_RANGES */ + step3 = subtract_ranges(step2, exclude_ranges); + print_ranges("step3", step3); + + /* + * After step3, we have the total ranges to be instrumented, we now subtract + * that from the original ranges of the modules to configure stalker. + */ + + step4 = subtract_ranges(module_ranges, step3); + print_ranges("step4", step4); + + ranges = merge_ranges(step4); + print_ranges("final", ranges); + + stalker = stalker_get(); + + for (int i = 0; i < ranges->len; i++) { + + r = &g_array_index(ranges, GumMemoryRange, i); + gum_stalker_exclude(stalker, r); } - g_strfreev(tokens); + g_array_free(step4, TRUE); + g_array_free(step3, TRUE); + g_array_free(step2, TRUE); + g_array_free(step1, TRUE); } @@ -382,13 +561,13 @@ gboolean range_is_excluded(gpointer address) { 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->base_address) { return false; } - if (test < curr_limit) { return exclude_ranges; } + if (test < curr_limit) { return true; } } - return !exclude_ranges; + return false; } diff --git a/frida_mode/src/stalker.c b/frida_mode/src/stalker.c new file mode 100644 index 00000000..5ee519ba --- /dev/null +++ b/frida_mode/src/stalker.c @@ -0,0 +1,49 @@ +#include "debug.h" + +#include "instrument.h" +#include "stalker.h" + +static GumStalker *stalker = NULL; + +void stalker_init(void) { + + stalker = gum_stalker_new(); + if (stalker == NULL) { FATAL("Failed to initialize stalker"); } + + gum_stalker_set_trust_threshold(stalker, 0); + +} + +GumStalker *stalker_get(void) { + + if (stalker == NULL) { FATAL("Stalker uninitialized"); } + return stalker; + +} + +__attribute__((noinline)) static void stalker_activation(void) { + + asm volatile(""); + +} + +void stalker_start(void) { + + GumStalkerTransformer *transformer = instrument_get_transformer(); + gum_stalker_follow_me(stalker, transformer, NULL); + +} + +void stalker_pause(void) { + + gum_stalker_deactivate(stalker); + +} + +void stalker_resume(void) { + + gum_stalker_activate(stalker, stalker_activation); + stalker_activation(); + +} + diff --git a/frida_mode/src/util.c b/frida_mode/src/util.c new file mode 100644 index 00000000..f42afd64 --- /dev/null +++ b/frida_mode/src/util.c @@ -0,0 +1,66 @@ +#include "util.h" + +#include "debug.h" + +guint64 util_read_address(char *key) { + + char *value_str = getenv(key); + + if (value_str == NULL) { return 0; } + + if (!g_str_has_prefix(value_str, "0x")) { + + FATAL("Invalid address should have 0x prefix: %s\n", value_str); + + } + + value_str = &value_str[2]; + + for (char *c = value_str; *c != '\0'; c++) { + + if (!g_ascii_isxdigit(*c)) { + + FATAL("Invalid address not formed of hex digits: %s\n", value_str); + + } + + } + + guint64 value = g_ascii_strtoull(value_str, NULL, 16); + if (value == 0) { + + FATAL("Invalid address failed hex conversion: %s\n", value_str); + + } + + return value; + +} + +guint64 util_read_num(char *key) { + + char *value_str = getenv(key); + + if (value_str == NULL) { return 0; } + + for (char *c = value_str; *c != '\0'; c++) { + + if (!g_ascii_isdigit(*c)) { + + FATAL("Invalid address not formed of decimal digits: %s\n", value_str); + + } + + } + + guint64 value = g_ascii_strtoull(value_str, NULL, 10); + if (value == 0) { + + FATAL("Invalid address failed numeric conversion: %s\n", value_str); + + } + + return value; + +} + diff --git a/frida_mode/test/cmplog/GNUmakefile b/frida_mode/test/cmplog/GNUmakefile new file mode 100644 index 00000000..c203fc5e --- /dev/null +++ b/frida_mode/test/cmplog/GNUmakefile @@ -0,0 +1,66 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../../)/ +BUILD_DIR:=$(PWD)build/ + +TEST_CMPLOG_DIR:=$(ROOT)qemu_mode/libcompcov/ +TEST_CMPLOG_OBJ=$(TEST_CMPLOG_DIR)compcovtest + +TEST_BIN:=$(PWD)../../build/test + + +TEST_DATA_DIR:=$(BUILD_DIR)in/ +CMP_LOG_INPUT:=$(TEST_DATA_DIR)in +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_INST_RANGES=$(shell $(PWD)get_section_addrs.py -f $(TEST_CMPLOG_OBJ) -s .text -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_INST_RANGES=$(shell $(PWD)get_section_addrs.py -f $(TEST_CMPLOG_OBJ) -s .text -b 0x0000555555554000) +endif + +.PHONY: all clean qemu frida + +all: + make -C $(ROOT)frida_mode/ + +$(BUILD_DIR): + mkdir -p $@ + +$(TEST_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(CMP_LOG_INPUT): | $(TEST_DATA_DIR) + truncate -s 64 $@ + +$(TEST_CMPLOG_OBJ): $(TEST_CMPLOG_DIR)compcovtest.cc + make -C $(TEST_CMPLOG_DIR) compcovtest + +qemu: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT) + $(ROOT)afl-fuzz \ + -D \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -c 0 \ + -l 3AT \ + -- \ + $(TEST_CMPLOG_OBJ) @@ + +frida: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT) + XAFL_FRIDA_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -c 0 \ + -l 3AT \ + -- \ + $(TEST_CMPLOG_OBJ) @@ + +clean: + rm -rf $(BUILD_DIR) \ No newline at end of file diff --git a/frida_mode/test/cmplog/Makefile b/frida_mode/test/cmplog/Makefile new file mode 100644 index 00000000..f322d1f5 --- /dev/null +++ b/frida_mode/test/cmplog/Makefile @@ -0,0 +1,12 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +frida: + @gmake frida \ No newline at end of file diff --git a/frida_mode/test/cmplog/get_section_addrs.py b/frida_mode/test/cmplog/get_section_addrs.py new file mode 100755 index 00000000..f648808b --- /dev/null +++ b/frida_mode/test/cmplog/get_section_addrs.py @@ -0,0 +1,49 @@ +#!/usr/bin/env 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() diff --git a/frida_mode/test/png/GNUmakefile b/frida_mode/test/png/GNUmakefile new file mode 100644 index 00000000..c381f5ab --- /dev/null +++ b/frida_mode/test/png/GNUmakefile @@ -0,0 +1,106 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ + +LIBPNG_BUILD_DIR:=$(BUILD_DIR)libpng/ +HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/ +PNGTEST_BUILD_DIR:=$(BUILD_DIR)pngtest/ + +LIBPNG_FILE:=$(LIBPNG_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:=$(LIBPNG_BUILD_DIR)libpng-1.2.56/ +LIBPNG_MAKEFILE:=$(LIBPNG_DIR)Makefile +LIBPNG_LIB:=$(LIBPNG_DIR).libs/libpng12.a + +HARNESS_FILE:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.c +HARNESS_OBJ:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.o +HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c" + +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" + +TEST_BIN:=$(BUILD_DIR)test + +TEST_DATA_DIR:=$(LIBPNG_DIR)contrib/pngsuite/ + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +.PHONY: all clean qemu frida + +all: $(TEST_BIN) + make -C $(ROOT)frida_mode/ + +$(BUILD_DIR): + mkdir -p $@ + +######### HARNESS ######## +$(HARNESS_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(HARNESS_FILE): | $(HARNESS_BUILD_DIR) + wget -O $@ $(HARNESS_URL) + +$(HARNESS_OBJ): $(HARNESS_FILE) + $(CC) -o $@ -c $< + +######### PNGTEST ######## + +$(PNGTEST_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(PNGTEST_FILE): | $(PNGTEST_BUILD_DIR) + wget -O $@ $(PNGTEST_URL) + +$(PNGTEST_OBJ): $(PNGTEST_FILE) | $(LIBPNG_DIR) + $(CXX) -std=c++11 -I $(LIBPNG_DIR) -o $@ -c $< + +######### LIBPNG ######## + +$(LIBPNG_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(LIBPNG_FILE): | $(LIBPNG_BUILD_DIR) + wget -O $@ $(LIBPNG_URL) + +$(LIBPNG_DIR): $(LIBPNG_FILE) + tar zxvf $(LIBPNG_FILE) -C $(LIBPNG_BUILD_DIR) + +$(LIBPNG_MAKEFILE): | $(LIBPNG_DIR) + cd $(LIBPNG_DIR) && ./configure + +$(LIBPNG_LIB): $(LIBPNG_MAKEFILE) + make -C $(LIBPNG_DIR) + +######### TEST ######## + +$(TEST_BIN): $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) + $(CXX) \ + -o $@ \ + $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) \ + -lz \ + $(TEST_LDFLAGS) + +clean: + rm -rf $(BUILD_DIR) + +qemu: $(TEST_BIN) + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) @@ + +frida: $(TEST_BIN) + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) @@ diff --git a/frida_mode/test/png/Makefile b/frida_mode/test/png/Makefile new file mode 100644 index 00000000..f322d1f5 --- /dev/null +++ b/frida_mode/test/png/Makefile @@ -0,0 +1,12 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +frida: + @gmake frida \ No newline at end of file diff --git a/frida_mode/test/png/persistent/GNUmakefile b/frida_mode/test/png/persistent/GNUmakefile new file mode 100644 index 00000000..25ddc782 --- /dev/null +++ b/frida_mode/test/png/persistent/GNUmakefile @@ -0,0 +1,54 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../../..)/ +BUILD_DIR:=$(PWD)build/ + +TEST_BIN:=$(PWD)../build/test +TEST_DATA_DIR:=../build/libpng/libpng-1.2.56/contrib/pngsuite/ + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x4000000000) + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x0000555555554000) +endif + +.PHONY: all clean qemu frida + +all: + make -C $(ROOT)frida_mode/test/png/ + +$(BUILD_DIR): + mkdir -p $@ + +qemu: | $(BUILD_DIR) + AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_GPR=1 \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) @@ + +frida: | $(BUILD_DIR) + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) @@ + +clean: + rm -rf $(BUILD_DIR) \ No newline at end of file diff --git a/frida_mode/test/png/persistent/Makefile b/frida_mode/test/png/persistent/Makefile new file mode 100644 index 00000000..f322d1f5 --- /dev/null +++ b/frida_mode/test/png/persistent/Makefile @@ -0,0 +1,12 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +frida: + @gmake frida \ No newline at end of file diff --git a/frida_mode/test/png/persistent/get_symbol_addr.py b/frida_mode/test/png/persistent/get_symbol_addr.py new file mode 100755 index 00000000..6458c212 --- /dev/null +++ b/frida_mode/test/png/persistent/get_symbol_addr.py @@ -0,0 +1,36 @@ +#!/usr/bin/python3 +import argparse +from elftools.elf.elffile import ELFFile + +def process_file(file, symbol, base): + with open(file, 'rb') as f: + elf = ELFFile(f) + symtab = elf.get_section_by_name('.symtab') + mains = symtab.get_symbol_by_name(symbol) + if len(mains) != 1: + print ("Failed to find main") + return 1 + + main_addr = mains[0]['st_value'] + main = base + main_addr + print ("0x%016x" % main) + return 0 + +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', '--symbol', dest='symbol', type=str, + help='symbol name', required=True) + parser.add_argument('-b', '--base', dest='base', type=hex_value, + help='elf base address', required=True) + + args = parser.parse_args() + return process_file (args.file, args.symbol, args.base) + +if __name__ == "__main__": + ret = main() + exit(ret) \ No newline at end of file diff --git a/frida_mode/test/png/persistent/hook/GNUmakefile b/frida_mode/test/png/persistent/hook/GNUmakefile new file mode 100644 index 00000000..2457287d --- /dev/null +++ b/frida_mode/test/png/persistent/hook/GNUmakefile @@ -0,0 +1,70 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../../../..)/ +BUILD_DIR:=$(PWD)build/ + +AFLPP_DRIVER_HOOK_DIR=$(ROOT)utils/aflpp_driver/ +AFLPP_DRIVER_HOOK_OBJ=$(AFLPP_DRIVER_HOOK_DIR)aflpp_qemu_driver_hook.so + +TEST_BIN:=$(PWD)../../build/test +TEST_DATA_DIR:=../../build/libpng/libpng-1.2.56/contrib/pngsuite/ + +AFLPP_DRIVER_DUMMY_INPUT:=$(BUILD_DIR)in +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000) + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000) +endif + +.PHONY: all clean qemu frida + +all: + make -C $(ROOT)frida_mode/test/png/persistent/ + +$(BUILD_DIR): + mkdir -p $@ + +$(TEST_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR) + truncate -s 1M $@ + +$(AFLPP_DRIVER_HOOK_OBJ): | $(AFLPP_DRIVER_HOOK_DIR) + make -C $(AFLPP_DRIVER_HOOK_DIR) + +qemu: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) + AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_GPR=1 \ + $(ROOT)/afl-fuzz \ + -D \ + -V 30 \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +frida: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +clean: + rm -rf $(BUILD_DIR) + diff --git a/frida_mode/test/png/persistent/hook/Makefile b/frida_mode/test/png/persistent/hook/Makefile new file mode 100644 index 00000000..f322d1f5 --- /dev/null +++ b/frida_mode/test/png/persistent/hook/Makefile @@ -0,0 +1,12 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +frida: + @gmake frida \ No newline at end of file diff --git a/frida_mode/test/testinstr.c b/frida_mode/test/testinstr.c deleted file mode 100644 index 37d47f91..00000000 --- a/frida_mode/test/testinstr.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - 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 -#include -#include -#include -#include - -#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); - if (buf == NULL) { - - perror("malloc"); - break; - - } - - 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; - -} - diff --git a/frida_mode/test/testinstr.py b/frida_mode/test/testinstr.py deleted file mode 100755 index f648808b..00000000 --- a/frida_mode/test/testinstr.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env 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() diff --git a/frida_mode/test/testinstr/GNUmakefile b/frida_mode/test/testinstr/GNUmakefile new file mode 100644 index 00000000..9aa24ee5 --- /dev/null +++ b/frida_mode/test/testinstr/GNUmakefile @@ -0,0 +1,50 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ +TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ +TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in + +TESTINSTBIN:=$(BUILD_DIR)testinstr +TESTINSTSRC:=$(PWD)testinstr.c + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +.PHONY: all clean qemu frida + +all: $(TESTINSTBIN) + make -C $(ROOT)frida_mode/ + +$(BUILD_DIR): + mkdir -p $@ + +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) + echo -n "000" > $@ + +$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) + $(CC) -o $@ $< + +clean: + rm -rf $(BUILD_DIR) + + +qemu: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + $(ROOT)afl-fuzz \ + -D \ + -Q \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TESTINSTBIN) @@ + +frida: $(FRIDA_TRACE) $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ \ No newline at end of file diff --git a/frida_mode/test/testinstr/Makefile b/frida_mode/test/testinstr/Makefile new file mode 100644 index 00000000..f322d1f5 --- /dev/null +++ b/frida_mode/test/testinstr/Makefile @@ -0,0 +1,12 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +frida: + @gmake frida \ No newline at end of file diff --git a/frida_mode/test/testinstr/testinstr.c b/frida_mode/test/testinstr/testinstr.c new file mode 100644 index 00000000..5e26fc46 --- /dev/null +++ b/frida_mode/test/testinstr/testinstr.c @@ -0,0 +1,112 @@ +/* + 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 +#include +#include +#include +#include + +#ifdef __APPLE__ + #define TESTINSTR_SECTION +#else + #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) +#endif + +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"); + +} + +TESTINSTR_SECTION 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); + if (buf == NULL) { + + perror("malloc"); + break; + + } + + 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; + +} + diff --git a/include/envs.h b/include/envs.h index ebe98257..cd23ca3f 100644 --- a/include/envs.h +++ b/include/envs.h @@ -59,6 +59,9 @@ static char *afl_environment_variables[] = { "AFL_FRIDA_INST_RANGES", "AFL_FRIDA_INST_STRICT", "AFL_FRIDA_INST_TRACE", + "AFL_FRIDA_PERSISTENT_ADDR", + "AFL_FRIDA_PERSISTENT_CNT", + "AFL_FRIDA_PERSISTENT_HOOK", "AFL_FUZZER_ARGS", // oss-fuzz "AFL_GDB", "AFL_GCC_ALLOWLIST", diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 552bbea8..2089ce78 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -79,8 +79,9 @@ #endif #if defined(__HAIKU__) - extern ssize_t _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize); -#endif // HAIKU +extern ssize_t _kern_write(int fd, off_t pos, const void *buffer, + size_t bufferSize); +#endif // HAIKU u8 __afl_area_initial[MAP_INITIAL_SIZE]; u8 * __afl_area_ptr_dummy = __afl_area_initial; @@ -1754,11 +1755,11 @@ static int area_is_valid(void *ptr, size_t len) { if (unlikely(!ptr || __asan_region_is_poisoned(ptr, len))) { return 0; } - #ifndef __HAIKU__ - long r = syscall(SYS_write, __afl_dummy_fd[1], ptr, len); - #else - long r = _kern_write(__afl_dummy_fd[1], -1, ptr, len); - #endif // HAIKU +#ifndef __HAIKU__ + long r = syscall(SYS_write, __afl_dummy_fd[1], ptr, len); +#else + long r = _kern_write(__afl_dummy_fd[1], -1, ptr, len); +#endif // HAIKU if (r <= 0 || r > len) return 0; diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index f6cdbe9e..68bd2fa5 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -89,11 +89,11 @@ class AFLLTOPass : public ModulePass { bool runOnModule(Module &M) override; protected: - uint32_t afl_global_id = 1, autodictionary = 1; - uint32_t function_minimum_size = 1; - uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0; + uint32_t afl_global_id = 1, autodictionary = 1; + uint32_t function_minimum_size = 1; + uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0; unsigned long long int map_addr = 0x10000; - char * skip_nozero = NULL; + char * skip_nozero = NULL; }; diff --git a/qemu_mode/qemuafl b/qemu_mode/qemuafl index d73b0336..d1ca56b8 160000 --- a/qemu_mode/qemuafl +++ b/qemu_mode/qemuafl @@ -1 +1 @@ -Subproject commit d73b0336b451fd034e5f469089fb7ee96c80adf2 +Subproject commit d1ca56b84e78f821406eef28d836918edfc8d610 diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 727e7f8d..d533fd4a 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -416,7 +416,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, struct rlimit r; - if (!fsrv->cmplog_binary && fsrv->qemu_mode == false) { + if (!fsrv->cmplog_binary && fsrv->qemu_mode == false && + fsrv->frida_mode == false) { unsetenv(CMPLOG_SHM_ENV_VAR); // we do not want that in non-cmplog fsrv diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index 27c6c413..c2e9c80f 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -35,7 +35,7 @@ void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) { if (fsrv->qemu_mode) { setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0); } - if (!fsrv->qemu_mode && argv[0] != fsrv->cmplog_binary) { + if (!fsrv->qemu_mode && !fsrv->frida_mode && argv[0] != fsrv->cmplog_binary) { argv[0] = fsrv->cmplog_binary; diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index b6bfbc29..547311c7 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2774,6 +2774,14 @@ void check_binary(afl_state_t *afl, u8 *fname) { WARNF("AFL_PERSISTENT is no longer supported and may misbehave!"); + } else if (getenv("AFL_FRIDA_PERSISTENT_ADDR")) { + + OKF("FRIDA Persistent mode configuration options detected."); + setenv(PERSIST_ENV_VAR, "1", 1); + afl->persistent_mode = 1; + + afl->shmem_testcase_mode = 1; + } if (afl->fsrv.frida_mode || diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 3606533d..58b0a5c2 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1697,13 +1697,14 @@ int main(int argc, char **argv_orig, char **envp) { // TODO: this is semi-nice afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits; afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode; + afl->cmplog_fsrv.frida_mode = afl->fsrv.frida_mode; afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary; afl->cmplog_fsrv.init_child_func = cmplog_exec_child; if ((map_size <= DEFAULT_SHMEM_SIZE || afl->cmplog_fsrv.map_size < map_size) && !afl->non_instrumented_mode && !afl->fsrv.qemu_mode && - !afl->unicorn_mode) { + !afl->fsrv.frida_mode && !afl->unicorn_mode) { afl->cmplog_fsrv.map_size = MAX(map_size, (u32)DEFAULT_SHMEM_SIZE); char vbuf[16]; -- cgit 1.4.1 From 29dbe665a7a7dc6b2232487dbc6c1ebecbbdfb06 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 29 Apr 2021 09:12:21 +0200 Subject: nits --- src/afl-fuzz.c | 2 ++ utils/libdislocator/libdislocator.so.c | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 58b0a5c2..1b3e303c 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1358,6 +1358,7 @@ int main(int argc, char **argv_orig, char **envp) { afl_preload = getenv("AFL_PRELOAD"); u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + OKF("Injecting %s ...", frida_binary); if (afl_preload) { frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); @@ -1383,6 +1384,7 @@ 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"); + OKF("Injecting %s ...", frida_binary); setenv("LD_PRELOAD", frida_binary, 1); setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); ck_free(frida_binary); diff --git a/utils/libdislocator/libdislocator.so.c b/utils/libdislocator/libdislocator.so.c index 7c651afd..dde78f7b 100644 --- a/utils/libdislocator/libdislocator.so.c +++ b/utils/libdislocator/libdislocator.so.c @@ -145,7 +145,7 @@ typedef struct { /* Configurable stuff (use AFL_LD_* to set): */ static size_t max_mem = MAX_ALLOC; /* Max heap usage to permit */ -static u8 alloc_verbose, /* Additional debug messages */ +static u8 alloc_verbose, /* Additional debug messages */ hard_fail, /* abort() when max_mem exceeded? */ no_calloc_over, /* abort() on calloc() overflows? */ align_allocations; /* Force alignment to sizeof(void*) */ @@ -504,7 +504,7 @@ __attribute__((constructor)) void __dislocator_init(void) { if (tmp) { - char *tok; + char * tok; unsigned long long mmem = strtoull(tmp, &tok, 10); if (*tok != '\0' || errno == ERANGE || mmem > SIZE_MAX / 1024 / 1024) FATAL("Bad value for AFL_LD_LIMIT_MB"); @@ -550,3 +550,4 @@ void *erealloc(void *ptr, size_t len) { return realloc(ptr, len); } + -- cgit 1.4.1 From e9d2f72382cab75832721d859c3e731da071435d Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 30 Apr 2021 13:35:24 +0200 Subject: fixed potential double free in custom trim (#881) --- include/afl-fuzz.h | 4 ++-- src/afl-fuzz-mutators.c | 23 +++++++++++++++++------ src/afl-fuzz-one.c | 8 ++++---- src/afl-fuzz-run.c | 8 ++++++-- 4 files changed, 29 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index f201782a..040d7ae9 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1003,7 +1003,7 @@ void read_afl_environment(afl_state_t *, char **); /* Custom mutators */ void setup_custom_mutators(afl_state_t *); void destroy_custom_mutators(afl_state_t *); -u8 trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf, +u8 trim_case_custom(afl_state_t *, struct queue_entry *q, u8 **in_buf, struct custom_mutator *mutator); /* Python */ @@ -1093,7 +1093,7 @@ fsrv_run_result_t fuzz_run_target(afl_state_t *, afl_forkserver_t *fsrv, u32); void write_to_testcase(afl_state_t *, void *, u32); u8 calibrate_case(afl_state_t *, struct queue_entry *, u8 *, u32, u8); void sync_fuzzers(afl_state_t *); -u8 trim_case(afl_state_t *, struct queue_entry *, u8 *); +u8 trim_case(afl_state_t *, struct queue_entry *, u8 **); u8 common_fuzz_stuff(afl_state_t *, u8 *, u32); /* Fuzz one */ diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index c99d9a4d..d8db8676 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -305,9 +305,13 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) { } -u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, +// Custom testcase trimming. +u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 **in_buf_p, struct custom_mutator *mutator) { + // We need to pass pointers around, as growing testcases may need to realloc. + u8 *in_buf = *in_buf_p; + u8 needs_write = 0, fault = 0; u32 trim_exec = 0; u32 orig_len = q->len; @@ -397,14 +401,21 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, if (likely(retlen && cksum == q->exec_cksum)) { - if (afl_realloc((void **)&in_buf, retlen) == NULL) { + // Check if we got a new retbuf and to memcpy our buf. + if (in_buf != retbuf) { - FATAL("can not allocate memory for trim"); + if (afl_realloc((void **)in_buf_p, retlen) == NULL) { - } + FATAL("can not allocate memory for trim"); + + } - memcpy(in_buf, retbuf, retlen); - q->len = retlen; + in_buf = *in_buf_p; + + memcpy(in_buf, retbuf, retlen); + q->len = retlen; + + } /* Let's save a clean trace, which will be needed by update_bitmap_score once we're done with the trimming stuff. */ diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index d72d4145..ed815cb4 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -508,7 +508,7 @@ u8 fuzz_one_original(afl_state_t *afl) { u32 old_len = afl->queue_cur->len; - u8 res = trim_case(afl, afl->queue_cur, in_buf); + u8 res = trim_case(afl, afl->queue_cur, &in_buf); orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur); if (unlikely(res == FSRV_RUN_ERROR)) { @@ -3007,16 +3007,16 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { u32 old_len = afl->queue_cur->len; - u8 res = trim_case(afl, afl->queue_cur, in_buf); + u8 res = trim_case(afl, afl->queue_cur, &in_buf); orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur); - if (res == FSRV_RUN_ERROR) { + if (unlikely(res == FSRV_RUN_ERROR)) { FATAL("Unable to execute target application"); } - if (afl->stop_soon) { + if (unlikely(afl->stop_soon)) { ++afl->cur_skipped_paths; goto abandon_entry; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 832f17bb..a7b071a5 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -720,7 +720,10 @@ void sync_fuzzers(afl_state_t *afl) { trimmer uses power-of-two increments somewhere between 1/16 and 1/1024 of file size, to keep the stage short and sweet. */ -u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { +u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 **in_buf_p) { + + // We need to pass pointers around, as growing testcases may need to realloc. + u8 *in_buf = *in_buf_p; u32 orig_len = q->len; @@ -734,7 +737,8 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { if (el->afl_custom_trim) { - trimmed_case = trim_case_custom(afl, q, in_buf, el); + trimmed_case = trim_case_custom(afl, q, in_buf_p, el); + in_buf = *in_buf_p; custom_trimmed = true; } -- cgit 1.4.1 From 38f1394e3ab5ccacff07e27f370f3edf1ce77afb Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 30 Apr 2021 13:36:35 +0200 Subject: error handling, freeing mem --- src/afl-cc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/afl-cc.c b/src/afl-cc.c index 1f89bac5..09009334 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -560,12 +560,14 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (lto_mode && !have_c) { u8 *ld_path = strdup(AFL_REAL_LD); - if (!*ld_path) ld_path = "ld.lld"; + if (!ld_path || !*ld_path) { ld_path = strdup("ld.lld"); } + if (!ld_path) { PFATAL("Could not allocate mem for ld_path"); } #if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 12 cc_params[cc_par_cnt++] = alloc_printf("--ld-path=%s", ld_path); #else cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", ld_path); #endif + free(ld_path); cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition"; -- cgit 1.4.1 From 56882f3a496fd287b50a18ec7c83d23e1630ef81 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 30 Apr 2021 13:44:59 +0200 Subject: fix statsd writing --- src/afl-fuzz-stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 22c0cbd2..fd9af5e4 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -544,7 +544,7 @@ void show_stats(afl_state_t *afl) { if (unlikely(afl->afl_env.afl_statsd)) { - if (unlikely(afl->force_ui_update && cur_ms - afl->statsd_last_send_ms > + if (unlikely(afl->force_ui_update || cur_ms - afl->statsd_last_send_ms > STATSD_UPDATE_SEC * 1000)) { /* reset counter, even if send failed. */ -- cgit 1.4.1 From 86452cc959bd4b0d5fe6e60d0eefbc7848fe38e2 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 30 Apr 2021 23:41:06 +0200 Subject: fix stdin trimming --- docs/Changelog.md | 1 + src/afl-forkserver.c | 2 +- src/afl-fuzz-run.c | 10 ++++------ utils/afl_proxy/afl-proxy.c | 23 +++++++++++++++-------- 4 files changed, 21 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/docs/Changelog.md b/docs/Changelog.md index 459c2f35..6a25865d 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -20,6 +20,7 @@ sending a mail to . - add recording of previous fuzz attempts for persistent mode to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h + - fixed a bug when trimming for stdin targets - default cmplog level (-l) is now 2, better efficiency. - cmplog level 3 (-l 3) now performs redqueen on everything. use with care. diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index d533fd4a..a07e78b4 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -1090,7 +1090,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { #endif - if (likely(fsrv->use_shmem_fuzz && fsrv->shmem_fuzz)) { + if (likely(fsrv->use_shmem_fuzz)) { if (unlikely(len > MAX_FILE)) len = MAX_FILE; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index a7b071a5..397d62bf 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -203,7 +203,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, } - if (afl->fsrv.shmem_fuzz) { + if (likely(afl->fsrv.use_shmem_fuzz)) { if (!post_process_skipped) { @@ -211,9 +211,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, memcpy(afl->fsrv.shmem_fuzz, new_mem, new_size); - } - - else { + } else { memcpy(afl->fsrv.shmem_fuzz, mem, skip_at); @@ -244,7 +242,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, return; - } else if (afl->fsrv.out_file) { + } else if (unlikely(!afl->fsrv.use_stdin)) { if (unlikely(afl->no_unlink)) { @@ -279,7 +277,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, } - if (!afl->fsrv.out_file) { + if (afl->fsrv.use_stdin) { if (ftruncate(fd, new_size)) { PFATAL("ftruncate() failed"); } lseek(fd, 0, SEEK_SET); diff --git a/utils/afl_proxy/afl-proxy.c b/utils/afl_proxy/afl-proxy.c index 2d8ba991..6006e238 100644 --- a/utils/afl_proxy/afl-proxy.c +++ b/utils/afl_proxy/afl-proxy.c @@ -195,10 +195,7 @@ static u32 __afl_next_testcase(u8 *buf, u32 max_len) { /* report that we are starting the target */ if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0; - if (status < 1) - return 0; - else - return status; + return status; } @@ -216,7 +213,7 @@ int main(int argc, char *argv[]) { /* This is were the testcase data is written into */ u8 buf[1024]; // this is the maximum size for a test case! set it! - u32 len; + s32 len; /* here you specify the map size you need that you are reporting to afl-fuzz. Any value is fine as long as it can be divided by 32. */ @@ -228,10 +225,20 @@ int main(int argc, char *argv[]) { while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) { - /* here you have to create the magic that feeds the buf/len to the - target and write the coverage to __afl_area_ptr */ + if (len > 4) { // the minimum data size you need for the target - // ... the magic ... + /* here you have to create the magic that feeds the buf/len to the + target and write the coverage to __afl_area_ptr */ + + // ... the magic ... + + // remove this, this is just to make afl-fuzz not complain when run + if (buf[0] == 0xff) + __afl_area_ptr[1] = 1; + else + __afl_area_ptr[2] = 2; + + } /* report the test case is done and wait for the next */ __afl_end_testcase(); -- cgit 1.4.1 From 6119c2eb5f4349c93abbeb19f0f9ec2f41aaabd1 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Sat, 1 May 2021 14:03:28 +0200 Subject: remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used --- qemu_mode/qemuafl | 2 +- src/afl-fuzz.c | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/qemu_mode/qemuafl b/qemu_mode/qemuafl index d73b0336..ddc4a974 160000 --- a/qemu_mode/qemuafl +++ b/qemu_mode/qemuafl @@ -1 +1 @@ -Subproject commit d73b0336b451fd034e5f469089fb7ee96c80adf2 +Subproject commit ddc4a9748d59857753fb33c30a356f354595f36d diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 1b3e303c..8c3ba575 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -2212,6 +2212,31 @@ stop_fuzzing: } afl_fsrv_deinit(&afl->fsrv); + + /* remove tmpfile */ + if (afl->tmp_dir != NULL && !afl->in_place_resume) { + + char tmpfile[PATH_MAX]; + + if (afl->file_extension) { + + snprintf(tmpfile, PATH_MAX, "%s/.cur_input.%s", afl->tmp_dir, + afl->file_extension); + + } else { + + snprintf(tmpfile, PATH_MAX, "%s/.cur_input", afl->tmp_dir); + + } + + if (unlink(tmpfile) != 0) { + + FATAL("Could not unlink current input file: %s.", tmpfile); + + } + + } + if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); } ck_free(afl->fsrv.target_path); ck_free(afl->fsrv.out_file); -- cgit 1.4.1 From 1d9a3d955cb4b1350ecad1e008b7c24c5ea3af57 Mon Sep 17 00:00:00 2001 From: realmadsci <71108352+realmadsci@users.noreply.github.com> Date: Thu, 6 May 2021 18:14:16 -0400 Subject: Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. --- include/afl-fuzz.h | 4 +-- src/afl-fuzz-mutators.c | 65 +++++++++++++++++++++++-------------------------- src/afl-fuzz-one.c | 4 +-- src/afl-fuzz-run.c | 8 ++---- 4 files changed, 37 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 040d7ae9..f201782a 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1003,7 +1003,7 @@ void read_afl_environment(afl_state_t *, char **); /* Custom mutators */ void setup_custom_mutators(afl_state_t *); void destroy_custom_mutators(afl_state_t *); -u8 trim_case_custom(afl_state_t *, struct queue_entry *q, u8 **in_buf, +u8 trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf, struct custom_mutator *mutator); /* Python */ @@ -1093,7 +1093,7 @@ fsrv_run_result_t fuzz_run_target(afl_state_t *, afl_forkserver_t *fsrv, u32); void write_to_testcase(afl_state_t *, void *, u32); u8 calibrate_case(afl_state_t *, struct queue_entry *, u8 *, u32, u8); void sync_fuzzers(afl_state_t *); -u8 trim_case(afl_state_t *, struct queue_entry *, u8 **); +u8 trim_case(afl_state_t *, struct queue_entry *, u8 *); u8 common_fuzz_stuff(afl_state_t *, u8 *, u32); /* Fuzz one */ diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index d8db8676..3bb37a89 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -305,16 +305,14 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) { } -// Custom testcase trimming. -u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 **in_buf_p, +u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, struct custom_mutator *mutator) { - // We need to pass pointers around, as growing testcases may need to realloc. - u8 *in_buf = *in_buf_p; - - u8 needs_write = 0, fault = 0; + u8 fault = 0; u32 trim_exec = 0; u32 orig_len = q->len; + u32 out_len = 0; + u8* out_buf = NULL; u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; @@ -401,40 +399,33 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 **in_buf_p, if (likely(retlen && cksum == q->exec_cksum)) { - // Check if we got a new retbuf and to memcpy our buf. - if (in_buf != retbuf) { - - if (afl_realloc((void **)in_buf_p, retlen) == NULL) { - - FATAL("can not allocate memory for trim"); - - } + /* Let's save a clean trace, which will be needed by + update_bitmap_score once we're done with the trimming stuff. + Use out_buf NULL check to make this only happen once per trim. */ - in_buf = *in_buf_p; + if (!out_buf) { - memcpy(in_buf, retbuf, retlen); - q->len = retlen; + memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits, + afl->fsrv.map_size); } - /* Let's save a clean trace, which will be needed by - update_bitmap_score once we're done with the trimming stuff. */ - - if (!needs_write) { + if (afl_realloc((void **)&out_buf, retlen) == NULL) { - needs_write = 1; - memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits, - afl->fsrv.map_size); + FATAL("can not allocate memory for trim"); } + out_len = retlen; + memcpy(out_buf, retbuf, retlen); + /* Tell the custom mutator that the trimming was successful */ afl->stage_cur = mutator->afl_custom_post_trim(mutator->data, 1); if (afl->not_on_tty && afl->debug) { SAYF("[Custom Trimming] SUCCESS: %u/%u iterations (now at %u bytes)", - afl->stage_cur, afl->stage_max, q->len); + afl->stage_cur, afl->stage_max, out_len); } @@ -467,16 +458,10 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 **in_buf_p, } - if (afl->not_on_tty && afl->debug) { - - SAYF("[Custom Trimming] DONE: %u bytes -> %u bytes", orig_len, q->len); - - } - - /* If we have made changes to in_buf, we also need to update the on-disk + /* If we have made changes, we also need to update the on-disk version of the test case. */ - if (needs_write) { + if (out_buf) { s32 fd; @@ -486,16 +471,28 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 **in_buf_p, if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); } - ck_write(fd, in_buf, q->len, q->fname); + ck_write(fd, out_buf, out_len, q->fname); close(fd); + /* Update the queue's knowledge of length as soon as we write the file. + We do this here so that exit/error cases that *don't* update the file also + don't update q->len. */ + q->len = out_len; + memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, afl->fsrv.map_size); update_bitmap_score(afl, q); } + if (afl->not_on_tty && afl->debug) { + + SAYF("[Custom Trimming] DONE: %u bytes -> %u bytes", orig_len, q->len); + + } + abort_trimming: + if (out_buf) afl_free(out_buf); afl->bytes_trim_out += q->len; return fault; diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index ed815cb4..4eeb93de 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -508,7 +508,7 @@ u8 fuzz_one_original(afl_state_t *afl) { u32 old_len = afl->queue_cur->len; - u8 res = trim_case(afl, afl->queue_cur, &in_buf); + u8 res = trim_case(afl, afl->queue_cur, in_buf); orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur); if (unlikely(res == FSRV_RUN_ERROR)) { @@ -3007,7 +3007,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { u32 old_len = afl->queue_cur->len; - u8 res = trim_case(afl, afl->queue_cur, &in_buf); + u8 res = trim_case(afl, afl->queue_cur, in_buf); orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur); if (unlikely(res == FSRV_RUN_ERROR)) { diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 397d62bf..6e5210b8 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -718,10 +718,7 @@ void sync_fuzzers(afl_state_t *afl) { trimmer uses power-of-two increments somewhere between 1/16 and 1/1024 of file size, to keep the stage short and sweet. */ -u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 **in_buf_p) { - - // We need to pass pointers around, as growing testcases may need to realloc. - u8 *in_buf = *in_buf_p; +u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { u32 orig_len = q->len; @@ -735,8 +732,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 **in_buf_p) { if (el->afl_custom_trim) { - trimmed_case = trim_case_custom(afl, q, in_buf_p, el); - in_buf = *in_buf_p; + trimmed_case = trim_case_custom(afl, q, in_buf, el); custom_trimmed = true; } -- cgit 1.4.1 From 069e61dfc67050154b649ba286552b563b27e9ba Mon Sep 17 00:00:00 2001 From: "Roman M. Iudichev" Date: Fri, 7 May 2021 18:32:17 +0300 Subject: Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. --- docs/env_variables.md | 4 ++++ include/afl-fuzz.h | 5 +++-- include/envs.h | 1 + src/afl-fuzz-state.c | 8 ++++++++ src/afl-fuzz-stats.c | 10 ++++++++++ src/afl-fuzz.c | 8 ++++++++ test/test-performance.sh | 1 + test/test-pre.sh | 1 + 8 files changed, 36 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/docs/env_variables.md b/docs/env_variables.md index 0100ffac..8879db72 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -284,6 +284,10 @@ checks or alter some of the more exotic semantics of the tool: normally indicated by the cycle counter in the UI turning green. May be convenient for some types of automated jobs. + - `AFL_EXIT_ON_TIME` Causes afl-fuzz to terminate if no new paths were + found within a specified period of time. May be convenient for some + types of automated jobs. + - `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behaviour which does not allow crashes or timeout seeds in the initial -i corpus. diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index f201782a..a09d6f79 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -392,7 +392,7 @@ typedef struct afl_env_vars { *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, *afl_testcache_entries, *afl_kill_signal, *afl_target_env, - *afl_persistent_record; + *afl_persistent_record, *afl_exit_on_time; } afl_env_vars_t; @@ -575,7 +575,8 @@ typedef struct afl_state { last_sync_cycle, /* Cycle no. of the last sync */ last_path_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) */ + last_hang_time, /* Time for most recent hang (ms) */ + exit_on_time; /* Delay to exit if no new paths */ u32 slowest_exec_ms, /* Slowest testcase non hang in ms */ subseq_tmouts; /* Number of timeouts in a row */ diff --git a/include/envs.h b/include/envs.h index cd23ca3f..9175005e 100644 --- a/include/envs.h +++ b/include/envs.h @@ -49,6 +49,7 @@ static char *afl_environment_variables[] = { "AFL_DUMB_FORKSRV", "AFL_ENTRYPOINT", "AFL_EXIT_WHEN_DONE", + "AFL_EXIT_ON_TIME", "AFL_EXIT_ON_SEED_ISSUES", "AFL_FAST_CAL", "AFL_FORCE_UI", diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 28d3339a..73ba7a52 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -99,6 +99,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->cal_cycles = CAL_CYCLES; afl->cal_cycles_long = CAL_CYCLES_LONG; afl->hang_tmout = EXEC_TIMEOUT; + afl->exit_on_time = 0; afl->stats_update_freq = 1; afl->stats_avg_exec = 0; afl->skip_deterministic = 1; @@ -187,6 +188,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_exit_when_done = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_EXIT_ON_TIME", + + afl_environment_variable_len)) { + + afl->afl_env.afl_exit_on_time = + (u8 *) get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_NO_AFFINITY", afl_environment_variable_len)) { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index fd9af5e4..ee8bd2da 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -574,6 +574,16 @@ void show_stats(afl_state_t *afl) { } + /* AFL_EXIT_ON_TIME. */ + + if (unlikely(afl->last_path_time && !afl->non_instrumented_mode && + afl->afl_env.afl_exit_on_time && + (cur_ms - afl->last_path_time) > afl->exit_on_time)) { + + afl->stop_soon = 2; + + } + if (unlikely(afl->total_crashes && afl->afl_env.afl_bench_until_crash)) { afl->stop_soon = 2; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 8c3ba575..8de3ed6b 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -204,6 +204,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_DISABLE_TRIM: disable the trimming of test cases\n" "AFL_DUMB_FORKSRV: use fork server without feedback from target\n" "AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n" + "AFL_EXIT_ON_TIME: exit when no new paths are found within the specified time period\n" "AFL_EXPAND_HAVOC_NOW: immediately enable expand havoc mode (default: after 60 minutes and a cycle without finds)\n" "AFL_FAST_CAL: limit the calibration stage to three cycles for speedup\n" "AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n" @@ -1246,6 +1247,13 @@ int main(int argc, char **argv_orig, char **envp) { } + if (afl->afl_env.afl_exit_on_time) { + + u64 exit_on_time = atoi(afl->afl_env.afl_exit_on_time); + afl->exit_on_time = (u64)exit_on_time * 1000; + + } + if (afl->afl_env.afl_max_det_extras) { s32 max_det_extras = atoi(afl->afl_env.afl_max_det_extras); diff --git a/test/test-performance.sh b/test/test-performance.sh index cd9f6caf..d61e2f2a 100755 --- a/test/test-performance.sh +++ b/test/test-performance.sh @@ -18,6 +18,7 @@ export AFL_QUIET=1 export AFL_PATH=`pwd`/.. unset AFL_EXIT_WHEN_DONE +unset AFL_EXIT_ON_TIME unset AFL_SKIP_CPUFREQ unset AFL_DEBUG unset AFL_HARDEN diff --git a/test/test-pre.sh b/test/test-pre.sh index 174f2f7f..7819da47 100755 --- a/test/test-pre.sh +++ b/test/test-pre.sh @@ -62,6 +62,7 @@ $ECHO \\101 2>&1 | grep -qE '^A' || { test -z "$ECHO" && { printf Error: printf command does not support octal character codes ; exit 1 ; } export AFL_EXIT_WHEN_DONE=1 +export AFL_EXIT_ON_TIME=60 export AFL_SKIP_CPUFREQ=1 export AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 unset AFL_NO_X86 -- cgit 1.4.1 From 6c274546c42f05292df6c8bcf3c524c4cfc3f031 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 8 May 2021 11:03:49 +0200 Subject: ensure crashes/README.txt exists --- include/afl-fuzz.h | 1 + src/afl-fuzz-stats.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'src') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index a09d6f79..72f956b9 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1135,6 +1135,7 @@ 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); /* CmpLog */ diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index ee8bd2da..bccd2f31 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -179,6 +179,8 @@ void load_stats_file(afl_state_t *afl) { } + if (afl->unique_crashes) { write_crash_readme(afl); } + return; } -- cgit 1.4.1 From b409d63fd30dd2dcbdc7be5fc559f246124ac110 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 8 May 2021 11:24:04 +0200 Subject: fix --- src/afl-fuzz-bitmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 3d0228db..97f10e6f 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -397,7 +397,7 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) { /* Write a message accompanying the crash directory :-) */ -static void write_crash_readme(afl_state_t *afl) { +void write_crash_readme(afl_state_t *afl) { u8 fn[PATH_MAX]; s32 fd; -- cgit 1.4.1 From ceb138cefe46e4412f54f31a812c125cebbb5b65 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 10 May 2021 10:30:57 +0200 Subject: afl-plot: relative time --- afl-plot | 6 +++--- src/afl-fuzz-init.c | 2 +- src/afl-fuzz-stats.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/afl-plot b/afl-plot index f5bb041d..26c8d1b7 100755 --- a/afl-plot +++ b/afl-plot @@ -111,9 +111,9 @@ set terminal png truecolor enhanced size 1000,300 butt set output '$outputdir/high_freq.png' -set xdata time -set timefmt '%s' -set format x "%b %d\n%H:%M" +#set xdata time +#set timefmt '%s' +#set format x "%b %d\n%H:%M" set tics font 'small' unset mxtics unset mytics diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 547311c7..cb586111 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2031,7 +2031,7 @@ void setup_dirs_fds(afl_state_t *afl) { fprintf( afl->fsrv.plot_file, - "# unix_time, cycles_done, cur_path, paths_total, " + "# relative_time, cycles_done, cur_path, paths_total, " "pending_total, pending_favs, map_size, unique_crashes, " "unique_hangs, max_depth, execs_per_sec, total_execs, edges_found\n"); diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index bccd2f31..2dea1bcb 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -386,7 +386,7 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, /* Fields in the file: - unix_time, afl->cycles_done, cur_path, paths_total, paths_not_fuzzed, + relative_time, afl->cycles_done, cur_path, paths_total, paths_not_fuzzed, favored_not_fuzzed, unique_crashes, unique_hangs, max_depth, execs_per_sec, edges_found */ -- cgit 1.4.1 From 50af4654e314df75ba8653340e5a58e9e42f1f19 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 10 May 2021 13:46:31 +0200 Subject: code-format --- src/afl-fuzz-mutators.c | 6 +++--- src/afl-fuzz-state.c | 2 +- src/afl-fuzz-stats.c | 8 ++++---- src/afl-ld-lto.c | 11 +++++------ 4 files changed, 13 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 3bb37a89..e27d6fae 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -312,7 +312,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, u32 trim_exec = 0; u32 orig_len = q->len; u32 out_len = 0; - u8* out_buf = NULL; + u8 *out_buf = NULL; u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; @@ -475,8 +475,8 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, close(fd); /* Update the queue's knowledge of length as soon as we write the file. - We do this here so that exit/error cases that *don't* update the file also - don't update q->len. */ + We do this here so that exit/error cases that *don't* update the file + also don't update q->len. */ q->len = out_len; memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, afl->fsrv.map_size); diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 73ba7a52..c886cb28 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -193,7 +193,7 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl_environment_variable_len)) { afl->afl_env.afl_exit_on_time = - (u8 *) get_afl_env(afl_environment_variables[i]); + (u8 *)get_afl_env(afl_environment_variables[i]); } else if (!strncmp(env, "AFL_NO_AFFINITY", diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 2dea1bcb..313263f9 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -576,11 +576,11 @@ void show_stats(afl_state_t *afl) { } - /* AFL_EXIT_ON_TIME. */ + /* AFL_EXIT_ON_TIME. */ - if (unlikely(afl->last_path_time && !afl->non_instrumented_mode && - afl->afl_env.afl_exit_on_time && - (cur_ms - afl->last_path_time) > afl->exit_on_time)) { + if (unlikely(afl->last_path_time && !afl->non_instrumented_mode && + afl->afl_env.afl_exit_on_time && + (cur_ms - afl->last_path_time) > afl->exit_on_time)) { afl->stop_soon = 2; diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c index d0113af9..1ce97649 100644 --- a/src/afl-ld-lto.c +++ b/src/afl-ld-lto.c @@ -298,13 +298,12 @@ int main(int argc, char **argv) { SAYF( "\n" - "This is a helper application for afl-clang-lto. It is a wrapper " - "around GNU " - "llvm's 'lld',\n" - "executed by the toolchain whenever using " - "afl-clang-lto/afl-clang-lto++.\n" + "This is a helper application for afl-clang-lto.\n" + "It is a wrapper around llvm's 'lld' in case afl-clang-lto cannot be " + "used.\n" + "Note that the target still has to be compiled with -flto=full!\n" "You probably don't want to run this program directly but rather pass " - "it as LD parameter to configure scripts\n\n" + "it as LD\nparameter to e.g. configure scripts.\n\n" "Environment variables:\n" " AFL_LD_PASSTHROUGH do not link+optimize == no instrumentation\n" -- cgit 1.4.1 From fd077e86bdfb73f1aa8432be547b1e8477883abb Mon Sep 17 00:00:00 2001 From: Dustin Spicuzza Date: Mon, 10 May 2021 18:20:28 -0400 Subject: OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory --- docs/INSTALL.md | 35 +++++++++++++++++++++++++++++++++++ src/afl-cc.c | 12 ++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/docs/INSTALL.md b/docs/INSTALL.md index e3c06c9d..80d452f7 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -103,6 +103,41 @@ The llvm instrumentation requires a fully-operational installation of clang. The comes with Xcode is missing some of the essential headers and helper tools. See README.llvm.md for advice on how to build the compiler from scratch. +MacOS X supports SYSV shared memory used by AFL's instrumentation, but the +default settings aren't usable with AFL++. The default settings on 10.14 seem +to be: + +```bash +$ ipcs -M +IPC status from as of XXX +shminfo: + shmmax: 4194304 (max shared memory segment size) + shmmin: 1 (min shared memory segment size) + shmmni: 32 (max number of shared memory identifiers) + shmseg: 8 (max shared memory segments per process) + shmall: 1024 (max amount of shared memory in pages) +``` + +To temporarily change your settings to something minimally usable with AFL++, +run these commands as root: + +```bash +sysctl kern.sysv.shmmax=8388608 +sysctl kern.sysv.shmall=4096 +``` + +If you're running more than one instance of AFL you likely want to make `shmall` +bigger and increase `shmseg` as well: + +```bash +sysctl kern.sysv.shmmax=8388608 +sysctl kern.sysv.shmseg=48 +sysctl kern.sysv.shmall=98304 +``` + +See http://www.spy-hill.com/help/apple/SharedMemory.html for documentation for +these settings and how to make them permanent. + ## 4. Linux or *BSD on non-x86 systems Standard build will fail on non-x86 systems, but you should be able to diff --git a/src/afl-cc.c b/src/afl-cc.c index 09009334..c1050355 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1574,7 +1574,12 @@ int main(int argc, char **argv, char **envp) { else if (have_gcc_plugin) compiler_mode = GCC_PLUGIN; else if (have_gcc) - compiler_mode = GCC; + #ifdef __APPLE__ + // on OSX clang masquerades as GCC + compiler_mode = CLANG; + #else + compiler_mode = GCC; + #endif else if (have_lto) compiler_mode = LTO; else @@ -1596,7 +1601,10 @@ int main(int argc, char **argv, char **envp) { } - if (compiler_mode == CLANG) { instrument_mode = INSTRUMENT_CLANG; } + if (compiler_mode == CLANG) { + instrument_mode = INSTRUMENT_CLANG; + setenv(CLANG_ENV_VAR, "1", 1); // used by afl-as + } if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) { -- cgit 1.4.1 From 72ca9b4684981ce2b807e4efd218bd1924f3e6b1 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 11 May 2021 22:06:37 +0200 Subject: fix a few cur_time uses --- docs/Changelog.md | 1 + src/afl-cc.c | 16 +++++++++------- src/afl-fuzz-one.c | 6 +++--- src/afl-fuzz-stats.c | 5 +++-- src/afl-fuzz.c | 6 ++++-- 5 files changed, 20 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/docs/Changelog.md b/docs/Changelog.md index ceb02bb9..e4c02921 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,6 +9,7 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . ### Version ++3.13a (development) + - Note: plot_data switched to relative time from unix time in 3.10 - frida_mode - new mode that uses frida to fuzz binary-only targets, it currently supports persistent mode and cmplog. thanks to @WorksButNotTested! diff --git a/src/afl-cc.c b/src/afl-cc.c index c1050355..ff7b5219 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1574,12 +1574,12 @@ int main(int argc, char **argv, char **envp) { else if (have_gcc_plugin) compiler_mode = GCC_PLUGIN; else if (have_gcc) - #ifdef __APPLE__ - // on OSX clang masquerades as GCC - compiler_mode = CLANG; - #else - compiler_mode = GCC; - #endif +#ifdef __APPLE__ + // on OSX clang masquerades as GCC + compiler_mode = CLANG; +#else + compiler_mode = GCC; +#endif else if (have_lto) compiler_mode = LTO; else @@ -1602,8 +1602,10 @@ int main(int argc, char **argv, char **envp) { } if (compiler_mode == CLANG) { + instrument_mode = INSTRUMENT_CLANG; - setenv(CLANG_ENV_VAR, "1", 1); // used by afl-as + setenv(CLANG_ENV_VAR, "1", 1); // used by afl-as + } if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) { diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 4eeb93de..4a3e7f33 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -562,7 +562,7 @@ u8 fuzz_one_original(afl_state_t *afl) { if (afl->cmplog_lvl == 3 || (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) || !(afl->fsrv.total_execs % afl->queued_paths) || - get_cur_time() - afl->last_path_time > 300000) { + get_cur_time() - afl->last_path_time > 300000) { // 300 seconds if (input_to_state_stage(afl, in_buf, out_buf, len)) { @@ -2013,7 +2013,7 @@ havoc_stage: } - if (unlikely(get_cur_time() - afl->last_path_time > 5000 && + if (unlikely(get_cur_time() - afl->last_path_time > 5000 /* 5 seconds */ && afl->ready_for_splicing_count > 1)) { /* add expensive havoc cases here if there is no findings in the last 5s */ @@ -3060,7 +3060,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { if (afl->cmplog_lvl == 3 || (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) || !(afl->fsrv.total_execs % afl->queued_paths) || - get_cur_time() - afl->last_path_time > 300000) { + get_cur_time() - afl->last_path_time > 300000) { // 300 seconds if (input_to_state_stage(afl, in_buf, out_buf, len)) { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 313263f9..4884b942 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -368,7 +368,8 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, afl->plot_prev_uh == afl->unique_hangs && afl->plot_prev_md == afl->max_depth && afl->plot_prev_ed == afl->fsrv.total_execs) || - !afl->queue_cycle || get_cur_time() - afl->start_time <= 60))) { + !afl->queue_cycle || + get_cur_time() - afl->start_time <= 60000))) { return; @@ -393,7 +394,7 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, fprintf(afl->fsrv.plot_file, "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu, " "%u\n", - (afl->prev_run_time + get_cur_time() - afl->start_time), + ((afl->prev_run_time + get_cur_time() - afl->start_time) / 1000), afl->queue_cycle - 1, afl->current_entry, afl->queued_paths, afl->pending_not_fuzzed, afl->pending_favored, bitmap_cvg, afl->unique_crashes, afl->unique_hangs, afl->max_depth, eps, diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 8de3ed6b..094fd161 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1940,8 +1940,10 @@ int main(int argc, char **argv_orig, char **envp) { /* If we had a full queue cycle with no new finds, try recombination strategies next. */ - if (unlikely(afl->queued_paths == prev_queued && - (get_cur_time() - afl->start_time) >= 3600)) { + if (unlikely(afl->queued_paths == prev_queued + /* FIXME TODO BUG: && (get_cur_time() - afl->start_time) >= + 3600 */ + )) { if (afl->use_splicing) { -- cgit 1.4.1 From 000c72909530274cb52015fee69e9700ec6a2c7e Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Sat, 15 May 2021 17:33:05 +0200 Subject: added bounds check to pivot_inputs (fixes #921) --- src/afl-fuzz-init.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index cb586111..7337bfbf 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -1294,9 +1294,13 @@ void pivot_inputs(afl_state_t *afl) { if (src_str && sscanf(src_str + 1, "%06u", &src_id) == 1) { - struct queue_entry *s = afl->queue_buf[src_id]; + if (src_id < afl->queued_paths) { - if (s) { q->depth = s->depth + 1; } + struct queue_entry *s = afl->queue_buf[src_id]; + + if (s) { q->depth = s->depth + 1; } + + } if (afl->max_depth < q->depth) { afl->max_depth = q->depth; } -- cgit 1.4.1 From 3d28925c13b5fc171b239c0c0451686967ee3bda Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Sat, 15 May 2021 18:23:13 +0200 Subject: additional safety checks for restarts --- src/afl-fuzz.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 094fd161..a4599b4a 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -332,7 +332,7 @@ static int stricmp(char const *a, char const *b) { int main(int argc, char **argv_orig, char **envp) { - s32 opt, i, auto_sync = 0 /*, user_set_cache = 0*/; + s32 opt, auto_sync = 0 /*, user_set_cache = 0*/; u64 prev_queued = 0; u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0, map_size = get_map_size(); @@ -1770,7 +1770,7 @@ int main(int argc, char **argv_orig, char **envp) { if (extras_dir_cnt) { - for (i = 0; i < extras_dir_cnt; i++) { + for (u8 i = 0; i < extras_dir_cnt; i++) { load_extras(afl, extras_dir[i]); @@ -1922,6 +1922,13 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(seek_to)) { + if (unlikely(seek_to >= afl->queued_paths)) { + + // This should never happen. + FATAL("BUG: seek_to location out of bounds!\n"); + + } + afl->current_entry = seek_to; afl->queue_cur = afl->queue_buf[seek_to]; seek_to = 0; @@ -2061,7 +2068,7 @@ int main(int argc, char **argv_orig, char **envp) { } // we must recalculate the scores of all queue entries - for (i = 0; i < (s32)afl->queued_paths; i++) { + for (u32 i = 0; i < afl->queued_paths; i++) { if (likely(!afl->queue_buf[i]->disabled)) { -- cgit 1.4.1 From 7b033367c2f49b47d0a5021a9ad9a82b514429de Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 17 May 2021 11:02:28 +0200 Subject: restrict afl-showmap in_file size --- src/afl-showmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 946b19cd..5994101e 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -386,7 +386,7 @@ static u32 read_file(u8 *in_file) { } - in_len = st.st_size; + in_len = st.st_size > MAX_FILE ? MAX_FILE : st.st_size; in_data = ck_alloc_nozero(in_len); ck_read(fd, in_data, in_len, in_file); -- cgit 1.4.1 From 738246465d07770471ec34500909ebb4c3c5f1cf Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 17 May 2021 13:08:05 +0200 Subject: fix seed crash disable --- src/afl-fuzz-init.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 7337bfbf..c43bcc2b 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -1044,18 +1044,16 @@ void perform_dry_run(afl_state_t *afl) { /* Remove from fuzzing queue but keep for splicing */ - struct queue_entry *p = afl->queue; + if (!q->was_fuzzed) { - if (!p->was_fuzzed) { - - p->was_fuzzed = 1; + q->was_fuzzed = 1; --afl->pending_not_fuzzed; --afl->active_paths; } - p->disabled = 1; - p->perf_score = 0; + q->disabled = 1; + q->perf_score = 0; u32 i = 0; while (unlikely(i < afl->queued_paths && afl->queue_buf[i] && -- cgit 1.4.1 From a3fffac90cb96736395aa9764f4cc5aa20e6cd71 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 17 May 2021 13:11:16 +0200 Subject: add warning for afl-showmap partial read --- src/afl-showmap.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 5994101e..41a62108 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -386,7 +386,18 @@ static u32 read_file(u8 *in_file) { } - in_len = st.st_size > MAX_FILE ? MAX_FILE : st.st_size; + if (st.st_size > MAX_FILE) { + + WARNF("Input file '%s' is too large, only reading %u bytes.", in_file, + MAX_FILE); + in_len = MAX_FILE; + + } else { + + in_len = st.st_size; + + } + in_data = ck_alloc_nozero(in_len); ck_read(fd, in_data, in_len, in_file); -- cgit 1.4.1 From 47e22e8d8d383078989906c6fe54a9ec4deff8c1 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 17 May 2021 16:52:52 +0200 Subject: no core dumps --- docs/Changelog.md | 1 + src/afl-forkserver.c | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/docs/Changelog.md b/docs/Changelog.md index e4c02921..4fa70bfd 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -29,6 +29,7 @@ sending a mail to . - ensure one fuzzer sync per cycle - fix afl_custom_queue_new_entry original file name when syncing from fuzzers + - on a crashing seed potentially the wrong input was disabled - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in -i dir crashes the target or results in a timeout. By default afl++ ignores these and uses them for splicing instead. diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index a07e78b4..0286ab47 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -451,8 +451,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered before the dump is complete. */ - // r.rlim_max = r.rlim_cur = 0; - // setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + if (!fsrv->debug) { + + r.rlim_max = r.rlim_cur = 0; + setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + + } /* Isolate the process and configure standard descriptors. If out_file is specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */ -- cgit 1.4.1 From ccf739f8801c373fe2aa1bb709ffd697cfe2a3e6 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 17 May 2021 18:16:41 +0200 Subject: AFL_PRINT_FILENAMES added --- afl-cmin | 2 ++ docs/Changelog.md | 1 + docs/env_variables.md | 3 ++ src/afl-showmap.c | 82 ++++++++++++++++++++++++++++----------------------- 4 files changed, 51 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/afl-cmin b/afl-cmin index 3f3a7517..adcbb221 100755 --- a/afl-cmin +++ b/afl-cmin @@ -123,6 +123,8 @@ function usage() { "AFL_KEEP_TRACES: leave the temporary /.traces directory\n" \ "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n" "AFL_PATH: path for the afl-showmap binary if not found anywhere else\n" \ +"AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \ + "printed to stdout\n" \ "AFL_SKIP_BIN_CHECK: skip check for target binary\n" exit 1 } diff --git a/docs/Changelog.md b/docs/Changelog.md index 4fa70bfd..67ab9d5e 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -50,6 +50,7 @@ sending a mail to . MacOS shared memory - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup + - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the current filename ### Version ++3.12c (release) - afl-fuzz: diff --git a/docs/env_variables.md b/docs/env_variables.md index 8879db72..99568146 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -567,6 +567,9 @@ The corpus minimization script offers very little customization: a modest security risk on multi-user systems with rogue users, but should be safe on dedicated fuzzing boxes. + - `AFL_PRINT_FILENAMES` prints each filename to stdout, as it gets processed. + This can help when embedding `afl-cmin` or `afl-showmap` in other scripts scripting. + ## 7) Settings for afl-tmin Virtually nothing to play with. Well, in QEMU mode (`-Q`), `AFL_PATH` will be diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 41a62108..336ac126 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -76,17 +76,18 @@ static u32 in_len; /* Input data length */ static u32 map_size = MAP_SIZE; -static u8 quiet_mode, /* Hide non-essential messages? */ +static bool quiet_mode, /* Hide non-essential messages? */ edges_only, /* Ignore hit counts? */ raw_instr_output, /* Do not apply AFL filters */ cmin_mode, /* Generate output in afl-cmin mode? */ binary_mode, /* Write output as a binary map */ keep_cores, /* Allow coredumps? */ - remove_shm = 1, /* remove shmem? */ + remove_shm = true, /* remove shmem? */ collect_coverage, /* collect coverage */ have_coverage, /* have coverage? */ no_classify, /* do not classify counts */ - debug; /* debug mode */ + debug, /* debug mode */ + print_filenames; /* print the current filename */ static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_crashed; /* Child crashed? */ @@ -320,11 +321,11 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, if (fsrv->trace_bits[0] == 1) { fsrv->trace_bits[0] = 0; - have_coverage = 1; + have_coverage = true; } else { - have_coverage = 0; + have_coverage = false; } @@ -335,11 +336,11 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(fsrv->child_status)) { - child_crashed = 1; + child_crashed = true; } else { - child_crashed = 0; + child_crashed = false; } @@ -375,6 +376,8 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, static u32 read_file(u8 *in_file) { + if (print_filenames) { SAYF("Processing %s\n", in_file); } + struct stat st; s32 fd = open(in_file, O_RDONLY); @@ -515,11 +518,11 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { if (fsrv->trace_bits[0] == 1) { fsrv->trace_bits[0] = 0; - have_coverage = 1; + have_coverage = true; } else { - have_coverage = 0; + have_coverage = false; } @@ -529,7 +532,7 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(status)) { - child_crashed = 1; + child_crashed = true; } @@ -559,7 +562,7 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { static void handle_stop_sig(int sig) { (void)sig; - stop_soon = 1; + stop_soon = true; afl_fsrv_killall(); } @@ -742,6 +745,8 @@ static void usage(u8 *argv0) { "AFL_MAP_SIZE: the shared memory size for that target. must be >= the " "size the target was compiled for\n" "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" + "AFL_PRINT_FILENAMES: If set, the filename currently processed will be " + "printed to stdout\n" "AFL_QUIET: do not print extra informational output\n", argv0, MEM_LIMIT, doc_path); @@ -755,14 +760,17 @@ int main(int argc, char **argv_orig, char **envp) { // TODO: u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ - s32 opt, i; - u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0; + s32 opt, i; + bool mem_limit_given = false, timeout_given = false, unicorn_mode = false, + use_wine = false; char **use_argv; char **argv = argv_cpy_dup(argc, argv_orig); afl_forkserver_t fsrv_var = {0}; - if (getenv("AFL_DEBUG")) { debug = 1; } + if (getenv("AFL_DEBUG")) { debug = true; } + if (getenv("AFL_PRINT_FILENAMES")) { print_filenames = true; } + fsrv = &fsrv_var; afl_fsrv_init(fsrv); map_size = get_map_size(); @@ -770,19 +778,19 @@ int main(int argc, char **argv_orig, char **envp) { doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; - if (getenv("AFL_QUIET") != NULL) { be_quiet = 1; } + if (getenv("AFL_QUIET") != NULL) { be_quiet = true; } while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZOQUWbcrsh")) > 0) { switch (opt) { case 's': - no_classify = 1; + no_classify = true; break; case 'C': - collect_coverage = 1; - quiet_mode = 1; + collect_coverage = true; + quiet_mode = true; break; case 'i': @@ -801,7 +809,7 @@ int main(int argc, char **argv_orig, char **envp) { u8 suffix = 'M'; if (mem_limit_given) { FATAL("Multiple -m options not supported"); } - mem_limit_given = 1; + mem_limit_given = true; if (!optarg) { FATAL("Wrong usage of -m"); } @@ -862,7 +870,7 @@ int main(int argc, char **argv_orig, char **envp) { case 't': if (timeout_given) { FATAL("Multiple -t options not supported"); } - timeout_given = 1; + timeout_given = true; if (!optarg) { FATAL("Wrong usage of -t"); } @@ -884,12 +892,12 @@ int main(int argc, char **argv_orig, char **envp) { if (edges_only) { FATAL("Multiple -e options not supported"); } if (raw_instr_output) { FATAL("-e and -r are mutually exclusive"); } - edges_only = 1; + edges_only = true; break; case 'q': - quiet_mode = 1; + quiet_mode = true; break; case 'Z': @@ -897,8 +905,8 @@ int main(int argc, char **argv_orig, char **envp) { /* This is an undocumented option to write data in the syntax expected by afl-cmin. Nobody else should have any use for this. */ - cmin_mode = 1; - quiet_mode = 1; + cmin_mode = true; + quiet_mode = true; break; case 'A': @@ -910,7 +918,7 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); } - fsrv->frida_mode = 1; + fsrv->frida_mode = true; break; @@ -918,21 +926,21 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); } - fsrv->qemu_mode = 1; + fsrv->qemu_mode = true; break; case 'U': if (unicorn_mode) { FATAL("Multiple -U options not supported"); } - unicorn_mode = 1; + unicorn_mode = true; break; case 'W': /* Wine+QEMU mode */ if (use_wine) { FATAL("Multiple -W options not supported"); } - fsrv->qemu_mode = 1; - use_wine = 1; + fsrv->qemu_mode = true; + use_wine = true; break; @@ -941,20 +949,20 @@ int main(int argc, char **argv_orig, char **envp) { /* Secret undocumented mode. Writes output in raw binary format similar to that dumped by afl-fuzz in cmplog_mode = 0; u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1); - shm_fuzz->shmemfuzz_mode = 1; + shm_fuzz->shmemfuzz_mode = true; if (!map) { FATAL("BUG: Zero return from afl_shm_init."); } #ifdef USEMMAP setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1); @@ -1073,7 +1081,7 @@ int main(int argc, char **argv_orig, char **envp) { setenv(SHM_FUZZ_ENV_VAR, shm_str, 1); ck_free(shm_str); #endif - fsrv->support_shmem_fuzz = 1; + fsrv->support_shmem_fuzz = true; fsrv->shmem_fuzz_len = (u32 *)map; fsrv->shmem_fuzz = map + sizeof(u32); @@ -1125,7 +1133,7 @@ int main(int argc, char **argv_orig, char **envp) { struct stat statbuf; #endif - if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = 1; + if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true; fsrv->dev_null_fd = open("/dev/null", O_RDWR); if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } @@ -1164,8 +1172,8 @@ int main(int argc, char **argv_orig, char **envp) { if ((coverage_map = (u8 *)malloc(map_size)) == NULL) FATAL("coult not grab memory"); - edges_only = 0; - raw_instr_output = 1; + edges_only = false; + raw_instr_output = true; } -- cgit 1.4.1 From 9d50ae7468970412177c9e08edf7f32ff9fdf1ce Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 17 May 2021 18:54:24 +0200 Subject: Flushing for AFL_PRINT_FILENAMES --- src/afl-forkserver.c | 2 +- src/afl-showmap.c | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 0286ab47..3d472b36 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -454,7 +454,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!fsrv->debug) { r.rlim_max = r.rlim_cur = 0; - setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 336ac126..10818905 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -376,7 +376,12 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, static u32 read_file(u8 *in_file) { - if (print_filenames) { SAYF("Processing %s\n", in_file); } + if (print_filenames) { + + SAYF("Processing %s\n", in_file); + fflush(stdout); + + } struct stat st; s32 fd = open(in_file, O_RDONLY); -- cgit 1.4.1 From e40c0c2da16f14dfddb5641f6f825903879534a9 Mon Sep 17 00:00:00 2001 From: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Date: Mon, 17 May 2021 19:02:45 +0100 Subject: FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name --- frida_mode/include/asan.h | 13 +++ frida_mode/include/ctx.h | 11 +++ frida_mode/src/asan/asan.c | 24 +++++ frida_mode/src/asan/asan_arm.c | 22 +++++ frida_mode/src/asan/asan_arm64.c | 22 +++++ frida_mode/src/asan/asan_x64.c | 93 ++++++++++++++++++++ frida_mode/src/asan/asan_x86.c | 22 +++++ frida_mode/src/cmplog/cmplog_x64.c | 119 ++----------------------- frida_mode/src/ctx/ctx_x64.c | 114 ++++++++++++++++++++++++ frida_mode/src/instrument/instrument.c | 3 + frida_mode/test/fasan/GNUmakefile | 156 +++++++++++++++++++++++++++++++++ frida_mode/test/fasan/Makefile | 18 ++++ frida_mode/test/fasan/test.c | 85 ++++++++++++++++++ include/envs.h | 1 + include/forkserver.h | 2 + src/afl-fuzz.c | 81 ++++++++++++++--- 16 files changed, 664 insertions(+), 122 deletions(-) create mode 100644 frida_mode/include/asan.h create mode 100644 frida_mode/include/ctx.h create mode 100644 frida_mode/src/asan/asan.c create mode 100644 frida_mode/src/asan/asan_arm.c create mode 100644 frida_mode/src/asan/asan_arm64.c create mode 100644 frida_mode/src/asan/asan_x64.c create mode 100644 frida_mode/src/asan/asan_x86.c create mode 100644 frida_mode/src/ctx/ctx_x64.c create mode 100644 frida_mode/test/fasan/GNUmakefile create mode 100644 frida_mode/test/fasan/Makefile create mode 100644 frida_mode/test/fasan/test.c (limited to 'src') diff --git a/frida_mode/include/asan.h b/frida_mode/include/asan.h new file mode 100644 index 00000000..7a8726e0 --- /dev/null +++ b/frida_mode/include/asan.h @@ -0,0 +1,13 @@ +#ifndef _ASAN_H +#define _ASAN_H + +#include "frida-gum.h" + +extern gboolean asan_initialized; + +void asan_init(void); +void asan_arch_init(void); +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator); + +#endif + diff --git a/frida_mode/include/ctx.h b/frida_mode/include/ctx.h new file mode 100644 index 00000000..030d124a --- /dev/null +++ b/frida_mode/include/ctx.h @@ -0,0 +1,11 @@ +#ifndef _CTX_H +#define _CTX_H + +#include "frida-gum.h" + +#if defined(__x86_64__) +guint64 ctx_read_reg(GumX64CpuContext *ctx, x86_reg reg); +#endif + +#endif + diff --git a/frida_mode/src/asan/asan.c b/frida_mode/src/asan/asan.c new file mode 100644 index 00000000..f78f690c --- /dev/null +++ b/frida_mode/src/asan/asan.c @@ -0,0 +1,24 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" + +gboolean asan_initialized = FALSE; + +void asan_init(void) { + + if (getenv("AFL_USE_FASAN") != NULL) { + + OKF("Frida ASAN mode enabled"); + asan_arch_init(); + asan_initialized = TRUE; + + } else { + + OKF("Frida ASAN mode disabled"); + + } + +} + diff --git a/frida_mode/src/asan/asan_arm.c b/frida_mode/src/asan/asan_arm.c new file mode 100644 index 00000000..526017be --- /dev/null +++ b/frida_mode/src/asan/asan_arm.c @@ -0,0 +1,22 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" +#include "util.h" + +#if defined(__arm__) +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(iterator); + if (asan_initialized) { + + FATAL("ASAN mode not supported on this architecture"); + + } + +} + +#endif + diff --git a/frida_mode/src/asan/asan_arm64.c b/frida_mode/src/asan/asan_arm64.c new file mode 100644 index 00000000..4e3fbafd --- /dev/null +++ b/frida_mode/src/asan/asan_arm64.c @@ -0,0 +1,22 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" +#include "util.h" + +#if defined(__aarch64__) +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(iterator); + if (asan_initialized) { + + FATAL("ASAN mode not supported on this architecture"); + + } + +} + +#endif + diff --git a/frida_mode/src/asan/asan_x64.c b/frida_mode/src/asan/asan_x64.c new file mode 100644 index 00000000..bdf4ac30 --- /dev/null +++ b/frida_mode/src/asan/asan_x64.c @@ -0,0 +1,93 @@ +#include +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" +#include "ctx.h" +#include "util.h" + +typedef void (*asan_loadN_t)(uint64_t address, uint8_t size); +typedef void (*asan_storeN_t)(uint64_t address, uint8_t size); + +asan_loadN_t asan_loadN = NULL; +asan_storeN_t asan_storeN = NULL; + +#if defined(__x86_64__) + +static void asan_callout(GumCpuContext *ctx, gpointer user_data) { + + UNUSED_PARAMETER(user_data); + + cs_x86_op * operand = (cs_x86_op *)user_data; + x86_op_mem *mem = &operand->mem; + uint64_t base = 0; + uint64_t index = 0; + uint64_t address; + uint8_t size; + + if (mem->base != X86_REG_INVALID) { base = ctx_read_reg(ctx, mem->base); } + + if (mem->index != X86_REG_INVALID) { index = ctx_read_reg(ctx, mem->index); } + + address = base + (mem->scale * index) + mem->disp; + size = operand->size; + + if (operand->access == CS_AC_READ) { + + asan_loadN(address, size); + + } else if (operand->access == CS_AC_WRITE) { + + asan_storeN(address, size); + + } + +} + +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(iterator); + + cs_x86 x86 = instr->detail->x86; + cs_x86_op * operand; + x86_op_mem *mem; + cs_x86_op * ctx; + + if (!asan_initialized) return; + + if (instr->id == X86_INS_LEA) return; + + if (instr->id == X86_INS_NOP) return; + + for (uint8_t i = 0; i < x86.op_count; i++) { + + operand = &x86.operands[i]; + + if (operand->type != X86_OP_MEM) { continue; } + + mem = &operand->mem; + if (mem->segment != X86_REG_INVALID) { continue; } + + ctx = g_malloc0(sizeof(cs_x86_op)); + memcpy(ctx, operand, sizeof(cs_x86_op)); + gum_stalker_iterator_put_callout(iterator, asan_callout, ctx, g_free); + + } + +} + +void asan_arch_init(void) { + + asan_loadN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_loadN"); + asan_storeN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_storeN"); + if (asan_loadN == NULL || asan_storeN == NULL) { + + FATAL("Frida ASAN failed to find '__asan_loadN' or '__asan_storeN'"); + + } + +} + +#endif + diff --git a/frida_mode/src/asan/asan_x86.c b/frida_mode/src/asan/asan_x86.c new file mode 100644 index 00000000..b946b3bf --- /dev/null +++ b/frida_mode/src/asan/asan_x86.c @@ -0,0 +1,22 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" +#include "util.h" + +#if defined(__i386__) +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(iterator); + if (asan_initialized) { + + FATAL("ASAN mode not supported on this architecture"); + + } + +} + +#endif + diff --git a/frida_mode/src/cmplog/cmplog_x64.c b/frida_mode/src/cmplog/cmplog_x64.c index 4d8f243a..c3621a29 100644 --- a/frida_mode/src/cmplog/cmplog_x64.c +++ b/frida_mode/src/cmplog/cmplog_x64.c @@ -3,46 +3,12 @@ #include "debug.h" #include "cmplog.h" +#include "ctx.h" #include "frida_cmplog.h" #include "util.h" #if defined(__x86_64__) - #define X86_REG_8L(LABEL, REG) \ - case LABEL: { \ - \ - return REG & GUM_INT8_MASK; \ - \ - } - - #define X86_REG_8H(LABEL, REG) \ - case LABEL: { \ - \ - return (REG & GUM_INT16_MASK) >> 8; \ - \ - } - - #define X86_REG_16(LABEL, REG) \ - case LABEL: { \ - \ - return (REG & GUM_INT16_MASK); \ - \ - } - - #define X86_REG_32(LABEL, REG) \ - case LABEL: { \ - \ - return (REG & GUM_INT32_MASK); \ - \ - } - - #define X86_REG_64(LABEL, REG) \ - case LABEL: { \ - \ - return (REG); \ - \ - } - typedef struct { x86_op_type type; @@ -65,75 +31,6 @@ typedef struct { } cmplog_pair_ctx_t; -static guint64 cmplog_read_reg(GumX64CpuContext *ctx, x86_reg reg) { - - switch (reg) { - - X86_REG_8L(X86_REG_AL, ctx->rax) - X86_REG_8L(X86_REG_BL, ctx->rbx) - X86_REG_8L(X86_REG_CL, ctx->rcx) - X86_REG_8L(X86_REG_DL, ctx->rdx) - X86_REG_8L(X86_REG_BPL, ctx->rbp) - X86_REG_8L(X86_REG_SIL, ctx->rsi) - X86_REG_8L(X86_REG_DIL, ctx->rdi) - - X86_REG_8H(X86_REG_AH, ctx->rax) - X86_REG_8H(X86_REG_BH, ctx->rbx) - X86_REG_8H(X86_REG_CH, ctx->rcx) - X86_REG_8H(X86_REG_DH, ctx->rdx) - - X86_REG_16(X86_REG_AX, ctx->rax) - X86_REG_16(X86_REG_BX, ctx->rbx) - X86_REG_16(X86_REG_CX, ctx->rcx) - X86_REG_16(X86_REG_DX, ctx->rdx) - X86_REG_16(X86_REG_DI, ctx->rdi) - X86_REG_16(X86_REG_SI, ctx->rsi) - X86_REG_16(X86_REG_BP, ctx->rbp) - - X86_REG_32(X86_REG_EAX, ctx->rax) - X86_REG_32(X86_REG_ECX, ctx->rcx) - X86_REG_32(X86_REG_EDX, ctx->rdx) - X86_REG_32(X86_REG_EBX, ctx->rbx) - X86_REG_32(X86_REG_ESP, ctx->rsp) - X86_REG_32(X86_REG_EBP, ctx->rbp) - X86_REG_32(X86_REG_ESI, ctx->rsi) - X86_REG_32(X86_REG_EDI, ctx->rdi) - X86_REG_32(X86_REG_R8D, ctx->r8) - X86_REG_32(X86_REG_R9D, ctx->r9) - X86_REG_32(X86_REG_R10D, ctx->r10) - X86_REG_32(X86_REG_R11D, ctx->r11) - X86_REG_32(X86_REG_R12D, ctx->r12) - X86_REG_32(X86_REG_R13D, ctx->r13) - X86_REG_32(X86_REG_R14D, ctx->r14) - X86_REG_32(X86_REG_R15D, ctx->r15) - X86_REG_32(X86_REG_EIP, ctx->rip) - - X86_REG_64(X86_REG_RAX, ctx->rax) - X86_REG_64(X86_REG_RCX, ctx->rcx) - X86_REG_64(X86_REG_RDX, ctx->rdx) - X86_REG_64(X86_REG_RBX, ctx->rbx) - X86_REG_64(X86_REG_RSP, ctx->rsp) - X86_REG_64(X86_REG_RBP, ctx->rbp) - X86_REG_64(X86_REG_RSI, ctx->rsi) - X86_REG_64(X86_REG_RDI, ctx->rdi) - X86_REG_64(X86_REG_R8, ctx->r8) - X86_REG_64(X86_REG_R9, ctx->r9) - X86_REG_64(X86_REG_R10, ctx->r10) - X86_REG_64(X86_REG_R11, ctx->r11) - X86_REG_64(X86_REG_R12, ctx->r12) - X86_REG_64(X86_REG_R13, ctx->r13) - X86_REG_64(X86_REG_R14, ctx->r14) - X86_REG_64(X86_REG_R15, ctx->r15) - X86_REG_64(X86_REG_RIP, ctx->rip) - - default: - FATAL("Failed to read register: %d", reg); - return 0; - - } - -} - static gboolean cmplog_read_mem(GumX64CpuContext *ctx, uint8_t size, x86_op_mem *mem, guint64 *val) { @@ -141,9 +38,9 @@ static gboolean cmplog_read_mem(GumX64CpuContext *ctx, uint8_t size, guint64 index = 0; guint64 address; - if (mem->base != X86_REG_INVALID) base = cmplog_read_reg(ctx, mem->base); + if (mem->base != X86_REG_INVALID) base = ctx_read_reg(ctx, mem->base); - if (mem->index != X86_REG_INVALID) index = cmplog_read_reg(ctx, mem->index); + if (mem->index != X86_REG_INVALID) index = ctx_read_reg(ctx, mem->index); address = base + (index * mem->scale) + mem->disp; @@ -178,7 +75,7 @@ static gboolean cmplog_get_operand_value(GumCpuContext *context, switch (ctx->type) { case X86_OP_REG: - *val = cmplog_read_reg(context, ctx->reg); + *val = ctx_read_reg(context, ctx->reg); return TRUE; case X86_OP_IMM: *val = ctx->imm; @@ -198,9 +95,9 @@ static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) { UNUSED_PARAMETER(user_data); - guint64 address = cmplog_read_reg(context, X86_REG_RIP); - guint64 rdi = cmplog_read_reg(context, X86_REG_RDI); - guint64 rsi = cmplog_read_reg(context, X86_REG_RSI); + guint64 address = ctx_read_reg(context, X86_REG_RIP); + guint64 rdi = ctx_read_reg(context, X86_REG_RDI); + guint64 rsi = ctx_read_reg(context, X86_REG_RSI); if (((G_MAXULONG - rdi) < 32) || ((G_MAXULONG - rsi) < 32)) return; @@ -275,7 +172,7 @@ static void cmplog_instrument_call(const cs_insn * instr, static void cmplog_handle_cmp_sub(GumCpuContext *context, guint64 operand1, guint64 operand2, uint8_t size) { - guint64 address = cmplog_read_reg(context, X86_REG_RIP); + guint64 address = ctx_read_reg(context, X86_REG_RIP); register uintptr_t k = (uintptr_t)address; diff --git a/frida_mode/src/ctx/ctx_x64.c b/frida_mode/src/ctx/ctx_x64.c new file mode 100644 index 00000000..dec759f4 --- /dev/null +++ b/frida_mode/src/ctx/ctx_x64.c @@ -0,0 +1,114 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "ctx.h" + +#if defined(__x86_64__) + + #define X86_REG_8L(LABEL, REG) \ + case LABEL: { \ + \ + return REG & GUM_INT8_MASK; \ + \ + } + + #define X86_REG_8H(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK) >> 8; \ + \ + } + + #define X86_REG_16(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK); \ + \ + } + + #define X86_REG_32(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT32_MASK); \ + \ + } + + #define X86_REG_64(LABEL, REG) \ + case LABEL: { \ + \ + return (REG); \ + \ + } + +guint64 ctx_read_reg(GumX64CpuContext *ctx, x86_reg reg) { + + switch (reg) { + + X86_REG_8L(X86_REG_AL, ctx->rax) + X86_REG_8L(X86_REG_BL, ctx->rbx) + X86_REG_8L(X86_REG_CL, ctx->rcx) + X86_REG_8L(X86_REG_DL, ctx->rdx) + X86_REG_8L(X86_REG_BPL, ctx->rbp) + X86_REG_8L(X86_REG_SIL, ctx->rsi) + X86_REG_8L(X86_REG_DIL, ctx->rdi) + + X86_REG_8H(X86_REG_AH, ctx->rax) + X86_REG_8H(X86_REG_BH, ctx->rbx) + X86_REG_8H(X86_REG_CH, ctx->rcx) + X86_REG_8H(X86_REG_DH, ctx->rdx) + + X86_REG_16(X86_REG_AX, ctx->rax) + X86_REG_16(X86_REG_BX, ctx->rbx) + X86_REG_16(X86_REG_CX, ctx->rcx) + X86_REG_16(X86_REG_DX, ctx->rdx) + X86_REG_16(X86_REG_DI, ctx->rdi) + X86_REG_16(X86_REG_SI, ctx->rsi) + X86_REG_16(X86_REG_BP, ctx->rbp) + + X86_REG_32(X86_REG_EAX, ctx->rax) + X86_REG_32(X86_REG_ECX, ctx->rcx) + X86_REG_32(X86_REG_EDX, ctx->rdx) + X86_REG_32(X86_REG_EBX, ctx->rbx) + X86_REG_32(X86_REG_ESP, ctx->rsp) + X86_REG_32(X86_REG_EBP, ctx->rbp) + X86_REG_32(X86_REG_ESI, ctx->rsi) + X86_REG_32(X86_REG_EDI, ctx->rdi) + X86_REG_32(X86_REG_R8D, ctx->r8) + X86_REG_32(X86_REG_R9D, ctx->r9) + X86_REG_32(X86_REG_R10D, ctx->r10) + X86_REG_32(X86_REG_R11D, ctx->r11) + X86_REG_32(X86_REG_R12D, ctx->r12) + X86_REG_32(X86_REG_R13D, ctx->r13) + X86_REG_32(X86_REG_R14D, ctx->r14) + X86_REG_32(X86_REG_R15D, ctx->r15) + X86_REG_32(X86_REG_EIP, ctx->rip) + + X86_REG_64(X86_REG_RAX, ctx->rax) + X86_REG_64(X86_REG_RCX, ctx->rcx) + X86_REG_64(X86_REG_RDX, ctx->rdx) + X86_REG_64(X86_REG_RBX, ctx->rbx) + X86_REG_64(X86_REG_RSP, ctx->rsp) + X86_REG_64(X86_REG_RBP, ctx->rbp) + X86_REG_64(X86_REG_RSI, ctx->rsi) + X86_REG_64(X86_REG_RDI, ctx->rdi) + X86_REG_64(X86_REG_R8, ctx->r8) + X86_REG_64(X86_REG_R9, ctx->r9) + X86_REG_64(X86_REG_R10, ctx->r10) + X86_REG_64(X86_REG_R11, ctx->r11) + X86_REG_64(X86_REG_R12, ctx->r12) + X86_REG_64(X86_REG_R13, ctx->r13) + X86_REG_64(X86_REG_R14, ctx->r14) + X86_REG_64(X86_REG_R15, ctx->r15) + X86_REG_64(X86_REG_RIP, ctx->rip) + + default: + FATAL("Failed to read register: %d", reg); + return 0; + + } + +} + +#endif + diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index 971f80c0..5c77ade6 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -5,6 +5,7 @@ #include "config.h" #include "debug.h" +#include "asan.h" #include "entry.h" #include "frida_cmplog.h" #include "instrument.h" @@ -107,6 +108,7 @@ static void instr_basic_block(GumStalkerIterator *iterator, if (!range_is_excluded((void *)instr->address)) { + asan_instrument(instr, iterator); cmplog_instrument(instr, iterator); } @@ -142,6 +144,7 @@ void instrument_init(void) { transformer = gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL); + asan_init(); cmplog_init(); } diff --git a/frida_mode/test/fasan/GNUmakefile b/frida_mode/test/fasan/GNUmakefile new file mode 100644 index 00000000..22689395 --- /dev/null +++ b/frida_mode/test/fasan/GNUmakefile @@ -0,0 +1,156 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ + +TEST_DATA_DIR:=$(BUILD_DIR)in/ +TEST_DATA_FILE:=$(TEST_DATA_DIR)in +FRIDA_OUT:=$(BUILD_DIR)frida-out + +TEST_SRC:=$(PWD)/test.c +TEST_BIN:=$(BUILD_DIR)test + +CFLAGS+=-fPIC \ + -D_GNU_SOURCE \ + -g \ + -fno-omit-frame-pointer \ + -Wno-stringop-overflow \ + +LDFLAGS+=-ldl \ + +ifdef DEBUG +CFLAGS+=-Werror \ + -Wall \ + -Wextra \ + -Wpointer-arith +else +CFLAGS+=-Wno-pointer-arith +endif + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +ifeq "$(ARCH)" "x86" +LIBASAN_FILE:=libclang_rt.asan-i386.so +endif + +ifeq "$(ARCH)" "x64" +LIBASAN_FILE:=libclang_rt.asan-x86_64.so +endif + +ifeq "$(ARCH)" "aarch64" +LIBASAN_FILE:=libclang_rt.asan-aarch64.so +endif + +# LIBASAN:=/usr/lib/llvm-10/lib/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.so +# LIBASAN:=/usr/lib/x86_64-linux-gnu/libasan.so.6.0.0 + +LLVM_CONFIG ?= llvm-config +ifeq "$(shell test -e '$(shell which $(LLVM_CONFIG))' && echo 1)" "1" + $(info Found llvm-config: '$(shell which $(LLVM_CONFIG))') +else + $(warning Cannot find llvm-config) +endif + +LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)/ +$(info LLVM_BINDIR: $(LLVM_BINDIR)) + +CLANG ?= $(LLVM_BINDIR)clang +ifeq "$(shell test -e '$(CLANG)' && echo 1)" "1" + $(info Found clang: '$(CLANG)') +else + $(warning Cannot find clang) +endif + +CLANGVER = $(shell $(CLANG) --version | sed -E -ne '/^.*version\ (1?[0-9]\.[0-9]\.[0-9]).*/s//\1/p') +$(info Clang version $(CLANGVER)) + +LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null) +$(info LLVM_LIBDIR: $(LLVM_LIBDIR)) + +LIBASAN:=$(LLVM_LIBDIR)/clang/$(CLANGVER)/lib/linux/$(LIBASAN_FILE) + +ifeq "$(shell test -e '$(LIBASAN)' && echo 1)" "1" + $(info Found Address Sanitizer DSO: '$(LIBASAN)') +else + $(error Error cannot find Address Sanitizer DSO) +endif + + +.PHONY: all clean format frida-noasan frida debug run + +############################## ALL ############################################# + +all: $(TEST_BIN) + +$(TEST_BIN): $(TEST_SRC) GNUmakefile | $(BUILD_DIR) + $(CC) \ + $(CFLAGS) \ + $(LDFLAGS) \ + -o $@ \ + $< + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +############################# TESTS ############################################ + +$(TEST_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TEST_DATA_FILE): | $(TEST_DATA_DIR) + echo -n "TUODATM" > $@ + +frida-noasan: $(TEST_BIN) $(TEST_DATA_FILE) + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) + + +frida: $(TEST_BIN) $(TEST_DATA_FILE) + AFL_PRELOAD=/usr/lib/llvm-10/lib/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.so \ + AFL_USE_FASAN=1 \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) + +debug: $(TEST_BIN) $(TEST_DATA_FILE) + gdb \ + --ex 'set environment LD_PRELOAD=$(LIBASAN):$(ROOT)afl-frida-trace.so' \ + --ex 'set environment ASAN_OPTIONS=detect_leaks=false,halt_on_error=0' \ + --ex 'set environment AFL_USE_FASAN=1' \ + --ex 'set disassembly-flavor intel' \ + --ex 'r < $(TEST_DATA_FILE)' \ + --args $(TEST_BIN) \ + +run: $(TEST_BIN) $(TEST_DATA_FILE) + LD_PRELOAD=$(LIBASAN):$(ROOT)afl-frida-trace.so \ + ASAN_OPTIONS=detect_leaks=false \ + AFL_USE_FASAN=1 \ + $(TEST_BIN) < $(TEST_DATA_FILE) + +############################# CLEAN ############################################ +clean: + rm -rf $(BUILD_DIR) + +############################# FORMAT ########################################### +format: + cd $(ROOT) && echo $(TEST_SRC) | xargs -L1 ./.custom-format.py -i + +############################# RUN ############################################# diff --git a/frida_mode/test/fasan/Makefile b/frida_mode/test/fasan/Makefile new file mode 100644 index 00000000..a7bf44c7 --- /dev/null +++ b/frida_mode/test/fasan/Makefile @@ -0,0 +1,18 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +clean: + @gmake clean + +frida-noasan: + @gmake frida-noasan + +frida: + @gmake frida + +debug: + @gmake debug + +run: + @gmake run \ No newline at end of file diff --git a/frida_mode/test/fasan/test.c b/frida_mode/test/fasan/test.c new file mode 100644 index 00000000..a7d03017 --- /dev/null +++ b/frida_mode/test/fasan/test.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include +#include + +#define LOG(x) \ + do { \ + \ + char buf[] = x; \ + write(STDOUT_FILENO, buf, sizeof(buf)); \ + \ + } while (false); + +void test(char data) { + + char *buf = malloc(10); + + if (buf == NULL) return; + + switch (data) { + + /* Underflow */ + case 'U': + LOG("Underflow\n"); + buf[-1] = '\0'; + free(buf); + break; + /* Overflow */ + case 'O': + LOG("Overflow\n"); + buf[10] = '\0'; + free(buf); + break; + /* Double free */ + case 'D': + LOG("Double free\n"); + free(buf); + free(buf); + break; + /* Use after free */ + case 'A': + LOG("Use after free\n"); + free(buf); + buf[0] = '\0'; + break; + /* Test Limits (OK) */ + case 'T': + LOG("Test-Limits - No Error\n"); + buf[0] = 'A'; + buf[9] = 'I'; + free(buf); + break; + case 'M': + LOG("Memset too many\n"); + memset(buf, '\0', 11); + free(buf); + break; + default: + LOG("Nop - No Error\n"); + break; + + } + +} + +int main(int argc, char **argv) { + + char input = '\0'; + + if (read(STDIN_FILENO, &input, 1) < 0) { + + LOG("Failed to read stdin\n"); + return 1; + + } + + test(input); + + LOG("DONE\n"); + return 0; + +} + diff --git a/include/envs.h b/include/envs.h index 9175005e..4fff1e3a 100644 --- a/include/envs.h +++ b/include/envs.h @@ -191,6 +191,7 @@ static char *afl_environment_variables[] = { "AFL_WINE_PATH", "AFL_NO_SNAPSHOT", "AFL_EXPAND_HAVOC_NOW", + "AFL_USE_FASAN", "AFL_USE_QASAN", NULL diff --git a/include/forkserver.h b/include/forkserver.h index 48db94c7..2baa6f0a 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -79,6 +79,8 @@ typedef struct afl_forkserver { bool frida_mode; /* if running in frida mode or not */ + bool frida_asan; /* if running with asan in frida mode */ + bool use_stdin; /* use stdin for sending data */ bool no_unlink; /* do not unlink cur_input */ diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a4599b4a..903068b2 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -328,6 +328,50 @@ static int stricmp(char const *a, char const *b) { } +static void fasan_check_afl_preload(char *afl_preload) { + + char first_preload[PATH_MAX + 1] = {0}; + char * separator = strchr(afl_preload, ':'); + size_t first_preload_len = PATH_MAX; + char * basename; + char clang_runtime_prefix[] = "libclang_rt.asan-"; + + if (separator != NULL && (separator - afl_preload) < PATH_MAX) { + + first_preload_len = separator - afl_preload; + + } + + strncpy(first_preload, afl_preload, first_preload_len); + + basename = strrchr(first_preload, '/'); + if (basename == NULL) { + + basename = first_preload; + + } else { + + basename = basename + 1; + + } + + if (strncmp(basename, clang_runtime_prefix, + sizeof(clang_runtime_prefix) - 1) != 0) { + + FATAL("Address Sanitizer DSO must be the first DSO in AFL_PRELOAD"); + + } + + if (access(first_preload, R_OK) != 0) { + + FATAL("Address Sanitizer DSO not found"); + + } + + OKF("Found ASAN DSO: %s", first_preload); + +} + /* Main entry point */ int main(int argc, char **argv_orig, char **envp) { @@ -785,6 +829,7 @@ int main(int argc, char **argv_orig, char **envp) { } afl->fsrv.frida_mode = 1; + if (get_afl_env("AFL_USE_FASAN")) { afl->fsrv.frida_asan = 1; } break; @@ -1365,18 +1410,21 @@ int main(int argc, char **argv_orig, char **envp) { } else if (afl->fsrv.frida_mode) { afl_preload = getenv("AFL_PRELOAD"); - u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); - OKF("Injecting %s ...", frida_binary); - if (afl_preload) { - frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); + if (afl->fsrv.frida_asan) { - } else { + OKF("Using Frida Address Sanitizer Mode"); + + fasan_check_afl_preload(afl_preload); - frida_afl_preload = alloc_printf("%s", frida_binary); + setenv("ASAN_OPTIONS", "detect_leaks=false", 1); } + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + OKF("Injecting %s ...", frida_binary); + frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); + ck_free(frida_binary); setenv("LD_PRELOAD", frida_afl_preload, 1); @@ -1391,11 +1439,22 @@ 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"); - OKF("Injecting %s ...", frida_binary); - setenv("LD_PRELOAD", frida_binary, 1); - setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); - ck_free(frida_binary); + if (afl->fsrv.frida_asan) { + + OKF("Using Frida Address Sanitizer Mode"); + FATAL( + "Address Sanitizer DSO must be loaded using AFL_PRELOAD in Frida " + "Address Sanitizer Mode"); + + } else { + + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + OKF("Injecting %s ...", frida_binary); + setenv("LD_PRELOAD", frida_binary, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); + ck_free(frida_binary); + + } } -- cgit 1.4.1 From d776d40669eb36cbfabeeeca55d4343413e2285b Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 19 May 2021 14:50:41 +0200 Subject: merge --- src/afl-fuzz.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 903068b2..1ac2e8ff 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1410,6 +1410,9 @@ int main(int argc, char **argv_orig, char **envp) { } else if (afl->fsrv.frida_mode) { afl_preload = getenv("AFL_PRELOAD"); + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + OKF("Injecting %s ...", frida_binary); + if (afl_preload) { if (afl->fsrv.frida_asan) { -- cgit 1.4.1 From dee64e74a8f5320e4fc86d6e6597c5f4b07d4ef7 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 19 May 2021 15:03:45 +0200 Subject: fix afl-fuzz.c frida preload --- src/afl-fuzz.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 1ac2e8ff..eff25c91 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1414,24 +1414,26 @@ int main(int argc, char **argv_orig, char **envp) { OKF("Injecting %s ...", frida_binary); if (afl_preload) { - if (afl->fsrv.frida_asan) { + if (afl->fsrv.frida_asan) { - OKF("Using Frida Address Sanitizer Mode"); + OKF("Using Frida Address Sanitizer Mode"); - fasan_check_afl_preload(afl_preload); + fasan_check_afl_preload(afl_preload); - setenv("ASAN_OPTIONS", "detect_leaks=false", 1); + setenv("ASAN_OPTIONS", "detect_leaks=false", 1); - } + } - u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); - OKF("Injecting %s ...", frida_binary); - frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + OKF("Injecting %s ...", frida_binary); + frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); - ck_free(frida_binary); + ck_free(frida_binary); - setenv("LD_PRELOAD", frida_afl_preload, 1); - setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); + setenv("LD_PRELOAD", frida_afl_preload, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); + + } } else { -- cgit 1.4.1 From cdae3d3d038a28f1096ab6d34128896c19ef4733 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Wed, 19 May 2021 22:21:46 +0200 Subject: cleaned up AFL_PRINT_FILENAMES env --- include/envs.h | 1 + src/afl-fuzz.c | 2 +- src/afl-showmap.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/include/envs.h b/include/envs.h index 4fff1e3a..f1314bad 100644 --- a/include/envs.h +++ b/include/envs.h @@ -193,6 +193,7 @@ static char *afl_environment_variables[] = { "AFL_EXPAND_HAVOC_NOW", "AFL_USE_FASAN", "AFL_USE_QASAN", + "AFL_PRINT_FILENAMES", NULL }; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index eff25c91..5f939115 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1432,7 +1432,7 @@ int main(int argc, char **argv_orig, char **envp) { setenv("LD_PRELOAD", frida_afl_preload, 1); setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); - + } } else { diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 10818905..9b4d21a5 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -774,7 +774,7 @@ int main(int argc, char **argv_orig, char **envp) { afl_forkserver_t fsrv_var = {0}; if (getenv("AFL_DEBUG")) { debug = true; } - if (getenv("AFL_PRINT_FILENAMES")) { print_filenames = true; } + if (get_afl_env("AFL_PRINT_FILENAMES")) { print_filenames = true; } fsrv = &fsrv_var; afl_fsrv_init(fsrv); -- cgit 1.4.1 From bceae827549beaa7721a847976d277f644ab93c6 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 21 May 2021 12:24:58 +0200 Subject: improve error msg --- src/afl-fuzz-init.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index c43bcc2b..b277802b 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2728,11 +2728,15 @@ void check_binary(afl_state_t *afl, u8 *fname) { " When source code is not available, you may be able to leverage " "QEMU\n" " mode support. Consult the README.md for tips on how to enable " - "this.\n" + "this.\n\n" + + " If your target is an instrumented binary (e.g. with zafl, " + "retrowrite,\n" + " etc.) then set 'AFL_SKIP_BIN_CHECK=1'\n\n" " (It is also possible to use afl-fuzz as a traditional, " - "non-instrumented fuzzer.\n" - " For that, you can use the -n option - but expect much worse " + "non-instrumented\n" + " fuzzer. For that use the -n option - but expect much worse " "results.)\n", doc_path); -- cgit 1.4.1 From 1edb89be0f7956f964d2d7c9c7a5813250108220 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 21 May 2021 22:40:36 +0200 Subject: showmap passes queue items in alphabetical order --- src/afl-showmap.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 9b4d21a5..9bf84956 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -52,6 +52,7 @@ #include #include +#include #include #include #ifndef USEMMAP @@ -1129,8 +1130,9 @@ int main(int argc, char **argv_orig, char **envp) { if (in_dir) { - DIR * dir_in, *dir_out = NULL; - struct dirent *dir_ent; + DIR * dir_in, *dir_out = NULL; + struct dirent **file_list; + // int done = 0; u8 infile[PATH_MAX], outfile[PATH_MAX]; u8 wait_for_gdb = 0; @@ -1155,12 +1157,6 @@ int main(int argc, char **argv_orig, char **envp) { ck_free(dn); if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir); - if (!(dir_in = opendir(in_dir))) { - - PFATAL("cannot open directory %s", in_dir); - - } - if (!collect_coverage) { if (!(dir_out = opendir(out_file))) { @@ -1246,7 +1242,16 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); - while ((dir_ent = readdir(dir_in))) { + int file_count = scandir(in_dir, &file_list, NULL, alphasort); + if (file_count < 0) { + + PFATAL("Failed to read from input dir at %s\n", in_dir); + + } + + for (int i = 0; i < file_count; i++) { + + struct dirent *dir_ent = file_list[i]; if (dir_ent->d_name[0] == '.') { @@ -1293,9 +1298,11 @@ int main(int argc, char **argv_orig, char **envp) { } + free(file_list); + file_list = NULL; + if (!quiet_mode) { OKF("Processed %llu input files.", fsrv->total_execs); } - closedir(dir_in); if (dir_out) { closedir(dir_out); } if (collect_coverage) { -- cgit 1.4.1 From d14a758f69407fe5c39cdcccc093efd5d15ed43c Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 21 May 2021 23:16:37 +0200 Subject: lenient dict parsing, no map size enum for binary fuzzing --- src/afl-fuzz-extras.c | 14 ++++++++++++++ src/afl-fuzz.c | 11 +++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index 6091db15..584241d4 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -130,6 +130,20 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len, } + /* Skip [number] */ + + if (*lptr == '[') { + + do { + + ++lptr; + + } while (*lptr >= '0' && *lptr <= '9'); + + if (*lptr == ']') { ++lptr; } + + } + /* Skip whitespace and = signs. */ while (isspace(*lptr) || *lptr == '=') { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 5f939115..37659831 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1717,10 +1717,11 @@ int main(int argc, char **argv_orig, char **envp) { afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode); if (!afl->non_instrumented_mode && !afl->fsrv.qemu_mode && - !afl->unicorn_mode) { + !afl->unicorn_mode && !afl->fsrv.frida_mode && + !((map_size == MAP_SIZE || map_size == 65536) && + afl->afl_env.afl_skip_bin_check)) { - if (map_size <= DEFAULT_SHMEM_SIZE && !afl->non_instrumented_mode && - !afl->fsrv.qemu_mode && !afl->unicorn_mode) { + if (map_size <= DEFAULT_SHMEM_SIZE) { afl->fsrv.map_size = DEFAULT_SHMEM_SIZE; // dummy temporary value char vbuf[16]; @@ -1778,7 +1779,9 @@ int main(int argc, char **argv_orig, char **envp) { if ((map_size <= DEFAULT_SHMEM_SIZE || afl->cmplog_fsrv.map_size < map_size) && !afl->non_instrumented_mode && !afl->fsrv.qemu_mode && - !afl->fsrv.frida_mode && !afl->unicorn_mode) { + !afl->fsrv.frida_mode && !afl->unicorn_mode && + !((map_size == MAP_SIZE || map_size == 65536) && + afl->afl_env.afl_skip_bin_check)) { afl->cmplog_fsrv.map_size = MAX(map_size, (u32)DEFAULT_SHMEM_SIZE); char vbuf[16]; -- cgit 1.4.1 From 58e39ecd8f601191a98d067d5567559de931c32c Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 22 May 2021 12:15:09 +0200 Subject: turn off map size detection if skip_bin_check is set --- docs/env_variables.md | 1 + src/afl-common.c | 4 ++++ src/afl-fuzz.c | 8 +++----- 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/docs/env_variables.md b/docs/env_variables.md index c3efa0c0..def1e297 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -355,6 +355,7 @@ checks or alter some of the more exotic semantics of the tool: and shell scripts; and `AFL_DUMB_FORKSRV` in conjunction with the `-n` setting to instruct afl-fuzz to still follow the fork server protocol without expecting any instrumentation data in return. + Note that this also turns off auto map size detection. - 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 diff --git a/src/afl-common.c b/src/afl-common.c index 0fb1462e..8826de70 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -1110,6 +1110,10 @@ u32 get_map_size(void) { if (map_size % 64) { map_size = (((map_size >> 6) + 1) << 6); } + } else if (getenv("AFL_SKIP_BIN_CHECK")) { + + map_size = MAP_SIZE; + } return map_size; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 37659831..76c4ca37 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -238,7 +238,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_TARGET_ENV: pass extra environment variables to target\n" "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n" - "AFL_SKIP_BIN_CHECK: skip the check, if the target is an executable\n" + "AFL_SKIP_BIN_CHECK: skip afl compatability checks, also disables auto map size\n" "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n" "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n" "AFL_STATSD: enables StatsD metrics collection\n" @@ -1718,8 +1718,7 @@ int main(int argc, char **argv_orig, char **envp) { if (!afl->non_instrumented_mode && !afl->fsrv.qemu_mode && !afl->unicorn_mode && !afl->fsrv.frida_mode && - !((map_size == MAP_SIZE || map_size == 65536) && - afl->afl_env.afl_skip_bin_check)) { + !afl->afl_env.afl_skip_bin_check) { if (map_size <= DEFAULT_SHMEM_SIZE) { @@ -1780,8 +1779,7 @@ int main(int argc, char **argv_orig, char **envp) { afl->cmplog_fsrv.map_size < map_size) && !afl->non_instrumented_mode && !afl->fsrv.qemu_mode && !afl->fsrv.frida_mode && !afl->unicorn_mode && - !((map_size == MAP_SIZE || map_size == 65536) && - afl->afl_env.afl_skip_bin_check)) { + !afl->afl_env.afl_skip_bin_check) { afl->cmplog_fsrv.map_size = MAX(map_size, (u32)DEFAULT_SHMEM_SIZE); char vbuf[16]; -- cgit 1.4.1 From 5864430d935fac57350726d0133b8926bc62d169 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Sat, 22 May 2021 15:49:47 +0200 Subject: Typo --- src/afl-fuzz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 76c4ca37..35fb2d04 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -238,7 +238,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_TARGET_ENV: pass extra environment variables to target\n" "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n" - "AFL_SKIP_BIN_CHECK: skip afl compatability checks, also disables auto map size\n" + "AFL_SKIP_BIN_CHECK: skip afl compatibility checks, also disables auto map size\n" "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n" "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n" "AFL_STATSD: enables StatsD metrics collection\n" -- cgit 1.4.1 From bc286035e94e43e1e7db1b2a8099210f0e71b88b Mon Sep 17 00:00:00 2001 From: buherator Date: Sun, 23 May 2021 18:26:15 +0200 Subject: Set kill signal before using it in afl-showmap (#935) --- src/afl-showmap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 9bf84956..d7af668c 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -1104,6 +1104,9 @@ int main(int argc, char **argv_orig, char **envp) { : 0); be_quiet = save_be_quiet; + fsrv->kill_signal = + parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL); + if (new_map_size) { // only reinitialize when it makes sense @@ -1211,9 +1214,6 @@ int main(int argc, char **argv_orig, char **envp) { } - fsrv->kill_signal = - parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL); - if (getenv("AFL_CRASH_EXITCODE")) { long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10); -- cgit 1.4.1 From bb45398d0bbad0b86e311fa6effc286206ecc611 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 23 May 2021 18:47:39 +0200 Subject: fix afl-cc help output --- src/afl-cc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/afl-cc.c b/src/afl-cc.c index ff7b5219..ebe11525 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1640,7 +1640,7 @@ int main(int argc, char **argv, char **envp) { " yes\n" " [LLVM] llvm: %s%s\n" " PCGUARD %s yes yes module yes yes " - "extern\n" + "yes\n" " CLASSIC %s no yes module yes yes " "yes\n" " - NORMAL\n" -- cgit 1.4.1 From 109383f43830010c36b704c682ee537e6474d25a Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 May 2021 09:08:31 +0200 Subject: less executions on variable paths --- docs/Changelog.md | 2 ++ include/config.h | 4 ++-- src/afl-fuzz-run.c | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/docs/Changelog.md b/docs/Changelog.md index dfd5c393..33d37067 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -35,6 +35,8 @@ sending a mail to . afl++ ignores these and uses them for splicing instead. - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after no new paths have been found for n seconds + - when AFL_FAST_CAL is set a variable path will no be calibrated 8 times + instead of 40 - afl-cc: - We do not support llvm versions prior 6.0 anymore - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD diff --git a/include/config.h b/include/config.h index aa24ea6c..80cdb684 100644 --- a/include/config.h +++ b/include/config.h @@ -154,7 +154,7 @@ cases that show variable behavior): */ #define CAL_CYCLES 8U -#define CAL_CYCLES_LONG 40U +#define CAL_CYCLES_LONG 20U /* Number of subsequent timeouts before abandoning an input file: */ @@ -163,7 +163,7 @@ /* Maximum number of unique hangs or crashes to record: */ #define KEEP_UNIQUE_HANG 500U -#define KEEP_UNIQUE_CRASH 5000U +#define KEEP_UNIQUE_CRASH 10000U /* Baseline number of random tweaks during a single 'havoc' stage: */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 6e5210b8..5a481639 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -410,7 +410,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } var_detected = 1; - afl->stage_max = CAL_CYCLES_LONG; + afl->stage_max = afl->fast_cal ? CAL_CYCLES : CAL_CYCLES_LONG; } else { -- cgit 1.4.1 From 8e75adfee5574d6d0dd7fd73e9c0899f3162c964 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 May 2021 09:22:50 +0200 Subject: AFL_SKIP_CRASHES is obsolete since 3.0 --- docs/env_variables.md | 5 ----- include/afl-fuzz.h | 2 +- src/afl-fuzz-init.c | 30 +++--------------------------- src/afl-fuzz-state.c | 3 +-- src/afl-fuzz.c | 2 +- 5 files changed, 6 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/docs/env_variables.md b/docs/env_variables.md index def1e297..442b0dd0 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -315,11 +315,6 @@ checks or alter some of the more exotic semantics of the tool: - Setting `AFL_NO_AUTODICT` will not load an LTO generated auto dictionary that is compiled into the target. - - `AFL_SKIP_CRASHES` causes AFL++ to tolerate crashing files in the input - queue. This can help with rare situations where a program crashes only - intermittently, but it's not really recommended under normal operating - conditions. - - Setting `AFL_HANG_TMOUT` allows you to specify a different timeout for deciding if a particular test case is a "hang". The default is 1 second or the value of the `-t` parameter, whichever is larger. Dialing the value diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 72f956b9..e9a72fc2 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -388,7 +388,7 @@ typedef struct afl_env_vars { afl_exit_on_seed_issues; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, - *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, + *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, *afl_testcache_entries, *afl_kill_signal, *afl_target_env, diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index b277802b..f2d1fb9b 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -823,7 +823,6 @@ void perform_dry_run(afl_state_t *afl) { struct queue_entry *q; u32 cal_failures = 0, idx; - u8 * skip_crashes = afl->afl_env.afl_skip_crashes; u8 * use_mem; for (idx = 0; idx < afl->queued_paths; idx++) { @@ -923,27 +922,6 @@ void perform_dry_run(afl_state_t *afl) { if (afl->crash_mode) { break; } - if (skip_crashes) { - - if (afl->fsrv.uses_crash_exitcode) { - - WARNF( - "Test case results in a crash or AFL_CRASH_EXITCODE %d " - "(skipping)", - (int)(s8)afl->fsrv.crash_exitcode); - - } else { - - WARNF("Test case results in a crash (skipping)"); - - } - - q->cal_failed = CAL_CHANCES; - ++cal_failures; - break; - - } - if (afl->fsrv.mem_limit) { u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; @@ -1117,14 +1095,12 @@ void perform_dry_run(afl_state_t *afl) { if (cal_failures == afl->queued_paths) { - FATAL("All test cases time out%s, giving up!", - skip_crashes ? " or crash" : ""); + FATAL("All test cases time out or crash, giving up!"); } - WARNF("Skipped %u test cases (%0.02f%%) due to timeouts%s.", cal_failures, - ((double)cal_failures) * 100 / afl->queued_paths, - skip_crashes ? " or crashes" : ""); + WARNF("Skipped %u test cases (%0.02f%%) due to timeouts or crashes.", + cal_failures, ((double)cal_failures) * 100 / afl->queued_paths); if (cal_failures * 5 > afl->queued_paths) { diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index c886cb28..046d17d6 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -206,8 +206,7 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl_environment_variable_len)) { - afl->afl_env.afl_skip_crashes = - (u8 *)get_afl_env(afl_environment_variables[i]); + // we should mark this obsolete in a few versions } else if (!strncmp(env, "AFL_HANG_TMOUT", diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 35fb2d04..3b6ac5e2 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -240,7 +240,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n" "AFL_SKIP_BIN_CHECK: skip afl compatibility checks, also disables auto map size\n" "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n" - "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n" + //"AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n" "AFL_STATSD: enables StatsD metrics collection\n" "AFL_STATSD_HOST: change default statsd host (default 127.0.0.1)\n" "AFL_STATSD_PORT: change default statsd port (default: 8125)\n" -- cgit 1.4.1 From 87b16c4460d34eb775660991732ca0ef0c2f8e78 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 May 2021 10:45:24 +0200 Subject: add AFL_TRY_AFFINITY --- Dockerfile | 1 + README.md | 4 ++-- docs/Changelog.md | 10 ++++++---- docs/env_variables.md | 3 +++ include/afl-fuzz.h | 2 +- include/envs.h | 1 + src/afl-fuzz-init.c | 34 ++++++++++++++++++++++++---------- src/afl-fuzz-state.c | 7 +++++++ src/afl-fuzz.c | 1 + 9 files changed, 46 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/Dockerfile b/Dockerfile index 8f89b9aa..9662ca7c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,6 +50,7 @@ RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 0 ENV LLVM_CONFIG=llvm-config-12 ENV AFL_SKIP_CPUFREQ=1 +ENV AFL_TRY_AFFINITY=1 ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 RUN git clone --depth=1 https://github.com/vanhauser-thc/afl-cov /afl-cov diff --git a/README.md b/README.md index cedf706c..69e2d14a 100644 --- a/README.md +++ b/README.md @@ -679,8 +679,8 @@ If you see that an important area or a feature has not been covered so far then try to find an input that is able to reach that and start a new secondary in that fuzzing campaign with that seed as input, let it run for a few minutes, then terminate it. The main node will pick it up and make it available to the -other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` if you have no -free core. +other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` or +`export AFL_TRY_AFFINITY=1` if you have no free core. Note that you in nearly all cases can never reach full coverage. A lot of functionality is usually behind options that were not activated or fuzz e.g. diff --git a/docs/Changelog.md b/docs/Changelog.md index 33d37067..bbe55e3e 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -33,10 +33,12 @@ sending a mail to . - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in -i dir crashes the target or results in a timeout. By default afl++ ignores these and uses them for splicing instead. - - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after - no new paths have been found for n seconds - - when AFL_FAST_CAL is set a variable path will no be calibrated 8 times - instead of 40 + - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing + after no new paths have been found for n seconds + - when AFL_FAST_CAL is set a variable path will no be calibrated + 8 times instead of 40 + - added AFL_TRY_AFFINITY to try to bind to CPUs but don't error if + it fails - afl-cc: - We do not support llvm versions prior 6.0 anymore - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD diff --git a/docs/env_variables.md b/docs/env_variables.md index 442b0dd0..a3267523 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -312,6 +312,9 @@ checks or alter some of the more exotic semantics of the tool: on Linux systems. This slows things down, but lets you run more instances of afl-fuzz than would be prudent (if you really want to). + - Setting `AFL_TRY_AFFINITY` tries to attempts to bind to a specific CPU core + on Linux systems, but will not terminate if it fails. + - Setting `AFL_NO_AUTODICT` will not load an LTO generated auto dictionary that is compiled into the target. diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index e9a72fc2..4aba3bdf 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -385,7 +385,7 @@ typedef struct afl_env_vars { afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one, 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_exit_on_seed_issues, afl_try_affinity; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload, diff --git a/include/envs.h b/include/envs.h index f1314bad..e7162c0f 100644 --- a/include/envs.h +++ b/include/envs.h @@ -120,6 +120,7 @@ static char *afl_environment_variables[] = { "AFL_LLVM_INSTRUMENT_FILE", "AFL_LLVM_SKIP_NEVERZERO", "AFL_NO_AFFINITY", + "AFL_TRY_AFFINITY", "AFL_LLVM_LTO_STARTID", "AFL_LLVM_LTO_DONTWRITEID", "AFL_NO_ARITH", diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index f2d1fb9b..88b5bc02 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -113,7 +113,7 @@ void bind_to_free_cpu(afl_state_t *afl) { u8 lockfile[PATH_MAX] = ""; s32 i; - if (afl->afl_env.afl_no_affinity) { + if (afl->afl_env.afl_no_affinity && !afl->afl_env.afl_try_affinity) { if (afl->cpu_to_bind != -1) { @@ -130,10 +130,21 @@ void bind_to_free_cpu(afl_state_t *afl) { if (!bind_cpu(afl, afl->cpu_to_bind)) { - FATAL( - "Could not bind to requested CPU %d! Make sure you passed a valid " - "-b.", - afl->cpu_to_bind); + if (afl->afl_env.afl_try_affinity) { + + WARNF( + "Could not bind to requested CPU %d! Make sure you passed a valid " + "-b.", + afl->cpu_to_bind); + + } else { + + FATAL( + "Could not bind to requested CPU %d! Make sure you passed a valid " + "-b.", + afl->cpu_to_bind); + + } } @@ -420,11 +431,14 @@ void bind_to_free_cpu(afl_state_t *afl) { "Uh-oh, looks like all %d CPU cores on your system are allocated to\n" " other instances of afl-fuzz (or similar CPU-locked tasks). " "Starting\n" - " another fuzzer on this machine is probably a bad plan, but if " - "you are\n" - " absolutely sure, you can set AFL_NO_AFFINITY and try again.\n", - afl->cpu_core_count); - FATAL("No more free CPU cores"); + " another fuzzer on this machine is probably a bad plan.\n" + "%s", + afl->cpu_core_count, + afl->afl_env.afl_try_affinity ? "" + : " If you are sure, you can set " + "AFL_NO_AFFINITY and try again.\n"); + + if (!afl->afl_env.afl_try_affinity) { FATAL("No more free CPU cores"); } } diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 046d17d6..0658070e 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -202,6 +202,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_no_affinity = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_TRY_AFFINITY", + + afl_environment_variable_len)) { + + afl->afl_env.afl_try_affinity = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_SKIP_CRASHES", afl_environment_variable_len)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 3b6ac5e2..bb970e5f 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -220,6 +220,7 @@ static void usage(u8 *argv0, int more_help) { " then they are randomly selected instead all of them being\n" " used. Defaults to 200.\n" "AFL_NO_AFFINITY: do not check for an unused cpu core to use for fuzzing\n" + "AFL_TRY_AFFINITY: try to bind to an unused core, but don't fail if unsuccessful\n" "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n" "AFL_NO_AUTODICT: do not load an offered auto dictionary compiled into a target\n" "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n" -- cgit 1.4.1 From 3b93729213de46a3008709bd8170d5593394d8cb Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 May 2021 22:04:25 +0200 Subject: tweaks --- docs/Changelog.md | 4 ++-- docs/custom_mutators.md | 3 +++ src/afl-fuzz-python.c | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/docs/Changelog.md b/docs/Changelog.md index f8831ff1..175c6c43 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -35,8 +35,8 @@ sending a mail to . afl++ ignores these and uses them for splicing instead. - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after no new paths have been found for n seconds - - when AFL_FAST_CAL is set a variable path will now be calibrated - 8 times instead of 40 + - when AFL_FAST_CAL is set a variable path will no be calibrated + 8 times instead of originally 40. Long calibration is now 20. - added AFL_TRY_AFFINITY to try to bind to CPUs but don't error if it fails - afl-cc: diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 9d5381e8..3e3ae01d 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -92,6 +92,9 @@ def queue_new_entry(filename_new_queue, filename_orig_queue): def introspection(): return string + +def deinit(): # optional for Python + pass ``` ### Custom Mutation diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 8760194c..3aa97635 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -212,7 +212,7 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { PyObject_GetAttrString(py_module, "introspection"); py_functions[PY_FUNC_DEINIT] = PyObject_GetAttrString(py_module, "deinit"); if (!py_functions[PY_FUNC_DEINIT]) - FATAL("deinit function not found in python module"); + WARNF("deinit function not found in python module"); for (py_idx = 0; py_idx < PY_FUNC_COUNT; ++py_idx) { -- cgit 1.4.1 From 64d9b7dd21aec84658f6ab89eee0455e98bdbc98 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 26 May 2021 22:42:14 +0200 Subject: fix for MacOS --- src/afl-fuzz.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index bb970e5f..4cd38d78 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -35,6 +35,10 @@ #include #endif +#ifdef __APPLE__ + #include +#endif + #ifdef PROFILING extern u64 time_spent_working; #endif -- cgit 1.4.1 From 0aeb871ac95b35d741628069a487e843369c1ab0 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 26 May 2021 22:55:21 +0200 Subject: fix tmpfile removal --- src/afl-fuzz.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 4cd38d78..a3a623d9 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -2301,26 +2301,9 @@ stop_fuzzing: afl_fsrv_deinit(&afl->fsrv); /* remove tmpfile */ - if (afl->tmp_dir != NULL && !afl->in_place_resume) { + if (afl->tmp_dir != NULL && !afl->in_place_resume && afl->fsrv.out_file) { - char tmpfile[PATH_MAX]; - - if (afl->file_extension) { - - snprintf(tmpfile, PATH_MAX, "%s/.cur_input.%s", afl->tmp_dir, - afl->file_extension); - - } else { - - snprintf(tmpfile, PATH_MAX, "%s/.cur_input", afl->tmp_dir); - - } - - if (unlink(tmpfile) != 0) { - - FATAL("Could not unlink current input file: %s.", tmpfile); - - } + (void)unlink(afl->fsrv.out_file); } -- cgit 1.4.1 From 8e86f7ad803e571bcd275d2aca597997ab0e4d2c Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 28 May 2021 13:35:05 +0200 Subject: add --afl-noopt to afl-cc --- docs/Changelog.md | 1 + src/afl-cc.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) (limited to 'src') diff --git a/docs/Changelog.md b/docs/Changelog.md index 594637fb..298a3998 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -46,6 +46,7 @@ sending a mail to . - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode - Fixed a crash in llvm dict2file when a strncmp length was -1 + - added --afl-noopt support - utils/aflpp_driver: - aflpp_qemu_driver_hook fixed to work with qemu_mode - aflpp_driver now compiled with -fPIC diff --git a/src/afl-cc.c b/src/afl-cc.c index ebe11525..8af8e7b0 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1224,6 +1224,14 @@ int main(int argc, char **argv, char **envp) { if (strncmp(argv[i], "--afl", 5) == 0) { + if (!strcmp(argv[i], "--afl_noopt") || !strcmp(argv[i], "--afl-noopt")) { + + passthrough = 1; + argv[i] = "-g"; // we have to overwrite it, -g is always good + continue; + + } + if (compiler_mode) WARNF( "--afl-... compiler mode supersedes the AFL_CC_COMPILER and " @@ -1821,6 +1829,12 @@ int main(int argc, char **argv, char **envp) { "If anything fails - be sure to read README.lto.md!\n"); #endif + SAYF( + "\nYou can supply --afl-noopt to not instrument, like AFL_NOOPT. " + "(this is helpful\n" + "in some build systems if you do not want to instrument " + "everything.\n"); + } SAYF( -- cgit 1.4.1 From c78762e690ff936c2e5394aff87deeb7b6b67a6c Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 30 May 2021 02:04:37 +0200 Subject: fix for afl-showmap --- src/afl-showmap.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/afl-showmap.c b/src/afl-showmap.c index d7af668c..96b72dd9 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -235,6 +235,9 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) { if (cmin_mode && (fsrv->last_run_timed_out || (!caa && child_crashed != cco))) { + // create empty file to prevent error messages in afl-cmin + fd = open(outfile, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + close(fd); return ret; } -- cgit 1.4.1