Merge branch 'dev' of github.com:AFLplusplus/AFLplusplus into dev

This commit is contained in:
Andrea Fioraldi 2021-10-19 13:59:38 +02:00
commit 23e69f1107
52 changed files with 565 additions and 505 deletions

112
README.md
View File

@ -6,7 +6,8 @@ Release version: [3.14c](https://github.com/AFLplusplus/AFLplusplus/releases)
GitHub version: 3.15a
Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
Repository:
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
AFL++ is maintained by:
@ -17,57 +18,74 @@ AFL++ is maintained by:
Originally developed by Michał "lcamtuf" Zalewski.
AFL++ is a superior fork to Google's AFL - more speed, more and better mutations, more and better instrumentation, custom module support, etc.
AFL++ is a superior fork to Google's AFL - more speed, more and better
mutations, more and better instrumentation, custom module support, etc.
You are free to copy, modify, and distribute AFL++ with attribution under the terms of the Apache-2.0 License. See the [LICENSE](LICENSE) for details.
You are free to copy, modify, and distribute AFL++ with attribution under the
terms of the Apache-2.0 License. See the [LICENSE](LICENSE) for details.
## Getting started
Here is some information to get you started:
* For releases, please see the [Releases](https://github.com/AFLplusplus/AFLplusplus/releases) tab and [branches](docs/branches.md). Also take a look at the list of [major behaviour changes in AFL++](docs/behaviour_changes.md).
* If you want to use AFL++ for your academic work, check the [papers page](https://aflplus.plus/papers/) on the website.
* For releases, please see the
[Releases](https://github.com/AFLplusplus/AFLplusplus/releases) tab and
[branches](docs/branches.md). Also take a look at the list of
[important changes in AFL++](docs/important_changes.md).
* If you want to use AFL++ for your academic work, check the
[papers page](https://aflplus.plus/papers/) on the website.
* To cite our work, look at the [Cite](#cite) section.
* For comparisons, use the fuzzbench `aflplusplus` setup, or use `afl-clang-fast` with `AFL_LLVM_CMPLOG=1`. You can find the `aflplusplus` default configuration on Google's [fuzzbench](https://github.com/google/fuzzbench/tree/master/fuzzers/aflplusplus).
* To get you started with tutorials, go to [docs/tutorials.md](docs/tutorials.md).
* For comparisons, use the fuzzbench `aflplusplus` setup, or use
`afl-clang-fast` with `AFL_LLVM_CMPLOG=1`. You can find the `aflplusplus`
default configuration on Google's
[fuzzbench](https://github.com/google/fuzzbench/tree/master/fuzzers/aflplusplus).
* To get you started with tutorials, go to
[docs/tutorials.md](docs/tutorials.md).
## Building and installing AFL++
To have AFL++ easily available with everything compiled, pull the image directly from the Docker Hub:
To have AFL++ easily available with everything compiled, pull the image
directly from the Docker Hub:
```shell
docker pull aflplusplus/aflplusplus
docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus
```
This image is automatically generated when a push to the stable repo happens (see [docs/branches.md](docs/branches.md)).
You will find your target source code in `/src` in the container.
This image is automatically generated when a push to the stable repo happens
(see [docs/branches.md](docs/branches.md)). You will find your target source
code in `/src` in the container.
To build AFL++ yourself, continue at [docs/INSTALL.md](docs/INSTALL.md).
## Quick start: Fuzzing with AFL++
*NOTE: Before you start, please read about the [common sense risks of fuzzing](docs/common_sense_risks.md).*
*NOTE: Before you start, please read about the [common sense risks of
fuzzing](docs/common_sense_risks.md).*
This is a quick start for fuzzing targets with the source code available.
To read about the process in detail, see [docs/fuzzing_expert.md](docs/fuzzing_expert.md).
This is a quick start for fuzzing targets with the source code available. To
read about the process in detail, see
[docs/fuzzing_expert.md](docs/fuzzing_expert.md).
To learn about fuzzing other targets, see:
* Binary-only targets: [docs/fuzzing_binary-only_targets.md](docs/fuzzing_binary-only_targets.md)
* Network services: [docs/best_practices.md#fuzzing-a-network-service](docs/best_practices.md#fuzzing-a-network-service)
* GUI programs: [docs/best_practices.md#fuzzing-a-gui-program](docs/best_practices.md#fuzzing-a-gui-program)
* Binary-only targets:
[docs/fuzzing_binary-only_targets.md](docs/fuzzing_binary-only_targets.md)
* Network services:
[docs/best_practices.md#fuzzing-a-network-service](docs/best_practices.md#fuzzing-a-network-service)
* GUI programs:
[docs/best_practices.md#fuzzing-a-gui-program](docs/best_practices.md#fuzzing-a-gui-program)
Step-by-step quick start:
1. Compile the program or library to be fuzzed using `afl-cc`.
A common way to do this would be:
1. Compile the program or library to be fuzzed using `afl-cc`. A common way to
do this would be:
CC=/path/to/afl-cc CXX=/path/to/afl-c++ ./configure --disable-shared
make clean all
2. Get a small but valid input file that makes sense to the program.
When fuzzing verbose syntax (SQL, HTTP, etc), create a dictionary as described
in [dictionaries/README.md](../dictionaries/README.md), too.
2. Get a small but valid input file that makes sense to the program. When
fuzzing verbose syntax (SQL, HTTP, etc), create a dictionary as described in
[dictionaries/README.md](dictionaries/README.md), too.
3. If the program reads from stdin, run `afl-fuzz` like so:
@ -78,42 +96,52 @@ in [dictionaries/README.md](../dictionaries/README.md), too.
To add a dictionary, add `-x /path/to/dictionary.txt` to afl-fuzz.
If the program takes input from a file, you can put `@@` in the program's
If the program takes input from a file, you can put `@@` in the program's
command line; AFL will put an auto-generated file name in there for you.
4. Investigate anything shown in red in the fuzzer UI by promptly consulting [docs/status_screen.md](docs/status_screen.md).
4. Investigate anything shown in red in the fuzzer UI by promptly consulting
[docs/status_screen.md](docs/status_screen.md).
5. You will find found crashes and hangs in the subdirectories `crashes/` and
`hangs/` in the `-o output_dir` directory. You can replay the crashes by
feeding them to the target, e.g.:
`cat output_dir/crashes/id:000000,* | /path/to/tested/program [...program's cmdline...]`
You can generate cores or use gdb directly to follow up the crashes.
5. You will find found crashes and hangs in the subdirectories `crashes/` and
`hangs/` in the `-o output_dir` directory. You can replay the crashes by
feeding them to the target, e.g.: `cat output_dir/crashes/id:000000,* |
/path/to/tested/program [...program's cmdline...]` You can generate cores or
use gdb directly to follow up the crashes.
## Contact
Questions? Concerns? Bug reports?
* The contributors can be reached via [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus).
* Take a look at our [FAQ](docs/faq.md). If you find an interesting or important question missing, submit it via
[https://github.com/AFLplusplus/AFLplusplus/discussions](https://github.com/AFLplusplus/AFLplusplus/discussions).
* There is a mailing list for the AFL/AFL++ project ([browse archive](https://groups.google.com/group/afl-users)). To compare notes with other users or to get notified about major new features, send an email to <afl-users+subscribe@googlegroups.com>.
* The contributors can be reached via
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus).
* Take a look at our [FAQ](docs/FAQ.md). If you find an interesting or
important question missing, submit it via
[https://github.com/AFLplusplus/AFLplusplus/discussions](https://github.com/AFLplusplus/AFLplusplus/discussions).
* There is a mailing list for the AFL/AFL++ project
([browse archive](https://groups.google.com/group/afl-users)). To compare
notes with other users or to get notified about major new features, send an
email to <afl-users+subscribe@googlegroups.com>.
* Or join the [Awesome Fuzzing](https://discord.gg/gCraWct) Discord server.
## Help wanted
We have several [ideas](docs/ideas.md) we would like to see in AFL++ to make it even better.
However, we already work on so many things that we do not have the time for all the big ideas.
We have several [ideas](docs/ideas.md) we would like to see in AFL++ to make it
even better. However, we already work on so many things that we do not have the
time for all the big ideas.
This can be your way to support and contribute to AFL++ - extend it to do something cool.
This can be your way to support and contribute to AFL++ - extend it to do
something cool.
For everyone who wants to contribute (and send pull requests), please read our [contributing guidelines](CONTRIBUTING.md) before your submit.
For everyone who wants to contribute (and send pull requests), please read our
[contributing guidelines](CONTRIBUTING.md) before your submit.
## Special thanks
Many of the improvements to the original AFL and AFL++ wouldn't be possible without feedback, bug reports, or patches from our contributors.
Many of the improvements to the original AFL and AFL++ wouldn't be possible
without feedback, bug reports, or patches from our contributors.
Thank you!
(For people sending pull requests - please add yourself to this list :-)
Thank you! (For people sending pull requests - please add yourself to this list
:-)
<details>
@ -172,7 +200,9 @@ Thank you!
## Cite
If you use AFL++ in scientific work, consider citing [our paper](https://www.usenix.org/conference/woot20/presentation/fioraldi) presented at WOOT'20:
If you use AFL++ in scientific work, consider citing
[our paper](https://www.usenix.org/conference/woot20/presentation/fioraldi)
presented at WOOT'20:
Andrea Fioraldi, Dominik Maier, Heiko Eißfeldt, and Marc Heuse. “AFL++: Combining incremental steps of fuzzing research”. In 14th USENIX Workshop on Offensive Technologies (WOOT 20). USENIX Association, Aug. 2020.
@ -191,4 +221,4 @@ If you use AFL++ in scientific work, consider citing [our paper](https://www.use
}
```
</details>
</details>

@ -1 +1 @@
Subproject commit eedf07ddb0fb1f437f5e76b77cfd4064cf6a5d63
Subproject commit b79d51a8daccbd7a693f9b6765c81ead14f28e26

View File

@ -1086,6 +1086,7 @@ ATTRIBUTE_INTERFACE size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size,
size_t MaxSize) {
assert(fuzzer::F);
fuzzer::F->GetMD().StartMutationSequence();
size_t r = fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize);
#ifdef INTROSPECTION
introspection_ptr = fuzzer::F->GetMD().WriteMutationSequence();

View File

@ -16,11 +16,16 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- fix a regression introduced in 3.10 that resulted in less
coverage being detected. thanks to Collin May for reporting!
- fix -n dumb mode (nobody should use this)
- fix stability issue with LTO and cmplog
- better banner
- frida_mode: David Carlier added Android support :)
- afl-showmap, afl-tmin and afl-analyze now honor persistent mode
for more speed. thanks to dloffre-snl for reporting!
- Prevent accidently killing non-afl/fuzz services when aborting
afl-showmap and other tools.
- afl-cc:
- fix for shared linking on MacOS
- llvm and LTO mode verified to work with new llvm 14-dev
- llvm and LTO mode modified to work with new llvm 14-dev (again)
- added the very good grammar mutator "GramaTron" to the
custom_mutators
- added optimin, a faster and better corpus minimizer by
@ -32,6 +37,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- fix AFL_PRELOAD issues on MacOS
- removed utils/afl_frida because frida_mode/ is now so much better
- added uninstall target to makefile (todo: update new readme!)
- removed indirections in rust callbacks for unicornafl
### Version ++3.14c (release)

View File

@ -59,10 +59,10 @@ which allows you to define network state with different type of data packets.
1. Use [llvm_mode](../instrumentation/README.llvm.md): afl-clang-lto (llvm >= 11) or afl-clang-fast (llvm >= 9 recommended).
2. Use [persistent mode](../instrumentation/README.persistent_mode.md) (x2-x20 speed increase).
3. Use the [AFL++ snapshot module](https://github.com/AFLplusplus/AFL-Snapshot-LKM) (x2 speed increase).
4. If you do not use shmem persistent mode, use `AFL_TMPDIR` to put the input file directory on a tempfs location, see [docs/env_variables.md](docs/env_variables.md).
4. If you do not use shmem persistent mode, use `AFL_TMPDIR` to put the input file directory on a tempfs location, see [env_variables.md](env_variables.md).
5. Improve Linux kernel performance: modify `/etc/default/grub`, set `GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"`; then `update-grub` and `reboot` (warning: makes the system less secure).
6. Running on an `ext2` filesystem with `noatime` mount option will be a bit faster than on any other journaling filesystem.
7. Use your cores! [README.md:3.b) Using multiple cores/threads](../README.md#b-using-multiple-coresthreads).
7. Use your cores! [fuzzing_expert.md:b) Using multiple cores](fuzzing_expert.md#b-using-multiple-cores).
### Improving stability
@ -117,4 +117,4 @@ Four steps are required to do this and it also requires quite some knowledge of
Recompile, fuzz it, be happy :)
This link explains this process for [Fuzzbench](https://github.com/google/fuzzbench/issues/677).
This link explains this process for [Fuzzbench](https://github.com/google/fuzzbench/issues/677).

View File

@ -7,4 +7,5 @@ The following branches exist:
* [dev](https://github.com/AFLplusplus/AFLplusplus/tree/dev): development state of AFL++ - bleeding edge and you might catch a checkout which does not compile or has a bug. *We only accept PRs in dev!!*
* (any other): experimental branches to work on specific features or testing new functionality or changes.
For releases, please see the [Releases](https://github.com/AFLplusplus/AFLplusplus/releases) tab. Also take a look at the list of [major behaviour changes in AFL++](behaviour_changes.md).
For releases, please see the [Releases](https://github.com/AFLplusplus/AFLplusplus/releases) tab.
Also take a look at the list of [important changes in AFL++](important_changes.md).

View File

@ -2,7 +2,7 @@
This document discusses the environment variables used by American Fuzzy Lop++
to expose various exotic functions that may be (rarely) useful for power
users or for some types of custom fuzzing setups. See [README.md](README.md) for the general
users or for some types of custom fuzzing setups. See [../README.md](../README.md) for the general
instruction manual.
Note that most tools will warn on any unknown AFL environment variables.
@ -422,7 +422,7 @@ checks or alter some of the more exotic semantics of the tool:
- Setting `AFL_FORCE_UI` will force painting the UI on the screen even if
no valid terminal was detected (for virtual consoles)
- If you are using persistent mode (you should, see [instrumentation/README.persistent_mode.md](instrumentation/README.persistent_mode.md))
- If you are using persistent mode (you should, see [instrumentation/README.persistent_mode.md](../instrumentation/README.persistent_mode.md))
some targets keep inherent state due which a detected crash testcase does
not crash the target again when the testcase is given. To be able to still
re-trigger these crashes you can use the `AFL_PERSISTENT_RECORD` variable

View File

@ -72,7 +72,7 @@ cd unicorn_mode
If the goal is to fuzz a dynamic library then there are two options available.
For both you need to write a small harness that loads and calls the library.
Then you fuzz this with either frida_mode or qemu_mode, and either use
`AFL_INST_LIBS=1` or `AFL_QEMU/FRIDA_INST_RANGES`
`AFL_INST_LIBS=1` or `AFL_QEMU/FRIDA_INST_RANGES`.
Another, less precise and slower option is using ptrace with debugger interrupt
instrumentation: [utils/afl_untracer/README.md](../utils/afl_untracer/README.md).

View File

@ -613,7 +613,7 @@ switch or honggfuzz.
* If you do not use shmem persistent mode, use `AFL_TMPDIR` to point the input file on a tempfs location, see [env_variables.md](env_variables.md)
* Linux: Improve kernel performance: modify `/etc/default/grub`, set `GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"`; then `update-grub` and `reboot` (warning: makes the system more insecure) - you can also just run `sudo afl-persistent-config`
* Linux: Running on an `ext2` filesystem with `noatime` mount option will be a bit faster than on any other journaling filesystem
* Use your cores! [3.b) Using multiple cores/threads](#b-using-multiple-coresthreads)
* Use your cores! [b) Using multiple cores](#b-using-multiple-cores)
* Run `sudo afl-system-config` before starting the first afl-fuzz instance after a reboot
### The End
@ -625,4 +625,4 @@ This is basically all you need to know to professionally run fuzzing campaigns.
If you want to know more, the tons of texts in [docs/](./) will have you covered.
Note that there are also a lot of tools out there that help fuzzing with AFL++
(some might be deprecated or unsupported), see [links_tools.md](links_tools.md).
(some might be deprecated or unsupported), see [tools.md](tools.md).

View File

@ -1,6 +1,6 @@
# Interpreting output
See the [docs/status_screen.md](docs/status_screen.md) file for information on
See the [status_screen.md](status_screen.md) file for information on
how to interpret the displayed stats and monitor the health of the process. Be
sure to consult this file especially if any UI elements are highlighted in red.
@ -68,4 +68,4 @@ cd utils/plot_ui
make
cd ../../
sudo make install
```
```

View File

@ -15,7 +15,7 @@ Here are some of the most important caveats for AFL:
To work around this, you can comment out the relevant checks (see
utils/libpng_no_checksum/ for inspiration); if this is not possible,
you can also write a postprocessor, one of the hooks of custom mutators.
See [docs/custom_mutators.md](docs/custom_mutators.md) on how to use
See [custom_mutators.md](custom_mutators.md) on how to use
`AFL_CUSTOM_MUTATOR_LIBRARY`
- There are some unfortunate trade-offs with ASAN and 64-bit binaries. This
@ -33,4 +33,4 @@ Here are some of the most important caveats for AFL:
- Occasionally, sentient machines rise against their creators. If this
happens to you, please consult [http://lcamtuf.coredump.cx/prep/](http://lcamtuf.coredump.cx/prep/).
Beyond this, see [INSTALL.md](INSTALL.md) for platform-specific tips.
Beyond this, see [INSTALL.md](INSTALL.md) for platform-specific tips.

View File

@ -1,87 +0,0 @@
# AFL "Life Pro Tips"
Bite-sized advice for those who understand the basics, but can't be bothered
to read or memorize every other piece of documentation for AFL.
## Get more bang for your buck by using fuzzing dictionaries.
See [dictionaries/README.md](../dictionaries/README.md) to learn how.
## You can get the most out of your hardware by parallelizing AFL jobs.
See [parallel_fuzzing.md](parallel_fuzzing.md) for step-by-step tips.
## Improve the odds of spotting memory corruption bugs with libdislocator.so!
It's easy. Consult [utils/libdislocator/README.md](../utils/libdislocator/README.md) for usage tips.
## Want to understand how your target parses a particular input file?
Try the bundled `afl-analyze` tool; it's got colors and all!
## You can visually monitor the progress of your fuzzing jobs.
Run the bundled `afl-plot` utility to generate browser-friendly graphs.
## Need to monitor AFL jobs programmatically?
Check out the `fuzzer_stats` file in the AFL output dir or try `afl-whatsup`.
## Puzzled by something showing up in red or purple in the AFL UI?
It could be important - consult docs/status_screen.md right away!
## Know your target? Convert it to persistent mode for a huge performance gain!
Consult section #5 in README.llvm.md for tips.
## Using clang?
Check out instrumentation/ for a faster alternative to afl-gcc!
## Did you know that AFL can fuzz closed-source or cross-platform binaries?
Check out qemu_mode/README.md and unicorn_mode/README.md for more.
## Did you know that afl-fuzz can minimize any test case for you?
Try the bundled `afl-tmin` tool - and get small repro files fast!
## Not sure if a crash is exploitable? AFL can help you figure it out. Specify
`-C` to enable the peruvian were-rabbit mode.
## Trouble dealing with a machine uprising? Relax, we've all been there.
Find essential survival tips at http://lcamtuf.coredump.cx/prep/.
## Want to automatically spot non-crashing memory handling bugs?
Try running an AFL-generated corpus through ASAN, MSAN, or Valgrind.
## Good selection of input files is critical to a successful fuzzing job.
See docs/perf_tips.md for pro tips.
## You can improve the odds of automatically spotting stack corruption issues.
Specify `AFL_HARDEN=1` in the environment to enable hardening flags.
## Bumping into problems with non-reproducible crashes?
It happens, but usually
isn't hard to diagnose. See section #7 in README.md for tips.
## Fuzzing is not just about memory corruption issues in the codebase.
Add some
sanity-checking `assert()` / `abort()` statements to effortlessly catch logic bugs.
## Hey kid... pssst... want to figure out how AFL really works?
Check out docs/technical_details.md for all the gory details in one place!
## There's a ton of third-party helper tools designed to work with AFL!
Be sure to check out docs/sister_projects.md before writing your own.
## Need to fuzz the command-line arguments of a particular program?
You can find a simple solution in utils/argv_fuzzing.
## Attacking a format that uses checksums?
Remove the checksum-checking code or use a postprocessor!
See `afl_custom_post_process` in custom_mutators/examples/example.c for more.

View File

@ -4,7 +4,7 @@ This document talks about synchronizing afl-fuzz jobs on a single machine
or across a fleet of systems. See README.md for the general instruction manual.
Note that this document is rather outdated. please refer to the main document
section on multiple core usage [../README.md#Using multiple cores](../README.md#b-using-multiple-coresthreads)
section on multiple core usage [fuzzing_expert.md#Using multiple cores](fuzzing_expert.md#b-using-multiple-cores)
for up to date strategies!
## 1) Introduction

View File

@ -50,7 +50,7 @@ Depending on your StatsD server, you will be able to monitor, trigger alerts, or
- `librato`
- `signalfx`
For more information on environment variables, see [docs/env_variables.md](docs/env_variables.md).
For more information on environment variables, see [env_variables.md](env_variables.md).
Note: When using multiple fuzzer instances with StatsD it is *strongly* recommended to set up `AFL_STATSD_TAGS_FLAVOR` to match your StatsD server. This will allow you to see individual fuzzer performance, detect bad ones, and see the progress of each strategy.
@ -152,4 +152,4 @@ To run your fuzzing instances:
AFL_STATSD_TAGS_FLAVOR=dogstatsd AFL_STATSD=1 afl-fuzz -M test-fuzzer-1 -i i -o o [./bin/my-application] @@
AFL_STATSD_TAGS_FLAVOR=dogstatsd AFL_STATSD=1 afl-fuzz -S test-fuzzer-2 -i i -o o [./bin/my-application] @@
...
```
```

View File

@ -43,4 +43,4 @@ file, attempts to sequentially flip bytes, and observes the behavior of the
tested program. It then color-codes the input based on which sections appear to
be critical, and which are not; while not bulletproof, it can often offer quick
insights into complex file formats. More info about its operation can be found
near the end of [docs/technical_details.md](docs/technical_details.md).
near the end of [technical_details.md](technical_details.md).

View File

@ -30,8 +30,7 @@ AFL_CFLAGS:=-Wno-unused-parameter \
LDFLAGS+=-shared \
-lpthread \
-lresolv \
-ldl
-lresolv
ifdef DEBUG
CFLAGS+=-Werror \
@ -71,7 +70,9 @@ ifdef DEBUG
endif
LDFLAGS+= -z noexecstack \
-Wl,--gc-sections \
-Wl,--exclude-libs,ALL
-Wl,--exclude-libs,ALL \
-ldl \
-lrt
LDSCRIPT:=-Wl,--version-script=$(PWD)frida.map
endif
@ -79,6 +80,22 @@ ifeq "$(shell uname)" "Linux"
OS:=linux
endif
ifneq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
OS:=android
ifneq "$(findstring aarch64, $(shell $(CC) --version 2>/dev/null))" ""
ARCH:=arm64
endif
ifneq "$(findstring arm, $(shell $(CC) --version 2>/dev/null))" ""
ARCH:=arm
endif
ifneq "$(findstring x86_64, $(shell $(CC) --version 2>/dev/null))" ""
ARCH:=x86_64
endif
ifneq "$(findstring i686, $(shell $(CC) --version 2>/dev/null))" ""
ARCH:=x86
endif
endif
ifndef OS
$(error "Operating system unsupported")
endif

View File

@ -55,6 +55,20 @@ 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.
### Android
In order to build, you need to download the Android SDK.
```
https://developer.android.com/ndk/downloads
```
Then creating locally a standalone chain as follow.
```
https://developer.android.com/ndk/guides/standalone_toolchain
```
## Usage
FRIDA mode added some small modifications to `afl-fuzz` and similar tools

View File

@ -29,6 +29,7 @@ GumStalkerTransformer *instrument_get_transformer(void);
/* Functions to be implemented by the different architectures */
gboolean instrument_is_coverage_optimize_supported(void);
void instrument_coverage_optimize_init(void);
void instrument_coverage_optimize(const cs_insn * instr,
GumStalkerOutput *output);

View File

@ -10,6 +10,8 @@ extern gboolean ranges_inst_jit;
void ranges_config(void);
void ranges_init(void);
void ranges_print_debug_maps(void);
gboolean range_is_excluded(GumAddress address);
void ranges_exclude();

View File

@ -356,6 +356,7 @@ void instrument_init(void) {
instrument_hash_seed);
instrument_hash_zero = instrument_get_offset_hash(0);
instrument_coverage_optimize_init();
instrument_debug_init();
instrument_coverage_init();
asan_init();

View File

@ -22,6 +22,10 @@ void instrument_coverage_optimize(const cs_insn * instr,
}
void instrument_coverage_optimize_init(void) {
WARNF("Optimized coverage not supported on this architecture");
}
void instrument_flush(GumStalkerOutput *output) {
gum_arm_writer_flush(output->writer.arm);

View File

@ -95,6 +95,9 @@ void instrument_coverage_optimize(const cs_insn * instr,
}
void instrument_coverage_optimize_init(void) {
}
void instrument_flush(GumStalkerOutput *output) {
gum_arm64_writer_flush(output->writer.arm64);

View File

@ -1,4 +1,16 @@
#include <fcntl.h>
#include <stddef.h>
#include <sys/mman.h>
#include <sys/shm.h>
#if defined(__linux__)
#if !defined(__ANDROID__)
#include <asm/prctl.h>
#include <sys/syscall.h>
#else
#include <linux/ashmem.h>
#endif
#endif
#include "frida-gumjs.h"
@ -6,125 +18,17 @@
#include "debug.h"
#include "instrument.h"
#include "ranges.h"
#if defined(__x86_64__)
static GumAddress current_log_impl = GUM_ADDRESS(0);
#pragma pack(push, 1)
typedef struct {
/*
* pushfq
* push rdx
* mov rdx, [&previouspc] (rip relative addr)
* xor rdx, rdi (current_pc)
* shr rdi. 1
* mov [&previouspc], rdi
* lea rsi, [&_afl_area_ptr] (rip relative)
* add rdx, rsi
* add byte ptr [rdx], 1
* adc byte ptr [rdx], 0
* pop rdx
* popfq
*/
uint8_t push_fq;
uint8_t push_rdx;
uint8_t mov_rdx_rip_off[7];
uint8_t xor_rdx_rdi[3];
uint8_t shr_rdi[3];
uint8_t mov_rip_off_rdi[7];
uint8_t lea_rdi_rip_off[7];
uint8_t add_rdx_rdi[3];
uint8_t add_byte_ptr_rdx[3];
uint8_t adc_byte_ptr_rdx[3];
uint8_t pop_rdx;
uint8_t pop_fq;
uint8_t ret;
} afl_log_code_asm_t;
#pragma pack(pop)
#pragma pack(push, 8)
typedef struct {
afl_log_code_asm_t assembly;
uint64_t current_pc;
} afl_log_code_t;
#pragma pack(pop)
typedef union {
afl_log_code_t data;
uint8_t bytes[0];
} afl_log_code;
static const afl_log_code_asm_t template = {
.push_fq = 0x9c,
.push_rdx = 0x52,
.mov_rdx_rip_off =
{
0x48, 0x8b, 0x15,
/* TBC */
},
.xor_rdx_rdi =
{
0x48,
0x31,
0xfa,
},
.shr_rdi = {0x48, 0xd1, 0xef},
.mov_rip_off_rdi = {0x48, 0x89, 0x3d},
.lea_rdi_rip_off =
{
0x48,
0x8d,
0x3d,
},
.add_rdx_rdi = {0x48, 0x01, 0xfA},
.add_byte_ptr_rdx =
{
0x80,
0x02,
0x01,
},
.adc_byte_ptr_rdx =
{
0x80,
0x12,
0x00,
},
.pop_rdx = 0x5a,
.pop_fq = 0x9d,
.ret = 0xc3};
static guint8 align_pad[] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
#ifndef MAP_FIXED_NOREPLACE
#ifdef MAP_EXCL
#define MAP_FIXED_NOREPLACE MAP_EXCL | MAP_FIXED
#else
#define MAP_FIXED_NOREPLACE MAP_FIXED
#endif
#endif
gboolean instrument_is_coverage_optimize_supported(void) {
@ -138,113 +42,266 @@ static gboolean instrument_coverage_in_range(gssize offset) {
}
static void instrument_coverate_write_function(GumStalkerOutput *output) {
#pragma pack(push, 1)
typedef struct {
guint64 misalign = 0;
GumX86Writer *cw = output->writer.x86;
GumAddress code_addr = 0;
afl_log_code code = {0};
/*guint64 instrument_hash_zero = 0;*/
// cur_location = (block_address >> 4) ^ (block_address << 8);
// shared_mem[cur_location ^ prev_location]++;
// prev_location = cur_location >> 1;
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)) {
// => 0x7ffff6cfb086: lea rsp,[rsp-0x80]
// 0x7ffff6cfb08b: pushf
// 0x7ffff6cfb08c: push rsi
// 0x7ffff6cfb08d: mov rsi,0x228
// 0x7ffff6cfb094: xchg QWORD PTR [rip+0x3136a5],rsi # 0x7ffff700e740
// 0x7ffff6cfb09b: xor rsi,0x451
// 0x7ffff6cfb0a2: add BYTE PTR [rsi+0x10000],0x1
// 0x7ffff6cfb0a9: adc BYTE PTR [rsi+0x10000],0x0
// 0x7ffff6cfb0b0: pop rsi
// 0x7ffff6cfb0b1: popf
// 0x7ffff6cfb0b2: lea rsp,[rsp+0x80]
gconstpointer after_log_impl = cw->code + 1;
gum_x86_writer_put_jmp_near_label(cw, after_log_impl);
uint8_t lea_rsp_rsp_sub_rz[5];
uint8_t push_fq;
uint8_t push_rsi;
misalign = (cw->pc & 0x7);
if (misalign != 0) {
uint8_t mov_rsi_curr_loc_shr_1[7];
uint8_t xchg_rsi_prev_loc_curr_loc[7];
uint8_t xor_rsi_curr_loc[7];
gum_x86_writer_put_bytes(cw, align_pad, 8 - misalign);
uint8_t add_rsi_1[7];
uint8_t adc_rsi_0[7];
}
uint8_t pop_rsi;
uint8_t pop_fq;
uint8_t lsa_rsp_rsp_add_rz[8];
current_log_impl = cw->pc;
// gum_x86_writer_put_breakpoint(cw);
code_addr = cw->pc;
} afl_log_code_asm_t;
code.data.assembly = template;
code.data.current_pc = instrument_get_offset_hash(0);
#pragma pack(pop)
gssize current_pc_value1 =
GPOINTER_TO_SIZE(&instrument_previous_pc) -
(code_addr + offsetof(afl_log_code, data.assembly.mov_rdx_rip_off) +
sizeof(code.data.assembly.mov_rdx_rip_off));
gssize patch_offset1 =
offsetof(afl_log_code, data.assembly.mov_rdx_rip_off) +
sizeof(code.data.assembly.mov_rdx_rip_off) - sizeof(gint);
if (!instrument_coverage_in_range(current_pc_value1)) {
typedef union {
FATAL("Patch out of range (current_pc_value1): 0x%016lX",
current_pc_value1);
afl_log_code_asm_t code;
uint8_t bytes[0];
}
} afl_log_code;
gint *dst_pc_value = (gint *)&code.bytes[patch_offset1];
*dst_pc_value = (gint)current_pc_value1;
static const afl_log_code_asm_t template =
{
gssize current_pc_value2 =
GPOINTER_TO_SIZE(&instrument_previous_pc) -
(code_addr + offsetof(afl_log_code, data.assembly.mov_rip_off_rdi) +
sizeof(code.data.assembly.mov_rip_off_rdi));
gssize patch_offset2 =
offsetof(afl_log_code, data.assembly.mov_rip_off_rdi) +
sizeof(code.data.assembly.mov_rip_off_rdi) - sizeof(gint);
.lea_rsp_rsp_sub_rz = {0x48, 0x8D, 0x64, 0x24, 0x80},
.push_fq = 0x9c,
.push_rsi = 0x56,
if (!instrument_coverage_in_range(current_pc_value2)) {
.mov_rsi_curr_loc_shr_1 = {0x48, 0xC7, 0xC6},
.xchg_rsi_prev_loc_curr_loc = {0x48, 0x87, 0x35},
.xor_rsi_curr_loc = {0x48, 0x81, 0xF6},
FATAL("Patch out of range (current_pc_value2): 0x%016lX",
current_pc_value2);
.add_rsi_1 = {0x80, 0x86, 0x00, 0x00, 0x00, 0x00, 0x01},
.adc_rsi_0 = {0x80, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00},
}
.pop_rsi = 0x5E,
.pop_fq = 0x9D,
.lsa_rsp_rsp_add_rz = {0x48, 0x8D, 0xA4, 0x24, 0x80, 0x00, 0x00, 0x00},
dst_pc_value = (gint *)&code.bytes[patch_offset2];
*dst_pc_value = (gint)current_pc_value2;
}
gsize afl_area_ptr_value =
GPOINTER_TO_SIZE(__afl_area_ptr) -
(code_addr + offsetof(afl_log_code, data.assembly.lea_rdi_rip_off) +
sizeof(code.data.assembly.lea_rdi_rip_off));
gssize afl_area_ptr_offset =
offsetof(afl_log_code, data.assembly.lea_rdi_rip_off) +
sizeof(code.data.assembly.lea_rdi_rip_off) - sizeof(gint);
;
if (!instrument_coverage_in_range(afl_area_ptr_value)) {
static gboolean instrument_coverage_find_low(const GumRangeDetails *details,
gpointer user_data) {
FATAL("Patch out of range (afl_area_ptr_value): 0x%016lX",
afl_area_ptr_value);
static GumAddress last_limit = (64ULL << 10);
gpointer * address = (gpointer *)user_data;
}
if ((details->range->base_address - last_limit) > __afl_map_size) {
gint *dst_afl_area_ptr_value = (gint *)&code.bytes[afl_area_ptr_offset];
*dst_afl_area_ptr_value = (gint)afl_area_ptr_value;
gum_x86_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
gum_x86_writer_put_label(cw, after_log_impl);
*address = GSIZE_TO_POINTER(last_limit);
return FALSE;
}
if (details->range->base_address > ((2ULL << 20) - __afl_map_size)) {
return FALSE;
}
last_limit = details->range->base_address + details->range->size;
return TRUE;
}
static void instrument_coverage_optimize_map_mmap_anon(gpointer address) {
__afl_area_ptr =
mmap(address, __afl_map_size, PROT_READ | PROT_WRITE,
MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (__afl_area_ptr != address) {
FATAL("Failed to map mmap __afl_area_ptr: %d", errno);
}
}
static void instrument_coverage_optimize_map_mmap(char * shm_file_path,
gpointer address) {
int shm_fd = -1;
if (munmap(__afl_area_ptr, __afl_map_size) != 0) {
FATAL("Failed to unmap previous __afl_area_ptr");
}
__afl_area_ptr = NULL;
#if !defined(__ANDROID__)
shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION);
if (shm_fd == -1) { FATAL("shm_open() failed\n"); }
#else
shm_fd = open("/dev/ashmem", O_RDWR);
if (shm_fd == -1) { FATAL("open() failed\n"); }
if (ioctl(shm_fd, ASHMEM_SET_NAME, shm_file_path) == -1) { FATAL("ioctl(ASHMEM_SET_NAME) failed"); }
if (ioctl(shm_fd, ASHMEM_SET_SIZE, __afl_map_size) == -1) { FATAL("ioctl(ASHMEM_SET_SIZE) failed"); }
#endif
__afl_area_ptr = mmap(address, __afl_map_size, PROT_READ | PROT_WRITE,
MAP_FIXED_NOREPLACE | MAP_SHARED, shm_fd, 0);
if (__afl_area_ptr != address) {
FATAL("Failed to map mmap __afl_area_ptr: %d", errno);
}
if (close(shm_fd) != 0) { FATAL("Failed to close shm_fd"); }
}
static void instrument_coverage_optimize_map_shm(guint64 shm_env_val,
gpointer address) {
if (shmdt(__afl_area_ptr) != 0) {
FATAL("Failed to detach previous __afl_area_ptr");
}
__afl_area_ptr = shmat(shm_env_val, address, 0);
if (__afl_area_ptr != address) {
FATAL("Failed to map shm __afl_area_ptr: %d", errno);
}
}
void instrument_coverage_optimize_init(void) {
gpointer low_address = NULL;
gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, instrument_coverage_find_low,
&low_address);
OKF("Low address: %p", low_address);
if (low_address == 0 ||
GPOINTER_TO_SIZE(low_address) > ((2UL << 20) - __afl_map_size)) {
FATAL("Invalid low_address: %p", low_address);
}
ranges_print_debug_maps();
char *shm_env = getenv(SHM_ENV_VAR);
OKF("SHM_ENV_VAR: %s", shm_env);
if (shm_env == NULL) {
WARNF("SHM_ENV_VAR not set, using anonymous map for debugging purposes");
instrument_coverage_optimize_map_mmap_anon(low_address);
} else {
guint64 shm_env_val = g_ascii_strtoull(shm_env, NULL, 10);
if (shm_env_val == 0) {
instrument_coverage_optimize_map_mmap(shm_env, low_address);
} else {
instrument_coverage_optimize_map_shm(shm_env_val, low_address);
}
}
OKF("__afl_area_ptr: %p", __afl_area_ptr);
OKF("instrument_previous_pc: %p", &instrument_previous_pc);
}
void instrument_coverage_optimize(const cs_insn * instr,
GumStalkerOutput *output) {
afl_log_code code = {0};
GumX86Writer *cw = output->writer.x86;
guint64 area_offset = instrument_get_offset_hash(GUM_ADDRESS(instr->address));
instrument_coverate_write_function(output);
GumAddress code_addr = 0;
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
-GUM_RED_ZONE_SIZE);
gum_x86_writer_put_push_reg(cw, GUM_REG_RDI);
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDI, area_offset);
gum_x86_writer_put_call_address(cw, current_log_impl);
gum_x86_writer_put_pop_reg(cw, GUM_REG_RDI);
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
GUM_RED_ZONE_SIZE);
// gum_x86_writer_put_breakpoint(cw);
code_addr = cw->pc;
code.code = template;
gssize curr_loc_shr_1_offset =
offsetof(afl_log_code, code.mov_rsi_curr_loc_shr_1) +
sizeof(code.code.mov_rsi_curr_loc_shr_1) - sizeof(guint32);
*((guint32 *)&code.bytes[curr_loc_shr_1_offset]) =
(guint32)(area_offset >> 1);
gssize prev_loc_value =
GPOINTER_TO_SIZE(&instrument_previous_pc) -
(code_addr + offsetof(afl_log_code, code.xchg_rsi_prev_loc_curr_loc) +
sizeof(code.code.xchg_rsi_prev_loc_curr_loc));
gssize prev_loc_value_offset =
offsetof(afl_log_code, code.xchg_rsi_prev_loc_curr_loc) +
sizeof(code.code.xchg_rsi_prev_loc_curr_loc) - sizeof(gint);
if (!instrument_coverage_in_range(prev_loc_value)) {
FATAL("Patch out of range (current_pc_value1): 0x%016lX", prev_loc_value);
}
*((gint *)&code.bytes[prev_loc_value_offset]) = (gint)prev_loc_value;
gssize xor_curr_loc_offset = offsetof(afl_log_code, code.xor_rsi_curr_loc) +
sizeof(code.code.xor_rsi_curr_loc) -
sizeof(guint32);
*((guint32 *)&code.bytes[xor_curr_loc_offset]) = (guint32)(area_offset);
gssize add_rsi_1_offset = offsetof(afl_log_code, code.add_rsi_1) +
sizeof(code.code.add_rsi_1) - sizeof(guint32) - 1;
*((guint32 *)&code.bytes[add_rsi_1_offset]) =
(guint32)GPOINTER_TO_SIZE(__afl_area_ptr);
gssize adc_rsi_0_ffset = offsetof(afl_log_code, code.adc_rsi_0) +
sizeof(code.code.adc_rsi_0) - sizeof(guint32) - 1;
*((guint32 *)&code.bytes[adc_rsi_0_ffset]) =
(guint32)GPOINTER_TO_SIZE(__afl_area_ptr);
gum_x86_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
}

View File

@ -83,6 +83,9 @@ void instrument_coverage_optimize(const cs_insn * instr,
}
void instrument_coverage_optimize_init(void) {
}
void instrument_flush(GumStalkerOutput *output) {
gum_x86_writer_flush(output->writer.x86);

View File

@ -549,18 +549,19 @@ static GArray *merge_ranges(GArray *a) {
}
void ranges_print_debug_maps(void) {
gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges_callback, NULL);
}
void ranges_config(void) {
if (getenv("AFL_FRIDA_DEBUG_MAPS") != NULL) { ranges_debug_maps = TRUE; }
if (getenv("AFL_INST_LIBS") != NULL) { ranges_inst_libs = TRUE; }
if (getenv("AFL_FRIDA_INST_JIT") != NULL) { ranges_inst_jit = TRUE; }
if (ranges_debug_maps) {
gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges_callback,
NULL);
}
if (ranges_debug_maps) { ranges_print_debug_maps(); }
include_ranges = collect_ranges("AFL_FRIDA_INST_RANGES");
exclude_ranges = collect_ranges("AFL_FRIDA_EXCLUDE_RANGES");

View File

@ -1,4 +1,4 @@
#ifndef __APPLE__
#if defined(__linux__) && !defined(__ANDROID__)
#include <stdbool.h>
#include <stdio.h>

View File

@ -1,4 +1,4 @@
#ifndef __APPLE__
#if defined(__linux__) && !defined(__ANDROID__)
#include <execinfo.h>
#include <fcntl.h>

View File

@ -1,4 +1,4 @@
#ifndef __APPLE__
#if defined(__linux__) && !defined(__ANDROID__)
#include <fcntl.h>
#include <sched.h>

View File

@ -1,4 +1,4 @@
#ifndef __APPLE__
#if defined(__linux__) && !defined(__ANDROID__)
#include <stdint.h>
#include <stdio.h>

View File

@ -1,4 +1,4 @@
#ifndef __APPLE__
#if defined(__linux__) && !defined(__ANDROID__)
#include <alloca.h>
#include <errno.h>

View File

@ -1,4 +1,4 @@
#ifndef __APPLE__
#if defined(__linux__) && !defined(__ANDROID__)
#include <stdarg.h>

View File

@ -1,4 +1,4 @@
#ifndef __APPLE__
#if defined(__linux__) && !defined(__ANDROID__)
#include <stdio.h>
#include <string.h>

View File

@ -1,4 +1,4 @@
#ifndef __APPLE__
#if defined(__linux__) && !defined(__ANDROID__)
#include <limits.h>
#include <stdio.h>

View File

@ -1130,7 +1130,6 @@ void get_core_count(afl_state_t *);
void fix_up_sync(afl_state_t *);
void check_asan_opts(afl_state_t *);
void check_binary(afl_state_t *, u8 *);
void fix_up_banner(afl_state_t *, u8 *);
void check_if_tty(afl_state_t *);
void setup_signal_handlers(void);
void save_cmdline(afl_state_t *, u32, char **);

View File

@ -3,9 +3,8 @@
## Introduction
This originally is the work of an individual nicknamed laf-intel.
His blog [Circumventing Fuzzing Roadblocks with Compiler Transformations]
(https://lafintel.wordpress.com/) and gitlab repo [laf-llvm-pass]
(https://gitlab.com/laf-intel/laf-llvm-pass/)
His blog [Circumventing Fuzzing Roadblocks with Compiler Transformations](https://lafintel.wordpress.com/)
and gitlab repo [laf-llvm-pass](https://gitlab.com/laf-intel/laf-llvm-pass/)
describe some code transformations that
help AFL++ to enter conditional blocks, where conditions consist of
comparisons of large values.

View File

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

View File

@ -250,7 +250,7 @@ class ModuleSanitizerCoverage {
Module * Mo = NULL;
GlobalVariable * AFLMapPtr = NULL;
Value * MapPtrFixed = NULL;
FILE * documentFile = NULL;
std::ofstream dFile;
size_t found = 0;
// afl++ END
@ -446,8 +446,8 @@ bool ModuleSanitizerCoverage::instrumentModule(
if ((ptr = getenv("AFL_LLVM_DOCUMENT_IDS")) != NULL) {
if ((documentFile = fopen(ptr, "a")) == NULL)
WARNF("Cannot access document file %s", ptr);
dFile.open(ptr, std::ofstream::out | std::ofstream::app);
if (dFile.is_open()) WARNF("Cannot access document file %s", ptr);
}
@ -1003,12 +1003,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
instrumentFunction(F, DTCallback, PDTCallback);
// afl++ START
if (documentFile) {
fclose(documentFile);
documentFile = NULL;
}
if (dFile.is_open()) dFile.close();
if (!getenv("AFL_LLVM_LTO_DONTWRITEID") || dictionary.size() || map_addr) {
@ -1069,7 +1064,6 @@ bool ModuleSanitizerCoverage::instrumentModule(
if (dictionary.size()) {
size_t memlen = 0, count = 0, offset = 0;
char * ptr;
// sort and unique the dictionary
std::sort(dictionary.begin(), dictionary.end());
@ -1089,13 +1083,7 @@ bool ModuleSanitizerCoverage::instrumentModule(
if (count) {
if ((ptr = (char *)malloc(memlen + count)) == NULL) {
fprintf(stderr, "Error: malloc for %lu bytes failed!\n",
memlen + count);
exit(-1);
}
auto ptrhld = std::unique_ptr<char[]>(new char[memlen + count]);
count = 0;
@ -1103,8 +1091,8 @@ bool ModuleSanitizerCoverage::instrumentModule(
if (offset + token.length() < 0xfffff0 && count < MAX_AUTO_EXTRAS) {
ptr[offset++] = (uint8_t)token.length();
memcpy(ptr + offset, token.c_str(), token.length());
ptrhld.get()[offset++] = (uint8_t)token.length();
memcpy(ptrhld.get() + offset, token.c_str(), token.length());
offset += token.length();
count++;
@ -1124,10 +1112,10 @@ bool ModuleSanitizerCoverage::instrumentModule(
GlobalVariable *AFLInternalDictionary = new GlobalVariable(
M, ArrayTy, true, GlobalValue::ExternalLinkage,
ConstantDataArray::get(Ctx,
*(new ArrayRef<char>((char *)ptr, offset))),
*(new ArrayRef<char>(ptrhld.get(), offset))),
"__afl_internal_dictionary");
AFLInternalDictionary->setInitializer(ConstantDataArray::get(
Ctx, *(new ArrayRef<char>((char *)ptr, offset))));
Ctx, *(new ArrayRef<char>(ptrhld.get(), offset))));
AFLInternalDictionary->setConstant(true);
GlobalVariable *AFLDictionary = new GlobalVariable(
@ -1509,12 +1497,12 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB,
// afl++ START
++afl_global_id;
if (documentFile) {
if (dFile.is_open()) {
unsigned long long int moduleID =
(((unsigned long long int)(rand() & 0xffffffff)) << 32) | getpid();
fprintf(documentFile, "ModuleID=%llu Function=%s edgeID=%u\n", moduleID,
F.getName().str().c_str(), afl_global_id);
dFile << "ModuleID=" << moduleID << " Function=" << F.getName().str()
<< " edgeID=" << afl_global_id << "\n";
}

View File

@ -881,8 +881,6 @@ void ModuleSanitizerCoverage::InjectCoverageForIndirectCalls(
Function &F, ArrayRef<Instruction *> IndirCalls) {
if (IndirCalls.empty()) return;
assert(Options.TracePC || Options.TracePCGuard ||
Options.Inline8bitCounters /*|| Options.InlineBoolFlag*/);
for (auto I : IndirCalls) {
IRBuilder<> IRB(I);

View File

@ -66,6 +66,9 @@ namespace {
class AFLdict2filePass : public ModulePass {
std::ofstream of;
void dict2file(u8 *, u32);
public:
static char ID;
@ -81,7 +84,7 @@ class AFLdict2filePass : public ModulePass {
} // namespace
void dict2file(int fd, u8 *mem, u32 len) {
void AFLdict2filePass::dict2file(u8 *mem, u32 len) {
u32 i, j, binary = 0;
char line[MAX_AUTO_EXTRA * 8], tmp[8];
@ -113,9 +116,8 @@ void dict2file(int fd, u8 *mem, u32 len) {
line[j] = 0;
strcat(line, "\"\n");
if (write(fd, line, strlen(line)) <= 0)
PFATAL("Could not write to dictionary file");
fsync(fd);
of << line;
of.flush();
if (!be_quiet) fprintf(stderr, "Found dictionary token: %s", line);
@ -125,7 +127,7 @@ bool AFLdict2filePass::runOnModule(Module &M) {
DenseMap<Value *, std::string *> valueMap;
char * ptr;
int fd, found = 0;
int found = 0;
/* Show a banner */
setvbuf(stdout, NULL, _IONBF, 0);
@ -146,8 +148,8 @@ bool AFLdict2filePass::runOnModule(Module &M) {
if (!ptr || *ptr != '/')
FATAL("AFL_LLVM_DICT2FILE is not set to an absolute path: %s", ptr);
if ((fd = open(ptr, O_WRONLY | O_APPEND | O_CREAT | O_DSYNC, 0644)) < 0)
PFATAL("Could not open/create %s.", ptr);
of.open(ptr, std::ofstream::out | std::ofstream::app);
if (!of.is_open()) PFATAL("Could not open/create %s.", ptr);
/* Instrument all the things! */
@ -264,11 +266,11 @@ bool AFLdict2filePass::runOnModule(Module &M) {
}
dict2file(fd, (u8 *)&val, len);
dict2file((u8 *)&val, len);
found++;
if (val2) {
dict2file(fd, (u8 *)&val2, len);
dict2file((u8 *)&val2, len);
found++;
}
@ -630,7 +632,7 @@ bool AFLdict2filePass::runOnModule(Module &M) {
ptr = (char *)thestring.c_str();
dict2file(fd, (u8 *)ptr, optLen);
dict2file((u8 *)ptr, optLen);
found++;
}
@ -641,7 +643,7 @@ bool AFLdict2filePass::runOnModule(Module &M) {
}
close(fd);
of.close();
/* Say something nice. */

View File

@ -108,8 +108,8 @@ bool AFLLTOPass::runOnModule(Module &M) {
// std::vector<CallInst *> calls;
DenseMap<Value *, std::string *> valueMap;
std::vector<BasicBlock *> BlockList;
std::ofstream dFile;
char * ptr;
FILE * documentFile = NULL;
size_t found = 0;
srand((unsigned int)time(NULL));
@ -137,8 +137,8 @@ bool AFLLTOPass::runOnModule(Module &M) {
if ((ptr = getenv("AFL_LLVM_DOCUMENT_IDS")) != NULL) {
if ((documentFile = fopen(ptr, "a")) == NULL)
WARNF("Cannot access document file %s", ptr);
dFile.open(ptr, std::ofstream::out | std::ofstream::app);
if (!dFile.is_open()) WARNF("Cannot access document file %s", ptr);
}
@ -243,8 +243,14 @@ bool AFLLTOPass::runOnModule(Module &M) {
// the instrument file list check
AttributeList Attrs = F.getAttributes();
#if LLVM_VERSION_MAJOR < 14
if (Attrs.hasAttribute(-1, StringRef("skipinstrument"))) {
#else
if (Attrs.hasFnAttr(StringRef("skipinstrument"))) {
#endif
if (debug)
fprintf(stderr,
"DEBUG: Function %s is not in a source file that was specified "
@ -845,10 +851,11 @@ bool AFLLTOPass::runOnModule(Module &M) {
}
if (documentFile) {
if (dFile.is_open()) {
fprintf(documentFile, "ModuleID=%llu Function=%s edgeID=%u\n",
moduleID, F.getName().str().c_str(), afl_global_id);
dFile << "ModuleID=" << moduleID
<< " Function=" << F.getName().str()
<< " edgeID=" << afl_global_id << "\n";
}
@ -920,8 +927,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
}
if (documentFile) fclose(documentFile);
documentFile = NULL;
if (dFile.is_open()) dFile.close();
// save highest location ID to global variable
// do this after each function to fail faster
@ -1016,7 +1022,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
if (count) {
auto ptrhld = std::unique_ptr<char []>(new char[memlen + count]);
auto ptrhld = std::unique_ptr<char[]>(new char[memlen + count]);
count = 0;

View File

@ -116,10 +116,15 @@ bool AFLcheckIfInstrument::runOnModule(Module &M) {
auto & Ctx = F.getContext();
AttributeList Attrs = F.getAttributes();
AttrBuilder NewAttrs;
#if LLVM_VERSION_MAJOR < 14
AttrBuilder NewAttrs;
NewAttrs.addAttribute("skipinstrument");
F.setAttributes(
Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs));
#else
AttributeList NewAttrs = Attrs.addFnAttribute(Ctx, "skipinstrument");
F.setAttributes(NewAttrs);
#endif
}

View File

@ -578,16 +578,16 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M,
/* dependent on the cmp of the high parts go to the end or go on with
* the comparison */
auto term = bb->getTerminator();
BranchInst *br = nullptr;
auto term = bb->getTerminator();
if (pred == CmpInst::ICMP_EQ) {
br = BranchInst::Create(cmp_low_bb, end_bb, icmp_high, bb);
BranchInst::Create(cmp_low_bb, end_bb, icmp_high, bb);
} else {
/* CmpInst::ICMP_NE */
br = BranchInst::Create(end_bb, cmp_low_bb, icmp_high, bb);
// CmpInst::ICMP_NE
BranchInst::Create(end_bb, cmp_low_bb, icmp_high, bb);
}

View File

@ -610,12 +610,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if (!time_ms) {
kill(fsrv->fsrv_pid, fsrv->kill_signal);
if (fsrv->fsrv_pid > 0) { kill(fsrv->fsrv_pid, fsrv->kill_signal); }
} else if (time_ms > fsrv->init_tmout) {
fsrv->last_run_timed_out = 1;
kill(fsrv->fsrv_pid, fsrv->kill_signal);
if (fsrv->fsrv_pid > 0) { kill(fsrv->fsrv_pid, fsrv->kill_signal); }
} else {
@ -1248,7 +1248,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
/* If there was no response from forkserver after timeout seconds,
we kill the child. The forkserver should inform us afterwards */
kill(fsrv->child_pid, fsrv->kill_signal);
if (fsrv->child_pid > 0) { kill(fsrv->child_pid, fsrv->kill_signal); }
fsrv->last_run_timed_out = 1;
if (read(fsrv->fsrv_st_fd, &fsrv->child_status, 4) < 4) { exec_ms = 0; }

View File

@ -2815,43 +2815,6 @@ void check_binary(afl_state_t *afl, u8 *fname) {
}
/* Trim and possibly create a banner for the run. */
void fix_up_banner(afl_state_t *afl, u8 *name) {
if (!afl->use_banner) {
if (afl->sync_id) {
afl->use_banner = afl->sync_id;
} else {
u8 *trim = strrchr(name, '/');
if (!trim) {
afl->use_banner = name;
} else {
afl->use_banner = trim + 1;
}
}
}
if (strlen(afl->use_banner) > 32) {
u8 *tmp = ck_alloc(36);
sprintf(tmp, "%.32s...", afl->use_banner);
afl->use_banner = tmp;
}
}
/* Check if we're on TTY. */
void check_if_tty(afl_state_t *afl) {

View File

@ -291,8 +291,6 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
u32 handicap, u8 from_queue) {
if (unlikely(afl->shm.cmplog_mode)) { q->exec_cksum = 0; }
u8 fault = 0, new_bits = 0, var_detected = 0, hnb = 0,
first_run = (q->exec_cksum == 0);
u64 start_us, stop_us, diff_us;
@ -300,6 +298,8 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
u32 use_tmout = afl->fsrv.exec_tmout;
u8 *old_sn = afl->stage_name;
if (unlikely(afl->shm.cmplog_mode)) { q->exec_cksum = 0; }
/* Be a bit more generous about timeouts when resuming sessions, or when
trying to calibrate already-added finds. This helps avoid trouble due
to intermittent latency. */
@ -343,6 +343,32 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
}
/* we need a dummy run if this is LTO + cmplog */
if (unlikely(afl->shm.cmplog_mode)) {
write_to_testcase(afl, use_mem, q->len);
fault = fuzz_run_target(afl, &afl->fsrv, use_tmout);
/* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed,
we want to bail out quickly. */
if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; }
if (!afl->non_instrumented_mode && !afl->stage_cur &&
!count_bytes(afl, afl->fsrv.trace_bits)) {
fault = FSRV_RUN_NOINST;
goto abort_calibration;
}
#ifdef INTROSPECTION
if (unlikely(!q->bitsmap_size)) q->bitsmap_size = afl->bitsmap_size;
#endif
}
if (q->exec_cksum) {
memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);

View File

@ -441,9 +441,10 @@ void show_stats(afl_state_t *afl) {
u64 cur_ms;
u32 t_bytes, t_bits;
u32 banner_len, banner_pad;
u8 tmp[256];
u8 time_tmp[64];
static u8 banner[128];
u32 banner_len, banner_pad;
u8 tmp[256];
u8 time_tmp[64];
u8 val_buf[8][STRINGIFY_VAL_SIZE_MAX];
#define IB(i) (val_buf[(i)])
@ -656,26 +657,34 @@ void show_stats(afl_state_t *afl) {
}
/* Let's start by drawing a centered banner. */
if (unlikely(!banner[0])) {
banner_len = (afl->crash_mode ? 24 : 22) + strlen(VERSION) +
strlen(afl->use_banner) + strlen(afl->power_name) + 3 + 5;
banner_pad = (79 - banner_len) / 2;
memset(tmp, ' ', banner_pad);
char *si = "";
if (afl->sync_id) { si = afl->sync_id; }
memset(banner, 0, sizeof(banner));
banner_len = (afl->crash_mode ? 20 : 18) + strlen(VERSION) + strlen(si) +
strlen(afl->power_name) + 4 + 6;
#ifdef HAVE_AFFINITY
sprintf(
tmp + banner_pad,
"%s " cLCY VERSION cLGN " (%s) " cPIN "[%s]" cBLU " {%d}",
afl->crash_mode ? cPIN "peruvian were-rabbit" : cYEL "american fuzzy lop",
afl->use_banner, afl->power_name, afl->cpu_aff);
#else
sprintf(
tmp + banner_pad, "%s " cLCY VERSION cLGN " (%s) " cPIN "[%s]",
afl->crash_mode ? cPIN "peruvian were-rabbit" : cYEL "american fuzzy lop",
afl->use_banner, afl->power_name);
#endif /* HAVE_AFFINITY */
if (strlen(afl->use_banner) + banner_len > 75) {
SAYF("\n%s\n", tmp);
afl->use_banner += (strlen(afl->use_banner) + banner_len) - 76;
memset(afl->use_banner, '.', 3);
}
banner_len += strlen(afl->use_banner);
banner_pad = (79 - banner_len) / 2;
memset(banner, ' ', banner_pad);
sprintf(banner + banner_pad,
"%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]",
afl->crash_mode ? cPIN "peruvian were-rabbit"
: cYEL "american fuzzy lop",
si, afl->use_banner, afl->power_name);
}
SAYF("\n%s\n", banner);
/* "Handy" shortcuts for drawing boxes... */

View File

@ -1189,7 +1189,17 @@ int main(int argc, char **argv_orig, char **envp) {
}
if (afl->sync_id) { fix_up_sync(afl); }
if (afl->sync_id) {
if (strlen(afl->sync_id) > 24) {
FATAL("sync_id max length is 24 characters");
}
fix_up_sync(afl);
}
if (!strcmp(afl->in_dir, afl->out_dir)) {
@ -1218,6 +1228,8 @@ int main(int argc, char **argv_orig, char **envp) {
if (unlikely(afl->afl_env.afl_statsd)) { statsd_setup_format(afl); }
if (!afl->use_banner) { afl->use_banner = argv[optind]; }
if (strchr(argv[optind], '/') == NULL && !afl->unicorn_mode) {
WARNF(cLRD
@ -1486,9 +1498,6 @@ int main(int argc, char **argv_orig, char **envp) {
}
save_cmdline(afl, argc, argv);
fix_up_banner(afl, argv[optind]);
check_if_tty(afl);
if (afl->afl_env.afl_force_ui) { afl->not_on_tty = 0; }

View File

@ -242,9 +242,14 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
if (cmin_mode &&
(fsrv->last_run_timed_out || (!caa && child_crashed != cco))) {
// create empty file to prevent error messages in afl-cmin
fd = open(outfile, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
close(fd);
if (strcmp(outfile, "-")) {
// create empty file to prevent error messages in afl-cmin
fd = open(outfile, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
close(fd);
}
return ret;
}

View File

@ -1 +1 @@
1c47d1ebc7e904ad4efc1370f23e269fb9ac3f93
d4915053d477dd827b3fe4b494173d3fbf9f456e

View File

@ -12,11 +12,11 @@ use std::{
use unicornafl::{
unicorn_const::{uc_error, Arch, Mode, Permission},
RegisterX86::{self, *},
Unicorn, UnicornHandle,
RegisterX86::*,
Unicorn,
};
const BINARY: &str = &"../target";
const BINARY: &str = "../target";
// Memory map for the code to be tested
// Arbitrary address where code to test will be loaded
@ -47,7 +47,7 @@ fn read_file(filename: &str) -> Result<Vec<u8>, io::Error> {
fn parse_locs(loc_name: &str) -> Result<Vec<u64>, io::Error> {
let contents = &read_file(&format!("../target.offsets.{}", loc_name))?;
//println!("Read: {:?}", contents);
Ok(str_from_u8_unchecked(&contents)
Ok(str_from_u8_unchecked(contents)
.split('\n')
.map(|x| {
//println!("Trying to convert {}", &x[2..]);
@ -87,8 +87,7 @@ fn main() {
}
fn fuzz(input_file: &str) -> Result<(), uc_error> {
let mut unicorn = Unicorn::new(Arch::X86, Mode::MODE_64, 0)?;
let mut uc: UnicornHandle<'_, _> = unicorn.borrow();
let mut uc = Unicorn::new(Arch::X86, Mode::MODE_64, 0)?;
let binary =
read_file(BINARY).unwrap_or_else(|_| panic!("Could not read modem image: {}", BINARY));
@ -105,7 +104,7 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> {
// Set the program counter to the start of the code
let main_locs = parse_locs("main").unwrap();
//println!("Entry Point: {:x}", main_locs[0]);
uc.reg_write(RegisterX86::RIP as i32, main_locs[0])?;
uc.reg_write(RIP, main_locs[0])?;
// Setup the stack.
uc.mem_map(
@ -114,14 +113,14 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> {
Permission::READ | Permission::WRITE,
)?;
// Setup the stack pointer, but allocate two pointers for the pointers to input.
uc.reg_write(RSP as i32, STACK_ADDRESS + STACK_SIZE - 16)?;
uc.reg_write(RSP, STACK_ADDRESS + STACK_SIZE - 16)?;
// Setup our input space, and push the pointer to it in the function params
uc.mem_map(INPUT_ADDRESS, INPUT_MAX as usize, Permission::READ)?;
// We have argc = 2
uc.reg_write(RDI as i32, 2)?;
uc.reg_write(RDI, 2)?;
// RSI points to our little 2 QWORD space at the beginning of the stack...
uc.reg_write(RSI as i32, STACK_ADDRESS + STACK_SIZE - 16)?;
uc.reg_write(RSI, STACK_ADDRESS + STACK_SIZE - 16)?;
// ... which points to the Input. Write the ptr to mem in little endian.
uc.mem_write(
STACK_ADDRESS + STACK_SIZE - 16,
@ -133,13 +132,13 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> {
let already_allocated_malloc = already_allocated.clone();
// We use a very simple malloc/free stub here,
// that only works for exactly one allocation at a time.
let hook_malloc = move |mut uc: UnicornHandle<'_, _>, addr: u64, size: u32| {
let hook_malloc = move |uc: &mut Unicorn<'_, _>, addr: u64, size: u32| {
if already_allocated_malloc.get() {
println!("Double malloc, not supported right now!");
abort();
}
// read the first param
let malloc_size = uc.reg_read(RDI as i32).unwrap();
let malloc_size = uc.reg_read(RDI).unwrap();
if malloc_size > HEAP_SIZE_MAX {
println!(
"Tried to allocate {} bytes, but we may only allocate up to {}",
@ -147,20 +146,20 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> {
);
abort();
}
uc.reg_write(RAX as i32, HEAP_ADDRESS).unwrap();
uc.reg_write(RIP as i32, addr + size as u64).unwrap();
uc.reg_write(RAX, HEAP_ADDRESS).unwrap();
uc.reg_write(RIP, addr + size as u64).unwrap();
already_allocated_malloc.set(true);
};
let already_allocated_free = already_allocated;
// No real free, just set the "used"-flag to false.
let hook_free = move |mut uc: UnicornHandle<'_, _>, addr, size| {
let hook_free = move |uc: &mut Unicorn<'_, _>, addr, size| {
if already_allocated_free.get() {
println!("Double free detected. Real bug?");
abort();
}
// read the first param
let free_ptr = uc.reg_read(RDI as i32).unwrap();
let free_ptr = uc.reg_read(RDI).unwrap();
if free_ptr != HEAP_ADDRESS {
println!(
"Tried to free wrong mem region {:x} at code loc {:x}",
@ -168,7 +167,7 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> {
);
abort();
}
uc.reg_write(RIP as i32, addr + size as u64).unwrap();
uc.reg_write(RIP, addr + size as u64).unwrap();
already_allocated_free.set(false);
};
@ -177,8 +176,8 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> {
*/
// This is a fancy print function that we're just going to skip for fuzzing.
let hook_magicfn = move |mut uc: UnicornHandle<'_, _>, addr, size| {
uc.reg_write(RIP as i32, addr + size as u64).unwrap();
let hook_magicfn = move |uc: &mut Unicorn<'_, _>, addr, size| {
uc.reg_write(RIP, addr + size as u64).unwrap();
};
for addr in parse_locs("malloc").unwrap() {
@ -195,7 +194,7 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> {
}
let place_input_callback =
|uc: &mut UnicornHandle<'_, _>, afl_input: &mut [u8], _persistent_round| {
|uc: &mut Unicorn<'_, _>, afl_input: &mut [u8], _persistent_round| {
// apply constraints to the mutated input
if afl_input.len() > INPUT_MAX as usize {
//println!("Skipping testcase with leng {}", afl_input.len());
@ -209,9 +208,7 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> {
// return true if the last run should be counted as crash
let crash_validation_callback =
|_uc: &mut UnicornHandle<'_, _>, result, _input: &[u8], _persistent_round| {
result != uc_error::OK
};
|_uc: &mut Unicorn<'_, _>, result, _input: &[u8], _persistent_round| result != uc_error::OK;
let end_addrs = parse_locs("main_ends").unwrap();

@ -1 +1 @@
Subproject commit c0e03d2c6b55a22025324f121746b41b1e756fb8
Subproject commit d4915053d477dd827b3fe4b494173d3fbf9f456e

View File

@ -6,6 +6,6 @@ for sending input to stdin which the target binary will think is coming from
a network socket.
This is desock_dup.c from the amazing preeny project
https://github.com/zardus/preeny
[https://github.com/zardus/preeny](https://github.com/zardus/preeny)
It is packaged in AFL++ to have it at hand if needed