mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-12 01:58:17 +00:00
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 <you@example.com>
This commit is contained in:
committed by
GitHub
parent
8da5cba401
commit
39ad3b8946
88
frida_mode/GNUmakefile
Normal file
88
frida_mode/GNUmakefile
Normal file
@ -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 #############################################
|
@ -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
|
||||
|
@ -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.
|
||||
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 |
|
||||
| -------------------------|:----------:|
|
||||
| NeverZero | |
|
||||
| Persistent Mode | |
|
||||
| LAF-Intel / CompCov | |
|
||||
| CmpLog | |
|
||||
| Selective Instrumentation| x |
|
||||
| Non-Colliding Coverage | |
|
||||
| Ngram prev_loc Coverage | |
|
||||
| Context Coverage | |
|
||||
| Auto Dictionary | |
|
||||
| Snapshot LKM Support | |
|
||||
| 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.
|
||||
|
9
frida_mode/include/complog.h
Normal file
9
frida_mode/include/complog.h
Normal file
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
8
frida_mode/include/lib.h
Normal file
8
frida_mode/include/lib.h
Normal file
@ -0,0 +1,8 @@
|
||||
#include "frida-gum.h"
|
||||
|
||||
void lib_init(void);
|
||||
|
||||
guint64 lib_get_text_base(void);
|
||||
|
||||
guint64 lib_get_text_limit(void);
|
||||
|
26
frida_mode/include/persistent.h
Normal file
26
frida_mode/include/persistent.h
Normal file
@ -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);
|
||||
|
@ -1,5 +1,6 @@
|
||||
void prefetch_init();
|
||||
void prefetch_start(GumStalker *stalker);
|
||||
void prefetch_write(void *addr);
|
||||
void prefetch_read(GumStalker *stalker);
|
||||
#include "frida-gum.h"
|
||||
|
||||
void prefetch_init(void);
|
||||
void prefetch_write(void *addr);
|
||||
void prefetch_read(void);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "frida-gum.h"
|
||||
|
||||
void ranges_init(GumStalker *stalker);
|
||||
void ranges_init(void);
|
||||
|
||||
gboolean range_is_excluded(gpointer address);
|
||||
|
||||
|
8
frida_mode/include/stalker.h
Normal file
8
frida_mode/include/stalker.h
Normal file
@ -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);
|
||||
|
6
frida_mode/include/util.h
Normal file
6
frida_mode/include/util.h
Normal file
@ -0,0 +1,6 @@
|
||||
#include "frida-gum.h"
|
||||
|
||||
guint64 util_read_address(char *key);
|
||||
|
||||
guint64 util_read_num(char *key);
|
||||
|
72
frida_mode/src/complog/complog.c
Normal file
72
frida_mode/src/complog/complog.c
Normal file
@ -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;
|
||||
|
||||
}
|
||||
|
15
frida_mode/src/complog/complog_arm.c
Normal file
15
frida_mode/src/complog/complog_arm.c
Normal file
@ -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
|
||||
|
15
frida_mode/src/complog/complog_arm64.c
Normal file
15
frida_mode/src/complog/complog_arm64.c
Normal file
@ -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
|
||||
|
363
frida_mode/src/complog/complog_x64.c
Normal file
363
frida_mode/src/complog/complog_x64.c
Normal file
@ -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
|
||||
|
15
frida_mode/src/complog/complog_x86.c
Normal file
15
frida_mode/src/complog/complog_x86.c
Normal file
@ -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
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
150
frida_mode/src/instrument/instrument.c
Normal file
150
frida_mode/src/instrument/instrument.c
Normal file
@ -0,0 +1,150 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
|
||||
}
|
||||
|
23
frida_mode/src/instrument/instrument_arm32.c
Normal file
23
frida_mode/src/instrument/instrument_arm32.c
Normal file
@ -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
|
||||
|
97
frida_mode/src/instrument/instrument_arm64.c
Normal file
97
frida_mode/src/instrument/instrument_arm64.c
Normal file
@ -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
|
||||
|
93
frida_mode/src/instrument/instrument_x64.c
Normal file
93
frida_mode/src/instrument/instrument_x64.c
Normal file
@ -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
|
||||
|
23
frida_mode/src/instrument/instrument_x86.c
Normal file
23
frida_mode/src/instrument/instrument_x86.c
Normal file
@ -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
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
167
frida_mode/src/lib.c
Normal file
167
frida_mode/src/lib.c
Normal file
@ -0,0 +1,167 @@
|
||||
#include <elf.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/limits.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
|
||||
}
|
||||
|
@ -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()) {
|
||||
|
68
frida_mode/src/persistent/persistent.c
Normal file
68
frida_mode/src/persistent/persistent.c
Normal file
@ -0,0 +1,68 @@
|
||||
#include <dlfcn.h>
|
||||
|
||||
#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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
70
frida_mode/src/persistent/persistent_arm32.c
Normal file
70
frida_mode/src/persistent/persistent_arm32.c
Normal file
@ -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
|
||||
|
113
frida_mode/src/persistent/persistent_arm64.c
Normal file
113
frida_mode/src/persistent/persistent_arm64.c
Normal file
@ -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
|
||||
|
337
frida_mode/src/persistent/persistent_x64.c
Normal file
337
frida_mode/src/persistent/persistent_x64.c
Normal file
@ -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
|
||||
|
53
frida_mode/src/persistent/persistent_x86.c
Normal file
53
frida_mode/src/persistent/persistent_x86.c
Normal file
@ -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
|
||||
|
@ -3,9 +3,12 @@
|
||||
#include <sys/mman.h>
|
||||
|
||||
#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();
|
||||
|
||||
}
|
||||
|
||||
|
@ -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,90 +157,6 @@ static void convert_token(gchar *token, GumMemoryRange *range) {
|
||||
|
||||
}
|
||||
|
||||
static gboolean include_ranges(const GumRangeDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
include_range_ctx_t *ctx = (include_range_ctx_t *)user_data;
|
||||
GArray * array = (GArray *)ctx->array;
|
||||
GumAddress base = details->range->base_address;
|
||||
GumAddress limit = details->range->base_address + details->range->size;
|
||||
|
||||
OKF("Range for inclusion 0x%016" G_GINT64_MODIFIER
|
||||
"x-0x%016" G_GINT64_MODIFIER "x",
|
||||
base, limit);
|
||||
|
||||
for (int i = 0; i < array->len; i++) {
|
||||
|
||||
GumMemoryRange *range = &g_array_index(array, GumMemoryRange, i);
|
||||
GumAddress range_base = range->base_address;
|
||||
GumAddress range_limit = range->base_address + range->size;
|
||||
|
||||
/* Before the region */
|
||||
if (range_limit < base) { continue; }
|
||||
|
||||
/* After the region */
|
||||
if (range_base > limit) {
|
||||
|
||||
GumMemoryRange exclude = {.base_address = base, .size = limit - base};
|
||||
OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER
|
||||
"x",
|
||||
base, limit);
|
||||
gum_stalker_exclude(ctx->stalker, &exclude);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/* Overlap the start of the region */
|
||||
if (range_base < base) {
|
||||
|
||||
/* Range contains the region */
|
||||
if (range_limit > limit) {
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
base = range_limit;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
/* Overlap the end of the region */
|
||||
|
||||
} else {
|
||||
|
||||
GumMemoryRange exclude = {.base_address = base,
|
||||
.size = range_base - base};
|
||||
OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER
|
||||
"x",
|
||||
base, range_base);
|
||||
gum_stalker_exclude(ctx->stalker, &exclude);
|
||||
/* Extend past the end of the region */
|
||||
if (range_limit >= limit) {
|
||||
|
||||
return true;
|
||||
|
||||
/* Contained within the region */
|
||||
|
||||
} else {
|
||||
|
||||
base = range_limit;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GumMemoryRange exclude = {.base_address = base, .size = limit - base};
|
||||
OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER "x",
|
||||
base, limit);
|
||||
gum_stalker_exclude(ctx->stalker, &exclude);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
gint range_sort(gconstpointer a, gconstpointer b) {
|
||||
|
||||
return ((GumMemoryRange *)a)->base_address -
|
||||
@ -250,8 +164,8 @@ gint range_sort(gconstpointer a, gconstpointer b) {
|
||||
|
||||
}
|
||||
|
||||
static gboolean print_ranges(const GumRangeDetails *details,
|
||||
gpointer user_data) {
|
||||
static gboolean print_ranges_callback(const GumRangeDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
if (details->file == NULL) {
|
||||
|
||||
@ -273,62 +187,75 @@ static gboolean print_ranges(const GumRangeDetails *details,
|
||||
|
||||
}
|
||||
|
||||
void ranges_init(GumStalker *stalker) {
|
||||
static void print_ranges(char *key, GArray *ranges) {
|
||||
|
||||
char * showmaps;
|
||||
char * include;
|
||||
char * exclude;
|
||||
char * list;
|
||||
OKF("Range: %s Length: %d", key, ranges->len);
|
||||
for (int i = 0; i < ranges->len; i++) {
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static gboolean collect_module_ranges_callback(const GumRangeDetails *details,
|
||||
gpointer user_data) {
|
||||
|
||||
GArray * ranges = (GArray *)user_data;
|
||||
GumMemoryRange range = *details->range;
|
||||
g_array_append_val(ranges, range);
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
static GArray *collect_module_ranges(void) {
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
static GArray *collect_ranges(char *env_key) {
|
||||
|
||||
char * env_val;
|
||||
gchar ** tokens;
|
||||
int token_count;
|
||||
GumMemoryRange range;
|
||||
int i;
|
||||
GArray * result;
|
||||
|
||||
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");
|
||||
env_val = getenv(env_key);
|
||||
if (env_val == NULL) return result;
|
||||
|
||||
if (showmaps) {
|
||||
|
||||
gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges, NULL);
|
||||
|
||||
}
|
||||
|
||||
if (include != NULL && exclude != NULL) {
|
||||
|
||||
FATAL(
|
||||
"Cannot specifify both AFL_FRIDA_INST_RANGES and "
|
||||
"AFL_FRIDA_EXCLUDE_RANGES");
|
||||
|
||||
}
|
||||
|
||||
if (include == NULL && exclude == NULL) { return; }
|
||||
|
||||
list = include == NULL ? exclude : include;
|
||||
exclude_ranges = include == NULL ? true : false;
|
||||
|
||||
tokens = g_strsplit(list, ",", MAX_RANGES);
|
||||
tokens = g_strsplit(env_val, ",", MAX_RANGES);
|
||||
|
||||
for (token_count = 0; tokens[token_count] != NULL; token_count++)
|
||||
;
|
||||
|
||||
ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), token_count);
|
||||
|
||||
for (i = 0; i < token_count; i++) {
|
||||
|
||||
convert_token(tokens[i], &range);
|
||||
g_array_append_val(ranges, range);
|
||||
g_array_append_val(result, range);
|
||||
|
||||
}
|
||||
|
||||
g_array_sort(ranges, range_sort);
|
||||
g_array_sort(result, range_sort);
|
||||
|
||||
/* Check for overlaps */
|
||||
for (i = 1; i < token_count; i++) {
|
||||
|
||||
GumMemoryRange *prev = &g_array_index(ranges, GumMemoryRange, i - 1);
|
||||
GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i);
|
||||
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) {
|
||||
@ -342,31 +269,283 @@ void ranges_init(GumStalker *stalker) {
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < token_count; i++) {
|
||||
print_ranges(env_key, result);
|
||||
|
||||
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);
|
||||
g_strfreev(tokens);
|
||||
|
||||
}
|
||||
return result;
|
||||
|
||||
if (include == NULL) {
|
||||
}
|
||||
|
||||
for (i = 0; i < token_count; i++) {
|
||||
static GArray *collect_libs_ranges(void) {
|
||||
|
||||
gum_stalker_exclude(stalker, &g_array_index(ranges, GumMemoryRange, i));
|
||||
GArray * result;
|
||||
GumMemoryRange range;
|
||||
result = g_array_new(false, false, sizeof(GumMemoryRange));
|
||||
|
||||
}
|
||||
if (getenv("AFL_INST_LIBS") == NULL) {
|
||||
|
||||
range.base_address = lib_get_text_base();
|
||||
range.size = lib_get_text_limit() - lib_get_text_base();
|
||||
|
||||
} else {
|
||||
|
||||
include_range_ctx_t ctx = {.stalker = stalker, .array = ranges};
|
||||
gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, include_ranges, &ctx);
|
||||
range.base_address = 0;
|
||||
range.size = G_MAXULONG;
|
||||
|
||||
}
|
||||
|
||||
g_strfreev(tokens);
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
static GArray *intersect_ranges(GArray *a, GArray *b) {
|
||||
|
||||
GArray * result;
|
||||
GumMemoryRange *ra;
|
||||
GumMemoryRange *rb;
|
||||
GumMemoryRange ri;
|
||||
|
||||
result = g_array_new(false, false, sizeof(GumMemoryRange));
|
||||
|
||||
for (int i = 0; i < a->len; i++) {
|
||||
|
||||
ra = &g_array_index(a, GumMemoryRange, i);
|
||||
for (int j = 0; j < b->len; j++) {
|
||||
|
||||
rb = &g_array_index(b, GumMemoryRange, j);
|
||||
|
||||
if (!intersect_range(&ri, ra, rb)) { break; }
|
||||
|
||||
if (ri.size == 0) { continue; }
|
||||
|
||||
g_array_append_val(result, ri);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
static GArray *subtract_ranges(GArray *a, GArray *b) {
|
||||
|
||||
GArray * result;
|
||||
GumMemoryRange *ra;
|
||||
GumAddress ral;
|
||||
GumMemoryRange *rb;
|
||||
GumMemoryRange ri;
|
||||
GumMemoryRange rs;
|
||||
|
||||
result = g_array_new(false, false, sizeof(GumMemoryRange));
|
||||
|
||||
for (int i = 0; i < a->len; i++) {
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
static GArray *merge_ranges(GArray *a) {
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
g_array_append_val(result, rp);
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
module_ranges = collect_module_ranges();
|
||||
libs_ranges = collect_libs_ranges();
|
||||
include_ranges = collect_ranges("AFL_FRIDA_INST_RANGES");
|
||||
|
||||
/* If include ranges is empty, then assume everything is included */
|
||||
if (include_ranges->len == 0) {
|
||||
|
||||
ri.base_address = 0;
|
||||
ri.size = G_MAXULONG;
|
||||
g_array_append_val(include_ranges, ri);
|
||||
|
||||
}
|
||||
|
||||
exclude_ranges = collect_ranges("AFL_FRIDA_EXCLUDE_RANGES");
|
||||
|
||||
/* 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_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;
|
||||
|
||||
}
|
||||
|
||||
|
49
frida_mode/src/stalker.c
Normal file
49
frida_mode/src/stalker.c
Normal file
@ -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();
|
||||
|
||||
}
|
||||
|
66
frida_mode/src/util.c
Normal file
66
frida_mode/src/util.c
Normal file
@ -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;
|
||||
|
||||
}
|
||||
|
66
frida_mode/test/cmplog/GNUmakefile
Normal file
66
frida_mode/test/cmplog/GNUmakefile
Normal file
@ -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)
|
12
frida_mode/test/cmplog/Makefile
Normal file
12
frida_mode/test/cmplog/Makefile
Normal file
@ -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
|
106
frida_mode/test/png/GNUmakefile
Normal file
106
frida_mode/test/png/GNUmakefile
Normal file
@ -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) @@
|
12
frida_mode/test/png/Makefile
Normal file
12
frida_mode/test/png/Makefile
Normal file
@ -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
|
54
frida_mode/test/png/persistent/GNUmakefile
Normal file
54
frida_mode/test/png/persistent/GNUmakefile
Normal file
@ -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)
|
12
frida_mode/test/png/persistent/Makefile
Normal file
12
frida_mode/test/png/persistent/Makefile
Normal file
@ -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
|
36
frida_mode/test/png/persistent/get_symbol_addr.py
Executable file
36
frida_mode/test/png/persistent/get_symbol_addr.py
Executable file
@ -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)
|
70
frida_mode/test/png/persistent/hook/GNUmakefile
Normal file
70
frida_mode/test/png/persistent/hook/GNUmakefile
Normal file
@ -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)
|
||||
|
12
frida_mode/test/png/persistent/hook/Makefile
Normal file
12
frida_mode/test/png/persistent/hook/Makefile
Normal file
@ -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
|
50
frida_mode/test/testinstr/GNUmakefile
Normal file
50
frida_mode/test/testinstr/GNUmakefile
Normal file
@ -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) @@
|
12
frida_mode/test/testinstr/Makefile
Normal file
12
frida_mode/test/testinstr/Makefile
Normal file
@ -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
|
@ -22,7 +22,7 @@
|
||||
#define TESTINSTR_SECTION __attribute__((section(".testinstr")))
|
||||
#endif
|
||||
|
||||
TESTINSTR_SECTION void testinstr(char *buf, int len) {
|
||||
void testinstr(char *buf, int len) {
|
||||
|
||||
if (len < 1) return;
|
||||
buf[len] = 0;
|
||||
@ -37,7 +37,7 @@ TESTINSTR_SECTION void testinstr(char *buf, int len) {
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
TESTINSTR_SECTION int main(int argc, char **argv) {
|
||||
|
||||
char * file;
|
||||
int fd = -1;
|
@ -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",
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
Submodule qemu_mode/qemuafl updated: d73b0336b4...d1ca56b84e
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 ||
|
||||
|
@ -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];
|
||||
|
Reference in New Issue
Block a user