mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-18 20:48:07 +00:00
Push to stable (#927)
* 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 commite9d2f72382
. * Revert "fix custom trim for increasing data" This reverts commit86a8ef168d
. * 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 thee9d2f72382
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 * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name <you@example.com> * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name <you@example.com> * Support for x86 (#920) Co-authored-by: Your Name <you@example.com> * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name <you@example.com> * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env 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> Co-authored-by: Dustin Spicuzza <dustin@virtualroadside.com>
This commit is contained in:
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -19,7 +19,7 @@ jobs:
|
|||||||
- name: update
|
- name: update
|
||||||
run: sudo apt-get update && sudo apt-get upgrade -y
|
run: sudo apt-get update && sudo apt-get upgrade -y
|
||||||
- name: install packages
|
- name: install packages
|
||||||
run: sudo apt-get install -y -m -f --install-suggests build-essential git libtool libtool-bin automake bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools
|
run: sudo apt-get install -y -m -f --install-suggests build-essential git libtool libtool-bin automake bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build
|
||||||
- name: compiler installed
|
- name: compiler installed
|
||||||
run: gcc -v ; echo ; clang -v
|
run: gcc -v ; echo ; clang -v
|
||||||
- name: install gcc plugin
|
- name: install gcc plugin
|
||||||
|
@ -90,16 +90,17 @@ 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 | x |
|
||||||
| Persistent Mode | | x | x | x | x86[_64]/arm[64] | x |
|
| Persistent Mode | | x | x | x86[_64] | 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 | | x | x86[_64]/arm[64] | |
|
| CmpLog | | x | | x86[_64] | 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) | | | | |
|
||||||
| Context Coverage | | x(6) | | | | |
|
| Context Coverage | | x(6) | | | | |
|
||||||
| Auto Dictionary | | x(7) | | | | |
|
| Auto Dictionary | | x(7) | | | | |
|
||||||
| Snapshot LKM Support | | (x)(8) | (x)(8) | | (x)(5) | |
|
| Snapshot LKM Support | | (x)(8) | (x)(8) | | (x)(5) | |
|
||||||
|
| Shared Memory Testcases | | x | x | x | x | x |
|
||||||
|
|
||||||
1. default for LLVM >= 9.0, env var for older version due an efficiency bug in previous llvm versions
|
1. default for LLVM >= 9.0, env var for older version due an efficiency bug in previous llvm versions
|
||||||
2. GCC creates non-performant code, hence it is disabled in gcc_plugin
|
2. GCC creates non-performant code, hence it is disabled in gcc_plugin
|
||||||
|
2
afl-cmin
2
afl-cmin
@ -123,6 +123,8 @@ function usage() {
|
|||||||
"AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \
|
"AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \
|
||||||
"AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n"
|
"AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n"
|
||||||
"AFL_PATH: path for the afl-showmap binary if not found anywhere else\n" \
|
"AFL_PATH: path for the afl-showmap binary if not found anywhere else\n" \
|
||||||
|
"AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \
|
||||||
|
"printed to stdout\n" \
|
||||||
"AFL_SKIP_BIN_CHECK: skip check for target binary\n"
|
"AFL_SKIP_BIN_CHECK: skip check for target binary\n"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ Want to stay in the loop on major new features? Join our mailing list by
|
|||||||
sending a mail to <afl-users+subscribe@googlegroups.com>.
|
sending a mail to <afl-users+subscribe@googlegroups.com>.
|
||||||
|
|
||||||
### Version ++3.13a (development)
|
### Version ++3.13a (development)
|
||||||
|
- Note: plot_data switched to relative time from unix time in 3.10
|
||||||
- frida_mode - new mode that uses frida to fuzz binary-only targets,
|
- frida_mode - new mode that uses frida to fuzz binary-only targets,
|
||||||
it currently supports persistent mode and cmplog.
|
it currently supports persistent mode and cmplog.
|
||||||
thanks to @WorksButNotTested!
|
thanks to @WorksButNotTested!
|
||||||
@ -28,9 +29,12 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
|
|||||||
- ensure one fuzzer sync per cycle
|
- ensure one fuzzer sync per cycle
|
||||||
- fix afl_custom_queue_new_entry original file name when syncing
|
- fix afl_custom_queue_new_entry original file name when syncing
|
||||||
from fuzzers
|
from fuzzers
|
||||||
|
- on a crashing seed potentially the wrong input was disabled
|
||||||
- added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in
|
- added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in
|
||||||
-i dir crashes the target or results in a timeout. By default
|
-i dir crashes the target or results in a timeout. By default
|
||||||
afl++ ignores these and uses them for splicing instead.
|
afl++ ignores these and uses them for splicing instead.
|
||||||
|
- added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after
|
||||||
|
no new paths have been found for n seconds
|
||||||
- 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
|
- Fix for -pie compiled binaries with default afl-clang-fast PCGUARD
|
||||||
@ -48,6 +52,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
|
|||||||
MacOS shared memory
|
MacOS shared memory
|
||||||
- updated the grammar custom mutator to the newest version
|
- 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
|
||||||
|
- added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the current filename
|
||||||
|
|
||||||
### Version ++3.12c (release)
|
### Version ++3.12c (release)
|
||||||
- afl-fuzz:
|
- afl-fuzz:
|
||||||
|
@ -103,6 +103,41 @@ The llvm instrumentation requires a fully-operational installation of clang. The
|
|||||||
comes with Xcode is missing some of the essential headers and helper tools.
|
comes with Xcode is missing some of the essential headers and helper tools.
|
||||||
See README.llvm.md for advice on how to build the compiler from scratch.
|
See README.llvm.md for advice on how to build the compiler from scratch.
|
||||||
|
|
||||||
|
MacOS X supports SYSV shared memory used by AFL's instrumentation, but the
|
||||||
|
default settings aren't usable with AFL++. The default settings on 10.14 seem
|
||||||
|
to be:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ ipcs -M
|
||||||
|
IPC status from <running system> as of XXX
|
||||||
|
shminfo:
|
||||||
|
shmmax: 4194304 (max shared memory segment size)
|
||||||
|
shmmin: 1 (min shared memory segment size)
|
||||||
|
shmmni: 32 (max number of shared memory identifiers)
|
||||||
|
shmseg: 8 (max shared memory segments per process)
|
||||||
|
shmall: 1024 (max amount of shared memory in pages)
|
||||||
|
```
|
||||||
|
|
||||||
|
To temporarily change your settings to something minimally usable with AFL++,
|
||||||
|
run these commands as root:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sysctl kern.sysv.shmmax=8388608
|
||||||
|
sysctl kern.sysv.shmall=4096
|
||||||
|
```
|
||||||
|
|
||||||
|
If you're running more than one instance of AFL you likely want to make `shmall`
|
||||||
|
bigger and increase `shmseg` as well:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sysctl kern.sysv.shmmax=8388608
|
||||||
|
sysctl kern.sysv.shmseg=48
|
||||||
|
sysctl kern.sysv.shmall=98304
|
||||||
|
```
|
||||||
|
|
||||||
|
See http://www.spy-hill.com/help/apple/SharedMemory.html for documentation for
|
||||||
|
these settings and how to make them permanent.
|
||||||
|
|
||||||
## 4. Linux or *BSD on non-x86 systems
|
## 4. Linux or *BSD on non-x86 systems
|
||||||
|
|
||||||
Standard build will fail on non-x86 systems, but you should be able to
|
Standard build will fail on non-x86 systems, but you should be able to
|
||||||
|
@ -285,8 +285,8 @@ checks or alter some of the more exotic semantics of the tool:
|
|||||||
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
|
- `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
|
found within a specified period of time (in seconds). May be convenient
|
||||||
types of automated jobs.
|
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.
|
||||||
@ -567,6 +567,9 @@ The corpus minimization script offers very little customization:
|
|||||||
a modest security risk on multi-user systems with rogue users, but should
|
a modest security risk on multi-user systems with rogue users, but should
|
||||||
be safe on dedicated fuzzing boxes.
|
be safe on dedicated fuzzing boxes.
|
||||||
|
|
||||||
|
- `AFL_PRINT_FILENAMES` prints each filename to stdout, as it gets processed.
|
||||||
|
This can help when embedding `afl-cmin` or `afl-showmap` in other scripts scripting.
|
||||||
|
|
||||||
## 7) Settings for afl-tmin
|
## 7) Settings for afl-tmin
|
||||||
|
|
||||||
Virtually nothing to play with. Well, in QEMU mode (`-Q`), `AFL_PATH` will be
|
Virtually nothing to play with. Well, in QEMU mode (`-Q`), `AFL_PATH` will be
|
||||||
|
@ -19,11 +19,13 @@ RT_CFLAGS:=-Wno-unused-parameter \
|
|||||||
-Wno-sign-compare \
|
-Wno-sign-compare \
|
||||||
-Wno-unused-function \
|
-Wno-unused-function \
|
||||||
-Wno-unused-result \
|
-Wno-unused-result \
|
||||||
|
-Wno-int-to-pointer-cast \
|
||||||
|
|
||||||
LDFLAGS+=-shared \
|
LDFLAGS+=-shared \
|
||||||
-lpthread \
|
-lpthread \
|
||||||
-lresolv \
|
-lresolv \
|
||||||
-ldl \
|
-ldl \
|
||||||
|
-z noexecstack \
|
||||||
|
|
||||||
ifdef DEBUG
|
ifdef DEBUG
|
||||||
CFLAGS+=-Werror \
|
CFLAGS+=-Werror \
|
||||||
@ -38,6 +40,8 @@ FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/
|
|||||||
FRIDA_TRACE:=$(BUILD_DIR)afl-frida-trace.so
|
FRIDA_TRACE:=$(BUILD_DIR)afl-frida-trace.so
|
||||||
FRIDA_TRACE_EMBEDDED:=$(BUILD_DIR)afl-frida-trace-embedded
|
FRIDA_TRACE_EMBEDDED:=$(BUILD_DIR)afl-frida-trace-embedded
|
||||||
|
|
||||||
|
ifndef ARCH
|
||||||
|
|
||||||
ARCH=$(shell uname -m)
|
ARCH=$(shell uname -m)
|
||||||
ifeq "$(ARCH)" "aarch64"
|
ifeq "$(ARCH)" "aarch64"
|
||||||
ARCH:=arm64
|
ARCH:=arm64
|
||||||
@ -46,6 +50,7 @@ endif
|
|||||||
ifeq "$(ARCH)" "i686"
|
ifeq "$(ARCH)" "i686"
|
||||||
ARCH:=x86
|
ARCH:=x86
|
||||||
endif
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq "$(shell uname)" "Darwin"
|
ifeq "$(shell uname)" "Darwin"
|
||||||
OS:=macos
|
OS:=macos
|
||||||
@ -83,13 +88,16 @@ 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_SRC:=$(ROOT)instrumentation/afl-compiler-rt.o.c
|
||||||
AFL_COMPILER_RT_OBJ:=$(OBJ_DIR)afl-compiler-rt.o
|
AFL_COMPILER_RT_OBJ:=$(OBJ_DIR)afl-compiler-rt.o
|
||||||
|
|
||||||
.PHONY: all clean format $(FRIDA_GUM)
|
.PHONY: all 32 clean format $(FRIDA_GUM)
|
||||||
|
|
||||||
############################## ALL #############################################
|
############################## ALL #############################################
|
||||||
|
|
||||||
all: $(FRIDA_TRACE)
|
all: $(FRIDA_TRACE)
|
||||||
make -C $(ROOT)
|
make -C $(ROOT)
|
||||||
|
|
||||||
|
32:
|
||||||
|
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||||
|
|
||||||
$(BUILD_DIR):
|
$(BUILD_DIR):
|
||||||
mkdir -p $(BUILD_DIR)
|
mkdir -p $(BUILD_DIR)
|
||||||
|
|
||||||
@ -161,11 +169,11 @@ $(foreach src,$(SOURCES),$(eval $(call BUILD_SOURCE,$(src),$(OBJ_DIR)$(notdir $(
|
|||||||
|
|
||||||
$(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(AFL_COMPILER_RT_OBJ) GNUmakefile | $(BUILD_DIR)
|
$(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(AFL_COMPILER_RT_OBJ) GNUmakefile | $(BUILD_DIR)
|
||||||
$(CC) \
|
$(CC) \
|
||||||
-o $@ \
|
|
||||||
$(OBJS) \
|
$(OBJS) \
|
||||||
$(GUM_DEVIT_LIBRARY) \
|
$(GUM_DEVIT_LIBRARY) \
|
||||||
$(AFL_COMPILER_RT_OBJ) \
|
$(AFL_COMPILER_RT_OBJ) \
|
||||||
$(LDFLAGS) \
|
$(LDFLAGS) \
|
||||||
|
-o $@ \
|
||||||
|
|
||||||
cp -v $(FRIDA_TRACE) $(ROOT)
|
cp -v $(FRIDA_TRACE) $(ROOT)
|
||||||
|
|
||||||
|
@ -2,6 +2,10 @@ all:
|
|||||||
@echo trying to use GNU make...
|
@echo trying to use GNU make...
|
||||||
@gmake all || echo please install GNUmake
|
@gmake all || echo please install GNUmake
|
||||||
|
|
||||||
|
32:
|
||||||
|
@echo trying to use GNU make...
|
||||||
|
@gmake 32 || echo please install GNUmake
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@gmake clean
|
@gmake clean
|
||||||
|
|
||||||
|
@ -19,18 +19,18 @@ should be possible to add these features in a similar manner to QEMU mode and
|
|||||||
perhaps leverage some of its design and implementation.
|
perhaps leverage some of its design and implementation.
|
||||||
|
|
||||||
| Feature/Instrumentation | frida-mode | Notes |
|
| Feature/Instrumentation | frida-mode | Notes |
|
||||||
| -------------------------|:----------:|:---------------------------------------:|
|
| -------------------------|:----------:|:--------------------------------------------:|
|
||||||
| NeverZero | x | |
|
| NeverZero | x | |
|
||||||
| Persistent Mode | x | (x64 only)(Only on function boundaries) |
|
| Persistent Mode | x | (x86/x64 only)(Only on function boundaries) |
|
||||||
| LAF-Intel / CompCov | - | (CMPLOG is better 90% of the time) |
|
| LAF-Intel / CompCov | - | (CMPLOG is better 90% of the time) |
|
||||||
| CMPLOG | x | (x64 only) |
|
| CMPLOG | x | (x86/x64 only) |
|
||||||
| Selective Instrumentation| x | |
|
| Selective Instrumentation| x | |
|
||||||
| Non-Colliding Coverage | - | |
|
| Non-Colliding Coverage | - | (Not possible in binary-only instrumentation |
|
||||||
| Ngram prev_loc Coverage | - | |
|
| Ngram prev_loc Coverage | - | |
|
||||||
| Context Coverage | - | |
|
| Context Coverage | - | |
|
||||||
| Auto Dictionary | - | |
|
| Auto Dictionary | - | |
|
||||||
| Snapshot LKM Support | - | |
|
| Snapshot LKM Support | - | |
|
||||||
| In-Memory Test Cases | x | (x64 only) |
|
| In-Memory Test Cases | x | (x86/x64 only) |
|
||||||
|
|
||||||
## Compatibility
|
## 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
|
||||||
@ -43,11 +43,17 @@ system does not support cross compilation.
|
|||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
To build everything run `make`.
|
To build everything run `make`. To build for x86 run `make 32`. Note that in
|
||||||
|
x86 bit mode, it is not necessary for afl-fuzz to be built for 32-bit. However,
|
||||||
|
the shared library for frida_mode must be since it is injected into the target
|
||||||
|
process.
|
||||||
|
|
||||||
Various tests can be found in subfolders within the `test/` directory. To use
|
Various tests can be found in subfolders within the `test/` directory. To use
|
||||||
these, first run `make` to build any dependencies. Then run `make qemu` or
|
these, first run `make` to build any dependencies. Then run `make qemu` or
|
||||||
`make frida` to run on either QEMU of FRIDA mode respectively.
|
`make frida` to run on either QEMU of FRIDA mode respectively. To run frida
|
||||||
|
tests in 32-bit mode, run `make ARCH=x86 frida`. When switching between
|
||||||
|
architectures it may be necessary to run `make clean` first for a given build
|
||||||
|
target to remove previously generated binaries for a different architecture.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@ -130,9 +136,47 @@ them and they be inherited by the next child on fork.
|
|||||||
* `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`.
|
||||||
|
|
||||||
|
## FASAN - Frida Address Sanitizer Mode
|
||||||
|
Frida mode also supports FASAN. The design of this is actually quite simple and
|
||||||
|
very similar to that used when instrumenting applications compiled from source.
|
||||||
|
|
||||||
|
### Address Sanitizer Basics
|
||||||
|
|
||||||
|
When Address Sanitizer is used to instrument programs built from source, the
|
||||||
|
compiler first adds a dependency (`DT_NEEDED` entry) for the Address Sanitizer
|
||||||
|
dynamic shared object (DSO). This shared object contains the main logic for Address
|
||||||
|
Sanitizer, including setting and managing up the shadow memory. It also provides
|
||||||
|
replacement implementations for a number of functions in standard libraries.
|
||||||
|
|
||||||
|
These replacements include things like `malloc` and `free` which allows for those
|
||||||
|
allocations to be marked in the shadow memory, but also a number of other fuctions.
|
||||||
|
Consider `memcpy` for example, this is instrumented to validate the paramters
|
||||||
|
(test the source and destination buffers against the shadow memory. This is much
|
||||||
|
easier than instrumenting those standard libraries since, first it would require
|
||||||
|
you to re-compile them and secondly it would mean that the instrumentation would
|
||||||
|
be applied at a more expensive granular level. Lastly, load-widening (typically
|
||||||
|
found in highy optimized code) can also make this instrumentation more difficult.
|
||||||
|
|
||||||
|
Since the DSO is loaded before all of the standard libraries (in fact it insists
|
||||||
|
on being first), the dynamic loader will use it to resolve imports from other
|
||||||
|
modules which depend on it.
|
||||||
|
|
||||||
|
### FASAN Implementation
|
||||||
|
|
||||||
|
FASAN takes a similar approach. It requires the user to add the Address Sanitizer
|
||||||
|
DSO to the `AFL_PRELOAD` environment variable such that it is loaded into the target.
|
||||||
|
Again, it must be first in the list. This means that it is not necessary to
|
||||||
|
instrument the standard libraries to detect when an application has provided an
|
||||||
|
incorrect argument to `memcpy` for example. This avoids issues with load-widening
|
||||||
|
and should also mean a huge improvement in performance.
|
||||||
|
|
||||||
|
FASAN then adds instrumentation for any instrucutions which use memory operands and
|
||||||
|
then calls into the `__asan_loadN` and `__asan_storeN` functions provided by the DSO
|
||||||
|
to validate memory accesses against the shadow memory.
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
The next features to be added are x86 support, integration with FuzzBench and
|
The next features to be added are Aarch64 and Aarch32 support as well as looking at
|
||||||
support for ASAN. The intention is to achieve feature parity with QEMU mode in
|
potential performance improvements. The intention is to achieve feature parity with
|
||||||
due course. Contributions are welcome, but please get in touch to ensure that
|
QEMU mode in due course. Contributions are welcome, but please get in touch to
|
||||||
efforts are deconflicted.
|
ensure that efforts are deconflicted.
|
||||||
|
13
frida_mode/include/asan.h
Normal file
13
frida_mode/include/asan.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef _ASAN_H
|
||||||
|
#define _ASAN_H
|
||||||
|
|
||||||
|
#include "frida-gum.h"
|
||||||
|
|
||||||
|
extern gboolean asan_initialized;
|
||||||
|
|
||||||
|
void asan_init(void);
|
||||||
|
void asan_arch_init(void);
|
||||||
|
void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
11
frida_mode/include/ctx.h
Normal file
11
frida_mode/include/ctx.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef _CTX_H
|
||||||
|
#define _CTX_H
|
||||||
|
|
||||||
|
#include "frida-gum.h"
|
||||||
|
|
||||||
|
#if defined(__x86_64__) || defined(__i386__)
|
||||||
|
gsize ctx_read_reg(GumCpuContext *ctx, x86_reg reg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -8,7 +8,7 @@ void cmplog_init(void);
|
|||||||
/* Functions to be implemented by the different architectures */
|
/* Functions to be implemented by the different architectures */
|
||||||
void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator);
|
void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator);
|
||||||
|
|
||||||
gboolean cmplog_is_readable(void *addr, size_t size);
|
gboolean cmplog_is_readable(guint64 addr, size_t size);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
24
frida_mode/src/asan/asan.c
Normal file
24
frida_mode/src/asan/asan.c
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include "frida-gum.h"
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "asan.h"
|
||||||
|
|
||||||
|
gboolean asan_initialized = FALSE;
|
||||||
|
|
||||||
|
void asan_init(void) {
|
||||||
|
|
||||||
|
if (getenv("AFL_USE_FASAN") != NULL) {
|
||||||
|
|
||||||
|
OKF("Frida ASAN mode enabled");
|
||||||
|
asan_arch_init();
|
||||||
|
asan_initialized = TRUE;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
OKF("Frida ASAN mode disabled");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
28
frida_mode/src/asan/asan_arm.c
Normal file
28
frida_mode/src/asan/asan_arm.c
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include "frida-gum.h"
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "asan.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#if defined(__arm__)
|
||||||
|
void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(instr);
|
||||||
|
UNUSED_PARAMETER(iterator);
|
||||||
|
if (asan_initialized) {
|
||||||
|
|
||||||
|
FATAL("ASAN mode not supported on this architecture");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void asan_arch_init(void) {
|
||||||
|
|
||||||
|
FATAL("ASAN mode not supported on this architecture");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
28
frida_mode/src/asan/asan_arm64.c
Normal file
28
frida_mode/src/asan/asan_arm64.c
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include "frida-gum.h"
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "asan.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#if defined(__aarch64__)
|
||||||
|
void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(instr);
|
||||||
|
UNUSED_PARAMETER(iterator);
|
||||||
|
if (asan_initialized) {
|
||||||
|
|
||||||
|
FATAL("ASAN mode not supported on this architecture");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void asan_arch_init(void) {
|
||||||
|
|
||||||
|
FATAL("ASAN mode not supported on this architecture");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
93
frida_mode/src/asan/asan_x64.c
Normal file
93
frida_mode/src/asan/asan_x64.c
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include <dlfcn.h>
|
||||||
|
#include "frida-gum.h"
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "asan.h"
|
||||||
|
#include "ctx.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
|
||||||
|
typedef void (*asan_loadN_t)(uint64_t address, uint8_t size);
|
||||||
|
typedef void (*asan_storeN_t)(uint64_t address, uint8_t size);
|
||||||
|
|
||||||
|
asan_loadN_t asan_loadN = NULL;
|
||||||
|
asan_storeN_t asan_storeN = NULL;
|
||||||
|
|
||||||
|
static void asan_callout(GumCpuContext *ctx, gpointer user_data) {
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(user_data);
|
||||||
|
|
||||||
|
cs_x86_op * operand = (cs_x86_op *)user_data;
|
||||||
|
x86_op_mem *mem = &operand->mem;
|
||||||
|
gsize base = 0;
|
||||||
|
gsize index = 0;
|
||||||
|
gsize address;
|
||||||
|
uint8_t size;
|
||||||
|
|
||||||
|
if (mem->base != X86_REG_INVALID) { base = ctx_read_reg(ctx, mem->base); }
|
||||||
|
|
||||||
|
if (mem->index != X86_REG_INVALID) { index = ctx_read_reg(ctx, mem->index); }
|
||||||
|
|
||||||
|
address = base + (mem->scale * index) + mem->disp;
|
||||||
|
size = operand->size;
|
||||||
|
|
||||||
|
if (operand->access == CS_AC_READ) {
|
||||||
|
|
||||||
|
asan_loadN(address, size);
|
||||||
|
|
||||||
|
} else if (operand->access == CS_AC_WRITE) {
|
||||||
|
|
||||||
|
asan_storeN(address, size);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(iterator);
|
||||||
|
|
||||||
|
cs_x86 x86 = instr->detail->x86;
|
||||||
|
cs_x86_op * operand;
|
||||||
|
x86_op_mem *mem;
|
||||||
|
cs_x86_op * ctx;
|
||||||
|
|
||||||
|
if (!asan_initialized) return;
|
||||||
|
|
||||||
|
if (instr->id == X86_INS_LEA) return;
|
||||||
|
|
||||||
|
if (instr->id == X86_INS_NOP) return;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < x86.op_count; i++) {
|
||||||
|
|
||||||
|
operand = &x86.operands[i];
|
||||||
|
|
||||||
|
if (operand->type != X86_OP_MEM) { continue; }
|
||||||
|
|
||||||
|
mem = &operand->mem;
|
||||||
|
if (mem->segment != X86_REG_INVALID) { continue; }
|
||||||
|
|
||||||
|
ctx = g_malloc0(sizeof(cs_x86_op));
|
||||||
|
memcpy(ctx, operand, sizeof(cs_x86_op));
|
||||||
|
gum_stalker_iterator_put_callout(iterator, asan_callout, ctx, g_free);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void asan_arch_init(void) {
|
||||||
|
|
||||||
|
asan_loadN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_loadN");
|
||||||
|
asan_storeN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_storeN");
|
||||||
|
if (asan_loadN == NULL || asan_storeN == NULL) {
|
||||||
|
|
||||||
|
FATAL("Frida ASAN failed to find '__asan_loadN' or '__asan_storeN'");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
93
frida_mode/src/asan/asan_x86.c
Normal file
93
frida_mode/src/asan/asan_x86.c
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include <dlfcn.h>
|
||||||
|
#include "frida-gum.h"
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "asan.h"
|
||||||
|
#include "ctx.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#if defined(__i386__)
|
||||||
|
|
||||||
|
typedef void (*asan_loadN_t)(gsize address, uint8_t size);
|
||||||
|
typedef void (*asan_storeN_t)(gsize address, uint8_t size);
|
||||||
|
|
||||||
|
asan_loadN_t asan_loadN = NULL;
|
||||||
|
asan_storeN_t asan_storeN = NULL;
|
||||||
|
|
||||||
|
static void asan_callout(GumCpuContext *ctx, gpointer user_data) {
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(user_data);
|
||||||
|
|
||||||
|
cs_x86_op * operand = (cs_x86_op *)user_data;
|
||||||
|
x86_op_mem *mem = &operand->mem;
|
||||||
|
gsize base = 0;
|
||||||
|
gsize index = 0;
|
||||||
|
gsize address;
|
||||||
|
uint8_t size;
|
||||||
|
|
||||||
|
if (mem->base != X86_REG_INVALID) { base = ctx_read_reg(ctx, mem->base); }
|
||||||
|
|
||||||
|
if (mem->index != X86_REG_INVALID) { index = ctx_read_reg(ctx, mem->index); }
|
||||||
|
|
||||||
|
address = base + (mem->scale * index) + mem->disp;
|
||||||
|
size = operand->size;
|
||||||
|
|
||||||
|
if (operand->access == CS_AC_READ) {
|
||||||
|
|
||||||
|
asan_loadN(address, size);
|
||||||
|
|
||||||
|
} else if (operand->access == CS_AC_WRITE) {
|
||||||
|
|
||||||
|
asan_storeN(address, size);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(iterator);
|
||||||
|
|
||||||
|
cs_x86 x86 = instr->detail->x86;
|
||||||
|
cs_x86_op * operand;
|
||||||
|
x86_op_mem *mem;
|
||||||
|
cs_x86_op * ctx;
|
||||||
|
|
||||||
|
if (!asan_initialized) return;
|
||||||
|
|
||||||
|
if (instr->id == X86_INS_LEA) return;
|
||||||
|
|
||||||
|
if (instr->id == X86_INS_NOP) return;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < x86.op_count; i++) {
|
||||||
|
|
||||||
|
operand = &x86.operands[i];
|
||||||
|
|
||||||
|
if (operand->type != X86_OP_MEM) { continue; }
|
||||||
|
|
||||||
|
mem = &operand->mem;
|
||||||
|
if (mem->segment != X86_REG_INVALID) { continue; }
|
||||||
|
|
||||||
|
ctx = g_malloc0(sizeof(cs_x86_op));
|
||||||
|
memcpy(ctx, operand, sizeof(cs_x86_op));
|
||||||
|
gum_stalker_iterator_put_callout(iterator, asan_callout, ctx, g_free);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void asan_arch_init(void) {
|
||||||
|
|
||||||
|
asan_loadN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_loadN");
|
||||||
|
asan_storeN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_storeN");
|
||||||
|
if (asan_loadN == NULL || asan_storeN == NULL) {
|
||||||
|
|
||||||
|
FATAL("Frida ASAN failed to find '__asan_loadN' or '__asan_storeN'");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -53,7 +53,7 @@ static gboolean cmplog_contains(GumAddress inner_base, GumAddress inner_limit,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean cmplog_is_readable(void *addr, size_t size) {
|
gboolean cmplog_is_readable(guint64 addr, size_t size) {
|
||||||
|
|
||||||
if (cmplog_ranges == NULL) FATAL("CMPLOG not initialized");
|
if (cmplog_ranges == NULL) FATAL("CMPLOG not initialized");
|
||||||
|
|
||||||
@ -65,9 +65,9 @@ gboolean cmplog_is_readable(void *addr, size_t size) {
|
|||||||
* is lower than this. This should avoid some overhead when functions are
|
* 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.
|
* 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; }
|
if (addr < DEFAULT_MMAP_MIN_ADDR) { return false; }
|
||||||
|
|
||||||
GumAddress inner_base = GUM_ADDRESS(addr);
|
GumAddress inner_base = addr;
|
||||||
GumAddress inner_limit = inner_base + size;
|
GumAddress inner_limit = inner_base + size;
|
||||||
|
|
||||||
for (guint i = 0; i < cmplog_ranges->len; i++) {
|
for (guint i = 0; i < cmplog_ranges->len; i++) {
|
||||||
|
@ -3,46 +3,12 @@
|
|||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "cmplog.h"
|
#include "cmplog.h"
|
||||||
|
|
||||||
|
#include "ctx.h"
|
||||||
#include "frida_cmplog.h"
|
#include "frida_cmplog.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#if defined(__x86_64__)
|
#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 {
|
typedef struct {
|
||||||
|
|
||||||
x86_op_type type;
|
x86_op_type type;
|
||||||
@ -65,123 +31,81 @@ typedef struct {
|
|||||||
|
|
||||||
} cmplog_pair_ctx_t;
|
} cmplog_pair_ctx_t;
|
||||||
|
|
||||||
static guint64 cmplog_read_reg(GumX64CpuContext *ctx, x86_reg reg) {
|
static gboolean cmplog_read_mem(GumCpuContext *ctx, uint8_t size,
|
||||||
|
x86_op_mem *mem, gsize *val) {
|
||||||
|
|
||||||
switch (reg) {
|
gsize base = 0;
|
||||||
|
gsize index = 0;
|
||||||
|
gsize address;
|
||||||
|
|
||||||
X86_REG_8L(X86_REG_AL, ctx->rax)
|
if (mem->base != X86_REG_INVALID) base = ctx_read_reg(ctx, mem->base);
|
||||||
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)
|
if (mem->index != X86_REG_INVALID) index = ctx_read_reg(ctx, mem->index);
|
||||||
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;
|
address = base + (index * mem->scale) + mem->disp;
|
||||||
return address;
|
|
||||||
|
if (!cmplog_is_readable(address, size)) { return FALSE; }
|
||||||
|
|
||||||
|
switch (size) {
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
*val = *((guint8 *)GSIZE_TO_POINTER(address));
|
||||||
|
return TRUE;
|
||||||
|
case 2:
|
||||||
|
*val = *((guint16 *)GSIZE_TO_POINTER(address));
|
||||||
|
return TRUE;
|
||||||
|
case 4:
|
||||||
|
*val = *((guint32 *)GSIZE_TO_POINTER(address));
|
||||||
|
return TRUE;
|
||||||
|
case 8:
|
||||||
|
*val = *((guint64 *)GSIZE_TO_POINTER(address));
|
||||||
|
return TRUE;
|
||||||
|
default:
|
||||||
|
FATAL("Invalid operand size: %d\n", size);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static guint64 cmplog_get_operand_value(GumCpuContext *context,
|
return FALSE;
|
||||||
cmplog_ctx_t * ctx) {
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean cmplog_get_operand_value(GumCpuContext *context,
|
||||||
|
cmplog_ctx_t *ctx, gsize *val) {
|
||||||
|
|
||||||
switch (ctx->type) {
|
switch (ctx->type) {
|
||||||
|
|
||||||
case X86_OP_REG:
|
case X86_OP_REG:
|
||||||
return cmplog_read_reg(context, ctx->reg);
|
*val = ctx_read_reg(context, ctx->reg);
|
||||||
|
return TRUE;
|
||||||
case X86_OP_IMM:
|
case X86_OP_IMM:
|
||||||
return ctx->imm;
|
*val = ctx->imm;
|
||||||
|
return TRUE;
|
||||||
case X86_OP_MEM:
|
case X86_OP_MEM:
|
||||||
return cmplog_read_mem(context, &ctx->mem);
|
return cmplog_read_mem(context, ctx->size, &ctx->mem, val);
|
||||||
default:
|
default:
|
||||||
FATAL("Invalid operand type: %d\n", ctx->type);
|
FATAL("Invalid operand type: %d\n", ctx->type);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) {
|
static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) {
|
||||||
|
|
||||||
UNUSED_PARAMETER(user_data);
|
UNUSED_PARAMETER(user_data);
|
||||||
|
|
||||||
guint64 address = cmplog_read_reg(context, X86_REG_RIP);
|
gsize address = ctx_read_reg(context, X86_REG_RIP);
|
||||||
guint64 rdi = cmplog_read_reg(context, X86_REG_RDI);
|
gsize rdi = ctx_read_reg(context, X86_REG_RDI);
|
||||||
guint64 rsi = cmplog_read_reg(context, X86_REG_RSI);
|
gsize rsi = ctx_read_reg(context, X86_REG_RSI);
|
||||||
|
|
||||||
if (((G_MAXULONG - rdi) < 32) || ((G_MAXULONG - rsi) < 32)) return;
|
if (((G_MAXULONG - rdi) < 32) || ((G_MAXULONG - rsi) < 32)) return;
|
||||||
|
|
||||||
|
if (!cmplog_is_readable(rdi, 32) || !cmplog_is_readable(rsi, 32)) return;
|
||||||
|
|
||||||
void *ptr1 = GSIZE_TO_POINTER(rdi);
|
void *ptr1 = GSIZE_TO_POINTER(rdi);
|
||||||
void *ptr2 = GSIZE_TO_POINTER(rsi);
|
void *ptr2 = GSIZE_TO_POINTER(rsi);
|
||||||
|
|
||||||
if (!cmplog_is_readable(ptr1, 32) || !cmplog_is_readable(ptr2, 32)) return;
|
|
||||||
|
|
||||||
uintptr_t k = address;
|
uintptr_t k = address;
|
||||||
|
|
||||||
k = (k >> 4) ^ (k << 8);
|
k = (k >> 4) ^ (k << 8);
|
||||||
@ -245,10 +169,10 @@ static void cmplog_instrument_call(const cs_insn * instr,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cmplog_handle_cmp_sub(GumCpuContext *context, guint64 operand1,
|
static void cmplog_handle_cmp_sub(GumCpuContext *context, gsize operand1,
|
||||||
guint64 operand2, uint8_t size) {
|
gsize operand2, uint8_t size) {
|
||||||
|
|
||||||
guint64 address = cmplog_read_reg(context, X86_REG_RIP);
|
gsize address = ctx_read_reg(context, X86_REG_RIP);
|
||||||
|
|
||||||
register uintptr_t k = (uintptr_t)address;
|
register uintptr_t k = (uintptr_t)address;
|
||||||
|
|
||||||
@ -271,11 +195,13 @@ static void cmplog_handle_cmp_sub(GumCpuContext *context, guint64 operand1,
|
|||||||
static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) {
|
static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) {
|
||||||
|
|
||||||
cmplog_pair_ctx_t *ctx = (cmplog_pair_ctx_t *)user_data;
|
cmplog_pair_ctx_t *ctx = (cmplog_pair_ctx_t *)user_data;
|
||||||
|
gsize operand1;
|
||||||
|
gsize operand2;
|
||||||
|
|
||||||
if (ctx->operand1.size != ctx->operand2.size) FATAL("Operand size mismatch");
|
if (ctx->operand1.size != ctx->operand2.size) FATAL("Operand size mismatch");
|
||||||
|
|
||||||
guint64 operand1 = cmplog_get_operand_value(context, &ctx->operand1);
|
if (!cmplog_get_operand_value(context, &ctx->operand1, &operand1)) { return; }
|
||||||
guint64 operand2 = cmplog_get_operand_value(context, &ctx->operand2);
|
if (!cmplog_get_operand_value(context, &ctx->operand2, &operand2)) { return; }
|
||||||
|
|
||||||
cmplog_handle_cmp_sub(context, operand1, operand2, ctx->operand1.size);
|
cmplog_handle_cmp_sub(context, operand1, operand2, ctx->operand1.size);
|
||||||
|
|
||||||
|
@ -1,17 +1,275 @@
|
|||||||
#include "frida-gum.h"
|
#include "frida-gum.h"
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "cmplog.h"
|
||||||
|
|
||||||
|
#include "ctx.h"
|
||||||
#include "frida_cmplog.h"
|
#include "frida_cmplog.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
|
|
||||||
|
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 gboolean cmplog_read_mem(GumCpuContext *ctx, uint8_t size,
|
||||||
|
x86_op_mem *mem, gsize *val) {
|
||||||
|
|
||||||
|
gsize base = 0;
|
||||||
|
gsize index = 0;
|
||||||
|
gsize address;
|
||||||
|
|
||||||
|
if (mem->base != X86_REG_INVALID) base = ctx_read_reg(ctx, mem->base);
|
||||||
|
|
||||||
|
if (mem->index != X86_REG_INVALID) index = ctx_read_reg(ctx, mem->index);
|
||||||
|
|
||||||
|
address = base + (index * mem->scale) + mem->disp;
|
||||||
|
|
||||||
|
if (!cmplog_is_readable(address, size)) { return FALSE; }
|
||||||
|
|
||||||
|
switch (size) {
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
*val = *((guint8 *)GSIZE_TO_POINTER(address));
|
||||||
|
return TRUE;
|
||||||
|
case 2:
|
||||||
|
*val = *((guint16 *)GSIZE_TO_POINTER(address));
|
||||||
|
return TRUE;
|
||||||
|
case 4:
|
||||||
|
*val = *((guint32 *)GSIZE_TO_POINTER(address));
|
||||||
|
return TRUE;
|
||||||
|
default:
|
||||||
|
FATAL("Invalid operand size: %d\n", size);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean cmplog_get_operand_value(GumCpuContext *context,
|
||||||
|
cmplog_ctx_t *ctx, gsize *val) {
|
||||||
|
|
||||||
|
switch (ctx->type) {
|
||||||
|
|
||||||
|
case X86_OP_REG:
|
||||||
|
*val = ctx_read_reg(context, ctx->reg);
|
||||||
|
return TRUE;
|
||||||
|
case X86_OP_IMM:
|
||||||
|
*val = ctx->imm;
|
||||||
|
return TRUE;
|
||||||
|
case X86_OP_MEM:
|
||||||
|
return cmplog_read_mem(context, ctx->size, &ctx->mem, val);
|
||||||
|
default:
|
||||||
|
FATAL("Invalid operand type: %d\n", ctx->type);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) {
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(user_data);
|
||||||
|
|
||||||
|
gsize address = ctx_read_reg(context, X86_REG_EIP);
|
||||||
|
gsize *esp = (gsize *)ctx_read_reg(context, X86_REG_ESP);
|
||||||
|
|
||||||
|
if (!cmplog_is_readable(GPOINTER_TO_SIZE(esp), 12)) return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This callout is place immediately before the call instruction, and hence
|
||||||
|
* the return address is not yet pushed on the top of the stack.
|
||||||
|
*/
|
||||||
|
gsize arg1 = esp[0];
|
||||||
|
gsize arg2 = esp[1];
|
||||||
|
|
||||||
|
if (((G_MAXULONG - arg1) < 32) || ((G_MAXULONG - arg2) < 32)) return;
|
||||||
|
|
||||||
|
if (!cmplog_is_readable(arg1, 32) || !cmplog_is_readable(arg2, 32)) return;
|
||||||
|
|
||||||
|
void *ptr1 = GSIZE_TO_POINTER(arg1);
|
||||||
|
void *ptr2 = GSIZE_TO_POINTER(arg2);
|
||||||
|
|
||||||
|
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, gsize operand1,
|
||||||
|
gsize operand2, uint8_t size) {
|
||||||
|
|
||||||
|
gsize address = ctx_read_reg(context, X86_REG_EIP);
|
||||||
|
|
||||||
|
register uintptr_t k = (uintptr_t)address;
|
||||||
|
|
||||||
|
k = (k >> 4) ^ (k << 8);
|
||||||
|
k &= CMP_MAP_W - 1;
|
||||||
|
|
||||||
|
__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;
|
||||||
|
gsize operand1;
|
||||||
|
gsize operand2;
|
||||||
|
|
||||||
|
if (ctx->operand1.size != ctx->operand2.size) FATAL("Operand size mismatch");
|
||||||
|
|
||||||
|
if (!cmplog_get_operand_value(context, &ctx->operand1, &operand1)) { return; }
|
||||||
|
if (!cmplog_get_operand_value(context, &ctx->operand2, &operand2)) { return; }
|
||||||
|
|
||||||
|
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) {
|
void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) {
|
||||||
|
|
||||||
UNUSED_PARAMETER(instr);
|
if (__afl_cmp_map == NULL) return;
|
||||||
UNUSED_PARAMETER(iterator);
|
|
||||||
if (__afl_cmp_map == NULL) { return; }
|
cmplog_instrument_call(instr, iterator);
|
||||||
FATAL("CMPLOG mode not supported on this architecture");
|
cmplog_instrument_cmp_sub(instr, iterator);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
114
frida_mode/src/ctx/ctx_x64.c
Normal file
114
frida_mode/src/ctx/ctx_x64.c
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#include "frida-gum.h"
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "ctx.h"
|
||||||
|
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
|
||||||
|
#define X86_REG_8L(LABEL, REG) \
|
||||||
|
case LABEL: { \
|
||||||
|
\
|
||||||
|
return REG & GUM_INT8_MASK; \
|
||||||
|
\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define X86_REG_8H(LABEL, REG) \
|
||||||
|
case LABEL: { \
|
||||||
|
\
|
||||||
|
return (REG & GUM_INT16_MASK) >> 8; \
|
||||||
|
\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define X86_REG_16(LABEL, REG) \
|
||||||
|
case LABEL: { \
|
||||||
|
\
|
||||||
|
return (REG & GUM_INT16_MASK); \
|
||||||
|
\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define X86_REG_32(LABEL, REG) \
|
||||||
|
case LABEL: { \
|
||||||
|
\
|
||||||
|
return (REG & GUM_INT32_MASK); \
|
||||||
|
\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define X86_REG_64(LABEL, REG) \
|
||||||
|
case LABEL: { \
|
||||||
|
\
|
||||||
|
return (REG); \
|
||||||
|
\
|
||||||
|
}
|
||||||
|
|
||||||
|
gsize ctx_read_reg(GumX64CpuContext *ctx, x86_reg reg) {
|
||||||
|
|
||||||
|
switch (reg) {
|
||||||
|
|
||||||
|
X86_REG_8L(X86_REG_AL, ctx->rax)
|
||||||
|
X86_REG_8L(X86_REG_BL, ctx->rbx)
|
||||||
|
X86_REG_8L(X86_REG_CL, ctx->rcx)
|
||||||
|
X86_REG_8L(X86_REG_DL, ctx->rdx)
|
||||||
|
X86_REG_8L(X86_REG_BPL, ctx->rbp)
|
||||||
|
X86_REG_8L(X86_REG_SIL, ctx->rsi)
|
||||||
|
X86_REG_8L(X86_REG_DIL, ctx->rdi)
|
||||||
|
|
||||||
|
X86_REG_8H(X86_REG_AH, ctx->rax)
|
||||||
|
X86_REG_8H(X86_REG_BH, ctx->rbx)
|
||||||
|
X86_REG_8H(X86_REG_CH, ctx->rcx)
|
||||||
|
X86_REG_8H(X86_REG_DH, ctx->rdx)
|
||||||
|
|
||||||
|
X86_REG_16(X86_REG_AX, ctx->rax)
|
||||||
|
X86_REG_16(X86_REG_BX, ctx->rbx)
|
||||||
|
X86_REG_16(X86_REG_CX, ctx->rcx)
|
||||||
|
X86_REG_16(X86_REG_DX, ctx->rdx)
|
||||||
|
X86_REG_16(X86_REG_DI, ctx->rdi)
|
||||||
|
X86_REG_16(X86_REG_SI, ctx->rsi)
|
||||||
|
X86_REG_16(X86_REG_BP, ctx->rbp)
|
||||||
|
|
||||||
|
X86_REG_32(X86_REG_EAX, ctx->rax)
|
||||||
|
X86_REG_32(X86_REG_ECX, ctx->rcx)
|
||||||
|
X86_REG_32(X86_REG_EDX, ctx->rdx)
|
||||||
|
X86_REG_32(X86_REG_EBX, ctx->rbx)
|
||||||
|
X86_REG_32(X86_REG_ESP, ctx->rsp)
|
||||||
|
X86_REG_32(X86_REG_EBP, ctx->rbp)
|
||||||
|
X86_REG_32(X86_REG_ESI, ctx->rsi)
|
||||||
|
X86_REG_32(X86_REG_EDI, ctx->rdi)
|
||||||
|
X86_REG_32(X86_REG_R8D, ctx->r8)
|
||||||
|
X86_REG_32(X86_REG_R9D, ctx->r9)
|
||||||
|
X86_REG_32(X86_REG_R10D, ctx->r10)
|
||||||
|
X86_REG_32(X86_REG_R11D, ctx->r11)
|
||||||
|
X86_REG_32(X86_REG_R12D, ctx->r12)
|
||||||
|
X86_REG_32(X86_REG_R13D, ctx->r13)
|
||||||
|
X86_REG_32(X86_REG_R14D, ctx->r14)
|
||||||
|
X86_REG_32(X86_REG_R15D, ctx->r15)
|
||||||
|
X86_REG_32(X86_REG_EIP, ctx->rip)
|
||||||
|
|
||||||
|
X86_REG_64(X86_REG_RAX, ctx->rax)
|
||||||
|
X86_REG_64(X86_REG_RCX, ctx->rcx)
|
||||||
|
X86_REG_64(X86_REG_RDX, ctx->rdx)
|
||||||
|
X86_REG_64(X86_REG_RBX, ctx->rbx)
|
||||||
|
X86_REG_64(X86_REG_RSP, ctx->rsp)
|
||||||
|
X86_REG_64(X86_REG_RBP, ctx->rbp)
|
||||||
|
X86_REG_64(X86_REG_RSI, ctx->rsi)
|
||||||
|
X86_REG_64(X86_REG_RDI, ctx->rdi)
|
||||||
|
X86_REG_64(X86_REG_R8, ctx->r8)
|
||||||
|
X86_REG_64(X86_REG_R9, ctx->r9)
|
||||||
|
X86_REG_64(X86_REG_R10, ctx->r10)
|
||||||
|
X86_REG_64(X86_REG_R11, ctx->r11)
|
||||||
|
X86_REG_64(X86_REG_R12, ctx->r12)
|
||||||
|
X86_REG_64(X86_REG_R13, ctx->r13)
|
||||||
|
X86_REG_64(X86_REG_R14, ctx->r14)
|
||||||
|
X86_REG_64(X86_REG_R15, ctx->r15)
|
||||||
|
X86_REG_64(X86_REG_RIP, ctx->rip)
|
||||||
|
|
||||||
|
default:
|
||||||
|
FATAL("Failed to read register: %d", reg);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
81
frida_mode/src/ctx/ctx_x86.c
Normal file
81
frida_mode/src/ctx/ctx_x86.c
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#include "frida-gum.h"
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "ctx.h"
|
||||||
|
|
||||||
|
#if defined(__i386__)
|
||||||
|
|
||||||
|
#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); \
|
||||||
|
\
|
||||||
|
}
|
||||||
|
|
||||||
|
gsize ctx_read_reg(GumIA32CpuContext *ctx, x86_reg reg) {
|
||||||
|
|
||||||
|
switch (reg) {
|
||||||
|
|
||||||
|
X86_REG_8L(X86_REG_AL, ctx->eax)
|
||||||
|
X86_REG_8L(X86_REG_BL, ctx->ebx)
|
||||||
|
X86_REG_8L(X86_REG_CL, ctx->ecx)
|
||||||
|
X86_REG_8L(X86_REG_DL, ctx->edx)
|
||||||
|
X86_REG_8L(X86_REG_BPL, ctx->ebp)
|
||||||
|
X86_REG_8L(X86_REG_SIL, ctx->esi)
|
||||||
|
X86_REG_8L(X86_REG_DIL, ctx->edi)
|
||||||
|
|
||||||
|
X86_REG_8H(X86_REG_AH, ctx->eax)
|
||||||
|
X86_REG_8H(X86_REG_BH, ctx->ebx)
|
||||||
|
X86_REG_8H(X86_REG_CH, ctx->ecx)
|
||||||
|
X86_REG_8H(X86_REG_DH, ctx->edx)
|
||||||
|
|
||||||
|
X86_REG_16(X86_REG_AX, ctx->eax)
|
||||||
|
X86_REG_16(X86_REG_BX, ctx->ebx)
|
||||||
|
X86_REG_16(X86_REG_CX, ctx->ecx)
|
||||||
|
X86_REG_16(X86_REG_DX, ctx->edx)
|
||||||
|
X86_REG_16(X86_REG_DI, ctx->edi)
|
||||||
|
X86_REG_16(X86_REG_SI, ctx->esi)
|
||||||
|
X86_REG_16(X86_REG_BP, ctx->ebp)
|
||||||
|
|
||||||
|
X86_REG_32(X86_REG_EAX, ctx->eax)
|
||||||
|
X86_REG_32(X86_REG_ECX, ctx->ecx)
|
||||||
|
X86_REG_32(X86_REG_EDX, ctx->edx)
|
||||||
|
X86_REG_32(X86_REG_EBX, ctx->ebx)
|
||||||
|
X86_REG_32(X86_REG_ESP, ctx->esp)
|
||||||
|
X86_REG_32(X86_REG_EBP, ctx->ebp)
|
||||||
|
X86_REG_32(X86_REG_ESI, ctx->esi)
|
||||||
|
X86_REG_32(X86_REG_EDI, ctx->edi)
|
||||||
|
X86_REG_32(X86_REG_EIP, ctx->eip)
|
||||||
|
|
||||||
|
default:
|
||||||
|
FATAL("Failed to read register: %d", reg);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -5,6 +5,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "asan.h"
|
||||||
#include "entry.h"
|
#include "entry.h"
|
||||||
#include "frida_cmplog.h"
|
#include "frida_cmplog.h"
|
||||||
#include "instrument.h"
|
#include "instrument.h"
|
||||||
@ -33,7 +34,7 @@ __attribute__((hot)) static void on_basic_block(GumCpuContext *context,
|
|||||||
*/
|
*/
|
||||||
static char buffer[200];
|
static char buffer[200];
|
||||||
int len;
|
int len;
|
||||||
guint64 current_pc = (guint64)user_data;
|
GumAddress current_pc = GUM_ADDRESS(user_data);
|
||||||
uint8_t * cursor;
|
uint8_t * cursor;
|
||||||
uint64_t value;
|
uint64_t value;
|
||||||
if (unlikely(tracing)) {
|
if (unlikely(tracing)) {
|
||||||
@ -85,8 +86,8 @@ static void instr_basic_block(GumStalkerIterator *iterator,
|
|||||||
|
|
||||||
if (begin) {
|
if (begin) {
|
||||||
|
|
||||||
prefetch_write((void *)instr->address);
|
prefetch_write(GSIZE_TO_POINTER(instr->address));
|
||||||
if (!range_is_excluded((void *)instr->address)) {
|
if (!range_is_excluded(GSIZE_TO_POINTER(instr->address))) {
|
||||||
|
|
||||||
if (optimize) {
|
if (optimize) {
|
||||||
|
|
||||||
@ -94,8 +95,8 @@ static void instr_basic_block(GumStalkerIterator *iterator,
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
gum_stalker_iterator_put_callout(iterator, on_basic_block,
|
gum_stalker_iterator_put_callout(
|
||||||
(gpointer)instr->address, NULL);
|
iterator, on_basic_block, GSIZE_TO_POINTER(instr->address), NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,8 +106,9 @@ static void instr_basic_block(GumStalkerIterator *iterator,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!range_is_excluded((void *)instr->address)) {
|
if (!range_is_excluded(GSIZE_TO_POINTER(instr->address))) {
|
||||||
|
|
||||||
|
asan_instrument(instr, iterator);
|
||||||
cmplog_instrument(instr, iterator);
|
cmplog_instrument(instr, iterator);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -142,6 +144,7 @@ void instrument_init(void) {
|
|||||||
transformer =
|
transformer =
|
||||||
gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL);
|
gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL);
|
||||||
|
|
||||||
|
asan_init();
|
||||||
cmplog_init();
|
cmplog_init();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
#include "instrument.h"
|
#include "instrument.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#if defined(__arm__)
|
#if defined(__arm__)
|
||||||
|
|
||||||
@ -15,6 +16,8 @@ gboolean instrument_is_coverage_optimize_supported(void) {
|
|||||||
void instrument_coverage_optimize(const cs_insn * instr,
|
void instrument_coverage_optimize(const cs_insn * instr,
|
||||||
GumStalkerOutput *output) {
|
GumStalkerOutput *output) {
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(instr);
|
||||||
|
UNUSED_PARAMETER(output);
|
||||||
FATAL("Optimized coverage not supported on this architecture");
|
FATAL("Optimized coverage not supported on this architecture");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,81 @@
|
|||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
#include "instrument.h"
|
#include "instrument.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
|
|
||||||
|
static GumAddress current_log_impl = GUM_ADDRESS(0);
|
||||||
|
|
||||||
|
static void instrument_coverage_function(GumX86Writer *cw) {
|
||||||
|
|
||||||
|
gum_x86_writer_put_pushfx(cw);
|
||||||
|
gum_x86_writer_put_push_reg(cw, GUM_REG_ECX);
|
||||||
|
gum_x86_writer_put_push_reg(cw, GUM_REG_EDX);
|
||||||
|
|
||||||
|
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_ECX,
|
||||||
|
GUM_ADDRESS(&previous_pc));
|
||||||
|
gum_x86_writer_put_mov_reg_reg_ptr(cw, GUM_REG_EDX, GUM_REG_ECX);
|
||||||
|
gum_x86_writer_put_xor_reg_reg(cw, GUM_REG_EDX, GUM_REG_EDI);
|
||||||
|
|
||||||
|
gum_x86_writer_put_add_reg_imm(cw, GUM_REG_EDX, GUM_ADDRESS(__afl_area_ptr));
|
||||||
|
|
||||||
|
/* add byte ptr [edx], 1 */
|
||||||
|
uint8_t add_byte_ptr_edx_1[] = {0x80, 0x02, 0x01};
|
||||||
|
gum_x86_writer_put_bytes(cw, add_byte_ptr_edx_1, sizeof(add_byte_ptr_edx_1));
|
||||||
|
|
||||||
|
/* adc byte ptr [edx], 0 */
|
||||||
|
uint8_t adc_byte_ptr_edx_0[] = {0x80, 0x12, 0x00};
|
||||||
|
gum_x86_writer_put_bytes(cw, adc_byte_ptr_edx_0, sizeof(adc_byte_ptr_edx_0));
|
||||||
|
|
||||||
|
gum_x86_writer_put_shr_reg_u8(cw, GUM_REG_EDI, 1);
|
||||||
|
gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_REG_ECX, GUM_REG_EDI);
|
||||||
|
|
||||||
|
gum_x86_writer_put_pop_reg(cw, GUM_REG_EDX);
|
||||||
|
gum_x86_writer_put_pop_reg(cw, GUM_REG_ECX);
|
||||||
|
gum_x86_writer_put_popfx(cw);
|
||||||
|
gum_x86_writer_put_ret(cw);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
gboolean instrument_is_coverage_optimize_supported(void) {
|
gboolean instrument_is_coverage_optimize_supported(void) {
|
||||||
|
|
||||||
return false;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void instrument_coverage_optimize(const cs_insn * instr,
|
void instrument_coverage_optimize(const cs_insn * instr,
|
||||||
GumStalkerOutput *output) {
|
GumStalkerOutput *output) {
|
||||||
|
|
||||||
FATAL("Optimized coverage not supported on this architecture");
|
UNUSED_PARAMETER(instr);
|
||||||
|
UNUSED_PARAMETER(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;
|
||||||
|
instrument_coverage_function(cw);
|
||||||
|
|
||||||
|
gum_x86_writer_put_label(cw, after_log_impl);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// gum_x86_writer_put_breakpoint(cw);
|
||||||
|
gum_x86_writer_put_push_reg(cw, GUM_REG_EDI);
|
||||||
|
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EDI, area_offset);
|
||||||
|
gum_x86_writer_put_call_address(cw, current_log_impl);
|
||||||
|
gum_x86_writer_put_pop_reg(cw, GUM_REG_EDI);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +90,8 @@ static void lib_read_text_section(lib_details_t *lib_details, Elf_Ehdr *hdr) {
|
|||||||
|
|
||||||
if (!found_preferred_base) { FATAL("Failed to find preferred load address"); }
|
if (!found_preferred_base) { FATAL("Failed to find preferred load address"); }
|
||||||
|
|
||||||
OKF("Image preferred load address 0x%016lx", preferred_base);
|
OKF("Image preferred load address 0x%016" G_GSIZE_MODIFIER "x",
|
||||||
|
preferred_base);
|
||||||
|
|
||||||
shdr = (Elf_Shdr *)((char *)hdr + hdr->e_shoff);
|
shdr = (Elf_Shdr *)((char *)hdr + hdr->e_shoff);
|
||||||
shstrtab = &shdr[hdr->e_shstrndx];
|
shstrtab = &shdr[hdr->e_shstrndx];
|
||||||
@ -107,15 +108,16 @@ static void lib_read_text_section(lib_details_t *lib_details, Elf_Ehdr *hdr) {
|
|||||||
if (curr->sh_name == 0) continue;
|
if (curr->sh_name == 0) continue;
|
||||||
|
|
||||||
section_name = &shstr[curr->sh_name];
|
section_name = &shstr[curr->sh_name];
|
||||||
OKF("Section: %2lu - base: 0x%016lX size: 0x%016lX %s", i, curr->sh_addr,
|
OKF("Section: %2" G_GSIZE_MODIFIER "u - base: 0x%016" G_GSIZE_MODIFIER
|
||||||
curr->sh_size, section_name);
|
"X size: 0x%016" G_GSIZE_MODIFIER "X %s",
|
||||||
|
i, curr->sh_addr, curr->sh_size, section_name);
|
||||||
if (memcmp(section_name, text_name, sizeof(text_name)) == 0 &&
|
if (memcmp(section_name, text_name, sizeof(text_name)) == 0 &&
|
||||||
text_base == 0) {
|
text_base == 0) {
|
||||||
|
|
||||||
text_base = lib_details->base_address + curr->sh_addr - preferred_base;
|
text_base = lib_details->base_address + curr->sh_addr - preferred_base;
|
||||||
text_limit = text_base + curr->sh_size;
|
text_limit = text_base + curr->sh_size;
|
||||||
OKF("> text_addr: 0x%016lX", text_base);
|
OKF("> text_addr: 0x%016" G_GINT64_MODIFIER "X", text_base);
|
||||||
OKF("> text_limit: 0x%016lX", text_limit);
|
OKF("> text_limit: 0x%016" G_GINT64_MODIFIER "X", text_limit);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +155,8 @@ void lib_init(void) {
|
|||||||
|
|
||||||
lib_details_t lib_details;
|
lib_details_t lib_details;
|
||||||
gum_process_enumerate_modules(lib_find_exe, &lib_details);
|
gum_process_enumerate_modules(lib_find_exe, &lib_details);
|
||||||
OKF("Executable: 0x%016lx - %s", lib_details.base_address, lib_details.path);
|
OKF("Executable: 0x%016" G_GINT64_MODIFIER "x - %s", lib_details.base_address,
|
||||||
|
lib_details.path);
|
||||||
lib_get_text_section(&lib_details);
|
lib_get_text_section(&lib_details);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -75,16 +75,22 @@ static void on_main_os(int argc, char **argv, char **envp) {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int *on_main(int argc, char **argv, char **envp) {
|
static void embedded_init() {
|
||||||
|
|
||||||
void *fork_addr;
|
static gboolean initialized = false;
|
||||||
|
if (!initialized) {
|
||||||
|
|
||||||
on_main_os(argc, argv, envp);
|
gum_init_embedded();
|
||||||
|
initialized = true;
|
||||||
|
|
||||||
unintercept_self();
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void afl_frida_start() {
|
||||||
|
|
||||||
|
embedded_init();
|
||||||
stalker_init();
|
stalker_init();
|
||||||
|
|
||||||
lib_init();
|
lib_init();
|
||||||
entry_init();
|
entry_init();
|
||||||
instrument_init();
|
instrument_init();
|
||||||
@ -92,12 +98,23 @@ static int *on_main(int argc, char **argv, char **envp) {
|
|||||||
prefetch_init();
|
prefetch_init();
|
||||||
ranges_init();
|
ranges_init();
|
||||||
|
|
||||||
fork_addr = GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork"));
|
void *fork_addr =
|
||||||
|
GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork"));
|
||||||
intercept(fork_addr, on_fork, NULL);
|
intercept(fork_addr, on_fork, NULL);
|
||||||
|
|
||||||
stalker_start();
|
stalker_start();
|
||||||
entry_run();
|
entry_run();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int *on_main(int argc, char **argv, char **envp) {
|
||||||
|
|
||||||
|
on_main_os(argc, argv, envp);
|
||||||
|
|
||||||
|
unintercept_self();
|
||||||
|
|
||||||
|
afl_frida_start();
|
||||||
|
|
||||||
return main_fn(argc, argv, envp);
|
return main_fn(argc, argv, envp);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -149,13 +166,7 @@ static void intercept_main(void) {
|
|||||||
|
|
||||||
__attribute__((constructor)) static void init(void) {
|
__attribute__((constructor)) static void init(void) {
|
||||||
|
|
||||||
gum_init_embedded();
|
embedded_init();
|
||||||
if (!gum_stalker_is_supported()) {
|
|
||||||
|
|
||||||
gum_deinit_embedded();
|
|
||||||
FATAL("Failed to initialize embedded");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
intercept_main();
|
intercept_main();
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#include "frida-gum.h"
|
#include "frida-gum.h"
|
||||||
|
|
||||||
#include "debug.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "instrument.h"
|
||||||
#include "persistent.h"
|
#include "persistent.h"
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
|
|
||||||
@ -38,16 +38,239 @@ struct x86_regs {
|
|||||||
|
|
||||||
typedef struct x86_regs arch_api_regs;
|
typedef struct x86_regs arch_api_regs;
|
||||||
|
|
||||||
|
static arch_api_regs saved_regs = {0};
|
||||||
|
static void * saved_return = NULL;
|
||||||
|
|
||||||
gboolean persistent_is_supported(void) {
|
gboolean persistent_is_supported(void) {
|
||||||
|
|
||||||
return false;
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void instrument_persitent_save_regs(GumX86Writer * cw,
|
||||||
|
struct x86_regs *regs) {
|
||||||
|
|
||||||
|
GumAddress regs_address = GUM_ADDRESS(regs);
|
||||||
|
|
||||||
|
/* Should be pushing FPU here, but meh */
|
||||||
|
gum_x86_writer_put_pushfx(cw);
|
||||||
|
gum_x86_writer_put_push_reg(cw, GUM_REG_EAX);
|
||||||
|
|
||||||
|
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, regs_address);
|
||||||
|
|
||||||
|
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 1),
|
||||||
|
GUM_REG_EBX);
|
||||||
|
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 2),
|
||||||
|
GUM_REG_ECX);
|
||||||
|
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 3),
|
||||||
|
GUM_REG_EDX);
|
||||||
|
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 4),
|
||||||
|
GUM_REG_EDI);
|
||||||
|
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 5),
|
||||||
|
GUM_REG_ESI);
|
||||||
|
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 6),
|
||||||
|
GUM_REG_EBP);
|
||||||
|
|
||||||
|
/* Store RIP */
|
||||||
|
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EBX,
|
||||||
|
GUM_ADDRESS(persistent_start));
|
||||||
|
|
||||||
|
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 7),
|
||||||
|
GUM_REG_EBX);
|
||||||
|
|
||||||
|
/* Store adjusted RSP */
|
||||||
|
gum_x86_writer_put_mov_reg_reg(cw, GUM_REG_EBX, GUM_REG_ESP);
|
||||||
|
|
||||||
|
/* RED_ZONE + Saved flags, RAX */
|
||||||
|
gum_x86_writer_put_add_reg_imm(cw, GUM_REG_EBX, (0x4 * 2));
|
||||||
|
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 8),
|
||||||
|
GUM_REG_EBX);
|
||||||
|
|
||||||
|
/* Save the flags */
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, 0x4);
|
||||||
|
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 9),
|
||||||
|
GUM_REG_EBX);
|
||||||
|
|
||||||
|
/* Save the RAX */
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, 0x0);
|
||||||
|
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 0),
|
||||||
|
GUM_REG_EBX);
|
||||||
|
|
||||||
|
/* Pop the saved values */
|
||||||
|
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, 0x8);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void instrument_persitent_restore_regs(GumX86Writer * cw,
|
||||||
|
struct x86_regs *regs) {
|
||||||
|
|
||||||
|
GumAddress regs_address = GUM_ADDRESS(regs);
|
||||||
|
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, regs_address);
|
||||||
|
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_EAX,
|
||||||
|
(0x4 * 2));
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDX, GUM_REG_EAX,
|
||||||
|
(0x4 * 3));
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDI, GUM_REG_EAX,
|
||||||
|
(0x4 * 4));
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ESI, GUM_REG_EAX,
|
||||||
|
(0x4 * 5));
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBP, GUM_REG_EAX,
|
||||||
|
(0x4 * 6));
|
||||||
|
|
||||||
|
/* Don't restore RIP or RSP */
|
||||||
|
|
||||||
|
/* Restore RBX, RAX & Flags */
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX,
|
||||||
|
(0x4 * 1));
|
||||||
|
gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
|
||||||
|
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX,
|
||||||
|
(0x4 * 0));
|
||||||
|
gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX,
|
||||||
|
(0x4 * 9));
|
||||||
|
gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
|
||||||
|
|
||||||
|
gum_x86_writer_put_popfx(cw);
|
||||||
|
gum_x86_writer_put_pop_reg(cw, GUM_REG_EAX);
|
||||||
|
gum_x86_writer_put_pop_reg(cw, GUM_REG_EBX);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void instrument_save_ret(GumX86Writer *cw, void **saved_return_ptr) {
|
||||||
|
|
||||||
|
GumAddress saved_return_address = GUM_ADDRESS(saved_return_ptr);
|
||||||
|
|
||||||
|
gum_x86_writer_put_push_reg(cw, GUM_REG_EAX);
|
||||||
|
gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
|
||||||
|
|
||||||
|
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, saved_return_address);
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, 0x8);
|
||||||
|
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, 0, GUM_REG_EBX);
|
||||||
|
|
||||||
|
gum_x86_writer_put_pop_reg(cw, GUM_REG_EBX);
|
||||||
|
gum_x86_writer_put_pop_reg(cw, GUM_REG_EAX);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void instrument_jump_ret(GumX86Writer *cw, void **saved_return_ptr) {
|
||||||
|
|
||||||
|
GumAddress saved_return_address = GUM_ADDRESS(saved_return_ptr);
|
||||||
|
|
||||||
|
/* Place holder for ret */
|
||||||
|
gum_x86_writer_put_push_reg(cw, GUM_REG_EAX);
|
||||||
|
gum_x86_writer_put_push_reg(cw, GUM_REG_EAX);
|
||||||
|
|
||||||
|
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, saved_return_address);
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EAX, GUM_REG_EAX, 0);
|
||||||
|
|
||||||
|
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_ESP, 0x4, GUM_REG_EAX);
|
||||||
|
gum_x86_writer_put_pop_reg(cw, GUM_REG_EAX);
|
||||||
|
gum_x86_writer_put_ret(cw);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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_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_EAX, GUM_REG_EAX);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void persistent_prologue_hook(GumX86Writer *cw, struct x86_regs *regs) {
|
||||||
|
|
||||||
|
if (hook == NULL) return;
|
||||||
|
|
||||||
|
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_ECX,
|
||||||
|
GUM_ADDRESS(&__afl_fuzz_len));
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_ECX, 0);
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_ECX, 0);
|
||||||
|
|
||||||
|
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EDX,
|
||||||
|
GUM_ADDRESS(&__afl_fuzz_ptr));
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDX, GUM_REG_EDX, 0);
|
||||||
|
|
||||||
|
/* Base address is 64-bits (hence two zero arguments) */
|
||||||
|
gum_x86_writer_put_call_address_with_arguments(
|
||||||
|
cw, GUM_CALL_CAPI, GUM_ADDRESS(hook), 5, GUM_ARG_ADDRESS,
|
||||||
|
GUM_ADDRESS(regs), GUM_ARG_ADDRESS, GUM_ADDRESS(0), GUM_ARG_ADDRESS,
|
||||||
|
GUM_ADDRESS(0), GUM_ARG_REGISTER, GUM_REG_EDX, GUM_ARG_REGISTER,
|
||||||
|
GUM_REG_ECX);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void persistent_prologue(GumStalkerOutput *output) {
|
void persistent_prologue(GumStalkerOutput *output) {
|
||||||
|
|
||||||
UNUSED_PARAMETER(output);
|
/*
|
||||||
FATAL("Persistent mode not supported on this architecture");
|
* 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;
|
||||||
|
|
||||||
|
/* 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_ESP, GUM_REG_ESP, (4));
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@ static GumStalker *stalker = NULL;
|
|||||||
|
|
||||||
void stalker_init(void) {
|
void stalker_init(void) {
|
||||||
|
|
||||||
|
if (!gum_stalker_is_supported()) { FATAL("Failed to initialize embedded"); }
|
||||||
|
|
||||||
stalker = gum_stalker_new();
|
stalker = gum_stalker_new();
|
||||||
if (stalker == NULL) { FATAL("Failed to initialize stalker"); }
|
if (stalker == NULL) { FATAL("Failed to initialize stalker"); }
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@ PWD:=$(shell pwd)/
|
|||||||
ROOT:=$(shell realpath $(PWD)../../../)/
|
ROOT:=$(shell realpath $(PWD)../../../)/
|
||||||
BUILD_DIR:=$(PWD)build/
|
BUILD_DIR:=$(PWD)build/
|
||||||
|
|
||||||
TEST_CMPLOG_DIR:=$(ROOT)qemu_mode/libcompcov/
|
TEST_CMPLOG_SRC=$(PWD)cmplog.c
|
||||||
TEST_CMPLOG_OBJ=$(TEST_CMPLOG_DIR)compcovtest
|
TEST_CMPLOG_OBJ=$(BUILD_DIR)compcovtest
|
||||||
|
|
||||||
TEST_BIN:=$(PWD)../../build/test
|
TEST_BIN:=$(PWD)../../build/test
|
||||||
|
|
||||||
@ -13,20 +13,14 @@ CMP_LOG_INPUT:=$(TEST_DATA_DIR)in
|
|||||||
QEMU_OUT:=$(BUILD_DIR)qemu-out
|
QEMU_OUT:=$(BUILD_DIR)qemu-out
|
||||||
FRIDA_OUT:=$(BUILD_DIR)frida-out
|
FRIDA_OUT:=$(BUILD_DIR)frida-out
|
||||||
|
|
||||||
ARCH=$(shell uname -m)
|
.PHONY: all 32 clean qemu frida format
|
||||||
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"
|
all: $(TEST_CMPLOG_OBJ)
|
||||||
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/
|
make -C $(ROOT)frida_mode/
|
||||||
|
|
||||||
|
32:
|
||||||
|
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||||
|
|
||||||
$(BUILD_DIR):
|
$(BUILD_DIR):
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
|
|
||||||
@ -34,33 +28,42 @@ $(TEST_DATA_DIR): | $(BUILD_DIR)
|
|||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
|
|
||||||
$(CMP_LOG_INPUT): | $(TEST_DATA_DIR)
|
$(CMP_LOG_INPUT): | $(TEST_DATA_DIR)
|
||||||
truncate -s 64 $@
|
echo -n "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" > $@
|
||||||
|
|
||||||
$(TEST_CMPLOG_OBJ): $(TEST_CMPLOG_DIR)compcovtest.cc
|
$(TEST_CMPLOG_OBJ): $(TEST_CMPLOG_SRC) | $(BUILD_DIR)
|
||||||
make -C $(TEST_CMPLOG_DIR) compcovtest
|
$(CXX) -std=c++11 -g $(CFLAGS) $(LDFLAGS) $< -o $@
|
||||||
|
|
||||||
qemu: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT)
|
qemu: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT)
|
||||||
$(ROOT)afl-fuzz \
|
$(ROOT)afl-fuzz \
|
||||||
-D \
|
|
||||||
-Q \
|
-Q \
|
||||||
-i $(TEST_DATA_DIR) \
|
-i $(TEST_DATA_DIR) \
|
||||||
-o $(QEMU_OUT) \
|
-o $(QEMU_OUT) \
|
||||||
-c 0 \
|
-c 0 \
|
||||||
-l 3AT \
|
-l 3AT \
|
||||||
|
-Z \
|
||||||
-- \
|
-- \
|
||||||
$(TEST_CMPLOG_OBJ) @@
|
$(TEST_CMPLOG_OBJ) @@
|
||||||
|
|
||||||
frida: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT)
|
frida: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT)
|
||||||
XAFL_FRIDA_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \
|
|
||||||
$(ROOT)afl-fuzz \
|
$(ROOT)afl-fuzz \
|
||||||
-D \
|
|
||||||
-O \
|
-O \
|
||||||
-i $(TEST_DATA_DIR) \
|
-i $(TEST_DATA_DIR) \
|
||||||
-o $(FRIDA_OUT) \
|
-o $(FRIDA_OUT) \
|
||||||
-c 0 \
|
-c 0 \
|
||||||
-l 3AT \
|
-l 3AT \
|
||||||
|
-Z \
|
||||||
-- \
|
-- \
|
||||||
$(TEST_CMPLOG_OBJ) @@
|
$(TEST_CMPLOG_OBJ) @@
|
||||||
|
|
||||||
|
debug: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT)
|
||||||
|
gdb \
|
||||||
|
--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
|
||||||
|
--ex 'set disassembly-flavor intel' \
|
||||||
|
--ex 'r $(CMP_LOG_INPUT)' \
|
||||||
|
--args $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(BUILD_DIR)
|
rm -rf $(BUILD_DIR)
|
||||||
|
|
||||||
|
format:
|
||||||
|
cd $(ROOT) && echo $(TEST_CMPLOG_SRC) | xargs -L1 ./.custom-format.py -i
|
||||||
|
@ -2,6 +2,10 @@ all:
|
|||||||
@echo trying to use GNU make...
|
@echo trying to use GNU make...
|
||||||
@gmake all || echo please install GNUmake
|
@gmake all || echo please install GNUmake
|
||||||
|
|
||||||
|
32:
|
||||||
|
@echo trying to use GNU make...
|
||||||
|
@gmake 32 || echo please install GNUmake
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@gmake clean
|
@gmake clean
|
||||||
|
|
||||||
@ -10,3 +14,9 @@ qemu:
|
|||||||
|
|
||||||
frida:
|
frida:
|
||||||
@gmake frida
|
@gmake frida
|
||||||
|
|
||||||
|
format:
|
||||||
|
@gmake format
|
||||||
|
|
||||||
|
debug:
|
||||||
|
@gmake debug
|
||||||
|
100
frida_mode/test/cmplog/cmplog.c
Normal file
100
frida_mode/test/cmplog/cmplog.c
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Author: Mateusz Jurczyk (mjurczyk@google.com)
|
||||||
|
//
|
||||||
|
// Copyright 2019-2020 Google LLC
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
// solution: echo -ne 'The quick brown fox jumps over the lazy
|
||||||
|
// dog\xbe\xba\xfe\xca\xbe\xba\xfe\xca\xde\xc0\xad\xde\xef\xbe' | ./compcovtest
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
char buffer[44] = {/* zero padding */};
|
||||||
|
|
||||||
|
FILE *file = stdin;
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
|
||||||
|
if ((file = fopen(argv[1], "r")) == NULL) {
|
||||||
|
|
||||||
|
perror(argv[1]);
|
||||||
|
exit(-1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fread(buffer, 1, sizeof(buffer) - 1, file);
|
||||||
|
|
||||||
|
if (memcmp(&buffer[0], "The quick brown fox ", 20) != 0 ||
|
||||||
|
strncmp(&buffer[20], "jumps over ", 11) != 0 ||
|
||||||
|
strcmp(&buffer[31], "the lazy dog") != 0) {
|
||||||
|
|
||||||
|
if (argc > 1) { fclose(file); }
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
uint64_t x = 0;
|
||||||
|
fread(&x, sizeof(x), 1, file);
|
||||||
|
if (x != 0xCAFEBABECAFEBABE) {
|
||||||
|
|
||||||
|
if (argc > 1) { fclose(file); }
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t y = 0;
|
||||||
|
fread(&y, sizeof(y), 1, file);
|
||||||
|
|
||||||
|
if (y != 0xDEADC0DE) {
|
||||||
|
|
||||||
|
if (argc > 1) { fclose(file); }
|
||||||
|
return 3;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t z = 0;
|
||||||
|
fread(&z, sizeof(z), 1, file);
|
||||||
|
|
||||||
|
switch (z) {
|
||||||
|
|
||||||
|
case 0xBEEF:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (argc > 1) { fclose(file); }
|
||||||
|
return 4;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Puzzle solved, congrats!\n");
|
||||||
|
abort();
|
||||||
|
|
||||||
|
if (argc > 1) { fclose(file); }
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,18 @@ FRIDA_OUT:=$(BUILD_DIR)frida-out
|
|||||||
|
|
||||||
GET_SYMBOL_ADDR:=$(ROOT)frida_mode/test/png/persistent/get_symbol_addr.py
|
GET_SYMBOL_ADDR:=$(ROOT)frida_mode/test/png/persistent/get_symbol_addr.py
|
||||||
|
|
||||||
|
ifndef ARCH
|
||||||
|
|
||||||
|
ARCH=$(shell uname -m)
|
||||||
|
ifeq "$(ARCH)" "aarch64"
|
||||||
|
ARCH:=arm64
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq "$(ARCH)" "i686"
|
||||||
|
ARCH:=x86
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
ARCH=$(shell uname -m)
|
ARCH=$(shell uname -m)
|
||||||
ifeq "$(ARCH)" "aarch64"
|
ifeq "$(ARCH)" "aarch64"
|
||||||
AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000aaaaaaaaa000)
|
AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000aaaaaaaaa000)
|
||||||
@ -21,11 +33,18 @@ ifeq "$(ARCH)" "x86_64"
|
|||||||
AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000555555554000)
|
AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000555555554000)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq "$(ARCH)" "x86"
|
||||||
|
AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x56555000)
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: all clean qemu frida
|
.PHONY: all clean qemu frida
|
||||||
|
|
||||||
all: $(TESTINSTBIN)
|
all: $(TESTINSTBIN)
|
||||||
make -C $(ROOT)frida_mode/
|
make -C $(ROOT)frida_mode/
|
||||||
|
|
||||||
|
32:
|
||||||
|
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||||
|
|
||||||
$(BUILD_DIR):
|
$(BUILD_DIR):
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
|
|
||||||
@ -36,7 +55,7 @@ $(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR)
|
|||||||
echo -n "000" > $@
|
echo -n "000" > $@
|
||||||
|
|
||||||
$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR)
|
$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR)
|
||||||
$(CC) -o $@ $<
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(BUILD_DIR)
|
rm -rf $(BUILD_DIR)
|
||||||
|
@ -2,6 +2,10 @@ all:
|
|||||||
@echo trying to use GNU make...
|
@echo trying to use GNU make...
|
||||||
@gmake all || echo please install GNUmake
|
@gmake all || echo please install GNUmake
|
||||||
|
|
||||||
|
32:
|
||||||
|
@echo trying to use GNU make...
|
||||||
|
@gmake 32 || echo please install GNUmake
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@gmake clean
|
@gmake clean
|
||||||
|
|
||||||
|
@ -106,7 +106,9 @@ int run(char *file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void slow() {
|
void slow() {
|
||||||
|
|
||||||
usleep(100000);
|
usleep(100000);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
@ -10,11 +10,14 @@ TESTINSTSRC:=$(PWD)testinstr.c
|
|||||||
QEMU_OUT:=$(BUILD_DIR)qemu-out
|
QEMU_OUT:=$(BUILD_DIR)qemu-out
|
||||||
FRIDA_OUT:=$(BUILD_DIR)frida-out
|
FRIDA_OUT:=$(BUILD_DIR)frida-out
|
||||||
|
|
||||||
.PHONY: all clean qemu frida
|
.PHONY: all 32 clean qemu frida
|
||||||
|
|
||||||
all: $(TESTINSTBIN)
|
all: $(TESTINSTBIN)
|
||||||
make -C $(ROOT)frida_mode/
|
make -C $(ROOT)frida_mode/
|
||||||
|
|
||||||
|
32:
|
||||||
|
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||||
|
|
||||||
$(BUILD_DIR):
|
$(BUILD_DIR):
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
|
|
||||||
@ -25,7 +28,7 @@ $(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR)
|
|||||||
echo -n "000" > $@
|
echo -n "000" > $@
|
||||||
|
|
||||||
$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR)
|
$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR)
|
||||||
$(CC) -o $@ $< -no-pie
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -no-pie
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(BUILD_DIR)
|
rm -rf $(BUILD_DIR)
|
||||||
|
@ -2,6 +2,10 @@ all:
|
|||||||
@echo trying to use GNU make...
|
@echo trying to use GNU make...
|
||||||
@gmake all || echo please install GNUmake
|
@gmake all || echo please install GNUmake
|
||||||
|
|
||||||
|
32:
|
||||||
|
@echo trying to use GNU make...
|
||||||
|
@gmake 32 || echo please install GNUmake
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@gmake clean
|
@gmake clean
|
||||||
|
|
||||||
|
159
frida_mode/test/fasan/GNUmakefile
Normal file
159
frida_mode/test/fasan/GNUmakefile
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
PWD:=$(shell pwd)/
|
||||||
|
ROOT:=$(shell realpath $(PWD)../../..)/
|
||||||
|
BUILD_DIR:=$(PWD)build/
|
||||||
|
|
||||||
|
TEST_DATA_DIR:=$(BUILD_DIR)in/
|
||||||
|
TEST_DATA_FILE:=$(TEST_DATA_DIR)in
|
||||||
|
FRIDA_OUT:=$(BUILD_DIR)frida-out
|
||||||
|
|
||||||
|
TEST_SRC:=$(PWD)/test.c
|
||||||
|
TEST_BIN:=$(BUILD_DIR)test
|
||||||
|
|
||||||
|
CFLAGS+=-fPIC \
|
||||||
|
-D_GNU_SOURCE \
|
||||||
|
-g \
|
||||||
|
-fno-omit-frame-pointer \
|
||||||
|
-Wno-stringop-overflow \
|
||||||
|
|
||||||
|
LDFLAGS+=-ldl \
|
||||||
|
|
||||||
|
ifdef DEBUG
|
||||||
|
CFLAGS+=-Werror \
|
||||||
|
-Wall \
|
||||||
|
-Wextra \
|
||||||
|
-Wpointer-arith
|
||||||
|
else
|
||||||
|
CFLAGS+=-Wno-pointer-arith
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef ARCH
|
||||||
|
|
||||||
|
ARCH=$(shell uname -m)
|
||||||
|
ifeq "$(ARCH)" "aarch64"
|
||||||
|
ARCH:=arm64
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq "$(ARCH)" "i686"
|
||||||
|
ARCH:=x86
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq "$(ARCH)" "x86"
|
||||||
|
LIBASAN_FILE:=libclang_rt.asan-i386.so
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq "$(ARCH)" "x86_64"
|
||||||
|
LIBASAN_FILE:=libclang_rt.asan-x86_64.so
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq "$(ARCH)" "aarch64"
|
||||||
|
LIBASAN_FILE:=libclang_rt.asan-aarch64.so
|
||||||
|
endif
|
||||||
|
|
||||||
|
# LIBASAN:=/usr/lib/llvm-10/lib/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.so
|
||||||
|
# LIBASAN:=/usr/lib/x86_64-linux-gnu/libasan.so.6.0.0
|
||||||
|
|
||||||
|
LLVM_CONFIG ?= llvm-config
|
||||||
|
ifeq "$(shell test -e '$(shell which $(LLVM_CONFIG))' && echo 1)" "1"
|
||||||
|
$(info Found llvm-config: '$(shell which $(LLVM_CONFIG))')
|
||||||
|
else
|
||||||
|
$(warning Cannot find llvm-config)
|
||||||
|
endif
|
||||||
|
|
||||||
|
LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)/
|
||||||
|
$(info LLVM_BINDIR: $(LLVM_BINDIR))
|
||||||
|
|
||||||
|
CLANG ?= $(LLVM_BINDIR)clang
|
||||||
|
ifeq "$(shell test -e '$(CLANG)' && echo 1)" "1"
|
||||||
|
$(info Found clang: '$(CLANG)')
|
||||||
|
else
|
||||||
|
$(warning Cannot find clang)
|
||||||
|
endif
|
||||||
|
|
||||||
|
CLANGVER = $(shell $(CLANG) --version | sed -E -ne '/^.*version\ (1?[0-9]\.[0-9]\.[0-9]).*/s//\1/p')
|
||||||
|
$(info Clang version $(CLANGVER))
|
||||||
|
|
||||||
|
LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
|
||||||
|
$(info LLVM_LIBDIR: $(LLVM_LIBDIR))
|
||||||
|
|
||||||
|
LIBASAN:=$(LLVM_LIBDIR)/clang/$(CLANGVER)/lib/linux/$(LIBASAN_FILE)
|
||||||
|
|
||||||
|
ifeq "$(shell test -e '$(LIBASAN)' && echo 1)" "1"
|
||||||
|
$(info Found Address Sanitizer DSO: '$(LIBASAN)')
|
||||||
|
else
|
||||||
|
$(error Error cannot find Address Sanitizer DSO)
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: all 32 clean format frida-noasan frida debug run
|
||||||
|
|
||||||
|
############################## ALL #############################################
|
||||||
|
|
||||||
|
all: $(TEST_BIN)
|
||||||
|
|
||||||
|
32:
|
||||||
|
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||||
|
|
||||||
|
$(TEST_BIN): $(TEST_SRC) GNUmakefile | $(BUILD_DIR)
|
||||||
|
$(CC) \
|
||||||
|
$(CFLAGS) \
|
||||||
|
$(LDFLAGS) \
|
||||||
|
-o $@ \
|
||||||
|
$<
|
||||||
|
|
||||||
|
$(BUILD_DIR):
|
||||||
|
mkdir -p $(BUILD_DIR)
|
||||||
|
|
||||||
|
############################# TESTS ############################################
|
||||||
|
|
||||||
|
$(TEST_DATA_DIR): | $(BUILD_DIR)
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
$(TEST_DATA_FILE): | $(TEST_DATA_DIR)
|
||||||
|
echo -n "TUODATM" > $@
|
||||||
|
|
||||||
|
frida-noasan: $(TEST_BIN) $(TEST_DATA_FILE)
|
||||||
|
$(ROOT)afl-fuzz \
|
||||||
|
-D \
|
||||||
|
-O \
|
||||||
|
-i $(TEST_DATA_DIR) \
|
||||||
|
-o $(FRIDA_OUT) \
|
||||||
|
-- \
|
||||||
|
$(TEST_BIN)
|
||||||
|
|
||||||
|
|
||||||
|
frida: $(TEST_BIN) $(TEST_DATA_FILE)
|
||||||
|
AFL_PRELOAD=$(LIBASAN) \
|
||||||
|
AFL_USE_FASAN=1 \
|
||||||
|
$(ROOT)afl-fuzz \
|
||||||
|
-D \
|
||||||
|
-O \
|
||||||
|
-i $(TEST_DATA_DIR) \
|
||||||
|
-o $(FRIDA_OUT) \
|
||||||
|
-- \
|
||||||
|
$(TEST_BIN)
|
||||||
|
|
||||||
|
debug: $(TEST_BIN) $(TEST_DATA_FILE)
|
||||||
|
gdb \
|
||||||
|
--ex 'set environment LD_PRELOAD=$(LIBASAN):$(ROOT)afl-frida-trace.so' \
|
||||||
|
--ex 'set environment ASAN_OPTIONS=detect_leaks=false,halt_on_error=0' \
|
||||||
|
--ex 'set environment AFL_USE_FASAN=1' \
|
||||||
|
--ex 'set disassembly-flavor intel' \
|
||||||
|
--ex 'r < $(TEST_DATA_FILE)' \
|
||||||
|
--args $(TEST_BIN) \
|
||||||
|
|
||||||
|
run: $(TEST_BIN) $(TEST_DATA_FILE)
|
||||||
|
LD_PRELOAD=$(LIBASAN):$(ROOT)afl-frida-trace.so \
|
||||||
|
ASAN_OPTIONS=detect_leaks=false \
|
||||||
|
AFL_USE_FASAN=1 \
|
||||||
|
$(TEST_BIN) < $(TEST_DATA_FILE)
|
||||||
|
|
||||||
|
############################# CLEAN ############################################
|
||||||
|
clean:
|
||||||
|
rm -rf $(BUILD_DIR)
|
||||||
|
|
||||||
|
############################# FORMAT ###########################################
|
||||||
|
format:
|
||||||
|
cd $(ROOT) && echo $(TEST_SRC) | xargs -L1 ./.custom-format.py -i
|
||||||
|
|
||||||
|
############################# RUN #############################################
|
22
frida_mode/test/fasan/Makefile
Normal file
22
frida_mode/test/fasan/Makefile
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
all:
|
||||||
|
@echo trying to use GNU make...
|
||||||
|
@gmake all || echo please install GNUmake
|
||||||
|
|
||||||
|
32:
|
||||||
|
@echo trying to use GNU make...
|
||||||
|
@gmake 32 || echo please install GNUmake
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@gmake clean
|
||||||
|
|
||||||
|
frida-noasan:
|
||||||
|
@gmake frida-noasan
|
||||||
|
|
||||||
|
frida:
|
||||||
|
@gmake frida
|
||||||
|
|
||||||
|
debug:
|
||||||
|
@gmake debug
|
||||||
|
|
||||||
|
run:
|
||||||
|
@gmake run
|
90
frida_mode/test/fasan/test.c
Normal file
90
frida_mode/test/fasan/test.c
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define UNUSED_PARAMETER(x) (void)(x)
|
||||||
|
|
||||||
|
#define LOG(x) \
|
||||||
|
do { \
|
||||||
|
\
|
||||||
|
char buf[] = x; \
|
||||||
|
write(STDOUT_FILENO, buf, sizeof(buf)); \
|
||||||
|
\
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
void test(char data) {
|
||||||
|
|
||||||
|
char *buf = malloc(10);
|
||||||
|
|
||||||
|
if (buf == NULL) return;
|
||||||
|
|
||||||
|
switch (data) {
|
||||||
|
|
||||||
|
/* Underflow */
|
||||||
|
case 'U':
|
||||||
|
LOG("Underflow\n");
|
||||||
|
buf[-1] = '\0';
|
||||||
|
free(buf);
|
||||||
|
break;
|
||||||
|
/* Overflow */
|
||||||
|
case 'O':
|
||||||
|
LOG("Overflow\n");
|
||||||
|
buf[10] = '\0';
|
||||||
|
free(buf);
|
||||||
|
break;
|
||||||
|
/* Double free */
|
||||||
|
case 'D':
|
||||||
|
LOG("Double free\n");
|
||||||
|
free(buf);
|
||||||
|
free(buf);
|
||||||
|
break;
|
||||||
|
/* Use after free */
|
||||||
|
case 'A':
|
||||||
|
LOG("Use after free\n");
|
||||||
|
free(buf);
|
||||||
|
buf[0] = '\0';
|
||||||
|
break;
|
||||||
|
/* Test Limits (OK) */
|
||||||
|
case 'T':
|
||||||
|
LOG("Test-Limits - No Error\n");
|
||||||
|
buf[0] = 'A';
|
||||||
|
buf[9] = 'I';
|
||||||
|
free(buf);
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
LOG("Memset too many\n");
|
||||||
|
memset(buf, '\0', 11);
|
||||||
|
free(buf);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG("Nop - No Error\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(argc);
|
||||||
|
UNUSED_PARAMETER(argv);
|
||||||
|
|
||||||
|
char input = '\0';
|
||||||
|
|
||||||
|
if (read(STDIN_FILENO, &input, 1) < 0) {
|
||||||
|
|
||||||
|
LOG("Failed to read stdin\n");
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
test(input);
|
||||||
|
|
||||||
|
LOG("DONE\n");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -35,6 +35,9 @@ FRIDA_OUT:=$(BUILD_DIR)frida-out
|
|||||||
all: $(TEST_BIN)
|
all: $(TEST_BIN)
|
||||||
make -C $(ROOT)frida_mode/
|
make -C $(ROOT)frida_mode/
|
||||||
|
|
||||||
|
32:
|
||||||
|
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||||
|
|
||||||
$(BUILD_DIR):
|
$(BUILD_DIR):
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
|
|
||||||
@ -46,7 +49,7 @@ $(HARNESS_FILE): | $(HARNESS_BUILD_DIR)
|
|||||||
wget -O $@ $(HARNESS_URL)
|
wget -O $@ $(HARNESS_URL)
|
||||||
|
|
||||||
$(HARNESS_OBJ): $(HARNESS_FILE)
|
$(HARNESS_OBJ): $(HARNESS_FILE)
|
||||||
$(CC) -o $@ -c $<
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
######### PNGTEST ########
|
######### PNGTEST ########
|
||||||
|
|
||||||
@ -57,7 +60,7 @@ $(PNGTEST_FILE): | $(PNGTEST_BUILD_DIR)
|
|||||||
wget -O $@ $(PNGTEST_URL)
|
wget -O $@ $(PNGTEST_URL)
|
||||||
|
|
||||||
$(PNGTEST_OBJ): $(PNGTEST_FILE) | $(LIBPNG_DIR)
|
$(PNGTEST_OBJ): $(PNGTEST_FILE) | $(LIBPNG_DIR)
|
||||||
$(CXX) -std=c++11 -I $(LIBPNG_DIR) -o $@ -c $<
|
$(CXX) $(CFLAGS) $(LDFLAGS) -std=c++11 -I $(LIBPNG_DIR) -o $@ -c $<
|
||||||
|
|
||||||
######### LIBPNG ########
|
######### LIBPNG ########
|
||||||
|
|
||||||
@ -80,6 +83,8 @@ $(LIBPNG_LIB): $(LIBPNG_MAKEFILE)
|
|||||||
|
|
||||||
$(TEST_BIN): $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB)
|
$(TEST_BIN): $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB)
|
||||||
$(CXX) \
|
$(CXX) \
|
||||||
|
$(CFLAGS) \
|
||||||
|
$(LDFLAGS) \
|
||||||
-o $@ \
|
-o $@ \
|
||||||
$(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) \
|
$(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) \
|
||||||
-lz \
|
-lz \
|
||||||
|
@ -2,6 +2,10 @@ all:
|
|||||||
@echo trying to use GNU make...
|
@echo trying to use GNU make...
|
||||||
@gmake all || echo please install GNUmake
|
@gmake all || echo please install GNUmake
|
||||||
|
|
||||||
|
32:
|
||||||
|
@echo trying to use GNU make...
|
||||||
|
@gmake 32 || echo please install GNUmake
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@gmake clean
|
@gmake clean
|
||||||
|
|
||||||
|
@ -8,6 +8,18 @@ TEST_DATA_DIR:=../build/libpng/libpng-1.2.56/contrib/pngsuite/
|
|||||||
QEMU_OUT:=$(BUILD_DIR)qemu-out
|
QEMU_OUT:=$(BUILD_DIR)qemu-out
|
||||||
FRIDA_OUT:=$(BUILD_DIR)frida-out
|
FRIDA_OUT:=$(BUILD_DIR)frida-out
|
||||||
|
|
||||||
|
ifndef ARCH
|
||||||
|
|
||||||
|
ARCH=$(shell uname -m)
|
||||||
|
ifeq "$(ARCH)" "aarch64"
|
||||||
|
ARCH:=arm64
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq "$(ARCH)" "i686"
|
||||||
|
ARCH:=x86
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x4000000000)
|
AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x4000000000)
|
||||||
|
|
||||||
ARCH=$(shell uname -m)
|
ARCH=$(shell uname -m)
|
||||||
@ -19,11 +31,18 @@ ifeq "$(ARCH)" "x86_64"
|
|||||||
AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x0000555555554000)
|
AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x0000555555554000)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: all clean qemu qemu_entry frida frida_entry
|
ifeq "$(ARCH)" "x86"
|
||||||
|
AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x56555000)
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: all 32 clean qemu qemu_entry frida frida_entry
|
||||||
|
|
||||||
all:
|
all:
|
||||||
make -C $(ROOT)frida_mode/test/png/
|
make -C $(ROOT)frida_mode/test/png/
|
||||||
|
|
||||||
|
32:
|
||||||
|
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||||
|
|
||||||
$(BUILD_DIR):
|
$(BUILD_DIR):
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
|
|
||||||
|
@ -2,6 +2,10 @@ all:
|
|||||||
@echo trying to use GNU make...
|
@echo trying to use GNU make...
|
||||||
@gmake all || echo please install GNUmake
|
@gmake all || echo please install GNUmake
|
||||||
|
|
||||||
|
32:
|
||||||
|
@echo trying to use GNU make...
|
||||||
|
@gmake 32 || echo please install GNUmake
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@gmake clean
|
@gmake clean
|
||||||
|
|
||||||
|
@ -2,8 +2,16 @@ PWD:=$(shell pwd)/
|
|||||||
ROOT:=$(shell realpath $(PWD)../../../../..)/
|
ROOT:=$(shell realpath $(PWD)../../../../..)/
|
||||||
BUILD_DIR:=$(PWD)build/
|
BUILD_DIR:=$(PWD)build/
|
||||||
|
|
||||||
AFLPP_DRIVER_HOOK_DIR=$(ROOT)utils/aflpp_driver/
|
AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c
|
||||||
AFLPP_DRIVER_HOOK_OBJ=$(AFLPP_DRIVER_HOOK_DIR)aflpp_qemu_driver_hook.so
|
AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so
|
||||||
|
|
||||||
|
CFLAGS+=-O3 \
|
||||||
|
-funroll-loops \
|
||||||
|
-g \
|
||||||
|
-fPIC \
|
||||||
|
-funroll-loops \
|
||||||
|
|
||||||
|
LDFLAGS+=-shared \
|
||||||
|
|
||||||
TEST_BIN:=$(PWD)../../build/test
|
TEST_BIN:=$(PWD)../../build/test
|
||||||
TEST_DATA_DIR:=../../build/libpng/libpng-1.2.56/contrib/pngsuite/
|
TEST_DATA_DIR:=../../build/libpng/libpng-1.2.56/contrib/pngsuite/
|
||||||
@ -12,9 +20,20 @@ AFLPP_DRIVER_DUMMY_INPUT:=$(BUILD_DIR)in
|
|||||||
QEMU_OUT:=$(BUILD_DIR)qemu-out
|
QEMU_OUT:=$(BUILD_DIR)qemu-out
|
||||||
FRIDA_OUT:=$(BUILD_DIR)frida-out
|
FRIDA_OUT:=$(BUILD_DIR)frida-out
|
||||||
|
|
||||||
AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000)
|
ifndef ARCH
|
||||||
|
|
||||||
ARCH=$(shell uname -m)
|
ARCH=$(shell uname -m)
|
||||||
|
ifeq "$(ARCH)" "aarch64"
|
||||||
|
ARCH:=arm64
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq "$(ARCH)" "i686"
|
||||||
|
ARCH:=x86
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000)
|
||||||
|
|
||||||
ifeq "$(ARCH)" "aarch64"
|
ifeq "$(ARCH)" "aarch64"
|
||||||
AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000)
|
AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000)
|
||||||
endif
|
endif
|
||||||
@ -23,6 +42,18 @@ ifeq "$(ARCH)" "x86_64"
|
|||||||
AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000)
|
AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq "$(ARCH)" "x86"
|
||||||
|
AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x56555000)
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: all 32 clean format qemu qemu_entry frida frida_entry debug
|
||||||
|
|
||||||
|
all: $(AFLPP_DRIVER_HOOK_OBJ)
|
||||||
|
make -C $(ROOT)frida_mode/test/png/persistent/
|
||||||
|
|
||||||
|
32:
|
||||||
|
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||||
|
|
||||||
.PHONY: all clean qemu qemu_entry frida frida_entry
|
.PHONY: all clean qemu qemu_entry frida frida_entry
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@ -37,8 +68,8 @@ $(TEST_DATA_DIR): | $(BUILD_DIR)
|
|||||||
$(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR)
|
$(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR)
|
||||||
truncate -s 1M $@
|
truncate -s 1M $@
|
||||||
|
|
||||||
$(AFLPP_DRIVER_HOOK_OBJ): | $(AFLPP_DRIVER_HOOK_DIR)
|
$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR)
|
||||||
make -C $(AFLPP_DRIVER_HOOK_DIR)
|
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
|
||||||
|
|
||||||
qemu: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR)
|
qemu: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR)
|
||||||
AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \
|
AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \
|
||||||
@ -93,6 +124,18 @@ frida_entry: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR)
|
|||||||
-- \
|
-- \
|
||||||
$(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
|
$(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
|
||||||
|
|
||||||
|
debug:
|
||||||
|
echo $(AFL_FRIDA_PERSISTENT_ADDR)
|
||||||
|
gdb \
|
||||||
|
--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
|
||||||
|
--ex 'set environment AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ)' \
|
||||||
|
--ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR)' \
|
||||||
|
--ex 'set disassembly-flavor intel' \
|
||||||
|
--args $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(BUILD_DIR)
|
rm -rf $(BUILD_DIR)
|
||||||
|
|
||||||
|
format:
|
||||||
|
cd $(ROOT) && echo $(AFLPP_DRIVER_HOOK_SRC) | xargs -L1 ./.custom-format.py -i
|
||||||
|
|
||||||
|
@ -2,9 +2,16 @@ all:
|
|||||||
@echo trying to use GNU make...
|
@echo trying to use GNU make...
|
||||||
@gmake all || echo please install GNUmake
|
@gmake all || echo please install GNUmake
|
||||||
|
|
||||||
|
32:
|
||||||
|
@echo trying to use GNU make...
|
||||||
|
@gmake 32 || echo please install GNUmake
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@gmake clean
|
@gmake clean
|
||||||
|
|
||||||
|
format:
|
||||||
|
@gmake format
|
||||||
|
|
||||||
qemu:
|
qemu:
|
||||||
@gmake qemu
|
@gmake qemu
|
||||||
|
|
||||||
@ -16,3 +23,6 @@ frida:
|
|||||||
|
|
||||||
frida_entry:
|
frida_entry:
|
||||||
@gmake frida_entry
|
@gmake frida_entry
|
||||||
|
|
||||||
|
debug:
|
||||||
|
@gmake debug
|
||||||
|
97
frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c
Normal file
97
frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <string.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];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base,
|
||||||
|
uint8_t *input_buf, uint32_t input_buf_len) {
|
||||||
|
|
||||||
|
memcpy((void *)regs->rdi, input_buf, input_buf_len);
|
||||||
|
regs->rsi = input_buf_len;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif 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];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base,
|
||||||
|
uint8_t *input_buf, uint32_t input_buf_len) {
|
||||||
|
|
||||||
|
void **esp = (void **)regs->esp;
|
||||||
|
void * arg1 = esp[1];
|
||||||
|
void **arg2 = &esp[2];
|
||||||
|
memcpy(arg1, input_buf, input_buf_len);
|
||||||
|
*arg2 = (void *)input_buf_len;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#pragma error "Unsupported architecture"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int afl_persistent_hook_init(void) {
|
||||||
|
|
||||||
|
// 1 for shared memory input (faster), 0 for normal input (you have to use
|
||||||
|
// read(), input_buf will be NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -10,11 +10,14 @@ TESTINSTSRC:=$(PWD)testinstr.c
|
|||||||
QEMU_OUT:=$(BUILD_DIR)qemu-out
|
QEMU_OUT:=$(BUILD_DIR)qemu-out
|
||||||
FRIDA_OUT:=$(BUILD_DIR)frida-out
|
FRIDA_OUT:=$(BUILD_DIR)frida-out
|
||||||
|
|
||||||
.PHONY: all clean qemu frida
|
.PHONY: all 32 clean qemu frida
|
||||||
|
|
||||||
all: $(TESTINSTBIN)
|
all: $(TESTINSTBIN)
|
||||||
make -C $(ROOT)frida_mode/
|
make -C $(ROOT)frida_mode/
|
||||||
|
|
||||||
|
32:
|
||||||
|
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||||
|
|
||||||
$(BUILD_DIR):
|
$(BUILD_DIR):
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
|
|
||||||
@ -25,7 +28,7 @@ $(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR)
|
|||||||
echo -n "000" > $@
|
echo -n "000" > $@
|
||||||
|
|
||||||
$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR)
|
$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR)
|
||||||
$(CC) -o $@ $<
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(BUILD_DIR)
|
rm -rf $(BUILD_DIR)
|
||||||
@ -48,3 +51,9 @@ frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
|
|||||||
-o $(FRIDA_OUT) \
|
-o $(FRIDA_OUT) \
|
||||||
-- \
|
-- \
|
||||||
$(TESTINSTBIN) @@
|
$(TESTINSTBIN) @@
|
||||||
|
|
||||||
|
debug:
|
||||||
|
gdb \
|
||||||
|
--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
|
||||||
|
--ex 'set disassembly-flavor intel' \
|
||||||
|
--args $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
|
||||||
|
@ -2,6 +2,10 @@ all:
|
|||||||
@echo trying to use GNU make...
|
@echo trying to use GNU make...
|
||||||
@gmake all || echo please install GNUmake
|
@gmake all || echo please install GNUmake
|
||||||
|
|
||||||
|
32:
|
||||||
|
@echo trying to use GNU make...
|
||||||
|
@gmake 32 || echo please install GNUmake
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@gmake clean
|
@gmake clean
|
||||||
|
|
||||||
@ -10,3 +14,6 @@ qemu:
|
|||||||
|
|
||||||
frida:
|
frida:
|
||||||
@gmake frida
|
@gmake frida
|
||||||
|
|
||||||
|
debug:
|
||||||
|
@gmake debug
|
||||||
|
@ -191,7 +191,9 @@ static char *afl_environment_variables[] = {
|
|||||||
"AFL_WINE_PATH",
|
"AFL_WINE_PATH",
|
||||||
"AFL_NO_SNAPSHOT",
|
"AFL_NO_SNAPSHOT",
|
||||||
"AFL_EXPAND_HAVOC_NOW",
|
"AFL_EXPAND_HAVOC_NOW",
|
||||||
|
"AFL_USE_FASAN",
|
||||||
"AFL_USE_QASAN",
|
"AFL_USE_QASAN",
|
||||||
|
"AFL_PRINT_FILENAMES",
|
||||||
NULL
|
NULL
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -79,6 +79,8 @@ typedef struct afl_forkserver {
|
|||||||
|
|
||||||
bool frida_mode; /* if running in frida mode or not */
|
bool frida_mode; /* if running in frida mode or not */
|
||||||
|
|
||||||
|
bool frida_asan; /* if running with asan in frida mode */
|
||||||
|
|
||||||
bool use_stdin; /* use stdin for sending data */
|
bool use_stdin; /* use stdin for sending data */
|
||||||
|
|
||||||
bool no_unlink; /* do not unlink cur_input */
|
bool no_unlink; /* do not unlink cur_input */
|
||||||
|
@ -25,9 +25,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
#include "libqasan.h"
|
#include "libqasan.h"
|
||||||
#include "map_macro.h"
|
#include "map_macro.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
|
||||||
ssize_t (*__lq_libc_write)(int, const void *, size_t);
|
|
||||||
ssize_t (*__lq_libc_read)(int, void *, size_t);
|
|
||||||
char *(*__lq_libc_fgets)(char *, int, FILE *);
|
char *(*__lq_libc_fgets)(char *, int, FILE *);
|
||||||
int (*__lq_libc_atoi)(const char *);
|
int (*__lq_libc_atoi)(const char *);
|
||||||
long (*__lq_libc_atol)(const char *);
|
long (*__lq_libc_atol)(const char *);
|
||||||
@ -37,8 +37,6 @@ void __libqasan_init_hooks(void) {
|
|||||||
|
|
||||||
__libqasan_init_malloc();
|
__libqasan_init_malloc();
|
||||||
|
|
||||||
__lq_libc_write = ASSERT_DLSYM(write);
|
|
||||||
__lq_libc_read = ASSERT_DLSYM(read);
|
|
||||||
__lq_libc_fgets = ASSERT_DLSYM(fgets);
|
__lq_libc_fgets = ASSERT_DLSYM(fgets);
|
||||||
__lq_libc_atoi = ASSERT_DLSYM(atoi);
|
__lq_libc_atoi = ASSERT_DLSYM(atoi);
|
||||||
__lq_libc_atol = ASSERT_DLSYM(atol);
|
__lq_libc_atol = ASSERT_DLSYM(atol);
|
||||||
@ -52,7 +50,7 @@ ssize_t write(int fd, const void *buf, size_t count) {
|
|||||||
|
|
||||||
QASAN_DEBUG("%14p: write(%d, %p, %zu)\n", rtv, fd, buf, count);
|
QASAN_DEBUG("%14p: write(%d, %p, %zu)\n", rtv, fd, buf, count);
|
||||||
QASAN_LOAD(buf, count);
|
QASAN_LOAD(buf, count);
|
||||||
ssize_t r = __lq_libc_write(fd, buf, count);
|
ssize_t r = syscall(SYS_write, fd, buf, count);
|
||||||
QASAN_DEBUG("\t\t = %zd\n", r);
|
QASAN_DEBUG("\t\t = %zd\n", r);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
@ -65,7 +63,7 @@ ssize_t read(int fd, void *buf, size_t count) {
|
|||||||
|
|
||||||
QASAN_DEBUG("%14p: read(%d, %p, %zu)\n", rtv, fd, buf, count);
|
QASAN_DEBUG("%14p: read(%d, %p, %zu)\n", rtv, fd, buf, count);
|
||||||
QASAN_STORE(buf, count);
|
QASAN_STORE(buf, count);
|
||||||
ssize_t r = __lq_libc_read(fd, buf, count);
|
ssize_t r = syscall(SYS_read, fd, buf, count);
|
||||||
QASAN_DEBUG("\t\t = %zd\n", r);
|
QASAN_DEBUG("\t\t = %zd\n", r);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
@ -61,10 +61,18 @@ void __libqasan_print_maps(void) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*__attribute__((constructor))*/ void __libqasan_init() {
|
int __libqasan_is_initialized = 0;
|
||||||
|
|
||||||
|
__attribute__((constructor)) void __libqasan_init() {
|
||||||
|
|
||||||
|
if (__libqasan_is_initialized) return;
|
||||||
|
__libqasan_is_initialized = 1;
|
||||||
|
|
||||||
__libqasan_init_hooks();
|
__libqasan_init_hooks();
|
||||||
|
|
||||||
|
if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH"))
|
||||||
|
__libqasan_hotpatch();
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
__qasan_debug = getenv("QASAN_DEBUG") != NULL;
|
__qasan_debug = getenv("QASAN_DEBUG") != NULL;
|
||||||
#endif
|
#endif
|
||||||
@ -86,7 +94,6 @@ int __libc_start_main(int (*main)(int, char **, char **), int argc, char **argv,
|
|||||||
typeof(&__libc_start_main) orig = dlsym(RTLD_NEXT, "__libc_start_main");
|
typeof(&__libc_start_main) orig = dlsym(RTLD_NEXT, "__libc_start_main");
|
||||||
|
|
||||||
__libqasan_init();
|
__libqasan_init();
|
||||||
if (getenv("AFL_INST_LIBS")) __libqasan_hotpatch();
|
|
||||||
|
|
||||||
return orig(main, argc, argv, init, fini, rtld_fini, stack_end);
|
return orig(main, argc, argv, init, fini, rtld_fini, stack_end);
|
||||||
|
|
||||||
|
12
src/afl-cc.c
12
src/afl-cc.c
@ -1574,7 +1574,12 @@ int main(int argc, char **argv, char **envp) {
|
|||||||
else if (have_gcc_plugin)
|
else if (have_gcc_plugin)
|
||||||
compiler_mode = GCC_PLUGIN;
|
compiler_mode = GCC_PLUGIN;
|
||||||
else if (have_gcc)
|
else if (have_gcc)
|
||||||
|
#ifdef __APPLE__
|
||||||
|
// on OSX clang masquerades as GCC
|
||||||
|
compiler_mode = CLANG;
|
||||||
|
#else
|
||||||
compiler_mode = GCC;
|
compiler_mode = GCC;
|
||||||
|
#endif
|
||||||
else if (have_lto)
|
else if (have_lto)
|
||||||
compiler_mode = LTO;
|
compiler_mode = LTO;
|
||||||
else
|
else
|
||||||
@ -1596,7 +1601,12 @@ int main(int argc, char **argv, char **envp) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compiler_mode == CLANG) { instrument_mode = INSTRUMENT_CLANG; }
|
if (compiler_mode == CLANG) {
|
||||||
|
|
||||||
|
instrument_mode = INSTRUMENT_CLANG;
|
||||||
|
setenv(CLANG_ENV_VAR, "1", 1); // used by afl-as
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) {
|
if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) {
|
||||||
|
|
||||||
|
@ -451,8 +451,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
|||||||
/* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered
|
/* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered
|
||||||
before the dump is complete. */
|
before the dump is complete. */
|
||||||
|
|
||||||
// r.rlim_max = r.rlim_cur = 0;
|
if (!fsrv->debug) {
|
||||||
// setrlimit(RLIMIT_CORE, &r); /* Ignore errors */
|
|
||||||
|
r.rlim_max = r.rlim_cur = 0;
|
||||||
|
setrlimit(RLIMIT_CORE, &r); /* Ignore errors */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* Isolate the process and configure standard descriptors. If out_file is
|
/* Isolate the process and configure standard descriptors. If out_file is
|
||||||
specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */
|
specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */
|
||||||
|
@ -1044,18 +1044,16 @@ void perform_dry_run(afl_state_t *afl) {
|
|||||||
|
|
||||||
/* Remove from fuzzing queue but keep for splicing */
|
/* Remove from fuzzing queue but keep for splicing */
|
||||||
|
|
||||||
struct queue_entry *p = afl->queue;
|
if (!q->was_fuzzed) {
|
||||||
|
|
||||||
if (!p->was_fuzzed) {
|
q->was_fuzzed = 1;
|
||||||
|
|
||||||
p->was_fuzzed = 1;
|
|
||||||
--afl->pending_not_fuzzed;
|
--afl->pending_not_fuzzed;
|
||||||
--afl->active_paths;
|
--afl->active_paths;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p->disabled = 1;
|
q->disabled = 1;
|
||||||
p->perf_score = 0;
|
q->perf_score = 0;
|
||||||
|
|
||||||
u32 i = 0;
|
u32 i = 0;
|
||||||
while (unlikely(i < afl->queued_paths && afl->queue_buf[i] &&
|
while (unlikely(i < afl->queued_paths && afl->queue_buf[i] &&
|
||||||
@ -1294,10 +1292,14 @@ void pivot_inputs(afl_state_t *afl) {
|
|||||||
|
|
||||||
if (src_str && sscanf(src_str + 1, "%06u", &src_id) == 1) {
|
if (src_str && sscanf(src_str + 1, "%06u", &src_id) == 1) {
|
||||||
|
|
||||||
|
if (src_id < afl->queued_paths) {
|
||||||
|
|
||||||
struct queue_entry *s = afl->queue_buf[src_id];
|
struct queue_entry *s = afl->queue_buf[src_id];
|
||||||
|
|
||||||
if (s) { q->depth = s->depth + 1; }
|
if (s) { q->depth = s->depth + 1; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (afl->max_depth < q->depth) { afl->max_depth = q->depth; }
|
if (afl->max_depth < q->depth) { afl->max_depth = q->depth; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -562,7 +562,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
|||||||
if (afl->cmplog_lvl == 3 ||
|
if (afl->cmplog_lvl == 3 ||
|
||||||
(afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) ||
|
(afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) ||
|
||||||
!(afl->fsrv.total_execs % afl->queued_paths) ||
|
!(afl->fsrv.total_execs % afl->queued_paths) ||
|
||||||
get_cur_time() - afl->last_path_time > 300000) {
|
get_cur_time() - afl->last_path_time > 300000) { // 300 seconds
|
||||||
|
|
||||||
if (input_to_state_stage(afl, in_buf, out_buf, len)) {
|
if (input_to_state_stage(afl, in_buf, out_buf, len)) {
|
||||||
|
|
||||||
@ -2013,7 +2013,7 @@ havoc_stage:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(get_cur_time() - afl->last_path_time > 5000 &&
|
if (unlikely(get_cur_time() - afl->last_path_time > 5000 /* 5 seconds */ &&
|
||||||
afl->ready_for_splicing_count > 1)) {
|
afl->ready_for_splicing_count > 1)) {
|
||||||
|
|
||||||
/* add expensive havoc cases here if there is no findings in the last 5s */
|
/* add expensive havoc cases here if there is no findings in the last 5s */
|
||||||
@ -3060,7 +3060,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
|
|||||||
if (afl->cmplog_lvl == 3 ||
|
if (afl->cmplog_lvl == 3 ||
|
||||||
(afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) ||
|
(afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) ||
|
||||||
!(afl->fsrv.total_execs % afl->queued_paths) ||
|
!(afl->fsrv.total_execs % afl->queued_paths) ||
|
||||||
get_cur_time() - afl->last_path_time > 300000) {
|
get_cur_time() - afl->last_path_time > 300000) { // 300 seconds
|
||||||
|
|
||||||
if (input_to_state_stage(afl, in_buf, out_buf, len)) {
|
if (input_to_state_stage(afl, in_buf, out_buf, len)) {
|
||||||
|
|
||||||
|
@ -368,7 +368,8 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
|
|||||||
afl->plot_prev_uh == afl->unique_hangs &&
|
afl->plot_prev_uh == afl->unique_hangs &&
|
||||||
afl->plot_prev_md == afl->max_depth &&
|
afl->plot_prev_md == afl->max_depth &&
|
||||||
afl->plot_prev_ed == afl->fsrv.total_execs) ||
|
afl->plot_prev_ed == afl->fsrv.total_execs) ||
|
||||||
!afl->queue_cycle || get_cur_time() - afl->start_time <= 60))) {
|
!afl->queue_cycle ||
|
||||||
|
get_cur_time() - afl->start_time <= 60000))) {
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -393,7 +394,7 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
|
|||||||
fprintf(afl->fsrv.plot_file,
|
fprintf(afl->fsrv.plot_file,
|
||||||
"%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu, "
|
"%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu, "
|
||||||
"%u\n",
|
"%u\n",
|
||||||
(afl->prev_run_time + get_cur_time() - afl->start_time),
|
((afl->prev_run_time + get_cur_time() - afl->start_time) / 1000),
|
||||||
afl->queue_cycle - 1, afl->current_entry, afl->queued_paths,
|
afl->queue_cycle - 1, afl->current_entry, afl->queued_paths,
|
||||||
afl->pending_not_fuzzed, afl->pending_favored, bitmap_cvg,
|
afl->pending_not_fuzzed, afl->pending_favored, bitmap_cvg,
|
||||||
afl->unique_crashes, afl->unique_hangs, afl->max_depth, eps,
|
afl->unique_crashes, afl->unique_hangs, afl->max_depth, eps,
|
||||||
|
@ -328,11 +328,55 @@ static int stricmp(char const *a, char const *b) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fasan_check_afl_preload(char *afl_preload) {
|
||||||
|
|
||||||
|
char first_preload[PATH_MAX + 1] = {0};
|
||||||
|
char * separator = strchr(afl_preload, ':');
|
||||||
|
size_t first_preload_len = PATH_MAX;
|
||||||
|
char * basename;
|
||||||
|
char clang_runtime_prefix[] = "libclang_rt.asan-";
|
||||||
|
|
||||||
|
if (separator != NULL && (separator - afl_preload) < PATH_MAX) {
|
||||||
|
|
||||||
|
first_preload_len = separator - afl_preload;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(first_preload, afl_preload, first_preload_len);
|
||||||
|
|
||||||
|
basename = strrchr(first_preload, '/');
|
||||||
|
if (basename == NULL) {
|
||||||
|
|
||||||
|
basename = first_preload;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
basename = basename + 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(basename, clang_runtime_prefix,
|
||||||
|
sizeof(clang_runtime_prefix) - 1) != 0) {
|
||||||
|
|
||||||
|
FATAL("Address Sanitizer DSO must be the first DSO in AFL_PRELOAD");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (access(first_preload, R_OK) != 0) {
|
||||||
|
|
||||||
|
FATAL("Address Sanitizer DSO not found");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
OKF("Found ASAN DSO: %s", first_preload);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* Main entry point */
|
/* Main entry point */
|
||||||
|
|
||||||
int main(int argc, char **argv_orig, char **envp) {
|
int main(int argc, char **argv_orig, char **envp) {
|
||||||
|
|
||||||
s32 opt, i, auto_sync = 0 /*, user_set_cache = 0*/;
|
s32 opt, auto_sync = 0 /*, user_set_cache = 0*/;
|
||||||
u64 prev_queued = 0;
|
u64 prev_queued = 0;
|
||||||
u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0,
|
u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0,
|
||||||
map_size = get_map_size();
|
map_size = get_map_size();
|
||||||
@ -785,6 +829,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
afl->fsrv.frida_mode = 1;
|
afl->fsrv.frida_mode = 1;
|
||||||
|
if (get_afl_env("AFL_USE_FASAN")) { afl->fsrv.frida_asan = 1; }
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1369,19 +1414,27 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
OKF("Injecting %s ...", frida_binary);
|
OKF("Injecting %s ...", frida_binary);
|
||||||
if (afl_preload) {
|
if (afl_preload) {
|
||||||
|
|
||||||
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
|
if (afl->fsrv.frida_asan) {
|
||||||
|
|
||||||
} else {
|
OKF("Using Frida Address Sanitizer Mode");
|
||||||
|
|
||||||
frida_afl_preload = alloc_printf("%s", frida_binary);
|
fasan_check_afl_preload(afl_preload);
|
||||||
|
|
||||||
|
setenv("ASAN_OPTIONS", "detect_leaks=false", 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||||
|
OKF("Injecting %s ...", frida_binary);
|
||||||
|
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
|
||||||
|
|
||||||
ck_free(frida_binary);
|
ck_free(frida_binary);
|
||||||
|
|
||||||
setenv("LD_PRELOAD", frida_afl_preload, 1);
|
setenv("LD_PRELOAD", frida_afl_preload, 1);
|
||||||
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
|
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||||
@ -1391,6 +1444,15 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
|
|
||||||
} else if (afl->fsrv.frida_mode) {
|
} else if (afl->fsrv.frida_mode) {
|
||||||
|
|
||||||
|
if (afl->fsrv.frida_asan) {
|
||||||
|
|
||||||
|
OKF("Using Frida Address Sanitizer Mode");
|
||||||
|
FATAL(
|
||||||
|
"Address Sanitizer DSO must be loaded using AFL_PRELOAD in Frida "
|
||||||
|
"Address Sanitizer Mode");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||||
OKF("Injecting %s ...", frida_binary);
|
OKF("Injecting %s ...", frida_binary);
|
||||||
setenv("LD_PRELOAD", frida_binary, 1);
|
setenv("LD_PRELOAD", frida_binary, 1);
|
||||||
@ -1399,6 +1461,8 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (getenv("AFL_LD_PRELOAD")) {
|
if (getenv("AFL_LD_PRELOAD")) {
|
||||||
|
|
||||||
FATAL("Use AFL_PRELOAD instead of AFL_LD_PRELOAD");
|
FATAL("Use AFL_PRELOAD instead of AFL_LD_PRELOAD");
|
||||||
@ -1770,7 +1834,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
|
|
||||||
if (extras_dir_cnt) {
|
if (extras_dir_cnt) {
|
||||||
|
|
||||||
for (i = 0; i < extras_dir_cnt; i++) {
|
for (u8 i = 0; i < extras_dir_cnt; i++) {
|
||||||
|
|
||||||
load_extras(afl, extras_dir[i]);
|
load_extras(afl, extras_dir[i]);
|
||||||
|
|
||||||
@ -1922,6 +1986,13 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
|
|
||||||
if (unlikely(seek_to)) {
|
if (unlikely(seek_to)) {
|
||||||
|
|
||||||
|
if (unlikely(seek_to >= afl->queued_paths)) {
|
||||||
|
|
||||||
|
// This should never happen.
|
||||||
|
FATAL("BUG: seek_to location out of bounds!\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
afl->current_entry = seek_to;
|
afl->current_entry = seek_to;
|
||||||
afl->queue_cur = afl->queue_buf[seek_to];
|
afl->queue_cur = afl->queue_buf[seek_to];
|
||||||
seek_to = 0;
|
seek_to = 0;
|
||||||
@ -1940,8 +2011,10 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
/* If we had a full queue cycle with no new finds, try
|
/* If we had a full queue cycle with no new finds, try
|
||||||
recombination strategies next. */
|
recombination strategies next. */
|
||||||
|
|
||||||
if (unlikely(afl->queued_paths == prev_queued &&
|
if (unlikely(afl->queued_paths == prev_queued
|
||||||
(get_cur_time() - afl->start_time) >= 3600)) {
|
/* FIXME TODO BUG: && (get_cur_time() - afl->start_time) >=
|
||||||
|
3600 */
|
||||||
|
)) {
|
||||||
|
|
||||||
if (afl->use_splicing) {
|
if (afl->use_splicing) {
|
||||||
|
|
||||||
@ -2059,7 +2132,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we must recalculate the scores of all queue entries
|
// we must recalculate the scores of all queue entries
|
||||||
for (i = 0; i < (s32)afl->queued_paths; i++) {
|
for (u32 i = 0; i < afl->queued_paths; i++) {
|
||||||
|
|
||||||
if (likely(!afl->queue_buf[i]->disabled)) {
|
if (likely(!afl->queue_buf[i]->disabled)) {
|
||||||
|
|
||||||
|
@ -76,17 +76,18 @@ static u32 in_len; /* Input data length */
|
|||||||
|
|
||||||
static u32 map_size = MAP_SIZE;
|
static u32 map_size = MAP_SIZE;
|
||||||
|
|
||||||
static u8 quiet_mode, /* Hide non-essential messages? */
|
static bool quiet_mode, /* Hide non-essential messages? */
|
||||||
edges_only, /* Ignore hit counts? */
|
edges_only, /* Ignore hit counts? */
|
||||||
raw_instr_output, /* Do not apply AFL filters */
|
raw_instr_output, /* Do not apply AFL filters */
|
||||||
cmin_mode, /* Generate output in afl-cmin mode? */
|
cmin_mode, /* Generate output in afl-cmin mode? */
|
||||||
binary_mode, /* Write output as a binary map */
|
binary_mode, /* Write output as a binary map */
|
||||||
keep_cores, /* Allow coredumps? */
|
keep_cores, /* Allow coredumps? */
|
||||||
remove_shm = 1, /* remove shmem? */
|
remove_shm = true, /* remove shmem? */
|
||||||
collect_coverage, /* collect coverage */
|
collect_coverage, /* collect coverage */
|
||||||
have_coverage, /* have coverage? */
|
have_coverage, /* have coverage? */
|
||||||
no_classify, /* do not classify counts */
|
no_classify, /* do not classify counts */
|
||||||
debug; /* debug mode */
|
debug, /* debug mode */
|
||||||
|
print_filenames; /* print the current filename */
|
||||||
|
|
||||||
static volatile u8 stop_soon, /* Ctrl-C pressed? */
|
static volatile u8 stop_soon, /* Ctrl-C pressed? */
|
||||||
child_crashed; /* Child crashed? */
|
child_crashed; /* Child crashed? */
|
||||||
@ -320,11 +321,11 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem,
|
|||||||
if (fsrv->trace_bits[0] == 1) {
|
if (fsrv->trace_bits[0] == 1) {
|
||||||
|
|
||||||
fsrv->trace_bits[0] = 0;
|
fsrv->trace_bits[0] = 0;
|
||||||
have_coverage = 1;
|
have_coverage = true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
have_coverage = 0;
|
have_coverage = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,11 +336,11 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem,
|
|||||||
if (!fsrv->last_run_timed_out && !stop_soon &&
|
if (!fsrv->last_run_timed_out && !stop_soon &&
|
||||||
WIFSIGNALED(fsrv->child_status)) {
|
WIFSIGNALED(fsrv->child_status)) {
|
||||||
|
|
||||||
child_crashed = 1;
|
child_crashed = true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
child_crashed = 0;
|
child_crashed = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,6 +376,13 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem,
|
|||||||
|
|
||||||
static u32 read_file(u8 *in_file) {
|
static u32 read_file(u8 *in_file) {
|
||||||
|
|
||||||
|
if (print_filenames) {
|
||||||
|
|
||||||
|
SAYF("Processing %s\n", in_file);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
s32 fd = open(in_file, O_RDONLY);
|
s32 fd = open(in_file, O_RDONLY);
|
||||||
|
|
||||||
@ -386,7 +394,18 @@ static u32 read_file(u8 *in_file) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (st.st_size > MAX_FILE) {
|
||||||
|
|
||||||
|
WARNF("Input file '%s' is too large, only reading %u bytes.", in_file,
|
||||||
|
MAX_FILE);
|
||||||
|
in_len = MAX_FILE;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
in_len = st.st_size;
|
in_len = st.st_size;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
in_data = ck_alloc_nozero(in_len);
|
in_data = ck_alloc_nozero(in_len);
|
||||||
|
|
||||||
ck_read(fd, in_data, in_len, in_file);
|
ck_read(fd, in_data, in_len, in_file);
|
||||||
@ -504,11 +523,11 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) {
|
|||||||
if (fsrv->trace_bits[0] == 1) {
|
if (fsrv->trace_bits[0] == 1) {
|
||||||
|
|
||||||
fsrv->trace_bits[0] = 0;
|
fsrv->trace_bits[0] = 0;
|
||||||
have_coverage = 1;
|
have_coverage = true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
have_coverage = 0;
|
have_coverage = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -518,7 +537,7 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) {
|
|||||||
|
|
||||||
if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(status)) {
|
if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(status)) {
|
||||||
|
|
||||||
child_crashed = 1;
|
child_crashed = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -548,7 +567,7 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) {
|
|||||||
static void handle_stop_sig(int sig) {
|
static void handle_stop_sig(int sig) {
|
||||||
|
|
||||||
(void)sig;
|
(void)sig;
|
||||||
stop_soon = 1;
|
stop_soon = true;
|
||||||
afl_fsrv_killall();
|
afl_fsrv_killall();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -731,6 +750,8 @@ static void usage(u8 *argv0) {
|
|||||||
"AFL_MAP_SIZE: the shared memory size for that target. must be >= the "
|
"AFL_MAP_SIZE: the shared memory size for that target. must be >= the "
|
||||||
"size the target was compiled for\n"
|
"size the target was compiled for\n"
|
||||||
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
|
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
|
||||||
|
"AFL_PRINT_FILENAMES: If set, the filename currently processed will be "
|
||||||
|
"printed to stdout\n"
|
||||||
"AFL_QUIET: do not print extra informational output\n",
|
"AFL_QUIET: do not print extra informational output\n",
|
||||||
argv0, MEM_LIMIT, doc_path);
|
argv0, MEM_LIMIT, doc_path);
|
||||||
|
|
||||||
@ -745,13 +766,16 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
// TODO: u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
|
// TODO: u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
|
||||||
|
|
||||||
s32 opt, i;
|
s32 opt, i;
|
||||||
u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0;
|
bool mem_limit_given = false, timeout_given = false, unicorn_mode = false,
|
||||||
|
use_wine = false;
|
||||||
char **use_argv;
|
char **use_argv;
|
||||||
|
|
||||||
char **argv = argv_cpy_dup(argc, argv_orig);
|
char **argv = argv_cpy_dup(argc, argv_orig);
|
||||||
|
|
||||||
afl_forkserver_t fsrv_var = {0};
|
afl_forkserver_t fsrv_var = {0};
|
||||||
if (getenv("AFL_DEBUG")) { debug = 1; }
|
if (getenv("AFL_DEBUG")) { debug = true; }
|
||||||
|
if (get_afl_env("AFL_PRINT_FILENAMES")) { print_filenames = true; }
|
||||||
|
|
||||||
fsrv = &fsrv_var;
|
fsrv = &fsrv_var;
|
||||||
afl_fsrv_init(fsrv);
|
afl_fsrv_init(fsrv);
|
||||||
map_size = get_map_size();
|
map_size = get_map_size();
|
||||||
@ -759,19 +783,19 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
|
|
||||||
doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
|
doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
|
||||||
|
|
||||||
if (getenv("AFL_QUIET") != NULL) { be_quiet = 1; }
|
if (getenv("AFL_QUIET") != NULL) { be_quiet = true; }
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZOQUWbcrsh")) > 0) {
|
while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZOQUWbcrsh")) > 0) {
|
||||||
|
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
no_classify = 1;
|
no_classify = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'C':
|
case 'C':
|
||||||
collect_coverage = 1;
|
collect_coverage = true;
|
||||||
quiet_mode = 1;
|
quiet_mode = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'i':
|
case 'i':
|
||||||
@ -790,7 +814,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
u8 suffix = 'M';
|
u8 suffix = 'M';
|
||||||
|
|
||||||
if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
|
if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
|
||||||
mem_limit_given = 1;
|
mem_limit_given = true;
|
||||||
|
|
||||||
if (!optarg) { FATAL("Wrong usage of -m"); }
|
if (!optarg) { FATAL("Wrong usage of -m"); }
|
||||||
|
|
||||||
@ -851,7 +875,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
case 't':
|
case 't':
|
||||||
|
|
||||||
if (timeout_given) { FATAL("Multiple -t options not supported"); }
|
if (timeout_given) { FATAL("Multiple -t options not supported"); }
|
||||||
timeout_given = 1;
|
timeout_given = true;
|
||||||
|
|
||||||
if (!optarg) { FATAL("Wrong usage of -t"); }
|
if (!optarg) { FATAL("Wrong usage of -t"); }
|
||||||
|
|
||||||
@ -873,12 +897,12 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
|
|
||||||
if (edges_only) { FATAL("Multiple -e options not supported"); }
|
if (edges_only) { FATAL("Multiple -e options not supported"); }
|
||||||
if (raw_instr_output) { FATAL("-e and -r are mutually exclusive"); }
|
if (raw_instr_output) { FATAL("-e and -r are mutually exclusive"); }
|
||||||
edges_only = 1;
|
edges_only = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'q':
|
case 'q':
|
||||||
|
|
||||||
quiet_mode = 1;
|
quiet_mode = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'Z':
|
case 'Z':
|
||||||
@ -886,8 +910,8 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
/* This is an undocumented option to write data in the syntax expected
|
/* This is an undocumented option to write data in the syntax expected
|
||||||
by afl-cmin. Nobody else should have any use for this. */
|
by afl-cmin. Nobody else should have any use for this. */
|
||||||
|
|
||||||
cmin_mode = 1;
|
cmin_mode = true;
|
||||||
quiet_mode = 1;
|
quiet_mode = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'A':
|
case 'A':
|
||||||
@ -899,7 +923,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
|
|
||||||
if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); }
|
if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); }
|
||||||
|
|
||||||
fsrv->frida_mode = 1;
|
fsrv->frida_mode = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -907,21 +931,21 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
|
|
||||||
if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); }
|
if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); }
|
||||||
|
|
||||||
fsrv->qemu_mode = 1;
|
fsrv->qemu_mode = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'U':
|
case 'U':
|
||||||
|
|
||||||
if (unicorn_mode) { FATAL("Multiple -U options not supported"); }
|
if (unicorn_mode) { FATAL("Multiple -U options not supported"); }
|
||||||
|
|
||||||
unicorn_mode = 1;
|
unicorn_mode = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'W': /* Wine+QEMU mode */
|
case 'W': /* Wine+QEMU mode */
|
||||||
|
|
||||||
if (use_wine) { FATAL("Multiple -W options not supported"); }
|
if (use_wine) { FATAL("Multiple -W options not supported"); }
|
||||||
fsrv->qemu_mode = 1;
|
fsrv->qemu_mode = true;
|
||||||
use_wine = 1;
|
use_wine = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -930,20 +954,20 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
/* Secret undocumented mode. Writes output in raw binary format
|
/* Secret undocumented mode. Writes output in raw binary format
|
||||||
similar to that dumped by afl-fuzz in <out_dir/queue/fuzz_bitmap. */
|
similar to that dumped by afl-fuzz in <out_dir/queue/fuzz_bitmap. */
|
||||||
|
|
||||||
binary_mode = 1;
|
binary_mode = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
|
|
||||||
if (keep_cores) { FATAL("Multiple -c options not supported"); }
|
if (keep_cores) { FATAL("Multiple -c options not supported"); }
|
||||||
keep_cores = 1;
|
keep_cores = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'r':
|
case 'r':
|
||||||
|
|
||||||
if (raw_instr_output) { FATAL("Multiple -r options not supported"); }
|
if (raw_instr_output) { FATAL("Multiple -r options not supported"); }
|
||||||
if (edges_only) { FATAL("-e and -r are mutually exclusive"); }
|
if (edges_only) { FATAL("-e and -r are mutually exclusive"); }
|
||||||
raw_instr_output = 1;
|
raw_instr_output = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
@ -1053,7 +1077,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
/* initialize cmplog_mode */
|
/* initialize cmplog_mode */
|
||||||
shm_fuzz->cmplog_mode = 0;
|
shm_fuzz->cmplog_mode = 0;
|
||||||
u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1);
|
u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1);
|
||||||
shm_fuzz->shmemfuzz_mode = 1;
|
shm_fuzz->shmemfuzz_mode = true;
|
||||||
if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
|
if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
|
||||||
#ifdef USEMMAP
|
#ifdef USEMMAP
|
||||||
setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1);
|
setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1);
|
||||||
@ -1062,7 +1086,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
setenv(SHM_FUZZ_ENV_VAR, shm_str, 1);
|
setenv(SHM_FUZZ_ENV_VAR, shm_str, 1);
|
||||||
ck_free(shm_str);
|
ck_free(shm_str);
|
||||||
#endif
|
#endif
|
||||||
fsrv->support_shmem_fuzz = 1;
|
fsrv->support_shmem_fuzz = true;
|
||||||
fsrv->shmem_fuzz_len = (u32 *)map;
|
fsrv->shmem_fuzz_len = (u32 *)map;
|
||||||
fsrv->shmem_fuzz = map + sizeof(u32);
|
fsrv->shmem_fuzz = map + sizeof(u32);
|
||||||
|
|
||||||
@ -1114,7 +1138,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = 1;
|
if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true;
|
||||||
|
|
||||||
fsrv->dev_null_fd = open("/dev/null", O_RDWR);
|
fsrv->dev_null_fd = open("/dev/null", O_RDWR);
|
||||||
if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
|
if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
|
||||||
@ -1153,8 +1177,8 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
|
|
||||||
if ((coverage_map = (u8 *)malloc(map_size)) == NULL)
|
if ((coverage_map = (u8 *)malloc(map_size)) == NULL)
|
||||||
FATAL("coult not grab memory");
|
FATAL("coult not grab memory");
|
||||||
edges_only = 0;
|
edges_only = false;
|
||||||
raw_instr_output = 1;
|
raw_instr_output = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user