mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-11 01:31:37 +00:00
Merge branch 'dev' of github.com:AFLplusplus/AFLplusplus into dev
This commit is contained in:
commit
23e69f1107
112
README.md
112
README.md
@ -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
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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).
|
||||
|
@ -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).
|
@ -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
|
||||
|
@ -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).
|
||||
|
@ -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).
|
@ -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
|
||||
```
|
||||
```
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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] @@
|
||||
...
|
||||
```
|
||||
```
|
||||
|
@ -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).
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -1,4 +1,4 @@
|
||||
#ifndef __APPLE__
|
||||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
@ -1,4 +1,4 @@
|
||||
#ifndef __APPLE__
|
||||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
|
||||
#include <execinfo.h>
|
||||
#include <fcntl.h>
|
||||
|
@ -1,4 +1,4 @@
|
||||
#ifndef __APPLE__
|
||||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
|
@ -1,4 +1,4 @@
|
||||
#ifndef __APPLE__
|
||||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
@ -1,4 +1,4 @@
|
||||
#ifndef __APPLE__
|
||||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
|
||||
#include <alloca.h>
|
||||
#include <errno.h>
|
||||
|
@ -1,4 +1,4 @@
|
||||
#ifndef __APPLE__
|
||||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#ifndef __APPLE__
|
||||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -1,4 +1,4 @@
|
||||
#ifndef __APPLE__
|
||||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
@ -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 **);
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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";
|
||||
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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... */
|
||||
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
1c47d1ebc7e904ad4efc1370f23e269fb9ac3f93
|
||||
d4915053d477dd827b3fe4b494173d3fbf9f456e
|
||||
|
@ -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
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user