Push to stable (#895)

* sync (#886)

* Create FUNDING.yml

* Update FUNDING.yml

* moved custom_mutator examples

* unicorn speedtest makefile cleanup

* fixed example location

* fix qdbi

* update util readme

* 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>

* nits

* fix frida mode

* Integer overflow/underflow fixes in libdislocator (#889)

* libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t'

* libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads

* Bumped warnings up to the max and fixed remaining issues (#890)

Co-authored-by: Your Name <you@example.com>

* nits

* frida mode - support non-pie

* nits

* nit

* update grammar mutator

* Fixes for aarch64, OSX and other minor issues (#891)

Co-authored-by: Your Name <you@example.com>

* nits

* nits

* fix PCGUARD, build aflpp_driver with fPIC

* Added representative fuzzbench test and test for libxml (#893)

* Added representative fuzzbench test and test for libxml

* Added support for building FRIDA from source with FRIDA_SOURCE=1

Co-authored-by: Your Name <you@example.com>

* nits

* update changelog

* typos

* fixed potential double free in custom trim (#881)

* error handling, freeing mem

* frida: complog -> cmplog

* fix statsd writing

* let aflpp_qemu_driver_hook.so build fail gracefully

* fix stdin trimming

* Support for AFL_ENTRYPOINT (#898)

Co-authored-by: Your Name <you@example.com>

* remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used

* reverse push (#901)

* Create FUNDING.yml

* Update FUNDING.yml

* disable QEMU static pie

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>

* clarify that no modifications are required.

* add new test for frida_mode (please review)

* typos

* fix persistent mode (64-bit)

* set ARCH for linux intel 32-bit for frida-gum-devkit

* prepare for 32-bit support (later)

* not on qemu 3 anymore

* unicorn mips fixes

* instrumentation further move to C++11 (#900)

* unicorn fixes

* more unicorn fixes

* Fix memory errors when trim causes testcase growth (#881) (#903)

* Revert "fixed potential double free in custom trim (#881)"

This reverts commit e9d2f72382.

* Revert "fix custom trim for increasing data"

This reverts commit 86a8ef168d.

* Fix memory errors when trim causes testcase growth

Modify trim_case_custom to avoid writing into in_buf because
some custom mutators can cause the testcase to grow rather than
shrink.

Instead of modifying in_buf directly, we write the update out
to the disk when trimming is complete, and then the caller is
responsible for refreshing the in-memory buffer from the file.

This is still a bit sketchy because it does need to modify q->len in
order to notify the upper layers that something changed, and it could
end up telling upper layer code that the q->len is *bigger* than
the buffer (q->testcase_buf) that contains it, which is asking
for trouble down the line somewhere...

* Fix an unlikely situation

Put back some `unlikely()` calls that were in
the e9d2f72382 commit that was
reverted.

* typo

* Exit on time (#904)

* Variable AFL_EXIT_ON_TIME description has been added.
Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added.
afl->exit_on_time variable initialization has been added.
The asignment of a value to the afl->afl_env.afl_exit_on_time variable from
environment variables has been added.
Code to exit on timeout if new path not found has been added.

* Type of afl_exit_on_time variable has been changed.
Variable exit_on_time has been added to the afl_state_t structure.

* Command `export AFL_EXIT_WHEN_DONE=1` has been added.

* Millisecond to second conversion has been added.
Call get_cur_time() has been added.

* Revert to using the saved current time value.

* Useless check has been removed.

* fix new path to custom-mutators

* ensure crashes/README.txt exists

* fix

* Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906)

Co-authored-by: Your Name <you@example.com>

* Fix numeric overflow in cmplog implementation (#907)

Co-authored-by: Your Name <you@example.com>

* testcase fixes for unicorn

* remove merge conflict artifacts

* fix afl-plot

* Changes to remove binaries from frida_mode (#913)

Co-authored-by: Your Name <you@example.com>

* Frida cmplog fail fast (#914)

* Changes to remove binaries from frida_mode

* Changes to make cmplog fail fast

Co-authored-by: Your Name <you@example.com>

* afl-plot: relative time

* arch linux and mac os support for afl-system-config

* typo

* code-format

* update documentation

Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com>
Co-authored-by: Your Name <you@example.com>
Co-authored-by: Dmitry Zheregelya <zheregelya.d@gmail.com>
Co-authored-by: hexcoder <hexcoder-@users.noreply.github.com>
Co-authored-by: hexcoder- <heiko@hexco.de>
Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
Co-authored-by: David CARLIER <devnexen@gmail.com>
Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com>
Co-authored-by: Roman M. Iudichev <SecNotice@ya.ru>
This commit is contained in:
van Hauser
2021-05-10 13:57:47 +02:00
committed by GitHub
parent d0225c2c4d
commit 8b7a7b29c6
121 changed files with 4059 additions and 1091 deletions

View File

@ -91,9 +91,9 @@ behaviours and defaults:
| Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | frida_mode | qemu_mode |unicorn_mode | | Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | frida_mode | qemu_mode |unicorn_mode |
| -------------------------|:-------:|:---------:|:----------:|:----------:|:----------------:|:------------:| | -------------------------|:-------:|:---------:|:----------:|:----------:|:----------------:|:------------:|
| NeverZero | x86[_64]| x(1) | x | | x | x | | NeverZero | x86[_64]| x(1) | x | | x | x |
| Persistent Mode | | x | x | | x86[_64]/arm[64] | x | | Persistent Mode | | x | x | x | x86[_64]/arm[64] | x |
| LAF-Intel / CompCov | | x | | | x86[_64]/arm[64] | x86[_64]/arm | | LAF-Intel / CompCov | | x | | | x86[_64]/arm[64] | x86[_64]/arm |
| CmpLog | | x | | | x86[_64]/arm[64] | | | CmpLog | | x | | x | x86[_64]/arm[64] | |
| Selective Instrumentation| | x | x | x | x | | | Selective Instrumentation| | x | x | x | x | |
| Non-Colliding Coverage | | x(4) | | | (x)(5) | | | Non-Colliding Coverage | | x(4) | | | (x)(5) | |
| Ngram prev_loc Coverage | | x(6) | | | | | | Ngram prev_loc Coverage | | x(6) | | | | |

View File

@ -111,9 +111,9 @@ set terminal png truecolor enhanced size 1000,300 butt
set output '$outputdir/high_freq.png' set output '$outputdir/high_freq.png'
set xdata time #set xdata time
set timefmt '%s' #set timefmt '%s'
set format x "%b %d\n%H:%M" #set format x "%b %d\n%H:%M"
set tics font 'small' set tics font 'small'
unset mxtics unset mxtics
unset mytics unset mytics
@ -129,7 +129,6 @@ set autoscale xfixmax
set xlabel "all times in UTC" font "small" set xlabel "all times in UTC" font "small"
set ytics auto
plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' linecolor rgb '#000000' fillstyle transparent solid 0.2 noborder, \\ plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' linecolor rgb '#000000' fillstyle transparent solid 0.2 noborder, \\
'' using 1:3 with filledcurve x1 title 'current path' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\ '' using 1:3 with filledcurve x1 title 'current path' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\
'' using 1:5 with lines title 'pending paths' linecolor rgb '#0090ff' linewidth 3, \\ '' using 1:5 with lines title 'pending paths' linecolor rgb '#0090ff' linewidth 3, \\
@ -139,7 +138,6 @@ plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' lin
set terminal png truecolor enhanced size 1000,200 butt set terminal png truecolor enhanced size 1000,200 butt
set output '$outputdir/low_freq.png' set output '$outputdir/low_freq.png'
set ytics 1
plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb '#c00080' fillstyle transparent solid 0.2 noborder, \\ plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb '#c00080' fillstyle transparent solid 0.2 noborder, \\
'' using 1:8 with lines title ' uniq crashes' linecolor rgb '#c00080' linewidth 3, \\ '' using 1:8 with lines title ' uniq crashes' linecolor rgb '#c00080' linewidth 3, \\
'' using 1:9 with lines title 'uniq hangs' linecolor rgb '#c000f0' linewidth 3, \\ '' using 1:9 with lines title 'uniq hangs' linecolor rgb '#c000f0' linewidth 3, \\
@ -148,14 +146,12 @@ plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb
set terminal png truecolor enhanced size 1000,200 butt set terminal png truecolor enhanced size 1000,200 butt
set output '$outputdir/exec_speed.png' set output '$outputdir/exec_speed.png'
set ytics auto
plot '$inputdir/plot_data' using 1:11 with filledcurve x1 title '' linecolor rgb '#0090ff' fillstyle transparent solid 0.2 noborder, \\ plot '$inputdir/plot_data' using 1:11 with filledcurve x1 title '' linecolor rgb '#0090ff' fillstyle transparent solid 0.2 noborder, \\
'$inputdir/plot_data' using 1:11 with lines title ' execs/sec' linecolor rgb '#0090ff' linewidth 3 smooth bezier; '$inputdir/plot_data' using 1:11 with lines title ' execs/sec' linecolor rgb '#0090ff' linewidth 3 smooth bezier;
set terminal png truecolor enhanced size 1000,300 butt set terminal png truecolor enhanced size 1000,300 butt
set output '$outputdir/edges.png' set output '$outputdir/edges.png'
set ytics auto
plot '$inputdir/plot_data' using 1:13 with lines title ' edges' linecolor rgb '#0090ff' linewidth 3 plot '$inputdir/plot_data' using 1:13 with lines title ' edges' linecolor rgb '#0090ff' linewidth 3
_EOF_ _EOF_

View File

@ -22,7 +22,10 @@ if [ '!' "$EUID" = 0 ] && [ '!' `id -u` = 0 ] ; then
fi fi
if [ "$PLATFORM" = "Linux" ] ; then if [ "$PLATFORM" = "Linux" ] ; then
{ {
sysctl -w kernel.core_pattern=core sysctl -w kernel.core_uses_pid=0
# Arch Linux requires core_pattern to be empty :(
test -e /etc/arch-release && sysctl -w kernel.core_pattern=
test -e /etc/arch-release || sysctl -w kernel.core_pattern=core
sysctl -w kernel.randomize_va_space=0 sysctl -w kernel.randomize_va_space=0
sysctl -w kernel.sched_child_runs_first=1 sysctl -w kernel.sched_child_runs_first=1
sysctl -w kernel.sched_autogroup_enabled=1 sysctl -w kernel.sched_autogroup_enabled=1
@ -86,14 +89,15 @@ if [ "$PLATFORM" = "NetBSD" ] ; then
DONE=1 DONE=1
fi fi
if [ "$PLATFORM" = "Darwin" ] ; then if [ "$PLATFORM" = "Darwin" ] ; then
sysctl kern.sysv.shmmax=8388608
sysctl kern.sysv.shmseg=48
sysctl kern.sysv.shmall=98304
if [ $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ] ; then if [ $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ] ; then
echo We unload the default crash reporter here echo We unload the default crash reporter here
SL=/System/Library; PL=com.apple.ReportCrash SL=/System/Library; PL=com.apple.ReportCrash
launchctl unload -w ${SL}/LaunchAgents/${PL}.plist launchctl unload -w ${SL}/LaunchAgents/${PL}.plist
sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist
echo Settings applied. echo Settings applied.
else
echo Nothing to do.
fi fi
DONE=1 DONE=1
fi fi

View File

@ -3,6 +3,14 @@
Custom mutators enhance and alter the mutation strategies of afl++. Custom mutators enhance and alter the mutation strategies of afl++.
For further information and documentation on how to write your own, read [the docs](../docs/custom_mutators.md). For further information and documentation on how to write your own, read [the docs](../docs/custom_mutators.md).
## Examples
The `./examples` folder contains examples for custom mutators in python and C.
## Rust
In `./rust`, you will find rust bindings, including a simple example in `./rust/example` and an example for structured fuzzing, based on lain, in`./rust/example_lain`.
## The afl++ Grammar Mutator ## The afl++ Grammar Mutator
If you use git to clone afl++, then the following will incorporate our If you use git to clone afl++, then the following will incorporate our

View File

@ -1 +1 @@
a2d4e4a b79d51a

View File

@ -10,6 +10,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
### Version ++3.13a (development) ### Version ++3.13a (development)
- frida_mode - new mode that uses frida to fuzz binary-only targets, - frida_mode - new mode that uses frida to fuzz binary-only targets,
it currently supports persistent mode and cmplog.
thanks to @WorksButNotTested! thanks to @WorksButNotTested!
- create a fuzzing dictionary with the help of CodeQL thanks to - create a fuzzing dictionary with the help of CodeQL thanks to
@microsvuln! see utils/autodict_ql @microsvuln! see utils/autodict_ql
@ -19,6 +20,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- add recording of previous fuzz attempts for persistent mode - add recording of previous fuzz attempts for persistent mode
to allow replay of non-reproducable crashes, see to allow replay of non-reproducable crashes, see
AFL_PERSISTENT_RECORD in config.h and docs/envs.h AFL_PERSISTENT_RECORD in config.h and docs/envs.h
- fixed a bug when trimming for stdin targets
- default cmplog level (-l) is now 2, better efficiency. - default cmplog level (-l) is now 2, better efficiency.
- cmplog level 3 (-l 3) now performs redqueen on everything. - cmplog level 3 (-l 3) now performs redqueen on everything.
use with care. use with care.
@ -31,10 +33,20 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
afl++ ignores these and uses them for splicing instead. afl++ ignores these and uses them for splicing instead.
- afl-cc: - afl-cc:
- We do not support llvm versions prior 6.0 anymore - We do not support llvm versions prior 6.0 anymore
- Fix for -pie compiled binaries with default afl-clang-fast PCGUARD
- Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks!
- Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed InsTrim instrumentation as it is not as good as PCGUARD
- Removed automatic linking with -lc++ for LTO mode - Removed automatic linking with -lc++ for LTO mode
- utils/aflpp_driver/aflpp_qemu_driver_hook fixed to work with qemu mode - utils/aflpp_driver:
- aflpp_qemu_driver_hook fixed to work with qemu_mode
- aflpp_driver now compiled with -fPIC
- unicornafl:
- fix MIPS delay slot caching, thanks @JackGrence
- fixed aarch64 exit address
- execution no longer stops at address 0x0
- updated afl-system-config to support Arch Linux weirdness and increase
MacOS shared memory
- updated the grammar custom mutator to the newest version
- add -d (add dead fuzzer stats) to afl-whatsup - add -d (add dead fuzzer stats) to afl-whatsup
### Version ++3.12c (release) ### Version ++3.12c (release)

View File

@ -285,8 +285,8 @@ afl-fuzz /path/to/program
## 4) Example ## 4) Example
Please see [example.c](../utils/custom_mutators/example.c) and Please see [example.c](../custom_mutators/examples/example.c) and
[example.py](../utils/custom_mutators/example.py) [example.py](../custom_mutators/examples/example.py)
## 5) Other Resources ## 5) Other Resources

View File

@ -284,6 +284,10 @@ checks or alter some of the more exotic semantics of the tool:
normally indicated by the cycle counter in the UI turning green. May be normally indicated by the cycle counter in the UI turning green. May be
convenient for some types of automated jobs. convenient for some types of automated jobs.
- `AFL_EXIT_ON_TIME` Causes afl-fuzz to terminate if no new paths were
found within a specified period of time. May be convenient for some
types of automated jobs.
- `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behaviour - `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behaviour
which does not allow crashes or timeout seeds in the initial -i corpus. which does not allow crashes or timeout seeds in the initial -i corpus.

View File

@ -83,5 +83,5 @@ You can find a simple solution in utils/argv_fuzzing.
## Attacking a format that uses checksums? ## Attacking a format that uses checksums?
Remove the checksum-checking code or use a postprocessor! Remove the checksum-checking code or use a postprocessor!
See utils/custom_mutators/ for more. See `afl_custom_post_process` in custom_mutators/examples/example.c for more.

181
frida_mode/GNUmakefile Normal file
View File

@ -0,0 +1,181 @@
PWD:=$(shell pwd)/
ROOT:=$(shell realpath $(PWD)..)/
INC_DIR:=$(PWD)include/
SRC_DIR:=$(PWD)src/
INCLUDES:=$(wildcard $(INC_DIR)*.h)
BUILD_DIR:=$(PWD)build/
OBJ_DIR:=$(BUILD_DIR)obj/
SOURCES:=$(wildcard $(SRC_DIR)**/*.c) $(wildcard $(SRC_DIR)*.c)
OBJS:=$(foreach src,$(SOURCES),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src))))
CFLAGS+=-fPIC \
-D_GNU_SOURCE \
-D_FORTIFY_SOURCE=2 \
-g \
-O3 \
-funroll-loops \
RT_CFLAGS:=-Wno-unused-parameter \
-Wno-sign-compare \
-Wno-unused-function \
-Wno-unused-result \
LDFLAGS+=-shared \
-lpthread \
-lresolv \
-ldl \
ifdef DEBUG
CFLAGS+=-Werror \
-Wall \
-Wextra \
-Wpointer-arith
else
CFLAGS+=-Wno-pointer-arith
endif
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 "$(ARCH)" "i686"
ARCH:=x86
endif
ifeq "$(shell uname)" "Darwin"
OS:=macos
RT_CFLAGS:=$(RT_CFLAGS) -Wno-deprecated-declarations
else
ifdef DEBUG
RT_CFLAGS:=$(RT_CFLAGS) -Wno-prio-ctor-dtor
endif
endif
ifeq "$(shell uname)" "Linux"
OS:=linux
endif
ifndef OS
$(error "Operating system unsupported")
endif
GUM_DEVKIT_VERSION=14.2.18
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
FRIDA_DIR:=$(PWD)build/frida-source/
FRIDA_MAKEFILE:=$(FRIDA_DIR)Makefile
FRIDA_GUM:=$(FRIDA_DIR)build/frida-linux-x86_64/lib/libfrida-gum-1.0.a
FRIDA_GUM_DEVKIT_DIR:=$(FRIDA_DIR)build/gum-devkit/
FRIDA_GUM_DEVKIT_HEADER:=$(FRIDA_GUM_DEVKIT_DIR)frida-gum.h
FRIDA_GUM_DEVKIT_TARBALL:=$(FRIDA_DIR)build/frida-gum-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar
FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL:=$(FRIDA_DIR)build/$(GUM_DEVKIT_FILENAME)
AFL_COMPILER_RT_SRC:=$(ROOT)instrumentation/afl-compiler-rt.o.c
AFL_COMPILER_RT_OBJ:=$(OBJ_DIR)afl-compiler-rt.o
.PHONY: all clean format $(FRIDA_GUM)
############################## ALL #############################################
all: $(FRIDA_TRACE)
make -C $(ROOT)
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
$(OBJ_DIR): | $(BUILD_DIR)
mkdir -p $@
############################# FRIDA ############################################
$(FRIDA_MAKEFILE): | $(BUILD_DIR)
git clone --recursive https://github.com/frida/frida.git $(FRIDA_DIR)
$(FRIDA_GUM): $(FRIDA_MAKEFILE)
cd $(FRIDA_DIR) && make gum-linux-$(ARCH)
$(FRIDA_GUM_DEVKIT_HEADER): $(FRIDA_GUM)
$(FRIDA_DIR)releng/devkit.py frida-gum linux-$(ARCH) $(FRIDA_DIR)build/gum-devkit/
$(FRIDA_GUM_DEVKIT_TARBALL): $(FRIDA_GUM_DEVKIT_HEADER)
cd $(FRIDA_GUM_DEVKIT_DIR) && tar cvf $(FRIDA_GUM_DEVKIT_TARBALL) .
$(FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL): $(FRIDA_GUM_DEVKIT_TARBALL)
xz -k -f -0 $(FRIDA_GUM_DEVKIT_TARBALL)
############################# DEVKIT ###########################################
$(FRIDA_BUILD_DIR): | $(BUILD_DIR)
mkdir -p $@
ifdef FRIDA_SOURCE
$(GUM_DEVKIT_TARBALL): $(FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL)| $(FRIDA_BUILD_DIR)
cp -v $< $@
else
$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR)
wget -O $@ $(GUM_DEVKIT_URL)
endif
$(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)
############################## AFL #############################################
$(AFL_COMPILER_RT_OBJ): $(AFL_COMPILER_RT_SRC)
$(CC) \
$(CFLAGS) \
$(RT_CFLAGS) \
-I $(ROOT) \
-I $(ROOT)include \
-o $@ \
-c $<
############################# SOURCE ###########################################
define BUILD_SOURCE
$(2): $(1) $(INCLUDES) GNUmakefile | $(OBJ_DIR)
$(CC) \
$(CFLAGS) \
-I $(ROOT)include \
-I $(FRIDA_BUILD_DIR) \
-I $(INC_DIR) \
-c $1 \
-o $2
endef
$(foreach src,$(SOURCES),$(eval $(call BUILD_SOURCE,$(src),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src))))))
######################## AFL-FRIDA-TRACE #######################################
$(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(AFL_COMPILER_RT_OBJ) GNUmakefile | $(BUILD_DIR)
$(CC) \
-o $@ \
$(OBJS) \
$(GUM_DEVIT_LIBRARY) \
$(AFL_COMPILER_RT_OBJ) \
$(LDFLAGS) \
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 #############################################

View File

@ -1,348 +1,9 @@
PWD:=$(shell pwd)/ all:
INC_DIR:=$(PWD)include/ @echo trying to use GNU make...
SRC_DIR:=$(PWD)src/ @gmake all || echo please install GNUmake
INCLUDES:=$(wildcard $(INC_DIR)*.h)
SOURCES:=$(wildcard $(SRC_DIR)*.c)
BUILD_DIR:=$(PWD)build/
CFLAGS+=-fPIC -D_GNU_SOURCE
FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/
FRIDA_TRACE:=$(FRIDA_BUILD_DIR)afl-frida-trace.so
ARCH=$(shell uname -m)
ifeq "$(ARCH)" "aarch64"
ARCH:=arm64
TESTINSTR_BASE:=0x0000aaaaaaaaa000
endif
ifeq "$(ARCH)" "x86_64"
TESTINSTR_BASE:=0x0000555555554000
endif
ifeq "$(shell uname)" "Darwin"
OS:=macos
AFL_FRIDA_INST_RANGES=0x0000000000001000-0xFFFFFFFFFFFFFFFF
CFLAGS:=$(CFLAGS) -Wno-deprecated-declarations
TEST_LDFLAGS:=-undefined dynamic_lookup
endif
ifeq "$(shell uname)" "Linux"
OS:=linux
AFL_FRIDA_INST_RANGES=$(shell $(PWD)test/testinstr.py -f $(BUILD_DIR)testinstr -s .testinstr -b $(TESTINSTR_BASE))
CFLAGS:=$(CFLAGS) -Wno-prio-ctor-dtor
TEST_LDFLAGS:=
endif
ifndef OS
$(error "Operating system unsupported")
endif
VERSION=14.2.13
GUM_DEVKIT_FILENAME=frida-gum-devkit-$(VERSION)-$(OS)-$(ARCH).tar.xz
GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(VERSION)/$(GUM_DEVKIT_FILENAME)"
GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME)
GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gum.a
GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gum.h
TEST_BUILD_DIR:=$(BUILD_DIR)test/
LIBPNG_FILE:=$(TEST_BUILD_DIR)libpng-1.2.56.tar.gz
LIBPNG_URL:=https://downloads.sourceforge.net/project/libpng/libpng12/older-releases/1.2.56/libpng-1.2.56.tar.gz
LIBPNG_DIR:=$(TEST_BUILD_DIR)libpng-1.2.56/
LIBPNG_MAKEFILE:=$(LIBPNG_DIR)Makefile
LIBPNG_LIB:=$(LIBPNG_DIR).libs/libpng12.a
HARNESS_FILE:=$(TEST_BUILD_DIR)StandaloneFuzzTargetMain.c
HARNESS_OBJ:=$(TEST_BUILD_DIR)StandaloneFuzzTargetMain.o
HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c"
PNGTEST_FILE:=$(TEST_BUILD_DIR)target.cc
PNGTEST_OBJ:=$(TEST_BUILD_DIR)target.o
PNGTEST_URL:="https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/libpng-1.2.56/target.cc"
TEST_BIN:=$(TEST_BUILD_DIR)pngtest
TESTINSTBIN:=$(BUILD_DIR)testinstr
TESTINSTSRC:=$(PWD)test/testinstr.c
TEST_DATA_DIR:=$(PWD)build/test/libpng-1.2.56/contrib/pngsuite/
TESTINSTR_DATA_DIR:=$(BUILD_DIR)testinstr_in/
TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)test.dat
FRIDA_OUT:=$(PWD)frida_out
QEMU_OUT:=$(PWD)qemu_out
.PHONY: all frida test clean format test_frida test_qemu compare testinstr test_testinstr standalone
all: $(FRIDA_TRACE)
frida: $(FRIDA_TRACE)
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
############################# FRIDA ############################################
$(FRIDA_BUILD_DIR): | $(BUILD_DIR)
mkdir -p $@
$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR)
wget -O $@ $(GUM_DEVKIT_URL)
$(GUM_DEVIT_LIBRARY): | $(GUM_DEVKIT_TARBALL)
tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR)
$(GUM_DEVIT_HEADER): | $(GUM_DEVKIT_TARBALL)
tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR)
$(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(SOURCES) Makefile | $(FRIDA_BUILD_DIR)
$(CC) -shared \
$(CFLAGS) \
-o $@ $(SOURCES) \
$(GUM_DEVIT_LIBRARY) \
-I $(FRIDA_BUILD_DIR) \
-I .. \
-I ../include \
-I $(INC_DIR) \
../instrumentation/afl-compiler-rt.o.c \
-lpthread -ldl -lresolv
cp -v $(FRIDA_TRACE) ../
############################# TEST #############################################
test: $(TEST_BIN)
$(TEST_BUILD_DIR): $(BUILD_DIR)
mkdir -p $@
$(HARNESS_FILE): | $(TEST_BUILD_DIR)
wget -O $@ $(HARNESS_URL)
$(HARNESS_OBJ): $(HARNESS_FILE)
$(CC) -o $@ -c $<
$(PNGTEST_FILE): | $(TEST_BUILD_DIR)
wget -O $@ $(PNGTEST_URL)
$(PNGTEST_OBJ): $(PNGTEST_FILE) | $(LIBPNG_DIR)
$(CXX) -std=c++11 -I $(LIBPNG_DIR) -o $@ -c $<
$(LIBPNG_FILE): | $(TEST_BUILD_DIR)
wget -O $@ $(LIBPNG_URL)
$(LIBPNG_DIR): $(LIBPNG_FILE)
tar zxvf $(LIBPNG_FILE) -C $(TEST_BUILD_DIR)
$(LIBPNG_MAKEFILE): | $(LIBPNG_DIR)
cd $(LIBPNG_DIR) && ./configure
$(LIBPNG_LIB): $(LIBPNG_MAKEFILE)
make -C $(LIBPNG_DIR)
$(TEST_BIN): $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB)
$(CXX) \
-o $@ \
$(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) \
-lz \
$(TEST_LDFLAGS)
############################# TESTINSR #########################################
$(TESTINSTR_DATA_DIR): | $(BUILD_DIR)
mkdir -p $@
$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR)
echo -n "000" > $@
$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR)
$(CC) -o $@ $<
testinstr: $(TESTINSTBIN)
############################# CLEAN ############################################
clean: clean:
rm -rf $(BUILD_DIR) @gmake clean
############################# FORMAT ###########################################
format: format:
cd .. && echo $(SOURCES) | xargs -L1 ./.custom-format.py -i @gmake format
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) @@

View File

@ -1,34 +1,38 @@
# FRIDA MODE # FRIDA MODE
The purpose of FRIDA mode is to provide an alternative binary only fuzzer for AFL
just like that provided by QEMU mode. The intention is to provide a very similar The purpose of FRIDA mode is to provide an alternative binary only fuzzer for
user experience, right down to the options provided through environment variables. AFL just like that provided by QEMU mode. The intention is to provide a very
similar user experience, right down to the options provided through environment
variables.
Whilst AFLplusplus already has some support for running on FRIDA [here](https://github.com/AFLplusplus/AFLplusplus/tree/stable/utils/afl_frida) Whilst AFLplusplus already has some support for running on FRIDA [here](https://github.com/AFLplusplus/AFLplusplus/tree/stable/utils/afl_frida)
this requires the code to be fuzzed to be provided as a shared library, it this requires the code to be fuzzed to be provided as a shared library, it
cannot be used to fuzz executables. Additionally, it requires the user to write cannot be used to fuzz executables. Additionally, it requires the user to write
a small harness around their target code of interest, FRIDA mode instead takes a a small harness around their target code of interest.
different approach to avoid these limitations. FRIDA mode instead takes a different approach to avoid these limitations.
In Frida mode binary programs are instrumented, similarly to QEMU mode.
# Current Progress ## Current Progress
As FRIDA mode is new, it is missing a lot of features. Most importantly,
persistent mode. The design is such that it should be possible to add these
features in a similar manner to QEMU mode and perhaps leverage some of its
design and implementation.
| Feature/Instrumentation | frida-mode | 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
| NeverZero | | perhaps leverage some of its design and implementation.
| Persistent Mode | |
| LAF-Intel / CompCov | |
| CmpLog | |
| Selective Instrumentation| x |
| Non-Colliding Coverage | |
| Ngram prev_loc Coverage | |
| Context Coverage | |
| Auto Dictionary | |
| Snapshot LKM Support | |
# Compatibility | Feature/Instrumentation | frida-mode | Notes |
| -------------------------|:----------:|:---------------------------------------:|
| NeverZero | x | |
| Persistent Mode | x | (x64 only)(Only on function boundaries) |
| LAF-Intel / CompCov | - | (CMPLOG is better 90% of the time) |
| 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 Currently FRIDA mode supports Linux and macOS targets on both x86/x64
architecture and aarch64. Later releases may add support for aarch32 and Windows architecture and aarch64. Later releases may add support for aarch32 and Windows
targets as well as embedded linux environments. targets as well as embedded linux environments.
@ -38,54 +42,53 @@ runtime libraries, so porting should be possible. However, the current build
system does not support cross compilation. system does not support cross compilation.
## Getting Started ## Getting Started
To build everything run `make`. To build everything run `make`.
To run the benchmark sample with qemu run `make png_qemu`. Various tests can be found in subfolders within the `test/` directory. To use
To run the benchmark sample with frida run `make png_frida`. 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 ## Usage
FRIDA mode requires some small modifications to `afl-fuzz` and similar tools
in AFLplusplus. The intention is that it behaves identically to QEMU, but uses FRIDA mode added some small modifications to `afl-fuzz` and similar tools
in AFLplusplus. The intention was that it behaves identically to QEMU, but it uses
the 'O' switch rather than 'Q'. Whilst the options 'f', 'F', 's' or 'S' may have the 'O' switch rather than 'Q'. Whilst the options 'f', 'F', 's' or 'S' may have
made more sense for a mode powered by FRIDA Stalker, they were all taken, so made more sense for a mode powered by FRIDA Stalker, they were all taken, so
instead we use 'O' in hommage to the [author](https://github.com/oleavr) of instead we use 'O' in hommage to the [author](https://github.com/oleavr) of
FRIDA. FRIDA.
Similarly, the intention is to mimic the use of environment variables used by Similarly, the intention is to mimic the use of environment variables used by
QEMU where possible (although replacing `s/QEMU/FRIDA/g`). Accodingly, the QEMU where possible (by replacing `s/QEMU/FRIDA/g`). Accordingly, the
following options are currently supported. following options are currently supported:
* `AFL_FRIDA_DEBUG_MAPS` - See `AFL_QEMU_DEBUG_MAPS` * `AFL_FRIDA_DEBUG_MAPS` - See `AFL_QEMU_DEBUG_MAPS`
* `AFL_FRIDA_EXCLUDE_RANGES` - See `AFL_QEMU_EXCLUDE_RANGES` * `AFL_FRIDA_EXCLUDE_RANGES` - See `AFL_QEMU_EXCLUDE_RANGES`
* `AFL_FRIDA_INST_RANGES` - See `AFL_QEMU_INST_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 To enable the powerful CMPLOG mechanism, set `-c 0` for `afl-fuzz`.
## Performance
Additionally, the intention is to be able to make a direct performance Additionally, the intention is to be able to make a direct performance
comparison between the two approaches. Accordingly, FRIDA mode includes a test comparison between the two approaches. Accordingly, FRIDA mode includes various
target based on the [libpng](https://libpng.sourceforge.io/) benchmark used by test targets based on the [libpng](https://libpng.sourceforge.io/) benchmark
[fuzzbench](https://google.github.io/fuzzbench/) and integrated with the 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) [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 from the llvm project. These tests include basic fork-server support, persistent
modifications to suit FRIDA or QEMU. We use the test data provided with libpng mode and persistent mode with in-memory test-cases. These are built and linked
as our corpus. 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 The intention is to add support for FRIDA mode to the FuzzBench project and
around 30-50% of that of QEMU mode, however, this gap may reduce with the perform a like-for-like comparison with QEMU mode to get an accurate
introduction of persistent mode. Performance can be tested by running appreciation of its performance.
`make compare`, albeit a longer time measurement may be required for more
accurate results.
Whilst [afl_frida](https://github.com/AFLplusplus/AFLplusplus/tree/stable/utils/afl_frida) ## Design
claims a 5-10x performance increase over QEMU, it has not been possible to
reproduce these claims. However, the number of executions per second can vary
dramatically as a result of the randomization of the fuzzer input. Some inputs
may traverse relatively few paths before being rejected as invalid whilst others
may be valid inputs or be subject to much more processing before rejection.
Accordingly, it is recommended that testing be carried out over prolongued
periods to gather timings which are more than indicative.
# Design
FRIDA mode is supported by using `LD_PRELOAD` (`DYLD_INSERT_LIBRARIES` on macOS) FRIDA mode is supported by using `LD_PRELOAD` (`DYLD_INSERT_LIBRARIES` on macOS)
to inject a shared library (`afl-frida-trace.so`) into the target. This shared to inject a shared library (`afl-frida-trace.so`) into the target. This shared
library is built using the [frida-gum](https://github.com/frida/frida-gum) library is built using the [frida-gum](https://github.com/frida/frida-gum)
@ -102,34 +105,34 @@ 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) 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 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 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 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 code, FRIDA mode instead makes use of optimized assembly instead on AARCH64 and
mode instead makes use of optimized assembly instead on AARCH64 and x86/64 x86/64 targets. By injecting these small snippets of assembly, we avoid having
targets. 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.
CMPLOG 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 CMPLOG 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
# Advanced configuration options
* `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage * `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage
instrumentation (the default where available). Required to use instrumentation (the default where available). Required to use
`AFL_FRIDA_INST_TRACE`. `AFL_FRIDA_INST_TRACE`.
* `AFL_FRIDA_INST_NO_PREFETCH` - Disable prefetching. By default the child will * `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 report instrumented blocks back to the parent so that it can also instrument
them and they be inherited by the next child on fork. 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. * `AFL_FRIDA_INST_TRACE` - Generate some logging when running instrumented code.
Requires `AFL_FRIDA_INST_NO_OPTIMIZE`. Requires `AFL_FRIDA_INST_NO_OPTIMIZE`.
# TODO ## 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 next features to be added are x86 support, integration with FuzzBench and
The intention is to achieve feature parity with QEMU mode in due course. support for ASAN. The intention is to achieve feature parity with QEMU mode in
Contributions are welcome, but please get in touch to ensure that efforts are due course. Contributions are welcome, but please get in touch to ensure that
deconflicted. efforts are deconflicted.

View File

@ -0,0 +1,15 @@
#ifndef _ENTRY_H
#define _ENTRY_H
#include "frida-gum.h"
extern guint64 entry_start;
void entry_init(void);
void entry_run(void);
void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output);
#endif

View File

@ -0,0 +1,14 @@
#ifndef _CMPLOG_H
#define _CMPLOG_H
extern struct cmp_map *__afl_cmp_map;
void cmplog_init(void);
/* Functions to be implemented by the different architectures */
void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator);
gboolean cmplog_is_readable(void *addr, size_t size);
#endif

View File

@ -1,7 +1,23 @@
#ifndef _INSTRUMENT_H
#define _INSTRUMENT_H
#include "frida-gum.h" #include "frida-gum.h"
void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, #include "config.h"
gpointer user_data);
void instrument_init(); extern __thread uint64_t 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);
#endif

View File

@ -1,4 +1,11 @@
#ifndef _INTERCEPTOR_H
#define _INTERCEPTOR_H
#include "frida-gum.h" #include "frida-gum.h"
void intercept(void *address, gpointer replacement, gpointer user_data); void intercept(void *address, gpointer replacement, gpointer user_data);
void unintercept(void *address);
void unintercept_self(void);
#endif

13
frida_mode/include/lib.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef _LIB_H
#define _LIB_H
#include "frida-gum.h"
void lib_init(void);
guint64 lib_get_text_base(void);
guint64 lib_get_text_limit(void);
#endif

View File

@ -0,0 +1,31 @@
#ifndef _PERSISTENT_H
#define _PERSISTENT_H
#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;
extern guint64 persistent_start;
extern guint64 persistent_count;
extern 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);
#endif

View File

@ -1,5 +1,11 @@
void prefetch_init(); #ifndef _PREFETCH_H
void prefetch_start(GumStalker *stalker); #define _PREFETCH_H
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);
#endif

View File

@ -1,6 +1,11 @@
#ifndef _RANGES_H
#define _RANGES_H
#include "frida-gum.h" #include "frida-gum.h"
void ranges_init(GumStalker *stalker); void ranges_init(void);
gboolean range_is_excluded(gpointer address); gboolean range_is_excluded(gpointer address);
#endif

View File

@ -0,0 +1,11 @@
#ifndef _STALKER_H
#define _STALKER_H
#include "frida-gum.h"
void stalker_init(void);
GumStalker *stalker_get(void);
void stalker_start(void);
#endif

14
frida_mode/include/util.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef _UTIL_H
#define _UTIL_H
#include "frida-gum.h"
#define UNUSED_PARAMETER(x) (void)(x)
#define IGNORED_RERURN(x) (void)!(x)
guint64 util_read_address(char *key);
guint64 util_read_num(char *key);
#endif

View File

@ -0,0 +1,87 @@
#include "frida-gum.h"
#include "debug.h"
#include "util.h"
#define DEFAULT_MMAP_MIN_ADDR (32UL << 10)
extern struct cmp_map *__afl_cmp_map;
static GArray *cmplog_ranges = NULL;
static gboolean cmplog_range(const GumRangeDetails *details,
gpointer user_data) {
UNUSED_PARAMETER(user_data);
GumMemoryRange range = *details->range;
g_array_append_val(cmplog_ranges, range);
return TRUE;
}
static gint cmplog_sort(gconstpointer a, gconstpointer b) {
return ((GumMemoryRange *)b)->base_address -
((GumMemoryRange *)a)->base_address;
}
void cmplog_init(void) {
if (__afl_cmp_map != NULL) { OKF("CMPLOG mode enabled"); }
cmplog_ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), 100);
gum_process_enumerate_ranges(GUM_PAGE_READ, cmplog_range, NULL);
g_array_sort(cmplog_ranges, cmplog_sort);
for (guint i = 0; i < cmplog_ranges->len; i++) {
GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i);
OKF("CMPLOG Range - 0x%016" G_GINT64_MODIFIER "X - 0x%016" G_GINT64_MODIFIER
"X",
range->base_address, range->base_address + range->size);
}
}
static gboolean cmplog_contains(GumAddress inner_base, GumAddress inner_limit,
GumAddress outer_base, GumAddress outer_limit) {
return (inner_base >= outer_base && inner_limit <= outer_limit);
}
gboolean cmplog_is_readable(void *addr, size_t size) {
if (cmplog_ranges == NULL) FATAL("CMPLOG not initialized");
/*
* The Linux kernel prevents mmap from allocating from the very bottom of the
* address space to mitigate NULL pointer dereference attacks. The exact size
* is set by sysctl by setting mmap_min_addr and 64k is suggested on most
* platforms with 32k on ARM systems. We therefore fail fast if the address
* is lower than this. This should avoid some overhead when functions are
* called where one of the parameters is a size, or a some other small value.
*/
if (GPOINTER_TO_SIZE(addr) < DEFAULT_MMAP_MIN_ADDR) { return false; }
GumAddress inner_base = GUM_ADDRESS(addr);
GumAddress inner_limit = inner_base + size;
for (guint i = 0; i < cmplog_ranges->len; i++) {
GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i);
GumAddress outer_base = range->base_address;
GumAddress outer_limit = outer_base + range->size;
if (cmplog_contains(inner_base, inner_limit, outer_base, outer_limit))
return true;
}
return false;
}

View File

@ -0,0 +1,19 @@
#include "frida-gum.h"
#include "debug.h"
#include "frida_cmplog.h"
#include "util.h"
#if defined(__arm__)
void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
UNUSED_PARAMETER(instr);
UNUSED_PARAMETER(iterator);
if (__afl_cmp_map == NULL) { return; }
FATAL("CMPLOG mode not supported on this architecture");
}
#endif

View File

@ -0,0 +1,19 @@
#include "frida-gum.h"
#include "debug.h"
#include "frida_cmplog.h"
#include "util.h"
#if defined(__aarch64__)
void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
UNUSED_PARAMETER(instr);
UNUSED_PARAMETER(iterator);
if (__afl_cmp_map == NULL) { return; }
FATAL("CMPLOG mode not supported on this architecture");
}
#endif

View File

@ -0,0 +1,346 @@
#include "frida-gum.h"
#include "debug.h"
#include "cmplog.h"
#include "frida_cmplog.h"
#include "util.h"
#if defined(__x86_64__)
#define X86_REG_8L(LABEL, REG) \
case LABEL: { \
\
return REG & GUM_INT8_MASK; \
\
}
#define X86_REG_8H(LABEL, REG) \
case LABEL: { \
\
return (REG & GUM_INT16_MASK) >> 8; \
\
}
#define X86_REG_16(LABEL, REG) \
case LABEL: { \
\
return (REG & GUM_INT16_MASK); \
\
}
#define X86_REG_32(LABEL, REG) \
case LABEL: { \
\
return (REG & GUM_INT32_MASK); \
\
}
#define X86_REG_64(LABEL, REG) \
case LABEL: { \
\
return (REG); \
\
}
typedef struct {
x86_op_type type;
uint8_t size;
union {
x86_op_mem mem;
x86_reg reg;
int64_t imm;
};
} cmplog_ctx_t;
typedef struct {
cmplog_ctx_t operand1;
cmplog_ctx_t operand2;
} cmplog_pair_ctx_t;
static guint64 cmplog_read_reg(GumX64CpuContext *ctx, x86_reg reg) {
switch (reg) {
X86_REG_8L(X86_REG_AL, ctx->rax)
X86_REG_8L(X86_REG_BL, ctx->rbx)
X86_REG_8L(X86_REG_CL, ctx->rcx)
X86_REG_8L(X86_REG_DL, ctx->rdx)
X86_REG_8L(X86_REG_BPL, ctx->rbp)
X86_REG_8L(X86_REG_SIL, ctx->rsi)
X86_REG_8L(X86_REG_DIL, ctx->rdi)
X86_REG_8H(X86_REG_AH, ctx->rax)
X86_REG_8H(X86_REG_BH, ctx->rbx)
X86_REG_8H(X86_REG_CH, ctx->rcx)
X86_REG_8H(X86_REG_DH, ctx->rdx)
X86_REG_16(X86_REG_AX, ctx->rax)
X86_REG_16(X86_REG_BX, ctx->rbx)
X86_REG_16(X86_REG_CX, ctx->rcx)
X86_REG_16(X86_REG_DX, ctx->rdx)
X86_REG_16(X86_REG_DI, ctx->rdi)
X86_REG_16(X86_REG_SI, ctx->rsi)
X86_REG_16(X86_REG_BP, ctx->rbp)
X86_REG_32(X86_REG_EAX, ctx->rax)
X86_REG_32(X86_REG_ECX, ctx->rcx)
X86_REG_32(X86_REG_EDX, ctx->rdx)
X86_REG_32(X86_REG_EBX, ctx->rbx)
X86_REG_32(X86_REG_ESP, ctx->rsp)
X86_REG_32(X86_REG_EBP, ctx->rbp)
X86_REG_32(X86_REG_ESI, ctx->rsi)
X86_REG_32(X86_REG_EDI, ctx->rdi)
X86_REG_32(X86_REG_R8D, ctx->r8)
X86_REG_32(X86_REG_R9D, ctx->r9)
X86_REG_32(X86_REG_R10D, ctx->r10)
X86_REG_32(X86_REG_R11D, ctx->r11)
X86_REG_32(X86_REG_R12D, ctx->r12)
X86_REG_32(X86_REG_R13D, ctx->r13)
X86_REG_32(X86_REG_R14D, ctx->r14)
X86_REG_32(X86_REG_R15D, ctx->r15)
X86_REG_32(X86_REG_EIP, ctx->rip)
X86_REG_64(X86_REG_RAX, ctx->rax)
X86_REG_64(X86_REG_RCX, ctx->rcx)
X86_REG_64(X86_REG_RDX, ctx->rdx)
X86_REG_64(X86_REG_RBX, ctx->rbx)
X86_REG_64(X86_REG_RSP, ctx->rsp)
X86_REG_64(X86_REG_RBP, ctx->rbp)
X86_REG_64(X86_REG_RSI, ctx->rsi)
X86_REG_64(X86_REG_RDI, ctx->rdi)
X86_REG_64(X86_REG_R8, ctx->r8)
X86_REG_64(X86_REG_R9, ctx->r9)
X86_REG_64(X86_REG_R10, ctx->r10)
X86_REG_64(X86_REG_R11, ctx->r11)
X86_REG_64(X86_REG_R12, ctx->r12)
X86_REG_64(X86_REG_R13, ctx->r13)
X86_REG_64(X86_REG_R14, ctx->r14)
X86_REG_64(X86_REG_R15, ctx->r15)
X86_REG_64(X86_REG_RIP, ctx->rip)
default:
FATAL("Failed to read register: %d", reg);
return 0;
}
}
static guint64 cmplog_read_mem(GumX64CpuContext *ctx, x86_op_mem *mem) {
guint64 base = 0;
guint64 index = 0;
guint64 address;
if (mem->base != X86_REG_INVALID) base = cmplog_read_reg(ctx, mem->base);
if (mem->index != X86_REG_INVALID) index = cmplog_read_reg(ctx, mem->index);
address = base + (index * mem->scale) + mem->disp;
return address;
}
static guint64 cmplog_get_operand_value(GumCpuContext *context,
cmplog_ctx_t * ctx) {
switch (ctx->type) {
case X86_OP_REG:
return cmplog_read_reg(context, ctx->reg);
case X86_OP_IMM:
return ctx->imm;
case X86_OP_MEM:
return cmplog_read_mem(context, &ctx->mem);
default:
FATAL("Invalid operand type: %d\n", ctx->type);
}
}
static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) {
UNUSED_PARAMETER(user_data);
guint64 address = cmplog_read_reg(context, X86_REG_RIP);
guint64 rdi = cmplog_read_reg(context, X86_REG_RDI);
guint64 rsi = cmplog_read_reg(context, X86_REG_RSI);
if (((G_MAXULONG - rdi) < 32) || ((G_MAXULONG - rsi) < 32)) return;
void *ptr1 = GSIZE_TO_POINTER(rdi);
void *ptr2 = GSIZE_TO_POINTER(rsi);
if (!cmplog_is_readable(ptr1, 32) || !cmplog_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 void cmplog_instrument_put_operand(cmplog_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 cmplog_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;
gum_stalker_iterator_put_callout(iterator, cmplog_call_callout, NULL, NULL);
}
static void cmplog_handle_cmp_sub(GumCpuContext *context, guint64 operand1,
guint64 operand2, uint8_t size) {
guint64 address = cmplog_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 cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) {
cmplog_pair_ctx_t *ctx = (cmplog_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);
cmplog_handle_cmp_sub(context, operand1, operand2, ctx->operand1.size);
}
static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator,
cs_x86_op * operand1,
cs_x86_op *operand2) {
cmplog_pair_ctx_t *ctx = g_malloc(sizeof(cmplog_pair_ctx_t));
if (ctx == NULL) return;
cmplog_instrument_put_operand(&ctx->operand1, operand1);
cmplog_instrument_put_operand(&ctx->operand2, operand2);
gum_stalker_iterator_put_callout(iterator, cmplog_cmp_sub_callout, ctx,
g_free);
}
static void cmplog_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;
cmplog_instrument_cmp_sub_put_callout(iterator, operand1, operand2);
}
void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
if (__afl_cmp_map == NULL) return;
cmplog_instrument_call(instr, iterator);
cmplog_instrument_cmp_sub(instr, iterator);
}
#endif

View File

@ -0,0 +1,19 @@
#include "frida-gum.h"
#include "debug.h"
#include "frida_cmplog.h"
#include "util.h"
#if defined(__i386__)
void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
UNUSED_PARAMETER(instr);
UNUSED_PARAMETER(iterator);
if (__afl_cmp_map == NULL) { return; }
FATAL("CMPLOG mode not supported on this architecture");
}
#endif

50
frida_mode/src/entry.c Normal file
View File

@ -0,0 +1,50 @@
#include "frida-gum.h"
#include "debug.h"
#include "entry.h"
#include "instrument.h"
#include "stalker.h"
#include "util.h"
extern void __afl_manual_init();
guint64 entry_start = 0;
static void entry_launch(void) {
__afl_manual_init();
/* Child here */
previous_pc = 0;
}
void entry_init(void) {
entry_start = util_read_address("AFL_ENTRYPOINT");
OKF("entry_point: 0x%016" G_GINT64_MODIFIER "X", entry_start);
}
void entry_run(void) {
if (entry_start == 0) { entry_launch(); }
}
static void entry_callout(GumCpuContext *cpu_context, gpointer user_data) {
UNUSED_PARAMETER(cpu_context);
UNUSED_PARAMETER(user_data);
entry_launch();
}
void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output) {
UNUSED_PARAMETER(output);
gum_stalker_iterator_put_callout(iterator, entry_callout, NULL, NULL);
}

View File

@ -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);
}
}

View File

@ -0,0 +1,155 @@
#include <unistd.h>
#include "frida-gum.h"
#include "config.h"
#include "debug.h"
#include "entry.h"
#include "frida_cmplog.h"
#include "instrument.h"
#include "persistent.h"
#include "prefetch.h"
#include "ranges.h"
#include "stalker.h"
#include "util.h"
static gboolean tracing = false;
static gboolean optimize = false;
static GumStalkerTransformer *transformer = NULL;
__thread uint64_t previous_pc = 0;
__attribute__((hot)) static void on_basic_block(GumCpuContext *context,
gpointer user_data) {
UNUSED_PARAMETER(context);
/*
* 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);
IGNORED_RERURN(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) {
UNUSED_PARAMETER(user_data);
const cs_insn *instr;
gboolean begin = TRUE;
while (gum_stalker_iterator_next(iterator, &instr)) {
if (instr->address == entry_start) { entry_prologue(iterator, output); }
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)) {
cmplog_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);
cmplog_init();
}
GumStalkerTransformer *instrument_get_transformer(void) {
if (transformer == NULL) { FATAL("Instrumentation not initialized"); }
return transformer;
}

View 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

View 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

View 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

View 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

View File

@ -1,4 +1,5 @@
#include "frida-gum.h" #include "frida-gum.h"
#include "debug.h" #include "debug.h"
#include "interceptor.h" #include "interceptor.h"
@ -9,8 +10,26 @@ void intercept(void *address, gpointer replacement, gpointer user_data) {
gum_interceptor_begin_transaction(interceptor); gum_interceptor_begin_transaction(interceptor);
GumReplaceReturn ret = GumReplaceReturn ret =
gum_interceptor_replace(interceptor, address, replacement, user_data); gum_interceptor_replace(interceptor, address, replacement, user_data);
if (ret != GUM_ATTACH_OK) { FATAL("gum_interceptor_attach: %d", ret); } if (ret != GUM_REPLACE_OK) { FATAL("gum_interceptor_attach: %d", ret); }
gum_interceptor_end_transaction(interceptor); gum_interceptor_end_transaction(interceptor);
} }
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);
}

176
frida_mode/src/lib/lib.c Normal file
View File

@ -0,0 +1,176 @@
#ifndef __APPLE__
#include <elf.h>
#include <fcntl.h>
#include <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;
typedef Elf32_Addr Elf_Addr;
#elif defined(__aarch64__) || defined(__x86_64__)
#define ELFCLASS ELFCLASS64
typedef Elf64_Ehdr Elf_Ehdr;
typedef Elf64_Phdr Elf_Phdr;
typedef Elf64_Shdr Elf_Shdr;
typedef Elf64_Addr Elf_Addr;
#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 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");
}
static void lib_read_text_section(lib_details_t *lib_details, Elf_Ehdr *hdr) {
Elf_Phdr *phdr;
gboolean found_preferred_base = FALSE;
Elf_Addr preferred_base;
Elf_Shdr *shdr;
Elf_Shdr *shstrtab;
char * shstr;
char * section_name;
Elf_Shdr *curr;
char text_name[] = ".text";
phdr = (Elf_Phdr *)((char *)hdr + hdr->e_phoff);
for (size_t i = 0; i < hdr->e_phnum; i++) {
if (phdr[i].p_type == PT_LOAD) {
preferred_base = phdr[i].p_vaddr;
found_preferred_base = TRUE;
break;
}
}
if (!found_preferred_base) { FATAL("Failed to find preferred load address"); }
OKF("Image preferred load address 0x%016lx", preferred_base);
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 - preferred_base;
text_limit = text_base + 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", 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;
}
#endif

View File

@ -0,0 +1,82 @@
#ifdef __APPLE__
#include "frida-gum.h"
#include "debug.h"
#include "lib.h"
#include "util.h"
extern mach_port_t mach_task_self();
extern void gum_darwin_enumerate_modules(mach_port_t task,
GumFoundModuleFunc func,
gpointer user_data);
static guint64 text_base = 0;
static guint64 text_limit = 0;
static gboolean lib_get_main_module(const GumModuleDetails *details,
gpointer user_data) {
GumDarwinModule **ret = (GumDarwinModule **)user_data;
GumDarwinModule * module = gum_darwin_module_new_from_memory(
details->path, mach_task_self(), details->range->base_address,
GUM_DARWIN_MODULE_FLAGS_NONE, NULL);
OKF("Found main module: %s", module->name);
*ret = module;
return FALSE;
}
gboolean lib_get_text_section(const GumDarwinSectionDetails *details,
gpointer user_data) {
UNUSED_PARAMETER(user_data);
static size_t idx = 0;
char text_name[] = "__text";
OKF("Section: %2lu - base: 0x%016" G_GINT64_MODIFIER
"X size: 0x%016" G_GINT64_MODIFIER "X %s",
idx++, details->vm_address, details->vm_address + details->size,
details->section_name);
if (memcmp(details->section_name, text_name, sizeof(text_name)) == 0 &&
text_base == 0) {
text_base = details->vm_address;
text_limit = details->vm_address + details->size;
OKF("> text_addr: 0x%016" G_GINT64_MODIFIER "X", text_base);
OKF("> text_limit: 0x%016" G_GINT64_MODIFIER "X", text_limit);
}
return TRUE;
}
void lib_init(void) {
GumDarwinModule *module = NULL;
gum_darwin_enumerate_modules(mach_task_self(), lib_get_main_module, &module);
gum_darwin_module_enumerate_sections(module, lib_get_text_section, NULL);
}
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;
}
#endif

View File

@ -10,13 +10,19 @@
#endif #endif
#include "frida-gum.h" #include "frida-gum.h"
#include "config.h" #include "config.h"
#include "debug.h" #include "debug.h"
#include "interceptor.h" #include "entry.h"
#include "instrument.h" #include "instrument.h"
#include "interceptor.h"
#include "lib.h"
#include "persistent.h"
#include "prefetch.h" #include "prefetch.h"
#include "ranges.h" #include "ranges.h"
#include "stalker.h"
#include "util.h"
#ifdef __APPLE__ #ifdef __APPLE__
extern mach_port_t mach_task_self(); extern mach_port_t mach_task_self();
@ -30,16 +36,11 @@ extern int __libc_start_main(int *(main)(int, char **, char **), int argc,
typedef int *(*main_fn_t)(int argc, char **argv, char **envp); typedef int *(*main_fn_t)(int argc, char **argv, char **envp);
static main_fn_t main_fn = NULL; static main_fn_t main_fn = NULL;
static GumStalker * stalker = NULL;
static GumMemoryRange code_range = {0};
extern void __afl_manual_init(); static int on_fork(void) {
extern __thread uint64_t previous_pc;
static int on_fork() { prefetch_read();
prefetch_read(stalker);
return fork(); return fork();
} }
@ -47,11 +48,17 @@ static int on_fork() {
#ifdef __APPLE__ #ifdef __APPLE__
static void on_main_os(int argc, char **argv, char **envp) { static void on_main_os(int argc, char **argv, char **envp) {
UNUSED_PARAMETER(argc);
UNUSED_PARAMETER(argv);
UNUSED_PARAMETER(envp);
} }
#else #else
static void on_main_os(int argc, char **argv, char **envp) { static void on_main_os(int argc, char **argv, char **envp) {
UNUSED_PARAMETER(argc);
/* Personality doesn't affect the current process, it only takes effect on /* Personality doesn't affect the current process, it only takes effect on
* evec */ * evec */
int persona = personality(ADDR_NO_RANDOMIZE); int persona = personality(ADDR_NO_RANDOMIZE);
@ -70,37 +77,43 @@ static void on_main_os(int argc, char **argv, char **envp) {
static int *on_main(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); on_main_os(argc, argv, envp);
stalker = gum_stalker_new(); unintercept_self();
if (stalker == NULL) { FATAL("Failed to initialize stalker"); }
gum_stalker_set_trust_threshold(stalker, 0); stalker_init();
GumStalkerTransformer *transformer =
gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL);
lib_init();
entry_init();
instrument_init(); instrument_init();
persistent_init();
prefetch_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); stalker_start();
gum_stalker_deactivate(stalker); entry_run();
__afl_manual_init(); return main_fn(argc, argv, envp);
/* Child here */
previous_pc = 0;
prefetch_start(stalker);
main_fn(argc, argv, envp);
_exit(0);
} }
#ifdef __APPLE__ #if defined(EMBEDDED)
static void intercept_main() { 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(); mach_port_t task = mach_task_self();
OKF("Task Id: %u", task); OKF("Task Id: %u", task);
@ -119,13 +132,14 @@ static int on_libc_start_main(int *(main)(int, char **, char **), int argc,
void(*stack_end)) { void(*stack_end)) {
main_fn = main; main_fn = main;
unintercept_self();
intercept(main, on_main, NULL); intercept(main, on_main, NULL);
return __libc_start_main(main, argc, ubp_av, init, fini, rtld_fini, return __libc_start_main(main, argc, ubp_av, init, fini, rtld_fini,
stack_end); stack_end);
} }
static void intercept_main() { static void intercept_main(void) {
intercept(__libc_start_main, on_libc_start_main, NULL); intercept(__libc_start_main, on_libc_start_main, NULL);
@ -133,7 +147,7 @@ static void intercept_main() {
#endif #endif
__attribute__((constructor)) static void init() { __attribute__((constructor)) static void init(void) {
gum_init_embedded(); gum_init_embedded();
if (!gum_stalker_is_supported()) { if (!gum_stalker_is_supported()) {

View File

@ -0,0 +1,65 @@
#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_start != 0 && !persistent_is_supported())
FATAL("Persistent mode not supported on this architecture");
OKF("Instrumentation - persistent mode [%c] (0x%016" G_GINT64_MODIFIER "X)",
persistent_start == 0 ? ' ' : 'X', persistent_start);
OKF("Instrumentation - persistent count [%c] (%" G_GINT64_MODIFIER "d)",
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;
}
}

View File

@ -0,0 +1,72 @@
#include "frida-gum.h"
#include "debug.h"
#include "persistent.h"
#include "util.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) {
UNUSED_PARAMETER(output);
FATAL("Persistent mode not supported on this architecture");
}
#endif

View File

@ -0,0 +1,115 @@
#include "frida-gum.h"
#include "config.h"
#include "debug.h"
#include "instrument.h"
#include "util.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) {
UNUSED_PARAMETER(output);
FATAL("Persistent mode not supported on this architecture");
}
#endif

View File

@ -0,0 +1,342 @@
#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 void 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_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_mov_reg_address(cw, GUM_REG_RDX,
GUM_ADDRESS(&__afl_fuzz_ptr));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RDX, 0);
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_REGISTER,
GUM_REG_RDX, 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

View File

@ -0,0 +1,55 @@
#include "frida-gum.h"
#include "debug.h"
#include "persistent.h"
#include "util.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) {
UNUSED_PARAMETER(output);
FATAL("Persistent mode not supported on this architecture");
}
#endif

View File

@ -3,9 +3,12 @@
#include <sys/mman.h> #include <sys/mman.h>
#include "frida-gum.h" #include "frida-gum.h"
#include "prefetch.h"
#include "debug.h" #include "debug.h"
#include "prefetch.h"
#include "stalker.h"
#define TRUST 0 #define TRUST 0
#define PREFETCH_SIZE 65536 #define PREFETCH_SIZE 65536
#define PREFETCH_ENTRIES ((PREFETCH_SIZE - sizeof(size_t)) / sizeof(void *)) #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 * 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; if (prefetch_data == NULL) return;
for (size_t i = 0; i < prefetch_data->count; i++) { 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); g_assert_cmpint(sizeof(prefetch_data_t), ==, PREFETCH_SIZE);
gboolean prefetch = (getenv("AFL_FRIDA_INST_NO_PREFETCH") == NULL); 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();
}

View File

@ -1,9 +1,12 @@
// 0x123-0x321 #include "frida-gum.h"
// module.so
#include "ranges.h"
#include "debug.h" #include "debug.h"
#include "lib.h"
#include "ranges.h"
#include "stalker.h"
#include "util.h"
#define MAX_RANGES 20 #define MAX_RANGES 20
typedef struct { typedef struct {
@ -14,15 +17,11 @@ typedef struct {
} convert_name_ctx_t; } convert_name_ctx_t;
typedef struct { GArray *module_ranges = NULL;
GArray *libs_ranges = NULL;
GumStalker *stalker; GArray *include_ranges = NULL;
GArray * array; GArray *exclude_ranges = NULL;
GArray *ranges = NULL;
} include_range_ctx_t;
GArray * ranges = NULL;
gboolean exclude_ranges = false;
static void convert_address_token(gchar *token, GumMemoryRange *range) { static void convert_address_token(gchar *token, GumMemoryRange *range) {
@ -159,90 +158,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) { gint range_sort(gconstpointer a, gconstpointer b) {
return ((GumMemoryRange *)a)->base_address - return ((GumMemoryRange *)a)->base_address -
@ -250,9 +165,10 @@ gint range_sort(gconstpointer a, gconstpointer b) {
} }
static gboolean print_ranges(const GumRangeDetails *details, static gboolean print_ranges_callback(const GumRangeDetails *details,
gpointer user_data) { gpointer user_data) {
UNUSED_PARAMETER(user_data);
if (details->file == NULL) { if (details->file == NULL) {
OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER "X", OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER "X",
@ -273,62 +189,75 @@ static gboolean print_ranges(const GumRangeDetails *details,
} }
void ranges_init(GumStalker *stalker) { static void print_ranges(char *key, GArray *ranges) {
char * showmaps; OKF("Range: %s Length: %d", key, ranges->len);
char * include; for (guint i = 0; i < ranges->len; i++) {
char * exclude;
char * list; 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; gchar ** tokens;
int token_count; int token_count;
GumMemoryRange range; GumMemoryRange range;
int i;
GArray * result;
int i; result = g_array_new(false, false, sizeof(GumMemoryRange));
showmaps = getenv("AFL_FRIDA_DEBUG_MAPS"); env_val = getenv(env_key);
include = getenv("AFL_FRIDA_INST_RANGES"); if (env_val == NULL) return result;
exclude = getenv("AFL_FRIDA_EXCLUDE_RANGES");
if (showmaps) { tokens = g_strsplit(env_val, ",", MAX_RANGES);
gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges, NULL);
}
if (include != NULL && exclude != NULL) {
FATAL(
"Cannot specifify both AFL_FRIDA_INST_RANGES and "
"AFL_FRIDA_EXCLUDE_RANGES");
}
if (include == NULL && exclude == NULL) { return; }
list = include == NULL ? exclude : include;
exclude_ranges = include == NULL ? true : false;
tokens = g_strsplit(list, ",", MAX_RANGES);
for (token_count = 0; tokens[token_count] != NULL; token_count++) 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++) { for (i = 0; i < token_count; i++) {
convert_token(tokens[i], &range); 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 */ /* Check for overlaps */
for (i = 1; i < token_count; i++) { for (i = 1; i < token_count; i++) {
GumMemoryRange *prev = &g_array_index(ranges, GumMemoryRange, i - 1); GumMemoryRange *prev = &g_array_index(result, GumMemoryRange, i - 1);
GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); GumMemoryRange *curr = &g_array_index(result, GumMemoryRange, i);
GumAddress prev_limit = prev->base_address + prev->size; GumAddress prev_limit = prev->base_address + prev->size;
GumAddress curr_limit = curr->base_address + curr->size; GumAddress curr_limit = curr->base_address + curr->size;
if (prev_limit > curr->base_address) { if (prev_limit > curr->base_address) {
@ -342,53 +271,304 @@ 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); g_strfreev(tokens);
GumAddress curr_limit = curr->base_address + curr->size;
OKF("Range %3d - 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER "x",
i, curr->base_address, curr_limit);
} return result;
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 { } else {
include_range_ctx_t ctx = {.stalker = stalker, .array = ranges}; range.base_address = 0;
gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, include_ranges, &ctx); 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 (guint i = 0; i < a->len; i++) {
ra = &g_array_index(a, GumMemoryRange, i);
for (guint 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 (guint i = 0; i < a->len; i++) {
ra = &g_array_index(a, GumMemoryRange, i);
ral = ra->base_address + ra->size;
for (guint 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 (guint 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 (guint 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);
} }
gboolean range_is_excluded(gpointer address) { gboolean range_is_excluded(gpointer address) {
int i;
GumAddress test = GUM_ADDRESS(address); GumAddress test = GUM_ADDRESS(address);
if (ranges == NULL) { return false; } if (ranges == NULL) { return false; }
for (i = 0; i < ranges->len; i++) { for (guint i = 0; i < ranges->len; i++) {
GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i);
GumAddress curr_limit = curr->base_address + curr->size; 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;
} }

30
frida_mode/src/stalker.c Normal file
View File

@ -0,0 +1,30 @@
#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;
}
void stalker_start(void) {
GumStalkerTransformer *transformer = instrument_get_transformer();
gum_stalker_follow_me(stalker, transformer, NULL);
}

67
frida_mode/src/util.c Normal file
View File

@ -0,0 +1,67 @@
#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);
}
char *value_str2 = &value_str[2];
for (char *c = value_str2; *c != '\0'; c++) {
if (!g_ascii_isxdigit(*c)) {
FATAL("Invalid address not formed of hex digits: %s ('%c')\n", value_str,
*c);
}
}
guint64 value = g_ascii_strtoull(value_str2, NULL, 16);
if (value == 0) {
FATAL("Invalid address failed hex conversion: %s\n", value_str2);
}
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;
}

View 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)

View 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

View File

@ -0,0 +1,61 @@
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
GET_SYMBOL_ADDR:=$(ROOT)frida_mode/test/png/persistent/get_symbol_addr.py
ARCH=$(shell uname -m)
ifeq "$(ARCH)" "aarch64"
AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000aaaaaaaaa000)
endif
ifeq "$(ARCH)" "x86_64"
AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000555555554000)
endif
.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)
frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
$(ROOT)afl-fuzz \
-D \
-O \
-i $(TESTINSTR_DATA_DIR) \
-o $(FRIDA_OUT) \
-- \
$(TESTINSTBIN) @@
frida_entry: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
AFL_ENTRYPOINT=$(AFL_ENTRYPOINT) \
$(ROOT)afl-fuzz \
-D \
-O \
-i $(TESTINSTR_DATA_DIR) \
-o $(FRIDA_OUT) \
-- \
$(TESTINSTBIN) @@

View File

@ -0,0 +1,12 @@
all:
@echo trying to use GNU make...
@gmake all || echo please install GNUmake
clean:
@gmake clean
frida:
@gmake frida
frida_entry:
@gmake frida

View File

@ -0,0 +1,119 @@
/*
american fuzzy lop++ - a trivial program to test the build
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
*/
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef __APPLE__
#define TESTINSTR_SECTION
#else
#define TESTINSTR_SECTION __attribute__((section(".testinstr")))
#endif
void testinstr(char *buf, int len) {
if (len < 1) return;
buf[len] = 0;
// we support three input cases
if (buf[0] == '0')
printf("Looks like a zero to me!\n");
else if (buf[0] == '1')
printf("Pretty sure that is a one!\n");
else
printf("Neither one or zero? How quaint!\n");
}
int run(char *file) {
int fd = -1;
off_t len;
char * buf = NULL;
size_t n_read;
int result = -1;
do {
dprintf(STDERR_FILENO, "Running: %s\n", file);
fd = open(file, O_RDONLY);
if (fd < 0) {
perror("open");
break;
}
len = lseek(fd, 0, SEEK_END);
if (len < 0) {
perror("lseek (SEEK_END)");
break;
}
if (lseek(fd, 0, SEEK_SET) != 0) {
perror("lseek (SEEK_SET)");
break;
}
buf = malloc(len);
if (buf == NULL) {
perror("malloc");
break;
}
n_read = read(fd, buf, len);
if (n_read != len) {
perror("read");
break;
}
dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read);
testinstr(buf, len);
dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read);
result = 0;
} while (false);
if (buf != NULL) { free(buf); }
if (fd != -1) { close(fd); }
return result;
}
void slow() {
usleep(100000);
}
int main(int argc, char **argv) {
if (argc != 2) { return 1; }
slow();
return run(argv[1]);
}

View 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 $@ $< -no-pie
clean:
rm -rf $(BUILD_DIR)
qemu: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
$(ROOT)afl-fuzz \
-D \
-Q \
-i $(TESTINSTR_DATA_DIR) \
-o $(QEMU_OUT) \
-- \
$(TESTINSTBIN) @@
frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
$(ROOT)afl-fuzz \
-D \
-O \
-i $(TESTINSTR_DATA_DIR) \
-o $(FRIDA_OUT) \
-- \
$(TESTINSTBIN) @@

View 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

View File

@ -22,7 +22,7 @@
#define TESTINSTR_SECTION __attribute__((section(".testinstr"))) #define TESTINSTR_SECTION __attribute__((section(".testinstr")))
#endif #endif
TESTINSTR_SECTION void testinstr(char *buf, int len) { void testinstr(char *buf, int len) {
if (len < 1) return; if (len < 1) return;
buf[len] = 0; 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; char * file;
int fd = -1; int fd = -1;

View File

@ -0,0 +1,109 @@
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
ifeq "$(shell uname)" "Darwin"
TEST_BIN_LDFLAGS:=-undefined dynamic_lookup
endif
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_BIN_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) @@

View 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

View File

@ -0,0 +1,79 @@
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 qemu_entry frida frida_entry
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) @@
qemu_entry: | $(BUILD_DIR)
AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \
AFL_QEMU_PERSISTENT_GPR=1 \
AFL_ENTRYPOINT=$(AFL_QEMU_PERSISTENT_ADDR) \
$(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) @@
frida_entry: | $(BUILD_DIR)
AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
AFL_ENTRYPOINT=$(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)

View File

@ -0,0 +1,18 @@
all:
@echo trying to use GNU make...
@gmake all || echo please install GNUmake
clean:
@gmake clean
qemu:
@gmake qemu
qemu_entry:
@gmake qemu_entry
frida:
@gmake frida
frida_entry:
@gmake frida_entry

View 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)

View File

@ -0,0 +1,98 @@
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 qemu_entry frida frida_entry
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)
qemu_entry: $(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_ENTRYPOINT=$(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)
frida_entry: $(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) \
AFL_ENTRYPOINT=$(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)

View File

@ -0,0 +1,18 @@
all:
@echo trying to use GNU make...
@gmake all || echo please install GNUmake
clean:
@gmake clean
qemu:
@gmake qemu
qemu_entry:
@gmake qemu_entry
frida:
@gmake frida
frida_entry:
@gmake frida_entry

View 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: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
$(ROOT)afl-fuzz \
-D \
-O \
-i $(TESTINSTR_DATA_DIR) \
-o $(FRIDA_OUT) \
-- \
$(TESTINSTBIN) @@

View 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

View File

@ -0,0 +1,112 @@
/*
american fuzzy lop++ - a trivial program to test the build
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
*/
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef __APPLE__
#define TESTINSTR_SECTION
#else
#define TESTINSTR_SECTION __attribute__((section(".testinstr")))
#endif
void testinstr(char *buf, int len) {
if (len < 1) return;
buf[len] = 0;
// we support three input cases
if (buf[0] == '0')
printf("Looks like a zero to me!\n");
else if (buf[0] == '1')
printf("Pretty sure that is a one!\n");
else
printf("Neither one or zero? How quaint!\n");
}
TESTINSTR_SECTION int main(int argc, char **argv) {
char * file;
int fd = -1;
off_t len;
char * buf = NULL;
size_t n_read;
int result = -1;
if (argc != 2) { return 1; }
do {
file = argv[1];
dprintf(STDERR_FILENO, "Running: %s\n", file);
fd = open(file, O_RDONLY);
if (fd < 0) {
perror("open");
break;
}
len = lseek(fd, 0, SEEK_END);
if (len < 0) {
perror("lseek (SEEK_END)");
break;
}
if (lseek(fd, 0, SEEK_SET) != 0) {
perror("lseek (SEEK_SET)");
break;
}
buf = malloc(len);
if (buf == NULL) {
perror("malloc");
break;
}
n_read = read(fd, buf, len);
if (n_read != len) {
perror("read");
break;
}
dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read);
testinstr(buf, len);
dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read);
result = 0;
} while (false);
if (buf != NULL) { free(buf); }
if (fd != -1) { close(fd); }
return result;
}

View File

@ -0,0 +1,13 @@
#!/bin/sh
test -n "$1" && { echo This script has no options. It updates the referenced Frida version in GNUmakefile to the most current one. ; exit 1 ; }
OLD=$(egrep '^GUM_DEVKIT_VERSION=' GNUmakefile 2>/dev/null|awk -F= '{print$2}')
NEW=$(curl https://github.com/frida/frida/releases/ 2>/dev/null|egrep 'frida-gum-devkit-[0-9.]*-linux-x86_64'|head -n 1|sed 's/.*frida-gum-devkit-//'|sed 's/-linux.*//')
echo Current set version: $OLD
echo Newest available version: $NEW
test -z "$OLD" -o -z "$NEW" -o "$OLD" = "$NEW" && { echo Nothing to be done. ; exit 0 ; }
sed -i "s/=$OLD/=$NEW/" GNUmakefile || exit 1
echo Successfully updated GNUmakefile

View File

@ -392,7 +392,7 @@ typedef struct afl_env_vars {
*afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port,
*afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size,
*afl_testcache_entries, *afl_kill_signal, *afl_target_env, *afl_testcache_entries, *afl_kill_signal, *afl_target_env,
*afl_persistent_record; *afl_persistent_record, *afl_exit_on_time;
} afl_env_vars_t; } afl_env_vars_t;
@ -575,7 +575,8 @@ typedef struct afl_state {
last_sync_cycle, /* Cycle no. of the last sync */ last_sync_cycle, /* Cycle no. of the last sync */
last_path_time, /* Time for most recent path (ms) */ last_path_time, /* Time for most recent path (ms) */
last_crash_time, /* Time for most recent crash (ms) */ last_crash_time, /* Time for most recent crash (ms) */
last_hang_time; /* Time for most recent hang (ms) */ last_hang_time, /* Time for most recent hang (ms) */
exit_on_time; /* Delay to exit if no new paths */
u32 slowest_exec_ms, /* Slowest testcase non hang in ms */ u32 slowest_exec_ms, /* Slowest testcase non hang in ms */
subseq_tmouts; /* Number of timeouts in a row */ subseq_tmouts; /* Number of timeouts in a row */
@ -1134,6 +1135,7 @@ void check_if_tty(afl_state_t *);
void setup_signal_handlers(void); void setup_signal_handlers(void);
void save_cmdline(afl_state_t *, u32, char **); void save_cmdline(afl_state_t *, u32, char **);
void read_foreign_testcases(afl_state_t *, int); void read_foreign_testcases(afl_state_t *, int);
void write_crash_readme(afl_state_t *afl);
/* CmpLog */ /* CmpLog */

View File

@ -49,6 +49,7 @@ static char *afl_environment_variables[] = {
"AFL_DUMB_FORKSRV", "AFL_DUMB_FORKSRV",
"AFL_ENTRYPOINT", "AFL_ENTRYPOINT",
"AFL_EXIT_WHEN_DONE", "AFL_EXIT_WHEN_DONE",
"AFL_EXIT_ON_TIME",
"AFL_EXIT_ON_SEED_ISSUES", "AFL_EXIT_ON_SEED_ISSUES",
"AFL_FAST_CAL", "AFL_FAST_CAL",
"AFL_FORCE_UI", "AFL_FORCE_UI",
@ -59,6 +60,9 @@ static char *afl_environment_variables[] = {
"AFL_FRIDA_INST_RANGES", "AFL_FRIDA_INST_RANGES",
"AFL_FRIDA_INST_STRICT", "AFL_FRIDA_INST_STRICT",
"AFL_FRIDA_INST_TRACE", "AFL_FRIDA_INST_TRACE",
"AFL_FRIDA_PERSISTENT_ADDR",
"AFL_FRIDA_PERSISTENT_CNT",
"AFL_FRIDA_PERSISTENT_HOOK",
"AFL_FUZZER_ARGS", // oss-fuzz "AFL_FUZZER_ARGS", // oss-fuzz
"AFL_GDB", "AFL_GDB",
"AFL_GCC_ALLOWLIST", "AFL_GCC_ALLOWLIST",

View File

@ -2,7 +2,7 @@
(See [../README.md](../README.md) for the general instruction manual.) (See [../README.md](../README.md) for the general instruction manual.)
(See [README.gcc_plugon.md](../README.gcc_plugin.md) for the GCC-based instrumentation.) (See [README.gcc_plugin.md](../README.gcc_plugin.md) for the GCC-based instrumentation.)
## 1) Introduction ## 1) Introduction

View File

@ -60,15 +60,14 @@ using namespace llvm;
#define DEBUG_TYPE "sancov" #define DEBUG_TYPE "sancov"
static const char *const SanCovTracePCIndirName = const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir";
"__sanitizer_cov_trace_pc_indir"; const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc";
static const char *const SanCovTracePCName = "__sanitizer_cov_trace_pc"; // const char SanCovTracePCGuardName =
// static const char *const SanCovTracePCGuardName =
// "__sanitizer_cov_trace_pc_guard"; // "__sanitizer_cov_trace_pc_guard";
static const char *const SanCovGuardsSectionName = "sancov_guards"; const char SanCovGuardsSectionName[] = "sancov_guards";
static const char *const SanCovCountersSectionName = "sancov_cntrs"; const char SanCovCountersSectionName[] = "sancov_cntrs";
static const char *const SanCovBoolFlagSectionName = "sancov_bools"; const char SanCovBoolFlagSectionName[] = "sancov_bools";
static const char *const SanCovPCsSectionName = "sancov_pcs"; const char SanCovPCsSectionName[] = "sancov_pcs";
static cl::opt<int> ClCoverageLevel( static cl::opt<int> ClCoverageLevel(
"lto-coverage-level", "lto-coverage-level",

View File

@ -52,49 +52,39 @@ using namespace llvm;
#define DEBUG_TYPE "sancov" #define DEBUG_TYPE "sancov"
static const char *const SanCovTracePCIndirName = const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir";
"__sanitizer_cov_trace_pc_indir"; const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc";
static const char *const SanCovTracePCName = "__sanitizer_cov_trace_pc"; const char SanCovTraceCmp1[] = "__sanitizer_cov_trace_cmp1";
static const char *const SanCovTraceCmp1 = "__sanitizer_cov_trace_cmp1"; const char SanCovTraceCmp2[] = "__sanitizer_cov_trace_cmp2";
static const char *const SanCovTraceCmp2 = "__sanitizer_cov_trace_cmp2"; const char SanCovTraceCmp4[] = "__sanitizer_cov_trace_cmp4";
static const char *const SanCovTraceCmp4 = "__sanitizer_cov_trace_cmp4"; const char SanCovTraceCmp8[] = "__sanitizer_cov_trace_cmp8";
static const char *const SanCovTraceCmp8 = "__sanitizer_cov_trace_cmp8"; const char SanCovTraceConstCmp1[] = "__sanitizer_cov_trace_const_cmp1";
static const char *const SanCovTraceConstCmp1 = const char SanCovTraceConstCmp2[] = "__sanitizer_cov_trace_const_cmp2";
"__sanitizer_cov_trace_const_cmp1"; const char SanCovTraceConstCmp4[] = "__sanitizer_cov_trace_const_cmp4";
static const char *const SanCovTraceConstCmp2 = const char SanCovTraceConstCmp8[] = "__sanitizer_cov_trace_const_cmp8";
"__sanitizer_cov_trace_const_cmp2"; const char SanCovTraceDiv4[] = "__sanitizer_cov_trace_div4";
static const char *const SanCovTraceConstCmp4 = const char SanCovTraceDiv8[] = "__sanitizer_cov_trace_div8";
"__sanitizer_cov_trace_const_cmp4"; const char SanCovTraceGep[] = "__sanitizer_cov_trace_gep";
static const char *const SanCovTraceConstCmp8 = const char SanCovTraceSwitchName[] = "__sanitizer_cov_trace_switch";
"__sanitizer_cov_trace_const_cmp8"; const char SanCovModuleCtorTracePcGuardName[] =
static const char *const SanCovTraceDiv4 = "__sanitizer_cov_trace_div4";
static const char *const SanCovTraceDiv8 = "__sanitizer_cov_trace_div8";
static const char *const SanCovTraceGep = "__sanitizer_cov_trace_gep";
static const char *const SanCovTraceSwitchName = "__sanitizer_cov_trace_switch";
static const char *const SanCovModuleCtorTracePcGuardName =
"sancov.module_ctor_trace_pc_guard"; "sancov.module_ctor_trace_pc_guard";
static const char *const SanCovModuleCtor8bitCountersName = const char SanCovModuleCtor8bitCountersName[] =
"sancov.module_ctor_8bit_counters"; "sancov.module_ctor_8bit_counters";
static const char *const SanCovModuleCtorBoolFlagName = const char SanCovModuleCtorBoolFlagName[] = "sancov.module_ctor_bool_flag";
"sancov.module_ctor_bool_flag";
static const uint64_t SanCtorAndDtorPriority = 2; static const uint64_t SanCtorAndDtorPriority = 2;
static const char *const SanCovTracePCGuardName = const char SanCovTracePCGuardName[] = "__sanitizer_cov_trace_pc_guard";
"__sanitizer_cov_trace_pc_guard"; const char SanCovTracePCGuardInitName[] = "__sanitizer_cov_trace_pc_guard_init";
static const char *const SanCovTracePCGuardInitName = const char SanCov8bitCountersInitName[] = "__sanitizer_cov_8bit_counters_init";
"__sanitizer_cov_trace_pc_guard_init"; const char SanCovBoolFlagInitName[] = "__sanitizer_cov_bool_flag_init";
static const char *const SanCov8bitCountersInitName = const char SanCovPCsInitName[] = "__sanitizer_cov_pcs_init";
"__sanitizer_cov_8bit_counters_init";
static const char *const SanCovBoolFlagInitName =
"__sanitizer_cov_bool_flag_init";
static const char *const SanCovPCsInitName = "__sanitizer_cov_pcs_init";
static const char *const SanCovGuardsSectionName = "sancov_guards"; const char SanCovGuardsSectionName[] = "sancov_guards";
static const char *const SanCovCountersSectionName = "sancov_cntrs"; const char SanCovCountersSectionName[] = "sancov_cntrs";
static const char *const SanCovBoolFlagSectionName = "sancov_bools"; const char SanCovBoolFlagSectionName[] = "sancov_bools";
static const char *const SanCovPCsSectionName = "sancov_pcs"; const char SanCovPCsSectionName[] = "sancov_pcs";
static const char *const SanCovLowestStackName = "__sancov_lowest_stack"; const char SanCovLowestStackName[] = "__sancov_lowest_stack";
static char *skip_nozero; static char *skip_nozero;
@ -320,12 +310,12 @@ std::pair<Value *, Value *> ModuleSanitizerCoverage::CreateSecStartEnd(
Module &M, const char *Section, Type *Ty) { Module &M, const char *Section, Type *Ty) {
GlobalVariable *SecStart = new GlobalVariable( GlobalVariable *SecStart = new GlobalVariable(
M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage, M, Ty->getPointerElementType(), false,
nullptr, getSectionStart(Section)); GlobalVariable::ExternalWeakLinkage, nullptr, getSectionStart(Section));
SecStart->setVisibility(GlobalValue::HiddenVisibility); SecStart->setVisibility(GlobalValue::HiddenVisibility);
GlobalVariable *SecEnd = new GlobalVariable( GlobalVariable *SecEnd = new GlobalVariable(
M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage, M, Ty->getPointerElementType(), false,
nullptr, getSectionEnd(Section)); GlobalVariable::ExternalWeakLinkage, nullptr, getSectionEnd(Section));
SecEnd->setVisibility(GlobalValue::HiddenVisibility); SecEnd->setVisibility(GlobalValue::HiddenVisibility);
IRBuilder<> IRB(M.getContext()); IRBuilder<> IRB(M.getContext());
if (!TargetTriple.isOSBinFormatCOFF()) if (!TargetTriple.isOSBinFormatCOFF())
@ -573,7 +563,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
} }
// True if block has successors and it dominates all of them. // True if block has successors and it dominates all of them.
static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) { bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) {
if (succ_begin(BB) == succ_end(BB)) return false; if (succ_begin(BB) == succ_end(BB)) return false;
@ -588,8 +578,7 @@ static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) {
} }
// True if block has predecessors and it postdominates all of them. // True if block has predecessors and it postdominates all of them.
static bool isFullPostDominator(const BasicBlock * BB, bool isFullPostDominator(const BasicBlock *BB, const PostDominatorTree *PDT) {
const PostDominatorTree *PDT) {
if (pred_begin(BB) == pred_end(BB)) return false; if (pred_begin(BB) == pred_end(BB)) return false;
@ -603,10 +592,10 @@ static bool isFullPostDominator(const BasicBlock * BB,
} }
static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
const DominatorTree * DT, const DominatorTree * DT,
const PostDominatorTree * PDT, const PostDominatorTree * PDT,
const SanitizerCoverageOptions &Options) { const SanitizerCoverageOptions &Options) {
// Don't insert coverage for blocks containing nothing but unreachable: we // Don't insert coverage for blocks containing nothing but unreachable: we
// will never call __sanitizer_cov() for them, so counting them in // will never call __sanitizer_cov() for them, so counting them in
@ -636,8 +625,7 @@ static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
// A twist here is that we treat From->To as a backedge if // A twist here is that we treat From->To as a backedge if
// * To dominates From or // * To dominates From or
// * To->UniqueSuccessor dominates From // * To->UniqueSuccessor dominates From
static bool IsBackEdge(BasicBlock *From, BasicBlock *To, bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT) {
const DominatorTree *DT) {
if (DT->dominates(To, From)) return true; if (DT->dominates(To, From)) return true;
if (auto Next = To->getUniqueSuccessor()) if (auto Next = To->getUniqueSuccessor())
@ -651,8 +639,8 @@ static bool IsBackEdge(BasicBlock *From, BasicBlock *To,
// //
// Note that Cmp pruning is controlled by the same flag as the // Note that Cmp pruning is controlled by the same flag as the
// BB pruning. // BB pruning.
static bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT, bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT,
const SanitizerCoverageOptions &Options) { const SanitizerCoverageOptions &Options) {
if (!Options.NoPrune) if (!Options.NoPrune)
if (CMP->hasOneUse()) if (CMP->hasOneUse())
@ -1046,7 +1034,7 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB,
if (IsEntryBB) { if (IsEntryBB) {
// Keep static allocas and llvm.localescape calls in the entry block. Even // Keep allocas and llvm.localescape calls in the entry block. Even
// if we aren't splitting the block, it's nice for allocas to be before // if we aren't splitting the block, it's nice for allocas to be before
// calls. // calls.
IP = PrepareToSplitEntryBlock(BB, IP); IP = PrepareToSplitEntryBlock(BB, IP);
@ -1221,17 +1209,17 @@ ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass(
} }
static void registerPCGUARDPass(const PassManagerBuilder &, void registerPCGUARDPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) { legacy::PassManagerBase &PM) {
auto p = new ModuleSanitizerCoverageLegacyPass(); auto p = new ModuleSanitizerCoverageLegacyPass();
PM.add(p); PM.add(p);
} }
static RegisterStandardPasses RegisterCompTransPass( RegisterStandardPasses RegisterCompTransPass(
PassManagerBuilder::EP_OptimizerLast, registerPCGUARDPass); PassManagerBuilder::EP_OptimizerLast, registerPCGUARDPass);
static RegisterStandardPasses RegisterCompTransPass0( RegisterStandardPasses RegisterCompTransPass0(
PassManagerBuilder::EP_EnabledOnOptLevel0, registerPCGUARDPass); PassManagerBuilder::EP_EnabledOnOptLevel0, registerPCGUARDPass);

View File

@ -79,8 +79,9 @@
#endif #endif
#if defined(__HAIKU__) #if defined(__HAIKU__)
extern ssize_t _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize); extern ssize_t _kern_write(int fd, off_t pos, const void *buffer,
#endif // HAIKU size_t bufferSize);
#endif // HAIKU
u8 __afl_area_initial[MAP_INITIAL_SIZE]; u8 __afl_area_initial[MAP_INITIAL_SIZE];
u8 * __afl_area_ptr_dummy = __afl_area_initial; 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; } if (unlikely(!ptr || __asan_region_is_poisoned(ptr, len))) { return 0; }
#ifndef __HAIKU__ #ifndef __HAIKU__
long r = syscall(SYS_write, __afl_dummy_fd[1], ptr, len); long r = syscall(SYS_write, __afl_dummy_fd[1], ptr, len);
#else #else
long r = _kern_write(__afl_dummy_fd[1], -1, ptr, len); long r = _kern_write(__afl_dummy_fd[1], -1, ptr, len);
#endif // HAIKU #endif // HAIKU
if (r <= 0 || r > len) return 0; if (r <= 0 || r > len) return 0;

View File

@ -177,7 +177,7 @@ int plugin_is_GPL_compatible = 1;
namespace { namespace {
static const struct pass_data afl_pass_data = { static constexpr struct pass_data afl_pass_data = {
.type = GIMPLE_PASS, .type = GIMPLE_PASS,
.name = "afl", .name = "afl",
@ -503,7 +503,7 @@ struct afl_pass : gimple_opt_pass {
// Starting from "LLVMFuzzer" these are functions used in libfuzzer based // Starting from "LLVMFuzzer" these are functions used in libfuzzer based
// fuzzing campaign installations, e.g. oss-fuzz // fuzzing campaign installations, e.g. oss-fuzz
static const char *ignoreList[] = { static constexpr const char *ignoreList[] = {
"asan.", "asan.",
"llvm.", "llvm.",

View File

@ -55,7 +55,7 @@ bool isIgnoreFunction(const llvm::Function *F) {
// Starting from "LLVMFuzzer" these are functions used in libfuzzer based // Starting from "LLVMFuzzer" these are functions used in libfuzzer based
// fuzzing campaign installations, e.g. oss-fuzz // fuzzing campaign installations, e.g. oss-fuzz
static const char *ignoreList[] = { static constexpr const char *ignoreList[] = {
"asan.", "asan.",
"llvm.", "llvm.",
@ -94,7 +94,7 @@ bool isIgnoreFunction(const llvm::Function *F) {
} }
static const char *ignoreSubstringList[] = { static constexpr const char *ignoreSubstringList[] = {
"__asan", "__msan", "__ubsan", "__lsan", "__asan", "__msan", "__ubsan", "__lsan",
"__san", "__sanitize", "__cxx", "_GLOBAL__", "__san", "__sanitize", "__cxx", "_GLOBAL__",

View File

@ -89,11 +89,11 @@ class AFLLTOPass : public ModulePass {
bool runOnModule(Module &M) override; bool runOnModule(Module &M) override;
protected: protected:
uint32_t afl_global_id = 1, autodictionary = 1; uint32_t afl_global_id = 1, autodictionary = 1;
uint32_t function_minimum_size = 1; uint32_t function_minimum_size = 1;
uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0; uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0;
unsigned long long int map_addr = 0x10000; unsigned long long int map_addr = 0x10000;
char * skip_nozero = NULL; char * skip_nozero = NULL;
}; };

View File

@ -89,7 +89,7 @@ class SplitSwitchesTransform : public ModulePass {
}; };
typedef std::vector<CaseExpr> CaseVector; using CaseVector = std::vector<CaseExpr>;
private: private:
bool splitSwitches(Module &M); bool splitSwitches(Module &M);

View File

@ -190,8 +190,8 @@ handlers of the target.
## 13) Gotchas, feedback, bugs ## 13) Gotchas, feedback, bugs
If you need to fix up checksums or do other cleanup on mutated test cases, see If you need to fix up checksums or do other cleanups on mutated test cases, see
utils/custom_mutators/ for a viable solution. `afl_custom_post_process` in custom_mutators/examples/example.c for a viable solution.
Do not mix QEMU mode with ASAN, MSAN, or the likes; QEMU doesn't appreciate Do not mix QEMU mode with ASAN, MSAN, or the likes; QEMU doesn't appreciate
the "shadow VM" trick employed by the sanitizers and will probably just the "shadow VM" trick employed by the sanitizers and will probably just

View File

@ -9,7 +9,7 @@
# TCG instrumentation and block chaining support by Andrea Biondo # TCG instrumentation and block chaining support by Andrea Biondo
# <andrea.biondo965@gmail.com> # <andrea.biondo965@gmail.com>
# #
# QEMU 3.1.1 port, TCG thread-safety, CompareCoverage and NeverZero # QEMU 5+ port, TCG thread-safety, CompareCoverage and NeverZero
# counters by Andrea Fioraldi <andreafioraldi@gmail.com> # counters by Andrea Fioraldi <andreafioraldi@gmail.com>
# #
# Copyright 2015, 2016, 2017 Google Inc. All rights reserved. # Copyright 2015, 2016, 2017 Google Inc. All rights reserved.

View File

@ -560,12 +560,14 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (lto_mode && !have_c) { if (lto_mode && !have_c) {
u8 *ld_path = strdup(AFL_REAL_LD); u8 *ld_path = strdup(AFL_REAL_LD);
if (!*ld_path) ld_path = "ld.lld"; if (!ld_path || !*ld_path) { ld_path = strdup("ld.lld"); }
if (!ld_path) { PFATAL("Could not allocate mem for ld_path"); }
#if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 12 #if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 12
cc_params[cc_par_cnt++] = alloc_printf("--ld-path=%s", ld_path); cc_params[cc_par_cnt++] = alloc_printf("--ld-path=%s", ld_path);
#else #else
cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", ld_path); cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", ld_path);
#endif #endif
free(ld_path);
cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition"; cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition";

View File

@ -416,7 +416,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
struct rlimit r; 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 unsetenv(CMPLOG_SHM_ENV_VAR); // we do not want that in non-cmplog fsrv
@ -1089,7 +1090,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
#endif #endif
if (likely(fsrv->use_shmem_fuzz && fsrv->shmem_fuzz)) { if (likely(fsrv->use_shmem_fuzz)) {
if (unlikely(len > MAX_FILE)) len = MAX_FILE; if (unlikely(len > MAX_FILE)) len = MAX_FILE;

View File

@ -397,7 +397,7 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) {
/* Write a message accompanying the crash directory :-) */ /* Write a message accompanying the crash directory :-) */
static void write_crash_readme(afl_state_t *afl) { void write_crash_readme(afl_state_t *afl) {
u8 fn[PATH_MAX]; u8 fn[PATH_MAX];
s32 fd; s32 fd;

View File

@ -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) { 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; argv[0] = fsrv->cmplog_binary;

View File

@ -2031,7 +2031,7 @@ void setup_dirs_fds(afl_state_t *afl) {
fprintf( fprintf(
afl->fsrv.plot_file, afl->fsrv.plot_file,
"# unix_time, cycles_done, cur_path, paths_total, " "# relative_time, cycles_done, cur_path, paths_total, "
"pending_total, pending_favs, map_size, unique_crashes, " "pending_total, pending_favs, map_size, unique_crashes, "
"unique_hangs, max_depth, execs_per_sec, total_execs, edges_found\n"); "unique_hangs, max_depth, execs_per_sec, total_execs, edges_found\n");
@ -2774,6 +2774,14 @@ void check_binary(afl_state_t *afl, u8 *fname) {
WARNF("AFL_PERSISTENT is no longer supported and may misbehave!"); 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 || if (afl->fsrv.frida_mode ||

View File

@ -308,9 +308,11 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
struct custom_mutator *mutator) { struct custom_mutator *mutator) {
u8 needs_write = 0, fault = 0; u8 fault = 0;
u32 trim_exec = 0; u32 trim_exec = 0;
u32 orig_len = q->len; u32 orig_len = q->len;
u32 out_len = 0;
u8 *out_buf = NULL;
u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
@ -397,25 +399,25 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
if (likely(retlen && cksum == q->exec_cksum)) { if (likely(retlen && cksum == q->exec_cksum)) {
if (afl_realloc((void **)&in_buf, retlen) == NULL) { /* Let's save a clean trace, which will be needed by
update_bitmap_score once we're done with the trimming stuff.
Use out_buf NULL check to make this only happen once per trim. */
if (!out_buf) {
memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits,
afl->fsrv.map_size);
}
if (afl_realloc((void **)&out_buf, retlen) == NULL) {
FATAL("can not allocate memory for trim"); FATAL("can not allocate memory for trim");
} }
memcpy(in_buf, retbuf, retlen); out_len = retlen;
q->len = retlen; memcpy(out_buf, retbuf, retlen);
/* Let's save a clean trace, which will be needed by
update_bitmap_score once we're done with the trimming stuff. */
if (!needs_write) {
needs_write = 1;
memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits,
afl->fsrv.map_size);
}
/* Tell the custom mutator that the trimming was successful */ /* Tell the custom mutator that the trimming was successful */
afl->stage_cur = mutator->afl_custom_post_trim(mutator->data, 1); afl->stage_cur = mutator->afl_custom_post_trim(mutator->data, 1);
@ -423,7 +425,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
if (afl->not_on_tty && afl->debug) { if (afl->not_on_tty && afl->debug) {
SAYF("[Custom Trimming] SUCCESS: %u/%u iterations (now at %u bytes)", SAYF("[Custom Trimming] SUCCESS: %u/%u iterations (now at %u bytes)",
afl->stage_cur, afl->stage_max, q->len); afl->stage_cur, afl->stage_max, out_len);
} }
@ -456,16 +458,10 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
} }
if (afl->not_on_tty && afl->debug) { /* If we have made changes, we also need to update the on-disk
SAYF("[Custom Trimming] DONE: %u bytes -> %u bytes", orig_len, q->len);
}
/* If we have made changes to in_buf, we also need to update the on-disk
version of the test case. */ version of the test case. */
if (needs_write) { if (out_buf) {
s32 fd; s32 fd;
@ -475,16 +471,28 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); } if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); }
ck_write(fd, in_buf, q->len, q->fname); ck_write(fd, out_buf, out_len, q->fname);
close(fd); close(fd);
/* Update the queue's knowledge of length as soon as we write the file.
We do this here so that exit/error cases that *don't* update the file
also don't update q->len. */
q->len = out_len;
memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, afl->fsrv.map_size); memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, afl->fsrv.map_size);
update_bitmap_score(afl, q); update_bitmap_score(afl, q);
} }
if (afl->not_on_tty && afl->debug) {
SAYF("[Custom Trimming] DONE: %u bytes -> %u bytes", orig_len, q->len);
}
abort_trimming: abort_trimming:
if (out_buf) afl_free(out_buf);
afl->bytes_trim_out += q->len; afl->bytes_trim_out += q->len;
return fault; return fault;

View File

@ -3010,13 +3010,13 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
u8 res = trim_case(afl, afl->queue_cur, in_buf); u8 res = trim_case(afl, afl->queue_cur, in_buf);
orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur); orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur);
if (res == FSRV_RUN_ERROR) { if (unlikely(res == FSRV_RUN_ERROR)) {
FATAL("Unable to execute target application"); FATAL("Unable to execute target application");
} }
if (afl->stop_soon) { if (unlikely(afl->stop_soon)) {
++afl->cur_skipped_paths; ++afl->cur_skipped_paths;
goto abandon_entry; goto abandon_entry;

View File

@ -203,7 +203,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
} }
if (afl->fsrv.shmem_fuzz) { if (likely(afl->fsrv.use_shmem_fuzz)) {
if (!post_process_skipped) { if (!post_process_skipped) {
@ -211,9 +211,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
memcpy(afl->fsrv.shmem_fuzz, new_mem, new_size); memcpy(afl->fsrv.shmem_fuzz, new_mem, new_size);
} } else {
else {
memcpy(afl->fsrv.shmem_fuzz, mem, skip_at); memcpy(afl->fsrv.shmem_fuzz, mem, skip_at);
@ -244,7 +242,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
return; return;
} else if (afl->fsrv.out_file) { } else if (unlikely(!afl->fsrv.use_stdin)) {
if (unlikely(afl->no_unlink)) { if (unlikely(afl->no_unlink)) {
@ -279,7 +277,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
} }
if (!afl->fsrv.out_file) { if (afl->fsrv.use_stdin) {
if (ftruncate(fd, new_size)) { PFATAL("ftruncate() failed"); } if (ftruncate(fd, new_size)) { PFATAL("ftruncate() failed"); }
lseek(fd, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);

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