From 80ddb484deb82aefc9ba35c766ffca313d74e377 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 6 May 2020 11:51:28 +0200 Subject: added InsTrimLTO :-) --- docs/Changelog.md | 1 + docs/env_variables.md | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 54564a5d..a5b761be 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -19,6 +19,7 @@ sending a mail to . - if LLVM 11 is installed the posix shm_open+mmap is used and a fixed address for the shared memory map is used as this increases the fuzzing speed + - InsTrim now has an LTO version! :-) That is the best and fastest mode! - fixes to LTO mode if instrumented edges > MAP_SIZE - CTX and NGRAM can now be used together - CTX and NGRAM are now also supported in CFG/INSTRIM mode diff --git a/docs/env_variables.md b/docs/env_variables.md index ed81c8a3..f5d28981 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -116,6 +116,9 @@ Then there are a few specific features that are only available in llvm_mode: afl-clang-lto/afl-clang-lto++ instead of afl-clang-fast, but is only built if LLVM 11 or newer is used. + - AFL_LLVM_INSTRUMENT=CFG will use Control Flow Graph instrumentation. + (recommended) + - AFL_LLVM_LTO_AUTODICTIONARY will generate a dictionary in the target binary based on string compare and memory compare functions. afl-fuzz will automatically get these transmitted when starting to @@ -139,7 +142,13 @@ Then there are a few specific features that are only available in llvm_mode: ### INSTRIM - This feature increases the speed by ~15% without any disadvantages. + This feature increases the speed by ~15% without any disadvantages to the + classic instrumentation. + + Note that there is also an LTO version (if you have llvm 11 or higher) - + that is the best instrumentation we have. Use `afl-clang-lto` to activate. + The InsTrim LTO version additionally has all the options and features of + LTO (see above). - Setting AFL_LLVM_INSTRIM or AFL_LLVM_INSTRUMENT=CFG to activates this mode -- cgit 1.4.1 From a1c9c497d5e0659e94a25f8cb399f4d111643606 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 6 May 2020 15:37:49 +0200 Subject: aarch64 support for afl-untracer --- docs/Changelog.md | 2 +- examples/afl_untracer/Makefile | 10 ++++-- examples/afl_untracer/README.md | 15 ++++++++ examples/afl_untracer/afl-untracer.c | 67 ++++++++++++++++++++++++++++++++---- 4 files changed, 84 insertions(+), 10 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index a5b761be..35240021 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -39,7 +39,7 @@ sending a mail to . network (not fuzzing tcp/ip services but running afl-fuzz on one system and the target being on an embedded device) - added examples/afl_untracer which does a binary-only fuzzing with the - modifications done in memory + modifications done in memory (intel32/64 and aarch64 support) - added examples/afl_proxy which can be easily used to fuzz and instrument non-standard things - all: diff --git a/examples/afl_untracer/Makefile b/examples/afl_untracer/Makefile index 5c525877..ad67e8bc 100644 --- a/examples/afl_untracer/Makefile +++ b/examples/afl_untracer/Makefile @@ -1,10 +1,16 @@ +ifdef DEBUG + OPT=-O0 +else + OPT=-O3 +endif + all: afl-untracer libtestinstr.so afl-untracer: afl-untracer.c - $(CC) -I../../include -g -o afl-untracer afl-untracer.c -ldl -pthread + $(CC) $(OPT) -I../../include -g -o afl-untracer afl-untracer.c -ldl -pthread libtestinstr.so: libtestinstr.c - $(CC) -fPIC -o libtestinstr.so -shared libtestinstr.c + $(CC) -g -O0 -fPIC -o libtestinstr.so -shared libtestinstr.c clean: rm -f afl-untracer libtestinstr.so *~ core diff --git a/examples/afl_untracer/README.md b/examples/afl_untracer/README.md index 4ff96423..8e24c2a4 100644 --- a/examples/afl_untracer/README.md +++ b/examples/afl_untracer/README.md @@ -14,6 +14,21 @@ To generate the `patches.txt` file for your target library use the `ida_get_patchpoints.py` script for IDA Pro or `ghidra_get_patchpoints.java` for Ghidra. +The patches.txt file has to pointed to by `AFL_UNTRACER_FILE`. + +Example (after modfying afl-untracer.c to your needs, compiling and creating +patches.txt): +``` +AFL_UNTRACER_FILE=./patches.txt afl-fuzz -i in -o out -- ./afl-untracer +``` + +To testing/debugging you can try: +``` +make DEBUG=1 +AFL_UNTRACER_FILE=./patches.txt AFL_DEBUG=1 gdb ./afl-untracer +``` +and then you can easily set breakpoints to "breakpoint" and "fuzz". + This idea is based on [UnTracer](https://github.com/FoRTE-Research/UnTracer-AFL) and modified by [Trapfuzz](https://github.com/googleprojectzero/p0tools/tree/master/TrapFuzz). This implementation is slower because the traps are not patched out with each diff --git a/examples/afl_untracer/afl-untracer.c b/examples/afl_untracer/afl-untracer.c index d319b530..ed1a8239 100644 --- a/examples/afl_untracer/afl-untracer.c +++ b/examples/afl_untracer/afl-untracer.c @@ -156,7 +156,7 @@ void read_library_information() { liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16); if (debug) fprintf( - stderr, "%s:%x (%lx-%lx)\n", liblist[liblist_cnt].name, + stderr, "%s:%llx (%llx-%llx)\n", liblist[liblist_cnt].name, liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start, liblist[liblist_cnt].addr_start, liblist[liblist_cnt].addr_end - 1); @@ -276,6 +276,17 @@ library_list_t *find_library(char *name) { } +/* for having an easy breakpoint after load the shared library */ +// this seems to work for clang too. nice :) requires gcc 4.4+ +#pragma GCC push_options +#pragma GCC optimize ("O0") +void breakpoint() { + + if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n"); + +} +#pragma GCC pop_options + /* Error reporting to forkserver controller */ void send_forkserver_error(int error) { @@ -433,10 +444,17 @@ static void __afl_end_testcase(int status) { } +#ifdef __aarch64__ +#define SHADOW(addr) \ + ((uint64_t *)(((uintptr_t)addr & 0xfffffffffffffff8) - \ + MEMORY_MAP_DECREMENT - \ + ((uintptr_t)addr & 0x7) * 0x10000000000)) +#else #define SHADOW(addr) \ ((uint32_t *)(((uintptr_t)addr & 0xfffffffffffffffc) - \ MEMORY_MAP_DECREMENT - \ ((uintptr_t)addr & 0x3) * 0x10000000000)) +#endif void setup_trap_instrumentation() { @@ -453,7 +471,11 @@ void setup_trap_instrumentation() { if (!patches) FATAL("Couldn't open AFL_UNTRACER_FILE file %s", filename); // Index into the coverage bitmap for the current trap instruction. - int bitmap_index = 0; +#ifdef __aarch64__ + uint64_t bitmap_index = 0; +#else + uint32_t bitmap_index = 0; +#endif while ((nread = getline(&line, &len, patches)) != -1) { @@ -486,7 +508,11 @@ void setup_trap_instrumentation() { FATAL("Failed to mprotect library %s writable", line); // Create shadow memory. +#ifdef __aarch64__ + for (int i = 0; i < 8; i++) { +#else for (int i = 0; i < 4; i++) { +#endif void *shadow_addr = SHADOW(lib_addr + i); void *shadow = mmap(shadow_addr, lib_size, PROT_READ | PROT_WRITE, @@ -513,12 +539,17 @@ void setup_trap_instrumentation() { if (bitmap_index >= __afl_map_size) FATAL("Too many basic blocks to instrument"); - uint32_t *shadow = SHADOW(lib_addr + offset); +#ifdef __arch64__ + uint64_t +#else + uint32_t +#endif + *shadow = SHADOW(lib_addr + offset); if (*shadow != 0) continue; // skip duplicates // Make lookup entry in shadow memory. -#if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__)) +#if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__) || defined(__i386__)) // this is for Intel x64 @@ -531,10 +562,24 @@ void setup_trap_instrumentation() { lib_addr, offset, lib_addr + offset, orig_byte, shadow, bitmap_index, *shadow); +#elif defined(__aarch64__) + + // this is for aarch64 + + uint32_t *patch_bytes = (uint32_t*)(lib_addr + offset); + uint32_t orig_bytes = *patch_bytes; + *shadow = (bitmap_index << 32) | orig_bytes; + *patch_bytes = 0xd4200000; // replace instruction with debug trap + if (debug) + fprintf(stderr, + "Patch entry: %p[%x] = %p = %02x -> SHADOW(%p) #%d -> %016x\n", + lib_addr, offset, lib_addr + offset, orig_bytes, shadow, + bitmap_index, *shadow); + #else // this will be ARM and AARCH64 // for ARM we will need to identify if the code is in thumb or ARM -#error "non x86_64 not supported yet" +#error "non x86_64/aarch64 not supported yet" //__arm__: // linux thumb: 0xde01 // linux arm: 0xe7f001f0 @@ -573,8 +618,15 @@ static void sigtrap_handler(int signum, siginfo_t *si, void *context) { ctx->uc_mcontext->__ss.__rip -= 1; addr = ctx->uc_mcontext->__ss.__rip; #elif defined(__linux__) - ctx->uc_mcontext.gregs[REG_RIP] -= 1; - addr = ctx->uc_mcontext.gregs[REG_RIP]; +#if defined(__x86_64__) || defined(__i386__) + ctx->uc_mcontext.mc_rip -= 1; + addr = ctx->uc_mcontext.mc_rip; +#elif defined(__aarch64__) + ctx->uc_mcontext.pc -= 4; + addr = ctx->uc_mcontext.pc; +#else +#error "Unsupported processor" +#endif #elif defined(__FreeBSD__) && defined(__LP64__) ctx->uc_mcontext.mc_rip -= 1; addr = ctx->uc_mcontext.mc_rip; @@ -642,6 +694,7 @@ int main(int argc, char *argv[]) { // END STEP 2 /* setup instrumentation, shared memory and forkserver */ + breakpoint(); read_library_information(); setup_trap_instrumentation(); __afl_map_shm(); -- cgit 1.4.1 From ef2ccc8117bb899616472e2d95525ae0ca1a2098 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 7 May 2020 14:59:12 +0200 Subject: added AFL_LLVM_SKIPSINGLEBLOCK and changed default behaviour to instrument single block functions --- docs/Changelog.md | 2 ++ docs/env_variables.md | 8 ++++---- llvm_mode/LLVMInsTrim.so.cc | 5 +++-- llvm_mode/afl-llvm-lto-instrim.so.cc | 3 ++- llvm_mode/afl-llvm-lto-instrumentation.so.cc | 7 ++++++- llvm_mode/afl-llvm-pass.so.cc | 17 ++++++++++++----- src/afl-common.c | 18 +++++++++--------- 7 files changed, 38 insertions(+), 22 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 35240021..8bcc8949 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -16,6 +16,8 @@ sending a mail to . - an old, old bug in afl that would show negative stability in rare circumstances is now hopefully fixed - llvm_mode: + - afl-clang-fast/lto now do not skip single block functions. This + behaviour can be reactivated with AFL_LLVM_SKIPSINGLEBLOCK - if LLVM 11 is installed the posix shm_open+mmap is used and a fixed address for the shared memory map is used as this increases the fuzzing speed diff --git a/docs/env_variables.md b/docs/env_variables.md index f5d28981..36e5a432 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -83,6 +83,10 @@ tools make fairly broad use of environmental variables: The native instrumentation helpers (llvm_mode and gcc_plugin) accept a subset of the settings discussed in section #1, with the exception of: + - Setting AFL_LLVM_SKIPSINGLEBLOCK=1 will skip instrumenting + functions with a single basic block. This is useful for most C and + some C++ targets. This works for all instrumentation modes. + - AFL_AS, since this toolchain does not directly invoke GNU as. - TMPDIR and AFL_KEEP_ASSEMBLY, since no temporary assembly files are @@ -156,10 +160,6 @@ Then there are a few specific features that are only available in llvm_mode: afl-fuzz will only be able to see the path the loop took, but not how many times it was called (unless it is a complex loop). - - Setting AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK=1 will skip instrumenting - functions with a single basic block. This is useful for most C and - some C++ targets. - See llvm_mode/README.instrim.md ### NGRAM diff --git a/llvm_mode/LLVMInsTrim.so.cc b/llvm_mode/LLVMInsTrim.so.cc index ad046a8b..ed6c79e8 100644 --- a/llvm_mode/LLVMInsTrim.so.cc +++ b/llvm_mode/LLVMInsTrim.so.cc @@ -134,7 +134,8 @@ struct InsTrim : public ModulePass { } - if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") != NULL) + if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") || + getenv("AFL_LLVM_SKIPSINGLEBLOCK")) function_minimum_size = 2; unsigned PrevLocSize = 0; @@ -394,7 +395,7 @@ struct InsTrim : public ModulePass { if ((callInst = dyn_cast(&IN))) { Function *Callee = callInst->getCalledFunction(); - if (!Callee || Callee->size() < 2) + if (!Callee || Callee->size() < function_minimum_size) continue; else { diff --git a/llvm_mode/afl-llvm-lto-instrim.so.cc b/llvm_mode/afl-llvm-lto-instrim.so.cc index 6371a3cc..a686bb81 100644 --- a/llvm_mode/afl-llvm-lto-instrim.so.cc +++ b/llvm_mode/afl-llvm-lto-instrim.so.cc @@ -172,7 +172,8 @@ struct InsTrimLTO : public ModulePass { } - if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") != NULL) + if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") || + getenv("AFL_LLVM_SKIPSINGLEBLOCK")) function_minimum_size = 2; // this is our default diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index 0e353fdf..f44b336e 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -87,6 +87,7 @@ class AFLLTOPass : public ModulePass { protected: int afl_global_id = 1, debug = 0, autodictionary = 0; + uint32_t function_minimum_size = 1; uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0, total_instr = 0; uint64_t map_addr = 0x10000; char * skip_nozero = NULL; @@ -124,6 +125,10 @@ bool AFLLTOPass::runOnModule(Module &M) { if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0; + if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") || + getenv("AFL_LLVM_SKIPSINGLEBLOCK")) + function_minimum_size = 2; + if ((ptr = getenv("AFL_LLVM_MAP_ADDR"))) { uint64_t val; @@ -189,7 +194,7 @@ bool AFLLTOPass::runOnModule(Module &M) { // fprintf(stderr, "DEBUG: Function %s\n", F.getName().str().c_str()); - if (F.size() < 2) continue; + if (F.size() < function_minimum_size) continue; if (isBlacklisted(&F)) continue; std::vector InsBlocks; diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc index 0d9e0aba..2d23ad21 100644 --- a/llvm_mode/afl-llvm-pass.so.cc +++ b/llvm_mode/afl-llvm-pass.so.cc @@ -84,6 +84,7 @@ class AFLCoverage : public ModulePass { uint32_t ngram_size = 0; uint32_t debug = 0; uint32_t map_size = MAP_SIZE; + uint32_t function_minimum_size = 1; char * ctx_str = NULL, *skip_nozero = NULL; }; @@ -182,6 +183,10 @@ bool AFLCoverage::runOnModule(Module &M) { #endif skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); + if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") || + getenv("AFL_LLVM_SKIPSINGLEBLOCK")) + function_minimum_size = 2; + unsigned PrevLocSize = 0; char *ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE"); @@ -294,13 +299,15 @@ bool AFLCoverage::runOnModule(Module &M) { if (!isInWhitelist(&F)) continue; + if (F.size() < function_minimum_size) continue; + for (auto &BB : F) { BasicBlock::iterator IP = BB.getFirstInsertionPt(); IRBuilder<> IRB(&(*IP)); // Context sensitive coverage - if (ctx_str && &BB == &F.getEntryBlock() && F.size() > 1) { + if (ctx_str && &BB == &F.getEntryBlock()) { // load the context ID of the previous function and write to to a local // variable on the stack @@ -318,7 +325,7 @@ bool AFLCoverage::runOnModule(Module &M) { if ((callInst = dyn_cast(&IN))) { Function *Callee = callInst->getCalledFunction(); - if (!Callee || Callee->size() < 2) + if (!Callee || Callee->size() < function_minimum_size) continue; else { @@ -389,11 +396,11 @@ bool AFLCoverage::runOnModule(Module &M) { } // fprintf(stderr, " == %d\n", more_than_one); - if (more_than_one != 1) { + if (F.size() > 1 && more_than_one != 1) { // in CTX mode we have to restore the original context for the caller - // she might be calling other functions which need the correct CTX - if (ctx_str && has_calls && F.size() > 1) { + if (ctx_str && has_calls) { Instruction *Inst = BB.getTerminator(); if (isa(Inst) || isa(Inst)) { @@ -526,7 +533,7 @@ bool AFLCoverage::runOnModule(Module &M) { // in CTX mode we have to restore the original context for the caller - // she might be calling other functions which need the correct CTX. // Currently this is only needed for the Ubuntu clang-6.0 bug - if (ctx_str && has_calls && F.size() > 1) { + if (ctx_str && has_calls) { Instruction *Inst = BB.getTerminator(); if (isa(Inst) || isa(Inst)) { diff --git a/src/afl-common.c b/src/afl-common.c index 54b2e790..d9d57863 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -64,15 +64,15 @@ char *afl_environment_variables[] = { "AFL_LD_PRELOAD", "AFL_LD_VERBOSE", "AFL_LLVM_CMPLOG", "AFL_LLVM_INSTRIM", "AFL_LLVM_CTX", "AFL_LLVM_INSTRUMENT", "AFL_LLVM_INSTRIM_LOOPHEAD", "AFL_LLVM_LTO_AUTODICTIONARY", "AFL_LLVM_AUTODICTIONARY", - "AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK", "AFL_LLVM_LAF_SPLIT_COMPARES", - "AFL_LLVM_LAF_SPLIT_COMPARES_BITW", "AFL_LLVM_LAF_SPLIT_FLOATS", - "AFL_LLVM_LAF_SPLIT_SWITCHES", "AFL_LLVM_LAF_TRANSFORM_COMPARES", - "AFL_LLVM_MAP_ADDR", "AFL_LLVM_MAP_DYNAMIC", "AFL_LLVM_NGRAM_SIZE", - "AFL_NGRAM_SIZE", "AFL_LLVM_NOT_ZERO", "AFL_LLVM_WHITELIST", - "AFL_LLVM_SKIP_NEVERZERO", "AFL_NO_AFFINITY", "AFL_LLVM_LTO_STARTID", - "AFL_LLVM_LTO_DONTWRITEID", "AFL_NO_ARITH", "AFL_NO_BUILTIN", - "AFL_NO_CPU_RED", "AFL_NO_FORKSRV", "AFL_NO_UI", "AFL_NO_PYTHON", - "AFL_UNTRACER_FILE", + "AFL_LLVM_SKIPSINGLEBLOCK", "AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK", + "AFL_LLVM_LAF_SPLIT_COMPARES", "AFL_LLVM_LAF_SPLIT_COMPARES_BITW", + "AFL_LLVM_LAF_SPLIT_FLOATS", "AFL_LLVM_LAF_SPLIT_SWITCHES", + "AFL_LLVM_LAF_TRANSFORM_COMPARES", "AFL_LLVM_MAP_ADDR", + "AFL_LLVM_MAP_DYNAMIC", "AFL_LLVM_NGRAM_SIZE", "AFL_NGRAM_SIZE", + "AFL_LLVM_NOT_ZERO", "AFL_LLVM_WHITELIST", "AFL_LLVM_SKIP_NEVERZERO", + "AFL_NO_AFFINITY", "AFL_LLVM_LTO_STARTID", "AFL_LLVM_LTO_DONTWRITEID", + "AFL_NO_ARITH", "AFL_NO_BUILTIN", "AFL_NO_CPU_RED", "AFL_NO_FORKSRV", + "AFL_NO_UI", "AFL_NO_PYTHON", "AFL_UNTRACER_FILE", "AFL_NO_X86", // not really an env but we dont want to warn on it "AFL_MAP_SIZE", "AFL_MAPSIZE", "AFL_PATH", "AFL_PERFORMANCE_FILE", //"AFL_PERSISTENT", // not implemented anymore, so warn additionally -- cgit 1.4.1 From 9484da57ed3f421ac274ac51282dba779994da9a Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Thu, 7 May 2020 18:32:36 +0200 Subject: convert docs/README.md into a symlink to toplevel README.md (helps website content) --- docs/README.md | 683 +-------------------------------------------------------- 1 file changed, 1 insertion(+), 682 deletions(-) mode change 100644 => 120000 docs/README.md (limited to 'docs') diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index cfa1cfc6..00000000 --- a/docs/README.md +++ /dev/null @@ -1,682 +0,0 @@ -# american fuzzy lop plus plus (afl++) - - ![Travis State](https://api.travis-ci.com/AFLplusplus/AFLplusplus.svg?branch=master) - - Release Version: 2.60c - - Github Version: 2.60d - - includes all necessary/interesting changes from Google's afl 2.56b - - - Originally developed by Michal "lcamtuf" Zalewski. - - Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus) - - afl++ is maintained by Marc "van Hauser" Heuse , - Heiko "hexcoder-" Eißfeldt , Andrea Fioraldi and Dominik Maier . - - Note that although afl now has a Google afl repository [https://github.com/Google/afl](https://github.com/Google/afl), - it is unlikely to receive any noteable enhancements: [https://twitter.com/Dor3s/status/1154737061787660288](https://twitter.com/Dor3s/status/1154737061787660288) - - -## The enhancements compared to the original stock afl - - Many improvements were made over the official afl release - which did not - get any feature improvements since November 2017. - - Among other changes afl++ has a more performant llvm_mode, supports - llvm up to version 11, QEMU 3.1, more speed and crashfixes for QEMU, - better *BSD and Android support and much, much more. - - Additionally the following features and patches have been integrated: - - * AFLfast's power schedules by Marcel Böhme: [https://github.com/mboehme/aflfast](https://github.com/mboehme/aflfast) - - * The new excellent MOpt mutator: [https://github.com/puppet-meteor/MOpt-AFL](https://github.com/puppet-meteor/MOpt-AFL) - - * InsTrim, a very effective CFG llvm_mode instrumentation implementation for large targets: [https://github.com/csienslab/instrim](https://github.com/csienslab/instrim) - - * C. Holler's afl-fuzz Python mutator module and llvm_mode whitelist support: [https://github.com/choller/afl](https://github.com/choller/afl) - - * Custom mutator by a library (instead of Python) by kyakdan - - * unicorn_mode which allows fuzzing of binaries from completely different platforms (integration provided by domenukk) - - * laf-intel or CompCov support for llvm_mode, qemu_mode and unicorn_mode - - * NeverZero patch for afl-gcc, llvm_mode, qemu_mode and unicorn_mode which prevents a wrapping map value to zero, increases coverage - - * Persistent mode and deferred forkserver for qemu_mode - - * Win32 PE binary-only fuzzing with QEMU and Wine - - * Radamsa mutator (enable with `-R` to add or `-RR` to run it exclusivly). - - * qbdi_mode: fuzz android native libraries via QBDI framework - - - A more thorough list is available in the PATCHES file. - - | Feature/Instrumentation | afl-gcc | llvm_mode | gcc_plugin | qemu_mode | unicorn_mode | - | ----------------------- |:-------:|:---------:|:----------:|:---------:|:------------:| - | laf-intel / CompCov | | x | | x86/arm | x86/arm | - | NeverZero | x | x(1) | (2) | x | x | - | Persistent mode | | x | x | x86 | x | - | Whitelist | | x | x | | | - | InsTrim | | x | | | | - - neverZero: - - (1) only in LLVM >= 9.0 due to a bug in llvm in previous versions - - (2) gcc creates non-performant code, hence it is disabled in gcc_plugin - - So all in all this is the best-of afl that is currently out there :-) - - For new versions and additional information, check out: - [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus) - - To compare notes with other users or get notified about major new features, - send a mail to . - - See [docs/QuickStartGuide.md](docs/QuickStartGuide.md) if you don't have time to - read this file. - - -## 0) Building and installing afl++ - -afl++ has many build options. -The easiest is to build and install everything: - -```shell -$ make distrib -$ sudo make install -``` - -Note that "make distrib" also builds llvm_mode, qemu_mode, unicorn_mode and -more. If you just want plain afl then do "make all", however compiling and -using at least llvm_mode is highly recommended for much better results - -hence in this case - -```shell -$ make source-only -``` -is what you should choose. - -These build options exist: - -* all: just the main afl++ binaries -* binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap, radamsa -* source-only: everything for source code fuzzing: llvm_mode, libdislocator, libtokencap, radamsa -* distrib: everything (for both binary-only and source code fuzzing) -* install: installs everything you have compiled with the build options above -* clean: cleans everything. for qemu_mode and unicorn_mode it means it deletes all downloads as well -* code-format: format the code, do this before you commit and send a PR please! -* tests: runs test cases to ensure that all features are still working as they should -* help: shows these build options - -[Unless you are on Mac OS X](https://developer.apple.com/library/archive/qa/qa1118/_index.html) you can also build statically linked versions of the -afl++ binaries by passing the STATIC=1 argument to make: - -```shell -$ make all STATIC=1 -``` - -Note that afl++ is faster and better the newer the compilers used are. -Hence gcc-9 and especially llvm-9 should be the compilers of choice. -If your distribution does not have them, you can use the Dockerfile: - -```shell -$ docker build -t aflplusplus -``` - - -## 1) Challenges of guided fuzzing - -Fuzzing is one of the most powerful and proven strategies for identifying -security issues in real-world software; it is responsible for the vast -majority of remote code execution and privilege escalation bugs found to date -in security-critical software. - -Unfortunately, fuzzing is also relatively shallow; blind, random mutations -make it very unlikely to reach certain code paths in the tested code, leaving -some vulnerabilities firmly outside the reach of this technique. - -There have been numerous attempts to solve this problem. One of the early -approaches - pioneered by Tavis Ormandy - is corpus distillation. The method -relies on coverage signals to select a subset of interesting seeds from a -massive, high-quality corpus of candidate files, and then fuzz them by -traditional means. The approach works exceptionally well, but requires such -a corpus to be readily available. In addition, block coverage measurements -provide only a very simplistic understanding of program state, and are less -useful for guiding the fuzzing effort in the long haul. - -Other, more sophisticated research has focused on techniques such as program -flow analysis ("concolic execution"), symbolic execution, or static analysis. -All these methods are extremely promising in experimental settings, but tend -to suffer from reliability and performance problems in practical uses - and -currently do not offer a viable alternative to "dumb" fuzzing techniques. - - -## 2) The afl-fuzz approach - -American Fuzzy Lop is a brute-force fuzzer coupled with an exceedingly simple -but rock-solid instrumentation-guided genetic algorithm. It uses a modified -form of edge coverage to effortlessly pick up subtle, local-scale changes to -program control flow. - -Simplifying a bit, the overall algorithm can be summed up as: - - 1) Load user-supplied initial test cases into the queue, - - 2) Take next input file from the queue, - - 3) Attempt to trim the test case to the smallest size that doesn't alter - the measured behavior of the program, - - 4) Repeatedly mutate the file using a balanced and well-researched variety - of traditional fuzzing strategies, - - 5) If any of the generated mutations resulted in a new state transition - recorded by the instrumentation, add mutated output as a new entry in the - queue. - - 6) Go to 2. - -The discovered test cases are also periodically culled to eliminate ones that -have been obsoleted by newer, higher-coverage finds; and undergo several other -instrumentation-driven effort minimization steps. - -As a side result of the fuzzing process, the tool creates a small, -self-contained corpus of interesting test cases. These are extremely useful -for seeding other, labor- or resource-intensive testing regimes - for example, -for stress-testing browsers, office applications, graphics suites, or -closed-source tools. - -The fuzzer is thoroughly tested to deliver out-of-the-box performance far -superior to blind fuzzing or coverage-only tools. - - -## 3) Instrumenting programs for use with AFL - -PLEASE NOTE: llvm_mode compilation with afl-clang-fast/afl-clang-fast++ -instead of afl-gcc/afl-g++ is much faster and has a few cool features. -See llvm_mode/ - however few code does not compile with llvm. -We support llvm versions 3.8.0 to 11. - -When source code is available, instrumentation can be injected by a companion -tool that works as a drop-in replacement for gcc or clang in any standard build -process for third-party code. - -The instrumentation has a fairly modest performance impact; in conjunction with -other optimizations implemented by afl-fuzz, most programs can be fuzzed as fast -or even faster than possible with traditional tools. - -The correct way to recompile the target program may vary depending on the -specifics of the build process, but a nearly-universal approach would be: - -```shell -$ CC=/path/to/afl/afl-gcc ./configure -$ make clean all -``` - -For C++ programs, you'd would also want to set `CXX=/path/to/afl/afl-g++`. - -The clang wrappers (afl-clang and afl-clang++) can be used in the same way; -clang users may also opt to leverage a higher-performance instrumentation mode, -as described in [llvm_mode/README.md](llvm_mode/README.md). -Clang/LLVM has a much better performance and works with LLVM version 3.8.0 to 11. - -Using the LAF Intel performance enhancements are also recommended, see -[llvm_mode/README.laf-intel.md](llvm_mode/README.laf-intel.md) - -Using partial instrumentation is also recommended, see -[llvm_mode/README.whitelist.md](llvm_mode/README.whitelist.md) - -When testing libraries, you need to find or write a simple program that reads -data from stdin or from a file and passes it to the tested library. In such a -case, it is essential to link this executable against a static version of the -instrumented library, or to make sure that the correct .so file is loaded at -runtime (usually by setting `LD_LIBRARY_PATH`). The simplest option is a static -build, usually possible via: - -```shell -$ CC=/path/to/afl/afl-gcc ./configure --disable-shared -``` - -Setting `AFL_HARDEN=1` when calling 'make' will cause the CC wrapper to -automatically enable code hardening options that make it easier to detect -simple memory bugs. Libdislocator, a helper library included with AFL (see -[libdislocator/README.md](libdislocator/README.md)) can help uncover heap corruption issues, too. - -PS. ASAN users are advised to review [docs/notes_for_asan.md](docs/notes_for_asan.md) -file for important caveats. - - -## 4) Instrumenting binary-only apps - -When source code is *NOT* available, the fuzzer offers experimental support for -fast, on-the-fly instrumentation of black-box binaries. This is accomplished -with a version of QEMU running in the lesser-known "user space emulation" mode. - -QEMU is a project separate from AFL, but you can conveniently build the -feature by doing: - -```shell -$ cd qemu_mode -$ ./build_qemu_support.sh -``` - -For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md). - -The mode is approximately 2-5x slower than compile-time instrumentation, is -less conducive to parallelization, and may have some other quirks. - -If [afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst) works for -your binary, then you can use afl-fuzz normally and it will have twice -the speed compared to qemu_mode. - -A more comprehensive description of these and other options can be found in -[docs/binaryonly_fuzzing.md](docs/binaryonly_fuzzing.md) - - -## 5) Power schedules - -The power schedules were copied from Marcel Böhme's excellent AFLfast -implementation and expand on the ability to discover new paths and -therefore may increase the code coverage. - -The available schedules are: - - - explore (default) - - fast - - coe - - quad - - lin - - exploit - -In parallel mode (-M/-S, several instances with shared queue), we suggest to -run the master using the exploit schedule (-p exploit) and the slaves with a -combination of cut-off-exponential (-p coe), exponential (-p fast; default), -and explore (-p explore) schedules. - -In single mode, using -p fast is usually more beneficial than the default -explore mode. -(We don't want to change the default behaviour of afl, so "fast" has not been -made the default mode). - -More details can be found in the paper published at the 23rd ACM Conference on -Computer and Communications Security [CCS'16](https://www.sigsac.org/ccs/CCS2016/accepted-papers/) -## 6) Choosing initial test cases - -To operate correctly, the fuzzer requires one or more starting file that -contains a good example of the input data normally expected by the targeted -application. There are two basic rules: - - - Keep the files small. Under 1 kB is ideal, although not strictly necessary. - For a discussion of why size matters, see [perf_tips.md](docs/perf_tips.md). - - - Use multiple test cases only if they are functionally different from - each other. There is no point in using fifty different vacation photos - to fuzz an image library. - -You can find many good examples of starting files in the testcases/ subdirectory -that comes with this tool. - -PS. If a large corpus of data is available for screening, you may want to use -the afl-cmin utility to identify a subset of functionally distinct files that -exercise different code paths in the target binary. - - -## 7) Fuzzing binaries - -The fuzzing process itself is carried out by the afl-fuzz utility. This program -requires a read-only directory with initial test cases, a separate place to -store its findings, plus a path to the binary to test. - -For target binaries that accept input directly from stdin, the usual syntax is: - -```shell -$ ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program [...params...] -``` - -For programs that take input from a file, use '@@' to mark the location in -the target's command line where the input file name should be placed. The -fuzzer will substitute this for you: - -```shell -$ ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program @@ -``` - -You can also use the -f option to have the mutated data written to a specific -file. This is useful if the program expects a particular file extension or so. - -Non-instrumented binaries can be fuzzed in the QEMU mode (add -Q in the command -line) or in a traditional, blind-fuzzer mode (specify -n). - -You can use -t and -m to override the default timeout and memory limit for the -executed process; rare examples of targets that may need these settings touched -include compilers and video decoders. - -Tips for optimizing fuzzing performance are discussed in [perf_tips.md](docs/perf_tips.md). - -Note that afl-fuzz starts by performing an array of deterministic fuzzing -steps, which can take several days, but tend to produce neat test cases. If you -want quick & dirty results right away - akin to zzuf and other traditional -fuzzers - add the -d option to the command line. - - -## 8) Interpreting output - -See the [docs/status_screen.md](docs/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. - -The fuzzing process will continue until you press Ctrl-C. At minimum, you want -to allow the fuzzer to complete one queue cycle, which may take anywhere from a -couple of hours to a week or so. - -There are three subdirectories created within the output directory and updated -in real time: - - - queue/ - test cases for every distinctive execution path, plus all the - starting files given by the user. This is the synthesized corpus - mentioned in section 2. - - Before using this corpus for any other purposes, you can shrink - it to a smaller size using the afl-cmin tool. The tool will find - a smaller subset of files offering equivalent edge coverage. - - - crashes/ - unique test cases that cause the tested program to receive a - fatal signal (e.g., SIGSEGV, SIGILL, SIGABRT). The entries are - grouped by the received signal. - - - hangs/ - unique test cases that cause the tested program to time out. The - default time limit before something is classified as a hang is - the larger of 1 second and the value of the -t parameter. - The value can be fine-tuned by setting AFL_HANG_TMOUT, but this - is rarely necessary. - -Crashes and hangs are considered "unique" if the associated execution paths -involve any state transitions not seen in previously-recorded faults. If a -single bug can be reached in multiple ways, there will be some count inflation -early in the process, but this should quickly taper off. - -The file names for crashes and hangs are correlated with parent, non-faulting -queue entries. This should help with debugging. - -When you can't reproduce a crash found by afl-fuzz, the most likely cause is -that you are not setting the same memory limit as used by the tool. Try: - -```shell -$ LIMIT_MB=50 -$ ( ulimit -Sv $[LIMIT_MB << 10]; /path/to/tested_binary ... ) -``` - -Change LIMIT_MB to match the -m parameter passed to afl-fuzz. On OpenBSD, -also change -Sv to -Sd. - -Any existing output directory can be also used to resume aborted jobs; try: - -```shell -$ ./afl-fuzz -i- -o existing_output_dir [...etc...] -``` - -If you have gnuplot installed, you can also generate some pretty graphs for any -active fuzzing task using afl-plot. For an example of how this looks like, -see [http://lcamtuf.coredump.cx/afl/plot/](http://lcamtuf.coredump.cx/afl/plot/). - - -## 9) Parallelized fuzzing - -Every instance of afl-fuzz takes up roughly one core. This means that on -multi-core systems, parallelization is necessary to fully utilize the hardware. -For tips on how to fuzz a common target on multiple cores or multiple networked -machines, please refer to [docs/parallel_fuzzing.md](docs/parallel_fuzzing.md). - -The parallel fuzzing mode also offers a simple way for interfacing AFL to other -fuzzers, to symbolic or concolic execution engines, and so forth; again, see the -last section of [docs/parallel_fuzzing.md](docs/parallel_fuzzing.md) for tips. - - -## 10) Fuzzer dictionaries - -By default, afl-fuzz mutation engine is optimized for compact data formats - -say, images, multimedia, compressed data, regular expression syntax, or shell -scripts. It is somewhat less suited for languages with particularly verbose and -redundant verbiage - notably including HTML, SQL, or JavaScript. - -To avoid the hassle of building syntax-aware tools, afl-fuzz provides a way to -seed the fuzzing process with an optional dictionary of language keywords, -magic headers, or other special tokens associated with the targeted data type --- and use that to reconstruct the underlying grammar on the go: - - [http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html](http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html) - -To use this feature, you first need to create a dictionary in one of the two -formats discussed in [dictionaries/README.md](dictionaries/README.md); -and then point the fuzzer to it via the -x option in the command line. - -(Several common dictionaries are already provided in that subdirectory, too.) - -There is no way to provide more structured descriptions of the underlying -syntax, but the fuzzer will likely figure out some of this based on the -instrumentation feedback alone. This actually works in practice, say: - - [http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html](http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html) - -PS. Even when no explicit dictionary is given, afl-fuzz will try to extract -existing syntax tokens in the input corpus by watching the instrumentation -very closely during deterministic byte flips. This works for some types of -parsers and grammars, but isn't nearly as good as the -x mode. - -If a dictionary is really hard to come by, another option is to let AFL run -for a while, and then use the token capture library that comes as a companion -utility with AFL. For that, see [libtokencap/README.md](libtokencap/README.tokencap.md). - - -## 11) Crash triage - -The coverage-based grouping of crashes usually produces a small data set that -can be quickly triaged manually or with a very simple GDB or Valgrind script. -Every crash is also traceable to its parent non-crashing test case in the -queue, making it easier to diagnose faults. - -Having said that, it's important to acknowledge that some fuzzing crashes can be -difficult to quickly evaluate for exploitability without a lot of debugging and -code analysis work. To assist with this task, afl-fuzz supports a very unique -"crash exploration" mode enabled with the -C flag. - -In this mode, the fuzzer takes one or more crashing test cases as the input, -and uses its feedback-driven fuzzing strategies to very quickly enumerate all -code paths that can be reached in the program while keeping it in the -crashing state. - -Mutations that do not result in a crash are rejected; so are any changes that -do not affect the execution path. - -The output is a small corpus of files that can be very rapidly examined to see -what degree of control the attacker has over the faulting address, or whether -it is possible to get past an initial out-of-bounds read - and see what lies -beneath. - -Oh, one more thing: for test case minimization, give afl-tmin a try. The tool -can be operated in a very simple way: - -```shell -$ ./afl-tmin -i test_case -o minimized_result -- /path/to/program [...] -``` - -The tool works with crashing and non-crashing test cases alike. In the crash -mode, it will happily accept instrumented and non-instrumented binaries. In the -non-crashing mode, the minimizer relies on standard AFL instrumentation to make -the file simpler without altering the execution path. - -The minimizer accepts the -m, -t, -f and @@ syntax in a manner compatible with -afl-fuzz. - -Another recent addition to AFL is the afl-analyze tool. It takes an input -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). - - -## 12) Going beyond crashes - -Fuzzing is a wonderful and underutilized technique for discovering non-crashing -design and implementation errors, too. Quite a few interesting bugs have been -found by modifying the target programs to call abort() when, say: - - - Two bignum libraries produce different outputs when given the same - fuzzer-generated input, - - - An image library produces different outputs when asked to decode the same - input image several times in a row, - - - A serialization / deserialization library fails to produce stable outputs - when iteratively serializing and deserializing fuzzer-supplied data, - - - A compression library produces an output inconsistent with the input file - when asked to compress and then decompress a particular blob. - -Implementing these or similar sanity checks usually takes very little time; -if you are the maintainer of a particular package, you can make this code -conditional with `#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` (a flag also -shared with libfuzzer) or `#ifdef __AFL_COMPILER` (this one is just for AFL). - - -## 13) Common-sense risks - -Please keep in mind that, similarly to many other computationally-intensive -tasks, fuzzing may put strain on your hardware and on the OS. In particular: - - - Your CPU will run hot and will need adequate cooling. In most cases, if - cooling is insufficient or stops working properly, CPU speeds will be - automatically throttled. That said, especially when fuzzing on less - suitable hardware (laptops, smartphones, etc), it's not entirely impossible - for something to blow up. - - - Targeted programs may end up erratically grabbing gigabytes of memory or - filling up disk space with junk files. AFL tries to enforce basic memory - limits, but can't prevent each and every possible mishap. The bottom line - is that you shouldn't be fuzzing on systems where the prospect of data loss - is not an acceptable risk. - - - Fuzzing involves billions of reads and writes to the filesystem. On modern - systems, this will be usually heavily cached, resulting in fairly modest - "physical" I/O - but there are many factors that may alter this equation. - It is your responsibility to monitor for potential trouble; with very heavy - I/O, the lifespan of many HDDs and SSDs may be reduced. - - A good way to monitor disk I/O on Linux is the 'iostat' command: - -```shell - $ iostat -d 3 -x -k [...optional disk ID...] -``` - - -## 14) Known limitations & areas for improvement - -Here are some of the most important caveats for AFL: - - - AFL detects faults by checking for the first spawned process dying due to - a signal (SIGSEGV, SIGABRT, etc). Programs that install custom handlers for - these signals may need to have the relevant code commented out. In the same - vein, faults in child processed spawned by the fuzzed target may evade - detection unless you manually add some code to catch that. - - - As with any other brute-force tool, the fuzzer offers limited coverage if - encryption, checksums, cryptographic signatures, or compression are used to - wholly wrap the actual data format to be tested. - - To work around this, you can comment out the relevant checks (see - examples/libpng_no_checksum/ for inspiration); if this is not possible, - you can also write a postprocessor, as explained in - examples/post_library/ (with AFL_POST_LIBRARY) - - - There are some unfortunate trade-offs with ASAN and 64-bit binaries. This - isn't due to any specific fault of afl-fuzz; see [docs/notes_for_asan.md](docs/notes_for_asan.md) - for tips. - - - There is no direct support for fuzzing network services, background - daemons, or interactive apps that require UI interaction to work. You may - need to make simple code changes to make them behave in a more traditional - way. Preeny may offer a relatively simple option, too - see: - [https://github.com/zardus/preeny](https://github.com/zardus/preeny) - - Some useful tips for modifying network-based services can be also found at: - [https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop) - - - AFL doesn't output human-readable coverage data. If you want to monitor - coverage, use afl-cov from Michael Rash: [https://github.com/mrash/afl-cov](https://github.com/mrash/afl-cov) - - - 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 for platform-specific tips. - - -## 15) Special thanks - -Many of the improvements to the original afl and afl++ wouldn't be possible -without feedback, bug reports, or patches from: - -``` - Jann Horn Hanno Boeck - Felix Groebert Jakub Wilk - Richard W. M. Jones Alexander Cherepanov - Tom Ritter Hovik Manucharyan - Sebastian Roschke Eberhard Mattes - Padraig Brady Ben Laurie - @dronesec Luca Barbato - Tobias Ospelt Thomas Jarosch - Martin Carpenter Mudge Zatko - Joe Zbiciak Ryan Govostes - Michael Rash William Robinet - Jonathan Gray Filipe Cabecinhas - Nico Weber Jodie Cunningham - Andrew Griffiths Parker Thompson - Jonathan Neuschaefer Tyler Nighswander - Ben Nagy Samir Aguiar - Aidan Thornton Aleksandar Nikolich - Sam Hakim Laszlo Szekeres - David A. Wheeler Turo Lamminen - Andreas Stieger Richard Godbee - Louis Dassy teor2345 - Alex Moneger Dmitry Vyukov - Keegan McAllister Kostya Serebryany - Richo Healey Martijn Bogaard - rc0r Jonathan Foote - Christian Holler Dominique Pelle - Jacek Wielemborek Leo Barnes - Jeremy Barnes Jeff Trull - Guillaume Endignoux ilovezfs - Daniel Godas-Lopez Franjo Ivancic - Austin Seipp Daniel Komaromy - Daniel Binderman Jonathan Metzman - Vegard Nossum Jan Kneschke - Kurt Roeckx Marcel Boehme - Van-Thuan Pham Abhik Roychoudhury - Joshua J. Drake Toby Hutton - Rene Freingruber Sergey Davidoff - Sami Liedes Craig Young - Andrzej Jackowski Daniel Hodson - Nathan Voss Dominik Maier - Andrea Biondo Vincent Le Garrec - Khaled Yakdan Kuang-che Wu -``` - -Thank you! - - -## 16) Contact - -Questions? Concerns? Bug reports? The contributors can be reached via -[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus) - -There is also a mailing list for the afl project; to join, send a mail to -. Or, if you prefer to browse -archives first, try: [https://groups.google.com/group/afl-users](https://groups.google.com/group/afl-users) diff --git a/docs/README.md b/docs/README.md new file mode 120000 index 00000000..32d46ee8 --- /dev/null +++ b/docs/README.md @@ -0,0 +1 @@ +../README.md \ No newline at end of file -- cgit 1.4.1 From cf9238e09d74791c93a3a50ef2460d96529bcfa1 Mon Sep 17 00:00:00 2001 From: Rishi Ranjan <43873720+rish9101@users.noreply.github.com> Date: Sat, 9 May 2020 03:31:11 +0530 Subject: Update docs and Changelog for custom_mutators (#355) --- docs/Changelog.md | 3 +++ docs/custom_mutators.md | 4 ++++ 2 files changed, 7 insertions(+) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 8bcc8949..0b5c11e8 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -2574,3 +2574,6 @@ sending a mail to . ### Version 0.21b (2013-11-12): - Initial public release. + + - Added support for use of multiple custom mutators which can be specified using + the environment variable AFL_CUSTOM_MUTATOR_LIBRARY. diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 49ce761e..acc9ff4e 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -16,6 +16,10 @@ fuzzing by using libraries that perform mutations according to a given grammar. The custom mutator is passed to `afl-fuzz` via the `AFL_CUSTOM_MUTATOR_LIBRARY` or `AFL_PYTHON_MODULE` environment variable, and must export a fuzz function. +Now afl also supports multiple custom mutators which can be specified in the same `AFL_CUSTOM_MUTATOR_LIBRARY` environment variable like this. +```bash +export AFL_CUSTOM_MUTATOR_LIBRARY="full/path/to/mutator_first.so;full/path/to/mutator_second.so" +``` Please see [APIs](#2-apis) and [Usage](#3-usage) for detail. The custom mutation stage is set to be the first non-deterministic stage (right before the havoc stage). -- cgit 1.4.1 From 7b9ac9d414e7434c11a95b85c2c24e9cbdcbe935 Mon Sep 17 00:00:00 2001 From: rish9101 Date: Sun, 10 May 2020 12:21:19 +0530 Subject: Specify usage of multiple custom mutators --- docs/custom_mutators.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index acc9ff4e..3cd874b9 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -213,12 +213,15 @@ For C/C++ mutator, the source code must be compiled as a shared object: ```bash gcc -shared -Wall -O3 example.c -o example.so ``` +Note that if you specify multiple custom mutators, the corresponding functions will +be called in the order in which they are specified. e.g first `pre_save` function of +`example_first.so` will be called and then that of `example_second.so` ### Run C/C++ ```bash -export AFL_CUSTOM_MUTATOR_LIBRARY=/full/path/to/example.so +export AFL_CUSTOM_MUTATOR_LIBRARY="/full/path/to/example_first.so;/full/path/to/example_second.so" afl-fuzz /path/to/program ``` -- cgit 1.4.1